blob: da3e89882967dab523ed4ca798a57033bcbc976a [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>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020020#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020021#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020022#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020023#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010024#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020025#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020026#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010027#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020028#include <fdtdec.h>
29#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010030#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020031#include <malloc.h>
Jagan Teki5bc34cb2021-02-22 00:12:34 +000032#include <video.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020033#include <video_fb.h>
Jagan Teki5bc34cb2021-02-22 00:12:34 +000034#include <dm/uclass-internal.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020035#include "../videomodes.h"
36#include "../anx9804.h"
37#include "../hitachi_tx18d42vm_lcd.h"
38#include "../ssd2828.h"
Icenowy Zheng067a6972017-10-26 11:14:45 +080039#include "simplefb_common.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020040
Hans de Goede2d5d3022015-01-22 21:02:42 +010041#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
42#define PWM_ON 0
43#define PWM_OFF 1
44#else
45#define PWM_ON 1
46#define PWM_OFF 0
47#endif
48
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020049DECLARE_GLOBAL_DATA_PTR;
50
Jagan Teki5bc34cb2021-02-22 00:12:34 +000051/* Maximum LCD size we support */
52#define LCD_MAX_WIDTH 3840
53#define LCD_MAX_HEIGHT 2160
54#define LCD_MAX_LOG2_BPP VIDEO_BPP32
55
Hans de Goedea0b1b732014-12-21 14:37:45 +010056enum sunxi_monitor {
57 sunxi_monitor_none,
58 sunxi_monitor_dvi,
59 sunxi_monitor_hdmi,
60 sunxi_monitor_lcd,
61 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020062 sunxi_monitor_composite_pal,
63 sunxi_monitor_composite_ntsc,
64 sunxi_monitor_composite_pal_m,
65 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010066};
Hans de Goedec06e00e2015-08-03 19:20:26 +020067#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010068
Jagan Teki5bc34cb2021-02-22 00:12:34 +000069struct sunxi_display_priv {
Hans de Goedea0b1b732014-12-21 14:37:45 +010070 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010071 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020072 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010073 unsigned int fb_size;
Jagan Teki5bc34cb2021-02-22 00:12:34 +000074};
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020075
Hans de Goedec06e00e2015-08-03 19:20:26 +020076const struct ctfb_res_modes composite_video_modes[2] = {
77 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
78 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
79 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
80};
81
Hans de Goedee9544592014-12-23 23:04:35 +010082#ifdef CONFIG_VIDEO_HDMI
83
Hans de Goedea5aa95f2014-12-19 16:05:12 +010084/*
85 * Wait up to 200ms for value to be set in given part of reg.
86 */
87static int await_completion(u32 *reg, u32 mask, u32 val)
88{
89 unsigned long tmo = timer_get_us() + 200000;
90
91 while ((readl(reg) & mask) != val) {
92 if (timer_get_us() > tmo) {
93 printf("DDC: timeout reading EDID\n");
94 return -ETIME;
95 }
96 }
97 return 0;
98}
99
Hans de Goede91593712014-12-28 09:13:21 +0100100static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200101{
102 struct sunxi_ccm_reg * const ccm =
103 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
104 struct sunxi_hdmi_reg * const hdmi =
105 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +0100106 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200107
108 /* Set pll3 to 300MHz */
109 clock_set_pll3(300000000);
110
111 /* Set hdmi parent to pll3 */
112 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
113 CCM_HDMI_CTRL_PLL3);
114
115 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200116#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100117 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
118#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200119 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
120
121 /* Clock on */
122 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
123
124 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
125 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
126
Priit Laesc9ecd5c2018-12-19 15:06:08 +0200127 /* Enable PLLs for eventual DDC */
128 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
129 &hdmi->pad_ctrl1);
130 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
131 &hdmi->pll_ctrl);
132 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
133
Hans de Goede205a30c2014-12-20 15:15:23 +0100134 while (timer_get_us() < tmo) {
135 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
136 return 1;
137 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200138
Hans de Goede205a30c2014-12-20 15:15:23 +0100139 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100140}
141
142static void sunxi_hdmi_shutdown(void)
143{
144 struct sunxi_ccm_reg * const ccm =
145 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
146 struct sunxi_hdmi_reg * const hdmi =
147 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200148
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200149 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
150 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
151 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200152#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100153 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
154#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200155 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200156}
157
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100158static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
159{
160 struct sunxi_hdmi_reg * const hdmi =
161 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
162
163 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
164 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
165 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
166 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
167 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
168#ifndef CONFIG_MACH_SUN6I
169 writel(n, &hdmi->ddc_byte_count);
170 writel(cmnd, &hdmi->ddc_cmnd);
171#else
172 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
173#endif
174 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
175
176 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
177}
178
179static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
180{
181 struct sunxi_hdmi_reg * const hdmi =
182 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
183 int i, n;
184
185 while (count > 0) {
186 if (count > 16)
187 n = 16;
188 else
189 n = count;
190
191 if (sunxi_hdmi_ddc_do_command(
192 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
193 offset, n))
194 return -ETIME;
195
196 for (i = 0; i < n; i++)
197 *buf++ = readb(&hdmi->ddc_fifo_data);
198
199 offset += n;
200 count -= n;
201 }
202
203 return 0;
204}
205
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100206static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
207{
208 int r, retries = 2;
209
210 do {
211 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
212 if (r)
213 continue;
214 r = edid_check_checksum(buf);
215 if (r) {
216 printf("EDID block %d: checksum error%s\n",
217 block, retries ? ", retrying" : "");
218 }
219 } while (r && retries--);
220
221 return r;
222}
223
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000224static int sunxi_hdmi_edid_get_mode(struct sunxi_display_priv *sunxi_display,
225 struct ctfb_res_modes *mode,
Priit Laesa9d6db72018-12-19 15:06:09 +0200226 bool verbose_mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100227{
228 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100229 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100230 struct edid_detailed_timing *t =
231 (struct edid_detailed_timing *)edid1.monitor_details.timing;
232 struct sunxi_hdmi_reg * const hdmi =
233 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
234 struct sunxi_ccm_reg * const ccm =
235 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100236 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100237
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100238 /* Reset i2c controller */
239 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
240 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
241 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
242 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
243 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
244 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
245 return -EIO;
246
247 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
248#ifndef CONFIG_MACH_SUN6I
249 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
250 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
251#endif
252
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100253 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100254 if (r == 0) {
255 r = edid_check_info(&edid1);
256 if (r) {
Priit Laesa9d6db72018-12-19 15:06:09 +0200257 if (verbose_mode)
258 printf("EDID: invalid EDID data\n");
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100259 r = -EINVAL;
260 }
261 }
262 if (r == 0) {
263 ext_blocks = edid1.extension_flag;
264 if (ext_blocks > 4)
265 ext_blocks = 4;
266 for (i = 0; i < ext_blocks; i++) {
267 if (sunxi_hdmi_edid_get_block(1 + i,
268 (u8 *)&cea681[i]) != 0) {
269 ext_blocks = i;
270 break;
271 }
272 }
273 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100274
275 /* Disable DDC engine, no longer needed */
276 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
277 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
278
279 if (r)
280 return r;
281
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100282 /* We want version 1.3 or 1.2 with detailed timing info */
283 if (edid1.version != 1 || (edid1.revision < 3 &&
284 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
285 printf("EDID: unsupported version %d.%d\n",
286 edid1.version, edid1.revision);
287 return -EINVAL;
288 }
289
290 /* Take the first usable detailed timing */
291 for (i = 0; i < 4; i++, t++) {
292 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
293 if (r == 0)
294 break;
295 }
296 if (i == 4) {
297 printf("EDID: no usable detailed timing found\n");
298 return -ENOENT;
299 }
300
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100301 /* Check for basic audio support, if found enable hdmi output */
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000302 sunxi_display->monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100303 for (i = 0; i < ext_blocks; i++) {
304 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
305 cea681[i].revision < 2)
306 continue;
307
308 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000309 sunxi_display->monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100310 }
311
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100312 return 0;
313}
314
Hans de Goedee9544592014-12-23 23:04:35 +0100315#endif /* CONFIG_VIDEO_HDMI */
316
Hans de Goedec3cc4262015-01-19 08:44:07 +0100317#ifdef CONFIG_MACH_SUN4I
318/*
319 * Testing has shown that on sun4i the display backend engine does not have
320 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
321 * fifo underruns. So on sun4i we use the display frontend engine to do the
322 * dma from memory, as the frontend does have deep enough fifo-s.
323 */
324
325static const u32 sun4i_vert_coef[32] = {
326 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
327 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
328 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
329 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
330 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
331 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
332 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
333 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
334};
335
336static const u32 sun4i_horz_coef[64] = {
337 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
338 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
339 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
340 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
341 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
342 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
343 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
344 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
345 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
346 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
347 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
348 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
349 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
350 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
351 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
352 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
353};
354
355static void sunxi_frontend_init(void)
356{
357 struct sunxi_ccm_reg * const ccm =
358 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
359 struct sunxi_de_fe_reg * const de_fe =
360 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
361 int i;
362
363 /* Clocks on */
364 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
365 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
366 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
367
368 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
369
370 for (i = 0; i < 32; i++) {
371 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
372 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
373 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
374 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
375 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
376 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
377 }
378
379 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
380}
381
382static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
383 unsigned int address)
384{
385 struct sunxi_de_fe_reg * const de_fe =
386 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
387
388 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
389 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
390 writel(mode->xres * 4, &de_fe->ch0_stride);
391 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
392 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
393
394 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
395 &de_fe->ch0_insize);
396 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
397 &de_fe->ch0_outsize);
398 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
399 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
400
401 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
402 &de_fe->ch1_insize);
403 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
404 &de_fe->ch1_outsize);
405 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
406 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
407
408 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
409}
410
411static void sunxi_frontend_enable(void)
412{
413 struct sunxi_de_fe_reg * const de_fe =
414 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
415
416 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
417}
418#else
419static void sunxi_frontend_init(void) {}
420static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
421 unsigned int address) {}
422static void sunxi_frontend_enable(void) {}
423#endif
424
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000425static bool sunxi_is_composite(enum sunxi_monitor monitor)
Hans de Goedec06e00e2015-08-03 19:20:26 +0200426{
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000427 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200428 case sunxi_monitor_none:
429 case sunxi_monitor_dvi:
430 case sunxi_monitor_hdmi:
431 case sunxi_monitor_lcd:
432 case sunxi_monitor_vga:
433 return false;
434 case sunxi_monitor_composite_pal:
435 case sunxi_monitor_composite_ntsc:
436 case sunxi_monitor_composite_pal_m:
437 case sunxi_monitor_composite_pal_nc:
438 return true;
439 }
440
441 return false; /* Never reached */
442}
443
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200444/*
445 * This is the entity that mixes and matches the different layers and inputs.
446 * Allwinner calls it the back-end, but i like composer better.
447 */
448static void sunxi_composer_init(void)
449{
450 struct sunxi_ccm_reg * const ccm =
451 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
452 struct sunxi_de_be_reg * const de_be =
453 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
454 int i;
455
Hans de Goedec3cc4262015-01-19 08:44:07 +0100456 sunxi_frontend_init();
457
Hans de Goedef07872b2015-04-06 20:33:34 +0200458#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100459 /* Reset off */
460 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
461#endif
462
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200463 /* Clocks on */
464 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100465#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200466 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100467#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200468 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
469
470 /* Engine bug, clear registers after reset */
471 for (i = 0x0800; i < 0x1000; i += 4)
472 writel(0, SUNXI_DE_BE0_BASE + i);
473
474 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
475}
476
Priit Laes82482d62018-10-23 20:20:31 +0300477static const u32 sunxi_rgb2yuv_coef[12] = {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200478 0x00000107, 0x00000204, 0x00000064, 0x00000108,
479 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
480 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
481};
482
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100483static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000484 unsigned int address,
485 enum sunxi_monitor monitor)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200486{
487 struct sunxi_de_be_reg * const de_be =
488 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200489 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200490
Hans de Goedec3cc4262015-01-19 08:44:07 +0100491 sunxi_frontend_mode_set(mode, address);
492
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200493 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
494 &de_be->disp_size);
495 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
496 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100497#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200498 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
499 writel(address << 3, &de_be->layer0_addr_low32b);
500 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100501#else
502 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
503#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200504 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
505
506 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200507 if (mode->vmode == FB_VMODE_INTERLACED)
508 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200509#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200510 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200511#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200512 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200513
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000514 if (sunxi_is_composite(monitor)) {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200515 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
516 &de_be->output_color_ctrl);
517 for (i = 0; i < 12; i++)
518 writel(sunxi_rgb2yuv_coef[i],
519 &de_be->output_color_coef[i]);
520 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200521}
522
Hans de Goede4125f922014-12-21 14:49:34 +0100523static void sunxi_composer_enable(void)
524{
525 struct sunxi_de_be_reg * const de_be =
526 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
527
Hans de Goedec3cc4262015-01-19 08:44:07 +0100528 sunxi_frontend_enable();
529
Hans de Goede4125f922014-12-21 14:49:34 +0100530 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
531 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
532}
533
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200534static void sunxi_lcdc_init(void)
535{
536 struct sunxi_ccm_reg * const ccm =
537 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
538 struct sunxi_lcdc_reg * const lcdc =
539 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
540
541 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200542#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100543 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
544#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200545 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100546#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200547
548 /* Clock on */
549 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100550#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200551#ifdef CONFIG_SUNXI_GEN_SUN6I
552 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
553#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100554 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
555#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200556#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200557
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200558 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200559}
560
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100561static void sunxi_lcdc_panel_enable(void)
562{
Hans de Goedece9e3322015-02-16 17:26:41 +0100563 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100564
565 /*
566 * Start with backlight disabled to avoid the screen flashing to
567 * white while the lcd inits.
568 */
569 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200570 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100571 gpio_request(pin, "lcd_backlight_enable");
572 gpio_direction_output(pin, 0);
573 }
574
575 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200576 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100577 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100578 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100579 }
580
Hans de Goedece9e3322015-02-16 17:26:41 +0100581 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200582 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100583 gpio_request(reset_pin, "lcd_reset");
584 gpio_direction_output(reset_pin, 0); /* Assert reset */
585 }
586
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100587 /* Give the backlight some time to turn off and power up the panel. */
588 mdelay(40);
589 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200590 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100591 gpio_request(pin, "lcd_power");
592 gpio_direction_output(pin, 1);
593 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100594
Hans de Goede7783ab22015-04-22 17:45:59 +0200595 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100596 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100597}
598
599static void sunxi_lcdc_backlight_enable(void)
600{
601 int pin;
602
603 /*
604 * We want to have scanned out at least one frame before enabling the
605 * backlight to avoid the screen flashing to white when we enable it.
606 */
607 mdelay(40);
608
609 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200610 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100611 gpio_direction_output(pin, 1);
612
613 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200614#ifdef SUNXI_PWM_PIN0
615 if (pin == SUNXI_PWM_PIN0) {
616 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
617 SUNXI_PWM_CTRL_ENABLE0 |
618 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
619 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
620 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
621 return;
622 }
623#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200624 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100625 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100626}
627
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000628static void sunxi_lcdc_tcon0_mode_set(struct sunxi_display_priv *sunxi_display,
629 const struct ctfb_res_modes *mode,
Hans de Goede18366f72015-01-25 15:33:07 +0100630 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100631{
632 struct sunxi_lcdc_reg * const lcdc =
633 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700634 struct sunxi_ccm_reg * const ccm =
635 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200636 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200637 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100638
Lawrence Yuf721f962016-03-04 09:08:56 -0800639#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
640 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
641#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200642 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800643#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100644#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100645 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100646#endif
647#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100648 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100649#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200650#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
651 sunxi_gpio_set_drv(pin, 3);
652#endif
653 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100654
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700655 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000656 sunxi_is_composite(sunxi_display->monitor));
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100657
Giulio Benetti953f5ed2020-04-08 17:10:12 +0200658 video_ctfb_mode_to_display_timing(mode, &timing);
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200659 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000660 sunxi_display->depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100661}
662
Hans de Goedec06e00e2015-08-03 19:20:26 +0200663#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100664static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100665 int *clk_div, int *clk_double,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000666 bool use_portd_hvsync,
667 enum sunxi_monitor monitor)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200668{
669 struct sunxi_lcdc_reg * const lcdc =
670 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700671 struct sunxi_ccm_reg * const ccm =
672 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200673 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200674
Giulio Benetti953f5ed2020-04-08 17:10:12 +0200675 video_ctfb_mode_to_display_timing(mode, &timing);
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200676 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000677 sunxi_is_composite(monitor));
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200678
Hans de Goedec3d15042014-12-27 15:19:23 +0100679 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100680 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
681 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100682 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200683
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700684 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000685 sunxi_is_composite(monitor));
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200686}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200687#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100688
689#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100690
Hans de Goedea2017e82014-12-20 13:38:06 +0100691static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
692{
693 struct sunxi_hdmi_reg * const hdmi =
694 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
695 u8 checksum = 0;
696 u8 avi_info_frame[17] = {
697 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699 0x00
700 };
701 u8 vendor_info_frame[19] = {
702 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
703 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704 0x00, 0x00, 0x00
705 };
706 int i;
707
708 if (mode->pixclock_khz <= 27000)
709 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
710 else
711 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
712
713 if (mode->xres * 100 / mode->yres < 156)
714 avi_info_frame[5] |= 0x18; /* 4 : 3 */
715 else
716 avi_info_frame[5] |= 0x28; /* 16 : 9 */
717
718 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
719 checksum += avi_info_frame[i];
720
721 avi_info_frame[3] = 0x100 - checksum;
722
723 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
724 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
725
726 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
727 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
728
729 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
730 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
731
732 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
733 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
734
735 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
736}
737
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100738static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000739 int clk_div, int clk_double,
740 enum sunxi_monitor monitor)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200741{
742 struct sunxi_hdmi_reg * const hdmi =
743 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
744 int x, y;
745
746 /* Write clear interrupt status bits */
747 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
748
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000749 if (monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100750 sunxi_hdmi_setup_info_frames(mode);
751
Hans de Goede95576692014-12-20 13:51:16 +0100752 /* Set input sync enable */
753 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
754
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200755 /* Init various registers, select pll3 as clock source */
756 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
757 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
758 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
759 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
760 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
761
762 /* Setup clk div and doubler */
763 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
764 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
765 if (!clk_double)
766 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
767
768 /* Setup timing registers */
769 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
770 &hdmi->video_size);
771
772 x = mode->hsync_len + mode->left_margin;
773 y = mode->vsync_len + mode->upper_margin;
774 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
775
776 x = mode->right_margin;
777 y = mode->lower_margin;
778 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
779
780 x = mode->hsync_len;
781 y = mode->vsync_len;
782 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
783
784 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
785 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
786
787 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
788 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
789}
790
Hans de Goede4125f922014-12-21 14:49:34 +0100791static void sunxi_hdmi_enable(void)
792{
793 struct sunxi_hdmi_reg * const hdmi =
794 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
795
796 udelay(100);
797 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
798}
799
Hans de Goedee9544592014-12-23 23:04:35 +0100800#endif /* CONFIG_VIDEO_HDMI */
801
Hans de Goedec06e00e2015-08-03 19:20:26 +0200802#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100803
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000804static void sunxi_tvencoder_mode_set(enum sunxi_monitor monitor)
Hans de Goede260f5202014-12-25 13:58:06 +0100805{
806 struct sunxi_ccm_reg * const ccm =
807 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
808 struct sunxi_tve_reg * const tve =
809 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
810
Hans de Goede8a195ca2015-08-06 12:08:33 +0200811 /* Reset off */
812 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100813 /* Clock on */
814 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
815
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000816 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200817 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200818 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200819 break;
820 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200821 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
822 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200823 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200824 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200825 break;
826 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200827 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
828 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200829 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200830 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200831 break;
832 case sunxi_monitor_none:
833 case sunxi_monitor_dvi:
834 case sunxi_monitor_hdmi:
835 case sunxi_monitor_lcd:
836 break;
837 }
Hans de Goede260f5202014-12-25 13:58:06 +0100838}
839
Hans de Goedec06e00e2015-08-03 19:20:26 +0200840#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100841
Hans de Goede115e4b42014-12-23 18:39:52 +0100842static void sunxi_drc_init(void)
843{
Hans de Goedef07872b2015-04-06 20:33:34 +0200844#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100845 struct sunxi_ccm_reg * const ccm =
846 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
847
848 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530849#ifdef CONFIG_MACH_SUN8I_A33
850 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
851#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100852 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
853 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
854#endif
855}
856
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800857#ifdef CONFIG_VIDEO_VGA_VIA_LCD
858static void sunxi_vga_external_dac_enable(void)
859{
860 int pin;
861
862 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200863 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800864 gpio_request(pin, "vga_enable");
865 gpio_direction_output(pin, 1);
866 }
867}
868#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
869
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200870#ifdef CONFIG_VIDEO_LCD_SSD2828
871static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
872{
873 struct ssd2828_config cfg = {
Samuel Hollandc7ab95d2021-09-11 16:50:48 -0500874 .csx_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
875 .sck_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
876 .sdi_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
877 .sdo_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
878 .reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200879 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
880 .ssd2828_color_depth = 24,
881#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
882 .mipi_dsi_number_of_data_lanes = 4,
883 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
884 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
885 .mipi_dsi_delay_after_set_display_on_ms = 200
886#else
887#error MIPI LCD panel needs configuration parameters
888#endif
889 };
890
891 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
892 printf("SSD2828: SPI pins are not properly configured\n");
893 return 1;
894 }
895 if (cfg.reset_pin == -1) {
896 printf("SSD2828: Reset pin is not properly configured\n");
897 return 1;
898 }
899
900 return ssd2828_init(&cfg, mode);
901}
902#endif /* CONFIG_VIDEO_LCD_SSD2828 */
903
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200904static void sunxi_engines_init(void)
905{
906 sunxi_composer_init();
907 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100908 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200909}
910
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000911static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display,
912 const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100913 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200914{
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000915 enum sunxi_monitor monitor = sunxi_display->monitor;
Hans de Goede260f5202014-12-25 13:58:06 +0100916 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200917 struct sunxi_lcdc_reg * const lcdc =
918 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +0200919 struct sunxi_tve_reg * __maybe_unused const tve =
920 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +0100921
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000922 switch (sunxi_display->monitor) {
Hans de Goede4125f922014-12-21 14:49:34 +0100923 case sunxi_monitor_none:
924 break;
925 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +0100926 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +0100927#ifdef CONFIG_VIDEO_HDMI
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000928 sunxi_composer_mode_set(mode, address, monitor);
929 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
930 sunxi_hdmi_mode_set(mode, clk_div, clk_double, monitor);
Hans de Goede4125f922014-12-21 14:49:34 +0100931 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000932 lcdc_enable(lcdc, sunxi_display->depth);
Hans de Goede4125f922014-12-21 14:49:34 +0100933 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +0100934#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100935 break;
936 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100937 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +0200938 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
939 /*
940 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200941 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +0200942 * to avoid turning this on when using hdmi output.
943 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200944 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +0200945 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
946 ANX9804_DATA_RATE_1620M,
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000947 sunxi_display->depth);
Hans de Goede91f1b822015-08-08 16:13:53 +0200948 }
Hans de Goede743fb9552015-01-20 09:23:36 +0100949 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
950 mdelay(50); /* Wait for lcd controller power on */
951 hitachi_tx18d42vm_init();
952 }
Hans de Goede613dade2015-02-16 17:49:47 +0100953 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
954 unsigned int orig_i2c_bus = i2c_get_bus_num();
955 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
956 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
957 i2c_set_bus_num(orig_i2c_bus);
958 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000959 sunxi_composer_mode_set(mode, address, monitor);
960 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100961 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000962 lcdc_enable(lcdc, sunxi_display->depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200963#ifdef CONFIG_VIDEO_LCD_SSD2828
964 sunxi_ssd2828_init(mode);
965#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100966 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +0100967 break;
968 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +0100969#ifdef CONFIG_VIDEO_VGA
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000970 sunxi_composer_mode_set(mode, address, monitor);
971 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1, monitor);
972 sunxi_tvencoder_mode_set(monitor);
Hans de Goede260f5202014-12-25 13:58:06 +0100973 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000974 lcdc_enable(lcdc, sunxi_display->depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200975 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +0100976#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000977 sunxi_composer_mode_set(mode, address, monitor);
978 sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +0100979 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000980 lcdc_enable(lcdc, sunxi_display->depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800981 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +0100982#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100983 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200984 case sunxi_monitor_composite_pal:
985 case sunxi_monitor_composite_ntsc:
986 case sunxi_monitor_composite_pal_m:
987 case sunxi_monitor_composite_pal_nc:
988#ifdef CONFIG_VIDEO_COMPOSITE
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000989 sunxi_composer_mode_set(mode, address, monitor);
990 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0, monitor);
991 sunxi_tvencoder_mode_set(monitor);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200992 sunxi_composer_enable();
Jagan Teki5bc34cb2021-02-22 00:12:34 +0000993 lcdc_enable(lcdc, sunxi_display->depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200994 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200995#endif
996 break;
Hans de Goede4125f922014-12-21 14:49:34 +0100997 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200998}
999
Hans de Goedea0b1b732014-12-21 14:37:45 +01001000static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1001{
1002 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001003 case sunxi_monitor_dvi: return "dvi";
1004 case sunxi_monitor_hdmi: return "hdmi";
1005 case sunxi_monitor_lcd: return "lcd";
1006 case sunxi_monitor_vga: return "vga";
1007 case sunxi_monitor_composite_pal: return "composite-pal";
1008 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1009 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1010 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Bin Meng12de4aa2020-04-06 06:06:58 -07001011 case sunxi_monitor_none: /* fall through */
1012 default: return "none";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001013 }
Hans de Goedea0b1b732014-12-21 14:37:45 +01001014}
1015
Hans de Goedea2bba492015-08-03 23:01:38 +02001016static bool sunxi_has_hdmi(void)
1017{
1018#ifdef CONFIG_VIDEO_HDMI
1019 return true;
1020#else
1021 return false;
1022#endif
1023}
1024
1025static bool sunxi_has_lcd(void)
1026{
1027 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1028
1029 return lcd_mode[0] != 0;
1030}
1031
1032static bool sunxi_has_vga(void)
1033{
1034#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1035 return true;
1036#else
1037 return false;
1038#endif
1039}
1040
Hans de Goedec06e00e2015-08-03 19:20:26 +02001041static bool sunxi_has_composite(void)
1042{
1043#ifdef CONFIG_VIDEO_COMPOSITE
1044 return true;
1045#else
1046 return false;
1047#endif
1048}
1049
Hans de Goedea2bba492015-08-03 23:01:38 +02001050static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1051{
1052 if (allow_hdmi && sunxi_has_hdmi())
1053 return sunxi_monitor_dvi;
1054 else if (sunxi_has_lcd())
1055 return sunxi_monitor_lcd;
1056 else if (sunxi_has_vga())
1057 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001058 else if (sunxi_has_composite())
1059 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001060 else
1061 return sunxi_monitor_none;
1062}
1063
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001064static int sunxi_de_probe(struct udevice *dev)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001065{
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001066 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
1067 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
1068 struct sunxi_display_priv *sunxi_display = dev_get_priv(dev);
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001069 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001070 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001071 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001072#ifdef CONFIG_VIDEO_HDMI
Priit Laesa9d6db72018-12-19 15:06:09 +02001073 int hpd, hpd_delay, edid;
1074 bool hdmi_present;
Hans de Goedee9544592014-12-23 23:04:35 +01001075#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001076 int i, overscan_offset, overscan_x, overscan_y;
1077 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001078 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001079 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001080
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001081 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001082 &sunxi_display->depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001083#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001084 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001085 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001086 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001087#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001088 overscan_x = video_get_option_int(options, "overscan_x", -1);
1089 overscan_y = video_get_option_int(options, "overscan_y", -1);
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001090 sunxi_display->monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001091 video_get_option_string(options, "monitor", mon, sizeof(mon),
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001092 sunxi_get_mon_desc(sunxi_display->monitor));
Hans de Goedea0b1b732014-12-21 14:37:45 +01001093 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1094 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001095 sunxi_display->monitor = i;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001096 break;
1097 }
1098 }
1099 if (i > SUNXI_MONITOR_LAST)
1100 printf("Unknown monitor: '%s', falling back to '%s'\n",
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001101 mon, sunxi_get_mon_desc(sunxi_display->monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001102
Hans de Goede7977ec22014-12-25 13:52:04 +01001103#ifdef CONFIG_VIDEO_HDMI
1104 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001105 if (sunxi_display->monitor == sunxi_monitor_dvi ||
1106 sunxi_display->monitor == sunxi_monitor_hdmi) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001107 /* Always call hdp_detect, as it also enables clocks, etc. */
Priit Laesa9d6db72018-12-19 15:06:09 +02001108 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1109 if (hdmi_present && edid) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001110 printf("HDMI connected: ");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001111 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, true) == 0)
Hans de Goede7977ec22014-12-25 13:52:04 +01001112 mode = &custom;
Priit Laesa9d6db72018-12-19 15:06:09 +02001113 else
1114 hdmi_present = false;
1115 }
1116 /* Fall back to EDID in case HPD failed */
1117 if (edid && !hdmi_present) {
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001118 if (sunxi_hdmi_edid_get_mode(sunxi_display, &custom, false) == 0) {
Priit Laesa9d6db72018-12-19 15:06:09 +02001119 mode = &custom;
1120 hdmi_present = true;
1121 }
1122 }
1123 /* Shut down when display was not found */
1124 if ((hpd || edid) && !hdmi_present) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001125 sunxi_hdmi_shutdown();
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001126 sunxi_display->monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001127 } /* else continue with hdmi/dvi without a cable connected */
1128 }
1129#endif
1130
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001131 switch (sunxi_display->monitor) {
Hans de Goede4125f922014-12-21 14:49:34 +01001132 case sunxi_monitor_none:
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001133 printf("Unknown monitor\n");
1134 return -EINVAL;
Hans de Goede4125f922014-12-21 14:49:34 +01001135 case sunxi_monitor_dvi:
1136 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001137 if (!sunxi_has_hdmi()) {
1138 printf("HDMI/DVI not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001139 sunxi_display->monitor = sunxi_monitor_none;
1140 return -EINVAL;
Hans de Goedea2bba492015-08-03 23:01:38 +02001141 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001142 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001143 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001144 if (!sunxi_has_lcd()) {
1145 printf("LCD not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001146 sunxi_display->monitor = sunxi_monitor_none;
1147 return -EINVAL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001148 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001149 sunxi_display->depth = video_get_params(&custom, lcd_mode);
Hans de Goedea2bba492015-08-03 23:01:38 +02001150 mode = &custom;
1151 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001152 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001153 if (!sunxi_has_vga()) {
1154 printf("VGA not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001155 sunxi_display->monitor = sunxi_monitor_none;
1156 return -EINVAL;
Hans de Goedea2bba492015-08-03 23:01:38 +02001157 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001158 sunxi_display->depth = 18;
Hans de Goedeac1633c2014-12-24 12:17:07 +01001159 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001160 case sunxi_monitor_composite_pal:
1161 case sunxi_monitor_composite_ntsc:
1162 case sunxi_monitor_composite_pal_m:
1163 case sunxi_monitor_composite_pal_nc:
1164 if (!sunxi_has_composite()) {
1165 printf("Composite video not supported on this board\n");
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001166 sunxi_display->monitor = sunxi_monitor_none;
1167 return -EINVAL;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001168 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001169 if (sunxi_display->monitor == sunxi_monitor_composite_pal ||
1170 sunxi_display->monitor == sunxi_monitor_composite_pal_nc)
Hans de Goedec06e00e2015-08-03 19:20:26 +02001171 mode = &composite_video_modes[0];
1172 else
1173 mode = &composite_video_modes[1];
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001174 sunxi_display->depth = 24;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001175 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001176 }
1177
Hans de Goeded955f442015-08-05 00:06:47 +02001178 /* Yes these defaults are quite high, overscan on composite sucks... */
1179 if (overscan_x == -1)
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001180 overscan_x = sunxi_is_composite(sunxi_display->monitor) ? 32 : 0;
Hans de Goeded955f442015-08-05 00:06:47 +02001181 if (overscan_y == -1)
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001182 overscan_y = sunxi_is_composite(sunxi_display->monitor) ? 20 : 0;
Hans de Goeded955f442015-08-05 00:06:47 +02001183
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001184 sunxi_display->fb_size = plat->size;
Hans de Goeded955f442015-08-05 00:06:47 +02001185 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1186 /* We want to keep the fb_base for simplefb page aligned, where as
1187 * the sunxi dma engines will happily accept an unaligned address. */
1188 if (overscan_offset)
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001189 sunxi_display->fb_size += 0x1000;
Hans de Goede18799252015-02-02 18:00:53 +01001190
Hans de Goeded955f442015-08-05 00:06:47 +02001191 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1192 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001193 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001194 sunxi_get_mon_desc(sunxi_display->monitor),
Hans de Goeded955f442015-08-05 00:06:47 +02001195 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001196
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001197 sunxi_display->fb_addr = plat->base;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001198 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001199
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001200#ifdef CONFIG_EFI_LOADER
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001201 efi_add_memory_map(sunxi_display->fb_addr, sunxi_display->fb_size,
Michael Walle282d3862020-05-17 12:29:19 +02001202 EFI_RESERVED_MEMORY_TYPE);
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001203#endif
1204
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001205 fb_dma_addr = sunxi_display->fb_addr - CONFIG_SYS_SDRAM_BASE;
Hans de Goeded955f442015-08-05 00:06:47 +02001206 if (overscan_offset) {
1207 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001208 sunxi_display->fb_addr += ALIGN(overscan_offset, 0x1000);
1209 memset((void *)sunxi_display->fb_addr, 0, sunxi_display->fb_size);
1210 flush_cache(sunxi_display->fb_addr, sunxi_display->fb_size);
Hans de Goeded955f442015-08-05 00:06:47 +02001211 }
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001212 sunxi_mode_set(sunxi_display, mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001213
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001214 /* The members of struct video_priv to be set by the driver. */
1215 uc_priv->bpix = VIDEO_BPP32;
1216 uc_priv->xsize = mode->xres;
1217 uc_priv->ysize = mode->yres;
1218
1219 video_set_flush_dcache(dev, true);
1220
1221 return 0;
1222}
1223
1224static int sunxi_de_bind(struct udevice *dev)
1225{
1226 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001227
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001228 plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * VNBYTES(LCD_MAX_LOG2_BPP);
1229
1230 return 0;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001231}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001232
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001233static const struct video_ops sunxi_de_ops = {
1234};
1235
1236U_BOOT_DRIVER(sunxi_de) = {
1237 .name = "sunxi_de",
1238 .id = UCLASS_VIDEO,
1239 .ops = &sunxi_de_ops,
1240 .bind = sunxi_de_bind,
1241 .probe = sunxi_de_probe,
1242 .priv_auto = sizeof(struct sunxi_display_priv),
1243 .flags = DM_FLAG_PRE_RELOC,
1244};
1245
1246U_BOOT_DRVINFO(sunxi_de) = {
1247 .name = "sunxi_de"
1248};
1249
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001250/*
1251 * Simplefb support.
1252 */
1253#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1254int sunxi_simplefb_setup(void *blob)
1255{
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001256 struct sunxi_display_priv *sunxi_display;
1257 struct video_priv *uc_priv;
1258 struct udevice *de;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001259 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001260 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001261 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001262
Hans de Goedec3cc4262015-01-19 08:44:07 +01001263#ifdef CONFIG_MACH_SUN4I
1264#define PIPELINE_PREFIX "de_fe0-"
1265#else
1266#define PIPELINE_PREFIX
1267#endif
1268
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001269 ret = uclass_find_device_by_name(UCLASS_VIDEO, "sunxi_de", &de);
1270 if (ret) {
1271 printf("DE not present\n");
1272 return 0;
1273 } else if (!device_active(de)) {
1274 printf("DE is present but not probed\n");
1275 return 0;
1276 }
1277
1278 uc_priv = dev_get_uclass_priv(de);
1279 sunxi_display = dev_get_priv(de);
1280
1281 switch (sunxi_display->monitor) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001282 case sunxi_monitor_none:
1283 return 0;
1284 case sunxi_monitor_dvi:
1285 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001286 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001287 break;
1288 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001289 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001290 break;
1291 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001292#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001293 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001294#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001295 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001296#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001297 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001298 case sunxi_monitor_composite_pal:
1299 case sunxi_monitor_composite_ntsc:
1300 case sunxi_monitor_composite_pal_m:
1301 case sunxi_monitor_composite_pal_nc:
1302 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1303 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001304 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001305
Icenowy Zheng067a6972017-10-26 11:14:45 +08001306 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001307 if (offset < 0) {
1308 eprintf("Cannot setup simplefb: node not found\n");
1309 return 0; /* Keep older kernels working */
1310 }
1311
Hans de Goede6c912862015-02-02 17:13:29 +01001312 /*
1313 * Do not report the framebuffer as free RAM to the OS, note we cannot
1314 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1315 * and e.g. Linux refuses to iomap RAM on ARM, see:
1316 * linux/arch/arm/mm/ioremap.c around line 301.
1317 */
1318 start = gd->bd->bi_dram[0].start;
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001319 size = sunxi_display->fb_addr - start;
Hans de Goede6c912862015-02-02 17:13:29 +01001320 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1321 if (ret) {
1322 eprintf("Cannot setup simplefb: Error reserving memory\n");
1323 return ret;
1324 }
1325
Jagan Teki5bc34cb2021-02-22 00:12:34 +00001326 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display->fb_addr,
1327 uc_priv->xsize, uc_priv->ysize,
1328 VNBYTES(uc_priv->bpix) * uc_priv->xsize,
1329 "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001330 if (ret)
1331 eprintf("Cannot setup simplefb: Error setting properties\n");
1332
1333 return ret;
1334}
1335#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */