blob: b1aa4b25be4fdcf4c31e2085ad8595fca1da6fda [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02002/*
3 * Display driver for Allwinner SoCs.
4 *
5 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
Hans de Goedec06e00e2015-08-03 19:20:26 +02006 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02007 */
8
9#include <common.h>
Simon Glass63334482019-11-14 12:57:39 -070010#include <cpu_func.h>
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +010011#include <efi_loader.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070012#include <time.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020013
14#include <asm/arch/clock.h>
15#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010016#include <asm/arch/gpio.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020017#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020018#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020019#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020020#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010021#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020022#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020023#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010024#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020025#include <fdtdec.h>
26#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010027#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020028#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020029#include <video_fb.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020030#include "../videomodes.h"
31#include "../anx9804.h"
32#include "../hitachi_tx18d42vm_lcd.h"
33#include "../ssd2828.h"
Icenowy Zheng067a6972017-10-26 11:14:45 +080034#include "simplefb_common.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020035
Hans de Goede2d5d3022015-01-22 21:02:42 +010036#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
37#define PWM_ON 0
38#define PWM_OFF 1
39#else
40#define PWM_ON 1
41#define PWM_OFF 0
42#endif
43
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020044DECLARE_GLOBAL_DATA_PTR;
45
Hans de Goedea0b1b732014-12-21 14:37:45 +010046enum sunxi_monitor {
47 sunxi_monitor_none,
48 sunxi_monitor_dvi,
49 sunxi_monitor_hdmi,
50 sunxi_monitor_lcd,
51 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020052 sunxi_monitor_composite_pal,
53 sunxi_monitor_composite_ntsc,
54 sunxi_monitor_composite_pal_m,
55 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010056};
Hans de Goedec06e00e2015-08-03 19:20:26 +020057#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010058
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020059struct sunxi_display {
60 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010061 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010062 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020063 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010064 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020065} sunxi_display;
66
Hans de Goedec06e00e2015-08-03 19:20:26 +020067const struct ctfb_res_modes composite_video_modes[2] = {
68 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
69 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
70 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
71};
72
Hans de Goedee9544592014-12-23 23:04:35 +010073#ifdef CONFIG_VIDEO_HDMI
74
Hans de Goedea5aa95f2014-12-19 16:05:12 +010075/*
76 * Wait up to 200ms for value to be set in given part of reg.
77 */
78static int await_completion(u32 *reg, u32 mask, u32 val)
79{
80 unsigned long tmo = timer_get_us() + 200000;
81
82 while ((readl(reg) & mask) != val) {
83 if (timer_get_us() > tmo) {
84 printf("DDC: timeout reading EDID\n");
85 return -ETIME;
86 }
87 }
88 return 0;
89}
90
Hans de Goede91593712014-12-28 09:13:21 +010091static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020092{
93 struct sunxi_ccm_reg * const ccm =
94 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
95 struct sunxi_hdmi_reg * const hdmi =
96 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010097 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020098
99 /* Set pll3 to 300MHz */
100 clock_set_pll3(300000000);
101
102 /* Set hdmi parent to pll3 */
103 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
104 CCM_HDMI_CTRL_PLL3);
105
106 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200107#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100108 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
109#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200110 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
111
112 /* Clock on */
113 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
114
115 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
116 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
117
Priit Laesc9ecd5c2018-12-19 15:06:08 +0200118 /* Enable PLLs for eventual DDC */
119 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
120 &hdmi->pad_ctrl1);
121 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
122 &hdmi->pll_ctrl);
123 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
124
Hans de Goede205a30c2014-12-20 15:15:23 +0100125 while (timer_get_us() < tmo) {
126 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
127 return 1;
128 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200129
Hans de Goede205a30c2014-12-20 15:15:23 +0100130 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100131}
132
133static void sunxi_hdmi_shutdown(void)
134{
135 struct sunxi_ccm_reg * const ccm =
136 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
137 struct sunxi_hdmi_reg * const hdmi =
138 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200139
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200140 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
141 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
142 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200143#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100144 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
145#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200146 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200147}
148
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100149static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
150{
151 struct sunxi_hdmi_reg * const hdmi =
152 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
153
154 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
155 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
156 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
157 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
158 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
159#ifndef CONFIG_MACH_SUN6I
160 writel(n, &hdmi->ddc_byte_count);
161 writel(cmnd, &hdmi->ddc_cmnd);
162#else
163 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
164#endif
165 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
166
167 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
168}
169
170static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
171{
172 struct sunxi_hdmi_reg * const hdmi =
173 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
174 int i, n;
175
176 while (count > 0) {
177 if (count > 16)
178 n = 16;
179 else
180 n = count;
181
182 if (sunxi_hdmi_ddc_do_command(
183 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
184 offset, n))
185 return -ETIME;
186
187 for (i = 0; i < n; i++)
188 *buf++ = readb(&hdmi->ddc_fifo_data);
189
190 offset += n;
191 count -= n;
192 }
193
194 return 0;
195}
196
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100197static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
198{
199 int r, retries = 2;
200
201 do {
202 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
203 if (r)
204 continue;
205 r = edid_check_checksum(buf);
206 if (r) {
207 printf("EDID block %d: checksum error%s\n",
208 block, retries ? ", retrying" : "");
209 }
210 } while (r && retries--);
211
212 return r;
213}
214
Priit Laesa9d6db72018-12-19 15:06:09 +0200215static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
216 bool verbose_mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100217{
218 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100219 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100220 struct edid_detailed_timing *t =
221 (struct edid_detailed_timing *)edid1.monitor_details.timing;
222 struct sunxi_hdmi_reg * const hdmi =
223 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
224 struct sunxi_ccm_reg * const ccm =
225 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100226 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100227
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100228 /* Reset i2c controller */
229 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
230 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
231 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
232 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
233 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
234 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
235 return -EIO;
236
237 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
238#ifndef CONFIG_MACH_SUN6I
239 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
240 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
241#endif
242
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100243 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100244 if (r == 0) {
245 r = edid_check_info(&edid1);
246 if (r) {
Priit Laesa9d6db72018-12-19 15:06:09 +0200247 if (verbose_mode)
248 printf("EDID: invalid EDID data\n");
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100249 r = -EINVAL;
250 }
251 }
252 if (r == 0) {
253 ext_blocks = edid1.extension_flag;
254 if (ext_blocks > 4)
255 ext_blocks = 4;
256 for (i = 0; i < ext_blocks; i++) {
257 if (sunxi_hdmi_edid_get_block(1 + i,
258 (u8 *)&cea681[i]) != 0) {
259 ext_blocks = i;
260 break;
261 }
262 }
263 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100264
265 /* Disable DDC engine, no longer needed */
266 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
267 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
268
269 if (r)
270 return r;
271
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100272 /* We want version 1.3 or 1.2 with detailed timing info */
273 if (edid1.version != 1 || (edid1.revision < 3 &&
274 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
275 printf("EDID: unsupported version %d.%d\n",
276 edid1.version, edid1.revision);
277 return -EINVAL;
278 }
279
280 /* Take the first usable detailed timing */
281 for (i = 0; i < 4; i++, t++) {
282 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
283 if (r == 0)
284 break;
285 }
286 if (i == 4) {
287 printf("EDID: no usable detailed timing found\n");
288 return -ENOENT;
289 }
290
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100291 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100292 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100293 for (i = 0; i < ext_blocks; i++) {
294 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
295 cea681[i].revision < 2)
296 continue;
297
298 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100299 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100300 }
301
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100302 return 0;
303}
304
Hans de Goedee9544592014-12-23 23:04:35 +0100305#endif /* CONFIG_VIDEO_HDMI */
306
Hans de Goedec3cc4262015-01-19 08:44:07 +0100307#ifdef CONFIG_MACH_SUN4I
308/*
309 * Testing has shown that on sun4i the display backend engine does not have
310 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
311 * fifo underruns. So on sun4i we use the display frontend engine to do the
312 * dma from memory, as the frontend does have deep enough fifo-s.
313 */
314
315static const u32 sun4i_vert_coef[32] = {
316 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
317 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
318 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
319 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
320 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
321 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
322 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
323 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
324};
325
326static const u32 sun4i_horz_coef[64] = {
327 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
328 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
329 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
330 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
331 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
332 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
333 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
334 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
335 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
336 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
337 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
338 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
339 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
340 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
341 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
342 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
343};
344
345static void sunxi_frontend_init(void)
346{
347 struct sunxi_ccm_reg * const ccm =
348 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
349 struct sunxi_de_fe_reg * const de_fe =
350 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
351 int i;
352
353 /* Clocks on */
354 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
355 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
356 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
357
358 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
359
360 for (i = 0; i < 32; i++) {
361 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
362 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
363 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
364 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
365 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
366 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
367 }
368
369 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
370}
371
372static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
373 unsigned int address)
374{
375 struct sunxi_de_fe_reg * const de_fe =
376 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
377
378 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
379 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
380 writel(mode->xres * 4, &de_fe->ch0_stride);
381 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
382 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
383
384 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
385 &de_fe->ch0_insize);
386 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
387 &de_fe->ch0_outsize);
388 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
389 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
390
391 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
392 &de_fe->ch1_insize);
393 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
394 &de_fe->ch1_outsize);
395 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
396 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
397
398 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
399}
400
401static void sunxi_frontend_enable(void)
402{
403 struct sunxi_de_fe_reg * const de_fe =
404 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
405
406 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
407}
408#else
409static void sunxi_frontend_init(void) {}
410static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
411 unsigned int address) {}
412static void sunxi_frontend_enable(void) {}
413#endif
414
Hans de Goedec06e00e2015-08-03 19:20:26 +0200415static bool sunxi_is_composite(void)
416{
417 switch (sunxi_display.monitor) {
418 case sunxi_monitor_none:
419 case sunxi_monitor_dvi:
420 case sunxi_monitor_hdmi:
421 case sunxi_monitor_lcd:
422 case sunxi_monitor_vga:
423 return false;
424 case sunxi_monitor_composite_pal:
425 case sunxi_monitor_composite_ntsc:
426 case sunxi_monitor_composite_pal_m:
427 case sunxi_monitor_composite_pal_nc:
428 return true;
429 }
430
431 return false; /* Never reached */
432}
433
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200434/*
435 * This is the entity that mixes and matches the different layers and inputs.
436 * Allwinner calls it the back-end, but i like composer better.
437 */
438static void sunxi_composer_init(void)
439{
440 struct sunxi_ccm_reg * const ccm =
441 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
442 struct sunxi_de_be_reg * const de_be =
443 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
444 int i;
445
Hans de Goedec3cc4262015-01-19 08:44:07 +0100446 sunxi_frontend_init();
447
Hans de Goedef07872b2015-04-06 20:33:34 +0200448#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100449 /* Reset off */
450 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
451#endif
452
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200453 /* Clocks on */
454 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100455#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200456 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100457#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200458 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
459
460 /* Engine bug, clear registers after reset */
461 for (i = 0x0800; i < 0x1000; i += 4)
462 writel(0, SUNXI_DE_BE0_BASE + i);
463
464 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
465}
466
Priit Laes82482d62018-10-23 20:20:31 +0300467static const u32 sunxi_rgb2yuv_coef[12] = {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200468 0x00000107, 0x00000204, 0x00000064, 0x00000108,
469 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
470 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
471};
472
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100473static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200474 unsigned int address)
475{
476 struct sunxi_de_be_reg * const de_be =
477 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200478 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200479
Hans de Goedec3cc4262015-01-19 08:44:07 +0100480 sunxi_frontend_mode_set(mode, address);
481
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200482 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
483 &de_be->disp_size);
484 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
485 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100486#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200487 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
488 writel(address << 3, &de_be->layer0_addr_low32b);
489 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100490#else
491 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
492#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200493 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
494
495 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200496 if (mode->vmode == FB_VMODE_INTERLACED)
497 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200498#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200499 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200500#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200501 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200502
503 if (sunxi_is_composite()) {
504 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
505 &de_be->output_color_ctrl);
506 for (i = 0; i < 12; i++)
507 writel(sunxi_rgb2yuv_coef[i],
508 &de_be->output_color_coef[i]);
509 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200510}
511
Hans de Goede4125f922014-12-21 14:49:34 +0100512static void sunxi_composer_enable(void)
513{
514 struct sunxi_de_be_reg * const de_be =
515 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
516
Hans de Goedec3cc4262015-01-19 08:44:07 +0100517 sunxi_frontend_enable();
518
Hans de Goede4125f922014-12-21 14:49:34 +0100519 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
520 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
521}
522
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200523static void sunxi_lcdc_init(void)
524{
525 struct sunxi_ccm_reg * const ccm =
526 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
527 struct sunxi_lcdc_reg * const lcdc =
528 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
529
530 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200531#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100532 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
533#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200534 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100535#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200536
537 /* Clock on */
538 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100539#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200540#ifdef CONFIG_SUNXI_GEN_SUN6I
541 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
542#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100543 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
544#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200545#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200546
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200547 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200548}
549
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100550static void sunxi_lcdc_panel_enable(void)
551{
Hans de Goedece9e3322015-02-16 17:26:41 +0100552 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100553
554 /*
555 * Start with backlight disabled to avoid the screen flashing to
556 * white while the lcd inits.
557 */
558 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200559 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100560 gpio_request(pin, "lcd_backlight_enable");
561 gpio_direction_output(pin, 0);
562 }
563
564 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200565 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100566 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100567 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100568 }
569
Hans de Goedece9e3322015-02-16 17:26:41 +0100570 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200571 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100572 gpio_request(reset_pin, "lcd_reset");
573 gpio_direction_output(reset_pin, 0); /* Assert reset */
574 }
575
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100576 /* Give the backlight some time to turn off and power up the panel. */
577 mdelay(40);
578 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200579 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100580 gpio_request(pin, "lcd_power");
581 gpio_direction_output(pin, 1);
582 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100583
Hans de Goede7783ab22015-04-22 17:45:59 +0200584 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100585 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100586}
587
588static void sunxi_lcdc_backlight_enable(void)
589{
590 int pin;
591
592 /*
593 * We want to have scanned out at least one frame before enabling the
594 * backlight to avoid the screen flashing to white when we enable it.
595 */
596 mdelay(40);
597
598 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200599 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100600 gpio_direction_output(pin, 1);
601
602 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200603#ifdef SUNXI_PWM_PIN0
604 if (pin == SUNXI_PWM_PIN0) {
605 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
606 SUNXI_PWM_CTRL_ENABLE0 |
607 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
608 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
609 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
610 return;
611 }
612#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200613 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100614 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100615}
616
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200617static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
618 struct display_timing *timing)
619{
620 timing->pixelclock.typ = mode->pixclock_khz * 1000;
621
622 timing->hactive.typ = mode->xres;
623 timing->hfront_porch.typ = mode->right_margin;
624 timing->hback_porch.typ = mode->left_margin;
625 timing->hsync_len.typ = mode->hsync_len;
626
627 timing->vactive.typ = mode->yres;
628 timing->vfront_porch.typ = mode->lower_margin;
629 timing->vback_porch.typ = mode->upper_margin;
630 timing->vsync_len.typ = mode->vsync_len;
631
Giulio Benetti105bdc62018-01-16 17:43:48 +0100632 timing->flags = 0;
633
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200634 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
635 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
636 else
637 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
638 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
639 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
640 else
641 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
642 if (mode->vmode == FB_VMODE_INTERLACED)
643 timing->flags |= DISPLAY_FLAGS_INTERLACED;
644}
645
Hans de Goede18366f72015-01-25 15:33:07 +0100646static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
647 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100648{
649 struct sunxi_lcdc_reg * const lcdc =
650 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700651 struct sunxi_ccm_reg * const ccm =
652 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200653 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200654 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100655
Lawrence Yuf721f962016-03-04 09:08:56 -0800656#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
657 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
658#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200659 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800660#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100661#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100662 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100663#endif
664#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100665 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100666#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200667#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
668 sunxi_gpio_set_drv(pin, 3);
669#endif
670 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100671
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700672 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
673 sunxi_is_composite());
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100674
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200675 sunxi_ctfb_mode_to_display_timing(mode, &timing);
676 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200677 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100678}
679
Hans de Goedec06e00e2015-08-03 19:20:26 +0200680#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100681static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100682 int *clk_div, int *clk_double,
683 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200684{
685 struct sunxi_lcdc_reg * const lcdc =
686 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700687 struct sunxi_ccm_reg * const ccm =
688 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200689 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200690
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200691 sunxi_ctfb_mode_to_display_timing(mode, &timing);
692 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200693 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200694
Hans de Goedec3d15042014-12-27 15:19:23 +0100695 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100696 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
697 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100698 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200699
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700700 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
701 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200702}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200703#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100704
705#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100706
Hans de Goedea2017e82014-12-20 13:38:06 +0100707static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
708{
709 struct sunxi_hdmi_reg * const hdmi =
710 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
711 u8 checksum = 0;
712 u8 avi_info_frame[17] = {
713 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715 0x00
716 };
717 u8 vendor_info_frame[19] = {
718 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
720 0x00, 0x00, 0x00
721 };
722 int i;
723
724 if (mode->pixclock_khz <= 27000)
725 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
726 else
727 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
728
729 if (mode->xres * 100 / mode->yres < 156)
730 avi_info_frame[5] |= 0x18; /* 4 : 3 */
731 else
732 avi_info_frame[5] |= 0x28; /* 16 : 9 */
733
734 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
735 checksum += avi_info_frame[i];
736
737 avi_info_frame[3] = 0x100 - checksum;
738
739 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
740 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
741
742 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
743 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
744
745 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
746 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
747
748 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
749 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
750
751 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
752}
753
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100754static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100755 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200756{
757 struct sunxi_hdmi_reg * const hdmi =
758 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
759 int x, y;
760
761 /* Write clear interrupt status bits */
762 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
763
Hans de Goedea0b1b732014-12-21 14:37:45 +0100764 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100765 sunxi_hdmi_setup_info_frames(mode);
766
Hans de Goede95576692014-12-20 13:51:16 +0100767 /* Set input sync enable */
768 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
769
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200770 /* Init various registers, select pll3 as clock source */
771 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
772 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
773 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
774 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
775 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
776
777 /* Setup clk div and doubler */
778 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
779 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
780 if (!clk_double)
781 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
782
783 /* Setup timing registers */
784 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
785 &hdmi->video_size);
786
787 x = mode->hsync_len + mode->left_margin;
788 y = mode->vsync_len + mode->upper_margin;
789 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
790
791 x = mode->right_margin;
792 y = mode->lower_margin;
793 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
794
795 x = mode->hsync_len;
796 y = mode->vsync_len;
797 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
798
799 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
800 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
801
802 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
803 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
804}
805
Hans de Goede4125f922014-12-21 14:49:34 +0100806static void sunxi_hdmi_enable(void)
807{
808 struct sunxi_hdmi_reg * const hdmi =
809 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
810
811 udelay(100);
812 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
813}
814
Hans de Goedee9544592014-12-23 23:04:35 +0100815#endif /* CONFIG_VIDEO_HDMI */
816
Hans de Goedec06e00e2015-08-03 19:20:26 +0200817#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100818
Hans de Goedec06e00e2015-08-03 19:20:26 +0200819static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100820{
821 struct sunxi_ccm_reg * const ccm =
822 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
823 struct sunxi_tve_reg * const tve =
824 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
825
Hans de Goede8a195ca2015-08-06 12:08:33 +0200826 /* Reset off */
827 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100828 /* Clock on */
829 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
830
Hans de Goedec06e00e2015-08-03 19:20:26 +0200831 switch (sunxi_display.monitor) {
832 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200833 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200834 break;
835 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200836 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
837 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200838 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200839 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200840 break;
841 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200842 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
843 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200844 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200845 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200846 break;
847 case sunxi_monitor_none:
848 case sunxi_monitor_dvi:
849 case sunxi_monitor_hdmi:
850 case sunxi_monitor_lcd:
851 break;
852 }
Hans de Goede260f5202014-12-25 13:58:06 +0100853}
854
Hans de Goedec06e00e2015-08-03 19:20:26 +0200855#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100856
Hans de Goede115e4b42014-12-23 18:39:52 +0100857static void sunxi_drc_init(void)
858{
Hans de Goedef07872b2015-04-06 20:33:34 +0200859#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100860 struct sunxi_ccm_reg * const ccm =
861 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
862
863 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530864#ifdef CONFIG_MACH_SUN8I_A33
865 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
866#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100867 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
868 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
869#endif
870}
871
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800872#ifdef CONFIG_VIDEO_VGA_VIA_LCD
873static void sunxi_vga_external_dac_enable(void)
874{
875 int pin;
876
877 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200878 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800879 gpio_request(pin, "vga_enable");
880 gpio_direction_output(pin, 1);
881 }
882}
883#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
884
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200885#ifdef CONFIG_VIDEO_LCD_SSD2828
886static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
887{
888 struct ssd2828_config cfg = {
889 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
890 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
891 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
892 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
893 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
894 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
895 .ssd2828_color_depth = 24,
896#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
897 .mipi_dsi_number_of_data_lanes = 4,
898 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
899 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
900 .mipi_dsi_delay_after_set_display_on_ms = 200
901#else
902#error MIPI LCD panel needs configuration parameters
903#endif
904 };
905
906 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
907 printf("SSD2828: SPI pins are not properly configured\n");
908 return 1;
909 }
910 if (cfg.reset_pin == -1) {
911 printf("SSD2828: Reset pin is not properly configured\n");
912 return 1;
913 }
914
915 return ssd2828_init(&cfg, mode);
916}
917#endif /* CONFIG_VIDEO_LCD_SSD2828 */
918
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200919static void sunxi_engines_init(void)
920{
921 sunxi_composer_init();
922 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100923 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200924}
925
Hans de Goedea0b1b732014-12-21 14:37:45 +0100926static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100927 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200928{
Hans de Goede260f5202014-12-25 13:58:06 +0100929 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200930 struct sunxi_lcdc_reg * const lcdc =
931 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +0200932 struct sunxi_tve_reg * __maybe_unused const tve =
933 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +0100934
Hans de Goede4125f922014-12-21 14:49:34 +0100935 switch (sunxi_display.monitor) {
936 case sunxi_monitor_none:
937 break;
938 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +0100939 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +0100940#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +0100941 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +0100942 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +0100943 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
944 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200945 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +0100946 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +0100947#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100948 break;
949 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100950 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +0200951 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
952 /*
953 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200954 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +0200955 * to avoid turning this on when using hdmi output.
956 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200957 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +0200958 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
959 ANX9804_DATA_RATE_1620M,
960 sunxi_display.depth);
961 }
Hans de Goede743fb9552015-01-20 09:23:36 +0100962 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
963 mdelay(50); /* Wait for lcd controller power on */
964 hitachi_tx18d42vm_init();
965 }
Hans de Goede613dade2015-02-16 17:49:47 +0100966 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
967 unsigned int orig_i2c_bus = i2c_get_bus_num();
968 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
969 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
970 i2c_set_bus_num(orig_i2c_bus);
971 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100972 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100973 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100974 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200975 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200976#ifdef CONFIG_VIDEO_LCD_SSD2828
977 sunxi_ssd2828_init(mode);
978#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100979 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +0100980 break;
981 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +0100982#ifdef CONFIG_VIDEO_VGA
983 sunxi_composer_mode_set(mode, address);
984 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200985 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +0100986 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200987 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200988 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +0100989#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +0100990 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100991 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +0100992 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200993 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800994 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +0100995#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100996 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200997 case sunxi_monitor_composite_pal:
998 case sunxi_monitor_composite_ntsc:
999 case sunxi_monitor_composite_pal_m:
1000 case sunxi_monitor_composite_pal_nc:
1001#ifdef CONFIG_VIDEO_COMPOSITE
1002 sunxi_composer_mode_set(mode, address);
1003 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1004 sunxi_tvencoder_mode_set();
1005 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001006 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001007 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001008#endif
1009 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001010 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001011}
1012
Hans de Goedea0b1b732014-12-21 14:37:45 +01001013static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1014{
1015 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001016 case sunxi_monitor_none: return "none";
1017 case sunxi_monitor_dvi: return "dvi";
1018 case sunxi_monitor_hdmi: return "hdmi";
1019 case sunxi_monitor_lcd: return "lcd";
1020 case sunxi_monitor_vga: return "vga";
1021 case sunxi_monitor_composite_pal: return "composite-pal";
1022 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1023 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1024 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001025 }
1026 return NULL; /* never reached */
1027}
1028
Hans de Goede6c912862015-02-02 17:13:29 +01001029ulong board_get_usable_ram_top(ulong total_size)
1030{
1031 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1032}
1033
Hans de Goedea2bba492015-08-03 23:01:38 +02001034static bool sunxi_has_hdmi(void)
1035{
1036#ifdef CONFIG_VIDEO_HDMI
1037 return true;
1038#else
1039 return false;
1040#endif
1041}
1042
1043static bool sunxi_has_lcd(void)
1044{
1045 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1046
1047 return lcd_mode[0] != 0;
1048}
1049
1050static bool sunxi_has_vga(void)
1051{
1052#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1053 return true;
1054#else
1055 return false;
1056#endif
1057}
1058
Hans de Goedec06e00e2015-08-03 19:20:26 +02001059static bool sunxi_has_composite(void)
1060{
1061#ifdef CONFIG_VIDEO_COMPOSITE
1062 return true;
1063#else
1064 return false;
1065#endif
1066}
1067
Hans de Goedea2bba492015-08-03 23:01:38 +02001068static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1069{
1070 if (allow_hdmi && sunxi_has_hdmi())
1071 return sunxi_monitor_dvi;
1072 else if (sunxi_has_lcd())
1073 return sunxi_monitor_lcd;
1074 else if (sunxi_has_vga())
1075 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001076 else if (sunxi_has_composite())
1077 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001078 else
1079 return sunxi_monitor_none;
1080}
1081
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001082void *video_hw_init(void)
1083{
1084 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001085 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001086 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001087 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001088#ifdef CONFIG_VIDEO_HDMI
Priit Laesa9d6db72018-12-19 15:06:09 +02001089 int hpd, hpd_delay, edid;
1090 bool hdmi_present;
Hans de Goedee9544592014-12-23 23:04:35 +01001091#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001092 int i, overscan_offset, overscan_x, overscan_y;
1093 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001094 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001095 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001096
1097 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1098
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001099 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1100 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001101#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001102 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001103 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001104 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001105#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001106 overscan_x = video_get_option_int(options, "overscan_x", -1);
1107 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001108 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001109 video_get_option_string(options, "monitor", mon, sizeof(mon),
1110 sunxi_get_mon_desc(sunxi_display.monitor));
1111 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1112 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1113 sunxi_display.monitor = i;
1114 break;
1115 }
1116 }
1117 if (i > SUNXI_MONITOR_LAST)
1118 printf("Unknown monitor: '%s', falling back to '%s'\n",
1119 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001120
Hans de Goede7977ec22014-12-25 13:52:04 +01001121#ifdef CONFIG_VIDEO_HDMI
1122 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1123 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1124 sunxi_display.monitor == sunxi_monitor_hdmi) {
1125 /* Always call hdp_detect, as it also enables clocks, etc. */
Priit Laesa9d6db72018-12-19 15:06:09 +02001126 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1127 if (hdmi_present && edid) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001128 printf("HDMI connected: ");
Priit Laesa9d6db72018-12-19 15:06:09 +02001129 if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
Hans de Goede7977ec22014-12-25 13:52:04 +01001130 mode = &custom;
Priit Laesa9d6db72018-12-19 15:06:09 +02001131 else
1132 hdmi_present = false;
1133 }
1134 /* Fall back to EDID in case HPD failed */
1135 if (edid && !hdmi_present) {
1136 if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1137 mode = &custom;
1138 hdmi_present = true;
1139 }
1140 }
1141 /* Shut down when display was not found */
1142 if ((hpd || edid) && !hdmi_present) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001143 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001144 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001145 } /* else continue with hdmi/dvi without a cable connected */
1146 }
1147#endif
1148
Hans de Goede4125f922014-12-21 14:49:34 +01001149 switch (sunxi_display.monitor) {
1150 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001151 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001152 case sunxi_monitor_dvi:
1153 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001154 if (!sunxi_has_hdmi()) {
1155 printf("HDMI/DVI not supported on this board\n");
1156 sunxi_display.monitor = sunxi_monitor_none;
1157 return NULL;
1158 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001159 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001160 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001161 if (!sunxi_has_lcd()) {
1162 printf("LCD not supported on this board\n");
1163 sunxi_display.monitor = sunxi_monitor_none;
1164 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001165 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001166 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1167 mode = &custom;
1168 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001169 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001170 if (!sunxi_has_vga()) {
1171 printf("VGA not supported on this board\n");
1172 sunxi_display.monitor = sunxi_monitor_none;
1173 return NULL;
1174 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001175 sunxi_display.depth = 18;
1176 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001177 case sunxi_monitor_composite_pal:
1178 case sunxi_monitor_composite_ntsc:
1179 case sunxi_monitor_composite_pal_m:
1180 case sunxi_monitor_composite_pal_nc:
1181 if (!sunxi_has_composite()) {
1182 printf("Composite video not supported on this board\n");
1183 sunxi_display.monitor = sunxi_monitor_none;
1184 return NULL;
1185 }
1186 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1187 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1188 mode = &composite_video_modes[0];
1189 else
1190 mode = &composite_video_modes[1];
1191 sunxi_display.depth = 24;
1192 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001193 }
1194
Hans de Goeded955f442015-08-05 00:06:47 +02001195 /* Yes these defaults are quite high, overscan on composite sucks... */
1196 if (overscan_x == -1)
1197 overscan_x = sunxi_is_composite() ? 32 : 0;
1198 if (overscan_y == -1)
1199 overscan_y = sunxi_is_composite() ? 20 : 0;
1200
Hans de Goede18799252015-02-02 18:00:53 +01001201 sunxi_display.fb_size =
1202 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001203 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1204 /* We want to keep the fb_base for simplefb page aligned, where as
1205 * the sunxi dma engines will happily accept an unaligned address. */
1206 if (overscan_offset)
1207 sunxi_display.fb_size += 0x1000;
1208
Hans de Goede18799252015-02-02 18:00:53 +01001209 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1210 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1211 sunxi_display.fb_size >> 10,
1212 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1213 return NULL;
1214 }
1215
Hans de Goeded955f442015-08-05 00:06:47 +02001216 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1217 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001218 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001219 sunxi_get_mon_desc(sunxi_display.monitor),
1220 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001221
Hans de Goede18799252015-02-02 18:00:53 +01001222 gd->fb_base = gd->bd->bi_dram[0].start +
1223 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001224 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001225
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001226#ifdef CONFIG_EFI_LOADER
1227 efi_add_memory_map(gd->fb_base,
1228 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1229 EFI_PAGE_SHIFT,
1230 EFI_RESERVED_MEMORY_TYPE, false);
1231#endif
1232
Hans de Goeded955f442015-08-05 00:06:47 +02001233 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1234 sunxi_display.fb_addr = gd->fb_base;
1235 if (overscan_offset) {
1236 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1237 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1238 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1239 flush_cache(gd->fb_base, sunxi_display.fb_size);
1240 }
1241 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001242
1243 /*
1244 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001245 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001246 */
Hans de Goeded955f442015-08-05 00:06:47 +02001247 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001248 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1249 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001250 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1251 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1252 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001253
1254 return graphic_device;
1255}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001256
1257/*
1258 * Simplefb support.
1259 */
1260#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1261int sunxi_simplefb_setup(void *blob)
1262{
1263 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1264 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001265 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001266 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001267
Hans de Goedec3cc4262015-01-19 08:44:07 +01001268#ifdef CONFIG_MACH_SUN4I
1269#define PIPELINE_PREFIX "de_fe0-"
1270#else
1271#define PIPELINE_PREFIX
1272#endif
1273
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001274 switch (sunxi_display.monitor) {
1275 case sunxi_monitor_none:
1276 return 0;
1277 case sunxi_monitor_dvi:
1278 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001279 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001280 break;
1281 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001282 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001283 break;
1284 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001285#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001286 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001287#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001288 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001289#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001290 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001291 case sunxi_monitor_composite_pal:
1292 case sunxi_monitor_composite_ntsc:
1293 case sunxi_monitor_composite_pal_m:
1294 case sunxi_monitor_composite_pal_nc:
1295 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1296 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001297 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001298
Icenowy Zheng067a6972017-10-26 11:14:45 +08001299 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001300 if (offset < 0) {
1301 eprintf("Cannot setup simplefb: node not found\n");
1302 return 0; /* Keep older kernels working */
1303 }
1304
Hans de Goede6c912862015-02-02 17:13:29 +01001305 /*
1306 * Do not report the framebuffer as free RAM to the OS, note we cannot
1307 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1308 * and e.g. Linux refuses to iomap RAM on ARM, see:
1309 * linux/arch/arm/mm/ioremap.c around line 301.
1310 */
1311 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001312 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001313 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1314 if (ret) {
1315 eprintf("Cannot setup simplefb: Error reserving memory\n");
1316 return ret;
1317 }
1318
Hans de Goeded955f442015-08-05 00:06:47 +02001319 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001320 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001321 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001322 if (ret)
1323 eprintf("Cannot setup simplefb: Error setting properties\n");
1324
1325 return ret;
1326}
1327#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */