blob: 48192ef87ea5ba39ce8c5b0f4b071fdd9987734c [file] [log] [blame]
Luc Verhaegen7f2c5212014-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 Goede39920c82015-08-03 19:20:26 +02005 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
Luc Verhaegen7f2c5212014-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 Goede2dae8002014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Jernej Skrabec5e023e72017-03-27 19:22:29 +020015#include <asm/arch/lcdc.h>
Hans de Goede421c98d2016-08-19 15:25:41 +020016#include <asm/arch/pwm.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020017#include <asm/global_data.h>
Hans de Goede2dae8002014-12-21 16:28:32 +010018#include <asm/gpio.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020019#include <asm/io.h>
Hans de Goede6944aff2015-10-03 15:18:33 +020020#include <axp_pmic.h>
Hans de Goede75481602014-12-19 16:05:12 +010021#include <errno.h>
Luc Verhaegen2d7a0842014-08-13 07:55:07 +020022#include <fdtdec.h>
23#include <fdt_support.h>
Hans de Goedeaad2ac22015-02-16 17:49:47 +010024#include <i2c.h>
Hans de Goede58332f82015-08-05 00:06:47 +020025#include <malloc.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020026#include <video_fb.h>
Jernej Skrabec5e023e72017-03-27 19:22:29 +020027#include "../videomodes.h"
28#include "../anx9804.h"
29#include "../hitachi_tx18d42vm_lcd.h"
30#include "../ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020031
Hans de Goedea7403ae2015-01-22 21:02:42 +010032#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
33#define PWM_ON 0
34#define PWM_OFF 1
35#else
36#define PWM_ON 1
37#define PWM_OFF 0
38#endif
39
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020040DECLARE_GLOBAL_DATA_PTR;
41
Hans de Goede1c092202014-12-21 14:37:45 +010042enum sunxi_monitor {
43 sunxi_monitor_none,
44 sunxi_monitor_dvi,
45 sunxi_monitor_hdmi,
46 sunxi_monitor_lcd,
47 sunxi_monitor_vga,
Hans de Goede39920c82015-08-03 19:20:26 +020048 sunxi_monitor_composite_pal,
49 sunxi_monitor_composite_ntsc,
50 sunxi_monitor_composite_pal_m,
51 sunxi_monitor_composite_pal_nc,
Hans de Goede1c092202014-12-21 14:37:45 +010052};
Hans de Goede39920c82015-08-03 19:20:26 +020053#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goede1c092202014-12-21 14:37:45 +010054
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020055struct sunxi_display {
56 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010057 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010058 unsigned int depth;
Hans de Goede58332f82015-08-05 00:06:47 +020059 unsigned int fb_addr;
Hans de Goede20779ec2015-02-02 18:00:53 +010060 unsigned int fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020061} sunxi_display;
62
Hans de Goede39920c82015-08-03 19:20:26 +020063const struct ctfb_res_modes composite_video_modes[2] = {
64 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
65 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
66 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
67};
68
Hans de Goede2fbf0912014-12-23 23:04:35 +010069#ifdef CONFIG_VIDEO_HDMI
70
Hans de Goede75481602014-12-19 16:05:12 +010071/*
72 * Wait up to 200ms for value to be set in given part of reg.
73 */
74static int await_completion(u32 *reg, u32 mask, u32 val)
75{
76 unsigned long tmo = timer_get_us() + 200000;
77
78 while ((readl(reg) & mask) != val) {
79 if (timer_get_us() > tmo) {
80 printf("DDC: timeout reading EDID\n");
81 return -ETIME;
82 }
83 }
84 return 0;
85}
86
Hans de Goede7fad8a92014-12-28 09:13:21 +010087static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020088{
89 struct sunxi_ccm_reg * const ccm =
90 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
91 struct sunxi_hdmi_reg * const hdmi =
92 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede7fad8a92014-12-28 09:13:21 +010093 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020094
95 /* Set pll3 to 300MHz */
96 clock_set_pll3(300000000);
97
98 /* Set hdmi parent to pll3 */
99 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
100 CCM_HDMI_CTRL_PLL3);
101
102 /* Set ahb gating to pass */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200103#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100104 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
105#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200106 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
107
108 /* Clock on */
109 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
110
111 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
112 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
113
Hans de Goede40f1b872014-12-20 15:15:23 +0100114 while (timer_get_us() < tmo) {
115 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
116 return 1;
117 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200118
Hans de Goede40f1b872014-12-20 15:15:23 +0100119 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100120}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200121
Hans de Goede518cef22014-12-19 15:13:57 +0100122static void sunxi_hdmi_shutdown(void)
123{
124 struct sunxi_ccm_reg * const ccm =
125 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
126 struct sunxi_hdmi_reg * const hdmi =
127 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
128
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200129 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
130 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
131 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goede44d8ae52015-04-06 20:33:34 +0200132#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100133 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
134#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200135 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200136}
137
Hans de Goede75481602014-12-19 16:05:12 +0100138static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
139{
140 struct sunxi_hdmi_reg * const hdmi =
141 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
142
143 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
144 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
145 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
146 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
147 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
148#ifndef CONFIG_MACH_SUN6I
149 writel(n, &hdmi->ddc_byte_count);
150 writel(cmnd, &hdmi->ddc_cmnd);
151#else
152 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
153#endif
154 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
155
156 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
157}
158
159static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
160{
161 struct sunxi_hdmi_reg * const hdmi =
162 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
163 int i, n;
164
165 while (count > 0) {
166 if (count > 16)
167 n = 16;
168 else
169 n = count;
170
171 if (sunxi_hdmi_ddc_do_command(
172 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
173 offset, n))
174 return -ETIME;
175
176 for (i = 0; i < n; i++)
177 *buf++ = readb(&hdmi->ddc_fifo_data);
178
179 offset += n;
180 count -= n;
181 }
182
183 return 0;
184}
185
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100186static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
187{
188 int r, retries = 2;
189
190 do {
191 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
192 if (r)
193 continue;
194 r = edid_check_checksum(buf);
195 if (r) {
196 printf("EDID block %d: checksum error%s\n",
197 block, retries ? ", retrying" : "");
198 }
199 } while (r && retries--);
200
201 return r;
202}
203
Hans de Goede1c092202014-12-21 14:37:45 +0100204static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100205{
206 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100207 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-12-19 16:05:12 +0100208 struct edid_detailed_timing *t =
209 (struct edid_detailed_timing *)edid1.monitor_details.timing;
210 struct sunxi_hdmi_reg * const hdmi =
211 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
212 struct sunxi_ccm_reg * const ccm =
213 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedef3000682014-12-20 14:31:45 +0100214 int i, r, ext_blocks = 0;
Hans de Goede75481602014-12-19 16:05:12 +0100215
216 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
217 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
218 &hdmi->pad_ctrl1);
219 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
220 &hdmi->pll_ctrl);
221 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
222
223 /* Reset i2c controller */
224 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
225 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
226 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
227 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
228 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
229 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
230 return -EIO;
231
232 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
233#ifndef CONFIG_MACH_SUN6I
234 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
235 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
236#endif
237
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100238 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-12-20 14:31:45 +0100239 if (r == 0) {
240 r = edid_check_info(&edid1);
241 if (r) {
242 printf("EDID: invalid EDID data\n");
243 r = -EINVAL;
244 }
245 }
246 if (r == 0) {
247 ext_blocks = edid1.extension_flag;
248 if (ext_blocks > 4)
249 ext_blocks = 4;
250 for (i = 0; i < ext_blocks; i++) {
251 if (sunxi_hdmi_edid_get_block(1 + i,
252 (u8 *)&cea681[i]) != 0) {
253 ext_blocks = i;
254 break;
255 }
256 }
257 }
Hans de Goede75481602014-12-19 16:05:12 +0100258
259 /* Disable DDC engine, no longer needed */
260 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
261 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
262
263 if (r)
264 return r;
265
Hans de Goede75481602014-12-19 16:05:12 +0100266 /* We want version 1.3 or 1.2 with detailed timing info */
267 if (edid1.version != 1 || (edid1.revision < 3 &&
268 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
269 printf("EDID: unsupported version %d.%d\n",
270 edid1.version, edid1.revision);
271 return -EINVAL;
272 }
273
274 /* Take the first usable detailed timing */
275 for (i = 0; i < 4; i++, t++) {
276 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
277 if (r == 0)
278 break;
279 }
280 if (i == 4) {
281 printf("EDID: no usable detailed timing found\n");
282 return -ENOENT;
283 }
284
Hans de Goedef3000682014-12-20 14:31:45 +0100285 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100286 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-12-20 14:31:45 +0100287 for (i = 0; i < ext_blocks; i++) {
288 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
289 cea681[i].revision < 2)
290 continue;
291
292 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goede1c092202014-12-21 14:37:45 +0100293 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100294 }
295
Hans de Goede75481602014-12-19 16:05:12 +0100296 return 0;
297}
298
Hans de Goede2fbf0912014-12-23 23:04:35 +0100299#endif /* CONFIG_VIDEO_HDMI */
300
Hans de Goede7cd6f922015-01-19 08:44:07 +0100301#ifdef CONFIG_MACH_SUN4I
302/*
303 * Testing has shown that on sun4i the display backend engine does not have
304 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
305 * fifo underruns. So on sun4i we use the display frontend engine to do the
306 * dma from memory, as the frontend does have deep enough fifo-s.
307 */
308
309static const u32 sun4i_vert_coef[32] = {
310 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
311 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
312 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
313 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
314 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
315 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
316 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
317 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
318};
319
320static const u32 sun4i_horz_coef[64] = {
321 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
322 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
323 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
324 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
325 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
326 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
327 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
328 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
329 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
330 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
331 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
332 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
333 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
334 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
335 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
336 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
337};
338
339static void sunxi_frontend_init(void)
340{
341 struct sunxi_ccm_reg * const ccm =
342 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
343 struct sunxi_de_fe_reg * const de_fe =
344 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
345 int i;
346
347 /* Clocks on */
348 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
349 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
350 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
351
352 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
353
354 for (i = 0; i < 32; i++) {
355 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
356 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
357 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
358 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
359 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
360 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
361 }
362
363 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
364}
365
366static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
367 unsigned int address)
368{
369 struct sunxi_de_fe_reg * const de_fe =
370 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
371
372 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
373 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
374 writel(mode->xres * 4, &de_fe->ch0_stride);
375 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
376 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
377
378 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
379 &de_fe->ch0_insize);
380 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
381 &de_fe->ch0_outsize);
382 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
383 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
384
385 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
386 &de_fe->ch1_insize);
387 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
388 &de_fe->ch1_outsize);
389 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
390 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
391
392 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
393}
394
395static void sunxi_frontend_enable(void)
396{
397 struct sunxi_de_fe_reg * const de_fe =
398 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
399
400 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
401}
402#else
403static void sunxi_frontend_init(void) {}
404static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
405 unsigned int address) {}
406static void sunxi_frontend_enable(void) {}
407#endif
408
Hans de Goede39920c82015-08-03 19:20:26 +0200409static bool sunxi_is_composite(void)
410{
411 switch (sunxi_display.monitor) {
412 case sunxi_monitor_none:
413 case sunxi_monitor_dvi:
414 case sunxi_monitor_hdmi:
415 case sunxi_monitor_lcd:
416 case sunxi_monitor_vga:
417 return false;
418 case sunxi_monitor_composite_pal:
419 case sunxi_monitor_composite_ntsc:
420 case sunxi_monitor_composite_pal_m:
421 case sunxi_monitor_composite_pal_nc:
422 return true;
423 }
424
425 return false; /* Never reached */
426}
427
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200428/*
429 * This is the entity that mixes and matches the different layers and inputs.
430 * Allwinner calls it the back-end, but i like composer better.
431 */
432static void sunxi_composer_init(void)
433{
434 struct sunxi_ccm_reg * const ccm =
435 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
436 struct sunxi_de_be_reg * const de_be =
437 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
438 int i;
439
Hans de Goede7cd6f922015-01-19 08:44:07 +0100440 sunxi_frontend_init();
441
Hans de Goede44d8ae52015-04-06 20:33:34 +0200442#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100443 /* Reset off */
444 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
445#endif
446
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200447 /* Clocks on */
448 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100449#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200450 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100451#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200452 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
453
454 /* Engine bug, clear registers after reset */
455 for (i = 0x0800; i < 0x1000; i += 4)
456 writel(0, SUNXI_DE_BE0_BASE + i);
457
458 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
459}
460
Hans de Goede39920c82015-08-03 19:20:26 +0200461static u32 sunxi_rgb2yuv_coef[12] = {
462 0x00000107, 0x00000204, 0x00000064, 0x00000108,
463 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
464 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
465};
466
Hans de Goedebe8ec632014-12-19 13:46:33 +0100467static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200468 unsigned int address)
469{
470 struct sunxi_de_be_reg * const de_be =
471 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goede39920c82015-08-03 19:20:26 +0200472 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200473
Hans de Goede7cd6f922015-01-19 08:44:07 +0100474 sunxi_frontend_mode_set(mode, address);
475
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200476 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
477 &de_be->disp_size);
478 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
479 &de_be->layer0_size);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100480#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200481 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
482 writel(address << 3, &de_be->layer0_addr_low32b);
483 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100484#else
485 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
486#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200487 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
488
489 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200490 if (mode->vmode == FB_VMODE_INTERLACED)
491 setbits_le32(&de_be->mode,
Hans de Goeded8d07992015-08-06 12:08:33 +0200492#ifndef CONFIG_MACH_SUN5I
Hans de Goedef6d9d322015-08-02 16:49:29 +0200493 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goeded8d07992015-08-06 12:08:33 +0200494#endif
Hans de Goedef6d9d322015-08-02 16:49:29 +0200495 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goede39920c82015-08-03 19:20:26 +0200496
497 if (sunxi_is_composite()) {
498 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
499 &de_be->output_color_ctrl);
500 for (i = 0; i < 12; i++)
501 writel(sunxi_rgb2yuv_coef[i],
502 &de_be->output_color_coef[i]);
503 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200504}
505
Hans de Goede0e045212014-12-21 14:49:34 +0100506static void sunxi_composer_enable(void)
507{
508 struct sunxi_de_be_reg * const de_be =
509 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
510
Hans de Goede7cd6f922015-01-19 08:44:07 +0100511 sunxi_frontend_enable();
512
Hans de Goede0e045212014-12-21 14:49:34 +0100513 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
514 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
515}
516
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200517/*
518 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
519 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100520static void sunxi_lcdc_pll_set(int tcon, int dotclock,
521 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200522{
523 struct sunxi_ccm_reg * const ccm =
524 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100525 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200526 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
527 int best_double = 0;
Hans de Goedefb685d32015-08-08 14:08:21 +0200528 bool use_mipi_pll = false;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200529
Hans de Goede5489ebc2014-12-21 16:27:45 +0100530 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100531#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100532 min_m = 6;
533 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100534#endif
535#ifdef CONFIG_VIDEO_LCD_IF_LVDS
536 min_m = max_m = 7;
537#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100538 } else {
539 min_m = 1;
540 max_m = 15;
541 }
542
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200543 /*
544 * Find the lowest divider resulting in a matching clock, if there
545 * is no match, pick the closest lower clock, as monitors tend to
546 * not sync to higher frequencies.
547 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100548 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200549 n = (m * dotclock) / 3000;
550
551 if ((n >= 9) && (n <= 127)) {
552 value = (3000 * n) / m;
553 diff = dotclock - value;
554 if (diff < best_diff) {
555 best_diff = diff;
556 best_m = m;
557 best_n = n;
558 best_double = 0;
559 }
560 }
561
562 /* These are just duplicates */
563 if (!(m & 1))
564 continue;
565
566 n = (m * dotclock) / 6000;
567 if ((n >= 9) && (n <= 127)) {
568 value = (6000 * n) / m;
569 diff = dotclock - value;
570 if (diff < best_diff) {
571 best_diff = diff;
572 best_m = m;
573 best_n = n;
574 best_double = 1;
575 }
576 }
577 }
578
Hans de Goedefb685d32015-08-08 14:08:21 +0200579#ifdef CONFIG_MACH_SUN6I
580 /*
581 * Use the MIPI pll if we've been unable to find any matching setting
582 * for PLL3, this happens with high dotclocks because of min_m = 6.
583 */
584 if (tcon == 0 && best_n == 0) {
585 use_mipi_pll = true;
586 best_m = 6; /* Minimum m for tcon0 */
587 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200588
Hans de Goedefb685d32015-08-08 14:08:21 +0200589 if (use_mipi_pll) {
590 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
591 clock_set_mipi_pll(best_m * dotclock * 1000);
592 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
593 dotclock, clock_get_mipi_pll() / best_m / 1000);
594 } else
595#endif
596 {
597 clock_set_pll3(best_n * 3000000);
598 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
599 dotclock,
600 (best_double + 1) * clock_get_pll3() / best_m / 1000,
601 best_double + 1, best_n, best_m);
602 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200603
Hans de Goede5489ebc2014-12-21 16:27:45 +0100604 if (tcon == 0) {
Hans de Goedefb685d32015-08-08 14:08:21 +0200605 u32 pll;
606
607 if (use_mipi_pll)
608 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
609 else if (best_double)
610 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
611 else
612 pll = CCM_LCD_CH0_CTRL_PLL3;
613
614 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
Hans de Goede5489ebc2014-12-21 16:27:45 +0100615 &ccm->lcd0_ch0_clk_cfg);
616 } else {
617 writel(CCM_LCD_CH1_CTRL_GATE |
618 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
619 CCM_LCD_CH1_CTRL_PLL3) |
620 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goede39920c82015-08-03 19:20:26 +0200621 if (sunxi_is_composite())
622 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
623 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goede5489ebc2014-12-21 16:27:45 +0100624 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200625
626 *clk_div = best_m;
627 *clk_double = best_double;
628}
629
630static void sunxi_lcdc_init(void)
631{
632 struct sunxi_ccm_reg * const ccm =
633 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
634 struct sunxi_lcdc_reg * const lcdc =
635 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
636
637 /* Reset off */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200638#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100639 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
640#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200641 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100642#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200643
644 /* Clock on */
645 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100646#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede83edb2a2015-05-14 18:52:54 +0200647#ifdef CONFIG_SUNXI_GEN_SUN6I
648 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
649#else
Hans de Goede213480e2015-01-01 22:04:34 +0100650 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
651#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200652#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200653
Jernej Skrabec5e023e72017-03-27 19:22:29 +0200654 lcdc_init(lcdc);
Hans de Goede0e045212014-12-21 14:49:34 +0100655}
656
Hans de Goede2dae8002014-12-21 16:28:32 +0100657static void sunxi_lcdc_panel_enable(void)
658{
Hans de Goede242e3d82015-02-16 17:26:41 +0100659 int pin, reset_pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100660
661 /*
662 * Start with backlight disabled to avoid the screen flashing to
663 * white while the lcd inits.
664 */
665 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200666 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100667 gpio_request(pin, "lcd_backlight_enable");
668 gpio_direction_output(pin, 0);
669 }
670
671 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200672 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100673 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goedea7403ae2015-01-22 21:02:42 +0100674 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-12-21 16:28:32 +0100675 }
676
Hans de Goede242e3d82015-02-16 17:26:41 +0100677 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede15728192015-04-22 17:45:59 +0200678 if (reset_pin >= 0) {
Hans de Goede242e3d82015-02-16 17:26:41 +0100679 gpio_request(reset_pin, "lcd_reset");
680 gpio_direction_output(reset_pin, 0); /* Assert reset */
681 }
682
Hans de Goede2dae8002014-12-21 16:28:32 +0100683 /* Give the backlight some time to turn off and power up the panel. */
684 mdelay(40);
685 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede15728192015-04-22 17:45:59 +0200686 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100687 gpio_request(pin, "lcd_power");
688 gpio_direction_output(pin, 1);
689 }
Hans de Goede242e3d82015-02-16 17:26:41 +0100690
Hans de Goede15728192015-04-22 17:45:59 +0200691 if (reset_pin >= 0)
Hans de Goede242e3d82015-02-16 17:26:41 +0100692 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede2dae8002014-12-21 16:28:32 +0100693}
694
695static void sunxi_lcdc_backlight_enable(void)
696{
697 int pin;
698
699 /*
700 * We want to have scanned out at least one frame before enabling the
701 * backlight to avoid the screen flashing to white when we enable it.
702 */
703 mdelay(40);
704
705 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200706 if (pin >= 0)
Hans de Goede2dae8002014-12-21 16:28:32 +0100707 gpio_direction_output(pin, 1);
708
709 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede421c98d2016-08-19 15:25:41 +0200710#ifdef SUNXI_PWM_PIN0
711 if (pin == SUNXI_PWM_PIN0) {
712 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
713 SUNXI_PWM_CTRL_ENABLE0 |
714 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
715 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
716 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
717 return;
718 }
719#endif
Hans de Goede15728192015-04-22 17:45:59 +0200720 if (pin >= 0)
Hans de Goedea7403ae2015-01-22 21:02:42 +0100721 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-12-21 16:28:32 +0100722}
723
Hans de Goedefb75d972015-01-25 15:33:07 +0100724static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
725 bool for_ext_vga_dac)
Hans de Goede2dae8002014-12-21 16:28:32 +0100726{
727 struct sunxi_lcdc_reg * const lcdc =
728 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec5e023e72017-03-27 19:22:29 +0200729 int clk_div, clk_double, pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100730
Lawrence Yucf6eca72016-03-04 09:08:56 -0800731#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
732 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
733#else
Hans de Goedec1cfd512015-08-08 16:13:53 +0200734 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yucf6eca72016-03-04 09:08:56 -0800735#endif
Hans de Goede213480e2015-01-01 22:04:34 +0100736#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100737 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100738#endif
739#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100740 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede213480e2015-01-01 22:04:34 +0100741#endif
Hans de Goedec1cfd512015-08-08 16:13:53 +0200742#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
743 sunxi_gpio_set_drv(pin, 3);
744#endif
745 }
Hans de Goede2dae8002014-12-21 16:28:32 +0100746
747 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
748
Jernej Skrabec5e023e72017-03-27 19:22:29 +0200749 lcdc_tcon0_mode_set(lcdc, mode, clk_div, for_ext_vga_dac,
750 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100751}
752
Hans de Goede39920c82015-08-03 19:20:26 +0200753#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede0e045212014-12-21 14:49:34 +0100754static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100755 int *clk_div, int *clk_double,
756 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200757{
758 struct sunxi_lcdc_reg * const lcdc =
759 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200760
Jernej Skrabec5e023e72017-03-27 19:22:29 +0200761 lcdc_tcon1_mode_set(lcdc, mode, use_portd_hvsync,
762 sunxi_is_composite());
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200763
Hans de Goede3ffbe472014-12-27 15:19:23 +0100764 if (use_portd_hvsync) {
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100765 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
766 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goede3ffbe472014-12-27 15:19:23 +0100767 }
Hans de Goeded8d07992015-08-06 12:08:33 +0200768
Hans de Goede5489ebc2014-12-21 16:27:45 +0100769 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200770}
Hans de Goede39920c82015-08-03 19:20:26 +0200771#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +0100772
773#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200774
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100775static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
776{
777 struct sunxi_hdmi_reg * const hdmi =
778 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
779 u8 checksum = 0;
780 u8 avi_info_frame[17] = {
781 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783 0x00
784 };
785 u8 vendor_info_frame[19] = {
786 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788 0x00, 0x00, 0x00
789 };
790 int i;
791
792 if (mode->pixclock_khz <= 27000)
793 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
794 else
795 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
796
797 if (mode->xres * 100 / mode->yres < 156)
798 avi_info_frame[5] |= 0x18; /* 4 : 3 */
799 else
800 avi_info_frame[5] |= 0x28; /* 16 : 9 */
801
802 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
803 checksum += avi_info_frame[i];
804
805 avi_info_frame[3] = 0x100 - checksum;
806
807 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
808 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
809
810 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
811 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
812
813 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
814 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
815
816 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
817 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
818
819 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
820}
821
Hans de Goedebe8ec632014-12-19 13:46:33 +0100822static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100823 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200824{
825 struct sunxi_hdmi_reg * const hdmi =
826 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
827 int x, y;
828
829 /* Write clear interrupt status bits */
830 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
831
Hans de Goede1c092202014-12-21 14:37:45 +0100832 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100833 sunxi_hdmi_setup_info_frames(mode);
834
Hans de Goede876aaaf2014-12-20 13:51:16 +0100835 /* Set input sync enable */
836 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
837
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200838 /* Init various registers, select pll3 as clock source */
839 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
840 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
841 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
842 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
843 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
844
845 /* Setup clk div and doubler */
846 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
847 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
848 if (!clk_double)
849 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
850
851 /* Setup timing registers */
852 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
853 &hdmi->video_size);
854
855 x = mode->hsync_len + mode->left_margin;
856 y = mode->vsync_len + mode->upper_margin;
857 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
858
859 x = mode->right_margin;
860 y = mode->lower_margin;
861 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
862
863 x = mode->hsync_len;
864 y = mode->vsync_len;
865 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
866
867 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
868 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
869
870 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
871 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
872}
873
Hans de Goede0e045212014-12-21 14:49:34 +0100874static void sunxi_hdmi_enable(void)
875{
876 struct sunxi_hdmi_reg * const hdmi =
877 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
878
879 udelay(100);
880 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
881}
882
Hans de Goede2fbf0912014-12-23 23:04:35 +0100883#endif /* CONFIG_VIDEO_HDMI */
884
Hans de Goede39920c82015-08-03 19:20:26 +0200885#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goeded9786d22014-12-25 13:58:06 +0100886
Hans de Goede39920c82015-08-03 19:20:26 +0200887static void sunxi_tvencoder_mode_set(void)
Hans de Goeded9786d22014-12-25 13:58:06 +0100888{
889 struct sunxi_ccm_reg * const ccm =
890 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
891 struct sunxi_tve_reg * const tve =
892 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
893
Hans de Goeded8d07992015-08-06 12:08:33 +0200894 /* Reset off */
895 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goeded9786d22014-12-25 13:58:06 +0100896 /* Clock on */
897 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
898
Hans de Goede39920c82015-08-03 19:20:26 +0200899 switch (sunxi_display.monitor) {
900 case sunxi_monitor_vga:
901 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
902 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
903 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
904 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
905 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
906 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
907 break;
908 case sunxi_monitor_composite_pal_nc:
909 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
910 /* Fall through */
911 case sunxi_monitor_composite_pal:
912 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
913 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
914 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
915 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
916 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
917 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
918 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
919 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
920 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
921 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
922 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
923 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
924 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
925 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
926 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
927 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
928 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
929 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
930 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
931 break;
932 case sunxi_monitor_composite_pal_m:
933 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
934 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
935 /* Fall through */
936 case sunxi_monitor_composite_ntsc:
937 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
938 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
939 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
940 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
941 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
942 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
943 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
944 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
945 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
946 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
947 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
948 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
949 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
950 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
951 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
952 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
953 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
954 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
955 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
956 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
957 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
958 break;
959 case sunxi_monitor_none:
960 case sunxi_monitor_dvi:
961 case sunxi_monitor_hdmi:
962 case sunxi_monitor_lcd:
963 break;
964 }
Hans de Goeded9786d22014-12-25 13:58:06 +0100965}
966
Hans de Goede39920c82015-08-03 19:20:26 +0200967static void sunxi_tvencoder_enable(void)
Hans de Goeded9786d22014-12-25 13:58:06 +0100968{
969 struct sunxi_tve_reg * const tve =
970 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
971
972 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
973}
974
Hans de Goede39920c82015-08-03 19:20:26 +0200975#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +0100976
Hans de Goedee8400792014-12-23 18:39:52 +0100977static void sunxi_drc_init(void)
978{
Hans de Goede44d8ae52015-04-06 20:33:34 +0200979#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedee8400792014-12-23 18:39:52 +0100980 struct sunxi_ccm_reg * const ccm =
981 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
982
983 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar8c3dacf2015-03-01 23:47:48 +0530984#ifdef CONFIG_MACH_SUN8I_A33
985 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
986#endif
Hans de Goedee8400792014-12-23 18:39:52 +0100987 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
988 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
989#endif
990}
991
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +0800992#ifdef CONFIG_VIDEO_VGA_VIA_LCD
993static void sunxi_vga_external_dac_enable(void)
994{
995 int pin;
996
997 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200998 if (pin >= 0) {
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +0800999 gpio_request(pin, "vga_enable");
1000 gpio_direction_output(pin, 1);
1001 }
1002}
1003#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1004
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001005#ifdef CONFIG_VIDEO_LCD_SSD2828
1006static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1007{
1008 struct ssd2828_config cfg = {
1009 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1010 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1011 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1012 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1013 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1014 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1015 .ssd2828_color_depth = 24,
1016#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1017 .mipi_dsi_number_of_data_lanes = 4,
1018 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1019 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1020 .mipi_dsi_delay_after_set_display_on_ms = 200
1021#else
1022#error MIPI LCD panel needs configuration parameters
1023#endif
1024 };
1025
1026 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1027 printf("SSD2828: SPI pins are not properly configured\n");
1028 return 1;
1029 }
1030 if (cfg.reset_pin == -1) {
1031 printf("SSD2828: Reset pin is not properly configured\n");
1032 return 1;
1033 }
1034
1035 return ssd2828_init(&cfg, mode);
1036}
1037#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1038
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001039static void sunxi_engines_init(void)
1040{
1041 sunxi_composer_init();
1042 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +01001043 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001044}
1045
Hans de Goede1c092202014-12-21 14:37:45 +01001046static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +01001047 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001048{
Hans de Goeded9786d22014-12-25 13:58:06 +01001049 int __maybe_unused clk_div, clk_double;
Jernej Skrabec5e023e72017-03-27 19:22:29 +02001050 struct sunxi_lcdc_reg * const lcdc =
1051 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goeded9786d22014-12-25 13:58:06 +01001052
Hans de Goede0e045212014-12-21 14:49:34 +01001053 switch (sunxi_display.monitor) {
1054 case sunxi_monitor_none:
1055 break;
1056 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001057 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001058#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001059 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001060 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001061 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1062 sunxi_composer_enable();
Jernej Skrabec5e023e72017-03-27 19:22:29 +02001063 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede0e045212014-12-21 14:49:34 +01001064 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001065#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001066 break;
1067 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001068 sunxi_lcdc_panel_enable();
Hans de Goedec1cfd512015-08-08 16:13:53 +02001069 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1070 /*
1071 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goede6944aff2015-10-03 15:18:33 +02001072 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goedec1cfd512015-08-08 16:13:53 +02001073 * to avoid turning this on when using hdmi output.
1074 */
Hans de Goede6944aff2015-10-03 15:18:33 +02001075 axp_set_eldo(3, 1800);
Hans de Goedec1cfd512015-08-08 16:13:53 +02001076 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1077 ANX9804_DATA_RATE_1620M,
1078 sunxi_display.depth);
1079 }
Hans de Goede27515b22015-01-20 09:23:36 +01001080 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1081 mdelay(50); /* Wait for lcd controller power on */
1082 hitachi_tx18d42vm_init();
1083 }
Hans de Goedeaad2ac22015-02-16 17:49:47 +01001084 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1085 unsigned int orig_i2c_bus = i2c_get_bus_num();
1086 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1087 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1088 i2c_set_bus_num(orig_i2c_bus);
1089 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001090 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001091 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede2dae8002014-12-21 16:28:32 +01001092 sunxi_composer_enable();
Jernej Skrabec5e023e72017-03-27 19:22:29 +02001093 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001094#ifdef CONFIG_VIDEO_LCD_SSD2828
1095 sunxi_ssd2828_init(mode);
1096#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001097 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001098 break;
1099 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001100#ifdef CONFIG_VIDEO_VGA
1101 sunxi_composer_mode_set(mode, address);
1102 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goede39920c82015-08-03 19:20:26 +02001103 sunxi_tvencoder_mode_set();
Hans de Goeded9786d22014-12-25 13:58:06 +01001104 sunxi_composer_enable();
Jernej Skrabec5e023e72017-03-27 19:22:29 +02001105 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede39920c82015-08-03 19:20:26 +02001106 sunxi_tvencoder_enable();
Hans de Goeded9786d22014-12-25 13:58:06 +01001107#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001108 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001109 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001110 sunxi_composer_enable();
Jernej Skrabec5e023e72017-03-27 19:22:29 +02001111 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001112 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001113#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001114 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001115 case sunxi_monitor_composite_pal:
1116 case sunxi_monitor_composite_ntsc:
1117 case sunxi_monitor_composite_pal_m:
1118 case sunxi_monitor_composite_pal_nc:
1119#ifdef CONFIG_VIDEO_COMPOSITE
1120 sunxi_composer_mode_set(mode, address);
1121 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1122 sunxi_tvencoder_mode_set();
1123 sunxi_composer_enable();
Jernej Skrabec5e023e72017-03-27 19:22:29 +02001124 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede39920c82015-08-03 19:20:26 +02001125 sunxi_tvencoder_enable();
1126#endif
1127 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001128 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001129}
1130
Hans de Goede1c092202014-12-21 14:37:45 +01001131static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1132{
1133 switch (monitor) {
Hans de Goede39920c82015-08-03 19:20:26 +02001134 case sunxi_monitor_none: return "none";
1135 case sunxi_monitor_dvi: return "dvi";
1136 case sunxi_monitor_hdmi: return "hdmi";
1137 case sunxi_monitor_lcd: return "lcd";
1138 case sunxi_monitor_vga: return "vga";
1139 case sunxi_monitor_composite_pal: return "composite-pal";
1140 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1141 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1142 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goede1c092202014-12-21 14:37:45 +01001143 }
1144 return NULL; /* never reached */
1145}
1146
Hans de Goede5633a292015-02-02 17:13:29 +01001147ulong board_get_usable_ram_top(ulong total_size)
1148{
1149 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1150}
1151
Hans de Goedebf689342015-08-03 23:01:38 +02001152static bool sunxi_has_hdmi(void)
1153{
1154#ifdef CONFIG_VIDEO_HDMI
1155 return true;
1156#else
1157 return false;
1158#endif
1159}
1160
1161static bool sunxi_has_lcd(void)
1162{
1163 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1164
1165 return lcd_mode[0] != 0;
1166}
1167
1168static bool sunxi_has_vga(void)
1169{
1170#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1171 return true;
1172#else
1173 return false;
1174#endif
1175}
1176
Hans de Goede39920c82015-08-03 19:20:26 +02001177static bool sunxi_has_composite(void)
1178{
1179#ifdef CONFIG_VIDEO_COMPOSITE
1180 return true;
1181#else
1182 return false;
1183#endif
1184}
1185
Hans de Goedebf689342015-08-03 23:01:38 +02001186static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1187{
1188 if (allow_hdmi && sunxi_has_hdmi())
1189 return sunxi_monitor_dvi;
1190 else if (sunxi_has_lcd())
1191 return sunxi_monitor_lcd;
1192 else if (sunxi_has_vga())
1193 return sunxi_monitor_vga;
Hans de Goede39920c82015-08-03 19:20:26 +02001194 else if (sunxi_has_composite())
1195 return sunxi_monitor_composite_pal;
Hans de Goedebf689342015-08-03 23:01:38 +02001196 else
1197 return sunxi_monitor_none;
1198}
1199
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001200void *video_hw_init(void)
1201{
1202 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001203 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001204 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001205 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001206#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001207 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001208#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001209 int i, overscan_offset, overscan_x, overscan_y;
1210 unsigned int fb_dma_addr;
Hans de Goede1c092202014-12-21 14:37:45 +01001211 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001212 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001213
1214 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1215
Hans de Goede2dae8002014-12-21 16:28:32 +01001216 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1217 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001218#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001219 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001220 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001221 edid = video_get_option_int(options, "edid", 1);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001222#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001223 overscan_x = video_get_option_int(options, "overscan_x", -1);
1224 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedebf689342015-08-03 23:01:38 +02001225 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goede1c092202014-12-21 14:37:45 +01001226 video_get_option_string(options, "monitor", mon, sizeof(mon),
1227 sunxi_get_mon_desc(sunxi_display.monitor));
1228 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1229 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1230 sunxi_display.monitor = i;
1231 break;
1232 }
1233 }
1234 if (i > SUNXI_MONITOR_LAST)
1235 printf("Unknown monitor: '%s', falling back to '%s'\n",
1236 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001237
Hans de Goede49d27032014-12-25 13:52:04 +01001238#ifdef CONFIG_VIDEO_HDMI
1239 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1240 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1241 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001242 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001243 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001244 if (ret) {
1245 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001246 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1247 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001248 } else if (hpd) {
1249 sunxi_hdmi_shutdown();
Hans de Goedebf689342015-08-03 23:01:38 +02001250 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede49d27032014-12-25 13:52:04 +01001251 } /* else continue with hdmi/dvi without a cable connected */
1252 }
1253#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001254
Hans de Goede49d27032014-12-25 13:52:04 +01001255 switch (sunxi_display.monitor) {
1256 case sunxi_monitor_none:
1257 return NULL;
1258 case sunxi_monitor_dvi:
1259 case sunxi_monitor_hdmi:
Hans de Goedebf689342015-08-03 23:01:38 +02001260 if (!sunxi_has_hdmi()) {
1261 printf("HDMI/DVI not supported on this board\n");
1262 sunxi_display.monitor = sunxi_monitor_none;
1263 return NULL;
Hans de Goede2dae8002014-12-21 16:28:32 +01001264 }
Hans de Goedebf689342015-08-03 23:01:38 +02001265 break;
1266 case sunxi_monitor_lcd:
1267 if (!sunxi_has_lcd()) {
1268 printf("LCD not supported on this board\n");
1269 sunxi_display.monitor = sunxi_monitor_none;
1270 return NULL;
1271 }
1272 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1273 mode = &custom;
1274 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001275 case sunxi_monitor_vga:
Hans de Goedebf689342015-08-03 23:01:38 +02001276 if (!sunxi_has_vga()) {
1277 printf("VGA not supported on this board\n");
1278 sunxi_display.monitor = sunxi_monitor_none;
1279 return NULL;
1280 }
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001281 sunxi_display.depth = 18;
1282 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001283 case sunxi_monitor_composite_pal:
1284 case sunxi_monitor_composite_ntsc:
1285 case sunxi_monitor_composite_pal_m:
1286 case sunxi_monitor_composite_pal_nc:
1287 if (!sunxi_has_composite()) {
1288 printf("Composite video not supported on this board\n");
1289 sunxi_display.monitor = sunxi_monitor_none;
1290 return NULL;
1291 }
1292 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1293 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1294 mode = &composite_video_modes[0];
1295 else
1296 mode = &composite_video_modes[1];
1297 sunxi_display.depth = 24;
1298 break;
Hans de Goede75481602014-12-19 16:05:12 +01001299 }
1300
Hans de Goede58332f82015-08-05 00:06:47 +02001301 /* Yes these defaults are quite high, overscan on composite sucks... */
1302 if (overscan_x == -1)
1303 overscan_x = sunxi_is_composite() ? 32 : 0;
1304 if (overscan_y == -1)
1305 overscan_y = sunxi_is_composite() ? 20 : 0;
1306
Hans de Goede20779ec2015-02-02 18:00:53 +01001307 sunxi_display.fb_size =
1308 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goede58332f82015-08-05 00:06:47 +02001309 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1310 /* We want to keep the fb_base for simplefb page aligned, where as
1311 * the sunxi dma engines will happily accept an unaligned address. */
1312 if (overscan_offset)
1313 sunxi_display.fb_size += 0x1000;
1314
Hans de Goede20779ec2015-02-02 18:00:53 +01001315 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1316 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1317 sunxi_display.fb_size >> 10,
1318 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1319 return NULL;
1320 }
1321
Hans de Goede58332f82015-08-05 00:06:47 +02001322 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1323 mode->xres, mode->yres,
Hans de Goedef6d9d322015-08-02 16:49:29 +02001324 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goede58332f82015-08-05 00:06:47 +02001325 sunxi_get_mon_desc(sunxi_display.monitor),
1326 overscan_x, overscan_y);
Hans de Goedef6d9d322015-08-02 16:49:29 +02001327
Hans de Goede20779ec2015-02-02 18:00:53 +01001328 gd->fb_base = gd->bd->bi_dram[0].start +
1329 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001330 sunxi_engines_init();
Hans de Goede58332f82015-08-05 00:06:47 +02001331
1332 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1333 sunxi_display.fb_addr = gd->fb_base;
1334 if (overscan_offset) {
1335 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1336 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1337 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1338 flush_cache(gd->fb_base, sunxi_display.fb_size);
1339 }
1340 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001341
1342 /*
1343 * These are the only members of this structure that are used. All the
Hans de Goede58332f82015-08-05 00:06:47 +02001344 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001345 */
Hans de Goede58332f82015-08-05 00:06:47 +02001346 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001347 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1348 graphic_device->gdfBytesPP = 4;
Hans de Goede58332f82015-08-05 00:06:47 +02001349 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1350 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1351 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001352
1353 return graphic_device;
1354}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001355
1356/*
1357 * Simplefb support.
1358 */
1359#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1360int sunxi_simplefb_setup(void *blob)
1361{
1362 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1363 int offset, ret;
Hans de Goede5633a292015-02-02 17:13:29 +01001364 u64 start, size;
Hans de Goede2dae8002014-12-21 16:28:32 +01001365 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001366
Hans de Goede7cd6f922015-01-19 08:44:07 +01001367#ifdef CONFIG_MACH_SUN4I
1368#define PIPELINE_PREFIX "de_fe0-"
1369#else
1370#define PIPELINE_PREFIX
1371#endif
1372
Hans de Goede2dae8002014-12-21 16:28:32 +01001373 switch (sunxi_display.monitor) {
1374 case sunxi_monitor_none:
1375 return 0;
1376 case sunxi_monitor_dvi:
1377 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001378 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001379 break;
1380 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001381 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001382 break;
1383 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001384#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001385 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001386#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001387 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001388#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001389 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001390 case sunxi_monitor_composite_pal:
1391 case sunxi_monitor_composite_ntsc:
1392 case sunxi_monitor_composite_pal_m:
1393 case sunxi_monitor_composite_pal_nc:
1394 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1395 break;
Hans de Goede2dae8002014-12-21 16:28:32 +01001396 }
1397
1398 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001399 offset = fdt_node_offset_by_compatible(blob, -1,
1400 "allwinner,simple-framebuffer");
1401 while (offset >= 0) {
Simon Glassb02e4042016-10-02 17:59:28 -06001402 ret = fdt_stringlist_search(blob, offset, "allwinner,pipeline",
Masahiro Yamada6e67f172016-10-17 20:43:01 +09001403 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001404 if (ret == 0)
1405 break;
1406 offset = fdt_node_offset_by_compatible(blob, offset,
1407 "allwinner,simple-framebuffer");
1408 }
1409 if (offset < 0) {
1410 eprintf("Cannot setup simplefb: node not found\n");
1411 return 0; /* Keep older kernels working */
1412 }
1413
Hans de Goede5633a292015-02-02 17:13:29 +01001414 /*
1415 * Do not report the framebuffer as free RAM to the OS, note we cannot
1416 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1417 * and e.g. Linux refuses to iomap RAM on ARM, see:
1418 * linux/arch/arm/mm/ioremap.c around line 301.
1419 */
1420 start = gd->bd->bi_dram[0].start;
Hans de Goede20779ec2015-02-02 18:00:53 +01001421 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede5633a292015-02-02 17:13:29 +01001422 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1423 if (ret) {
1424 eprintf("Cannot setup simplefb: Error reserving memory\n");
1425 return ret;
1426 }
1427
Hans de Goede58332f82015-08-05 00:06:47 +02001428 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001429 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goede58332f82015-08-05 00:06:47 +02001430 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001431 if (ret)
1432 eprintf("Cannot setup simplefb: Error setting properties\n");
1433
1434 return ret;
1435}
1436#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */