blob: 7f25ed5f26e9d7e90e8be43d076295c6047c3de3 [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>
11
12#include <asm/arch/clock.h>
13#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020015#include <asm/arch/lcdc.h>
Hans de Goede663ae652016-08-19 15:25:41 +020016#include <asm/arch/pwm.h>
Jernej Skrabec8531d082017-05-10 18:46:28 +020017#include <asm/arch/tve.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020018#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010019#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020020#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020021#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010022#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020023#include <fdtdec.h>
24#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010025#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020026#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020027#include <video_fb.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020028#include "../videomodes.h"
29#include "../anx9804.h"
30#include "../hitachi_tx18d42vm_lcd.h"
31#include "../ssd2828.h"
Icenowy Zheng067a6972017-10-26 11:14:45 +080032#include "simplefb_common.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020033
Hans de Goede2d5d3022015-01-22 21:02:42 +010034#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
35#define PWM_ON 0
36#define PWM_OFF 1
37#else
38#define PWM_ON 1
39#define PWM_OFF 0
40#endif
41
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020042DECLARE_GLOBAL_DATA_PTR;
43
Hans de Goedea0b1b732014-12-21 14:37:45 +010044enum sunxi_monitor {
45 sunxi_monitor_none,
46 sunxi_monitor_dvi,
47 sunxi_monitor_hdmi,
48 sunxi_monitor_lcd,
49 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020050 sunxi_monitor_composite_pal,
51 sunxi_monitor_composite_ntsc,
52 sunxi_monitor_composite_pal_m,
53 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010054};
Hans de Goedec06e00e2015-08-03 19:20:26 +020055#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010056
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020057struct sunxi_display {
58 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010059 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010060 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020061 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010062 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020063} sunxi_display;
64
Hans de Goedec06e00e2015-08-03 19:20:26 +020065const struct ctfb_res_modes composite_video_modes[2] = {
66 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
67 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
68 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
69};
70
Hans de Goedee9544592014-12-23 23:04:35 +010071#ifdef CONFIG_VIDEO_HDMI
72
Hans de Goedea5aa95f2014-12-19 16:05:12 +010073/*
74 * Wait up to 200ms for value to be set in given part of reg.
75 */
76static int await_completion(u32 *reg, u32 mask, u32 val)
77{
78 unsigned long tmo = timer_get_us() + 200000;
79
80 while ((readl(reg) & mask) != val) {
81 if (timer_get_us() > tmo) {
82 printf("DDC: timeout reading EDID\n");
83 return -ETIME;
84 }
85 }
86 return 0;
87}
88
Hans de Goede91593712014-12-28 09:13:21 +010089static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020090{
91 struct sunxi_ccm_reg * const ccm =
92 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
93 struct sunxi_hdmi_reg * const hdmi =
94 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010095 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020096
97 /* Set pll3 to 300MHz */
98 clock_set_pll3(300000000);
99
100 /* Set hdmi parent to pll3 */
101 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
102 CCM_HDMI_CTRL_PLL3);
103
104 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +0200105#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100106 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
107#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200108 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
109
110 /* Clock on */
111 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
112
113 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
114 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
115
Hans de Goede205a30c2014-12-20 15:15:23 +0100116 while (timer_get_us() < tmo) {
117 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
118 return 1;
119 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200120
Hans de Goede205a30c2014-12-20 15:15:23 +0100121 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100122}
123
124static void sunxi_hdmi_shutdown(void)
125{
126 struct sunxi_ccm_reg * const ccm =
127 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
128 struct sunxi_hdmi_reg * const hdmi =
129 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200130
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200131 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
132 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
133 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200134#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100135 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
136#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200137 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200138}
139
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100140static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
141{
142 struct sunxi_hdmi_reg * const hdmi =
143 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
144
145 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
146 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
147 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
148 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
149 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
150#ifndef CONFIG_MACH_SUN6I
151 writel(n, &hdmi->ddc_byte_count);
152 writel(cmnd, &hdmi->ddc_cmnd);
153#else
154 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
155#endif
156 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
157
158 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
159}
160
161static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
162{
163 struct sunxi_hdmi_reg * const hdmi =
164 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
165 int i, n;
166
167 while (count > 0) {
168 if (count > 16)
169 n = 16;
170 else
171 n = count;
172
173 if (sunxi_hdmi_ddc_do_command(
174 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
175 offset, n))
176 return -ETIME;
177
178 for (i = 0; i < n; i++)
179 *buf++ = readb(&hdmi->ddc_fifo_data);
180
181 offset += n;
182 count -= n;
183 }
184
185 return 0;
186}
187
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100188static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
189{
190 int r, retries = 2;
191
192 do {
193 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
194 if (r)
195 continue;
196 r = edid_check_checksum(buf);
197 if (r) {
198 printf("EDID block %d: checksum error%s\n",
199 block, retries ? ", retrying" : "");
200 }
201 } while (r && retries--);
202
203 return r;
204}
205
Hans de Goedea0b1b732014-12-21 14:37:45 +0100206static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100207{
208 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100209 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100210 struct edid_detailed_timing *t =
211 (struct edid_detailed_timing *)edid1.monitor_details.timing;
212 struct sunxi_hdmi_reg * const hdmi =
213 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
214 struct sunxi_ccm_reg * const ccm =
215 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100216 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100217
218 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
219 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
220 &hdmi->pad_ctrl1);
221 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
222 &hdmi->pll_ctrl);
223 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
224
225 /* Reset i2c controller */
226 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
227 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
228 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
229 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
230 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
231 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
232 return -EIO;
233
234 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
235#ifndef CONFIG_MACH_SUN6I
236 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
237 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
238#endif
239
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100240 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100241 if (r == 0) {
242 r = edid_check_info(&edid1);
243 if (r) {
244 printf("EDID: invalid EDID data\n");
245 r = -EINVAL;
246 }
247 }
248 if (r == 0) {
249 ext_blocks = edid1.extension_flag;
250 if (ext_blocks > 4)
251 ext_blocks = 4;
252 for (i = 0; i < ext_blocks; i++) {
253 if (sunxi_hdmi_edid_get_block(1 + i,
254 (u8 *)&cea681[i]) != 0) {
255 ext_blocks = i;
256 break;
257 }
258 }
259 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100260
261 /* Disable DDC engine, no longer needed */
262 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
263 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
264
265 if (r)
266 return r;
267
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100268 /* We want version 1.3 or 1.2 with detailed timing info */
269 if (edid1.version != 1 || (edid1.revision < 3 &&
270 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
271 printf("EDID: unsupported version %d.%d\n",
272 edid1.version, edid1.revision);
273 return -EINVAL;
274 }
275
276 /* Take the first usable detailed timing */
277 for (i = 0; i < 4; i++, t++) {
278 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
279 if (r == 0)
280 break;
281 }
282 if (i == 4) {
283 printf("EDID: no usable detailed timing found\n");
284 return -ENOENT;
285 }
286
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100287 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100288 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100289 for (i = 0; i < ext_blocks; i++) {
290 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
291 cea681[i].revision < 2)
292 continue;
293
294 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100295 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100296 }
297
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100298 return 0;
299}
300
Hans de Goedee9544592014-12-23 23:04:35 +0100301#endif /* CONFIG_VIDEO_HDMI */
302
Hans de Goedec3cc4262015-01-19 08:44:07 +0100303#ifdef CONFIG_MACH_SUN4I
304/*
305 * Testing has shown that on sun4i the display backend engine does not have
306 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
307 * fifo underruns. So on sun4i we use the display frontend engine to do the
308 * dma from memory, as the frontend does have deep enough fifo-s.
309 */
310
311static const u32 sun4i_vert_coef[32] = {
312 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
313 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
314 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
315 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
316 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
317 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
318 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
319 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
320};
321
322static const u32 sun4i_horz_coef[64] = {
323 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
324 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
325 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
326 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
327 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
328 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
329 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
330 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
331 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
332 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
333 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
334 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
335 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
336 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
337 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
338 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
339};
340
341static void sunxi_frontend_init(void)
342{
343 struct sunxi_ccm_reg * const ccm =
344 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
345 struct sunxi_de_fe_reg * const de_fe =
346 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
347 int i;
348
349 /* Clocks on */
350 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
351 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
352 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
353
354 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
355
356 for (i = 0; i < 32; i++) {
357 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
358 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
359 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
360 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
361 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
362 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
363 }
364
365 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
366}
367
368static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
369 unsigned int address)
370{
371 struct sunxi_de_fe_reg * const de_fe =
372 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
373
374 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
375 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
376 writel(mode->xres * 4, &de_fe->ch0_stride);
377 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
378 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
379
380 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
381 &de_fe->ch0_insize);
382 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
383 &de_fe->ch0_outsize);
384 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
385 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
386
387 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
388 &de_fe->ch1_insize);
389 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
390 &de_fe->ch1_outsize);
391 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
392 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
393
394 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
395}
396
397static void sunxi_frontend_enable(void)
398{
399 struct sunxi_de_fe_reg * const de_fe =
400 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
401
402 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
403}
404#else
405static void sunxi_frontend_init(void) {}
406static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
407 unsigned int address) {}
408static void sunxi_frontend_enable(void) {}
409#endif
410
Hans de Goedec06e00e2015-08-03 19:20:26 +0200411static bool sunxi_is_composite(void)
412{
413 switch (sunxi_display.monitor) {
414 case sunxi_monitor_none:
415 case sunxi_monitor_dvi:
416 case sunxi_monitor_hdmi:
417 case sunxi_monitor_lcd:
418 case sunxi_monitor_vga:
419 return false;
420 case sunxi_monitor_composite_pal:
421 case sunxi_monitor_composite_ntsc:
422 case sunxi_monitor_composite_pal_m:
423 case sunxi_monitor_composite_pal_nc:
424 return true;
425 }
426
427 return false; /* Never reached */
428}
429
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200430/*
431 * This is the entity that mixes and matches the different layers and inputs.
432 * Allwinner calls it the back-end, but i like composer better.
433 */
434static void sunxi_composer_init(void)
435{
436 struct sunxi_ccm_reg * const ccm =
437 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
438 struct sunxi_de_be_reg * const de_be =
439 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
440 int i;
441
Hans de Goedec3cc4262015-01-19 08:44:07 +0100442 sunxi_frontend_init();
443
Hans de Goedef07872b2015-04-06 20:33:34 +0200444#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100445 /* Reset off */
446 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
447#endif
448
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200449 /* Clocks on */
450 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100451#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200452 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100453#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200454 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
455
456 /* Engine bug, clear registers after reset */
457 for (i = 0x0800; i < 0x1000; i += 4)
458 writel(0, SUNXI_DE_BE0_BASE + i);
459
460 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
461}
462
Hans de Goedec06e00e2015-08-03 19:20:26 +0200463static u32 sunxi_rgb2yuv_coef[12] = {
464 0x00000107, 0x00000204, 0x00000064, 0x00000108,
465 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
466 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
467};
468
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100469static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200470 unsigned int address)
471{
472 struct sunxi_de_be_reg * const de_be =
473 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200474 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200475
Hans de Goedec3cc4262015-01-19 08:44:07 +0100476 sunxi_frontend_mode_set(mode, address);
477
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200478 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
479 &de_be->disp_size);
480 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
481 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100482#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200483 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
484 writel(address << 3, &de_be->layer0_addr_low32b);
485 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100486#else
487 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
488#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200489 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
490
491 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200492 if (mode->vmode == FB_VMODE_INTERLACED)
493 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200494#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200495 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200496#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200497 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200498
499 if (sunxi_is_composite()) {
500 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
501 &de_be->output_color_ctrl);
502 for (i = 0; i < 12; i++)
503 writel(sunxi_rgb2yuv_coef[i],
504 &de_be->output_color_coef[i]);
505 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200506}
507
Hans de Goede4125f922014-12-21 14:49:34 +0100508static void sunxi_composer_enable(void)
509{
510 struct sunxi_de_be_reg * const de_be =
511 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
512
Hans de Goedec3cc4262015-01-19 08:44:07 +0100513 sunxi_frontend_enable();
514
Hans de Goede4125f922014-12-21 14:49:34 +0100515 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
516 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
517}
518
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200519/*
520 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
521 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100522static void sunxi_lcdc_pll_set(int tcon, int dotclock,
523 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200524{
525 struct sunxi_ccm_reg * const ccm =
526 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100527 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200528 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
529 int best_double = 0;
Hans de Goede13365782015-08-08 14:08:21 +0200530 bool use_mipi_pll = false;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200531
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100532 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100533#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100534 min_m = 6;
535 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100536#endif
537#ifdef CONFIG_VIDEO_LCD_IF_LVDS
538 min_m = max_m = 7;
539#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100540 } else {
541 min_m = 1;
542 max_m = 15;
543 }
544
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200545 /*
546 * Find the lowest divider resulting in a matching clock, if there
547 * is no match, pick the closest lower clock, as monitors tend to
548 * not sync to higher frequencies.
549 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100550 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200551 n = (m * dotclock) / 3000;
552
553 if ((n >= 9) && (n <= 127)) {
554 value = (3000 * n) / m;
555 diff = dotclock - value;
556 if (diff < best_diff) {
557 best_diff = diff;
558 best_m = m;
559 best_n = n;
560 best_double = 0;
561 }
562 }
563
564 /* These are just duplicates */
565 if (!(m & 1))
566 continue;
567
568 n = (m * dotclock) / 6000;
569 if ((n >= 9) && (n <= 127)) {
570 value = (6000 * n) / m;
571 diff = dotclock - value;
572 if (diff < best_diff) {
573 best_diff = diff;
574 best_m = m;
575 best_n = n;
576 best_double = 1;
577 }
578 }
579 }
580
Hans de Goede13365782015-08-08 14:08:21 +0200581#ifdef CONFIG_MACH_SUN6I
582 /*
583 * Use the MIPI pll if we've been unable to find any matching setting
584 * for PLL3, this happens with high dotclocks because of min_m = 6.
585 */
586 if (tcon == 0 && best_n == 0) {
587 use_mipi_pll = true;
588 best_m = 6; /* Minimum m for tcon0 */
589 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200590
Hans de Goede13365782015-08-08 14:08:21 +0200591 if (use_mipi_pll) {
592 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
593 clock_set_mipi_pll(best_m * dotclock * 1000);
594 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
595 dotclock, clock_get_mipi_pll() / best_m / 1000);
596 } else
597#endif
598 {
599 clock_set_pll3(best_n * 3000000);
600 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
601 dotclock,
602 (best_double + 1) * clock_get_pll3() / best_m / 1000,
603 best_double + 1, best_n, best_m);
604 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200605
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100606 if (tcon == 0) {
Hans de Goede13365782015-08-08 14:08:21 +0200607 u32 pll;
608
609 if (use_mipi_pll)
610 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
611 else if (best_double)
612 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
613 else
614 pll = CCM_LCD_CH0_CTRL_PLL3;
615
616 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100617 &ccm->lcd0_ch0_clk_cfg);
618 } else {
619 writel(CCM_LCD_CH1_CTRL_GATE |
620 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
621 CCM_LCD_CH1_CTRL_PLL3) |
622 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200623 if (sunxi_is_composite())
624 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
625 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100626 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200627
628 *clk_div = best_m;
629 *clk_double = best_double;
630}
631
632static void sunxi_lcdc_init(void)
633{
634 struct sunxi_ccm_reg * const ccm =
635 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
636 struct sunxi_lcdc_reg * const lcdc =
637 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
638
639 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200640#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100641 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
642#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200643 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100644#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200645
646 /* Clock on */
647 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100648#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200649#ifdef CONFIG_SUNXI_GEN_SUN6I
650 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
651#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100652 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
653#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200654#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200655
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200656 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200657}
658
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100659static void sunxi_lcdc_panel_enable(void)
660{
Hans de Goedece9e3322015-02-16 17:26:41 +0100661 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100662
663 /*
664 * Start with backlight disabled to avoid the screen flashing to
665 * white while the lcd inits.
666 */
667 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200668 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100669 gpio_request(pin, "lcd_backlight_enable");
670 gpio_direction_output(pin, 0);
671 }
672
673 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200674 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100675 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100676 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100677 }
678
Hans de Goedece9e3322015-02-16 17:26:41 +0100679 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200680 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100681 gpio_request(reset_pin, "lcd_reset");
682 gpio_direction_output(reset_pin, 0); /* Assert reset */
683 }
684
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100685 /* Give the backlight some time to turn off and power up the panel. */
686 mdelay(40);
687 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200688 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100689 gpio_request(pin, "lcd_power");
690 gpio_direction_output(pin, 1);
691 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100692
Hans de Goede7783ab22015-04-22 17:45:59 +0200693 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100694 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100695}
696
697static void sunxi_lcdc_backlight_enable(void)
698{
699 int pin;
700
701 /*
702 * We want to have scanned out at least one frame before enabling the
703 * backlight to avoid the screen flashing to white when we enable it.
704 */
705 mdelay(40);
706
707 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200708 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100709 gpio_direction_output(pin, 1);
710
711 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede663ae652016-08-19 15:25:41 +0200712#ifdef SUNXI_PWM_PIN0
713 if (pin == SUNXI_PWM_PIN0) {
714 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
715 SUNXI_PWM_CTRL_ENABLE0 |
716 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
717 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
718 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
719 return;
720 }
721#endif
Hans de Goede7783ab22015-04-22 17:45:59 +0200722 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100723 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100724}
725
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200726static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
727 struct display_timing *timing)
728{
729 timing->pixelclock.typ = mode->pixclock_khz * 1000;
730
731 timing->hactive.typ = mode->xres;
732 timing->hfront_porch.typ = mode->right_margin;
733 timing->hback_porch.typ = mode->left_margin;
734 timing->hsync_len.typ = mode->hsync_len;
735
736 timing->vactive.typ = mode->yres;
737 timing->vfront_porch.typ = mode->lower_margin;
738 timing->vback_porch.typ = mode->upper_margin;
739 timing->vsync_len.typ = mode->vsync_len;
740
741 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
742 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
743 else
744 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
745 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
746 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
747 else
748 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
749 if (mode->vmode == FB_VMODE_INTERLACED)
750 timing->flags |= DISPLAY_FLAGS_INTERLACED;
751}
752
Hans de Goede18366f72015-01-25 15:33:07 +0100753static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
754 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100755{
756 struct sunxi_lcdc_reg * const lcdc =
757 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200758 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200759 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100760
Lawrence Yuf721f962016-03-04 09:08:56 -0800761#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
762 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
763#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200764 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800765#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100766#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100767 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100768#endif
769#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100770 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100771#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200772#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
773 sunxi_gpio_set_drv(pin, 3);
774#endif
775 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100776
777 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
778
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200779 sunxi_ctfb_mode_to_display_timing(mode, &timing);
780 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200781 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100782}
783
Hans de Goedec06e00e2015-08-03 19:20:26 +0200784#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100785static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100786 int *clk_div, int *clk_double,
787 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200788{
789 struct sunxi_lcdc_reg * const lcdc =
790 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200791 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200792
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200793 sunxi_ctfb_mode_to_display_timing(mode, &timing);
794 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200795 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200796
Hans de Goedec3d15042014-12-27 15:19:23 +0100797 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100798 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
799 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100800 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200801
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100802 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200803}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200804#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100805
806#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100807
Hans de Goedea2017e82014-12-20 13:38:06 +0100808static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
809{
810 struct sunxi_hdmi_reg * const hdmi =
811 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
812 u8 checksum = 0;
813 u8 avi_info_frame[17] = {
814 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00
817 };
818 u8 vendor_info_frame[19] = {
819 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
821 0x00, 0x00, 0x00
822 };
823 int i;
824
825 if (mode->pixclock_khz <= 27000)
826 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
827 else
828 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
829
830 if (mode->xres * 100 / mode->yres < 156)
831 avi_info_frame[5] |= 0x18; /* 4 : 3 */
832 else
833 avi_info_frame[5] |= 0x28; /* 16 : 9 */
834
835 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
836 checksum += avi_info_frame[i];
837
838 avi_info_frame[3] = 0x100 - checksum;
839
840 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
841 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
842
843 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
844 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
845
846 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
847 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
848
849 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
850 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
851
852 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
853}
854
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100855static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100856 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200857{
858 struct sunxi_hdmi_reg * const hdmi =
859 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
860 int x, y;
861
862 /* Write clear interrupt status bits */
863 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
864
Hans de Goedea0b1b732014-12-21 14:37:45 +0100865 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100866 sunxi_hdmi_setup_info_frames(mode);
867
Hans de Goede95576692014-12-20 13:51:16 +0100868 /* Set input sync enable */
869 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
870
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200871 /* Init various registers, select pll3 as clock source */
872 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
873 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
874 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
875 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
876 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
877
878 /* Setup clk div and doubler */
879 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
880 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
881 if (!clk_double)
882 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
883
884 /* Setup timing registers */
885 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
886 &hdmi->video_size);
887
888 x = mode->hsync_len + mode->left_margin;
889 y = mode->vsync_len + mode->upper_margin;
890 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
891
892 x = mode->right_margin;
893 y = mode->lower_margin;
894 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
895
896 x = mode->hsync_len;
897 y = mode->vsync_len;
898 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
899
900 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
901 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
902
903 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
904 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
905}
906
Hans de Goede4125f922014-12-21 14:49:34 +0100907static void sunxi_hdmi_enable(void)
908{
909 struct sunxi_hdmi_reg * const hdmi =
910 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
911
912 udelay(100);
913 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
914}
915
Hans de Goedee9544592014-12-23 23:04:35 +0100916#endif /* CONFIG_VIDEO_HDMI */
917
Hans de Goedec06e00e2015-08-03 19:20:26 +0200918#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100919
Hans de Goedec06e00e2015-08-03 19:20:26 +0200920static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100921{
922 struct sunxi_ccm_reg * const ccm =
923 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
924 struct sunxi_tve_reg * const tve =
925 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
926
Hans de Goede8a195ca2015-08-06 12:08:33 +0200927 /* Reset off */
928 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100929 /* Clock on */
930 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
931
Hans de Goedec06e00e2015-08-03 19:20:26 +0200932 switch (sunxi_display.monitor) {
933 case sunxi_monitor_vga:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200934 tvencoder_mode_set(tve, tve_mode_vga);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200935 break;
936 case sunxi_monitor_composite_pal_nc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200937 tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
938 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200939 case sunxi_monitor_composite_pal:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200940 tvencoder_mode_set(tve, tve_mode_composite_pal);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200941 break;
942 case sunxi_monitor_composite_pal_m:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200943 tvencoder_mode_set(tve, tve_mode_composite_pal_m);
944 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200945 case sunxi_monitor_composite_ntsc:
Jernej Skrabec8531d082017-05-10 18:46:28 +0200946 tvencoder_mode_set(tve, tve_mode_composite_ntsc);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200947 break;
948 case sunxi_monitor_none:
949 case sunxi_monitor_dvi:
950 case sunxi_monitor_hdmi:
951 case sunxi_monitor_lcd:
952 break;
953 }
Hans de Goede260f5202014-12-25 13:58:06 +0100954}
955
Hans de Goedec06e00e2015-08-03 19:20:26 +0200956#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100957
Hans de Goede115e4b42014-12-23 18:39:52 +0100958static void sunxi_drc_init(void)
959{
Hans de Goedef07872b2015-04-06 20:33:34 +0200960#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100961 struct sunxi_ccm_reg * const ccm =
962 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
963
964 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530965#ifdef CONFIG_MACH_SUN8I_A33
966 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
967#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100968 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
969 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
970#endif
971}
972
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800973#ifdef CONFIG_VIDEO_VGA_VIA_LCD
974static void sunxi_vga_external_dac_enable(void)
975{
976 int pin;
977
978 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200979 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800980 gpio_request(pin, "vga_enable");
981 gpio_direction_output(pin, 1);
982 }
983}
984#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
985
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200986#ifdef CONFIG_VIDEO_LCD_SSD2828
987static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
988{
989 struct ssd2828_config cfg = {
990 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
991 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
992 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
993 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
994 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
995 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
996 .ssd2828_color_depth = 24,
997#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
998 .mipi_dsi_number_of_data_lanes = 4,
999 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1000 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1001 .mipi_dsi_delay_after_set_display_on_ms = 200
1002#else
1003#error MIPI LCD panel needs configuration parameters
1004#endif
1005 };
1006
1007 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1008 printf("SSD2828: SPI pins are not properly configured\n");
1009 return 1;
1010 }
1011 if (cfg.reset_pin == -1) {
1012 printf("SSD2828: Reset pin is not properly configured\n");
1013 return 1;
1014 }
1015
1016 return ssd2828_init(&cfg, mode);
1017}
1018#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1019
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001020static void sunxi_engines_init(void)
1021{
1022 sunxi_composer_init();
1023 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +01001024 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001025}
1026
Hans de Goedea0b1b732014-12-21 14:37:45 +01001027static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +01001028 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001029{
Hans de Goede260f5202014-12-25 13:58:06 +01001030 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001031 struct sunxi_lcdc_reg * const lcdc =
1032 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec8531d082017-05-10 18:46:28 +02001033 struct sunxi_tve_reg * __maybe_unused const tve =
1034 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +01001035
Hans de Goede4125f922014-12-21 14:49:34 +01001036 switch (sunxi_display.monitor) {
1037 case sunxi_monitor_none:
1038 break;
1039 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001040 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001041#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001042 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001043 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001044 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1045 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001046 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +01001047 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001048#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001049 break;
1050 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001051 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +02001052 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1053 /*
1054 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +02001055 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +02001056 * to avoid turning this on when using hdmi output.
1057 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +02001058 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +02001059 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1060 ANX9804_DATA_RATE_1620M,
1061 sunxi_display.depth);
1062 }
Hans de Goede743fb9552015-01-20 09:23:36 +01001063 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1064 mdelay(50); /* Wait for lcd controller power on */
1065 hitachi_tx18d42vm_init();
1066 }
Hans de Goede613dade2015-02-16 17:49:47 +01001067 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1068 unsigned int orig_i2c_bus = i2c_get_bus_num();
1069 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1070 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1071 i2c_set_bus_num(orig_i2c_bus);
1072 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001073 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001074 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001075 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001076 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001077#ifdef CONFIG_VIDEO_LCD_SSD2828
1078 sunxi_ssd2828_init(mode);
1079#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001080 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001081 break;
1082 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001083#ifdef CONFIG_VIDEO_VGA
1084 sunxi_composer_mode_set(mode, address);
1085 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001086 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +01001087 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001088 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001089 tvencoder_enable(tve);
Hans de Goede260f5202014-12-25 13:58:06 +01001090#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001091 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001092 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001093 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001094 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001095 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001096#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001097 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001098 case sunxi_monitor_composite_pal:
1099 case sunxi_monitor_composite_ntsc:
1100 case sunxi_monitor_composite_pal_m:
1101 case sunxi_monitor_composite_pal_nc:
1102#ifdef CONFIG_VIDEO_COMPOSITE
1103 sunxi_composer_mode_set(mode, address);
1104 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1105 sunxi_tvencoder_mode_set();
1106 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001107 lcdc_enable(lcdc, sunxi_display.depth);
Jernej Skrabec8531d082017-05-10 18:46:28 +02001108 tvencoder_enable(tve);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001109#endif
1110 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001111 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001112}
1113
Hans de Goedea0b1b732014-12-21 14:37:45 +01001114static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1115{
1116 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001117 case sunxi_monitor_none: return "none";
1118 case sunxi_monitor_dvi: return "dvi";
1119 case sunxi_monitor_hdmi: return "hdmi";
1120 case sunxi_monitor_lcd: return "lcd";
1121 case sunxi_monitor_vga: return "vga";
1122 case sunxi_monitor_composite_pal: return "composite-pal";
1123 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1124 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1125 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001126 }
1127 return NULL; /* never reached */
1128}
1129
Hans de Goede6c912862015-02-02 17:13:29 +01001130ulong board_get_usable_ram_top(ulong total_size)
1131{
1132 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1133}
1134
Hans de Goedea2bba492015-08-03 23:01:38 +02001135static bool sunxi_has_hdmi(void)
1136{
1137#ifdef CONFIG_VIDEO_HDMI
1138 return true;
1139#else
1140 return false;
1141#endif
1142}
1143
1144static bool sunxi_has_lcd(void)
1145{
1146 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1147
1148 return lcd_mode[0] != 0;
1149}
1150
1151static bool sunxi_has_vga(void)
1152{
1153#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1154 return true;
1155#else
1156 return false;
1157#endif
1158}
1159
Hans de Goedec06e00e2015-08-03 19:20:26 +02001160static bool sunxi_has_composite(void)
1161{
1162#ifdef CONFIG_VIDEO_COMPOSITE
1163 return true;
1164#else
1165 return false;
1166#endif
1167}
1168
Hans de Goedea2bba492015-08-03 23:01:38 +02001169static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1170{
1171 if (allow_hdmi && sunxi_has_hdmi())
1172 return sunxi_monitor_dvi;
1173 else if (sunxi_has_lcd())
1174 return sunxi_monitor_lcd;
1175 else if (sunxi_has_vga())
1176 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001177 else if (sunxi_has_composite())
1178 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001179 else
1180 return sunxi_monitor_none;
1181}
1182
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001183void *video_hw_init(void)
1184{
1185 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001186 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001187 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001188 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001189#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001190 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001191#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001192 int i, overscan_offset, overscan_x, overscan_y;
1193 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001194 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001195 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001196
1197 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1198
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001199 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1200 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001201#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001202 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001203 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001204 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001205#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001206 overscan_x = video_get_option_int(options, "overscan_x", -1);
1207 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001208 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001209 video_get_option_string(options, "monitor", mon, sizeof(mon),
1210 sunxi_get_mon_desc(sunxi_display.monitor));
1211 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1212 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1213 sunxi_display.monitor = i;
1214 break;
1215 }
1216 }
1217 if (i > SUNXI_MONITOR_LAST)
1218 printf("Unknown monitor: '%s', falling back to '%s'\n",
1219 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001220
Hans de Goede7977ec22014-12-25 13:52:04 +01001221#ifdef CONFIG_VIDEO_HDMI
1222 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1223 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1224 sunxi_display.monitor == sunxi_monitor_hdmi) {
1225 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001226 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001227 if (ret) {
1228 printf("HDMI connected: ");
1229 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1230 mode = &custom;
1231 } else if (hpd) {
1232 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001233 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001234 } /* else continue with hdmi/dvi without a cable connected */
1235 }
1236#endif
1237
Hans de Goede4125f922014-12-21 14:49:34 +01001238 switch (sunxi_display.monitor) {
1239 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001240 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001241 case sunxi_monitor_dvi:
1242 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001243 if (!sunxi_has_hdmi()) {
1244 printf("HDMI/DVI not supported on this board\n");
1245 sunxi_display.monitor = sunxi_monitor_none;
1246 return NULL;
1247 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001248 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001249 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001250 if (!sunxi_has_lcd()) {
1251 printf("LCD not supported on this board\n");
1252 sunxi_display.monitor = sunxi_monitor_none;
1253 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001254 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001255 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1256 mode = &custom;
1257 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001258 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001259 if (!sunxi_has_vga()) {
1260 printf("VGA not supported on this board\n");
1261 sunxi_display.monitor = sunxi_monitor_none;
1262 return NULL;
1263 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001264 sunxi_display.depth = 18;
1265 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001266 case sunxi_monitor_composite_pal:
1267 case sunxi_monitor_composite_ntsc:
1268 case sunxi_monitor_composite_pal_m:
1269 case sunxi_monitor_composite_pal_nc:
1270 if (!sunxi_has_composite()) {
1271 printf("Composite video not supported on this board\n");
1272 sunxi_display.monitor = sunxi_monitor_none;
1273 return NULL;
1274 }
1275 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1276 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1277 mode = &composite_video_modes[0];
1278 else
1279 mode = &composite_video_modes[1];
1280 sunxi_display.depth = 24;
1281 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001282 }
1283
Hans de Goeded955f442015-08-05 00:06:47 +02001284 /* Yes these defaults are quite high, overscan on composite sucks... */
1285 if (overscan_x == -1)
1286 overscan_x = sunxi_is_composite() ? 32 : 0;
1287 if (overscan_y == -1)
1288 overscan_y = sunxi_is_composite() ? 20 : 0;
1289
Hans de Goede18799252015-02-02 18:00:53 +01001290 sunxi_display.fb_size =
1291 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001292 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1293 /* We want to keep the fb_base for simplefb page aligned, where as
1294 * the sunxi dma engines will happily accept an unaligned address. */
1295 if (overscan_offset)
1296 sunxi_display.fb_size += 0x1000;
1297
Hans de Goede18799252015-02-02 18:00:53 +01001298 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1299 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1300 sunxi_display.fb_size >> 10,
1301 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1302 return NULL;
1303 }
1304
Hans de Goeded955f442015-08-05 00:06:47 +02001305 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1306 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001307 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001308 sunxi_get_mon_desc(sunxi_display.monitor),
1309 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001310
Hans de Goede18799252015-02-02 18:00:53 +01001311 gd->fb_base = gd->bd->bi_dram[0].start +
1312 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001313 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001314
1315 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1316 sunxi_display.fb_addr = gd->fb_base;
1317 if (overscan_offset) {
1318 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1319 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1320 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1321 flush_cache(gd->fb_base, sunxi_display.fb_size);
1322 }
1323 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001324
1325 /*
1326 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001327 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001328 */
Hans de Goeded955f442015-08-05 00:06:47 +02001329 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001330 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1331 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001332 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1333 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1334 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001335
1336 return graphic_device;
1337}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001338
1339/*
1340 * Simplefb support.
1341 */
1342#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1343int sunxi_simplefb_setup(void *blob)
1344{
1345 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1346 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001347 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001348 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001349
Hans de Goedec3cc4262015-01-19 08:44:07 +01001350#ifdef CONFIG_MACH_SUN4I
1351#define PIPELINE_PREFIX "de_fe0-"
1352#else
1353#define PIPELINE_PREFIX
1354#endif
1355
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001356 switch (sunxi_display.monitor) {
1357 case sunxi_monitor_none:
1358 return 0;
1359 case sunxi_monitor_dvi:
1360 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001361 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001362 break;
1363 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001364 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001365 break;
1366 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001367#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001368 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001369#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001370 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001371#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001372 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001373 case sunxi_monitor_composite_pal:
1374 case sunxi_monitor_composite_ntsc:
1375 case sunxi_monitor_composite_pal_m:
1376 case sunxi_monitor_composite_pal_nc:
1377 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1378 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001379 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001380
Icenowy Zheng067a6972017-10-26 11:14:45 +08001381 offset = sunxi_simplefb_fdt_match(blob, pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001382 if (offset < 0) {
1383 eprintf("Cannot setup simplefb: node not found\n");
1384 return 0; /* Keep older kernels working */
1385 }
1386
Hans de Goede6c912862015-02-02 17:13:29 +01001387 /*
1388 * Do not report the framebuffer as free RAM to the OS, note we cannot
1389 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1390 * and e.g. Linux refuses to iomap RAM on ARM, see:
1391 * linux/arch/arm/mm/ioremap.c around line 301.
1392 */
1393 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001394 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001395 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1396 if (ret) {
1397 eprintf("Cannot setup simplefb: Error reserving memory\n");
1398 return ret;
1399 }
1400
Hans de Goeded955f442015-08-05 00:06:47 +02001401 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001402 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001403 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001404 if (ret)
1405 eprintf("Cannot setup simplefb: Error setting properties\n");
1406
1407 return ret;
1408}
1409#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */