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