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