blob: 4361a58cd7e39f752cbac103968e543f48654ddd [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>
Jagan Teki5bc34cb2021-02-22 00:12:34 +000010#include <display.h>
11#include <dm.h>
Simon Glass63334482019-11-14 12:57:39 -070012#include <cpu_func.h>
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +010013#include <efi_loader.h>
Simon Glass6980b6b2019-11-14 12:57:45 -070014#include <init.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070015#include <time.h>
Simon Glassdbd79542020-05-10 11:40:11 -060016#include <linux/delay.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020017
18#include <asm/arch/clock.h>
19#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010020#include <asm/arch/gpio.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020021#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020022#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020023#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020024#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010025#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020026#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020027#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010028#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020029#include <fdtdec.h>
30#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010031#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020032#include <malloc.h>
Jagan Teki5bc34cb2021-02-22 00:12:34 +000033#include <video.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020034#include <video_fb.h>
Jagan Teki5bc34cb2021-02-22 00:12:34 +000035#include <dm/uclass-internal.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020036#include "../videomodes.h"
37#include "../anx9804.h"
38#include "../hitachi_tx18d42vm_lcd.h"
39#include "../ssd2828.h"
Icenowy Zheng067a6972017-10-26 11:14:45 +080040#include "simplefb_common.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020041
Hans de Goede2d5d3022015-01-22 21:02:42 +010042#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
43#define PWM_ON 0
44#define PWM_OFF 1
45#else
46#define PWM_ON 1
47#define PWM_OFF 0
48#endif
49
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020050DECLARE_GLOBAL_DATA_PTR;
51
Jagan Teki5bc34cb2021-02-22 00:12:34 +000052/* Maximum LCD size we support */
53#define LCD_MAX_WIDTH 3840
54#define LCD_MAX_HEIGHT 2160
55#define LCD_MAX_LOG2_BPP VIDEO_BPP32
56
Hans de Goedea0b1b732014-12-21 14:37:45 +010057enum sunxi_monitor {
58 sunxi_monitor_none,
59 sunxi_monitor_dvi,
60 sunxi_monitor_hdmi,
61 sunxi_monitor_lcd,
62 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020063 sunxi_monitor_composite_pal,
64 sunxi_monitor_composite_ntsc,
65 sunxi_monitor_composite_pal_m,
66 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010067};
Hans de Goedec06e00e2015-08-03 19:20:26 +020068#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010069
Jagan Teki5bc34cb2021-02-22 00:12:34 +000070struct sunxi_display_priv {
Hans de Goedea0b1b732014-12-21 14:37:45 +010071 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010072 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020073 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010074 unsigned int fb_size;
Jagan Teki5bc34cb2021-02-22 00:12:34 +000075};
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020076
Hans de Goedec06e00e2015-08-03 19:20:26 +020077const struct ctfb_res_modes composite_video_modes[2] = {
78 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
79 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
80 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
81};
82
Hans de Goedee9544592014-12-23 23:04:35 +010083#ifdef CONFIG_VIDEO_HDMI
84
Hans de Goedea5aa95f2014-12-19 16:05:12 +010085/*
86 * Wait up to 200ms for value to be set in given part of reg.
87 */
88static int await_completion(u32 *reg, u32 mask, u32 val)
89{
90 unsigned long tmo = timer_get_us() + 200000;
91
92 while ((readl(reg) & mask) != val) {
93 if (timer_get_us() > tmo) {
94 printf("DDC: timeout reading EDID\n");
95 return -ETIME;
96 }
97 }
98 return 0;
99}
100
Hans de Goede91593712014-12-28 09:13:21 +0100101static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200102{
103 struct sunxi_ccm_reg * const ccm =
104 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
105 struct sunxi_hdmi_reg * const hdmi =
106 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +0100107 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200108
109 /* Set pll3 to 300MHz */
110 clock_set_pll3(300000000);
111
112 /* Set hdmi parent to pll3 */
113 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
114 CCM_HDMI_CTRL_PLL3);
115
116 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200117#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100118 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
119#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200120 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
121
122 /* Clock on */
123 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
124
125 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
126 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
127
Priit Laesc9ecd5c2018-12-19 15:06:08 +0200128 /* Enable PLLs for eventual DDC */
129 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
130 &hdmi->pad_ctrl1);
131 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
132 &hdmi->pll_ctrl);
133 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
134
Hans de Goede205a30c2014-12-20 15:15:23 +0100135 while (timer_get_us() < tmo) {
136 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
137 return 1;
138 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200139
Hans de Goede205a30c2014-12-20 15:15:23 +0100140 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100141}
142
143static void sunxi_hdmi_shutdown(void)
144{
145 struct sunxi_ccm_reg * const ccm =
146 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
147 struct sunxi_hdmi_reg * const hdmi =
148 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200149
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200150 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
151 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
152 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200153#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100154 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
155#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200156 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200157}
158
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100159static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
160{
161 struct sunxi_hdmi_reg * const hdmi =
162 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
163
164 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
165 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
166 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
167 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
168 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
169#ifndef CONFIG_MACH_SUN6I
170 writel(n, &hdmi->ddc_byte_count);
171 writel(cmnd, &hdmi->ddc_cmnd);
172#else
173 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
174#endif
175 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
176
177 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
178}
179
180static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
181{
182 struct sunxi_hdmi_reg * const hdmi =
183 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
184 int i, n;
185
186 while (count > 0) {
187 if (count > 16)
188 n = 16;
189 else
190 n = count;
191
192 if (sunxi_hdmi_ddc_do_command(
193 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
194 offset, n))
195 return -ETIME;
196
197 for (i = 0; i < n; i++)
198 *buf++ = readb(&hdmi->ddc_fifo_data);
199
200 offset += n;
201 count -= n;
202 }
203
204 return 0;
205}
206
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100207static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
208{
209 int r, retries = 2;
210
211 do {
212 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
213 if (r)
214 continue;
215 r = edid_check_checksum(buf);
216 if (r) {
217 printf("EDID block %d: checksum error%s\n",
218 block, retries ? ", retrying" : "");
219 }
220 } while (r && retries--);
221
222 return r;
223}
224
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000225static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
226 struct ctfb_res_modes *mode,
Priit Laesa9d6db72018-12-19 15:06:09 +0200227 bool verbose_mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100228{
229 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100230 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100231 struct edid_detailed_timing *t =
232 (struct edid_detailed_timing *)edid1.monitor_details.timing;
233 struct sunxi_hdmi_reg * const hdmi =
234 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
235 struct sunxi_ccm_reg * const ccm =
236 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100237 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100238
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100239 /* Reset i2c controller */
240 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
241 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
242 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
243 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
244 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
245 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
246 return -EIO;
247
248 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
249#ifndef CONFIG_MACH_SUN6I
250 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
251 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
252#endif
253
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100254 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100255 if (r == 0) {
256 r = edid_check_info(&edid1);
257 if (r) {
Priit Laesa9d6db72018-12-19 15:06:09 +0200258 if (verbose_mode)
259 printf("EDID: invalid EDID data\n");
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100260 r = -EINVAL;
261 }
262 }
263 if (r == 0) {
264 ext_blocks = edid1.extension_flag;
265 if (ext_blocks > 4)
266 ext_blocks = 4;
267 for (i = 0; i < ext_blocks; i++) {
268 if (sunxi_hdmi_edid_get_block(1 + i,
269 (u8 *)&cea681[i]) != 0) {
270 ext_blocks = i;
271 break;
272 }
273 }
274 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100275
276 /* Disable DDC engine, no longer needed */
277 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
278 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
279
280 if (r)
281 return r;
282
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100283 /* We want version 1.3 or 1.2 with detailed timing info */
284 if (edid1.version != 1 || (edid1.revision < 3 &&
285 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
286 printf("EDID: unsupported version %d.%d\n",
287 edid1.version, edid1.revision);
288 return -EINVAL;
289 }
290
291 /* Take the first usable detailed timing */
292 for (i = 0; i < 4; i++, t++) {
293 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
294 if (r == 0)
295 break;
296 }
297 if (i == 4) {
298 printf("EDID: no usable detailed timing found\n");
299 return -ENOENT;
300 }
301
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100302 /* Check for basic audio support, if found enable hdmi output */
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000303 sunxi_display->monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100304 for (i = 0; i < ext_blocks; i++) {
305 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
306 cea681[i].revision < 2)
307 continue;
308
309 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000310 sunxi_display->monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100311 }
312
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100313 return 0;
314}
315
Hans de Goedee9544592014-12-23 23:04:35 +0100316#endif /* CONFIG_VIDEO_HDMI */
317
Hans de Goedec3cc4262015-01-19 08:44:07 +0100318#ifdef CONFIG_MACH_SUN4I
319/*
320 * Testing has shown that on sun4i the display backend engine does not have
321 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
322 * fifo underruns. So on sun4i we use the display frontend engine to do the
323 * dma from memory, as the frontend does have deep enough fifo-s.
324 */
325
326static const u32 sun4i_vert_coef[32] = {
327 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
328 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
329 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
330 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
331 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
332 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
333 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
334 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
335};
336
337static const u32 sun4i_horz_coef[64] = {
338 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
339 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
340 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
341 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
342 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
343 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
344 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
345 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
346 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
347 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
348 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
349 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
350 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
351 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
352 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
353 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
354};
355
356static void sunxi_frontend_init(void)
357{
358 struct sunxi_ccm_reg * const ccm =
359 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
360 struct sunxi_de_fe_reg * const de_fe =
361 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
362 int i;
363
364 /* Clocks on */
365 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
366 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
367 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
368
369 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
370
371 for (i = 0; i < 32; i++) {
372 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
373 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
374 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
375 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
376 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
377 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
378 }
379
380 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
381}
382
383static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
384 unsigned int address)
385{
386 struct sunxi_de_fe_reg * const de_fe =
387 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
388
389 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
390 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
391 writel(mode->xres * 4, &de_fe->ch0_stride);
392 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
393 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
394
395 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
396 &de_fe->ch0_insize);
397 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
398 &de_fe->ch0_outsize);
399 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
400 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
401
402 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
403 &de_fe->ch1_insize);
404 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
405 &de_fe->ch1_outsize);
406 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
407 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
408
409 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
410}
411
412static void sunxi_frontend_enable(void)
413{
414 struct sunxi_de_fe_reg * const de_fe =
415 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
416
417 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
418}
419#else
420static void sunxi_frontend_init(void) {}
421static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
422 unsigned int address) {}
423static void sunxi_frontend_enable(void) {}
424#endif
425
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000426static bool sunxi_is_composite(enum sunxi_monitor monitor)
Hans de Goedec06e00e2015-08-03 19:20:26 +0200427{
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000428 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200429 case sunxi_monitor_none:
430 case sunxi_monitor_dvi:
431 case sunxi_monitor_hdmi:
432 case sunxi_monitor_lcd:
433 case sunxi_monitor_vga:
434 return false;
435 case sunxi_monitor_composite_pal:
436 case sunxi_monitor_composite_ntsc:
437 case sunxi_monitor_composite_pal_m:
438 case sunxi_monitor_composite_pal_nc:
439 return true;
440 }
441
442 return false; /* Never reached */
443}
444
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200445/*
446 * This is the entity that mixes and matches the different layers and inputs.
447 * Allwinner calls it the back-end, but i like composer better.
448 */
449static void sunxi_composer_init(void)
450{
451 struct sunxi_ccm_reg * const ccm =
452 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
453 struct sunxi_de_be_reg * const de_be =
454 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
455 int i;
456
Hans de Goedec3cc4262015-01-19 08:44:07 +0100457 sunxi_frontend_init();
458
Hans de Goedef07872b2015-04-06 20:33:34 +0200459#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100460 /* Reset off */
461 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
462#endif
463
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200464 /* Clocks on */
465 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100466#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200467 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100468#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200469 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
470
471 /* Engine bug, clear registers after reset */
472 for (i = 0x0800; i < 0x1000; i += 4)
473 writel(0, SUNXI_DE_BE0_BASE + i);
474
475 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
476}
477
Priit Laes82482d62018-10-23 20:20:31 +0300478static const u32 sunxi_rgb2yuv_coef[12] = {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200479 0x00000107, 0x00000204, 0x00000064, 0x00000108,
480 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
481 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
482};
483
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100484static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000485 unsigned int address,
486 enum sunxi_monitor monitor)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200487{
488 struct sunxi_de_be_reg * const de_be =
489 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200490 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200491
Hans de Goedec3cc4262015-01-19 08:44:07 +0100492 sunxi_frontend_mode_set(mode, address);
493
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200494 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
495 &de_be->disp_size);
496 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
497 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100498#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200499 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
500 writel(address << 3, &de_be->layer0_addr_low32b);
501 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100502#else
503 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
504#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200505 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
506
507 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200508 if (mode->vmode == FB_VMODE_INTERLACED)
509 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200510#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200511 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200512#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200513 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200514
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000515 if (sunxi_is_composite(monitor)) {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200516 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
517 &de_be->output_color_ctrl);
518 for (i = 0; i < 12; i++)
519 writel(sunxi_rgb2yuv_coef[i],
520 &de_be->output_color_coef[i]);
521 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200522}
523
Hans de Goede4125f922014-12-21 14:49:34 +0100524static void sunxi_composer_enable(void)
525{
526 struct sunxi_de_be_reg * const de_be =
527 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
528
Hans de Goedec3cc4262015-01-19 08:44:07 +0100529 sunxi_frontend_enable();
530
Hans de Goede4125f922014-12-21 14:49:34 +0100531 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
532 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
533}
534
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200535static void sunxi_lcdc_init(void)
536{
537 struct sunxi_ccm_reg * const ccm =
538 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
539 struct sunxi_lcdc_reg * const lcdc =
540 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
541
542 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200543#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100544 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
545#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200546 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100547#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200548
549 /* Clock on */
550 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100551#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200552#ifdef CONFIG_SUNXI_GEN_SUN6I
553 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
554#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100555 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
556#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200557#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200558
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200559 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200560}
561
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100562static void sunxi_lcdc_panel_enable(void)
563{
Hans de Goedece9e3322015-02-16 17:26:41 +0100564 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100565
566 /*
567 * Start with backlight disabled to avoid the screen flashing to
568 * white while the lcd inits.
569 */
570 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200571 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100572 gpio_request(pin, "lcd_backlight_enable");
573 gpio_direction_output(pin, 0);
574 }
575
576 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200577 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100578 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100579 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100580 }
581
Hans de Goedece9e3322015-02-16 17:26:41 +0100582 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200583 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100584 gpio_request(reset_pin, "lcd_reset");
585 gpio_direction_output(reset_pin, 0); /* Assert reset */
586 }
587
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100588 /* Give the backlight some time to turn off and power up the panel. */
589 mdelay(40);
590 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200591 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100592 gpio_request(pin, "lcd_power");
593 gpio_direction_output(pin, 1);
594 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100595
Hans de Goede7783ab22015-04-22 17:45:59 +0200596 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100597 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100598}
599
600static void sunxi_lcdc_backlight_enable(void)
601{
602 int pin;
603
604 /*
605 * We want to have scanned out at least one frame before enabling the
606 * backlight to avoid the screen flashing to white when we enable it.
607 */
608 mdelay(40);
609
610 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200611 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100612 gpio_direction_output(pin, 1);
613
614 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200615#ifdef SUNXI_PWM_PIN0
616 if (pin == SUNXI_PWM_PIN0) {
617 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
618 SUNXI_PWM_CTRL_ENABLE0 |
619 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
620 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
621 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
622 return;
623 }
624#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200625 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100626 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100627}
628
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000629static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
630 const struct ctfb_res_modes *mode,
Hans de Goede18366f72015-01-25 15:33:07 +0100631 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100632{
633 struct sunxi_lcdc_reg * const lcdc =
634 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700635 struct sunxi_ccm_reg * const ccm =
636 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200637 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200638 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100639
Lawrence Yuf721f962016-03-04 09:08:56 -0800640#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
641 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
642#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200643 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800644#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100645#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100646 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100647#endif
648#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100649 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100650#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200651#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
652 sunxi_gpio_set_drv(pin, 3);
653#endif
654 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100655
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700656 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000657 sunxi_is_composite(sunxi_display->monitor));
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100658
Giulio Benetti953f5ed2020-04-08 17:10:12 +0200659 video_ctfb_mode_to_display_timing(mode, &timing);
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200660 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000661 sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100662}
663
Hans de Goedec06e00e2015-08-03 19:20:26 +0200664#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100665static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100666 int *clk_div, int *clk_double,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000667 bool use_portd_hvsync,
668 enum sunxi_monitor monitor)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200669{
670 struct sunxi_lcdc_reg * const lcdc =
671 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700672 struct sunxi_ccm_reg * const ccm =
673 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200674 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200675
Giulio Benetti953f5ed2020-04-08 17:10:12 +0200676 video_ctfb_mode_to_display_timing(mode, &timing);
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200677 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000678 sunxi_is_composite(monitor));
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200679
Hans de Goedec3d15042014-12-27 15:19:23 +0100680 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100681 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
682 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100683 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200684
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700685 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000686 sunxi_is_composite(monitor));
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200687}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200688#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100689
690#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100691
Hans de Goedea2017e82014-12-20 13:38:06 +0100692static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
693{
694 struct sunxi_hdmi_reg * const hdmi =
695 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
696 u8 checksum = 0;
697 u8 avi_info_frame[17] = {
698 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700 0x00
701 };
702 u8 vendor_info_frame[19] = {
703 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
704 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705 0x00, 0x00, 0x00
706 };
707 int i;
708
709 if (mode->pixclock_khz <= 27000)
710 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
711 else
712 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
713
714 if (mode->xres * 100 / mode->yres < 156)
715 avi_info_frame[5] |= 0x18; /* 4 : 3 */
716 else
717 avi_info_frame[5] |= 0x28; /* 16 : 9 */
718
719 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
720 checksum += avi_info_frame[i];
721
722 avi_info_frame[3] = 0x100 - checksum;
723
724 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
725 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
726
727 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
728 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
729
730 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
731 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
732
733 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
734 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
735
736 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
737}
738
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100739static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000740 int clk_div, int clk_double,
741 enum sunxi_monitor monitor)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200742{
743 struct sunxi_hdmi_reg * const hdmi =
744 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
745 int x, y;
746
747 /* Write clear interrupt status bits */
748 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
749
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000750 if (monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100751 sunxi_hdmi_setup_info_frames(mode);
752
Hans de Goede95576692014-12-20 13:51:16 +0100753 /* Set input sync enable */
754 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
755
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200756 /* Init various registers, select pll3 as clock source */
757 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
758 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
759 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
760 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
761 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
762
763 /* Setup clk div and doubler */
764 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
765 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
766 if (!clk_double)
767 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
768
769 /* Setup timing registers */
770 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
771 &hdmi->video_size);
772
773 x = mode->hsync_len + mode->left_margin;
774 y = mode->vsync_len + mode->upper_margin;
775 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
776
777 x = mode->right_margin;
778 y = mode->lower_margin;
779 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
780
781 x = mode->hsync_len;
782 y = mode->vsync_len;
783 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
784
785 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
786 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
787
788 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
789 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
790}
791
Hans de Goede4125f922014-12-21 14:49:34 +0100792static void sunxi_hdmi_enable(void)
793{
794 struct sunxi_hdmi_reg * const hdmi =
795 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
796
797 udelay(100);
798 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
799}
800
Hans de Goedee9544592014-12-23 23:04:35 +0100801#endif /* CONFIG_VIDEO_HDMI */
802
Hans de Goedec06e00e2015-08-03 19:20:26 +0200803#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100804
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000805static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
Hans de Goede260f5202014-12-25 13:58:06 +0100806{
807 struct sunxi_ccm_reg * const ccm =
808 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
809 struct sunxi_tve_reg * const tve =
810 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
811
Hans de Goede8a195ca2015-08-06 12:08:33 +0200812 /* Reset off */
813 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100814 /* Clock on */
815 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
816
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000817 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200818 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200819 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200820 break;
821 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200822 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
823 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200824 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200825 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200826 break;
827 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200828 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
829 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200830 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200831 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200832 break;
833 case sunxi_monitor_none:
834 case sunxi_monitor_dvi:
835 case sunxi_monitor_hdmi:
836 case sunxi_monitor_lcd:
837 break;
838 }
Hans de Goede260f5202014-12-25 13:58:06 +0100839}
840
Hans de Goedec06e00e2015-08-03 19:20:26 +0200841#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100842
Hans de Goede115e4b42014-12-23 18:39:52 +0100843static void sunxi_drc_init(void)
844{
Hans de Goedef07872b2015-04-06 20:33:34 +0200845#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100846 struct sunxi_ccm_reg * const ccm =
847 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
848
849 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530850#ifdef CONFIG_MACH_SUN8I_A33
851 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
852#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100853 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
854 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
855#endif
856}
857
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800858#ifdef CONFIG_VIDEO_VGA_VIA_LCD
859static void sunxi_vga_external_dac_enable(void)
860{
861 int pin;
862
863 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200864 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800865 gpio_request(pin, "vga_enable");
866 gpio_direction_output(pin, 1);
867 }
868}
869#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
870
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200871#ifdef CONFIG_VIDEO_LCD_SSD2828
872static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
873{
874 struct ssd2828_config cfg = {
875 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
876 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
877 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
878 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
879 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
880 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
881 .ssd2828_color_depth = 24,
882#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
883 .mipi_dsi_number_of_data_lanes = 4,
884 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
885 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
886 .mipi_dsi_delay_after_set_display_on_ms = 200
887#else
888#error MIPI LCD panel needs configuration parameters
889#endif
890 };
891
892 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
893 printf("SSD2828: SPI pins are not properly configured\n");
894 return 1;
895 }
896 if (cfg.reset_pin == -1) {
897 printf("SSD2828: Reset pin is not properly configured\n");
898 return 1;
899 }
900
901 return ssd2828_init(&cfg, mode);
902}
903#endif /* CONFIG_VIDEO_LCD_SSD2828 */
904
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200905static void sunxi_engines_init(void)
906{
907 sunxi_composer_init();
908 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100909 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200910}
911
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000912static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
913 const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100914 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200915{
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000916 enum sunxi_monitor monitor = sunxi_display->monitor;
Hans de Goede260f5202014-12-25 13:58:06 +0100917 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200918 struct sunxi_lcdc_reg * const lcdc =
919 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +0200920 struct sunxi_tve_reg * __maybe_unused const tve =
921 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +0100922
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000923 switch (sunxi_display->monitor) {
Hans de Goede4125f922014-12-21 14:49:34 +0100924 case sunxi_monitor_none:
925 break;
926 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +0100927 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +0100928#ifdef CONFIG_VIDEO_HDMI
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000929 sunxi_composer_mode_set(mode, address, monitor);
930 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
931 sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
Hans de Goede4125f922014-12-21 14:49:34 +0100932 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000933 lcdc_enable(lcdc, sunxi_display->depth);
Hans de Goede4125f922014-12-21 14:49:34 +0100934 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +0100935#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100936 break;
937 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100938 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +0200939 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
940 /*
941 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200942 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +0200943 * to avoid turning this on when using hdmi output.
944 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200945 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +0200946 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
947 ANX9804_DATA_RATE_1620M,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000948 sunxi_display->depth);
Hans de Goede91f1b822015-08-08 16:13:53 +0200949 }
Hans de Goede743fb9552015-01-20 09:23:36 +0100950 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
951 mdelay(50); /* Wait for lcd controller power on */
952 hitachi_tx18d42vm_init();
953 }
Hans de Goede613dade2015-02-16 17:49:47 +0100954 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
955 unsigned int orig_i2c_bus = i2c_get_bus_num();
956 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
957 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
958 i2c_set_bus_num(orig_i2c_bus);
959 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000960 sunxi_composer_mode_set(mode, address, monitor);
961 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100962 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000963 lcdc_enable(lcdc, sunxi_display->depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200964#ifdef CONFIG_VIDEO_LCD_SSD2828
965 sunxi_ssd2828_init(mode);
966#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100967 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +0100968 break;
969 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +0100970#ifdef CONFIG_VIDEO_VGA
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000971 sunxi_composer_mode_set(mode, address, monitor);
972 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
973 sunxi_tvencoder_mode_set(monitor);
Hans de Goede260f5202014-12-25 13:58:06 +0100974 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000975 lcdc_enable(lcdc, sunxi_display->depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200976 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +0100977#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000978 sunxi_composer_mode_set(mode, address, monitor);
979 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +0100980 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000981 lcdc_enable(lcdc, sunxi_display->depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800982 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +0100983#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100984 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200985 case sunxi_monitor_composite_pal:
986 case sunxi_monitor_composite_ntsc:
987 case sunxi_monitor_composite_pal_m:
988 case sunxi_monitor_composite_pal_nc:
989#ifdef CONFIG_VIDEO_COMPOSITE
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000990 sunxi_composer_mode_set(mode, address, monitor);
991 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
992 sunxi_tvencoder_mode_set(monitor);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200993 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000994 lcdc_enable(lcdc, sunxi_display->depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200995 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200996#endif
997 break;
Hans de Goede4125f922014-12-21 14:49:34 +0100998 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200999}
1000
Hans de Goedea0b1b732014-12-21 14:37:45 +01001001static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1002{
1003 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001004 case sunxi_monitor_dvi: return "dvi";
1005 case sunxi_monitor_hdmi: return "hdmi";
1006 case sunxi_monitor_lcd: return "lcd";
1007 case sunxi_monitor_vga: return "vga";
1008 case sunxi_monitor_composite_pal: return "composite-pal";
1009 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1010 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1011 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Bin Meng12de4aa2020-04-06 06:06:58 -07001012 case sunxi_monitor_none: /* fall through */
1013 default: return "none";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001014 }
Hans de Goedea0b1b732014-12-21 14:37:45 +01001015}
1016
Hans de Goedea2bba492015-08-03 23:01:38 +02001017static bool sunxi_has_hdmi(void)
1018{
1019#ifdef CONFIG_VIDEO_HDMI
1020 return true;
1021#else
1022 return false;
1023#endif
1024}
1025
1026static bool sunxi_has_lcd(void)
1027{
1028 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1029
1030 return lcd_mode[0] != 0;
1031}
1032
1033static bool sunxi_has_vga(void)
1034{
1035#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1036 return true;
1037#else
1038 return false;
1039#endif
1040}
1041
Hans de Goedec06e00e2015-08-03 19:20:26 +02001042static bool sunxi_has_composite(void)
1043{
1044#ifdef CONFIG_VIDEO_COMPOSITE
1045 return true;
1046#else
1047 return false;
1048#endif
1049}
1050
Hans de Goedea2bba492015-08-03 23:01:38 +02001051static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1052{
1053 if (allow_hdmi && sunxi_has_hdmi())
1054 return sunxi_monitor_dvi;
1055 else if (sunxi_has_lcd())
1056 return sunxi_monitor_lcd;
1057 else if (sunxi_has_vga())
1058 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001059 else if (sunxi_has_composite())
1060 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001061 else
1062 return sunxi_monitor_none;
1063}
1064
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001065static int sunxi_de_probe(struct udevice *dev)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001066{
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001067 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
1068 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1069 struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001070 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001071 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001072 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001073#ifdef CONFIG_VIDEO_HDMI
Priit Laesa9d6db72018-12-19 15:06:09 +02001074 int hpd, hpd_delay, edid;
1075 bool hdmi_present;
Hans de Goedee9544592014-12-23 23:04:35 +01001076#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001077 int i, overscan_offset, overscan_x, overscan_y;
1078 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001079 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001080 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001081
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001082 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001083 &sunxi_display->depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001084#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001085 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001086 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001087 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001088#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001089 overscan_x = video_get_option_int(options, "overscan_x", -1);
1090 overscan_y = video_get_option_int(options, "overscan_y", -1);
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001091 sunxi_display->monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001092 video_get_option_string(options, "monitor", mon, sizeof(mon),
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001093 sunxi_get_mon_desc(sunxi_display->monitor));
Hans de Goedea0b1b732014-12-21 14:37:45 +01001094 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1095 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001096 sunxi_display->monitor = i;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001097 break;
1098 }
1099 }
1100 if (i > SUNXI_MONITOR_LAST)
1101 printf("Unknown monitor: '%s', falling back to '%s'\n",
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001102 mon, sunxi_get_mon_desc(sunxi_display->monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001103
Hans de Goede7977ec22014-12-25 13:52:04 +01001104#ifdef CONFIG_VIDEO_HDMI
1105 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001106 if (sunxi_display->monitor == sunxi_monitor_dvi ||
1107 sunxi_display->monitor == sunxi_monitor_hdmi) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001108 /* Always call hdp_detect, as it also enables clocks, etc. */
Priit Laesa9d6db72018-12-19 15:06:09 +02001109 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1110 if (hdmi_present && edid) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001111 printf("HDMI connected: ");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001112 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
Hans de Goede7977ec22014-12-25 13:52:04 +01001113 mode = &custom;
Priit Laesa9d6db72018-12-19 15:06:09 +02001114 else
1115 hdmi_present = false;
1116 }
1117 /* Fall back to EDID in case HPD failed */
1118 if (edid && !hdmi_present) {
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001119 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
Priit Laesa9d6db72018-12-19 15:06:09 +02001120 mode = &custom;
1121 hdmi_present = true;
1122 }
1123 }
1124 /* Shut down when display was not found */
1125 if ((hpd || edid) && !hdmi_present) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001126 sunxi_hdmi_shutdown();
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001127 sunxi_display->monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001128 } /* else continue with hdmi/dvi without a cable connected */
1129 }
1130#endif
1131
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001132 switch (sunxi_display->monitor) {
Hans de Goede4125f922014-12-21 14:49:34 +01001133 case sunxi_monitor_none:
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001134 printf("Unknown monitor\n");
1135 return -EINVAL;
Hans de Goede4125f922014-12-21 14:49:34 +01001136 case sunxi_monitor_dvi:
1137 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001138 if (!sunxi_has_hdmi()) {
1139 printf("HDMI/DVI not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001140 sunxi_display->monitor = sunxi_monitor_none;
1141 return -EINVAL;
Hans de Goedea2bba492015-08-03 23:01:38 +02001142 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001143 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001144 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001145 if (!sunxi_has_lcd()) {
1146 printf("LCD not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001147 sunxi_display->monitor = sunxi_monitor_none;
1148 return -EINVAL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001149 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001150 sunxi_display->depth = video_get_params(&custom, lcd_mode);
Hans de Goedea2bba492015-08-03 23:01:38 +02001151 mode = &custom;
1152 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001153 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001154 if (!sunxi_has_vga()) {
1155 printf("VGA not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001156 sunxi_display->monitor = sunxi_monitor_none;
1157 return -EINVAL;
Hans de Goedea2bba492015-08-03 23:01:38 +02001158 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001159 sunxi_display->depth = 18;
Hans de Goedeac1633c2014-12-24 12:17:07 +01001160 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001161 case sunxi_monitor_composite_pal:
1162 case sunxi_monitor_composite_ntsc:
1163 case sunxi_monitor_composite_pal_m:
1164 case sunxi_monitor_composite_pal_nc:
1165 if (!sunxi_has_composite()) {
1166 printf("Composite video not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001167 sunxi_display->monitor = sunxi_monitor_none;
1168 return -EINVAL;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001169 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001170 if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
1171 sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
Hans de Goedec06e00e2015-08-03 19:20:26 +02001172 mode = &composite_video_modes[0];
1173 else
1174 mode = &composite_video_modes[1];
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001175 sunxi_display->depth = 24;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001176 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001177 }
1178
Hans de Goeded955f442015-08-05 00:06:47 +02001179 /* Yes these defaults are quite high, overscan on composite sucks... */
1180 if (overscan_x == -1)
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001181 overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
Hans de Goeded955f442015-08-05 00:06:47 +02001182 if (overscan_y == -1)
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001183 overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
Hans de Goeded955f442015-08-05 00:06:47 +02001184
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001185 sunxi_display->fb_size = plat->size;
Hans de Goeded955f442015-08-05 00:06:47 +02001186 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1187 /* We want to keep the fb_base for simplefb page aligned, where as
1188 * the sunxi dma engines will happily accept an unaligned address. */
1189 if (overscan_offset)
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001190 sunxi_display->fb_size += 0x1000;
Hans de Goede18799252015-02-02 18:00:53 +01001191
Hans de Goeded955f442015-08-05 00:06:47 +02001192 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1193 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001194 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001195 sunxi_get_mon_desc(sunxi_display->monitor),
Hans de Goeded955f442015-08-05 00:06:47 +02001196 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001197
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001198 sunxi_display->fb_addr = plat->base;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001199 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001200
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001201#ifdef CONFIG_EFI_LOADER
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001202 efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
Michael Walle282d3862020-05-17 12:29:19 +02001203 EFI_RESERVED_MEMORY_TYPE);
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001204#endif
1205
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001206 fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
Hans de Goeded955f442015-08-05 00:06:47 +02001207 if (overscan_offset) {
1208 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001209 sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
1210 memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
1211 flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
Hans de Goeded955f442015-08-05 00:06:47 +02001212 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001213 sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001214
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001215 /* The members of struct video_priv to be set by the driver. */
1216 uc_priv->bpix = VIDEO_BPP32;
1217 uc_priv->xsize = mode->xres;
1218 uc_priv->ysize = mode->yres;
1219
1220 video_set_flush_dcache(dev, true);
1221
1222 return 0;
1223}
1224
1225static int sunxi_de_bind(struct udevice *dev)
1226{
1227 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001228
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001229 plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
1230
1231 return 0;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001232}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001233
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001234static const struct video_ops sunxi_de_ops = {
1235};
1236
1237U_BOOT_DRIVER(sunxi_de) = {
1238 .name = "sunxi_de",
1239 .id = UCLASS_VIDEO,
1240 .ops = &sunxi_de_ops,
1241 .bind = sunxi_de_bind,
1242 .probe = sunxi_de_probe,
1243 .priv_auto = sizeof(struct sunxi_display_priv),
1244 .flags = DM_FLAG_PRE_RELOC,
1245};
1246
1247U_BOOT_DRVINFO(sunxi_de) = {
1248 .name = "sunxi_de"
1249};
1250
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001251/*
1252 * Simplefb support.
1253 */
1254#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1255int sunxi_simplefb_setup(void *blob)
1256{
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001257 struct sunxi_display_priv *sunxi_display;
1258 struct video_priv *uc_priv;
1259 struct udevice *de;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001260 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001261 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001262 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001263
Hans de Goedec3cc4262015-01-19 08:44:07 +01001264#ifdef CONFIG_MACH_SUN4I
1265#define PIPELINE_PREFIX "de_fe0-"
1266#else
1267#define PIPELINE_PREFIX
1268#endif
1269
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001270 ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
1271 if (ret) {
1272 printf("DE not present\n");
1273 return 0;
1274 } else if (!device_active(de)) {
1275 printf("DE is present but not probed\n");
1276 return 0;
1277 }
1278
1279 uc_priv = dev_get_uclass_priv(de);
1280 sunxi_display = dev_get_priv(de);
1281
1282 switch (sunxi_display->monitor) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001283 case sunxi_monitor_none:
1284 return 0;
1285 case sunxi_monitor_dvi:
1286 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001287 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001288 break;
1289 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001290 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001291 break;
1292 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001293#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001294 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001295#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001296 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001297#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001298 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001299 case sunxi_monitor_composite_pal:
1300 case sunxi_monitor_composite_ntsc:
1301 case sunxi_monitor_composite_pal_m:
1302 case sunxi_monitor_composite_pal_nc:
1303 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1304 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001305 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001306
Icenowy Zheng067a6972017-10-26 11:14:45 +08001307 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001308 if (offset < 0) {
1309 eprintf("Cannot setup simplefb: node not found\n");
1310 return 0; /* Keep older kernels working */
1311 }
1312
Hans de Goede6c912862015-02-02 17:13:29 +01001313 /*
1314 * Do not report the framebuffer as free RAM to the OS, note we cannot
1315 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1316 * and e.g. Linux refuses to iomap RAM on ARM, see:
1317 * linux/arch/arm/mm/ioremap.c around line 301.
1318 */
1319 start = gd->bd->bi_dram[0].start;
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001320 size = sunxi_display->fb_addr - start;
Hans de Goede6c912862015-02-02 17:13:29 +01001321 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1322 if (ret) {
1323 eprintf("Cannot setup simplefb: Error reserving memory\n");
1324 return ret;
1325 }
1326
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001327 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
1328 uc_priv->xsize, uc_priv->ysize,
1329 VNBYTES(uc_priv->bpix) * uc_priv->xsize,
1330 "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001331 if (ret)
1332 eprintf("Cannot setup simplefb: Error setting properties\n");
1333
1334 return ret;
1335}
1336#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */