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