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