common: Move ARM cache operations out of common.h
[platform/kernel/u-boot.git] / drivers / video / sunxi / sunxi_display.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Display driver for Allwinner SoCs.
4  *
5  * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
6  * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
7  */
8
9 #include <common.h>
10 #include <cpu_func.h>
11 #include <efi_loader.h>
12 #include <time.h>
13
14 #include <asm/arch/clock.h>
15 #include <asm/arch/display.h>
16 #include <asm/arch/gpio.h>
17 #include <asm/arch/lcdc.h>
18 #include <asm/arch/pwm.h>
19 #include <asm/arch/tve.h>
20 #include <asm/global_data.h>
21 #include <asm/gpio.h>
22 #include <asm/io.h>
23 #include <axp_pmic.h>
24 #include <errno.h>
25 #include <fdtdec.h>
26 #include <fdt_support.h>
27 #include <i2c.h>
28 #include <malloc.h>
29 #include <video_fb.h>
30 #include "../videomodes.h"
31 #include "../anx9804.h"
32 #include "../hitachi_tx18d42vm_lcd.h"
33 #include "../ssd2828.h"
34 #include "simplefb_common.h"
35
36 #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
37 #define PWM_ON 0
38 #define PWM_OFF 1
39 #else
40 #define PWM_ON 1
41 #define PWM_OFF 0
42 #endif
43
44 DECLARE_GLOBAL_DATA_PTR;
45
46 enum sunxi_monitor {
47         sunxi_monitor_none,
48         sunxi_monitor_dvi,
49         sunxi_monitor_hdmi,
50         sunxi_monitor_lcd,
51         sunxi_monitor_vga,
52         sunxi_monitor_composite_pal,
53         sunxi_monitor_composite_ntsc,
54         sunxi_monitor_composite_pal_m,
55         sunxi_monitor_composite_pal_nc,
56 };
57 #define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
58
59 struct sunxi_display {
60         GraphicDevice graphic_device;
61         enum sunxi_monitor monitor;
62         unsigned int depth;
63         unsigned int fb_addr;
64         unsigned int fb_size;
65 } sunxi_display;
66
67 const struct ctfb_res_modes composite_video_modes[2] = {
68         /*  x     y  hz  pixclk ps/kHz   le   ri  up  lo   hs vs  s  vmode */
69         { 720,  576, 50, 37037,  27000, 137,   5, 20, 27,   2, 2, 0, FB_VMODE_INTERLACED },
70         { 720,  480, 60, 37037,  27000, 116,  20, 16, 27,   2, 2, 0, FB_VMODE_INTERLACED },
71 };
72
73 #ifdef CONFIG_VIDEO_HDMI
74
75 /*
76  * Wait up to 200ms for value to be set in given part of reg.
77  */
78 static int await_completion(u32 *reg, u32 mask, u32 val)
79 {
80         unsigned long tmo = timer_get_us() + 200000;
81
82         while ((readl(reg) & mask) != val) {
83                 if (timer_get_us() > tmo) {
84                         printf("DDC: timeout reading EDID\n");
85                         return -ETIME;
86                 }
87         }
88         return 0;
89 }
90
91 static int sunxi_hdmi_hpd_detect(int hpd_delay)
92 {
93         struct sunxi_ccm_reg * const ccm =
94                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
95         struct sunxi_hdmi_reg * const hdmi =
96                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
97         unsigned long tmo = timer_get_us() + hpd_delay * 1000;
98
99         /* Set pll3 to 300MHz */
100         clock_set_pll3(300000000);
101
102         /* Set hdmi parent to pll3 */
103         clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
104                         CCM_HDMI_CTRL_PLL3);
105
106         /* Set ahb gating to pass */
107 #ifdef CONFIG_SUNXI_GEN_SUN6I
108         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
109 #endif
110         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
111
112         /* Clock on */
113         setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
114
115         writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
116         writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
117
118         /* Enable PLLs for eventual DDC */
119         writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
120                &hdmi->pad_ctrl1);
121         writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
122                &hdmi->pll_ctrl);
123         writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
124
125         while (timer_get_us() < tmo) {
126                 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
127                         return 1;
128         }
129
130         return 0;
131 }
132
133 static void sunxi_hdmi_shutdown(void)
134 {
135         struct sunxi_ccm_reg * const ccm =
136                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
137         struct sunxi_hdmi_reg * const hdmi =
138                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
139
140         clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
141         clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
142         clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
143 #ifdef CONFIG_SUNXI_GEN_SUN6I
144         clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
145 #endif
146         clock_set_pll3(0);
147 }
148
149 static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
150 {
151         struct sunxi_hdmi_reg * const hdmi =
152                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
153
154         setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
155         writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
156                SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
157                SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
158                SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
159 #ifndef CONFIG_MACH_SUN6I
160         writel(n, &hdmi->ddc_byte_count);
161         writel(cmnd, &hdmi->ddc_cmnd);
162 #else
163         writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
164 #endif
165         setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
166
167         return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
168 }
169
170 static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
171 {
172         struct sunxi_hdmi_reg * const hdmi =
173                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
174         int i, n;
175
176         while (count > 0) {
177                 if (count > 16)
178                         n = 16;
179                 else
180                         n = count;
181
182                 if (sunxi_hdmi_ddc_do_command(
183                                 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
184                                 offset, n))
185                         return -ETIME;
186
187                 for (i = 0; i < n; i++)
188                         *buf++ = readb(&hdmi->ddc_fifo_data);
189
190                 offset += n;
191                 count -= n;
192         }
193
194         return 0;
195 }
196
197 static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
198 {
199         int r, retries = 2;
200
201         do {
202                 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
203                 if (r)
204                         continue;
205                 r = edid_check_checksum(buf);
206                 if (r) {
207                         printf("EDID block %d: checksum error%s\n",
208                                block, retries ? ", retrying" : "");
209                 }
210         } while (r && retries--);
211
212         return r;
213 }
214
215 static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
216                                     bool verbose_mode)
217 {
218         struct edid1_info edid1;
219         struct edid_cea861_info cea681[4];
220         struct edid_detailed_timing *t =
221                 (struct edid_detailed_timing *)edid1.monitor_details.timing;
222         struct sunxi_hdmi_reg * const hdmi =
223                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
224         struct sunxi_ccm_reg * const ccm =
225                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
226         int i, r, ext_blocks = 0;
227
228         /* Reset i2c controller */
229         setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
230         writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
231                SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
232                SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
233                SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
234         if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
235                 return -EIO;
236
237         writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
238 #ifndef CONFIG_MACH_SUN6I
239         writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
240                SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
241 #endif
242
243         r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
244         if (r == 0) {
245                 r = edid_check_info(&edid1);
246                 if (r) {
247                         if (verbose_mode)
248                                 printf("EDID: invalid EDID data\n");
249                         r = -EINVAL;
250                 }
251         }
252         if (r == 0) {
253                 ext_blocks = edid1.extension_flag;
254                 if (ext_blocks > 4)
255                         ext_blocks = 4;
256                 for (i = 0; i < ext_blocks; i++) {
257                         if (sunxi_hdmi_edid_get_block(1 + i,
258                                                 (u8 *)&cea681[i]) != 0) {
259                                 ext_blocks = i;
260                                 break;
261                         }
262                 }
263         }
264
265         /* Disable DDC engine, no longer needed */
266         clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
267         clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
268
269         if (r)
270                 return r;
271
272         /* We want version 1.3 or 1.2 with detailed timing info */
273         if (edid1.version != 1 || (edid1.revision < 3 &&
274                         !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
275                 printf("EDID: unsupported version %d.%d\n",
276                        edid1.version, edid1.revision);
277                 return -EINVAL;
278         }
279
280         /* Take the first usable detailed timing */
281         for (i = 0; i < 4; i++, t++) {
282                 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
283                 if (r == 0)
284                         break;
285         }
286         if (i == 4) {
287                 printf("EDID: no usable detailed timing found\n");
288                 return -ENOENT;
289         }
290
291         /* Check for basic audio support, if found enable hdmi output */
292         sunxi_display.monitor = sunxi_monitor_dvi;
293         for (i = 0; i < ext_blocks; i++) {
294                 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
295                     cea681[i].revision < 2)
296                         continue;
297
298                 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
299                         sunxi_display.monitor = sunxi_monitor_hdmi;
300         }
301
302         return 0;
303 }
304
305 #endif /* CONFIG_VIDEO_HDMI */
306
307 #ifdef CONFIG_MACH_SUN4I
308 /*
309  * Testing has shown that on sun4i the display backend engine does not have
310  * deep enough fifo-s causing flickering / tearing in full-hd mode due to
311  * fifo underruns. So on sun4i we use the display frontend engine to do the
312  * dma from memory, as the frontend does have deep enough fifo-s.
313  */
314
315 static const u32 sun4i_vert_coef[32] = {
316         0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
317         0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
318         0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
319         0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
320         0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
321         0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
322         0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
323         0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
324 };
325
326 static const u32 sun4i_horz_coef[64] = {
327         0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
328         0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
329         0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
330         0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
331         0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
332         0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
333         0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
334         0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
335         0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
336         0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
337         0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
338         0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
339         0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
340         0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
341         0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
342         0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
343 };
344
345 static void sunxi_frontend_init(void)
346 {
347         struct sunxi_ccm_reg * const ccm =
348                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
349         struct sunxi_de_fe_reg * const de_fe =
350                 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
351         int i;
352
353         /* Clocks on */
354         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
355         setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
356         clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
357
358         setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
359
360         for (i = 0; i < 32; i++) {
361                 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
362                 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
363                 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
364                 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
365                 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
366                 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
367         }
368
369         setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
370 }
371
372 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
373                                     unsigned int address)
374 {
375         struct sunxi_de_fe_reg * const de_fe =
376                 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
377
378         setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
379         writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
380         writel(mode->xres * 4, &de_fe->ch0_stride);
381         writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
382         writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
383
384         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
385                &de_fe->ch0_insize);
386         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
387                &de_fe->ch0_outsize);
388         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
389         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
390
391         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
392                &de_fe->ch1_insize);
393         writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
394                &de_fe->ch1_outsize);
395         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
396         writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
397
398         setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
399 }
400
401 static void sunxi_frontend_enable(void)
402 {
403         struct sunxi_de_fe_reg * const de_fe =
404                 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
405
406         setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
407 }
408 #else
409 static void sunxi_frontend_init(void) {}
410 static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
411                                     unsigned int address) {}
412 static void sunxi_frontend_enable(void) {}
413 #endif
414
415 static bool sunxi_is_composite(void)
416 {
417         switch (sunxi_display.monitor) {
418         case sunxi_monitor_none:
419         case sunxi_monitor_dvi:
420         case sunxi_monitor_hdmi:
421         case sunxi_monitor_lcd:
422         case sunxi_monitor_vga:
423                 return false;
424         case sunxi_monitor_composite_pal:
425         case sunxi_monitor_composite_ntsc:
426         case sunxi_monitor_composite_pal_m:
427         case sunxi_monitor_composite_pal_nc:
428                 return true;
429         }
430
431         return false; /* Never reached */
432 }
433
434 /*
435  * This is the entity that mixes and matches the different layers and inputs.
436  * Allwinner calls it the back-end, but i like composer better.
437  */
438 static void sunxi_composer_init(void)
439 {
440         struct sunxi_ccm_reg * const ccm =
441                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
442         struct sunxi_de_be_reg * const de_be =
443                 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
444         int i;
445
446         sunxi_frontend_init();
447
448 #ifdef CONFIG_SUNXI_GEN_SUN6I
449         /* Reset off */
450         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
451 #endif
452
453         /* Clocks on */
454         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
455 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
456         setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
457 #endif
458         clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
459
460         /* Engine bug, clear registers after reset */
461         for (i = 0x0800; i < 0x1000; i += 4)
462                 writel(0, SUNXI_DE_BE0_BASE + i);
463
464         setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
465 }
466
467 static const u32 sunxi_rgb2yuv_coef[12] = {
468         0x00000107, 0x00000204, 0x00000064, 0x00000108,
469         0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
470         0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
471 };
472
473 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
474                                     unsigned int address)
475 {
476         struct sunxi_de_be_reg * const de_be =
477                 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
478         int i;
479
480         sunxi_frontend_mode_set(mode, address);
481
482         writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
483                &de_be->disp_size);
484         writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
485                &de_be->layer0_size);
486 #ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
487         writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
488         writel(address << 3, &de_be->layer0_addr_low32b);
489         writel(address >> 29, &de_be->layer0_addr_high4b);
490 #else
491         writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
492 #endif
493         writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
494
495         setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
496         if (mode->vmode == FB_VMODE_INTERLACED)
497                 setbits_le32(&de_be->mode,
498 #ifndef CONFIG_MACH_SUN5I
499                              SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
500 #endif
501                              SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
502
503         if (sunxi_is_composite()) {
504                 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
505                        &de_be->output_color_ctrl);
506                 for (i = 0; i < 12; i++)
507                         writel(sunxi_rgb2yuv_coef[i],
508                                &de_be->output_color_coef[i]);
509         }
510 }
511
512 static void sunxi_composer_enable(void)
513 {
514         struct sunxi_de_be_reg * const de_be =
515                 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
516
517         sunxi_frontend_enable();
518
519         setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
520         setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
521 }
522
523 static void sunxi_lcdc_init(void)
524 {
525         struct sunxi_ccm_reg * const ccm =
526                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
527         struct sunxi_lcdc_reg * const lcdc =
528                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
529
530         /* Reset off */
531 #ifdef CONFIG_SUNXI_GEN_SUN6I
532         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
533 #else
534         setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
535 #endif
536
537         /* Clock on */
538         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
539 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
540 #ifdef CONFIG_SUNXI_GEN_SUN6I
541         setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
542 #else
543         setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
544 #endif
545 #endif
546
547         lcdc_init(lcdc);
548 }
549
550 static void sunxi_lcdc_panel_enable(void)
551 {
552         int pin, reset_pin;
553
554         /*
555          * Start with backlight disabled to avoid the screen flashing to
556          * white while the lcd inits.
557          */
558         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
559         if (pin >= 0) {
560                 gpio_request(pin, "lcd_backlight_enable");
561                 gpio_direction_output(pin, 0);
562         }
563
564         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
565         if (pin >= 0) {
566                 gpio_request(pin, "lcd_backlight_pwm");
567                 gpio_direction_output(pin, PWM_OFF);
568         }
569
570         reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
571         if (reset_pin >= 0) {
572                 gpio_request(reset_pin, "lcd_reset");
573                 gpio_direction_output(reset_pin, 0); /* Assert reset */
574         }
575
576         /* Give the backlight some time to turn off and power up the panel. */
577         mdelay(40);
578         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
579         if (pin >= 0) {
580                 gpio_request(pin, "lcd_power");
581                 gpio_direction_output(pin, 1);
582         }
583
584         if (reset_pin >= 0)
585                 gpio_direction_output(reset_pin, 1); /* De-assert reset */
586 }
587
588 static void sunxi_lcdc_backlight_enable(void)
589 {
590         int pin;
591
592         /*
593          * We want to have scanned out at least one frame before enabling the
594          * backlight to avoid the screen flashing to white when we enable it.
595          */
596         mdelay(40);
597
598         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
599         if (pin >= 0)
600                 gpio_direction_output(pin, 1);
601
602         pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
603 #ifdef SUNXI_PWM_PIN0
604         if (pin == SUNXI_PWM_PIN0) {
605                 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
606                        SUNXI_PWM_CTRL_ENABLE0 |
607                        SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
608                 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
609                 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
610                 return;
611         }
612 #endif
613         if (pin >= 0)
614                 gpio_direction_output(pin, PWM_ON);
615 }
616
617 static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
618                                               struct display_timing *timing)
619 {
620         timing->pixelclock.typ = mode->pixclock_khz * 1000;
621
622         timing->hactive.typ = mode->xres;
623         timing->hfront_porch.typ = mode->right_margin;
624         timing->hback_porch.typ = mode->left_margin;
625         timing->hsync_len.typ = mode->hsync_len;
626
627         timing->vactive.typ = mode->yres;
628         timing->vfront_porch.typ = mode->lower_margin;
629         timing->vback_porch.typ = mode->upper_margin;
630         timing->vsync_len.typ = mode->vsync_len;
631
632         timing->flags = 0;
633
634         if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
635                 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
636         else
637                 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
638         if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
639                 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
640         else
641                 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
642         if (mode->vmode == FB_VMODE_INTERLACED)
643                 timing->flags |= DISPLAY_FLAGS_INTERLACED;
644 }
645
646 static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
647                                       bool for_ext_vga_dac)
648 {
649         struct sunxi_lcdc_reg * const lcdc =
650                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
651         struct sunxi_ccm_reg * const ccm =
652                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
653         int clk_div, clk_double, pin;
654         struct display_timing timing;
655
656 #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
657         for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
658 #else
659         for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
660 #endif
661 #ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
662                 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
663 #endif
664 #ifdef CONFIG_VIDEO_LCD_IF_LVDS
665                 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
666 #endif
667 #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
668                 sunxi_gpio_set_drv(pin, 3);
669 #endif
670         }
671
672         lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
673                      sunxi_is_composite());
674
675         sunxi_ctfb_mode_to_display_timing(mode, &timing);
676         lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
677                             sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
678 }
679
680 #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
681 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
682                                       int *clk_div, int *clk_double,
683                                       bool use_portd_hvsync)
684 {
685         struct sunxi_lcdc_reg * const lcdc =
686                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
687         struct sunxi_ccm_reg * const ccm =
688                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
689         struct display_timing timing;
690
691         sunxi_ctfb_mode_to_display_timing(mode, &timing);
692         lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
693                             sunxi_is_composite());
694
695         if (use_portd_hvsync) {
696                 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
697                 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
698         }
699
700         lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
701                      sunxi_is_composite());
702 }
703 #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
704
705 #ifdef CONFIG_VIDEO_HDMI
706
707 static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
708 {
709         struct sunxi_hdmi_reg * const hdmi =
710                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
711         u8 checksum = 0;
712         u8 avi_info_frame[17] = {
713                 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
714                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715                 0x00
716         };
717         u8 vendor_info_frame[19] = {
718                 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
719                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
720                 0x00, 0x00, 0x00
721         };
722         int i;
723
724         if (mode->pixclock_khz <= 27000)
725                 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
726         else
727                 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
728
729         if (mode->xres * 100 / mode->yres < 156)
730                 avi_info_frame[5] |= 0x18; /* 4 : 3 */
731         else
732                 avi_info_frame[5] |= 0x28; /* 16 : 9 */
733
734         for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
735                 checksum += avi_info_frame[i];
736
737         avi_info_frame[3] = 0x100 - checksum;
738
739         for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
740                 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
741
742         writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
743         writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
744
745         for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
746                 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
747
748         writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
749         writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
750
751         setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
752 }
753
754 static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
755                                 int clk_div, int clk_double)
756 {
757         struct sunxi_hdmi_reg * const hdmi =
758                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
759         int x, y;
760
761         /* Write clear interrupt status bits */
762         writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
763
764         if (sunxi_display.monitor == sunxi_monitor_hdmi)
765                 sunxi_hdmi_setup_info_frames(mode);
766
767         /* Set input sync enable */
768         writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
769
770         /* Init various registers, select pll3 as clock source */
771         writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
772         writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
773         writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
774         writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
775         writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
776
777         /* Setup clk div and doubler */
778         clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
779                         SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
780         if (!clk_double)
781                 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
782
783         /* Setup timing registers */
784         writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
785                &hdmi->video_size);
786
787         x = mode->hsync_len + mode->left_margin;
788         y = mode->vsync_len + mode->upper_margin;
789         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
790
791         x = mode->right_margin;
792         y = mode->lower_margin;
793         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
794
795         x = mode->hsync_len;
796         y = mode->vsync_len;
797         writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
798
799         if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
800                 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
801
802         if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
803                 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
804 }
805
806 static void sunxi_hdmi_enable(void)
807 {
808         struct sunxi_hdmi_reg * const hdmi =
809                 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
810
811         udelay(100);
812         setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
813 }
814
815 #endif /* CONFIG_VIDEO_HDMI */
816
817 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
818
819 static void sunxi_tvencoder_mode_set(void)
820 {
821         struct sunxi_ccm_reg * const ccm =
822                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
823         struct sunxi_tve_reg * const tve =
824                 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
825
826         /* Reset off */
827         setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
828         /* Clock on */
829         setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
830
831         switch (sunxi_display.monitor) {
832         case sunxi_monitor_vga:
833                 tvencoder_mode_set(tve, tve_mode_vga);
834                 break;
835         case sunxi_monitor_composite_pal_nc:
836                 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
837                 break;
838         case sunxi_monitor_composite_pal:
839                 tvencoder_mode_set(tve, tve_mode_composite_pal);
840                 break;
841         case sunxi_monitor_composite_pal_m:
842                 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
843                 break;
844         case sunxi_monitor_composite_ntsc:
845                 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
846                 break;
847         case sunxi_monitor_none:
848         case sunxi_monitor_dvi:
849         case sunxi_monitor_hdmi:
850         case sunxi_monitor_lcd:
851                 break;
852         }
853 }
854
855 #endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
856
857 static void sunxi_drc_init(void)
858 {
859 #ifdef CONFIG_SUNXI_GEN_SUN6I
860         struct sunxi_ccm_reg * const ccm =
861                 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
862
863         /* On sun6i the drc must be clocked even when in pass-through mode */
864 #ifdef CONFIG_MACH_SUN8I_A33
865         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
866 #endif
867         setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
868         clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
869 #endif
870 }
871
872 #ifdef CONFIG_VIDEO_VGA_VIA_LCD
873 static void sunxi_vga_external_dac_enable(void)
874 {
875         int pin;
876
877         pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
878         if (pin >= 0) {
879                 gpio_request(pin, "vga_enable");
880                 gpio_direction_output(pin, 1);
881         }
882 }
883 #endif /* CONFIG_VIDEO_VGA_VIA_LCD */
884
885 #ifdef CONFIG_VIDEO_LCD_SSD2828
886 static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
887 {
888         struct ssd2828_config cfg = {
889                 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
890                 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
891                 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
892                 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
893                 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
894                 .ssd2828_tx_clk_khz  = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
895                 .ssd2828_color_depth = 24,
896 #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
897                 .mipi_dsi_number_of_data_lanes           = 4,
898                 .mipi_dsi_bitrate_per_data_lane_mbps     = 513,
899                 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
900                 .mipi_dsi_delay_after_set_display_on_ms  = 200
901 #else
902 #error MIPI LCD panel needs configuration parameters
903 #endif
904         };
905
906         if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
907                 printf("SSD2828: SPI pins are not properly configured\n");
908                 return 1;
909         }
910         if (cfg.reset_pin == -1) {
911                 printf("SSD2828: Reset pin is not properly configured\n");
912                 return 1;
913         }
914
915         return ssd2828_init(&cfg, mode);
916 }
917 #endif /* CONFIG_VIDEO_LCD_SSD2828 */
918
919 static void sunxi_engines_init(void)
920 {
921         sunxi_composer_init();
922         sunxi_lcdc_init();
923         sunxi_drc_init();
924 }
925
926 static void sunxi_mode_set(const struct ctfb_res_modes *mode,
927                            unsigned int address)
928 {
929         int __maybe_unused clk_div, clk_double;
930         struct sunxi_lcdc_reg * const lcdc =
931                 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
932         struct sunxi_tve_reg * __maybe_unused const tve =
933                 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
934
935         switch (sunxi_display.monitor) {
936         case sunxi_monitor_none:
937                 break;
938         case sunxi_monitor_dvi:
939         case sunxi_monitor_hdmi:
940 #ifdef CONFIG_VIDEO_HDMI
941                 sunxi_composer_mode_set(mode, address);
942                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
943                 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
944                 sunxi_composer_enable();
945                 lcdc_enable(lcdc, sunxi_display.depth);
946                 sunxi_hdmi_enable();
947 #endif
948                 break;
949         case sunxi_monitor_lcd:
950                 sunxi_lcdc_panel_enable();
951                 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
952                         /*
953                          * The anx9804 needs 1.8V from eldo3, we do this here
954                          * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
955                          * to avoid turning this on when using hdmi output.
956                          */
957                         axp_set_eldo(3, 1800);
958                         anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
959                                      ANX9804_DATA_RATE_1620M,
960                                      sunxi_display.depth);
961                 }
962                 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
963                         mdelay(50); /* Wait for lcd controller power on */
964                         hitachi_tx18d42vm_init();
965                 }
966                 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
967                         unsigned int orig_i2c_bus = i2c_get_bus_num();
968                         i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
969                         i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
970                         i2c_set_bus_num(orig_i2c_bus);
971                 }
972                 sunxi_composer_mode_set(mode, address);
973                 sunxi_lcdc_tcon0_mode_set(mode, false);
974                 sunxi_composer_enable();
975                 lcdc_enable(lcdc, sunxi_display.depth);
976 #ifdef CONFIG_VIDEO_LCD_SSD2828
977                 sunxi_ssd2828_init(mode);
978 #endif
979                 sunxi_lcdc_backlight_enable();
980                 break;
981         case sunxi_monitor_vga:
982 #ifdef CONFIG_VIDEO_VGA
983                 sunxi_composer_mode_set(mode, address);
984                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
985                 sunxi_tvencoder_mode_set();
986                 sunxi_composer_enable();
987                 lcdc_enable(lcdc, sunxi_display.depth);
988                 tvencoder_enable(tve);
989 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
990                 sunxi_composer_mode_set(mode, address);
991                 sunxi_lcdc_tcon0_mode_set(mode, true);
992                 sunxi_composer_enable();
993                 lcdc_enable(lcdc, sunxi_display.depth);
994                 sunxi_vga_external_dac_enable();
995 #endif
996                 break;
997         case sunxi_monitor_composite_pal:
998         case sunxi_monitor_composite_ntsc:
999         case sunxi_monitor_composite_pal_m:
1000         case sunxi_monitor_composite_pal_nc:
1001 #ifdef CONFIG_VIDEO_COMPOSITE
1002                 sunxi_composer_mode_set(mode, address);
1003                 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1004                 sunxi_tvencoder_mode_set();
1005                 sunxi_composer_enable();
1006                 lcdc_enable(lcdc, sunxi_display.depth);
1007                 tvencoder_enable(tve);
1008 #endif
1009                 break;
1010         }
1011 }
1012
1013 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1014 {
1015         switch (monitor) {
1016         case sunxi_monitor_none:                return "none";
1017         case sunxi_monitor_dvi:                 return "dvi";
1018         case sunxi_monitor_hdmi:                return "hdmi";
1019         case sunxi_monitor_lcd:                 return "lcd";
1020         case sunxi_monitor_vga:                 return "vga";
1021         case sunxi_monitor_composite_pal:       return "composite-pal";
1022         case sunxi_monitor_composite_ntsc:      return "composite-ntsc";
1023         case sunxi_monitor_composite_pal_m:     return "composite-pal-m";
1024         case sunxi_monitor_composite_pal_nc:    return "composite-pal-nc";
1025         }
1026         return NULL; /* never reached */
1027 }
1028
1029 ulong board_get_usable_ram_top(ulong total_size)
1030 {
1031         return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1032 }
1033
1034 static bool sunxi_has_hdmi(void)
1035 {
1036 #ifdef CONFIG_VIDEO_HDMI
1037         return true;
1038 #else
1039         return false;
1040 #endif
1041 }
1042
1043 static bool sunxi_has_lcd(void)
1044 {
1045         char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1046
1047         return lcd_mode[0] != 0;
1048 }
1049
1050 static bool sunxi_has_vga(void)
1051 {
1052 #if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1053         return true;
1054 #else
1055         return false;
1056 #endif
1057 }
1058
1059 static bool sunxi_has_composite(void)
1060 {
1061 #ifdef CONFIG_VIDEO_COMPOSITE
1062         return true;
1063 #else
1064         return false;
1065 #endif
1066 }
1067
1068 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1069 {
1070         if (allow_hdmi && sunxi_has_hdmi())
1071                 return sunxi_monitor_dvi;
1072         else if (sunxi_has_lcd())
1073                 return sunxi_monitor_lcd;
1074         else if (sunxi_has_vga())
1075                 return sunxi_monitor_vga;
1076         else if (sunxi_has_composite())
1077                 return sunxi_monitor_composite_pal;
1078         else
1079                 return sunxi_monitor_none;
1080 }
1081
1082 void *video_hw_init(void)
1083 {
1084         static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1085         const struct ctfb_res_modes *mode;
1086         struct ctfb_res_modes custom;
1087         const char *options;
1088 #ifdef CONFIG_VIDEO_HDMI
1089         int hpd, hpd_delay, edid;
1090         bool hdmi_present;
1091 #endif
1092         int i, overscan_offset, overscan_x, overscan_y;
1093         unsigned int fb_dma_addr;
1094         char mon[16];
1095         char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1096
1097         memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1098
1099         video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1100                                  &sunxi_display.depth, &options);
1101 #ifdef CONFIG_VIDEO_HDMI
1102         hpd = video_get_option_int(options, "hpd", 1);
1103         hpd_delay = video_get_option_int(options, "hpd_delay", 500);
1104         edid = video_get_option_int(options, "edid", 1);
1105 #endif
1106         overscan_x = video_get_option_int(options, "overscan_x", -1);
1107         overscan_y = video_get_option_int(options, "overscan_y", -1);
1108         sunxi_display.monitor = sunxi_get_default_mon(true);
1109         video_get_option_string(options, "monitor", mon, sizeof(mon),
1110                                 sunxi_get_mon_desc(sunxi_display.monitor));
1111         for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1112                 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1113                         sunxi_display.monitor = i;
1114                         break;
1115                 }
1116         }
1117         if (i > SUNXI_MONITOR_LAST)
1118                 printf("Unknown monitor: '%s', falling back to '%s'\n",
1119                        mon, sunxi_get_mon_desc(sunxi_display.monitor));
1120
1121 #ifdef CONFIG_VIDEO_HDMI
1122         /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1123         if (sunxi_display.monitor == sunxi_monitor_dvi ||
1124             sunxi_display.monitor == sunxi_monitor_hdmi) {
1125                 /* Always call hdp_detect, as it also enables clocks, etc. */
1126                 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1127                 if (hdmi_present && edid) {
1128                         printf("HDMI connected: ");
1129                         if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
1130                                 mode = &custom;
1131                         else
1132                                 hdmi_present = false;
1133                 }
1134                 /* Fall back to EDID in case HPD failed */
1135                 if (edid && !hdmi_present) {
1136                         if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1137                                 mode = &custom;
1138                                 hdmi_present = true;
1139                         }
1140                 }
1141                 /* Shut down when display was not found */
1142                 if ((hpd || edid) && !hdmi_present) {
1143                         sunxi_hdmi_shutdown();
1144                         sunxi_display.monitor = sunxi_get_default_mon(false);
1145                 } /* else continue with hdmi/dvi without a cable connected */
1146         }
1147 #endif
1148
1149         switch (sunxi_display.monitor) {
1150         case sunxi_monitor_none:
1151                 return NULL;
1152         case sunxi_monitor_dvi:
1153         case sunxi_monitor_hdmi:
1154                 if (!sunxi_has_hdmi()) {
1155                         printf("HDMI/DVI not supported on this board\n");
1156                         sunxi_display.monitor = sunxi_monitor_none;
1157                         return NULL;
1158                 }
1159                 break;
1160         case sunxi_monitor_lcd:
1161                 if (!sunxi_has_lcd()) {
1162                         printf("LCD not supported on this board\n");
1163                         sunxi_display.monitor = sunxi_monitor_none;
1164                         return NULL;
1165                 }
1166                 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1167                 mode = &custom;
1168                 break;
1169         case sunxi_monitor_vga:
1170                 if (!sunxi_has_vga()) {
1171                         printf("VGA not supported on this board\n");
1172                         sunxi_display.monitor = sunxi_monitor_none;
1173                         return NULL;
1174                 }
1175                 sunxi_display.depth = 18;
1176                 break;
1177         case sunxi_monitor_composite_pal:
1178         case sunxi_monitor_composite_ntsc:
1179         case sunxi_monitor_composite_pal_m:
1180         case sunxi_monitor_composite_pal_nc:
1181                 if (!sunxi_has_composite()) {
1182                         printf("Composite video not supported on this board\n");
1183                         sunxi_display.monitor = sunxi_monitor_none;
1184                         return NULL;
1185                 }
1186                 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1187                     sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1188                         mode = &composite_video_modes[0];
1189                 else
1190                         mode = &composite_video_modes[1];
1191                 sunxi_display.depth = 24;
1192                 break;
1193         }
1194
1195         /* Yes these defaults are quite high, overscan on composite sucks... */
1196         if (overscan_x == -1)
1197                 overscan_x = sunxi_is_composite() ? 32 : 0;
1198         if (overscan_y == -1)
1199                 overscan_y = sunxi_is_composite() ? 20 : 0;
1200
1201         sunxi_display.fb_size =
1202                 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1203         overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1204         /* We want to keep the fb_base for simplefb page aligned, where as
1205          * the sunxi dma engines will happily accept an unaligned address. */
1206         if (overscan_offset)
1207                 sunxi_display.fb_size += 0x1000;
1208
1209         if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1210                 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1211                        sunxi_display.fb_size >> 10,
1212                        CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1213                 return NULL;
1214         }
1215
1216         printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1217                mode->xres, mode->yres,
1218                (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1219                sunxi_get_mon_desc(sunxi_display.monitor),
1220                overscan_x, overscan_y);
1221
1222         gd->fb_base = gd->bd->bi_dram[0].start +
1223                       gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1224         sunxi_engines_init();
1225
1226 #ifdef CONFIG_EFI_LOADER
1227         efi_add_memory_map(gd->fb_base,
1228                            ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1229                            EFI_PAGE_SHIFT,
1230                            EFI_RESERVED_MEMORY_TYPE, false);
1231 #endif
1232
1233         fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1234         sunxi_display.fb_addr = gd->fb_base;
1235         if (overscan_offset) {
1236                 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1237                 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1238                 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1239                 flush_cache(gd->fb_base, sunxi_display.fb_size);
1240         }
1241         sunxi_mode_set(mode, fb_dma_addr);
1242
1243         /*
1244          * These are the only members of this structure that are used. All the
1245          * others are driver specific. The pitch is stored in plnSizeX.
1246          */
1247         graphic_device->frameAdrs = sunxi_display.fb_addr;
1248         graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1249         graphic_device->gdfBytesPP = 4;
1250         graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1251         graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1252         graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
1253
1254         return graphic_device;
1255 }
1256
1257 /*
1258  * Simplefb support.
1259  */
1260 #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1261 int sunxi_simplefb_setup(void *blob)
1262 {
1263         static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1264         int offset, ret;
1265         u64 start, size;
1266         const char *pipeline = NULL;
1267
1268 #ifdef CONFIG_MACH_SUN4I
1269 #define PIPELINE_PREFIX "de_fe0-"
1270 #else
1271 #define PIPELINE_PREFIX
1272 #endif
1273
1274         switch (sunxi_display.monitor) {
1275         case sunxi_monitor_none:
1276                 return 0;
1277         case sunxi_monitor_dvi:
1278         case sunxi_monitor_hdmi:
1279                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
1280                 break;
1281         case sunxi_monitor_lcd:
1282                 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1283                 break;
1284         case sunxi_monitor_vga:
1285 #ifdef CONFIG_VIDEO_VGA
1286                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1287 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1288                 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1289 #endif
1290                 break;
1291         case sunxi_monitor_composite_pal:
1292         case sunxi_monitor_composite_ntsc:
1293         case sunxi_monitor_composite_pal_m:
1294         case sunxi_monitor_composite_pal_nc:
1295                 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1296                 break;
1297         }
1298
1299         offset = sunxi_simplefb_fdt_match(blob, pipeline);
1300         if (offset < 0) {
1301                 eprintf("Cannot setup simplefb: node not found\n");
1302                 return 0; /* Keep older kernels working */
1303         }
1304
1305         /*
1306          * Do not report the framebuffer as free RAM to the OS, note we cannot
1307          * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1308          * and e.g. Linux refuses to iomap RAM on ARM, see:
1309          * linux/arch/arm/mm/ioremap.c around line 301.
1310          */
1311         start = gd->bd->bi_dram[0].start;
1312         size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
1313         ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1314         if (ret) {
1315                 eprintf("Cannot setup simplefb: Error reserving memory\n");
1316                 return ret;
1317         }
1318
1319         ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
1320                         graphic_device->winSizeX, graphic_device->winSizeY,
1321                         graphic_device->plnSizeX, "x8r8g8b8");
1322         if (ret)
1323                 eprintf("Cannot setup simplefb: Error setting properties\n");
1324
1325         return ret;
1326 }
1327 #endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */