blob: 92c9d06054f7192f21dada0a98f08136391effa2 [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>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020017#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010018#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020019#include <asm/io.h>
Hans de Goeded9ee84b2015-10-03 15:18:33 +020020#include <axp_pmic.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010021#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020022#include <fdtdec.h>
23#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010024#include <i2c.h>
Hans de Goeded955f442015-08-05 00:06:47 +020025#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020026#include <video_fb.h>
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +020027#include "../videomodes.h"
28#include "../anx9804.h"
29#include "../hitachi_tx18d42vm_lcd.h"
30#include "../ssd2828.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020031
Hans de Goede2d5d3022015-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 Verhaegenb01df1e2014-08-13 07:55:06 +020040DECLARE_GLOBAL_DATA_PTR;
41
Hans de Goedea0b1b732014-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 Goedec06e00e2015-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 Goedea0b1b732014-12-21 14:37:45 +010052};
Hans de Goedec06e00e2015-08-03 19:20:26 +020053#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010054
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020055struct sunxi_display {
56 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010057 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010058 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020059 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010060 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020061} sunxi_display;
62
Hans de Goedec06e00e2015-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 Goedee9544592014-12-23 23:04:35 +010069#ifdef CONFIG_VIDEO_HDMI
70
Hans de Goedea5aa95f2014-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 Goede91593712014-12-28 09:13:21 +010087static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-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 Goede91593712014-12-28 09:13:21 +010093 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-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 Goedef07872b2015-04-06 20:33:34 +0200103#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100104 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
105#endif
Luc Verhaegenb01df1e2014-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 Goede205a30c2014-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200118
Hans de Goede205a30c2014-12-20 15:15:23 +0100119 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100120}
121
122static 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;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200128
Luc Verhaegenb01df1e2014-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 Goedef07872b2015-04-06 20:33:34 +0200132#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100133 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
134#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200135 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200136}
137
Hans de Goedea5aa95f2014-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 Goede45b8f7b2014-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 Goedea0b1b732014-12-21 14:37:45 +0100204static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100205{
206 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100207 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-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 Goede1ff6cc42014-12-20 14:31:45 +0100214 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-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 Goede45b8f7b2014-12-20 14:01:48 +0100238 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-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 Goedea5aa95f2014-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 Goedea5aa95f2014-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 Goede1ff6cc42014-12-20 14:31:45 +0100285 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100286 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-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 Goedea0b1b732014-12-21 14:37:45 +0100293 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100294 }
295
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100296 return 0;
297}
298
Hans de Goedee9544592014-12-23 23:04:35 +0100299#endif /* CONFIG_VIDEO_HDMI */
300
Hans de Goedec3cc4262015-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 Goedec06e00e2015-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 Verhaegenb01df1e2014-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 Goedec3cc4262015-01-19 08:44:07 +0100440 sunxi_frontend_init();
441
Hans de Goedef07872b2015-04-06 20:33:34 +0200442#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200447 /* Clocks on */
448 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100449#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200450 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100451#endif
Luc Verhaegenb01df1e2014-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 Goedec06e00e2015-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 Goedeccb0ed52014-12-19 13:46:33 +0100467static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-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 Goedec06e00e2015-08-03 19:20:26 +0200472 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200473
Hans de Goedec3cc4262015-01-19 08:44:07 +0100474 sunxi_frontend_mode_set(mode, address);
475
Luc Verhaegenb01df1e2014-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 Goedec3cc4262015-01-19 08:44:07 +0100480#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-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 Goedec3cc4262015-01-19 08:44:07 +0100484#else
485 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
486#endif
Luc Verhaegenb01df1e2014-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 Goede1977bbb2015-08-02 16:49:29 +0200490 if (mode->vmode == FB_VMODE_INTERLACED)
491 setbits_le32(&de_be->mode,
Hans de Goede8a195ca2015-08-06 12:08:33 +0200492#ifndef CONFIG_MACH_SUN5I
Hans de Goede1977bbb2015-08-02 16:49:29 +0200493 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goede8a195ca2015-08-06 12:08:33 +0200494#endif
Hans de Goede1977bbb2015-08-02 16:49:29 +0200495 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200504}
505
Hans de Goede4125f922014-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 Goedec3cc4262015-01-19 08:44:07 +0100511 sunxi_frontend_enable();
512
Hans de Goede4125f922014-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200517/*
518 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
519 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100520static void sunxi_lcdc_pll_set(int tcon, int dotclock,
521 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200522{
523 struct sunxi_ccm_reg * const ccm =
524 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100525 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200526 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
527 int best_double = 0;
Hans de Goede13365782015-08-08 14:08:21 +0200528 bool use_mipi_pll = false;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200529
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100530 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100531#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100532 min_m = 6;
533 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100534#endif
535#ifdef CONFIG_VIDEO_LCD_IF_LVDS
536 min_m = max_m = 7;
537#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100538 } else {
539 min_m = 1;
540 max_m = 15;
541 }
542
Luc Verhaegenb01df1e2014-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 Goedec5a3b4b2014-12-21 16:27:45 +0100548 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-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 Goede13365782015-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200588
Hans de Goede13365782015-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200603
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100604 if (tcon == 0) {
Hans de Goede13365782015-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 Goedec5a3b4b2014-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 Goedec06e00e2015-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 Goedec5a3b4b2014-12-21 16:27:45 +0100624 }
Luc Verhaegenb01df1e2014-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 Goedef07872b2015-04-06 20:33:34 +0200638#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100639 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
640#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200641 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100642#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200643
644 /* Clock on */
645 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100646#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-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 Goede797a0f52015-01-01 22:04:34 +0100650 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
651#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200652#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200653
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200654 lcdc_init(lcdc);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200655}
656
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100657static void sunxi_lcdc_panel_enable(void)
658{
Hans de Goedece9e3322015-02-16 17:26:41 +0100659 int pin, reset_pin;
Hans de Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200666 if (pin >= 0) {
Hans de Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200672 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100673 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100674 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100675 }
676
Hans de Goedece9e3322015-02-16 17:26:41 +0100677 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200678 if (reset_pin >= 0) {
Hans de Goedece9e3322015-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 Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200686 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100687 gpio_request(pin, "lcd_power");
688 gpio_direction_output(pin, 1);
689 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100690
Hans de Goede7783ab22015-04-22 17:45:59 +0200691 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100692 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200706 if (pin >= 0)
Hans de Goede7e68a1b2014-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 Goede663ae652016-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 Goede7783ab22015-04-22 17:45:59 +0200720 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100721 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100722}
723
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200724static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
725 struct display_timing *timing)
726{
727 timing->pixelclock.typ = mode->pixclock_khz * 1000;
728
729 timing->hactive.typ = mode->xres;
730 timing->hfront_porch.typ = mode->right_margin;
731 timing->hback_porch.typ = mode->left_margin;
732 timing->hsync_len.typ = mode->hsync_len;
733
734 timing->vactive.typ = mode->yres;
735 timing->vfront_porch.typ = mode->lower_margin;
736 timing->vback_porch.typ = mode->upper_margin;
737 timing->vsync_len.typ = mode->vsync_len;
738
739 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
740 timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
741 else
742 timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
743 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
744 timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
745 else
746 timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
747 if (mode->vmode == FB_VMODE_INTERLACED)
748 timing->flags |= DISPLAY_FLAGS_INTERLACED;
749}
750
Hans de Goede18366f72015-01-25 15:33:07 +0100751static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
752 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100753{
754 struct sunxi_lcdc_reg * const lcdc =
755 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200756 int clk_div, clk_double, pin;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200757 struct display_timing timing;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100758
Lawrence Yuf721f962016-03-04 09:08:56 -0800759#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
760 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
761#else
Hans de Goede91f1b822015-08-08 16:13:53 +0200762 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yuf721f962016-03-04 09:08:56 -0800763#endif
Hans de Goede797a0f52015-01-01 22:04:34 +0100764#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100765 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100766#endif
767#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100768 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100769#endif
Hans de Goede91f1b822015-08-08 16:13:53 +0200770#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
771 sunxi_gpio_set_drv(pin, 3);
772#endif
773 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100774
775 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
776
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200777 sunxi_ctfb_mode_to_display_timing(mode, &timing);
778 lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200779 sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100780}
781
Hans de Goedec06e00e2015-08-03 19:20:26 +0200782#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100783static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100784 int *clk_div, int *clk_double,
785 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200786{
787 struct sunxi_lcdc_reg * const lcdc =
788 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200789 struct display_timing timing;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200790
Jernej Skrabecccfbe5f2017-03-27 19:22:30 +0200791 sunxi_ctfb_mode_to_display_timing(mode, &timing);
792 lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +0200793 sunxi_is_composite());
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200794
Hans de Goedec3d15042014-12-27 15:19:23 +0100795 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100796 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
797 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100798 }
Hans de Goede8a195ca2015-08-06 12:08:33 +0200799
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100800 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200801}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200802#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100803
804#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100805
Hans de Goedea2017e82014-12-20 13:38:06 +0100806static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
807{
808 struct sunxi_hdmi_reg * const hdmi =
809 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
810 u8 checksum = 0;
811 u8 avi_info_frame[17] = {
812 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00
815 };
816 u8 vendor_info_frame[19] = {
817 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x00, 0x00, 0x00
820 };
821 int i;
822
823 if (mode->pixclock_khz <= 27000)
824 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
825 else
826 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
827
828 if (mode->xres * 100 / mode->yres < 156)
829 avi_info_frame[5] |= 0x18; /* 4 : 3 */
830 else
831 avi_info_frame[5] |= 0x28; /* 16 : 9 */
832
833 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
834 checksum += avi_info_frame[i];
835
836 avi_info_frame[3] = 0x100 - checksum;
837
838 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
839 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
840
841 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
842 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
843
844 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
845 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
846
847 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
848 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
849
850 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
851}
852
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100853static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100854 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200855{
856 struct sunxi_hdmi_reg * const hdmi =
857 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
858 int x, y;
859
860 /* Write clear interrupt status bits */
861 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
862
Hans de Goedea0b1b732014-12-21 14:37:45 +0100863 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100864 sunxi_hdmi_setup_info_frames(mode);
865
Hans de Goede95576692014-12-20 13:51:16 +0100866 /* Set input sync enable */
867 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
868
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200869 /* Init various registers, select pll3 as clock source */
870 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
871 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
872 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
873 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
874 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
875
876 /* Setup clk div and doubler */
877 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
878 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
879 if (!clk_double)
880 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
881
882 /* Setup timing registers */
883 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
884 &hdmi->video_size);
885
886 x = mode->hsync_len + mode->left_margin;
887 y = mode->vsync_len + mode->upper_margin;
888 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
889
890 x = mode->right_margin;
891 y = mode->lower_margin;
892 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
893
894 x = mode->hsync_len;
895 y = mode->vsync_len;
896 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
897
898 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
899 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
900
901 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
902 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
903}
904
Hans de Goede4125f922014-12-21 14:49:34 +0100905static void sunxi_hdmi_enable(void)
906{
907 struct sunxi_hdmi_reg * const hdmi =
908 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
909
910 udelay(100);
911 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
912}
913
Hans de Goedee9544592014-12-23 23:04:35 +0100914#endif /* CONFIG_VIDEO_HDMI */
915
Hans de Goedec06e00e2015-08-03 19:20:26 +0200916#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100917
Hans de Goedec06e00e2015-08-03 19:20:26 +0200918static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100919{
920 struct sunxi_ccm_reg * const ccm =
921 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
922 struct sunxi_tve_reg * const tve =
923 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
924
Hans de Goede8a195ca2015-08-06 12:08:33 +0200925 /* Reset off */
926 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goede260f5202014-12-25 13:58:06 +0100927 /* Clock on */
928 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
929
Hans de Goedec06e00e2015-08-03 19:20:26 +0200930 switch (sunxi_display.monitor) {
931 case sunxi_monitor_vga:
932 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
933 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
934 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
935 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
936 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
937 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
938 break;
939 case sunxi_monitor_composite_pal_nc:
940 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
941 /* Fall through */
942 case sunxi_monitor_composite_pal:
943 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
944 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
945 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
946 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
947 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
948 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
949 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
950 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
951 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
952 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
953 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
954 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
955 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
956 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
957 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
958 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
959 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
960 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
961 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
962 break;
963 case sunxi_monitor_composite_pal_m:
964 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
965 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
966 /* Fall through */
967 case sunxi_monitor_composite_ntsc:
968 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
969 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
970 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
971 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
972 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
973 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
974 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
975 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
976 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
977 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
978 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
979 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
980 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
981 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
982 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
983 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
984 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
985 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
986 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
987 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
988 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
989 break;
990 case sunxi_monitor_none:
991 case sunxi_monitor_dvi:
992 case sunxi_monitor_hdmi:
993 case sunxi_monitor_lcd:
994 break;
995 }
Hans de Goede260f5202014-12-25 13:58:06 +0100996}
997
Hans de Goedec06e00e2015-08-03 19:20:26 +0200998static void sunxi_tvencoder_enable(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100999{
1000 struct sunxi_tve_reg * const tve =
1001 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1002
1003 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1004}
1005
Hans de Goedec06e00e2015-08-03 19:20:26 +02001006#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +01001007
Hans de Goede115e4b42014-12-23 18:39:52 +01001008static void sunxi_drc_init(void)
1009{
Hans de Goedef07872b2015-04-06 20:33:34 +02001010#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +01001011 struct sunxi_ccm_reg * const ccm =
1012 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1013
1014 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +05301015#ifdef CONFIG_MACH_SUN8I_A33
1016 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1017#endif
Hans de Goede115e4b42014-12-23 18:39:52 +01001018 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1019 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1020#endif
1021}
1022
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001023#ifdef CONFIG_VIDEO_VGA_VIA_LCD
1024static void sunxi_vga_external_dac_enable(void)
1025{
1026 int pin;
1027
1028 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +02001029 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001030 gpio_request(pin, "vga_enable");
1031 gpio_direction_output(pin, 1);
1032 }
1033}
1034#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1035
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001036#ifdef CONFIG_VIDEO_LCD_SSD2828
1037static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1038{
1039 struct ssd2828_config cfg = {
1040 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1041 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1042 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1043 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1044 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1045 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1046 .ssd2828_color_depth = 24,
1047#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1048 .mipi_dsi_number_of_data_lanes = 4,
1049 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1050 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1051 .mipi_dsi_delay_after_set_display_on_ms = 200
1052#else
1053#error MIPI LCD panel needs configuration parameters
1054#endif
1055 };
1056
1057 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1058 printf("SSD2828: SPI pins are not properly configured\n");
1059 return 1;
1060 }
1061 if (cfg.reset_pin == -1) {
1062 printf("SSD2828: Reset pin is not properly configured\n");
1063 return 1;
1064 }
1065
1066 return ssd2828_init(&cfg, mode);
1067}
1068#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1069
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001070static void sunxi_engines_init(void)
1071{
1072 sunxi_composer_init();
1073 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +01001074 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001075}
1076
Hans de Goedea0b1b732014-12-21 14:37:45 +01001077static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +01001078 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001079{
Hans de Goede260f5202014-12-25 13:58:06 +01001080 int __maybe_unused clk_div, clk_double;
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001081 struct sunxi_lcdc_reg * const lcdc =
1082 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goede260f5202014-12-25 13:58:06 +01001083
Hans de Goede4125f922014-12-21 14:49:34 +01001084 switch (sunxi_display.monitor) {
1085 case sunxi_monitor_none:
1086 break;
1087 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001088 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001089#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001090 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001091 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001092 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1093 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001094 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goede4125f922014-12-21 14:49:34 +01001095 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001096#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001097 break;
1098 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001099 sunxi_lcdc_panel_enable();
Hans de Goede91f1b822015-08-08 16:13:53 +02001100 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1101 /*
1102 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goeded9ee84b2015-10-03 15:18:33 +02001103 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goede91f1b822015-08-08 16:13:53 +02001104 * to avoid turning this on when using hdmi output.
1105 */
Hans de Goeded9ee84b2015-10-03 15:18:33 +02001106 axp_set_eldo(3, 1800);
Hans de Goede91f1b822015-08-08 16:13:53 +02001107 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1108 ANX9804_DATA_RATE_1620M,
1109 sunxi_display.depth);
1110 }
Hans de Goede743fb9552015-01-20 09:23:36 +01001111 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1112 mdelay(50); /* Wait for lcd controller power on */
1113 hitachi_tx18d42vm_init();
1114 }
Hans de Goede613dade2015-02-16 17:49:47 +01001115 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1116 unsigned int orig_i2c_bus = i2c_get_bus_num();
1117 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1118 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1119 i2c_set_bus_num(orig_i2c_bus);
1120 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001121 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001122 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001123 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001124 lcdc_enable(lcdc, sunxi_display.depth);
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001125#ifdef CONFIG_VIDEO_LCD_SSD2828
1126 sunxi_ssd2828_init(mode);
1127#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001128 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001129 break;
1130 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001131#ifdef CONFIG_VIDEO_VGA
1132 sunxi_composer_mode_set(mode, address);
1133 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001134 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +01001135 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001136 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001137 sunxi_tvencoder_enable();
Hans de Goede260f5202014-12-25 13:58:06 +01001138#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001139 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001140 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001141 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001142 lcdc_enable(lcdc, sunxi_display.depth);
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001143 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001144#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001145 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001146 case sunxi_monitor_composite_pal:
1147 case sunxi_monitor_composite_ntsc:
1148 case sunxi_monitor_composite_pal_m:
1149 case sunxi_monitor_composite_pal_nc:
1150#ifdef CONFIG_VIDEO_COMPOSITE
1151 sunxi_composer_mode_set(mode, address);
1152 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1153 sunxi_tvencoder_mode_set();
1154 sunxi_composer_enable();
Jernej Skrabec2e0a1f32017-03-27 19:22:29 +02001155 lcdc_enable(lcdc, sunxi_display.depth);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001156 sunxi_tvencoder_enable();
1157#endif
1158 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001159 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001160}
1161
Hans de Goedea0b1b732014-12-21 14:37:45 +01001162static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1163{
1164 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001165 case sunxi_monitor_none: return "none";
1166 case sunxi_monitor_dvi: return "dvi";
1167 case sunxi_monitor_hdmi: return "hdmi";
1168 case sunxi_monitor_lcd: return "lcd";
1169 case sunxi_monitor_vga: return "vga";
1170 case sunxi_monitor_composite_pal: return "composite-pal";
1171 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1172 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1173 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001174 }
1175 return NULL; /* never reached */
1176}
1177
Hans de Goede6c912862015-02-02 17:13:29 +01001178ulong board_get_usable_ram_top(ulong total_size)
1179{
1180 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1181}
1182
Hans de Goedea2bba492015-08-03 23:01:38 +02001183static bool sunxi_has_hdmi(void)
1184{
1185#ifdef CONFIG_VIDEO_HDMI
1186 return true;
1187#else
1188 return false;
1189#endif
1190}
1191
1192static bool sunxi_has_lcd(void)
1193{
1194 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1195
1196 return lcd_mode[0] != 0;
1197}
1198
1199static bool sunxi_has_vga(void)
1200{
1201#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1202 return true;
1203#else
1204 return false;
1205#endif
1206}
1207
Hans de Goedec06e00e2015-08-03 19:20:26 +02001208static bool sunxi_has_composite(void)
1209{
1210#ifdef CONFIG_VIDEO_COMPOSITE
1211 return true;
1212#else
1213 return false;
1214#endif
1215}
1216
Hans de Goedea2bba492015-08-03 23:01:38 +02001217static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1218{
1219 if (allow_hdmi && sunxi_has_hdmi())
1220 return sunxi_monitor_dvi;
1221 else if (sunxi_has_lcd())
1222 return sunxi_monitor_lcd;
1223 else if (sunxi_has_vga())
1224 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001225 else if (sunxi_has_composite())
1226 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001227 else
1228 return sunxi_monitor_none;
1229}
1230
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001231void *video_hw_init(void)
1232{
1233 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001234 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001235 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001236 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001237#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001238 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001239#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001240 int i, overscan_offset, overscan_x, overscan_y;
1241 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001242 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001243 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001244
1245 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1246
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001247 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1248 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001249#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001250 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001251 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001252 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001253#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001254 overscan_x = video_get_option_int(options, "overscan_x", -1);
1255 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001256 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001257 video_get_option_string(options, "monitor", mon, sizeof(mon),
1258 sunxi_get_mon_desc(sunxi_display.monitor));
1259 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1260 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1261 sunxi_display.monitor = i;
1262 break;
1263 }
1264 }
1265 if (i > SUNXI_MONITOR_LAST)
1266 printf("Unknown monitor: '%s', falling back to '%s'\n",
1267 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001268
Hans de Goede7977ec22014-12-25 13:52:04 +01001269#ifdef CONFIG_VIDEO_HDMI
1270 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1271 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1272 sunxi_display.monitor == sunxi_monitor_hdmi) {
1273 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001274 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001275 if (ret) {
1276 printf("HDMI connected: ");
1277 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1278 mode = &custom;
1279 } else if (hpd) {
1280 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001281 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001282 } /* else continue with hdmi/dvi without a cable connected */
1283 }
1284#endif
1285
Hans de Goede4125f922014-12-21 14:49:34 +01001286 switch (sunxi_display.monitor) {
1287 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001288 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001289 case sunxi_monitor_dvi:
1290 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001291 if (!sunxi_has_hdmi()) {
1292 printf("HDMI/DVI not supported on this board\n");
1293 sunxi_display.monitor = sunxi_monitor_none;
1294 return NULL;
1295 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001296 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001297 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001298 if (!sunxi_has_lcd()) {
1299 printf("LCD not supported on this board\n");
1300 sunxi_display.monitor = sunxi_monitor_none;
1301 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001302 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001303 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1304 mode = &custom;
1305 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001306 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001307 if (!sunxi_has_vga()) {
1308 printf("VGA not supported on this board\n");
1309 sunxi_display.monitor = sunxi_monitor_none;
1310 return NULL;
1311 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001312 sunxi_display.depth = 18;
1313 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001314 case sunxi_monitor_composite_pal:
1315 case sunxi_monitor_composite_ntsc:
1316 case sunxi_monitor_composite_pal_m:
1317 case sunxi_monitor_composite_pal_nc:
1318 if (!sunxi_has_composite()) {
1319 printf("Composite video not supported on this board\n");
1320 sunxi_display.monitor = sunxi_monitor_none;
1321 return NULL;
1322 }
1323 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1324 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1325 mode = &composite_video_modes[0];
1326 else
1327 mode = &composite_video_modes[1];
1328 sunxi_display.depth = 24;
1329 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001330 }
1331
Hans de Goeded955f442015-08-05 00:06:47 +02001332 /* Yes these defaults are quite high, overscan on composite sucks... */
1333 if (overscan_x == -1)
1334 overscan_x = sunxi_is_composite() ? 32 : 0;
1335 if (overscan_y == -1)
1336 overscan_y = sunxi_is_composite() ? 20 : 0;
1337
Hans de Goede18799252015-02-02 18:00:53 +01001338 sunxi_display.fb_size =
1339 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001340 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1341 /* We want to keep the fb_base for simplefb page aligned, where as
1342 * the sunxi dma engines will happily accept an unaligned address. */
1343 if (overscan_offset)
1344 sunxi_display.fb_size += 0x1000;
1345
Hans de Goede18799252015-02-02 18:00:53 +01001346 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1347 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1348 sunxi_display.fb_size >> 10,
1349 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1350 return NULL;
1351 }
1352
Hans de Goeded955f442015-08-05 00:06:47 +02001353 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1354 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001355 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001356 sunxi_get_mon_desc(sunxi_display.monitor),
1357 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001358
Hans de Goede18799252015-02-02 18:00:53 +01001359 gd->fb_base = gd->bd->bi_dram[0].start +
1360 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001361 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001362
1363 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1364 sunxi_display.fb_addr = gd->fb_base;
1365 if (overscan_offset) {
1366 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1367 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1368 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1369 flush_cache(gd->fb_base, sunxi_display.fb_size);
1370 }
1371 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001372
1373 /*
1374 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001375 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001376 */
Hans de Goeded955f442015-08-05 00:06:47 +02001377 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001378 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1379 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001380 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1381 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1382 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001383
1384 return graphic_device;
1385}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001386
1387/*
1388 * Simplefb support.
1389 */
1390#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1391int sunxi_simplefb_setup(void *blob)
1392{
1393 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1394 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001395 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001396 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001397
Hans de Goedec3cc4262015-01-19 08:44:07 +01001398#ifdef CONFIG_MACH_SUN4I
1399#define PIPELINE_PREFIX "de_fe0-"
1400#else
1401#define PIPELINE_PREFIX
1402#endif
1403
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001404 switch (sunxi_display.monitor) {
1405 case sunxi_monitor_none:
1406 return 0;
1407 case sunxi_monitor_dvi:
1408 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001409 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001410 break;
1411 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001412 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001413 break;
1414 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001415#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001416 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001417#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001418 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001419#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001420 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001421 case sunxi_monitor_composite_pal:
1422 case sunxi_monitor_composite_ntsc:
1423 case sunxi_monitor_composite_pal_m:
1424 case sunxi_monitor_composite_pal_nc:
1425 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1426 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001427 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001428
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001429 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001430 offset = fdt_node_offset_by_compatible(blob, -1,
1431 "allwinner,simple-framebuffer");
1432 while (offset >= 0) {
Simon Glassb0ea7402016-10-02 17:59:28 -06001433 ret = fdt_stringlist_search(blob, offset, "allwinner,pipeline",
Masahiro Yamadadb090a22016-10-17 20:43:01 +09001434 pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001435 if (ret == 0)
1436 break;
1437 offset = fdt_node_offset_by_compatible(blob, offset,
1438 "allwinner,simple-framebuffer");
1439 }
1440 if (offset < 0) {
1441 eprintf("Cannot setup simplefb: node not found\n");
1442 return 0; /* Keep older kernels working */
1443 }
1444
Hans de Goede6c912862015-02-02 17:13:29 +01001445 /*
1446 * Do not report the framebuffer as free RAM to the OS, note we cannot
1447 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1448 * and e.g. Linux refuses to iomap RAM on ARM, see:
1449 * linux/arch/arm/mm/ioremap.c around line 301.
1450 */
1451 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001452 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001453 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1454 if (ret) {
1455 eprintf("Cannot setup simplefb: Error reserving memory\n");
1456 return ret;
1457 }
1458
Hans de Goeded955f442015-08-05 00:06:47 +02001459 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001460 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001461 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001462 if (ret)
1463 eprintf("Cannot setup simplefb: Error setting properties\n");
1464
1465 return ret;
1466}
1467#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */