blob: c45b3ebe6ea5a304a0a99417a4a4c476e923363d [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>
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +010010#include <efi_loader.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070011#include <time.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020012
13#include <asm/arch/clock.h>
14#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010015#include <asm/arch/gpio.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020016#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020017#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020018#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020019#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010020#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020021#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020022#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010023#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020024#include <fdtdec.h>
25#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010026#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020027#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020028#include <video_fb.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020029#include "../videomodes.h"
30#include "../anx9804.h"
31#include "../hitachi_tx18d42vm_lcd.h"
32#include "../ssd2828.h"
Icenowy Zheng067a6972017-10-26 11:14:45 +080033#include "simplefb_common.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020034
Hans de Goede2d5d3022015-01-22 21:02:42 +010035#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
36#define PWM_ON 0
37#define PWM_OFF 1
38#else
39#define PWM_ON 1
40#define PWM_OFF 0
41#endif
42
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020043DECLARE_GLOBAL_DATA_PTR;
44
Hans de Goedea0b1b732014-12-21 14:37:45 +010045enum sunxi_monitor {
46 sunxi_monitor_none,
47 sunxi_monitor_dvi,
48 sunxi_monitor_hdmi,
49 sunxi_monitor_lcd,
50 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020051 sunxi_monitor_composite_pal,
52 sunxi_monitor_composite_ntsc,
53 sunxi_monitor_composite_pal_m,
54 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010055};
Hans de Goedec06e00e2015-08-03 19:20:26 +020056#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010057
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020058struct sunxi_display {
59 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010060 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010061 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020062 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010063 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020064} sunxi_display;
65
Hans de Goedec06e00e2015-08-03 19:20:26 +020066const struct ctfb_res_modes composite_video_modes[2] = {
67 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
68 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
69 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
70};
71
Hans de Goedee9544592014-12-23 23:04:35 +010072#ifdef CONFIG_VIDEO_HDMI
73
Hans de Goedea5aa95f2014-12-19 16:05:12 +010074/*
75 * Wait up to 200ms for value to be set in given part of reg.
76 */
77static int await_completion(u32 *reg, u32 mask, u32 val)
78{
79 unsigned long tmo = timer_get_us() + 200000;
80
81 while ((readl(reg) & mask) != val) {
82 if (timer_get_us() > tmo) {
83 printf("DDC: timeout reading EDID\n");
84 return -ETIME;
85 }
86 }
87 return 0;
88}
89
Hans de Goede91593712014-12-28 09:13:21 +010090static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020091{
92 struct sunxi_ccm_reg * const ccm =
93 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
94 struct sunxi_hdmi_reg * const hdmi =
95 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010096 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020097
98 /* Set pll3 to 300MHz */
99 clock_set_pll3(300000000);
100
101 /* Set hdmi parent to pll3 */
102 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
103 CCM_HDMI_CTRL_PLL3);
104
105 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200106#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100107 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
108#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200109 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
110
111 /* Clock on */
112 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
113
114 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
115 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
116
Priit Laesc9ecd5c2018-12-19 15:06:08 +0200117 /* Enable PLLs for eventual DDC */
118 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
119 &hdmi->pad_ctrl1);
120 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
121 &hdmi->pll_ctrl);
122 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
123
Hans de Goede205a30c2014-12-20 15:15:23 +0100124 while (timer_get_us() < tmo) {
125 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
126 return 1;
127 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200128
Hans de Goede205a30c2014-12-20 15:15:23 +0100129 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100130}
131
132static void sunxi_hdmi_shutdown(void)
133{
134 struct sunxi_ccm_reg * const ccm =
135 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
136 struct sunxi_hdmi_reg * const hdmi =
137 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200138
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200139 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
140 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
141 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200142#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100143 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
144#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200145 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200146}
147
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100148static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
149{
150 struct sunxi_hdmi_reg * const hdmi =
151 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
152
153 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
154 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
155 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
156 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
157 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
158#ifndef CONFIG_MACH_SUN6I
159 writel(n, &hdmi->ddc_byte_count);
160 writel(cmnd, &hdmi->ddc_cmnd);
161#else
162 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
163#endif
164 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
165
166 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
167}
168
169static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
170{
171 struct sunxi_hdmi_reg * const hdmi =
172 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
173 int i, n;
174
175 while (count > 0) {
176 if (count > 16)
177 n = 16;
178 else
179 n = count;
180
181 if (sunxi_hdmi_ddc_do_command(
182 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
183 offset, n))
184 return -ETIME;
185
186 for (i = 0; i < n; i++)
187 *buf++ = readb(&hdmi->ddc_fifo_data);
188
189 offset += n;
190 count -= n;
191 }
192
193 return 0;
194}
195
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100196static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
197{
198 int r, retries = 2;
199
200 do {
201 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
202 if (r)
203 continue;
204 r = edid_check_checksum(buf);
205 if (r) {
206 printf("EDID block %d: checksum error%s\n",
207 block, retries ? ", retrying" : "");
208 }
209 } while (r && retries--);
210
211 return r;
212}
213
Priit Laesa9d6db72018-12-19 15:06:09 +0200214static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode,
215 bool verbose_mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100216{
217 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100218 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100219 struct edid_detailed_timing *t =
220 (struct edid_detailed_timing *)edid1.monitor_details.timing;
221 struct sunxi_hdmi_reg * const hdmi =
222 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
223 struct sunxi_ccm_reg * const ccm =
224 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100225 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100226
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100227 /* Reset i2c controller */
228 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
229 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
230 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
231 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
232 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
233 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
234 return -EIO;
235
236 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
237#ifndef CONFIG_MACH_SUN6I
238 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
239 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
240#endif
241
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100242 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100243 if (r == 0) {
244 r = edid_check_info(&edid1);
245 if (r) {
Priit Laesa9d6db72018-12-19 15:06:09 +0200246 if (verbose_mode)
247 printf("EDID: invalid EDID data\n");
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100248 r = -EINVAL;
249 }
250 }
251 if (r == 0) {
252 ext_blocks = edid1.extension_flag;
253 if (ext_blocks > 4)
254 ext_blocks = 4;
255 for (i = 0; i < ext_blocks; i++) {
256 if (sunxi_hdmi_edid_get_block(1 + i,
257 (u8 *)&cea681[i]) != 0) {
258 ext_blocks = i;
259 break;
260 }
261 }
262 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100263
264 /* Disable DDC engine, no longer needed */
265 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
266 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
267
268 if (r)
269 return r;
270
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100271 /* We want version 1.3 or 1.2 with detailed timing info */
272 if (edid1.version != 1 || (edid1.revision < 3 &&
273 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
274 printf("EDID: unsupported version %d.%d\n",
275 edid1.version, edid1.revision);
276 return -EINVAL;
277 }
278
279 /* Take the first usable detailed timing */
280 for (i = 0; i < 4; i++, t++) {
281 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
282 if (r == 0)
283 break;
284 }
285 if (i == 4) {
286 printf("EDID: no usable detailed timing found\n");
287 return -ENOENT;
288 }
289
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100290 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100291 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100292 for (i = 0; i < ext_blocks; i++) {
293 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
294 cea681[i].revision < 2)
295 continue;
296
297 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100298 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100299 }
300
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100301 return 0;
302}
303
Hans de Goedee9544592014-12-23 23:04:35 +0100304#endif /* CONFIG_VIDEO_HDMI */
305
Hans de Goedec3cc4262015-01-19 08:44:07 +0100306#ifdef CONFIG_MACH_SUN4I
307/*
308 * Testing has shown that on sun4i the display backend engine does not have
309 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
310 * fifo underruns. So on sun4i we use the display frontend engine to do the
311 * dma from memory, as the frontend does have deep enough fifo-s.
312 */
313
314static const u32 sun4i_vert_coef[32] = {
315 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
316 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
317 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
318 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
319 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
320 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
321 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
322 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
323};
324
325static const u32 sun4i_horz_coef[64] = {
326 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
327 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
328 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
329 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
330 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
331 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
332 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
333 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
334 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
335 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
336 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
337 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
338 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
339 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
340 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
341 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
342};
343
344static void sunxi_frontend_init(void)
345{
346 struct sunxi_ccm_reg * const ccm =
347 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
348 struct sunxi_de_fe_reg * const de_fe =
349 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
350 int i;
351
352 /* Clocks on */
353 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
354 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
355 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
356
357 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
358
359 for (i = 0; i < 32; i++) {
360 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
361 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
362 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
363 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
364 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
365 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
366 }
367
368 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
369}
370
371static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
372 unsigned int address)
373{
374 struct sunxi_de_fe_reg * const de_fe =
375 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
376
377 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
378 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
379 writel(mode->xres * 4, &de_fe->ch0_stride);
380 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
381 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
382
383 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
384 &de_fe->ch0_insize);
385 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
386 &de_fe->ch0_outsize);
387 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
388 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
389
390 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
391 &de_fe->ch1_insize);
392 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
393 &de_fe->ch1_outsize);
394 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
395 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
396
397 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
398}
399
400static void sunxi_frontend_enable(void)
401{
402 struct sunxi_de_fe_reg * const de_fe =
403 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
404
405 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
406}
407#else
408static void sunxi_frontend_init(void) {}
409static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
410 unsigned int address) {}
411static void sunxi_frontend_enable(void) {}
412#endif
413
Hans de Goedec06e00e2015-08-03 19:20:26 +0200414static bool sunxi_is_composite(void)
415{
416 switch (sunxi_display.monitor) {
417 case sunxi_monitor_none:
418 case sunxi_monitor_dvi:
419 case sunxi_monitor_hdmi:
420 case sunxi_monitor_lcd:
421 case sunxi_monitor_vga:
422 return false;
423 case sunxi_monitor_composite_pal:
424 case sunxi_monitor_composite_ntsc:
425 case sunxi_monitor_composite_pal_m:
426 case sunxi_monitor_composite_pal_nc:
427 return true;
428 }
429
430 return false; /* Never reached */
431}
432
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200433/*
434 * This is the entity that mixes and matches the different layers and inputs.
435 * Allwinner calls it the back-end, but i like composer better.
436 */
437static void sunxi_composer_init(void)
438{
439 struct sunxi_ccm_reg * const ccm =
440 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
441 struct sunxi_de_be_reg * const de_be =
442 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
443 int i;
444
Hans de Goedec3cc4262015-01-19 08:44:07 +0100445 sunxi_frontend_init();
446
Hans de Goedef07872b2015-04-06 20:33:34 +0200447#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100448 /* Reset off */
449 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
450#endif
451
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200452 /* Clocks on */
453 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100454#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200455 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100456#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200457 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
458
459 /* Engine bug, clear registers after reset */
460 for (i = 0x0800; i < 0x1000; i += 4)
461 writel(0, SUNXI_DE_BE0_BASE + i);
462
463 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
464}
465
Priit Laes82482d62018-10-23 20:20:31 +0300466static const u32 sunxi_rgb2yuv_coef[12] = {
Hans de Goedec06e00e2015-08-03 19:20:26 +0200467 0x00000107, 0x00000204, 0x00000064, 0x00000108,
468 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
469 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
470};
471
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100472static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200473 unsigned int address)
474{
475 struct sunxi_de_be_reg * const de_be =
476 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200477 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200478
Hans de Goedec3cc4262015-01-19 08:44:07 +0100479 sunxi_frontend_mode_set(mode, address);
480
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200481 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
482 &de_be->disp_size);
483 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
484 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100485#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200486 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
487 writel(address << 3, &de_be->layer0_addr_low32b);
488 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100489#else
490 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
491#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200492 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
493
494 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200495 if (mode->vmode == FB_VMODE_INTERLACED)
496 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200497#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200498 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200499#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200500 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200501
502 if (sunxi_is_composite()) {
503 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
504 &de_be->output_color_ctrl);
505 for (i = 0; i < 12; i++)
506 writel(sunxi_rgb2yuv_coef[i],
507 &de_be->output_color_coef[i]);
508 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200509}
510
Hans de Goede4125f922014-12-21 14:49:34 +0100511static void sunxi_composer_enable(void)
512{
513 struct sunxi_de_be_reg * const de_be =
514 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
515
Hans de Goedec3cc4262015-01-19 08:44:07 +0100516 sunxi_frontend_enable();
517
Hans de Goede4125f922014-12-21 14:49:34 +0100518 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
519 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
520}
521
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200522static void sunxi_lcdc_init(void)
523{
524 struct sunxi_ccm_reg * const ccm =
525 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
526 struct sunxi_lcdc_reg * const lcdc =
527 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
528
529 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200530#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100531 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
532#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200533 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100534#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200535
536 /* Clock on */
537 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100538#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200539#ifdef CONFIG_SUNXI_GEN_SUN6I
540 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
541#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100542 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
543#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200544#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200545
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200546 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200547}
548
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100549static void sunxi_lcdc_panel_enable(void)
550{
Hans de Goedece9e3322015-02-16 17:26:41 +0100551 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100552
553 /*
554 * Start with backlight disabled to avoid the screen flashing to
555 * white while the lcd inits.
556 */
557 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200558 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100559 gpio_request(pin, "lcd_backlight_enable");
560 gpio_direction_output(pin, 0);
561 }
562
563 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200564 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100565 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100566 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100567 }
568
Hans de Goedece9e3322015-02-16 17:26:41 +0100569 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200570 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100571 gpio_request(reset_pin, "lcd_reset");
572 gpio_direction_output(reset_pin, 0); /* Assert reset */
573 }
574
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100575 /* Give the backlight some time to turn off and power up the panel. */
576 mdelay(40);
577 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200578 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100579 gpio_request(pin, "lcd_power");
580 gpio_direction_output(pin, 1);
581 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100582
Hans de Goede7783ab22015-04-22 17:45:59 +0200583 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100584 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100585}
586
587static void sunxi_lcdc_backlight_enable(void)
588{
589 int pin;
590
591 /*
592 * We want to have scanned out at least one frame before enabling the
593 * backlight to avoid the screen flashing to white when we enable it.
594 */
595 mdelay(40);
596
597 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200598 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100599 gpio_direction_output(pin, 1);
600
601 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200602#ifdef SUNXI_PWM_PIN0
603 if (pin == SUNXI_PWM_PIN0) {
604 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
605 SUNXI_PWM_CTRL_ENABLE0 |
606 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
607 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
608 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
609 return;
610 }
611#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200612 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100613 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100614}
615
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200616static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
617 struct display_timing *timing)
618{
619 timing->pixelclock.typ = mode->pixclock_khz * 1000;
620
621 timing->hactive.typ = mode->xres;
622 timing->hfront_porch.typ = mode->right_margin;
623 timing->hback_porch.typ = mode->left_margin;
624 timing->hsync_len.typ = mode->hsync_len;
625
626 timing->vactive.typ = mode->yres;
627 timing->vfront_porch.typ = mode->lower_margin;
628 timing->vback_porch.typ = mode->upper_margin;
629 timing->vsync_len.typ = mode->vsync_len;
630
Giulio Benetti105bdc62018-01-16 17:43:48 +0100631 timing->flags = 0;
632
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200633 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
634 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
635 else
636 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
637 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
638 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
639 else
640 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
641 if (mode->vmode == FB_VMODE_INTERLACED)
642 timing->flags |= DISPLAY_FLAGS_INTERLACED;
643}
644
Hans de Goede18366f72015-01-25 15:33:07 +0100645static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
646 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100647{
648 struct sunxi_lcdc_reg * const lcdc =
649 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700650 struct sunxi_ccm_reg * const ccm =
651 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200652 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200653 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100654
Lawrence Yuf721f962016-03-04 09:08:56 -0800655#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
656 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
657#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200658 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800659#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100660#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100661 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100662#endif
663#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100664 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100665#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200666#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
667 sunxi_gpio_set_drv(pin, 3);
668#endif
669 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100670
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700671 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
672 sunxi_is_composite());
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100673
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200674 sunxi_ctfb_mode_to_display_timing(mode, &timing);
675 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200676 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100677}
678
Hans de Goedec06e00e2015-08-03 19:20:26 +0200679#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100680static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100681 int *clk_div, int *clk_double,
682 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200683{
684 struct sunxi_lcdc_reg * const lcdc =
685 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700686 struct sunxi_ccm_reg * const ccm =
687 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200688 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200689
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200690 sunxi_ctfb_mode_to_display_timing(mode, &timing);
691 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200692 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200693
Hans de Goedec3d15042014-12-27 15:19:23 +0100694 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100695 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
696 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100697 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200698
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700699 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
700 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200701}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200702#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100703
704#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100705
Hans de Goedea2017e82014-12-20 13:38:06 +0100706static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
707{
708 struct sunxi_hdmi_reg * const hdmi =
709 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
710 u8 checksum = 0;
711 u8 avi_info_frame[17] = {
712 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 0x00
715 };
716 u8 vendor_info_frame[19] = {
717 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
718 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
719 0x00, 0x00, 0x00
720 };
721 int i;
722
723 if (mode->pixclock_khz <= 27000)
724 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
725 else
726 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
727
728 if (mode->xres * 100 / mode->yres < 156)
729 avi_info_frame[5] |= 0x18; /* 4 : 3 */
730 else
731 avi_info_frame[5] |= 0x28; /* 16 : 9 */
732
733 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
734 checksum += avi_info_frame[i];
735
736 avi_info_frame[3] = 0x100 - checksum;
737
738 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
739 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
740
741 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
742 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
743
744 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
745 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
746
747 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
748 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
749
750 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
751}
752
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100753static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100754 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200755{
756 struct sunxi_hdmi_reg * const hdmi =
757 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
758 int x, y;
759
760 /* Write clear interrupt status bits */
761 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
762
Hans de Goedea0b1b732014-12-21 14:37:45 +0100763 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100764 sunxi_hdmi_setup_info_frames(mode);
765
Hans de Goede95576692014-12-20 13:51:16 +0100766 /* Set input sync enable */
767 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
768
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200769 /* Init various registers, select pll3 as clock source */
770 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
771 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
772 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
773 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
774 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
775
776 /* Setup clk div and doubler */
777 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
778 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
779 if (!clk_double)
780 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
781
782 /* Setup timing registers */
783 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
784 &hdmi->video_size);
785
786 x = mode->hsync_len + mode->left_margin;
787 y = mode->vsync_len + mode->upper_margin;
788 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
789
790 x = mode->right_margin;
791 y = mode->lower_margin;
792 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
793
794 x = mode->hsync_len;
795 y = mode->vsync_len;
796 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
797
798 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
799 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
800
801 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
802 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
803}
804
Hans de Goede4125f922014-12-21 14:49:34 +0100805static void sunxi_hdmi_enable(void)
806{
807 struct sunxi_hdmi_reg * const hdmi =
808 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
809
810 udelay(100);
811 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
812}
813
Hans de Goedee9544592014-12-23 23:04:35 +0100814#endif /* CONFIG_VIDEO_HDMI */
815
Hans de Goedec06e00e2015-08-03 19:20:26 +0200816#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100817
Hans de Goedec06e00e2015-08-03 19:20:26 +0200818static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100819{
820 struct sunxi_ccm_reg * const ccm =
821 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
822 struct sunxi_tve_reg * const tve =
823 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
824
Hans de Goede8a195ca2015-08-06 12:08:33 +0200825 /* Reset off */
826 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100827 /* Clock on */
828 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
829
Hans de Goedec06e00e2015-08-03 19:20:26 +0200830 switch (sunxi_display.monitor) {
831 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200832 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200833 break;
834 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200835 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
836 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200837 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200838 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200839 break;
840 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200841 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
842 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200843 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200844 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200845 break;
846 case sunxi_monitor_none:
847 case sunxi_monitor_dvi:
848 case sunxi_monitor_hdmi:
849 case sunxi_monitor_lcd:
850 break;
851 }
Hans de Goede260f5202014-12-25 13:58:06 +0100852}
853
Hans de Goedec06e00e2015-08-03 19:20:26 +0200854#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100855
Hans de Goede115e4b42014-12-23 18:39:52 +0100856static void sunxi_drc_init(void)
857{
Hans de Goedef07872b2015-04-06 20:33:34 +0200858#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100859 struct sunxi_ccm_reg * const ccm =
860 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
861
862 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530863#ifdef CONFIG_MACH_SUN8I_A33
864 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
865#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100866 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
867 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
868#endif
869}
870
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800871#ifdef CONFIG_VIDEO_VGA_VIA_LCD
872static void sunxi_vga_external_dac_enable(void)
873{
874 int pin;
875
876 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200877 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800878 gpio_request(pin, "vga_enable");
879 gpio_direction_output(pin, 1);
880 }
881}
882#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
883
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200884#ifdef CONFIG_VIDEO_LCD_SSD2828
885static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
886{
887 struct ssd2828_config cfg = {
888 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
889 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
890 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
891 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
892 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
893 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
894 .ssd2828_color_depth = 24,
895#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
896 .mipi_dsi_number_of_data_lanes = 4,
897 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
898 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
899 .mipi_dsi_delay_after_set_display_on_ms = 200
900#else
901#error MIPI LCD panel needs configuration parameters
902#endif
903 };
904
905 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
906 printf("SSD2828: SPI pins are not properly configured\n");
907 return 1;
908 }
909 if (cfg.reset_pin == -1) {
910 printf("SSD2828: Reset pin is not properly configured\n");
911 return 1;
912 }
913
914 return ssd2828_init(&cfg, mode);
915}
916#endif /* CONFIG_VIDEO_LCD_SSD2828 */
917
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200918static void sunxi_engines_init(void)
919{
920 sunxi_composer_init();
921 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100922 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200923}
924
Hans de Goedea0b1b732014-12-21 14:37:45 +0100925static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100926 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200927{
Hans de Goede260f5202014-12-25 13:58:06 +0100928 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200929 struct sunxi_lcdc_reg * const lcdc =
930 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +0200931 struct sunxi_tve_reg * __maybe_unused const tve =
932 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +0100933
Hans de Goede4125f922014-12-21 14:49:34 +0100934 switch (sunxi_display.monitor) {
935 case sunxi_monitor_none:
936 break;
937 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +0100938 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +0100939#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +0100940 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +0100941 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +0100942 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
943 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200944 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +0100945 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +0100946#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100947 break;
948 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100949 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +0200950 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
951 /*
952 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200953 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +0200954 * to avoid turning this on when using hdmi output.
955 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200956 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +0200957 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
958 ANX9804_DATA_RATE_1620M,
959 sunxi_display.depth);
960 }
Hans de Goede743fb9552015-01-20 09:23:36 +0100961 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
962 mdelay(50); /* Wait for lcd controller power on */
963 hitachi_tx18d42vm_init();
964 }
Hans de Goede613dade2015-02-16 17:49:47 +0100965 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
966 unsigned int orig_i2c_bus = i2c_get_bus_num();
967 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
968 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
969 i2c_set_bus_num(orig_i2c_bus);
970 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100971 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100972 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100973 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200974 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200975#ifdef CONFIG_VIDEO_LCD_SSD2828
976 sunxi_ssd2828_init(mode);
977#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100978 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +0100979 break;
980 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +0100981#ifdef CONFIG_VIDEO_VGA
982 sunxi_composer_mode_set(mode, address);
983 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200984 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +0100985 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200986 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200987 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +0100988#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +0100989 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100990 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +0100991 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200992 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800993 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +0100994#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100995 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200996 case sunxi_monitor_composite_pal:
997 case sunxi_monitor_composite_ntsc:
998 case sunxi_monitor_composite_pal_m:
999 case sunxi_monitor_composite_pal_nc:
1000#ifdef CONFIG_VIDEO_COMPOSITE
1001 sunxi_composer_mode_set(mode, address);
1002 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1003 sunxi_tvencoder_mode_set();
1004 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001005 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001006 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001007#endif
1008 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001009 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001010}
1011
Hans de Goedea0b1b732014-12-21 14:37:45 +01001012static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1013{
1014 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001015 case sunxi_monitor_none: return "none";
1016 case sunxi_monitor_dvi: return "dvi";
1017 case sunxi_monitor_hdmi: return "hdmi";
1018 case sunxi_monitor_lcd: return "lcd";
1019 case sunxi_monitor_vga: return "vga";
1020 case sunxi_monitor_composite_pal: return "composite-pal";
1021 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1022 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1023 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001024 }
1025 return NULL; /* never reached */
1026}
1027
Hans de Goede6c912862015-02-02 17:13:29 +01001028ulong board_get_usable_ram_top(ulong total_size)
1029{
1030 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1031}
1032
Hans de Goedea2bba492015-08-03 23:01:38 +02001033static bool sunxi_has_hdmi(void)
1034{
1035#ifdef CONFIG_VIDEO_HDMI
1036 return true;
1037#else
1038 return false;
1039#endif
1040}
1041
1042static bool sunxi_has_lcd(void)
1043{
1044 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1045
1046 return lcd_mode[0] != 0;
1047}
1048
1049static bool sunxi_has_vga(void)
1050{
1051#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1052 return true;
1053#else
1054 return false;
1055#endif
1056}
1057
Hans de Goedec06e00e2015-08-03 19:20:26 +02001058static bool sunxi_has_composite(void)
1059{
1060#ifdef CONFIG_VIDEO_COMPOSITE
1061 return true;
1062#else
1063 return false;
1064#endif
1065}
1066
Hans de Goedea2bba492015-08-03 23:01:38 +02001067static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1068{
1069 if (allow_hdmi && sunxi_has_hdmi())
1070 return sunxi_monitor_dvi;
1071 else if (sunxi_has_lcd())
1072 return sunxi_monitor_lcd;
1073 else if (sunxi_has_vga())
1074 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001075 else if (sunxi_has_composite())
1076 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001077 else
1078 return sunxi_monitor_none;
1079}
1080
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001081void *video_hw_init(void)
1082{
1083 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001084 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001085 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001086 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001087#ifdef CONFIG_VIDEO_HDMI
Priit Laesa9d6db72018-12-19 15:06:09 +02001088 int hpd, hpd_delay, edid;
1089 bool hdmi_present;
Hans de Goedee9544592014-12-23 23:04:35 +01001090#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001091 int i, overscan_offset, overscan_x, overscan_y;
1092 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001093 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001094 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001095
1096 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1097
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001098 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1099 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001100#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001101 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001102 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001103 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001104#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001105 overscan_x = video_get_option_int(options, "overscan_x", -1);
1106 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001107 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001108 video_get_option_string(options, "monitor", mon, sizeof(mon),
1109 sunxi_get_mon_desc(sunxi_display.monitor));
1110 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1111 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1112 sunxi_display.monitor = i;
1113 break;
1114 }
1115 }
1116 if (i > SUNXI_MONITOR_LAST)
1117 printf("Unknown monitor: '%s', falling back to '%s'\n",
1118 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001119
Hans de Goede7977ec22014-12-25 13:52:04 +01001120#ifdef CONFIG_VIDEO_HDMI
1121 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1122 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1123 sunxi_display.monitor == sunxi_monitor_hdmi) {
1124 /* Always call hdp_detect, as it also enables clocks, etc. */
Priit Laesa9d6db72018-12-19 15:06:09 +02001125 hdmi_present = (sunxi_hdmi_hpd_detect(hpd_delay) == 1);
1126 if (hdmi_present && edid) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001127 printf("HDMI connected: ");
Priit Laesa9d6db72018-12-19 15:06:09 +02001128 if (sunxi_hdmi_edid_get_mode(&custom, true) == 0)
Hans de Goede7977ec22014-12-25 13:52:04 +01001129 mode = &custom;
Priit Laesa9d6db72018-12-19 15:06:09 +02001130 else
1131 hdmi_present = false;
1132 }
1133 /* Fall back to EDID in case HPD failed */
1134 if (edid && !hdmi_present) {
1135 if (sunxi_hdmi_edid_get_mode(&custom, false) == 0) {
1136 mode = &custom;
1137 hdmi_present = true;
1138 }
1139 }
1140 /* Shut down when display was not found */
1141 if ((hpd || edid) && !hdmi_present) {
Hans de Goede7977ec22014-12-25 13:52:04 +01001142 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001143 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001144 } /* else continue with hdmi/dvi without a cable connected */
1145 }
1146#endif
1147
Hans de Goede4125f922014-12-21 14:49:34 +01001148 switch (sunxi_display.monitor) {
1149 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001150 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001151 case sunxi_monitor_dvi:
1152 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001153 if (!sunxi_has_hdmi()) {
1154 printf("HDMI/DVI not supported on this board\n");
1155 sunxi_display.monitor = sunxi_monitor_none;
1156 return NULL;
1157 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001158 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001159 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001160 if (!sunxi_has_lcd()) {
1161 printf("LCD not supported on this board\n");
1162 sunxi_display.monitor = sunxi_monitor_none;
1163 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001164 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001165 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1166 mode = &custom;
1167 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001168 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001169 if (!sunxi_has_vga()) {
1170 printf("VGA not supported on this board\n");
1171 sunxi_display.monitor = sunxi_monitor_none;
1172 return NULL;
1173 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001174 sunxi_display.depth = 18;
1175 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001176 case sunxi_monitor_composite_pal:
1177 case sunxi_monitor_composite_ntsc:
1178 case sunxi_monitor_composite_pal_m:
1179 case sunxi_monitor_composite_pal_nc:
1180 if (!sunxi_has_composite()) {
1181 printf("Composite video not supported on this board\n");
1182 sunxi_display.monitor = sunxi_monitor_none;
1183 return NULL;
1184 }
1185 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1186 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1187 mode = &composite_video_modes[0];
1188 else
1189 mode = &composite_video_modes[1];
1190 sunxi_display.depth = 24;
1191 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001192 }
1193
Hans de Goeded955f442015-08-05 00:06:47 +02001194 /* Yes these defaults are quite high, overscan on composite sucks... */
1195 if (overscan_x == -1)
1196 overscan_x = sunxi_is_composite() ? 32 : 0;
1197 if (overscan_y == -1)
1198 overscan_y = sunxi_is_composite() ? 20 : 0;
1199
Hans de Goede18799252015-02-02 18:00:53 +01001200 sunxi_display.fb_size =
1201 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001202 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1203 /* We want to keep the fb_base for simplefb page aligned, where as
1204 * the sunxi dma engines will happily accept an unaligned address. */
1205 if (overscan_offset)
1206 sunxi_display.fb_size += 0x1000;
1207
Hans de Goede18799252015-02-02 18:00:53 +01001208 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1209 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1210 sunxi_display.fb_size >> 10,
1211 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1212 return NULL;
1213 }
1214
Hans de Goeded955f442015-08-05 00:06:47 +02001215 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1216 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001217 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001218 sunxi_get_mon_desc(sunxi_display.monitor),
1219 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001220
Hans de Goede18799252015-02-02 18:00:53 +01001221 gd->fb_base = gd->bd->bi_dram[0].start +
1222 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001223 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001224
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001225#ifdef CONFIG_EFI_LOADER
1226 efi_add_memory_map(gd->fb_base,
1227 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1228 EFI_PAGE_SHIFT,
1229 EFI_RESERVED_MEMORY_TYPE, false);
1230#endif
1231
Hans de Goeded955f442015-08-05 00:06:47 +02001232 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1233 sunxi_display.fb_addr = gd->fb_base;
1234 if (overscan_offset) {
1235 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1236 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1237 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1238 flush_cache(gd->fb_base, sunxi_display.fb_size);
1239 }
1240 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001241
1242 /*
1243 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001244 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001245 */
Hans de Goeded955f442015-08-05 00:06:47 +02001246 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001247 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1248 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001249 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1250 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1251 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001252
1253 return graphic_device;
1254}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001255
1256/*
1257 * Simplefb support.
1258 */
1259#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1260int sunxi_simplefb_setup(void *blob)
1261{
1262 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1263 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001264 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001265 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001266
Hans de Goedec3cc4262015-01-19 08:44:07 +01001267#ifdef CONFIG_MACH_SUN4I
1268#define PIPELINE_PREFIX "de_fe0-"
1269#else
1270#define PIPELINE_PREFIX
1271#endif
1272
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001273 switch (sunxi_display.monitor) {
1274 case sunxi_monitor_none:
1275 return 0;
1276 case sunxi_monitor_dvi:
1277 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001278 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001279 break;
1280 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001281 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001282 break;
1283 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001284#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001285 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001286#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001287 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001288#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001289 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001290 case sunxi_monitor_composite_pal:
1291 case sunxi_monitor_composite_ntsc:
1292 case sunxi_monitor_composite_pal_m:
1293 case sunxi_monitor_composite_pal_nc:
1294 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1295 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001296 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001297
Icenowy Zheng067a6972017-10-26 11:14:45 +08001298 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001299 if (offset < 0) {
1300 eprintf("Cannot setup simplefb: node not found\n");
1301 return 0; /* Keep older kernels working */
1302 }
1303
Hans de Goede6c912862015-02-02 17:13:29 +01001304 /*
1305 * Do not report the framebuffer as free RAM to the OS, note we cannot
1306 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1307 * and e.g. Linux refuses to iomap RAM on ARM, see:
1308 * linux/arch/arm/mm/ioremap.c around line 301.
1309 */
1310 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001311 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001312 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1313 if (ret) {
1314 eprintf("Cannot setup simplefb: Error reserving memory\n");
1315 return ret;
1316 }
1317
Hans de Goeded955f442015-08-05 00:06:47 +02001318 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001319 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001320 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001321 if (ret)
1322 eprintf("Cannot setup simplefb: Error setting properties\n");
1323
1324 return ret;
1325}
1326#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */