blob: 31f0aa7ddcc456d9f38d4cb0cac798cbcf416dc9 [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 Glass6980b6b2019-11-14 12:57:45 -070012#include <init.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070013#include <time.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020014
15#include <asm/arch/clock.h>
16#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010017#include <asm/arch/gpio.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020018#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020019#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020020#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020021#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010022#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020023#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020024#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010025#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020026#include <fdtdec.h>
27#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010028#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020029#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020030#include <video_fb.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020031#include "../videomodes.h"
32#include "../anx9804.h"
33#include "../hitachi_tx18d42vm_lcd.h"
34#include "../ssd2828.h"
Icenowy Zheng067a6972017-10-26 11:14:45 +080035#include "simplefb_common.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020036
Hans de Goede2d5d3022015-01-22 21:02:42 +010037#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
38#define PWM_ON 0
39#define PWM_OFF 1
40#else
41#define PWM_ON 1
42#define PWM_OFF 0
43#endif
44
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020045DECLARE_GLOBAL_DATA_PTR;
46
Hans de Goedea0b1b732014-12-21 14:37:45 +010047enum sunxi_monitor {
48 sunxi_monitor_none,
49 sunxi_monitor_dvi,
50 sunxi_monitor_hdmi,
51 sunxi_monitor_lcd,
52 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020053 sunxi_monitor_composite_pal,
54 sunxi_monitor_composite_ntsc,
55 sunxi_monitor_composite_pal_m,
56 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010057};
Hans de Goedec06e00e2015-08-03 19:20:26 +020058#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010059
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020060struct sunxi_display {
61 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010062 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010063 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020064 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010065 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020066} sunxi_display;
67
Hans de Goedec06e00e2015-08-03 19:20:26 +020068const struct ctfb_res_modes composite_video_modes[2] = {
69 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
70 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
71 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
72};
73
Hans de Goedee9544592014-12-23 23:04:35 +010074#ifdef CONFIG_VIDEO_HDMI
75
Hans de Goedea5aa95f2014-12-19 16:05:12 +010076/*
77 * Wait up to 200ms for value to be set in given part of reg.
78 */
79static int await_completion(u32 *reg, u32 mask, u32 val)
80{
81 unsigned long tmo = timer_get_us() + 200000;
82
83 while ((readl(reg) & mask) != val) {
84 if (timer_get_us() > tmo) {
85 printf("DDC: timeout reading EDID\n");
86 return -ETIME;
87 }
88 }
89 return 0;
90}
91
Hans de Goede91593712014-12-28 09:13:21 +010092static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020093{
94 struct sunxi_ccm_reg * const ccm =
95 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
96 struct sunxi_hdmi_reg * const hdmi =
97 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010098 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020099
100 /* Set pll3 to 300MHz */
101 clock_set_pll3(300000000);
102
103 /* Set hdmi parent to pll3 */
104 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
105 CCM_HDMI_CTRL_PLL3);
106
107 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200108#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100109 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
110#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200111 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
112
113 /* Clock on */
114 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
115
116 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
117 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
118
Priit Laesc9ecd5c2018-12-19 15:06:08 +0200119 /* Enable PLLs for eventual DDC */
120 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
121 &hdmi->pad_ctrl1);
122 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
123 &hdmi->pll_ctrl);
124 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
125
Hans de Goede205a30c2014-12-20 15:15:23 +0100126 while (timer_get_us() < tmo) {
127 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
128 return 1;
129 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200130
Hans de Goede205a30c2014-12-20 15:15:23 +0100131 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100132}
133
134static void sunxi_hdmi_shutdown(void)
135{
136 struct sunxi_ccm_reg * const ccm =
137 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
138 struct sunxi_hdmi_reg * const hdmi =
139 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200140
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200141 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
142 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
143 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200144#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100145 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
146#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200147 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200148}
149
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100150static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
151{
152 struct sunxi_hdmi_reg * const hdmi =
153 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
154
155 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
156 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
157 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
158 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
159 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
160#ifndef CONFIG_MACH_SUN6I
161 writel(n, &hdmi->ddc_byte_count);
162 writel(cmnd, &hdmi->ddc_cmnd);
163#else
164 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
165#endif
166 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
167
168 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
169}
170
171static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
172{
173 struct sunxi_hdmi_reg * const hdmi =
174 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
175 int i, n;
176
177 while (count > 0) {
178 if (count > 16)
179 n = 16;
180 else
181 n = count;
182
183 if (sunxi_hdmi_ddc_do_command(
184 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
185 offset, n))
186 return -ETIME;
187
188 for (i = 0; i < n; i++)
189 *buf++ = readb(&hdmi->ddc_fifo_data);
190
191 offset += n;
192 count -= n;
193 }
194
195 return 0;
196}
197
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100198static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
199{
200 int r, retries = 2;
201
202 do {
203 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
204 if (r)
205 continue;
206 r = edid_check_checksum(buf);
207 if (r) {
208 printf("EDID block %d: checksum error%s\n",
209 block, retries ? ", retrying" : "");
210 }
211 } while (r && retries--);
212
213 return r;
214}
215
Priit Laesa9d6db72018-12-19 15:06:09 +0200216static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
217 bool verbose_mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100218{
219 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100220 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100221 struct edid_detailed_timing *t =
222 (struct edid_detailed_timing *)edid1.monitor_details.timing;
223 struct sunxi_hdmi_reg * const hdmi =
224 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
225 struct sunxi_ccm_reg * const ccm =
226 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100227 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100228
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100229 /* Reset i2c controller */
230 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
231 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
232 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
233 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
234 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
235 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
236 return -EIO;
237
238 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
239#ifndef CONFIG_MACH_SUN6I
240 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
241 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
242#endif
243
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100244 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100245 if (r == 0) {
246 r = edid_check_info(&edid1);
247 if (r) {
Priit Laesa9d6db72018-12-19 15:06:09 +0200248 if (verbose_mode)
249 printf("EDID: invalid EDID data\n");
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100250 r = -EINVAL;
251 }
252 }
253 if (r == 0) {
254 ext_blocks = edid1.extension_flag;
255 if (ext_blocks > 4)
256 ext_blocks = 4;
257 for (i = 0; i < ext_blocks; i++) {
258 if (sunxi_hdmi_edid_get_block(1 + i,
259 (u8 *)&cea681[i]) != 0) {
260 ext_blocks = i;
261 break;
262 }
263 }
264 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100265
266 /* Disable DDC engine, no longer needed */
267 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
268 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
269
270 if (r)
271 return r;
272
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100273 /* We want version 1.3 or 1.2 with detailed timing info */
274 if (edid1.version != 1 || (edid1.revision < 3 &&
275 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
276 printf("EDID: unsupported version %d.%d\n",
277 edid1.version, edid1.revision);
278 return -EINVAL;
279 }
280
281 /* Take the first usable detailed timing */
282 for (i = 0; i < 4; i++, t++) {
283 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
284 if (r == 0)
285 break;
286 }
287 if (i == 4) {
288 printf("EDID: no usable detailed timing found\n");
289 return -ENOENT;
290 }
291
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100292 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100293 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100294 for (i = 0; i < ext_blocks; i++) {
295 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
296 cea681[i].revision < 2)
297 continue;
298
299 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100300 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100301 }
302
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100303 return 0;
304}
305
Hans de Goedee9544592014-12-23 23:04:35 +0100306#endif /* CONFIG_VIDEO_HDMI */
307
Hans de Goedec3cc4262015-01-19 08:44:07 +0100308#ifdef CONFIG_MACH_SUN4I
309/*
310 * Testing has shown that on sun4i the display backend engine does not have
311 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
312 * fifo underruns. So on sun4i we use the display frontend engine to do the
313 * dma from memory, as the frontend does have deep enough fifo-s.
314 */
315
316static const u32 sun4i_vert_coef[32] = {
317 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
318 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
319 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
320 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
321 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
322 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
323 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
324 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
325};
326
327static const u32 sun4i_horz_coef[64] = {
328 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
329 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
330 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
331 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
332 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
333 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
334 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
335 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
336 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
337 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
338 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
339 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
340 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
341 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
342 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
343 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
344};
345
346static void sunxi_frontend_init(void)
347{
348 struct sunxi_ccm_reg * const ccm =
349 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
350 struct sunxi_de_fe_reg * const de_fe =
351 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
352 int i;
353
354 /* Clocks on */
355 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
356 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
357 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
358
359 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
360
361 for (i = 0; i < 32; i++) {
362 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
363 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
364 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
365 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
366 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
367 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
368 }
369
370 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
371}
372
373static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
374 unsigned int address)
375{
376 struct sunxi_de_fe_reg * const de_fe =
377 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
378
379 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
380 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
381 writel(mode->xres * 4, &de_fe->ch0_stride);
382 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
383 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
384
385 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
386 &de_fe->ch0_insize);
387 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
388 &de_fe->ch0_outsize);
389 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
390 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
391
392 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
393 &de_fe->ch1_insize);
394 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
395 &de_fe->ch1_outsize);
396 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
397 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
398
399 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
400}
401
402static void sunxi_frontend_enable(void)
403{
404 struct sunxi_de_fe_reg * const de_fe =
405 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
406
407 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
408}
409#else
410static void sunxi_frontend_init(void) {}
411static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
412 unsigned int address) {}
413static void sunxi_frontend_enable(void) {}
414#endif
415
Hans de Goedec06e00e2015-08-03 19:20:26 +0200416static bool sunxi_is_composite(void)
417{
418 switch (sunxi_display.monitor) {
419 case sunxi_monitor_none:
420 case sunxi_monitor_dvi:
421 case sunxi_monitor_hdmi:
422 case sunxi_monitor_lcd:
423 case sunxi_monitor_vga:
424 return false;
425 case sunxi_monitor_composite_pal:
426 case sunxi_monitor_composite_ntsc:
427 case sunxi_monitor_composite_pal_m:
428 case sunxi_monitor_composite_pal_nc:
429 return true;
430 }
431
432 return false; /* Never reached */
433}
434
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200435/*
436 * This is the entity that mixes and matches the different layers and inputs.
437 * Allwinner calls it the back-end, but i like composer better.
438 */
439static void sunxi_composer_init(void)
440{
441 struct sunxi_ccm_reg * const ccm =
442 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
443 struct sunxi_de_be_reg * const de_be =
444 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
445 int i;
446
Hans de Goedec3cc4262015-01-19 08:44:07 +0100447 sunxi_frontend_init();
448
Hans de Goedef07872b2015-04-06 20:33:34 +0200449#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100450 /* Reset off */
451 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
452#endif
453
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200454 /* Clocks on */
455 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100456#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200457 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100458#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200459 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
460
461 /* Engine bug, clear registers after reset */
462 for (i = 0x0800; i < 0x1000; i += 4)
463 writel(0, SUNXI_DE_BE0_BASE + i);
464
465 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
466}
467
Priit Laes82482d62018-10-23 20:20:31 +0300468static const u32 sunxi_rgb2yuv_coef[12] = {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200469 0x00000107, 0x00000204, 0x00000064, 0x00000108,
470 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
471 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
472};
473
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100474static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200475 unsigned int address)
476{
477 struct sunxi_de_be_reg * const de_be =
478 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200479 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200480
Hans de Goedec3cc4262015-01-19 08:44:07 +0100481 sunxi_frontend_mode_set(mode, address);
482
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200483 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
484 &de_be->disp_size);
485 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
486 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100487#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200488 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
489 writel(address << 3, &de_be->layer0_addr_low32b);
490 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100491#else
492 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
493#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200494 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
495
496 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200497 if (mode->vmode == FB_VMODE_INTERLACED)
498 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200499#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200500 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200501#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200502 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200503
504 if (sunxi_is_composite()) {
505 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
506 &de_be->output_color_ctrl);
507 for (i = 0; i < 12; i++)
508 writel(sunxi_rgb2yuv_coef[i],
509 &de_be->output_color_coef[i]);
510 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200511}
512
Hans de Goede4125f922014-12-21 14:49:34 +0100513static void sunxi_composer_enable(void)
514{
515 struct sunxi_de_be_reg * const de_be =
516 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
517
Hans de Goedec3cc4262015-01-19 08:44:07 +0100518 sunxi_frontend_enable();
519
Hans de Goede4125f922014-12-21 14:49:34 +0100520 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
521 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
522}
523
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200524static void sunxi_lcdc_init(void)
525{
526 struct sunxi_ccm_reg * const ccm =
527 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
528 struct sunxi_lcdc_reg * const lcdc =
529 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
530
531 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200532#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100533 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
534#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200535 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100536#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200537
538 /* Clock on */
539 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100540#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200541#ifdef CONFIG_SUNXI_GEN_SUN6I
542 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
543#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100544 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
545#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200546#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200547
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200548 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200549}
550
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100551static void sunxi_lcdc_panel_enable(void)
552{
Hans de Goedece9e3322015-02-16 17:26:41 +0100553 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100554
555 /*
556 * Start with backlight disabled to avoid the screen flashing to
557 * white while the lcd inits.
558 */
559 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200560 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100561 gpio_request(pin, "lcd_backlight_enable");
562 gpio_direction_output(pin, 0);
563 }
564
565 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200566 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100567 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100568 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100569 }
570
Hans de Goedece9e3322015-02-16 17:26:41 +0100571 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200572 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100573 gpio_request(reset_pin, "lcd_reset");
574 gpio_direction_output(reset_pin, 0); /* Assert reset */
575 }
576
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100577 /* Give the backlight some time to turn off and power up the panel. */
578 mdelay(40);
579 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200580 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100581 gpio_request(pin, "lcd_power");
582 gpio_direction_output(pin, 1);
583 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100584
Hans de Goede7783ab22015-04-22 17:45:59 +0200585 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100586 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100587}
588
589static void sunxi_lcdc_backlight_enable(void)
590{
591 int pin;
592
593 /*
594 * We want to have scanned out at least one frame before enabling the
595 * backlight to avoid the screen flashing to white when we enable it.
596 */
597 mdelay(40);
598
599 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200600 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100601 gpio_direction_output(pin, 1);
602
603 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200604#ifdef SUNXI_PWM_PIN0
605 if (pin == SUNXI_PWM_PIN0) {
606 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
607 SUNXI_PWM_CTRL_ENABLE0 |
608 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
609 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
610 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
611 return;
612 }
613#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200614 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100615 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100616}
617
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200618static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
619 struct display_timing *timing)
620{
621 timing->pixelclock.typ = mode->pixclock_khz * 1000;
622
623 timing->hactive.typ = mode->xres;
624 timing->hfront_porch.typ = mode->right_margin;
625 timing->hback_porch.typ = mode->left_margin;
626 timing->hsync_len.typ = mode->hsync_len;
627
628 timing->vactive.typ = mode->yres;
629 timing->vfront_porch.typ = mode->lower_margin;
630 timing->vback_porch.typ = mode->upper_margin;
631 timing->vsync_len.typ = mode->vsync_len;
632
Giulio Benetti105bdc62018-01-16 17:43:48 +0100633 timing->flags = 0;
634
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200635 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
636 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
637 else
638 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
639 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
640 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
641 else
642 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
643 if (mode->vmode == FB_VMODE_INTERLACED)
644 timing->flags |= DISPLAY_FLAGS_INTERLACED;
645}
646
Hans de Goede18366f72015-01-25 15:33:07 +0100647static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
648 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100649{
650 struct sunxi_lcdc_reg * const lcdc =
651 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700652 struct sunxi_ccm_reg * const ccm =
653 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200654 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200655 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100656
Lawrence Yuf721f962016-03-04 09:08:56 -0800657#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
658 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
659#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200660 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800661#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100662#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100663 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100664#endif
665#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100666 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100667#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200668#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
669 sunxi_gpio_set_drv(pin, 3);
670#endif
671 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100672
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700673 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
674 sunxi_is_composite());
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100675
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200676 sunxi_ctfb_mode_to_display_timing(mode, &timing);
677 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200678 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100679}
680
Hans de Goedec06e00e2015-08-03 19:20:26 +0200681#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100682static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100683 int *clk_div, int *clk_double,
684 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200685{
686 struct sunxi_lcdc_reg * const lcdc =
687 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700688 struct sunxi_ccm_reg * const ccm =
689 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200690 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200691
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200692 sunxi_ctfb_mode_to_display_timing(mode, &timing);
693 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200694 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200695
Hans de Goedec3d15042014-12-27 15:19:23 +0100696 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100697 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
698 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100699 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200700
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700701 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
702 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200703}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200704#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100705
706#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100707
Hans de Goedea2017e82014-12-20 13:38:06 +0100708static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
709{
710 struct sunxi_hdmi_reg * const hdmi =
711 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
712 u8 checksum = 0;
713 u8 avi_info_frame[17] = {
714 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 0x00
717 };
718 u8 vendor_info_frame[19] = {
719 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
720 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
721 0x00, 0x00, 0x00
722 };
723 int i;
724
725 if (mode->pixclock_khz <= 27000)
726 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
727 else
728 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
729
730 if (mode->xres * 100 / mode->yres < 156)
731 avi_info_frame[5] |= 0x18; /* 4 : 3 */
732 else
733 avi_info_frame[5] |= 0x28; /* 16 : 9 */
734
735 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
736 checksum += avi_info_frame[i];
737
738 avi_info_frame[3] = 0x100 - checksum;
739
740 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
741 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
742
743 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
744 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
745
746 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
747 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
748
749 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
750 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
751
752 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
753}
754
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100755static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100756 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200757{
758 struct sunxi_hdmi_reg * const hdmi =
759 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
760 int x, y;
761
762 /* Write clear interrupt status bits */
763 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
764
Hans de Goedea0b1b732014-12-21 14:37:45 +0100765 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100766 sunxi_hdmi_setup_info_frames(mode);
767
Hans de Goede95576692014-12-20 13:51:16 +0100768 /* Set input sync enable */
769 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
770
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200771 /* Init various registers, select pll3 as clock source */
772 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
773 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
774 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
775 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
776 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
777
778 /* Setup clk div and doubler */
779 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
780 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
781 if (!clk_double)
782 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
783
784 /* Setup timing registers */
785 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
786 &hdmi->video_size);
787
788 x = mode->hsync_len + mode->left_margin;
789 y = mode->vsync_len + mode->upper_margin;
790 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
791
792 x = mode->right_margin;
793 y = mode->lower_margin;
794 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
795
796 x = mode->hsync_len;
797 y = mode->vsync_len;
798 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
799
800 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
801 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
802
803 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
804 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
805}
806
Hans de Goede4125f922014-12-21 14:49:34 +0100807static void sunxi_hdmi_enable(void)
808{
809 struct sunxi_hdmi_reg * const hdmi =
810 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
811
812 udelay(100);
813 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
814}
815
Hans de Goedee9544592014-12-23 23:04:35 +0100816#endif /* CONFIG_VIDEO_HDMI */
817
Hans de Goedec06e00e2015-08-03 19:20:26 +0200818#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100819
Hans de Goedec06e00e2015-08-03 19:20:26 +0200820static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100821{
822 struct sunxi_ccm_reg * const ccm =
823 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
824 struct sunxi_tve_reg * const tve =
825 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
826
Hans de Goede8a195ca2015-08-06 12:08:33 +0200827 /* Reset off */
828 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100829 /* Clock on */
830 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
831
Hans de Goedec06e00e2015-08-03 19:20:26 +0200832 switch (sunxi_display.monitor) {
833 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200834 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200835 break;
836 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200837 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
838 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200839 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200840 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200841 break;
842 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200843 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
844 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200845 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200846 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200847 break;
848 case sunxi_monitor_none:
849 case sunxi_monitor_dvi:
850 case sunxi_monitor_hdmi:
851 case sunxi_monitor_lcd:
852 break;
853 }
Hans de Goede260f5202014-12-25 13:58:06 +0100854}
855
Hans de Goedec06e00e2015-08-03 19:20:26 +0200856#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100857
Hans de Goede115e4b42014-12-23 18:39:52 +0100858static void sunxi_drc_init(void)
859{
Hans de Goedef07872b2015-04-06 20:33:34 +0200860#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100861 struct sunxi_ccm_reg * const ccm =
862 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
863
864 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530865#ifdef CONFIG_MACH_SUN8I_A33
866 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
867#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100868 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
869 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
870#endif
871}
872
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800873#ifdef CONFIG_VIDEO_VGA_VIA_LCD
874static void sunxi_vga_external_dac_enable(void)
875{
876 int pin;
877
878 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200879 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800880 gpio_request(pin, "vga_enable");
881 gpio_direction_output(pin, 1);
882 }
883}
884#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
885
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200886#ifdef CONFIG_VIDEO_LCD_SSD2828
887static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
888{
889 struct ssd2828_config cfg = {
890 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
891 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
892 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
893 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
894 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
895 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
896 .ssd2828_color_depth = 24,
897#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
898 .mipi_dsi_number_of_data_lanes = 4,
899 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
900 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
901 .mipi_dsi_delay_after_set_display_on_ms = 200
902#else
903#error MIPI LCD panel needs configuration parameters
904#endif
905 };
906
907 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
908 printf("SSD2828: SPI pins are not properly configured\n");
909 return 1;
910 }
911 if (cfg.reset_pin == -1) {
912 printf("SSD2828: Reset pin is not properly configured\n");
913 return 1;
914 }
915
916 return ssd2828_init(&cfg, mode);
917}
918#endif /* CONFIG_VIDEO_LCD_SSD2828 */
919
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200920static void sunxi_engines_init(void)
921{
922 sunxi_composer_init();
923 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100924 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200925}
926
Hans de Goedea0b1b732014-12-21 14:37:45 +0100927static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100928 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200929{
Hans de Goede260f5202014-12-25 13:58:06 +0100930 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200931 struct sunxi_lcdc_reg * const lcdc =
932 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +0200933 struct sunxi_tve_reg * __maybe_unused const tve =
934 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +0100935
Hans de Goede4125f922014-12-21 14:49:34 +0100936 switch (sunxi_display.monitor) {
937 case sunxi_monitor_none:
938 break;
939 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +0100940 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +0100941#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +0100942 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +0100943 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +0100944 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
945 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200946 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +0100947 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +0100948#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100949 break;
950 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100951 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +0200952 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
953 /*
954 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200955 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +0200956 * to avoid turning this on when using hdmi output.
957 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200958 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +0200959 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
960 ANX9804_DATA_RATE_1620M,
961 sunxi_display.depth);
962 }
Hans de Goede743fb9552015-01-20 09:23:36 +0100963 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
964 mdelay(50); /* Wait for lcd controller power on */
965 hitachi_tx18d42vm_init();
966 }
Hans de Goede613dade2015-02-16 17:49:47 +0100967 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
968 unsigned int orig_i2c_bus = i2c_get_bus_num();
969 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
970 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
971 i2c_set_bus_num(orig_i2c_bus);
972 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100973 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100974 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100975 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200976 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200977#ifdef CONFIG_VIDEO_LCD_SSD2828
978 sunxi_ssd2828_init(mode);
979#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100980 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +0100981 break;
982 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +0100983#ifdef CONFIG_VIDEO_VGA
984 sunxi_composer_mode_set(mode, address);
985 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200986 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +0100987 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200988 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200989 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +0100990#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +0100991 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100992 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +0100993 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200994 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800995 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +0100996#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100997 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200998 case sunxi_monitor_composite_pal:
999 case sunxi_monitor_composite_ntsc:
1000 case sunxi_monitor_composite_pal_m:
1001 case sunxi_monitor_composite_pal_nc:
1002#ifdef CONFIG_VIDEO_COMPOSITE
1003 sunxi_composer_mode_set(mode, address);
1004 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1005 sunxi_tvencoder_mode_set();
1006 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001007 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001008 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001009#endif
1010 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001011 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001012}
1013
Hans de Goedea0b1b732014-12-21 14:37:45 +01001014static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1015{
1016 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001017 case sunxi_monitor_none: return "none";
1018 case sunxi_monitor_dvi: return "dvi";
1019 case sunxi_monitor_hdmi: return "hdmi";
1020 case sunxi_monitor_lcd: return "lcd";
1021 case sunxi_monitor_vga: return "vga";
1022 case sunxi_monitor_composite_pal: return "composite-pal";
1023 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1024 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1025 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001026 }
1027 return NULL; /* never reached */
1028}
1029
Hans de Goede6c912862015-02-02 17:13:29 +01001030ulong board_get_usable_ram_top(ulong total_size)
1031{
1032 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1033}
1034
Hans de Goedea2bba492015-08-03 23:01:38 +02001035static bool sunxi_has_hdmi(void)
1036{
1037#ifdef CONFIG_VIDEO_HDMI
1038 return true;
1039#else
1040 return false;
1041#endif
1042}
1043
1044static bool sunxi_has_lcd(void)
1045{
1046 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1047
1048 return lcd_mode[0] != 0;
1049}
1050
1051static bool sunxi_has_vga(void)
1052{
1053#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1054 return true;
1055#else
1056 return false;
1057#endif
1058}
1059
Hans de Goedec06e00e2015-08-03 19:20:26 +02001060static bool sunxi_has_composite(void)
1061{
1062#ifdef CONFIG_VIDEO_COMPOSITE
1063 return true;
1064#else
1065 return false;
1066#endif
1067}
1068
Hans de Goedea2bba492015-08-03 23:01:38 +02001069static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1070{
1071 if (allow_hdmi && sunxi_has_hdmi())
1072 return sunxi_monitor_dvi;
1073 else if (sunxi_has_lcd())
1074 return sunxi_monitor_lcd;
1075 else if (sunxi_has_vga())
1076 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001077 else if (sunxi_has_composite())
1078 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001079 else
1080 return sunxi_monitor_none;
1081}
1082
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001083void *video_hw_init(void)
1084{
1085 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001086 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001087 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001088 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001089#ifdef CONFIG_VIDEO_HDMI
Priit Laesa9d6db72018-12-19 15:06:09 +02001090 int hpd, hpd_delay, edid;
1091 bool hdmi_present;
Hans de Goedee9544592014-12-23 23:04:35 +01001092#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001093 int i, overscan_offset, overscan_x, overscan_y;
1094 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001095 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001096 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001097
1098 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1099
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001100 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1101 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001102#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001103 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001104 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001105 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001106#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001107 overscan_x = video_get_option_int(options, "overscan_x", -1);
1108 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001109 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001110 video_get_option_string(options, "monitor", mon, sizeof(mon),
1111 sunxi_get_mon_desc(sunxi_display.monitor));
1112 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1113 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1114 sunxi_display.monitor = i;
1115 break;
1116 }
1117 }
1118 if (i > SUNXI_MONITOR_LAST)
1119 printf("Unknown monitor: '%s', falling back to '%s'\n",
1120 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001121
Hans de Goede7977ec22014-12-25 13:52:04 +01001122#ifdef CONFIG_VIDEO_HDMI
1123 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1124 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1125 sunxi_display.monitor == sunxi_monitor_hdmi) {
1126 /* Always call hdp_detect, as it also enables clocks, etc. */
Priit Laesa9d6db72018-12-19 15:06:09 +02001127 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1128 if (hdmi_present && edid) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001129 printf("HDMI connected: ");
Priit Laesa9d6db72018-12-19 15:06:09 +02001130 if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
Hans de Goede7977ec22014-12-25 13:52:04 +01001131 mode = &custom;
Priit Laesa9d6db72018-12-19 15:06:09 +02001132 else
1133 hdmi_present = false;
1134 }
1135 /* Fall back to EDID in case HPD failed */
1136 if (edid && !hdmi_present) {
1137 if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1138 mode = &custom;
1139 hdmi_present = true;
1140 }
1141 }
1142 /* Shut down when display was not found */
1143 if ((hpd || edid) && !hdmi_present) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001144 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001145 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001146 } /* else continue with hdmi/dvi without a cable connected */
1147 }
1148#endif
1149
Hans de Goede4125f922014-12-21 14:49:34 +01001150 switch (sunxi_display.monitor) {
1151 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001152 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001153 case sunxi_monitor_dvi:
1154 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001155 if (!sunxi_has_hdmi()) {
1156 printf("HDMI/DVI not supported on this board\n");
1157 sunxi_display.monitor = sunxi_monitor_none;
1158 return NULL;
1159 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001160 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001161 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001162 if (!sunxi_has_lcd()) {
1163 printf("LCD not supported on this board\n");
1164 sunxi_display.monitor = sunxi_monitor_none;
1165 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001166 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001167 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1168 mode = &custom;
1169 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001170 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001171 if (!sunxi_has_vga()) {
1172 printf("VGA not supported on this board\n");
1173 sunxi_display.monitor = sunxi_monitor_none;
1174 return NULL;
1175 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001176 sunxi_display.depth = 18;
1177 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001178 case sunxi_monitor_composite_pal:
1179 case sunxi_monitor_composite_ntsc:
1180 case sunxi_monitor_composite_pal_m:
1181 case sunxi_monitor_composite_pal_nc:
1182 if (!sunxi_has_composite()) {
1183 printf("Composite video not supported on this board\n");
1184 sunxi_display.monitor = sunxi_monitor_none;
1185 return NULL;
1186 }
1187 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1188 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1189 mode = &composite_video_modes[0];
1190 else
1191 mode = &composite_video_modes[1];
1192 sunxi_display.depth = 24;
1193 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001194 }
1195
Hans de Goeded955f442015-08-05 00:06:47 +02001196 /* Yes these defaults are quite high, overscan on composite sucks... */
1197 if (overscan_x == -1)
1198 overscan_x = sunxi_is_composite() ? 32 : 0;
1199 if (overscan_y == -1)
1200 overscan_y = sunxi_is_composite() ? 20 : 0;
1201
Hans de Goede18799252015-02-02 18:00:53 +01001202 sunxi_display.fb_size =
1203 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001204 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1205 /* We want to keep the fb_base for simplefb page aligned, where as
1206 * the sunxi dma engines will happily accept an unaligned address. */
1207 if (overscan_offset)
1208 sunxi_display.fb_size += 0x1000;
1209
Hans de Goede18799252015-02-02 18:00:53 +01001210 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1211 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1212 sunxi_display.fb_size >> 10,
1213 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1214 return NULL;
1215 }
1216
Hans de Goeded955f442015-08-05 00:06:47 +02001217 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1218 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001219 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001220 sunxi_get_mon_desc(sunxi_display.monitor),
1221 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001222
Hans de Goede18799252015-02-02 18:00:53 +01001223 gd->fb_base = gd->bd->bi_dram[0].start +
1224 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001225 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001226
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001227#ifdef CONFIG_EFI_LOADER
1228 efi_add_memory_map(gd->fb_base,
1229 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1230 EFI_PAGE_SHIFT,
1231 EFI_RESERVED_MEMORY_TYPE, false);
1232#endif
1233
Hans de Goeded955f442015-08-05 00:06:47 +02001234 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1235 sunxi_display.fb_addr = gd->fb_base;
1236 if (overscan_offset) {
1237 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1238 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1239 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1240 flush_cache(gd->fb_base, sunxi_display.fb_size);
1241 }
1242 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001243
1244 /*
1245 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001246 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001247 */
Hans de Goeded955f442015-08-05 00:06:47 +02001248 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001249 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1250 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001251 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1252 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1253 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001254
1255 return graphic_device;
1256}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001257
1258/*
1259 * Simplefb support.
1260 */
1261#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1262int sunxi_simplefb_setup(void *blob)
1263{
1264 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1265 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001266 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001267 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001268
Hans de Goedec3cc4262015-01-19 08:44:07 +01001269#ifdef CONFIG_MACH_SUN4I
1270#define PIPELINE_PREFIX "de_fe0-"
1271#else
1272#define PIPELINE_PREFIX
1273#endif
1274
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001275 switch (sunxi_display.monitor) {
1276 case sunxi_monitor_none:
1277 return 0;
1278 case sunxi_monitor_dvi:
1279 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001280 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001281 break;
1282 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001283 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001284 break;
1285 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001286#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001287 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001288#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001289 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001290#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001291 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001292 case sunxi_monitor_composite_pal:
1293 case sunxi_monitor_composite_ntsc:
1294 case sunxi_monitor_composite_pal_m:
1295 case sunxi_monitor_composite_pal_nc:
1296 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1297 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001298 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001299
Icenowy Zheng067a6972017-10-26 11:14:45 +08001300 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001301 if (offset < 0) {
1302 eprintf("Cannot setup simplefb: node not found\n");
1303 return 0; /* Keep older kernels working */
1304 }
1305
Hans de Goede6c912862015-02-02 17:13:29 +01001306 /*
1307 * Do not report the framebuffer as free RAM to the OS, note we cannot
1308 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1309 * and e.g. Linux refuses to iomap RAM on ARM, see:
1310 * linux/arch/arm/mm/ioremap.c around line 301.
1311 */
1312 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001313 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001314 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1315 if (ret) {
1316 eprintf("Cannot setup simplefb: Error reserving memory\n");
1317 return ret;
1318 }
1319
Hans de Goeded955f442015-08-05 00:06:47 +02001320 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001321 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001322 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001323 if (ret)
1324 eprintf("Cannot setup simplefb: Error setting properties\n");
1325
1326 return ret;
1327}
1328#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */