blob: 4da169fffd8cc5a2887e7e889c5278c6e9b35cba [file] [log] [blame]
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001/*
2 * Display driver for Allwinner SoCs.
3 *
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
Hans de Goedec06e00e2015-08-03 19:20:26 +02005 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02006 *
7 * SPDX-License-Identifier: GPL-2.0+
8 */
9
10#include <common.h>
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +010011#include <efi_loader.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
Hans de Goede205a30c2014-12-20 15:15:23 +0100117 while (timer_get_us() < tmo) {
118 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
119 return 1;
120 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200121
Hans de Goede205a30c2014-12-20 15:15:23 +0100122 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100123}
124
125static void sunxi_hdmi_shutdown(void)
126{
127 struct sunxi_ccm_reg * const ccm =
128 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
129 struct sunxi_hdmi_reg * const hdmi =
130 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200131
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200132 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
133 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
134 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200135#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100136 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
137#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200138 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200139}
140
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100141static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
142{
143 struct sunxi_hdmi_reg * const hdmi =
144 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
145
146 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
147 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
148 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
149 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
150 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
151#ifndef CONFIG_MACH_SUN6I
152 writel(n, &hdmi->ddc_byte_count);
153 writel(cmnd, &hdmi->ddc_cmnd);
154#else
155 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
156#endif
157 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
158
159 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
160}
161
162static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
163{
164 struct sunxi_hdmi_reg * const hdmi =
165 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
166 int i, n;
167
168 while (count > 0) {
169 if (count > 16)
170 n = 16;
171 else
172 n = count;
173
174 if (sunxi_hdmi_ddc_do_command(
175 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
176 offset, n))
177 return -ETIME;
178
179 for (i = 0; i < n; i++)
180 *buf++ = readb(&hdmi->ddc_fifo_data);
181
182 offset += n;
183 count -= n;
184 }
185
186 return 0;
187}
188
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100189static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
190{
191 int r, retries = 2;
192
193 do {
194 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
195 if (r)
196 continue;
197 r = edid_check_checksum(buf);
198 if (r) {
199 printf("EDID block %d: checksum error%s\n",
200 block, retries ? ", retrying" : "");
201 }
202 } while (r && retries--);
203
204 return r;
205}
206
Hans de Goedea0b1b732014-12-21 14:37:45 +0100207static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100208{
209 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100210 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100211 struct edid_detailed_timing *t =
212 (struct edid_detailed_timing *)edid1.monitor_details.timing;
213 struct sunxi_hdmi_reg * const hdmi =
214 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
215 struct sunxi_ccm_reg * const ccm =
216 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100217 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100218
219 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
220 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
221 &hdmi->pad_ctrl1);
222 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
223 &hdmi->pll_ctrl);
224 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
225
226 /* Reset i2c controller */
227 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
228 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
229 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
230 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
231 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
232 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
233 return -EIO;
234
235 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
236#ifndef CONFIG_MACH_SUN6I
237 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
238 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
239#endif
240
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100241 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100242 if (r == 0) {
243 r = edid_check_info(&edid1);
244 if (r) {
245 printf("EDID: invalid EDID data\n");
246 r = -EINVAL;
247 }
248 }
249 if (r == 0) {
250 ext_blocks = edid1.extension_flag;
251 if (ext_blocks > 4)
252 ext_blocks = 4;
253 for (i = 0; i < ext_blocks; i++) {
254 if (sunxi_hdmi_edid_get_block(1 + i,
255 (u8 *)&cea681[i]) != 0) {
256 ext_blocks = i;
257 break;
258 }
259 }
260 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100261
262 /* Disable DDC engine, no longer needed */
263 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
264 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
265
266 if (r)
267 return r;
268
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100269 /* We want version 1.3 or 1.2 with detailed timing info */
270 if (edid1.version != 1 || (edid1.revision < 3 &&
271 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
272 printf("EDID: unsupported version %d.%d\n",
273 edid1.version, edid1.revision);
274 return -EINVAL;
275 }
276
277 /* Take the first usable detailed timing */
278 for (i = 0; i < 4; i++, t++) {
279 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
280 if (r == 0)
281 break;
282 }
283 if (i == 4) {
284 printf("EDID: no usable detailed timing found\n");
285 return -ENOENT;
286 }
287
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100288 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100289 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100290 for (i = 0; i < ext_blocks; i++) {
291 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
292 cea681[i].revision < 2)
293 continue;
294
295 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100296 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100297 }
298
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100299 return 0;
300}
301
Hans de Goedee9544592014-12-23 23:04:35 +0100302#endif /* CONFIG_VIDEO_HDMI */
303
Hans de Goedec3cc4262015-01-19 08:44:07 +0100304#ifdef CONFIG_MACH_SUN4I
305/*
306 * Testing has shown that on sun4i the display backend engine does not have
307 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
308 * fifo underruns. So on sun4i we use the display frontend engine to do the
309 * dma from memory, as the frontend does have deep enough fifo-s.
310 */
311
312static const u32 sun4i_vert_coef[32] = {
313 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
314 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
315 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
316 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
317 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
318 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
319 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
320 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
321};
322
323static const u32 sun4i_horz_coef[64] = {
324 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
325 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
326 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
327 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
328 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
329 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
330 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
331 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
332 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
333 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
334 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
335 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
336 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
337 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
338 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
339 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
340};
341
342static void sunxi_frontend_init(void)
343{
344 struct sunxi_ccm_reg * const ccm =
345 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
346 struct sunxi_de_fe_reg * const de_fe =
347 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
348 int i;
349
350 /* Clocks on */
351 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
352 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
353 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
354
355 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
356
357 for (i = 0; i < 32; i++) {
358 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
359 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
360 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
361 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
362 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
363 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
364 }
365
366 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
367}
368
369static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
370 unsigned int address)
371{
372 struct sunxi_de_fe_reg * const de_fe =
373 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
374
375 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
376 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
377 writel(mode->xres * 4, &de_fe->ch0_stride);
378 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
379 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
380
381 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
382 &de_fe->ch0_insize);
383 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
384 &de_fe->ch0_outsize);
385 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
386 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
387
388 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
389 &de_fe->ch1_insize);
390 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
391 &de_fe->ch1_outsize);
392 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
393 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
394
395 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
396}
397
398static void sunxi_frontend_enable(void)
399{
400 struct sunxi_de_fe_reg * const de_fe =
401 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
402
403 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
404}
405#else
406static void sunxi_frontend_init(void) {}
407static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
408 unsigned int address) {}
409static void sunxi_frontend_enable(void) {}
410#endif
411
Hans de Goedec06e00e2015-08-03 19:20:26 +0200412static bool sunxi_is_composite(void)
413{
414 switch (sunxi_display.monitor) {
415 case sunxi_monitor_none:
416 case sunxi_monitor_dvi:
417 case sunxi_monitor_hdmi:
418 case sunxi_monitor_lcd:
419 case sunxi_monitor_vga:
420 return false;
421 case sunxi_monitor_composite_pal:
422 case sunxi_monitor_composite_ntsc:
423 case sunxi_monitor_composite_pal_m:
424 case sunxi_monitor_composite_pal_nc:
425 return true;
426 }
427
428 return false; /* Never reached */
429}
430
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200431/*
432 * This is the entity that mixes and matches the different layers and inputs.
433 * Allwinner calls it the back-end, but i like composer better.
434 */
435static void sunxi_composer_init(void)
436{
437 struct sunxi_ccm_reg * const ccm =
438 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
439 struct sunxi_de_be_reg * const de_be =
440 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
441 int i;
442
Hans de Goedec3cc4262015-01-19 08:44:07 +0100443 sunxi_frontend_init();
444
Hans de Goedef07872b2015-04-06 20:33:34 +0200445#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100446 /* Reset off */
447 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
448#endif
449
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200450 /* Clocks on */
451 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100452#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200453 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100454#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200455 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
456
457 /* Engine bug, clear registers after reset */
458 for (i = 0x0800; i < 0x1000; i += 4)
459 writel(0, SUNXI_DE_BE0_BASE + i);
460
461 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
462}
463
Hans de Goedec06e00e2015-08-03 19:20:26 +0200464static u32 sunxi_rgb2yuv_coef[12] = {
465 0x00000107, 0x00000204, 0x00000064, 0x00000108,
466 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
467 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
468};
469
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100470static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200471 unsigned int address)
472{
473 struct sunxi_de_be_reg * const de_be =
474 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200475 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200476
Hans de Goedec3cc4262015-01-19 08:44:07 +0100477 sunxi_frontend_mode_set(mode, address);
478
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200479 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
480 &de_be->disp_size);
481 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
482 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100483#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200484 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
485 writel(address << 3, &de_be->layer0_addr_low32b);
486 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100487#else
488 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
489#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200490 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
491
492 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200493 if (mode->vmode == FB_VMODE_INTERLACED)
494 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200495#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200496 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200497#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200498 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200499
500 if (sunxi_is_composite()) {
501 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
502 &de_be->output_color_ctrl);
503 for (i = 0; i < 12; i++)
504 writel(sunxi_rgb2yuv_coef[i],
505 &de_be->output_color_coef[i]);
506 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200507}
508
Hans de Goede4125f922014-12-21 14:49:34 +0100509static void sunxi_composer_enable(void)
510{
511 struct sunxi_de_be_reg * const de_be =
512 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
513
Hans de Goedec3cc4262015-01-19 08:44:07 +0100514 sunxi_frontend_enable();
515
Hans de Goede4125f922014-12-21 14:49:34 +0100516 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
517 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
518}
519
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200520static void sunxi_lcdc_init(void)
521{
522 struct sunxi_ccm_reg * const ccm =
523 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
524 struct sunxi_lcdc_reg * const lcdc =
525 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
526
527 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200528#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100529 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
530#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200531 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100532#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200533
534 /* Clock on */
535 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100536#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200537#ifdef CONFIG_SUNXI_GEN_SUN6I
538 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
539#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100540 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
541#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200542#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200543
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200544 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200545}
546
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100547static void sunxi_lcdc_panel_enable(void)
548{
Hans de Goedece9e3322015-02-16 17:26:41 +0100549 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100550
551 /*
552 * Start with backlight disabled to avoid the screen flashing to
553 * white while the lcd inits.
554 */
555 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200556 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100557 gpio_request(pin, "lcd_backlight_enable");
558 gpio_direction_output(pin, 0);
559 }
560
561 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200562 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100563 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100564 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100565 }
566
Hans de Goedece9e3322015-02-16 17:26:41 +0100567 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200568 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100569 gpio_request(reset_pin, "lcd_reset");
570 gpio_direction_output(reset_pin, 0); /* Assert reset */
571 }
572
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100573 /* Give the backlight some time to turn off and power up the panel. */
574 mdelay(40);
575 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
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_power");
578 gpio_direction_output(pin, 1);
579 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100580
Hans de Goede7783ab22015-04-22 17:45:59 +0200581 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100582 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100583}
584
585static void sunxi_lcdc_backlight_enable(void)
586{
587 int pin;
588
589 /*
590 * We want to have scanned out at least one frame before enabling the
591 * backlight to avoid the screen flashing to white when we enable it.
592 */
593 mdelay(40);
594
595 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200596 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100597 gpio_direction_output(pin, 1);
598
599 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200600#ifdef SUNXI_PWM_PIN0
601 if (pin == SUNXI_PWM_PIN0) {
602 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
603 SUNXI_PWM_CTRL_ENABLE0 |
604 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
605 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
606 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
607 return;
608 }
609#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200610 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100611 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100612}
613
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200614static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
615 struct display_timing *timing)
616{
617 timing->pixelclock.typ = mode->pixclock_khz * 1000;
618
619 timing->hactive.typ = mode->xres;
620 timing->hfront_porch.typ = mode->right_margin;
621 timing->hback_porch.typ = mode->left_margin;
622 timing->hsync_len.typ = mode->hsync_len;
623
624 timing->vactive.typ = mode->yres;
625 timing->vfront_porch.typ = mode->lower_margin;
626 timing->vback_porch.typ = mode->upper_margin;
627 timing->vsync_len.typ = mode->vsync_len;
628
Giulio Benetti105bdc62018-01-16 17:43:48 +0100629 timing->flags = 0;
630
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200631 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
632 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
633 else
634 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
635 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
636 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
637 else
638 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
639 if (mode->vmode == FB_VMODE_INTERLACED)
640 timing->flags |= DISPLAY_FLAGS_INTERLACED;
641}
642
Hans de Goede18366f72015-01-25 15:33:07 +0100643static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
644 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100645{
646 struct sunxi_lcdc_reg * const lcdc =
647 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700648 struct sunxi_ccm_reg * const ccm =
649 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200650 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200651 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100652
Lawrence Yuf721f962016-03-04 09:08:56 -0800653#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
654 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
655#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200656 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800657#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100658#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100659 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100660#endif
661#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100662 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100663#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200664#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
665 sunxi_gpio_set_drv(pin, 3);
666#endif
667 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100668
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700669 lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
670 sunxi_is_composite());
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100671
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200672 sunxi_ctfb_mode_to_display_timing(mode, &timing);
673 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200674 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100675}
676
Hans de Goedec06e00e2015-08-03 19:20:26 +0200677#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100678static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100679 int *clk_div, int *clk_double,
680 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200681{
682 struct sunxi_lcdc_reg * const lcdc =
683 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700684 struct sunxi_ccm_reg * const ccm =
685 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200686 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200687
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200688 sunxi_ctfb_mode_to_display_timing(mode, &timing);
689 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200690 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200691
Hans de Goedec3d15042014-12-27 15:19:23 +0100692 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100693 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
694 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100695 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200696
Vasily Khoruzhickf079f932017-10-26 21:51:51 -0700697 lcdc_pll_set(ccm, 1, mode->pixclock_khz, clk_div, clk_double,
698 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200699}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200700#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100701
702#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100703
Hans de Goedea2017e82014-12-20 13:38:06 +0100704static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
705{
706 struct sunxi_hdmi_reg * const hdmi =
707 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
708 u8 checksum = 0;
709 u8 avi_info_frame[17] = {
710 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
711 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712 0x00
713 };
714 u8 vendor_info_frame[19] = {
715 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
716 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
717 0x00, 0x00, 0x00
718 };
719 int i;
720
721 if (mode->pixclock_khz <= 27000)
722 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
723 else
724 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
725
726 if (mode->xres * 100 / mode->yres < 156)
727 avi_info_frame[5] |= 0x18; /* 4 : 3 */
728 else
729 avi_info_frame[5] |= 0x28; /* 16 : 9 */
730
731 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
732 checksum += avi_info_frame[i];
733
734 avi_info_frame[3] = 0x100 - checksum;
735
736 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
737 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
738
739 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
740 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
741
742 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
743 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
744
745 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
746 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
747
748 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
749}
750
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100751static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100752 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200753{
754 struct sunxi_hdmi_reg * const hdmi =
755 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
756 int x, y;
757
758 /* Write clear interrupt status bits */
759 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
760
Hans de Goedea0b1b732014-12-21 14:37:45 +0100761 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100762 sunxi_hdmi_setup_info_frames(mode);
763
Hans de Goede95576692014-12-20 13:51:16 +0100764 /* Set input sync enable */
765 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
766
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200767 /* Init various registers, select pll3 as clock source */
768 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
769 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
770 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
771 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
772 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
773
774 /* Setup clk div and doubler */
775 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
776 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
777 if (!clk_double)
778 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
779
780 /* Setup timing registers */
781 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
782 &hdmi->video_size);
783
784 x = mode->hsync_len + mode->left_margin;
785 y = mode->vsync_len + mode->upper_margin;
786 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
787
788 x = mode->right_margin;
789 y = mode->lower_margin;
790 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
791
792 x = mode->hsync_len;
793 y = mode->vsync_len;
794 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
795
796 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
797 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
798
799 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
800 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
801}
802
Hans de Goede4125f922014-12-21 14:49:34 +0100803static void sunxi_hdmi_enable(void)
804{
805 struct sunxi_hdmi_reg * const hdmi =
806 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
807
808 udelay(100);
809 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
810}
811
Hans de Goedee9544592014-12-23 23:04:35 +0100812#endif /* CONFIG_VIDEO_HDMI */
813
Hans de Goedec06e00e2015-08-03 19:20:26 +0200814#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100815
Hans de Goedec06e00e2015-08-03 19:20:26 +0200816static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100817{
818 struct sunxi_ccm_reg * const ccm =
819 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
820 struct sunxi_tve_reg * const tve =
821 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
822
Hans de Goede8a195ca2015-08-06 12:08:33 +0200823 /* Reset off */
824 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100825 /* Clock on */
826 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
827
Hans de Goedec06e00e2015-08-03 19:20:26 +0200828 switch (sunxi_display.monitor) {
829 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200830 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200831 break;
832 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200833 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
834 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200835 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200836 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200837 break;
838 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200839 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
840 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200841 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200842 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200843 break;
844 case sunxi_monitor_none:
845 case sunxi_monitor_dvi:
846 case sunxi_monitor_hdmi:
847 case sunxi_monitor_lcd:
848 break;
849 }
Hans de Goede260f5202014-12-25 13:58:06 +0100850}
851
Hans de Goedec06e00e2015-08-03 19:20:26 +0200852#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100853
Hans de Goede115e4b42014-12-23 18:39:52 +0100854static void sunxi_drc_init(void)
855{
Hans de Goedef07872b2015-04-06 20:33:34 +0200856#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100857 struct sunxi_ccm_reg * const ccm =
858 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
859
860 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530861#ifdef CONFIG_MACH_SUN8I_A33
862 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
863#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100864 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
865 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
866#endif
867}
868
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800869#ifdef CONFIG_VIDEO_VGA_VIA_LCD
870static void sunxi_vga_external_dac_enable(void)
871{
872 int pin;
873
874 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200875 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800876 gpio_request(pin, "vga_enable");
877 gpio_direction_output(pin, 1);
878 }
879}
880#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
881
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200882#ifdef CONFIG_VIDEO_LCD_SSD2828
883static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
884{
885 struct ssd2828_config cfg = {
886 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
887 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
888 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
889 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
890 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
891 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
892 .ssd2828_color_depth = 24,
893#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
894 .mipi_dsi_number_of_data_lanes = 4,
895 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
896 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
897 .mipi_dsi_delay_after_set_display_on_ms = 200
898#else
899#error MIPI LCD panel needs configuration parameters
900#endif
901 };
902
903 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
904 printf("SSD2828: SPI pins are not properly configured\n");
905 return 1;
906 }
907 if (cfg.reset_pin == -1) {
908 printf("SSD2828: Reset pin is not properly configured\n");
909 return 1;
910 }
911
912 return ssd2828_init(&cfg, mode);
913}
914#endif /* CONFIG_VIDEO_LCD_SSD2828 */
915
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200916static void sunxi_engines_init(void)
917{
918 sunxi_composer_init();
919 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100920 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200921}
922
Hans de Goedea0b1b732014-12-21 14:37:45 +0100923static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100924 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200925{
Hans de Goede260f5202014-12-25 13:58:06 +0100926 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200927 struct sunxi_lcdc_reg * const lcdc =
928 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +0200929 struct sunxi_tve_reg * __maybe_unused const tve =
930 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +0100931
Hans de Goede4125f922014-12-21 14:49:34 +0100932 switch (sunxi_display.monitor) {
933 case sunxi_monitor_none:
934 break;
935 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +0100936 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +0100937#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +0100938 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +0100939 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +0100940 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
941 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200942 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +0100943 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +0100944#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100945 break;
946 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100947 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +0200948 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
949 /*
950 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200951 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +0200952 * to avoid turning this on when using hdmi output.
953 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +0200954 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +0200955 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
956 ANX9804_DATA_RATE_1620M,
957 sunxi_display.depth);
958 }
Hans de Goede743fb9552015-01-20 09:23:36 +0100959 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
960 mdelay(50); /* Wait for lcd controller power on */
961 hitachi_tx18d42vm_init();
962 }
Hans de Goede613dade2015-02-16 17:49:47 +0100963 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
964 unsigned int orig_i2c_bus = i2c_get_bus_num();
965 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
966 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
967 i2c_set_bus_num(orig_i2c_bus);
968 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100969 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100970 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100971 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200972 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200973#ifdef CONFIG_VIDEO_LCD_SSD2828
974 sunxi_ssd2828_init(mode);
975#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100976 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +0100977 break;
978 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +0100979#ifdef CONFIG_VIDEO_VGA
980 sunxi_composer_mode_set(mode, address);
981 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200982 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +0100983 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200984 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +0200985 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +0100986#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +0100987 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +0100988 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +0100989 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200990 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800991 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +0100992#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100993 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200994 case sunxi_monitor_composite_pal:
995 case sunxi_monitor_composite_ntsc:
996 case sunxi_monitor_composite_pal_m:
997 case sunxi_monitor_composite_pal_nc:
998#ifdef CONFIG_VIDEO_COMPOSITE
999 sunxi_composer_mode_set(mode, address);
1000 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1001 sunxi_tvencoder_mode_set();
1002 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001003 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001004 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001005#endif
1006 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001007 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001008}
1009
Hans de Goedea0b1b732014-12-21 14:37:45 +01001010static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1011{
1012 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001013 case sunxi_monitor_none: return "none";
1014 case sunxi_monitor_dvi: return "dvi";
1015 case sunxi_monitor_hdmi: return "hdmi";
1016 case sunxi_monitor_lcd: return "lcd";
1017 case sunxi_monitor_vga: return "vga";
1018 case sunxi_monitor_composite_pal: return "composite-pal";
1019 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1020 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1021 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001022 }
1023 return NULL; /* never reached */
1024}
1025
Hans de Goede6c912862015-02-02 17:13:29 +01001026ulong board_get_usable_ram_top(ulong total_size)
1027{
1028 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1029}
1030
Hans de Goedea2bba492015-08-03 23:01:38 +02001031static bool sunxi_has_hdmi(void)
1032{
1033#ifdef CONFIG_VIDEO_HDMI
1034 return true;
1035#else
1036 return false;
1037#endif
1038}
1039
1040static bool sunxi_has_lcd(void)
1041{
1042 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1043
1044 return lcd_mode[0] != 0;
1045}
1046
1047static bool sunxi_has_vga(void)
1048{
1049#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1050 return true;
1051#else
1052 return false;
1053#endif
1054}
1055
Hans de Goedec06e00e2015-08-03 19:20:26 +02001056static bool sunxi_has_composite(void)
1057{
1058#ifdef CONFIG_VIDEO_COMPOSITE
1059 return true;
1060#else
1061 return false;
1062#endif
1063}
1064
Hans de Goedea2bba492015-08-03 23:01:38 +02001065static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1066{
1067 if (allow_hdmi && sunxi_has_hdmi())
1068 return sunxi_monitor_dvi;
1069 else if (sunxi_has_lcd())
1070 return sunxi_monitor_lcd;
1071 else if (sunxi_has_vga())
1072 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001073 else if (sunxi_has_composite())
1074 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001075 else
1076 return sunxi_monitor_none;
1077}
1078
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001079void *video_hw_init(void)
1080{
1081 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001082 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001083 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001084 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001085#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001086 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001087#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001088 int i, overscan_offset, overscan_x, overscan_y;
1089 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001090 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001091 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001092
1093 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1094
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001095 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1096 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001097#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001098 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001099 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001100 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001101#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001102 overscan_x = video_get_option_int(options, "overscan_x", -1);
1103 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001104 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001105 video_get_option_string(options, "monitor", mon, sizeof(mon),
1106 sunxi_get_mon_desc(sunxi_display.monitor));
1107 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1108 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1109 sunxi_display.monitor = i;
1110 break;
1111 }
1112 }
1113 if (i > SUNXI_MONITOR_LAST)
1114 printf("Unknown monitor: '%s', falling back to '%s'\n",
1115 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001116
Hans de Goede7977ec22014-12-25 13:52:04 +01001117#ifdef CONFIG_VIDEO_HDMI
1118 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1119 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1120 sunxi_display.monitor == sunxi_monitor_hdmi) {
1121 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001122 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001123 if (ret) {
1124 printf("HDMI connected: ");
1125 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1126 mode = &custom;
1127 } else if (hpd) {
1128 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001129 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001130 } /* else continue with hdmi/dvi without a cable connected */
1131 }
1132#endif
1133
Hans de Goede4125f922014-12-21 14:49:34 +01001134 switch (sunxi_display.monitor) {
1135 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001136 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001137 case sunxi_monitor_dvi:
1138 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001139 if (!sunxi_has_hdmi()) {
1140 printf("HDMI/DVI not supported on this board\n");
1141 sunxi_display.monitor = sunxi_monitor_none;
1142 return NULL;
1143 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001144 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001145 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001146 if (!sunxi_has_lcd()) {
1147 printf("LCD not supported on this board\n");
1148 sunxi_display.monitor = sunxi_monitor_none;
1149 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001150 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001151 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1152 mode = &custom;
1153 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001154 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001155 if (!sunxi_has_vga()) {
1156 printf("VGA not supported on this board\n");
1157 sunxi_display.monitor = sunxi_monitor_none;
1158 return NULL;
1159 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001160 sunxi_display.depth = 18;
1161 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001162 case sunxi_monitor_composite_pal:
1163 case sunxi_monitor_composite_ntsc:
1164 case sunxi_monitor_composite_pal_m:
1165 case sunxi_monitor_composite_pal_nc:
1166 if (!sunxi_has_composite()) {
1167 printf("Composite video not supported on this board\n");
1168 sunxi_display.monitor = sunxi_monitor_none;
1169 return NULL;
1170 }
1171 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1172 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1173 mode = &composite_video_modes[0];
1174 else
1175 mode = &composite_video_modes[1];
1176 sunxi_display.depth = 24;
1177 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001178 }
1179
Hans de Goeded955f442015-08-05 00:06:47 +02001180 /* Yes these defaults are quite high, overscan on composite sucks... */
1181 if (overscan_x == -1)
1182 overscan_x = sunxi_is_composite() ? 32 : 0;
1183 if (overscan_y == -1)
1184 overscan_y = sunxi_is_composite() ? 20 : 0;
1185
Hans de Goede18799252015-02-02 18:00:53 +01001186 sunxi_display.fb_size =
1187 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001188 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1189 /* We want to keep the fb_base for simplefb page aligned, where as
1190 * the sunxi dma engines will happily accept an unaligned address. */
1191 if (overscan_offset)
1192 sunxi_display.fb_size += 0x1000;
1193
Hans de Goede18799252015-02-02 18:00:53 +01001194 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1195 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1196 sunxi_display.fb_size >> 10,
1197 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1198 return NULL;
1199 }
1200
Hans de Goeded955f442015-08-05 00:06:47 +02001201 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1202 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001203 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001204 sunxi_get_mon_desc(sunxi_display.monitor),
1205 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001206
Hans de Goede18799252015-02-02 18:00:53 +01001207 gd->fb_base = gd->bd->bi_dram[0].start +
1208 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001209 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001210
Heinrich Schuchardt084d3d92018-03-03 10:30:17 +01001211#ifdef CONFIG_EFI_LOADER
1212 efi_add_memory_map(gd->fb_base,
1213 ALIGN(sunxi_display.fb_size, EFI_PAGE_SIZE) >>
1214 EFI_PAGE_SHIFT,
1215 EFI_RESERVED_MEMORY_TYPE, false);
1216#endif
1217
Hans de Goeded955f442015-08-05 00:06:47 +02001218 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1219 sunxi_display.fb_addr = gd->fb_base;
1220 if (overscan_offset) {
1221 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1222 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1223 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1224 flush_cache(gd->fb_base, sunxi_display.fb_size);
1225 }
1226 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001227
1228 /*
1229 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001230 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001231 */
Hans de Goeded955f442015-08-05 00:06:47 +02001232 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001233 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1234 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001235 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1236 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1237 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001238
1239 return graphic_device;
1240}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001241
1242/*
1243 * Simplefb support.
1244 */
1245#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1246int sunxi_simplefb_setup(void *blob)
1247{
1248 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1249 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001250 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001251 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001252
Hans de Goedec3cc4262015-01-19 08:44:07 +01001253#ifdef CONFIG_MACH_SUN4I
1254#define PIPELINE_PREFIX "de_fe0-"
1255#else
1256#define PIPELINE_PREFIX
1257#endif
1258
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001259 switch (sunxi_display.monitor) {
1260 case sunxi_monitor_none:
1261 return 0;
1262 case sunxi_monitor_dvi:
1263 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001264 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001265 break;
1266 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001267 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001268 break;
1269 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001270#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001271 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001272#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001273 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001274#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001275 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001276 case sunxi_monitor_composite_pal:
1277 case sunxi_monitor_composite_ntsc:
1278 case sunxi_monitor_composite_pal_m:
1279 case sunxi_monitor_composite_pal_nc:
1280 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1281 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001282 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001283
Icenowy Zheng067a6972017-10-26 11:14:45 +08001284 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001285 if (offset < 0) {
1286 eprintf("Cannot setup simplefb: node not found\n");
1287 return 0; /* Keep older kernels working */
1288 }
1289
Hans de Goede6c912862015-02-02 17:13:29 +01001290 /*
1291 * Do not report the framebuffer as free RAM to the OS, note we cannot
1292 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1293 * and e.g. Linux refuses to iomap RAM on ARM, see:
1294 * linux/arch/arm/mm/ioremap.c around line 301.
1295 */
1296 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001297 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001298 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1299 if (ret) {
1300 eprintf("Cannot setup simplefb: Error reserving memory\n");
1301 return ret;
1302 }
1303
Hans de Goeded955f442015-08-05 00:06:47 +02001304 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001305 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001306 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001307 if (ret)
1308 eprintf("Cannot setup simplefb: Error setting properties\n");
1309
1310 return ret;
1311}
1312#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */