blob: de768ba94a3351e08ca0a01fb5307dc7237159ff [file] [log] [blame]
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001/*
2 * Display driver for Allwinner SoCs.
3 *
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
Hans de Goedec06e00e2015-08-03 19:20:26 +02005 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02006 *
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>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020015#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020016#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020017#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020018#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010019#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020020#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020021#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010022#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020023#include <fdtdec.h>
24#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010025#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020026#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020027#include <video_fb.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020028#include "../videomodes.h"
29#include "../anx9804.h"
30#include "../hitachi_tx18d42vm_lcd.h"
31#include "../ssd2828.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020032
Hans de Goede2d5d3022015-01-22 21:02:42 +010033#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
34#define PWM_ON 0
35#define PWM_OFF 1
36#else
37#define PWM_ON 1
38#define PWM_OFF 0
39#endif
40
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020041DECLARE_GLOBAL_DATA_PTR;
42
Hans de Goedea0b1b732014-12-21 14:37:45 +010043enum sunxi_monitor {
44 sunxi_monitor_none,
45 sunxi_monitor_dvi,
46 sunxi_monitor_hdmi,
47 sunxi_monitor_lcd,
48 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020049 sunxi_monitor_composite_pal,
50 sunxi_monitor_composite_ntsc,
51 sunxi_monitor_composite_pal_m,
52 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010053};
Hans de Goedec06e00e2015-08-03 19:20:26 +020054#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010055
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020056struct sunxi_display {
57 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010058 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010059 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020060 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010061 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020062} sunxi_display;
63
Hans de Goedec06e00e2015-08-03 19:20:26 +020064const struct ctfb_res_modes composite_video_modes[2] = {
65 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
66 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
67 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
68};
69
Hans de Goedee9544592014-12-23 23:04:35 +010070#ifdef CONFIG_VIDEO_HDMI
71
Hans de Goedea5aa95f2014-12-19 16:05:12 +010072/*
73 * Wait up to 200ms for value to be set in given part of reg.
74 */
75static int await_completion(u32 *reg, u32 mask, u32 val)
76{
77 unsigned long tmo = timer_get_us() + 200000;
78
79 while ((readl(reg) & mask) != val) {
80 if (timer_get_us() > tmo) {
81 printf("DDC: timeout reading EDID\n");
82 return -ETIME;
83 }
84 }
85 return 0;
86}
87
Hans de Goede91593712014-12-28 09:13:21 +010088static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020089{
90 struct sunxi_ccm_reg * const ccm =
91 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
92 struct sunxi_hdmi_reg * const hdmi =
93 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010094 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020095
96 /* Set pll3 to 300MHz */
97 clock_set_pll3(300000000);
98
99 /* Set hdmi parent to pll3 */
100 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
101 CCM_HDMI_CTRL_PLL3);
102
103 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200104#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100105 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
106#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200107 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
108
109 /* Clock on */
110 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
111
112 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
113 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
114
Hans de Goede205a30c2014-12-20 15:15:23 +0100115 while (timer_get_us() < tmo) {
116 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
117 return 1;
118 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200119
Hans de Goede205a30c2014-12-20 15:15:23 +0100120 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100121}
122
123static void sunxi_hdmi_shutdown(void)
124{
125 struct sunxi_ccm_reg * const ccm =
126 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
127 struct sunxi_hdmi_reg * const hdmi =
128 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200129
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200130 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
131 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
132 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200133#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100134 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
135#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200136 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200137}
138
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100139static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
140{
141 struct sunxi_hdmi_reg * const hdmi =
142 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
143
144 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
145 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
146 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
147 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
148 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
149#ifndef CONFIG_MACH_SUN6I
150 writel(n, &hdmi->ddc_byte_count);
151 writel(cmnd, &hdmi->ddc_cmnd);
152#else
153 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
154#endif
155 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
156
157 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
158}
159
160static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
161{
162 struct sunxi_hdmi_reg * const hdmi =
163 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
164 int i, n;
165
166 while (count > 0) {
167 if (count > 16)
168 n = 16;
169 else
170 n = count;
171
172 if (sunxi_hdmi_ddc_do_command(
173 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
174 offset, n))
175 return -ETIME;
176
177 for (i = 0; i < n; i++)
178 *buf++ = readb(&hdmi->ddc_fifo_data);
179
180 offset += n;
181 count -= n;
182 }
183
184 return 0;
185}
186
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100187static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
188{
189 int r, retries = 2;
190
191 do {
192 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
193 if (r)
194 continue;
195 r = edid_check_checksum(buf);
196 if (r) {
197 printf("EDID block %d: checksum error%s\n",
198 block, retries ? ", retrying" : "");
199 }
200 } while (r && retries--);
201
202 return r;
203}
204
Hans de Goedea0b1b732014-12-21 14:37:45 +0100205static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100206{
207 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100208 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100209 struct edid_detailed_timing *t =
210 (struct edid_detailed_timing *)edid1.monitor_details.timing;
211 struct sunxi_hdmi_reg * const hdmi =
212 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
213 struct sunxi_ccm_reg * const ccm =
214 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100215 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100216
217 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
218 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
219 &hdmi->pad_ctrl1);
220 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
221 &hdmi->pll_ctrl);
222 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
223
224 /* Reset i2c controller */
225 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
226 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
227 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
228 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
229 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
230 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
231 return -EIO;
232
233 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
234#ifndef CONFIG_MACH_SUN6I
235 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
236 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
237#endif
238
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100239 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100240 if (r == 0) {
241 r = edid_check_info(&edid1);
242 if (r) {
243 printf("EDID: invalid EDID data\n");
244 r = -EINVAL;
245 }
246 }
247 if (r == 0) {
248 ext_blocks = edid1.extension_flag;
249 if (ext_blocks > 4)
250 ext_blocks = 4;
251 for (i = 0; i < ext_blocks; i++) {
252 if (sunxi_hdmi_edid_get_block(1 + i,
253 (u8 *)&cea681[i]) != 0) {
254 ext_blocks = i;
255 break;
256 }
257 }
258 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100259
260 /* Disable DDC engine, no longer needed */
261 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
262 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
263
264 if (r)
265 return r;
266
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100267 /* We want version 1.3 or 1.2 with detailed timing info */
268 if (edid1.version != 1 || (edid1.revision < 3 &&
269 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
270 printf("EDID: unsupported version %d.%d\n",
271 edid1.version, edid1.revision);
272 return -EINVAL;
273 }
274
275 /* Take the first usable detailed timing */
276 for (i = 0; i < 4; i++, t++) {
277 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
278 if (r == 0)
279 break;
280 }
281 if (i == 4) {
282 printf("EDID: no usable detailed timing found\n");
283 return -ENOENT;
284 }
285
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100286 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100287 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100288 for (i = 0; i < ext_blocks; i++) {
289 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
290 cea681[i].revision < 2)
291 continue;
292
293 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100294 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100295 }
296
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100297 return 0;
298}
299
Hans de Goedee9544592014-12-23 23:04:35 +0100300#endif /* CONFIG_VIDEO_HDMI */
301
Hans de Goedec3cc4262015-01-19 08:44:07 +0100302#ifdef CONFIG_MACH_SUN4I
303/*
304 * Testing has shown that on sun4i the display backend engine does not have
305 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
306 * fifo underruns. So on sun4i we use the display frontend engine to do the
307 * dma from memory, as the frontend does have deep enough fifo-s.
308 */
309
310static const u32 sun4i_vert_coef[32] = {
311 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
312 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
313 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
314 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
315 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
316 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
317 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
318 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
319};
320
321static const u32 sun4i_horz_coef[64] = {
322 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
323 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
324 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
325 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
326 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
327 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
328 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
329 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
330 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
331 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
332 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
333 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
334 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
335 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
336 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
337 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
338};
339
340static void sunxi_frontend_init(void)
341{
342 struct sunxi_ccm_reg * const ccm =
343 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
344 struct sunxi_de_fe_reg * const de_fe =
345 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
346 int i;
347
348 /* Clocks on */
349 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
350 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
351 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
352
353 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
354
355 for (i = 0; i < 32; i++) {
356 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
357 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
358 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
359 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
360 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
361 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
362 }
363
364 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
365}
366
367static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
368 unsigned int address)
369{
370 struct sunxi_de_fe_reg * const de_fe =
371 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
372
373 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
374 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
375 writel(mode->xres * 4, &de_fe->ch0_stride);
376 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
377 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
378
379 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
380 &de_fe->ch0_insize);
381 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
382 &de_fe->ch0_outsize);
383 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
384 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
385
386 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
387 &de_fe->ch1_insize);
388 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
389 &de_fe->ch1_outsize);
390 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
391 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
392
393 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
394}
395
396static void sunxi_frontend_enable(void)
397{
398 struct sunxi_de_fe_reg * const de_fe =
399 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
400
401 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
402}
403#else
404static void sunxi_frontend_init(void) {}
405static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
406 unsigned int address) {}
407static void sunxi_frontend_enable(void) {}
408#endif
409
Hans de Goedec06e00e2015-08-03 19:20:26 +0200410static bool sunxi_is_composite(void)
411{
412 switch (sunxi_display.monitor) {
413 case sunxi_monitor_none:
414 case sunxi_monitor_dvi:
415 case sunxi_monitor_hdmi:
416 case sunxi_monitor_lcd:
417 case sunxi_monitor_vga:
418 return false;
419 case sunxi_monitor_composite_pal:
420 case sunxi_monitor_composite_ntsc:
421 case sunxi_monitor_composite_pal_m:
422 case sunxi_monitor_composite_pal_nc:
423 return true;
424 }
425
426 return false; /* Never reached */
427}
428
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200429/*
430 * This is the entity that mixes and matches the different layers and inputs.
431 * Allwinner calls it the back-end, but i like composer better.
432 */
433static void sunxi_composer_init(void)
434{
435 struct sunxi_ccm_reg * const ccm =
436 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
437 struct sunxi_de_be_reg * const de_be =
438 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
439 int i;
440
Hans de Goedec3cc4262015-01-19 08:44:07 +0100441 sunxi_frontend_init();
442
Hans de Goedef07872b2015-04-06 20:33:34 +0200443#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100444 /* Reset off */
445 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
446#endif
447
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200448 /* Clocks on */
449 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100450#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200451 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100452#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200453 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
454
455 /* Engine bug, clear registers after reset */
456 for (i = 0x0800; i < 0x1000; i += 4)
457 writel(0, SUNXI_DE_BE0_BASE + i);
458
459 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
460}
461
Hans de Goedec06e00e2015-08-03 19:20:26 +0200462static u32 sunxi_rgb2yuv_coef[12] = {
463 0x00000107, 0x00000204, 0x00000064, 0x00000108,
464 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
465 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
466};
467
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100468static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200469 unsigned int address)
470{
471 struct sunxi_de_be_reg * const de_be =
472 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200473 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200474
Hans de Goedec3cc4262015-01-19 08:44:07 +0100475 sunxi_frontend_mode_set(mode, address);
476
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200477 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
478 &de_be->disp_size);
479 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
480 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100481#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200482 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
483 writel(address << 3, &de_be->layer0_addr_low32b);
484 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100485#else
486 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
487#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200488 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
489
490 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200491 if (mode->vmode == FB_VMODE_INTERLACED)
492 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200493#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200494 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200495#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200496 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200497
498 if (sunxi_is_composite()) {
499 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
500 &de_be->output_color_ctrl);
501 for (i = 0; i < 12; i++)
502 writel(sunxi_rgb2yuv_coef[i],
503 &de_be->output_color_coef[i]);
504 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200505}
506
Hans de Goede4125f922014-12-21 14:49:34 +0100507static void sunxi_composer_enable(void)
508{
509 struct sunxi_de_be_reg * const de_be =
510 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
511
Hans de Goedec3cc4262015-01-19 08:44:07 +0100512 sunxi_frontend_enable();
513
Hans de Goede4125f922014-12-21 14:49:34 +0100514 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
515 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
516}
517
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200518/*
519 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
520 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100521static void sunxi_lcdc_pll_set(int tcon, int dotclock,
522 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200523{
524 struct sunxi_ccm_reg * const ccm =
525 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100526 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200527 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
528 int best_double = 0;
Hans de Goede13365782015-08-08 14:08:21 +0200529 bool use_mipi_pll = false;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200530
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100531 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100532#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100533 min_m = 6;
534 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100535#endif
536#ifdef CONFIG_VIDEO_LCD_IF_LVDS
537 min_m = max_m = 7;
538#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100539 } else {
540 min_m = 1;
541 max_m = 15;
542 }
543
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200544 /*
545 * Find the lowest divider resulting in a matching clock, if there
546 * is no match, pick the closest lower clock, as monitors tend to
547 * not sync to higher frequencies.
548 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100549 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200550 n = (m * dotclock) / 3000;
551
552 if ((n >= 9) && (n <= 127)) {
553 value = (3000 * n) / m;
554 diff = dotclock - value;
555 if (diff < best_diff) {
556 best_diff = diff;
557 best_m = m;
558 best_n = n;
559 best_double = 0;
560 }
561 }
562
563 /* These are just duplicates */
564 if (!(m & 1))
565 continue;
566
567 n = (m * dotclock) / 6000;
568 if ((n >= 9) && (n <= 127)) {
569 value = (6000 * n) / m;
570 diff = dotclock - value;
571 if (diff < best_diff) {
572 best_diff = diff;
573 best_m = m;
574 best_n = n;
575 best_double = 1;
576 }
577 }
578 }
579
Hans de Goede13365782015-08-08 14:08:21 +0200580#ifdef CONFIG_MACH_SUN6I
581 /*
582 * Use the MIPI pll if we've been unable to find any matching setting
583 * for PLL3, this happens with high dotclocks because of min_m = 6.
584 */
585 if (tcon == 0 && best_n == 0) {
586 use_mipi_pll = true;
587 best_m = 6; /* Minimum m for tcon0 */
588 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200589
Hans de Goede13365782015-08-08 14:08:21 +0200590 if (use_mipi_pll) {
591 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
592 clock_set_mipi_pll(best_m * dotclock * 1000);
593 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
594 dotclock, clock_get_mipi_pll() / best_m / 1000);
595 } else
596#endif
597 {
598 clock_set_pll3(best_n * 3000000);
599 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
600 dotclock,
601 (best_double + 1) * clock_get_pll3() / best_m / 1000,
602 best_double + 1, best_n, best_m);
603 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200604
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100605 if (tcon == 0) {
Hans de Goede13365782015-08-08 14:08:21 +0200606 u32 pll;
607
608 if (use_mipi_pll)
609 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
610 else if (best_double)
611 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
612 else
613 pll = CCM_LCD_CH0_CTRL_PLL3;
614
615 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100616 &ccm->lcd0_ch0_clk_cfg);
617 } else {
618 writel(CCM_LCD_CH1_CTRL_GATE |
619 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
620 CCM_LCD_CH1_CTRL_PLL3) |
621 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200622 if (sunxi_is_composite())
623 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
624 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100625 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200626
627 *clk_div = best_m;
628 *clk_double = best_double;
629}
630
631static void sunxi_lcdc_init(void)
632{
633 struct sunxi_ccm_reg * const ccm =
634 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
635 struct sunxi_lcdc_reg * const lcdc =
636 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
637
638 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200639#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100640 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
641#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200642 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100643#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200644
645 /* Clock on */
646 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100647#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200648#ifdef CONFIG_SUNXI_GEN_SUN6I
649 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
650#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100651 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
652#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200653#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200654
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200655 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200656}
657
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100658static void sunxi_lcdc_panel_enable(void)
659{
Hans de Goedece9e3322015-02-16 17:26:41 +0100660 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100661
662 /*
663 * Start with backlight disabled to avoid the screen flashing to
664 * white while the lcd inits.
665 */
666 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200667 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100668 gpio_request(pin, "lcd_backlight_enable");
669 gpio_direction_output(pin, 0);
670 }
671
672 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200673 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100674 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100675 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100676 }
677
Hans de Goedece9e3322015-02-16 17:26:41 +0100678 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200679 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100680 gpio_request(reset_pin, "lcd_reset");
681 gpio_direction_output(reset_pin, 0); /* Assert reset */
682 }
683
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100684 /* Give the backlight some time to turn off and power up the panel. */
685 mdelay(40);
686 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200687 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100688 gpio_request(pin, "lcd_power");
689 gpio_direction_output(pin, 1);
690 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100691
Hans de Goede7783ab22015-04-22 17:45:59 +0200692 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100693 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100694}
695
696static void sunxi_lcdc_backlight_enable(void)
697{
698 int pin;
699
700 /*
701 * We want to have scanned out at least one frame before enabling the
702 * backlight to avoid the screen flashing to white when we enable it.
703 */
704 mdelay(40);
705
706 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200707 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100708 gpio_direction_output(pin, 1);
709
710 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200711#ifdef SUNXI_PWM_PIN0
712 if (pin == SUNXI_PWM_PIN0) {
713 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
714 SUNXI_PWM_CTRL_ENABLE0 |
715 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
716 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
717 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
718 return;
719 }
720#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200721 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100722 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100723}
724
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200725static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
726 struct display_timing *timing)
727{
728 timing->pixelclock.typ = mode->pixclock_khz * 1000;
729
730 timing->hactive.typ = mode->xres;
731 timing->hfront_porch.typ = mode->right_margin;
732 timing->hback_porch.typ = mode->left_margin;
733 timing->hsync_len.typ = mode->hsync_len;
734
735 timing->vactive.typ = mode->yres;
736 timing->vfront_porch.typ = mode->lower_margin;
737 timing->vback_porch.typ = mode->upper_margin;
738 timing->vsync_len.typ = mode->vsync_len;
739
740 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
741 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
742 else
743 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
744 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
745 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
746 else
747 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
748 if (mode->vmode == FB_VMODE_INTERLACED)
749 timing->flags |= DISPLAY_FLAGS_INTERLACED;
750}
751
Hans de Goede18366f72015-01-25 15:33:07 +0100752static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
753 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100754{
755 struct sunxi_lcdc_reg * const lcdc =
756 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200757 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200758 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100759
Lawrence Yuf721f962016-03-04 09:08:56 -0800760#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
761 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
762#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200763 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800764#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100765#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100766 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100767#endif
768#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100769 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100770#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200771#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
772 sunxi_gpio_set_drv(pin, 3);
773#endif
774 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100775
776 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
777
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200778 sunxi_ctfb_mode_to_display_timing(mode, &timing);
779 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200780 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100781}
782
Hans de Goedec06e00e2015-08-03 19:20:26 +0200783#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100784static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100785 int *clk_div, int *clk_double,
786 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200787{
788 struct sunxi_lcdc_reg * const lcdc =
789 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200790 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200791
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200792 sunxi_ctfb_mode_to_display_timing(mode, &timing);
793 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200794 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200795
Hans de Goedec3d15042014-12-27 15:19:23 +0100796 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100797 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
798 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100799 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200800
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100801 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200802}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200803#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100804
805#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100806
Hans de Goedea2017e82014-12-20 13:38:06 +0100807static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
808{
809 struct sunxi_hdmi_reg * const hdmi =
810 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
811 u8 checksum = 0;
812 u8 avi_info_frame[17] = {
813 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00
816 };
817 u8 vendor_info_frame[19] = {
818 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820 0x00, 0x00, 0x00
821 };
822 int i;
823
824 if (mode->pixclock_khz <= 27000)
825 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
826 else
827 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
828
829 if (mode->xres * 100 / mode->yres < 156)
830 avi_info_frame[5] |= 0x18; /* 4 : 3 */
831 else
832 avi_info_frame[5] |= 0x28; /* 16 : 9 */
833
834 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
835 checksum += avi_info_frame[i];
836
837 avi_info_frame[3] = 0x100 - checksum;
838
839 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
840 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
841
842 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
843 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
844
845 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
846 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
847
848 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
849 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
850
851 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
852}
853
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100854static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100855 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200856{
857 struct sunxi_hdmi_reg * const hdmi =
858 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
859 int x, y;
860
861 /* Write clear interrupt status bits */
862 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
863
Hans de Goedea0b1b732014-12-21 14:37:45 +0100864 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100865 sunxi_hdmi_setup_info_frames(mode);
866
Hans de Goede95576692014-12-20 13:51:16 +0100867 /* Set input sync enable */
868 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
869
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200870 /* Init various registers, select pll3 as clock source */
871 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
872 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
873 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
874 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
875 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
876
877 /* Setup clk div and doubler */
878 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
879 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
880 if (!clk_double)
881 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
882
883 /* Setup timing registers */
884 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
885 &hdmi->video_size);
886
887 x = mode->hsync_len + mode->left_margin;
888 y = mode->vsync_len + mode->upper_margin;
889 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
890
891 x = mode->right_margin;
892 y = mode->lower_margin;
893 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
894
895 x = mode->hsync_len;
896 y = mode->vsync_len;
897 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
898
899 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
900 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
901
902 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
903 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
904}
905
Hans de Goede4125f922014-12-21 14:49:34 +0100906static void sunxi_hdmi_enable(void)
907{
908 struct sunxi_hdmi_reg * const hdmi =
909 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
910
911 udelay(100);
912 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
913}
914
Hans de Goedee9544592014-12-23 23:04:35 +0100915#endif /* CONFIG_VIDEO_HDMI */
916
Hans de Goedec06e00e2015-08-03 19:20:26 +0200917#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100918
Hans de Goedec06e00e2015-08-03 19:20:26 +0200919static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100920{
921 struct sunxi_ccm_reg * const ccm =
922 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
923 struct sunxi_tve_reg * const tve =
924 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
925
Hans de Goede8a195ca2015-08-06 12:08:33 +0200926 /* Reset off */
927 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100928 /* Clock on */
929 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
930
Hans de Goedec06e00e2015-08-03 19:20:26 +0200931 switch (sunxi_display.monitor) {
932 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200933 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200934 break;
935 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200936 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
937 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200938 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200939 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200940 break;
941 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200942 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
943 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200944 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200945 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200946 break;
947 case sunxi_monitor_none:
948 case sunxi_monitor_dvi:
949 case sunxi_monitor_hdmi:
950 case sunxi_monitor_lcd:
951 break;
952 }
Hans de Goede260f5202014-12-25 13:58:06 +0100953}
954
Hans de Goedec06e00e2015-08-03 19:20:26 +0200955#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100956
Hans de Goede115e4b42014-12-23 18:39:52 +0100957static void sunxi_drc_init(void)
958{
Hans de Goedef07872b2015-04-06 20:33:34 +0200959#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100960 struct sunxi_ccm_reg * const ccm =
961 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
962
963 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530964#ifdef CONFIG_MACH_SUN8I_A33
965 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
966#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100967 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
968 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
969#endif
970}
971
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800972#ifdef CONFIG_VIDEO_VGA_VIA_LCD
973static void sunxi_vga_external_dac_enable(void)
974{
975 int pin;
976
977 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200978 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800979 gpio_request(pin, "vga_enable");
980 gpio_direction_output(pin, 1);
981 }
982}
983#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
984
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200985#ifdef CONFIG_VIDEO_LCD_SSD2828
986static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
987{
988 struct ssd2828_config cfg = {
989 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
990 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
991 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
992 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
993 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
994 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
995 .ssd2828_color_depth = 24,
996#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
997 .mipi_dsi_number_of_data_lanes = 4,
998 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
999 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1000 .mipi_dsi_delay_after_set_display_on_ms = 200
1001#else
1002#error MIPI LCD panel needs configuration parameters
1003#endif
1004 };
1005
1006 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1007 printf("SSD2828: SPI pins are not properly configured\n");
1008 return 1;
1009 }
1010 if (cfg.reset_pin == -1) {
1011 printf("SSD2828: Reset pin is not properly configured\n");
1012 return 1;
1013 }
1014
1015 return ssd2828_init(&cfg, mode);
1016}
1017#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1018
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001019static void sunxi_engines_init(void)
1020{
1021 sunxi_composer_init();
1022 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +01001023 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001024}
1025
Hans de Goedea0b1b732014-12-21 14:37:45 +01001026static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +01001027 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001028{
Hans de Goede260f5202014-12-25 13:58:06 +01001029 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001030 struct sunxi_lcdc_reg * const lcdc =
1031 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +02001032 struct sunxi_tve_reg * __maybe_unused const tve =
1033 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +01001034
Hans de Goede4125f922014-12-21 14:49:34 +01001035 switch (sunxi_display.monitor) {
1036 case sunxi_monitor_none:
1037 break;
1038 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001039 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001040#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001041 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001042 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001043 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1044 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001045 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +01001046 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001047#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001048 break;
1049 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001050 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +02001051 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1052 /*
1053 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +02001054 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +02001055 * to avoid turning this on when using hdmi output.
1056 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +02001057 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +02001058 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1059 ANX9804_DATA_RATE_1620M,
1060 sunxi_display.depth);
1061 }
Hans de Goede743fb9552015-01-20 09:23:36 +01001062 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1063 mdelay(50); /* Wait for lcd controller power on */
1064 hitachi_tx18d42vm_init();
1065 }
Hans de Goede613dade2015-02-16 17:49:47 +01001066 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1067 unsigned int orig_i2c_bus = i2c_get_bus_num();
1068 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1069 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1070 i2c_set_bus_num(orig_i2c_bus);
1071 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001072 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001073 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001074 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001075 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001076#ifdef CONFIG_VIDEO_LCD_SSD2828
1077 sunxi_ssd2828_init(mode);
1078#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001079 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001080 break;
1081 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001082#ifdef CONFIG_VIDEO_VGA
1083 sunxi_composer_mode_set(mode, address);
1084 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001085 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +01001086 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001087 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001088 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +01001089#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001090 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001091 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001092 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001093 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001094 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001095#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001096 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001097 case sunxi_monitor_composite_pal:
1098 case sunxi_monitor_composite_ntsc:
1099 case sunxi_monitor_composite_pal_m:
1100 case sunxi_monitor_composite_pal_nc:
1101#ifdef CONFIG_VIDEO_COMPOSITE
1102 sunxi_composer_mode_set(mode, address);
1103 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1104 sunxi_tvencoder_mode_set();
1105 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001106 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001107 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001108#endif
1109 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001110 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001111}
1112
Hans de Goedea0b1b732014-12-21 14:37:45 +01001113static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1114{
1115 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001116 case sunxi_monitor_none: return "none";
1117 case sunxi_monitor_dvi: return "dvi";
1118 case sunxi_monitor_hdmi: return "hdmi";
1119 case sunxi_monitor_lcd: return "lcd";
1120 case sunxi_monitor_vga: return "vga";
1121 case sunxi_monitor_composite_pal: return "composite-pal";
1122 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1123 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1124 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001125 }
1126 return NULL; /* never reached */
1127}
1128
Hans de Goede6c912862015-02-02 17:13:29 +01001129ulong board_get_usable_ram_top(ulong total_size)
1130{
1131 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1132}
1133
Hans de Goedea2bba492015-08-03 23:01:38 +02001134static bool sunxi_has_hdmi(void)
1135{
1136#ifdef CONFIG_VIDEO_HDMI
1137 return true;
1138#else
1139 return false;
1140#endif
1141}
1142
1143static bool sunxi_has_lcd(void)
1144{
1145 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1146
1147 return lcd_mode[0] != 0;
1148}
1149
1150static bool sunxi_has_vga(void)
1151{
1152#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1153 return true;
1154#else
1155 return false;
1156#endif
1157}
1158
Hans de Goedec06e00e2015-08-03 19:20:26 +02001159static bool sunxi_has_composite(void)
1160{
1161#ifdef CONFIG_VIDEO_COMPOSITE
1162 return true;
1163#else
1164 return false;
1165#endif
1166}
1167
Hans de Goedea2bba492015-08-03 23:01:38 +02001168static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1169{
1170 if (allow_hdmi && sunxi_has_hdmi())
1171 return sunxi_monitor_dvi;
1172 else if (sunxi_has_lcd())
1173 return sunxi_monitor_lcd;
1174 else if (sunxi_has_vga())
1175 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001176 else if (sunxi_has_composite())
1177 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001178 else
1179 return sunxi_monitor_none;
1180}
1181
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001182void *video_hw_init(void)
1183{
1184 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001185 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001186 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001187 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001188#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001189 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001190#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001191 int i, overscan_offset, overscan_x, overscan_y;
1192 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001193 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001194 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001195
1196 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1197
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001198 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1199 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001200#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001201 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001202 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001203 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001204#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001205 overscan_x = video_get_option_int(options, "overscan_x", -1);
1206 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001207 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001208 video_get_option_string(options, "monitor", mon, sizeof(mon),
1209 sunxi_get_mon_desc(sunxi_display.monitor));
1210 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1211 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1212 sunxi_display.monitor = i;
1213 break;
1214 }
1215 }
1216 if (i > SUNXI_MONITOR_LAST)
1217 printf("Unknown monitor: '%s', falling back to '%s'\n",
1218 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001219
Hans de Goede7977ec22014-12-25 13:52:04 +01001220#ifdef CONFIG_VIDEO_HDMI
1221 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1222 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1223 sunxi_display.monitor == sunxi_monitor_hdmi) {
1224 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001225 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001226 if (ret) {
1227 printf("HDMI connected: ");
1228 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1229 mode = &custom;
1230 } else if (hpd) {
1231 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001232 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001233 } /* else continue with hdmi/dvi without a cable connected */
1234 }
1235#endif
1236
Hans de Goede4125f922014-12-21 14:49:34 +01001237 switch (sunxi_display.monitor) {
1238 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001239 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001240 case sunxi_monitor_dvi:
1241 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001242 if (!sunxi_has_hdmi()) {
1243 printf("HDMI/DVI not supported on this board\n");
1244 sunxi_display.monitor = sunxi_monitor_none;
1245 return NULL;
1246 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001247 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001248 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001249 if (!sunxi_has_lcd()) {
1250 printf("LCD not supported on this board\n");
1251 sunxi_display.monitor = sunxi_monitor_none;
1252 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001253 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001254 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1255 mode = &custom;
1256 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001257 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001258 if (!sunxi_has_vga()) {
1259 printf("VGA not supported on this board\n");
1260 sunxi_display.monitor = sunxi_monitor_none;
1261 return NULL;
1262 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001263 sunxi_display.depth = 18;
1264 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001265 case sunxi_monitor_composite_pal:
1266 case sunxi_monitor_composite_ntsc:
1267 case sunxi_monitor_composite_pal_m:
1268 case sunxi_monitor_composite_pal_nc:
1269 if (!sunxi_has_composite()) {
1270 printf("Composite video not supported on this board\n");
1271 sunxi_display.monitor = sunxi_monitor_none;
1272 return NULL;
1273 }
1274 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1275 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1276 mode = &composite_video_modes[0];
1277 else
1278 mode = &composite_video_modes[1];
1279 sunxi_display.depth = 24;
1280 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001281 }
1282
Hans de Goeded955f442015-08-05 00:06:47 +02001283 /* Yes these defaults are quite high, overscan on composite sucks... */
1284 if (overscan_x == -1)
1285 overscan_x = sunxi_is_composite() ? 32 : 0;
1286 if (overscan_y == -1)
1287 overscan_y = sunxi_is_composite() ? 20 : 0;
1288
Hans de Goede18799252015-02-02 18:00:53 +01001289 sunxi_display.fb_size =
1290 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001291 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1292 /* We want to keep the fb_base for simplefb page aligned, where as
1293 * the sunxi dma engines will happily accept an unaligned address. */
1294 if (overscan_offset)
1295 sunxi_display.fb_size += 0x1000;
1296
Hans de Goede18799252015-02-02 18:00:53 +01001297 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1298 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1299 sunxi_display.fb_size >> 10,
1300 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1301 return NULL;
1302 }
1303
Hans de Goeded955f442015-08-05 00:06:47 +02001304 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1305 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001306 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001307 sunxi_get_mon_desc(sunxi_display.monitor),
1308 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001309
Hans de Goede18799252015-02-02 18:00:53 +01001310 gd->fb_base = gd->bd->bi_dram[0].start +
1311 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001312 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001313
1314 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1315 sunxi_display.fb_addr = gd->fb_base;
1316 if (overscan_offset) {
1317 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1318 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1319 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1320 flush_cache(gd->fb_base, sunxi_display.fb_size);
1321 }
1322 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001323
1324 /*
1325 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001326 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001327 */
Hans de Goeded955f442015-08-05 00:06:47 +02001328 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001329 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1330 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001331 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1332 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1333 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001334
1335 return graphic_device;
1336}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001337
1338/*
1339 * Simplefb support.
1340 */
1341#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1342int sunxi_simplefb_setup(void *blob)
1343{
1344 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1345 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001346 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001347 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001348
Hans de Goedec3cc4262015-01-19 08:44:07 +01001349#ifdef CONFIG_MACH_SUN4I
1350#define PIPELINE_PREFIX "de_fe0-"
1351#else
1352#define PIPELINE_PREFIX
1353#endif
1354
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001355 switch (sunxi_display.monitor) {
1356 case sunxi_monitor_none:
1357 return 0;
1358 case sunxi_monitor_dvi:
1359 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001360 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001361 break;
1362 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001363 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001364 break;
1365 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001366#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001367 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001368#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001369 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001370#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001371 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001372 case sunxi_monitor_composite_pal:
1373 case sunxi_monitor_composite_ntsc:
1374 case sunxi_monitor_composite_pal_m:
1375 case sunxi_monitor_composite_pal_nc:
1376 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1377 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001378 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001379
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001380 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001381 offset = fdt_node_offset_by_compatible(blob, -1,
1382 "allwinner,simple-framebuffer");
1383 while (offset >= 0) {
Simon Glassb0ea7402016-10-02 17:59:28 -06001384 ret = fdt_stringlist_search(blob, offset, "allwinner,pipeline",
Masahiro Yamadadb090a22016-10-17 20:43:01 +09001385 pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001386 if (ret == 0)
1387 break;
1388 offset = fdt_node_offset_by_compatible(blob, offset,
1389 "allwinner,simple-framebuffer");
1390 }
1391 if (offset < 0) {
1392 eprintf("Cannot setup simplefb: node not found\n");
1393 return 0; /* Keep older kernels working */
1394 }
1395
Hans de Goede6c912862015-02-02 17:13:29 +01001396 /*
1397 * Do not report the framebuffer as free RAM to the OS, note we cannot
1398 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1399 * and e.g. Linux refuses to iomap RAM on ARM, see:
1400 * linux/arch/arm/mm/ioremap.c around line 301.
1401 */
1402 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001403 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001404 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1405 if (ret) {
1406 eprintf("Cannot setup simplefb: Error reserving memory\n");
1407 return ret;
1408 }
1409
Hans de Goeded955f442015-08-05 00:06:47 +02001410 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001411 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001412 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001413 if (ret)
1414 eprintf("Cannot setup simplefb: Error setting properties\n");
1415
1416 return ret;
1417}
1418#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */