blob: 5c8f88c42fe82066b859e7fe4907f3503572ab4f [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02002/*
3 * Display driver for Allwinner SoCs.
4 *
5 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
Hans de Goedec06e00e2015-08-03 19:20:26 +02006 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02007 */
8
9#include <common.h>
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +010010#include <efi_loader.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020011
12#include <asm/arch/clock.h>
13#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020015#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020016#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020017#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020018#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010019#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020020#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020021#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010022#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020023#include <fdtdec.h>
24#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010025#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020026#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020027#include <video_fb.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020028#include "../videomodes.h"
29#include "../anx9804.h"
30#include "../hitachi_tx18d42vm_lcd.h"
31#include "../ssd2828.h"
Icenowy Zheng067a6972017-10-26 11:14:45 +080032#include "simplefb_common.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020033
Hans de Goede2d5d3022015-01-22 21:02:42 +010034#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
35#define PWM_ON 0
36#define PWM_OFF 1
37#else
38#define PWM_ON 1
39#define PWM_OFF 0
40#endif
41
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020042DECLARE_GLOBAL_DATA_PTR;
43
Hans de Goedea0b1b732014-12-21 14:37:45 +010044enum sunxi_monitor {
45 sunxi_monitor_none,
46 sunxi_monitor_dvi,
47 sunxi_monitor_hdmi,
48 sunxi_monitor_lcd,
49 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020050 sunxi_monitor_composite_pal,
51 sunxi_monitor_composite_ntsc,
52 sunxi_monitor_composite_pal_m,
53 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010054};
Hans de Goedec06e00e2015-08-03 19:20:26 +020055#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010056
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020057struct sunxi_display {
58 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010059 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010060 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020061 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010062 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020063} sunxi_display;
64
Hans de Goedec06e00e2015-08-03 19:20:26 +020065const struct ctfb_res_modes composite_video_modes[2] = {
66 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
67 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
68 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
69};
70
Hans de Goedee9544592014-12-23 23:04:35 +010071#ifdef CONFIG_VIDEO_HDMI
72
Hans de Goedea5aa95f2014-12-19 16:05:12 +010073/*
74 * Wait up to 200ms for value to be set in given part of reg.
75 */
76static int await_completion(u32 *reg, u32 mask, u32 val)
77{
78 unsigned long tmo = timer_get_us() + 200000;
79
80 while ((readl(reg) & mask) != val) {
81 if (timer_get_us() > tmo) {
82 printf("DDC: timeout reading EDID\n");
83 return -ETIME;
84 }
85 }
86 return 0;
87}
88
Hans de Goede91593712014-12-28 09:13:21 +010089static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020090{
91 struct sunxi_ccm_reg * const ccm =
92 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
93 struct sunxi_hdmi_reg * const hdmi =
94 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010095 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020096
97 /* Set pll3 to 300MHz */
98 clock_set_pll3(300000000);
99
100 /* Set hdmi parent to pll3 */
101 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
102 CCM_HDMI_CTRL_PLL3);
103
104 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200105#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100106 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
107#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200108 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
109
110 /* Clock on */
111 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
112
113 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
114 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
115
Hans de Goede205a30c2014-12-20 15:15:23 +0100116 while (timer_get_us() < tmo) {
117 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
118 return 1;
119 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200120
Hans de Goede205a30c2014-12-20 15:15:23 +0100121 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100122}
123
124static void sunxi_hdmi_shutdown(void)
125{
126 struct sunxi_ccm_reg * const ccm =
127 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
128 struct sunxi_hdmi_reg * const hdmi =
129 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200130
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200131 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
132 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
133 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200134#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100135 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
136#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200137 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200138}
139
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100140static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
141{
142 struct sunxi_hdmi_reg * const hdmi =
143 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
144
145 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
146 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
147 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
148 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
149 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
150#ifndef CONFIG_MACH_SUN6I
151 writel(n, &hdmi->ddc_byte_count);
152 writel(cmnd, &hdmi->ddc_cmnd);
153#else
154 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
155#endif
156 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
157
158 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
159}
160
161static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
162{
163 struct sunxi_hdmi_reg * const hdmi =
164 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
165 int i, n;
166
167 while (count > 0) {
168 if (count > 16)
169 n = 16;
170 else
171 n = count;
172
173 if (sunxi_hdmi_ddc_do_command(
174 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
175 offset, n))
176 return -ETIME;
177
178 for (i = 0; i < n; i++)
179 *buf++ = readb(&hdmi->ddc_fifo_data);
180
181 offset += n;
182 count -= n;
183 }
184
185 return 0;
186}
187
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100188static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
189{
190 int r, retries = 2;
191
192 do {
193 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
194 if (r)
195 continue;
196 r = edid_check_checksum(buf);
197 if (r) {
198 printf("EDID block %d: checksum error%s\n",
199 block, retries ? ", retrying" : "");
200 }
201 } while (r && retries--);
202
203 return r;
204}
205
Hans de Goedea0b1b732014-12-21 14:37:45 +0100206static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100207{
208 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100209 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100210 struct edid_detailed_timing *t =
211 (struct edid_detailed_timing *)edid1.monitor_details.timing;
212 struct sunxi_hdmi_reg * const hdmi =
213 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
214 struct sunxi_ccm_reg * const ccm =
215 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100216 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100217
218 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
219 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
220 &hdmi->pad_ctrl1);
221 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
222 &hdmi->pll_ctrl);
223 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
224
225 /* Reset i2c controller */
226 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
227 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
228 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
229 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
230 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
231 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
232 return -EIO;
233
234 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
235#ifndef CONFIG_MACH_SUN6I
236 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
237 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
238#endif
239
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100240 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100241 if (r == 0) {
242 r = edid_check_info(&edid1);
243 if (r) {
244 printf("EDID: invalid EDID data\n");
245 r = -EINVAL;
246 }
247 }
248 if (r == 0) {
249 ext_blocks = edid1.extension_flag;
250 if (ext_blocks > 4)
251 ext_blocks = 4;
252 for (i = 0; i < ext_blocks; i++) {
253 if (sunxi_hdmi_edid_get_block(1 + i,
254 (u8 *)&cea681[i]) != 0) {
255 ext_blocks = i;
256 break;
257 }
258 }
259 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100260
261 /* Disable DDC engine, no longer needed */
262 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
263 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
264
265 if (r)
266 return r;
267
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100268 /* We want version 1.3 or 1.2 with detailed timing info */
269 if (edid1.version != 1 || (edid1.revision < 3 &&
270 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
271 printf("EDID: unsupported version %d.%d\n",
272 edid1.version, edid1.revision);
273 return -EINVAL;
274 }
275
276 /* Take the first usable detailed timing */
277 for (i = 0; i < 4; i++, t++) {
278 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
279 if (r == 0)
280 break;
281 }
282 if (i == 4) {
283 printf("EDID: no usable detailed timing found\n");
284 return -ENOENT;
285 }
286
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100287 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100288 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100289 for (i = 0; i < ext_blocks; i++) {
290 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
291 cea681[i].revision < 2)
292 continue;
293
294 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100295 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100296 }
297
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100298 return 0;
299}
300
Hans de Goedee9544592014-12-23 23:04:35 +0100301#endif /* CONFIG_VIDEO_HDMI */
302
Hans de Goedec3cc4262015-01-19 08:44:07 +0100303#ifdef CONFIG_MACH_SUN4I
304/*
305 * Testing has shown that on sun4i the display backend engine does not have
306 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
307 * fifo underruns. So on sun4i we use the display frontend engine to do the
308 * dma from memory, as the frontend does have deep enough fifo-s.
309 */
310
311static const u32 sun4i_vert_coef[32] = {
312 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
313 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
314 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
315 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
316 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
317 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
318 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
319 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
320};
321
322static const u32 sun4i_horz_coef[64] = {
323 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
324 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
325 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
326 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
327 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
328 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
329 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
330 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
331 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
332 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
333 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
334 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
335 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
336 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
337 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
338 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
339};
340
341static void sunxi_frontend_init(void)
342{
343 struct sunxi_ccm_reg * const ccm =
344 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
345 struct sunxi_de_fe_reg * const de_fe =
346 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
347 int i;
348
349 /* Clocks on */
350 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
351 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
352 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
353
354 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
355
356 for (i = 0; i < 32; i++) {
357 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
358 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
359 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
360 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
361 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
362 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
363 }
364
365 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
366}
367
368static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
369 unsigned int address)
370{
371 struct sunxi_de_fe_reg * const de_fe =
372 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
373
374 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
375 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
376 writel(mode->xres * 4, &de_fe->ch0_stride);
377 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
378 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
379
380 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
381 &de_fe->ch0_insize);
382 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
383 &de_fe->ch0_outsize);
384 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
385 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
386
387 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
388 &de_fe->ch1_insize);
389 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
390 &de_fe->ch1_outsize);
391 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
392 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
393
394 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
395}
396
397static void sunxi_frontend_enable(void)
398{
399 struct sunxi_de_fe_reg * const de_fe =
400 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
401
402 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
403}
404#else
405static void sunxi_frontend_init(void) {}
406static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
407 unsigned int address) {}
408static void sunxi_frontend_enable(void) {}
409#endif
410
Hans de Goedec06e00e2015-08-03 19:20:26 +0200411static bool sunxi_is_composite(void)
412{
413 switch (sunxi_display.monitor) {
414 case sunxi_monitor_none:
415 case sunxi_monitor_dvi:
416 case sunxi_monitor_hdmi:
417 case sunxi_monitor_lcd:
418 case sunxi_monitor_vga:
419 return false;
420 case sunxi_monitor_composite_pal:
421 case sunxi_monitor_composite_ntsc:
422 case sunxi_monitor_composite_pal_m:
423 case sunxi_monitor_composite_pal_nc:
424 return true;
425 }
426
427 return false; /* Never reached */
428}
429
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200430/*
431 * This is the entity that mixes and matches the different layers and inputs.
432 * Allwinner calls it the back-end, but i like composer better.
433 */
434static void sunxi_composer_init(void)
435{
436 struct sunxi_ccm_reg * const ccm =
437 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
438 struct sunxi_de_be_reg * const de_be =
439 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
440 int i;
441
Hans de Goedec3cc4262015-01-19 08:44:07 +0100442 sunxi_frontend_init();
443
Hans de Goedef07872b2015-04-06 20:33:34 +0200444#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100445 /* Reset off */
446 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
447#endif
448
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200449 /* Clocks on */
450 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100451#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200452 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100453#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200454 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
455
456 /* Engine bug, clear registers after reset */
457 for (i = 0x0800; i < 0x1000; i += 4)
458 writel(0, SUNXI_DE_BE0_BASE + i);
459
460 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
461}
462
Hans de Goedec06e00e2015-08-03 19:20:26 +0200463static u32 sunxi_rgb2yuv_coef[12] = {
464 0x00000107, 0x00000204, 0x00000064, 0x00000108,
465 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
466 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
467};
468
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100469static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200470 unsigned int address)
471{
472 struct sunxi_de_be_reg * const de_be =
473 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200474 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200475
Hans de Goedec3cc4262015-01-19 08:44:07 +0100476 sunxi_frontend_mode_set(mode, address);
477
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200478 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
479 &de_be->disp_size);
480 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
481 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100482#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200483 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
484 writel(address << 3, &de_be->layer0_addr_low32b);
485 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100486#else
487 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
488#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200489 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
490
491 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200492 if (mode->vmode == FB_VMODE_INTERLACED)
493 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200494#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200495 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200496#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200497 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200498
499 if (sunxi_is_composite()) {
500 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
501 &de_be->output_color_ctrl);
502 for (i = 0; i < 12; i++)
503 writel(sunxi_rgb2yuv_coef[i],
504 &de_be->output_color_coef[i]);
505 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200506}
507
Hans de Goede4125f922014-12-21 14:49:34 +0100508static void sunxi_composer_enable(void)
509{
510 struct sunxi_de_be_reg * const de_be =
511 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
512
Hans de Goedec3cc4262015-01-19 08:44:07 +0100513 sunxi_frontend_enable();
514
Hans de Goede4125f922014-12-21 14:49:34 +0100515 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
516 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
517}
518
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200519static void sunxi_lcdc_init(void)
520{
521 struct sunxi_ccm_reg * const ccm =
522 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
523 struct sunxi_lcdc_reg * const lcdc =
524 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
525
526 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200527#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100528 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
529#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200530 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100531#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200532
533 /* Clock on */
534 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100535#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200536#ifdef CONFIG_SUNXI_GEN_SUN6I
537 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
538#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100539 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
540#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200541#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200542
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200543 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200544}
545
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100546static void sunxi_lcdc_panel_enable(void)
547{
Hans de Goedece9e3322015-02-16 17:26:41 +0100548 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100549
550 /*
551 * Start with backlight disabled to avoid the screen flashing to
552 * white while the lcd inits.
553 */
554 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200555 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100556 gpio_request(pin, "lcd_backlight_enable");
557 gpio_direction_output(pin, 0);
558 }
559
560 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200561 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100562 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100563 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100564 }
565
Hans de Goedece9e3322015-02-16 17:26:41 +0100566 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200567 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100568 gpio_request(reset_pin, "lcd_reset");
569 gpio_direction_output(reset_pin, 0); /* Assert reset */
570 }
571
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100572 /* Give the backlight some time to turn off and power up the panel. */
573 mdelay(40);
574 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200575 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100576 gpio_request(pin, "lcd_power");
577 gpio_direction_output(pin, 1);
578 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100579
Hans de Goede7783ab22015-04-22 17:45:59 +0200580 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100581 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100582}
583
584static void sunxi_lcdc_backlight_enable(void)
585{
586 int pin;
587
588 /*
589 * We want to have scanned out at least one frame before enabling the
590 * backlight to avoid the screen flashing to white when we enable it.
591 */
592 mdelay(40);
593
594 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200595 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100596 gpio_direction_output(pin, 1);
597
598 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200599#ifdef SUNXI_PWM_PIN0
600 if (pin == SUNXI_PWM_PIN0) {
601 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
602 SUNXI_PWM_CTRL_ENABLE0 |
603 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
604 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
605 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
606 return;
607 }
608#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200609 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100610 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100611}
612
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200613static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
614 struct display_timing *timing)
615{
616 timing->pixelclock.typ = mode->pixclock_khz * 1000;
617
618 timing->hactive.typ = mode->xres;
619 timing->hfront_porch.typ = mode->right_margin;
620 timing->hback_porch.typ = mode->left_margin;
621 timing->hsync_len.typ = mode->hsync_len;
622
623 timing->vactive.typ = mode->yres;
624 timing->vfront_porch.typ = mode->lower_margin;
625 timing->vback_porch.typ = mode->upper_margin;
626 timing->vsync_len.typ = mode->vsync_len;
627
Giulio Benetti105bdc62018-01-16 17:43:48 +0100628 timing->flags = 0;
629
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200630 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
631 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
632 else
633 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
634 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
635 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
636 else
637 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
638 if (mode->vmode == FB_VMODE_INTERLACED)
639 timing->flags |= DISPLAY_FLAGS_INTERLACED;
640}
641
Hans de Goede18366f72015-01-25 15:33:07 +0100642static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
643 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100644{
645 struct sunxi_lcdc_reg * const lcdc =
646 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700647 struct sunxi_ccm_reg * const ccm =
648 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200649 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200650 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100651
Lawrence Yuf721f962016-03-04 09:08:56 -0800652#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
653 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
654#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200655 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800656#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100657#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100658 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100659#endif
660#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100661 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100662#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200663#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
664 sunxi_gpio_set_drv(pin, 3);
665#endif
666 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100667
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700668 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
669 sunxi_is_composite());
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100670
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200671 sunxi_ctfb_mode_to_display_timing(mode, &timing);
672 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200673 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100674}
675
Hans de Goedec06e00e2015-08-03 19:20:26 +0200676#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100677static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100678 int *clk_div, int *clk_double,
679 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200680{
681 struct sunxi_lcdc_reg * const lcdc =
682 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700683 struct sunxi_ccm_reg * const ccm =
684 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200685 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200686
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200687 sunxi_ctfb_mode_to_display_timing(mode, &timing);
688 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200689 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200690
Hans de Goedec3d15042014-12-27 15:19:23 +0100691 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100692 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
693 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100694 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200695
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700696 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
697 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200698}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200699#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100700
701#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100702
Hans de Goedea2017e82014-12-20 13:38:06 +0100703static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
704{
705 struct sunxi_hdmi_reg * const hdmi =
706 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
707 u8 checksum = 0;
708 u8 avi_info_frame[17] = {
709 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711 0x00
712 };
713 u8 vendor_info_frame[19] = {
714 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 0x00, 0x00, 0x00
717 };
718 int i;
719
720 if (mode->pixclock_khz <= 27000)
721 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
722 else
723 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
724
725 if (mode->xres * 100 / mode->yres < 156)
726 avi_info_frame[5] |= 0x18; /* 4 : 3 */
727 else
728 avi_info_frame[5] |= 0x28; /* 16 : 9 */
729
730 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
731 checksum += avi_info_frame[i];
732
733 avi_info_frame[3] = 0x100 - checksum;
734
735 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
736 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
737
738 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
739 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
740
741 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
742 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
743
744 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
745 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
746
747 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
748}
749
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100750static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100751 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200752{
753 struct sunxi_hdmi_reg * const hdmi =
754 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
755 int x, y;
756
757 /* Write clear interrupt status bits */
758 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
759
Hans de Goedea0b1b732014-12-21 14:37:45 +0100760 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100761 sunxi_hdmi_setup_info_frames(mode);
762
Hans de Goede95576692014-12-20 13:51:16 +0100763 /* Set input sync enable */
764 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
765
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200766 /* Init various registers, select pll3 as clock source */
767 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
768 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
769 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
770 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
771 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
772
773 /* Setup clk div and doubler */
774 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
775 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
776 if (!clk_double)
777 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
778
779 /* Setup timing registers */
780 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
781 &hdmi->video_size);
782
783 x = mode->hsync_len + mode->left_margin;
784 y = mode->vsync_len + mode->upper_margin;
785 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
786
787 x = mode->right_margin;
788 y = mode->lower_margin;
789 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
790
791 x = mode->hsync_len;
792 y = mode->vsync_len;
793 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
794
795 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
796 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
797
798 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
799 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
800}
801
Hans de Goede4125f922014-12-21 14:49:34 +0100802static void sunxi_hdmi_enable(void)
803{
804 struct sunxi_hdmi_reg * const hdmi =
805 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
806
807 udelay(100);
808 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
809}
810
Hans de Goedee9544592014-12-23 23:04:35 +0100811#endif /* CONFIG_VIDEO_HDMI */
812
Hans de Goedec06e00e2015-08-03 19:20:26 +0200813#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100814
Hans de Goedec06e00e2015-08-03 19:20:26 +0200815static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100816{
817 struct sunxi_ccm_reg * const ccm =
818 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
819 struct sunxi_tve_reg * const tve =
820 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
821
Hans de Goede8a195ca2015-08-06 12:08:33 +0200822 /* Reset off */
823 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100824 /* Clock on */
825 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
826
Hans de Goedec06e00e2015-08-03 19:20:26 +0200827 switch (sunxi_display.monitor) {
828 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200829 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200830 break;
831 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200832 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
833 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200834 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200835 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200836 break;
837 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200838 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
839 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200840 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200841 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200842 break;
843 case sunxi_monitor_none:
844 case sunxi_monitor_dvi:
845 case sunxi_monitor_hdmi:
846 case sunxi_monitor_lcd:
847 break;
848 }
Hans de Goede260f5202014-12-25 13:58:06 +0100849}
850
Hans de Goedec06e00e2015-08-03 19:20:26 +0200851#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100852
Hans de Goede115e4b42014-12-23 18:39:52 +0100853static void sunxi_drc_init(void)
854{
Hans de Goedef07872b2015-04-06 20:33:34 +0200855#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100856 struct sunxi_ccm_reg * const ccm =
857 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
858
859 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530860#ifdef CONFIG_MACH_SUN8I_A33
861 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
862#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100863 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
864 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
865#endif
866}
867
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800868#ifdef CONFIG_VIDEO_VGA_VIA_LCD
869static void sunxi_vga_external_dac_enable(void)
870{
871 int pin;
872
873 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200874 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800875 gpio_request(pin, "vga_enable");
876 gpio_direction_output(pin, 1);
877 }
878}
879#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
880
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200881#ifdef CONFIG_VIDEO_LCD_SSD2828
882static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
883{
884 struct ssd2828_config cfg = {
885 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
886 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
887 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
888 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
889 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
890 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
891 .ssd2828_color_depth = 24,
892#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
893 .mipi_dsi_number_of_data_lanes = 4,
894 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
895 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
896 .mipi_dsi_delay_after_set_display_on_ms = 200
897#else
898#error MIPI LCD panel needs configuration parameters
899#endif
900 };
901
902 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
903 printf("SSD2828: SPI pins are not properly configured\n");
904 return 1;
905 }
906 if (cfg.reset_pin == -1) {
907 printf("SSD2828: Reset pin is not properly configured\n");
908 return 1;
909 }
910
911 return ssd2828_init(&cfg, mode);
912}
913#endif /* CONFIG_VIDEO_LCD_SSD2828 */
914
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200915static void sunxi_engines_init(void)
916{
917 sunxi_composer_init();
918 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100919 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200920}
921
Hans de Goedea0b1b732014-12-21 14:37:45 +0100922static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100923 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200924{
Hans de Goede260f5202014-12-25 13:58:06 +0100925 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200926 struct sunxi_lcdc_reg * const lcdc =
927 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +0200928 struct sunxi_tve_reg * __maybe_unused const tve =
929 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +0100930
Hans de Goede4125f922014-12-21 14:49:34 +0100931 switch (sunxi_display.monitor) {
932 case sunxi_monitor_none:
933 break;
934 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +0100935 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +0100936#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +0100937 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +0100938 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +0100939 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
940 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200941 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +0100942 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +0100943#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100944 break;
945 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100946 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +0200947 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
948 /*
949 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200950 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +0200951 * to avoid turning this on when using hdmi output.
952 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200953 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +0200954 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
955 ANX9804_DATA_RATE_1620M,
956 sunxi_display.depth);
957 }
Hans de Goede743fb9552015-01-20 09:23:36 +0100958 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
959 mdelay(50); /* Wait for lcd controller power on */
960 hitachi_tx18d42vm_init();
961 }
Hans de Goede613dade2015-02-16 17:49:47 +0100962 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
963 unsigned int orig_i2c_bus = i2c_get_bus_num();
964 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
965 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
966 i2c_set_bus_num(orig_i2c_bus);
967 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100968 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100969 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100970 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200971 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200972#ifdef CONFIG_VIDEO_LCD_SSD2828
973 sunxi_ssd2828_init(mode);
974#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100975 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +0100976 break;
977 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +0100978#ifdef CONFIG_VIDEO_VGA
979 sunxi_composer_mode_set(mode, address);
980 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200981 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +0100982 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200983 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200984 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +0100985#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +0100986 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100987 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +0100988 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200989 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800990 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +0100991#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100992 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200993 case sunxi_monitor_composite_pal:
994 case sunxi_monitor_composite_ntsc:
995 case sunxi_monitor_composite_pal_m:
996 case sunxi_monitor_composite_pal_nc:
997#ifdef CONFIG_VIDEO_COMPOSITE
998 sunxi_composer_mode_set(mode, address);
999 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1000 sunxi_tvencoder_mode_set();
1001 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001002 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001003 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001004#endif
1005 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001006 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001007}
1008
Hans de Goedea0b1b732014-12-21 14:37:45 +01001009static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1010{
1011 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001012 case sunxi_monitor_none: return "none";
1013 case sunxi_monitor_dvi: return "dvi";
1014 case sunxi_monitor_hdmi: return "hdmi";
1015 case sunxi_monitor_lcd: return "lcd";
1016 case sunxi_monitor_vga: return "vga";
1017 case sunxi_monitor_composite_pal: return "composite-pal";
1018 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1019 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1020 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001021 }
1022 return NULL; /* never reached */
1023}
1024
Hans de Goede6c912862015-02-02 17:13:29 +01001025ulong board_get_usable_ram_top(ulong total_size)
1026{
1027 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1028}
1029
Hans de Goedea2bba492015-08-03 23:01:38 +02001030static bool sunxi_has_hdmi(void)
1031{
1032#ifdef CONFIG_VIDEO_HDMI
1033 return true;
1034#else
1035 return false;
1036#endif
1037}
1038
1039static bool sunxi_has_lcd(void)
1040{
1041 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1042
1043 return lcd_mode[0] != 0;
1044}
1045
1046static bool sunxi_has_vga(void)
1047{
1048#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1049 return true;
1050#else
1051 return false;
1052#endif
1053}
1054
Hans de Goedec06e00e2015-08-03 19:20:26 +02001055static bool sunxi_has_composite(void)
1056{
1057#ifdef CONFIG_VIDEO_COMPOSITE
1058 return true;
1059#else
1060 return false;
1061#endif
1062}
1063
Hans de Goedea2bba492015-08-03 23:01:38 +02001064static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1065{
1066 if (allow_hdmi && sunxi_has_hdmi())
1067 return sunxi_monitor_dvi;
1068 else if (sunxi_has_lcd())
1069 return sunxi_monitor_lcd;
1070 else if (sunxi_has_vga())
1071 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001072 else if (sunxi_has_composite())
1073 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001074 else
1075 return sunxi_monitor_none;
1076}
1077
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001078void *video_hw_init(void)
1079{
1080 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001081 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001082 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001083 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001084#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001085 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001086#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001087 int i, overscan_offset, overscan_x, overscan_y;
1088 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001089 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001090 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001091
1092 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1093
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001094 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1095 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001096#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001097 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001098 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001099 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001100#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001101 overscan_x = video_get_option_int(options, "overscan_x", -1);
1102 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001103 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001104 video_get_option_string(options, "monitor", mon, sizeof(mon),
1105 sunxi_get_mon_desc(sunxi_display.monitor));
1106 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1107 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1108 sunxi_display.monitor = i;
1109 break;
1110 }
1111 }
1112 if (i > SUNXI_MONITOR_LAST)
1113 printf("Unknown monitor: '%s', falling back to '%s'\n",
1114 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001115
Hans de Goede7977ec22014-12-25 13:52:04 +01001116#ifdef CONFIG_VIDEO_HDMI
1117 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1118 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1119 sunxi_display.monitor == sunxi_monitor_hdmi) {
1120 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001121 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001122 if (ret) {
1123 printf("HDMI connected: ");
1124 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1125 mode = &custom;
1126 } else if (hpd) {
1127 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001128 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001129 } /* else continue with hdmi/dvi without a cable connected */
1130 }
1131#endif
1132
Hans de Goede4125f922014-12-21 14:49:34 +01001133 switch (sunxi_display.monitor) {
1134 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001135 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001136 case sunxi_monitor_dvi:
1137 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001138 if (!sunxi_has_hdmi()) {
1139 printf("HDMI/DVI not supported on this board\n");
1140 sunxi_display.monitor = sunxi_monitor_none;
1141 return NULL;
1142 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001143 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001144 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001145 if (!sunxi_has_lcd()) {
1146 printf("LCD not supported on this board\n");
1147 sunxi_display.monitor = sunxi_monitor_none;
1148 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001149 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001150 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1151 mode = &custom;
1152 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001153 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001154 if (!sunxi_has_vga()) {
1155 printf("VGA not supported on this board\n");
1156 sunxi_display.monitor = sunxi_monitor_none;
1157 return NULL;
1158 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001159 sunxi_display.depth = 18;
1160 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001161 case sunxi_monitor_composite_pal:
1162 case sunxi_monitor_composite_ntsc:
1163 case sunxi_monitor_composite_pal_m:
1164 case sunxi_monitor_composite_pal_nc:
1165 if (!sunxi_has_composite()) {
1166 printf("Composite video not supported on this board\n");
1167 sunxi_display.monitor = sunxi_monitor_none;
1168 return NULL;
1169 }
1170 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1171 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1172 mode = &composite_video_modes[0];
1173 else
1174 mode = &composite_video_modes[1];
1175 sunxi_display.depth = 24;
1176 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001177 }
1178
Hans de Goeded955f442015-08-05 00:06:47 +02001179 /* Yes these defaults are quite high, overscan on composite sucks... */
1180 if (overscan_x == -1)
1181 overscan_x = sunxi_is_composite() ? 32 : 0;
1182 if (overscan_y == -1)
1183 overscan_y = sunxi_is_composite() ? 20 : 0;
1184
Hans de Goede18799252015-02-02 18:00:53 +01001185 sunxi_display.fb_size =
1186 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001187 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1188 /* We want to keep the fb_base for simplefb page aligned, where as
1189 * the sunxi dma engines will happily accept an unaligned address. */
1190 if (overscan_offset)
1191 sunxi_display.fb_size += 0x1000;
1192
Hans de Goede18799252015-02-02 18:00:53 +01001193 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1194 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1195 sunxi_display.fb_size >> 10,
1196 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1197 return NULL;
1198 }
1199
Hans de Goeded955f442015-08-05 00:06:47 +02001200 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1201 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001202 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001203 sunxi_get_mon_desc(sunxi_display.monitor),
1204 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001205
Hans de Goede18799252015-02-02 18:00:53 +01001206 gd->fb_base = gd->bd->bi_dram[0].start +
1207 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001208 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001209
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001210#ifdef CONFIG_EFI_LOADER
1211 efi_add_memory_map(gd->fb_base,
1212 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1213 EFI_PAGE_SHIFT,
1214 EFI_RESERVED_MEMORY_TYPE, false);
1215#endif
1216
Hans de Goeded955f442015-08-05 00:06:47 +02001217 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1218 sunxi_display.fb_addr = gd->fb_base;
1219 if (overscan_offset) {
1220 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1221 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1222 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1223 flush_cache(gd->fb_base, sunxi_display.fb_size);
1224 }
1225 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001226
1227 /*
1228 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001229 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001230 */
Hans de Goeded955f442015-08-05 00:06:47 +02001231 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001232 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1233 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001234 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1235 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1236 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001237
1238 return graphic_device;
1239}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001240
1241/*
1242 * Simplefb support.
1243 */
1244#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1245int sunxi_simplefb_setup(void *blob)
1246{
1247 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1248 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001249 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001250 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001251
Hans de Goedec3cc4262015-01-19 08:44:07 +01001252#ifdef CONFIG_MACH_SUN4I
1253#define PIPELINE_PREFIX "de_fe0-"
1254#else
1255#define PIPELINE_PREFIX
1256#endif
1257
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001258 switch (sunxi_display.monitor) {
1259 case sunxi_monitor_none:
1260 return 0;
1261 case sunxi_monitor_dvi:
1262 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001263 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001264 break;
1265 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001266 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001267 break;
1268 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001269#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001270 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001271#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001272 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001273#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001274 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001275 case sunxi_monitor_composite_pal:
1276 case sunxi_monitor_composite_ntsc:
1277 case sunxi_monitor_composite_pal_m:
1278 case sunxi_monitor_composite_pal_nc:
1279 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1280 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001281 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001282
Icenowy Zheng067a6972017-10-26 11:14:45 +08001283 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001284 if (offset < 0) {
1285 eprintf("Cannot setup simplefb: node not found\n");
1286 return 0; /* Keep older kernels working */
1287 }
1288
Hans de Goede6c912862015-02-02 17:13:29 +01001289 /*
1290 * Do not report the framebuffer as free RAM to the OS, note we cannot
1291 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1292 * and e.g. Linux refuses to iomap RAM on ARM, see:
1293 * linux/arch/arm/mm/ioremap.c around line 301.
1294 */
1295 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001296 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001297 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1298 if (ret) {
1299 eprintf("Cannot setup simplefb: Error reserving memory\n");
1300 return ret;
1301 }
1302
Hans de Goeded955f442015-08-05 00:06:47 +02001303 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001304 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001305 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001306 if (ret)
1307 eprintf("Cannot setup simplefb: Error setting properties\n");
1308
1309 return ret;
1310}
1311#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */