blob: 18681850587c61e9bddb638c8b38db520a2383c7 [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>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020015#include <asm/global_data.h>
Hans de Goede2dae8002014-12-21 16:28:32 +010016#include <asm/gpio.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020017#include <asm/io.h>
Hans de Goede75481602014-12-19 16:05:12 +010018#include <errno.h>
Luc Verhaegen2d7a0842014-08-13 07:55:07 +020019#include <fdtdec.h>
20#include <fdt_support.h>
Hans de Goedeaad2ac22015-02-16 17:49:47 +010021#include <i2c.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020022#include <video_fb.h>
Hans de Goedebe8ec632014-12-19 13:46:33 +010023#include "videomodes.h"
Hans de Goede27515b22015-01-20 09:23:36 +010024#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashka97ece832015-01-19 05:23:33 +020025#include "ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020026
Hans de Goedea7403ae2015-01-22 21:02:42 +010027#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
28#define PWM_ON 0
29#define PWM_OFF 1
30#else
31#define PWM_ON 1
32#define PWM_OFF 0
33#endif
34
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020035DECLARE_GLOBAL_DATA_PTR;
36
Hans de Goede1c092202014-12-21 14:37:45 +010037enum sunxi_monitor {
38 sunxi_monitor_none,
39 sunxi_monitor_dvi,
40 sunxi_monitor_hdmi,
41 sunxi_monitor_lcd,
42 sunxi_monitor_vga,
Hans de Goede39920c82015-08-03 19:20:26 +020043 sunxi_monitor_composite_pal,
44 sunxi_monitor_composite_ntsc,
45 sunxi_monitor_composite_pal_m,
46 sunxi_monitor_composite_pal_nc,
Hans de Goede1c092202014-12-21 14:37:45 +010047};
Hans de Goede39920c82015-08-03 19:20:26 +020048#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goede1c092202014-12-21 14:37:45 +010049
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020050struct sunxi_display {
51 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010052 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010053 unsigned int depth;
Hans de Goede20779ec2015-02-02 18:00:53 +010054 unsigned int fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020055} sunxi_display;
56
Hans de Goede39920c82015-08-03 19:20:26 +020057const struct ctfb_res_modes composite_video_modes[2] = {
58 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
59 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
60 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
61};
62
Hans de Goede2fbf0912014-12-23 23:04:35 +010063#ifdef CONFIG_VIDEO_HDMI
64
Hans de Goede75481602014-12-19 16:05:12 +010065/*
66 * Wait up to 200ms for value to be set in given part of reg.
67 */
68static int await_completion(u32 *reg, u32 mask, u32 val)
69{
70 unsigned long tmo = timer_get_us() + 200000;
71
72 while ((readl(reg) & mask) != val) {
73 if (timer_get_us() > tmo) {
74 printf("DDC: timeout reading EDID\n");
75 return -ETIME;
76 }
77 }
78 return 0;
79}
80
Hans de Goede7fad8a92014-12-28 09:13:21 +010081static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020082{
83 struct sunxi_ccm_reg * const ccm =
84 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
85 struct sunxi_hdmi_reg * const hdmi =
86 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede7fad8a92014-12-28 09:13:21 +010087 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020088
89 /* Set pll3 to 300MHz */
90 clock_set_pll3(300000000);
91
92 /* Set hdmi parent to pll3 */
93 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
94 CCM_HDMI_CTRL_PLL3);
95
96 /* Set ahb gating to pass */
Hans de Goede44d8ae52015-04-06 20:33:34 +020097#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +010098 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
99#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200100 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
101
102 /* Clock on */
103 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
104
105 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
106 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
107
Hans de Goede40f1b872014-12-20 15:15:23 +0100108 while (timer_get_us() < tmo) {
109 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
110 return 1;
111 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200112
Hans de Goede40f1b872014-12-20 15:15:23 +0100113 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100114}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200115
Hans de Goede518cef22014-12-19 15:13:57 +0100116static void sunxi_hdmi_shutdown(void)
117{
118 struct sunxi_ccm_reg * const ccm =
119 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
120 struct sunxi_hdmi_reg * const hdmi =
121 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
122
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200123 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
124 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
125 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goede44d8ae52015-04-06 20:33:34 +0200126#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100127 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
128#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200129 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200130}
131
Hans de Goede75481602014-12-19 16:05:12 +0100132static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
133{
134 struct sunxi_hdmi_reg * const hdmi =
135 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
136
137 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
138 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
139 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
140 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
141 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
142#ifndef CONFIG_MACH_SUN6I
143 writel(n, &hdmi->ddc_byte_count);
144 writel(cmnd, &hdmi->ddc_cmnd);
145#else
146 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
147#endif
148 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
149
150 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
151}
152
153static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
154{
155 struct sunxi_hdmi_reg * const hdmi =
156 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
157 int i, n;
158
159 while (count > 0) {
160 if (count > 16)
161 n = 16;
162 else
163 n = count;
164
165 if (sunxi_hdmi_ddc_do_command(
166 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
167 offset, n))
168 return -ETIME;
169
170 for (i = 0; i < n; i++)
171 *buf++ = readb(&hdmi->ddc_fifo_data);
172
173 offset += n;
174 count -= n;
175 }
176
177 return 0;
178}
179
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100180static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
181{
182 int r, retries = 2;
183
184 do {
185 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
186 if (r)
187 continue;
188 r = edid_check_checksum(buf);
189 if (r) {
190 printf("EDID block %d: checksum error%s\n",
191 block, retries ? ", retrying" : "");
192 }
193 } while (r && retries--);
194
195 return r;
196}
197
Hans de Goede1c092202014-12-21 14:37:45 +0100198static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100199{
200 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100201 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-12-19 16:05:12 +0100202 struct edid_detailed_timing *t =
203 (struct edid_detailed_timing *)edid1.monitor_details.timing;
204 struct sunxi_hdmi_reg * const hdmi =
205 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
206 struct sunxi_ccm_reg * const ccm =
207 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedef3000682014-12-20 14:31:45 +0100208 int i, r, ext_blocks = 0;
Hans de Goede75481602014-12-19 16:05:12 +0100209
210 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
211 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
212 &hdmi->pad_ctrl1);
213 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
214 &hdmi->pll_ctrl);
215 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
216
217 /* Reset i2c controller */
218 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
219 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
220 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
221 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
222 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
223 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
224 return -EIO;
225
226 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
227#ifndef CONFIG_MACH_SUN6I
228 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
229 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
230#endif
231
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100232 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-12-20 14:31:45 +0100233 if (r == 0) {
234 r = edid_check_info(&edid1);
235 if (r) {
236 printf("EDID: invalid EDID data\n");
237 r = -EINVAL;
238 }
239 }
240 if (r == 0) {
241 ext_blocks = edid1.extension_flag;
242 if (ext_blocks > 4)
243 ext_blocks = 4;
244 for (i = 0; i < ext_blocks; i++) {
245 if (sunxi_hdmi_edid_get_block(1 + i,
246 (u8 *)&cea681[i]) != 0) {
247 ext_blocks = i;
248 break;
249 }
250 }
251 }
Hans de Goede75481602014-12-19 16:05:12 +0100252
253 /* Disable DDC engine, no longer needed */
254 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
255 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
256
257 if (r)
258 return r;
259
Hans de Goede75481602014-12-19 16:05:12 +0100260 /* We want version 1.3 or 1.2 with detailed timing info */
261 if (edid1.version != 1 || (edid1.revision < 3 &&
262 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
263 printf("EDID: unsupported version %d.%d\n",
264 edid1.version, edid1.revision);
265 return -EINVAL;
266 }
267
268 /* Take the first usable detailed timing */
269 for (i = 0; i < 4; i++, t++) {
270 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
271 if (r == 0)
272 break;
273 }
274 if (i == 4) {
275 printf("EDID: no usable detailed timing found\n");
276 return -ENOENT;
277 }
278
Hans de Goedef3000682014-12-20 14:31:45 +0100279 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100280 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-12-20 14:31:45 +0100281 for (i = 0; i < ext_blocks; i++) {
282 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
283 cea681[i].revision < 2)
284 continue;
285
286 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goede1c092202014-12-21 14:37:45 +0100287 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100288 }
289
Hans de Goede75481602014-12-19 16:05:12 +0100290 return 0;
291}
292
Hans de Goede2fbf0912014-12-23 23:04:35 +0100293#endif /* CONFIG_VIDEO_HDMI */
294
Hans de Goede7cd6f922015-01-19 08:44:07 +0100295#ifdef CONFIG_MACH_SUN4I
296/*
297 * Testing has shown that on sun4i the display backend engine does not have
298 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
299 * fifo underruns. So on sun4i we use the display frontend engine to do the
300 * dma from memory, as the frontend does have deep enough fifo-s.
301 */
302
303static const u32 sun4i_vert_coef[32] = {
304 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
305 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
306 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
307 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
308 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
309 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
310 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
311 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
312};
313
314static const u32 sun4i_horz_coef[64] = {
315 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
316 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
317 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
318 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
319 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
320 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
321 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
322 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
323 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
324 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
325 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
326 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
327 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
328 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
329 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
330 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
331};
332
333static void sunxi_frontend_init(void)
334{
335 struct sunxi_ccm_reg * const ccm =
336 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
337 struct sunxi_de_fe_reg * const de_fe =
338 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
339 int i;
340
341 /* Clocks on */
342 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
343 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
344 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
345
346 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
347
348 for (i = 0; i < 32; i++) {
349 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
350 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
351 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
352 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
353 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
354 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
355 }
356
357 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
358}
359
360static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
361 unsigned int address)
362{
363 struct sunxi_de_fe_reg * const de_fe =
364 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
365
366 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
367 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
368 writel(mode->xres * 4, &de_fe->ch0_stride);
369 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
370 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
371
372 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
373 &de_fe->ch0_insize);
374 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
375 &de_fe->ch0_outsize);
376 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
377 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
378
379 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
380 &de_fe->ch1_insize);
381 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
382 &de_fe->ch1_outsize);
383 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
384 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
385
386 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
387}
388
389static void sunxi_frontend_enable(void)
390{
391 struct sunxi_de_fe_reg * const de_fe =
392 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
393
394 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
395}
396#else
397static void sunxi_frontend_init(void) {}
398static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
399 unsigned int address) {}
400static void sunxi_frontend_enable(void) {}
401#endif
402
Hans de Goede39920c82015-08-03 19:20:26 +0200403static bool sunxi_is_composite(void)
404{
405 switch (sunxi_display.monitor) {
406 case sunxi_monitor_none:
407 case sunxi_monitor_dvi:
408 case sunxi_monitor_hdmi:
409 case sunxi_monitor_lcd:
410 case sunxi_monitor_vga:
411 return false;
412 case sunxi_monitor_composite_pal:
413 case sunxi_monitor_composite_ntsc:
414 case sunxi_monitor_composite_pal_m:
415 case sunxi_monitor_composite_pal_nc:
416 return true;
417 }
418
419 return false; /* Never reached */
420}
421
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200422/*
423 * This is the entity that mixes and matches the different layers and inputs.
424 * Allwinner calls it the back-end, but i like composer better.
425 */
426static void sunxi_composer_init(void)
427{
428 struct sunxi_ccm_reg * const ccm =
429 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
430 struct sunxi_de_be_reg * const de_be =
431 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
432 int i;
433
Hans de Goede7cd6f922015-01-19 08:44:07 +0100434 sunxi_frontend_init();
435
Hans de Goede44d8ae52015-04-06 20:33:34 +0200436#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100437 /* Reset off */
438 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
439#endif
440
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200441 /* Clocks on */
442 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100443#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200444 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100445#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200446 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
447
448 /* Engine bug, clear registers after reset */
449 for (i = 0x0800; i < 0x1000; i += 4)
450 writel(0, SUNXI_DE_BE0_BASE + i);
451
452 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
453}
454
Hans de Goede39920c82015-08-03 19:20:26 +0200455static u32 sunxi_rgb2yuv_coef[12] = {
456 0x00000107, 0x00000204, 0x00000064, 0x00000108,
457 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
458 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
459};
460
Hans de Goedebe8ec632014-12-19 13:46:33 +0100461static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200462 unsigned int address)
463{
464 struct sunxi_de_be_reg * const de_be =
465 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goede39920c82015-08-03 19:20:26 +0200466 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200467
Hans de Goede7cd6f922015-01-19 08:44:07 +0100468 sunxi_frontend_mode_set(mode, address);
469
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200470 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
471 &de_be->disp_size);
472 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
473 &de_be->layer0_size);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100474#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200475 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
476 writel(address << 3, &de_be->layer0_addr_low32b);
477 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100478#else
479 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
480#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200481 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
482
483 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200484 if (mode->vmode == FB_VMODE_INTERLACED)
485 setbits_le32(&de_be->mode,
486 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
487 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goede39920c82015-08-03 19:20:26 +0200488
489 if (sunxi_is_composite()) {
490 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
491 &de_be->output_color_ctrl);
492 for (i = 0; i < 12; i++)
493 writel(sunxi_rgb2yuv_coef[i],
494 &de_be->output_color_coef[i]);
495 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200496}
497
Hans de Goede0e045212014-12-21 14:49:34 +0100498static void sunxi_composer_enable(void)
499{
500 struct sunxi_de_be_reg * const de_be =
501 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
502
Hans de Goede7cd6f922015-01-19 08:44:07 +0100503 sunxi_frontend_enable();
504
Hans de Goede0e045212014-12-21 14:49:34 +0100505 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
506 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
507}
508
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200509/*
510 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
511 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100512static void sunxi_lcdc_pll_set(int tcon, int dotclock,
513 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200514{
515 struct sunxi_ccm_reg * const ccm =
516 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100517 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200518 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
519 int best_double = 0;
520
Hans de Goede5489ebc2014-12-21 16:27:45 +0100521 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100522#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100523 min_m = 6;
524 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100525#endif
526#ifdef CONFIG_VIDEO_LCD_IF_LVDS
527 min_m = max_m = 7;
528#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100529 } else {
530 min_m = 1;
531 max_m = 15;
532 }
533
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200534 /*
535 * Find the lowest divider resulting in a matching clock, if there
536 * is no match, pick the closest lower clock, as monitors tend to
537 * not sync to higher frequencies.
538 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100539 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200540 n = (m * dotclock) / 3000;
541
542 if ((n >= 9) && (n <= 127)) {
543 value = (3000 * n) / m;
544 diff = dotclock - value;
545 if (diff < best_diff) {
546 best_diff = diff;
547 best_m = m;
548 best_n = n;
549 best_double = 0;
550 }
551 }
552
553 /* These are just duplicates */
554 if (!(m & 1))
555 continue;
556
557 n = (m * dotclock) / 6000;
558 if ((n >= 9) && (n <= 127)) {
559 value = (6000 * n) / m;
560 diff = dotclock - value;
561 if (diff < best_diff) {
562 best_diff = diff;
563 best_m = m;
564 best_n = n;
565 best_double = 1;
566 }
567 }
568 }
569
570 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
571 dotclock, (best_double + 1) * 3000 * best_n / best_m,
572 best_double + 1, best_n, best_m);
573
574 clock_set_pll3(best_n * 3000000);
575
Hans de Goede5489ebc2014-12-21 16:27:45 +0100576 if (tcon == 0) {
577 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
578 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
579 CCM_LCD_CH0_CTRL_PLL3),
580 &ccm->lcd0_ch0_clk_cfg);
581 } else {
582 writel(CCM_LCD_CH1_CTRL_GATE |
583 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
584 CCM_LCD_CH1_CTRL_PLL3) |
585 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goede39920c82015-08-03 19:20:26 +0200586 if (sunxi_is_composite())
587 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
588 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goede5489ebc2014-12-21 16:27:45 +0100589 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200590
591 *clk_div = best_m;
592 *clk_double = best_double;
593}
594
595static void sunxi_lcdc_init(void)
596{
597 struct sunxi_ccm_reg * const ccm =
598 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
599 struct sunxi_lcdc_reg * const lcdc =
600 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
601
602 /* Reset off */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200603#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100604 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
605#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200606 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100607#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200608
609 /* Clock on */
610 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100611#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede83edb2a2015-05-14 18:52:54 +0200612#ifdef CONFIG_SUNXI_GEN_SUN6I
613 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
614#else
Hans de Goede213480e2015-01-01 22:04:34 +0100615 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
616#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200617#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200618
619 /* Init lcdc */
620 writel(0, &lcdc->ctrl); /* Disable tcon */
621 writel(0, &lcdc->int0); /* Disable all interrupts */
622
623 /* Disable tcon0 dot clock */
624 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
625
626 /* Set all io lines to tristate */
627 writel(0xffffffff, &lcdc->tcon0_io_tristate);
628 writel(0xffffffff, &lcdc->tcon1_io_tristate);
629}
630
Hans de Goede0e045212014-12-21 14:49:34 +0100631static void sunxi_lcdc_enable(void)
632{
633 struct sunxi_lcdc_reg * const lcdc =
634 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
635
636 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede213480e2015-01-01 22:04:34 +0100637#ifdef CONFIG_VIDEO_LCD_IF_LVDS
638 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
639 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede83edb2a2015-05-14 18:52:54 +0200640#ifdef CONFIG_SUNXI_GEN_SUN6I
641 udelay(2); /* delay at least 1200 ns */
642 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
643 udelay(2); /* delay at least 1200 ns */
644 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
645 if (sunxi_display.depth == 18)
646 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
647 else
648 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
649#else
Hans de Goede213480e2015-01-01 22:04:34 +0100650 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
651 udelay(2); /* delay at least 1200 ns */
652 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
653 udelay(1); /* delay at least 120 ns */
654 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
655 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
656#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200657#endif
Hans de Goede0e045212014-12-21 14:49:34 +0100658}
659
Hans de Goede2dae8002014-12-21 16:28:32 +0100660static void sunxi_lcdc_panel_enable(void)
661{
Hans de Goede242e3d82015-02-16 17:26:41 +0100662 int pin, reset_pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100663
664 /*
665 * Start with backlight disabled to avoid the screen flashing to
666 * white while the lcd inits.
667 */
668 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200669 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100670 gpio_request(pin, "lcd_backlight_enable");
671 gpio_direction_output(pin, 0);
672 }
673
674 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200675 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100676 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goedea7403ae2015-01-22 21:02:42 +0100677 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-12-21 16:28:32 +0100678 }
679
Hans de Goede242e3d82015-02-16 17:26:41 +0100680 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede15728192015-04-22 17:45:59 +0200681 if (reset_pin >= 0) {
Hans de Goede242e3d82015-02-16 17:26:41 +0100682 gpio_request(reset_pin, "lcd_reset");
683 gpio_direction_output(reset_pin, 0); /* Assert reset */
684 }
685
Hans de Goede2dae8002014-12-21 16:28:32 +0100686 /* Give the backlight some time to turn off and power up the panel. */
687 mdelay(40);
688 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede15728192015-04-22 17:45:59 +0200689 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100690 gpio_request(pin, "lcd_power");
691 gpio_direction_output(pin, 1);
692 }
Hans de Goede242e3d82015-02-16 17:26:41 +0100693
Hans de Goede15728192015-04-22 17:45:59 +0200694 if (reset_pin >= 0)
Hans de Goede242e3d82015-02-16 17:26:41 +0100695 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede2dae8002014-12-21 16:28:32 +0100696}
697
698static void sunxi_lcdc_backlight_enable(void)
699{
700 int pin;
701
702 /*
703 * We want to have scanned out at least one frame before enabling the
704 * backlight to avoid the screen flashing to white when we enable it.
705 */
706 mdelay(40);
707
708 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200709 if (pin >= 0)
Hans de Goede2dae8002014-12-21 16:28:32 +0100710 gpio_direction_output(pin, 1);
711
712 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200713 if (pin >= 0)
Hans de Goedea7403ae2015-01-22 21:02:42 +0100714 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-12-21 16:28:32 +0100715}
716
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200717static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede2dae8002014-12-21 16:28:32 +0100718{
719 int delay;
720
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200721 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200722 if (mode->vmode == FB_VMODE_INTERLACED)
723 delay /= 2;
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200724 if (tcon == 1)
725 delay -= 2;
726
Hans de Goede2dae8002014-12-21 16:28:32 +0100727 return (delay > 30) ? 30 : delay;
728}
729
Hans de Goedefb75d972015-01-25 15:33:07 +0100730static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
731 bool for_ext_vga_dac)
Hans de Goede2dae8002014-12-21 16:28:32 +0100732{
733 struct sunxi_lcdc_reg * const lcdc =
734 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
735 int bp, clk_delay, clk_div, clk_double, pin, total, val;
736
737 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede213480e2015-01-01 22:04:34 +0100738#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100739 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100740#endif
741#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100742 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede213480e2015-01-01 22:04:34 +0100743#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100744
745 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
746
747 /* Use tcon0 */
748 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
749 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
750
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200751 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede2dae8002014-12-21 16:28:32 +0100752 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
753 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
754
755 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
756 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
757
758 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
759 &lcdc->tcon0_timing_active);
760
761 bp = mode->hsync_len + mode->left_margin;
762 total = mode->xres + mode->right_margin + bp;
763 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
764 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
765
766 bp = mode->vsync_len + mode->upper_margin;
767 total = mode->yres + mode->lower_margin + bp;
768 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
769 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
770
Hans de Goede213480e2015-01-01 22:04:34 +0100771#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100772 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
773 &lcdc->tcon0_timing_sync);
774
Hans de Goede2dae8002014-12-21 16:28:32 +0100775 writel(0, &lcdc->tcon0_hv_intf);
776 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100777#endif
778#ifdef CONFIG_VIDEO_LCD_IF_LVDS
779 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede83edb2a2015-05-14 18:52:54 +0200780 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
781 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100782#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100783
784 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
785 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
786 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
787 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
788 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
789 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
790 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
791 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
792 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
793 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
794 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
795 writel(((sunxi_display.depth == 18) ?
796 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
797 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
798 &lcdc->tcon0_frm_ctrl);
799 }
800
Hans de Goede65150322015-01-13 13:21:46 +0100801 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100802 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
803 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
804 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
805 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goedefb75d972015-01-25 15:33:07 +0100806
807#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
808 if (for_ext_vga_dac)
809 val = 0;
810#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100811 writel(val, &lcdc->tcon0_io_polarity);
812
813 writel(0, &lcdc->tcon0_io_tristate);
814}
815
Hans de Goede39920c82015-08-03 19:20:26 +0200816#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede0e045212014-12-21 14:49:34 +0100817static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100818 int *clk_div, int *clk_double,
819 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200820{
821 struct sunxi_lcdc_reg * const lcdc =
822 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200823 int bp, clk_delay, total, val, yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200824
825 /* Use tcon1 */
826 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
827 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
828
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200829 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200830 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedef6d9d322015-08-02 16:49:29 +0200831 ((mode->vmode == FB_VMODE_INTERLACED) ?
832 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
Hans de Goede6741cc72014-12-24 19:50:11 +0100833 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200834
Hans de Goedef6d9d322015-08-02 16:49:29 +0200835 yres = mode->yres;
836 if (mode->vmode == FB_VMODE_INTERLACED)
837 yres /= 2;
838 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200839 &lcdc->tcon1_timing_source);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200840 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200841 &lcdc->tcon1_timing_scale);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200842 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200843 &lcdc->tcon1_timing_out);
844
845 bp = mode->hsync_len + mode->left_margin;
846 total = mode->xres + mode->right_margin + bp;
847 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
848 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
849
850 bp = mode->vsync_len + mode->upper_margin;
851 total = mode->yres + mode->lower_margin + bp;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200852 if (mode->vmode == FB_VMODE_NONINTERLACED)
853 total *= 2;
854 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200855 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
856
857 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
858 &lcdc->tcon1_timing_sync);
859
Hans de Goede3ffbe472014-12-27 15:19:23 +0100860 if (use_portd_hvsync) {
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100861 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
862 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goede3ffbe472014-12-27 15:19:23 +0100863
864 val = 0;
865 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
866 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
867 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
868 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
869 writel(val, &lcdc->tcon1_io_polarity);
870
871 clrbits_le32(&lcdc->tcon1_io_tristate,
872 SUNXI_LCDC_TCON_VSYNC_MASK |
873 SUNXI_LCDC_TCON_HSYNC_MASK);
874 }
Hans de Goede5489ebc2014-12-21 16:27:45 +0100875 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200876}
Hans de Goede39920c82015-08-03 19:20:26 +0200877#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +0100878
879#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200880
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100881static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
882{
883 struct sunxi_hdmi_reg * const hdmi =
884 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
885 u8 checksum = 0;
886 u8 avi_info_frame[17] = {
887 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
889 0x00
890 };
891 u8 vendor_info_frame[19] = {
892 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
894 0x00, 0x00, 0x00
895 };
896 int i;
897
898 if (mode->pixclock_khz <= 27000)
899 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
900 else
901 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
902
903 if (mode->xres * 100 / mode->yres < 156)
904 avi_info_frame[5] |= 0x18; /* 4 : 3 */
905 else
906 avi_info_frame[5] |= 0x28; /* 16 : 9 */
907
908 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
909 checksum += avi_info_frame[i];
910
911 avi_info_frame[3] = 0x100 - checksum;
912
913 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
914 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
915
916 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
917 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
918
919 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
920 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
921
922 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
923 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
924
925 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
926}
927
Hans de Goedebe8ec632014-12-19 13:46:33 +0100928static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100929 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200930{
931 struct sunxi_hdmi_reg * const hdmi =
932 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
933 int x, y;
934
935 /* Write clear interrupt status bits */
936 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
937
Hans de Goede1c092202014-12-21 14:37:45 +0100938 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100939 sunxi_hdmi_setup_info_frames(mode);
940
Hans de Goede876aaaf2014-12-20 13:51:16 +0100941 /* Set input sync enable */
942 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
943
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200944 /* Init various registers, select pll3 as clock source */
945 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
946 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
947 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
948 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
949 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
950
951 /* Setup clk div and doubler */
952 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
953 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
954 if (!clk_double)
955 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
956
957 /* Setup timing registers */
958 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
959 &hdmi->video_size);
960
961 x = mode->hsync_len + mode->left_margin;
962 y = mode->vsync_len + mode->upper_margin;
963 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
964
965 x = mode->right_margin;
966 y = mode->lower_margin;
967 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
968
969 x = mode->hsync_len;
970 y = mode->vsync_len;
971 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
972
973 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
974 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
975
976 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
977 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
978}
979
Hans de Goede0e045212014-12-21 14:49:34 +0100980static void sunxi_hdmi_enable(void)
981{
982 struct sunxi_hdmi_reg * const hdmi =
983 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
984
985 udelay(100);
986 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
987}
988
Hans de Goede2fbf0912014-12-23 23:04:35 +0100989#endif /* CONFIG_VIDEO_HDMI */
990
Hans de Goede39920c82015-08-03 19:20:26 +0200991#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goeded9786d22014-12-25 13:58:06 +0100992
Hans de Goede39920c82015-08-03 19:20:26 +0200993static void sunxi_tvencoder_mode_set(void)
Hans de Goeded9786d22014-12-25 13:58:06 +0100994{
995 struct sunxi_ccm_reg * const ccm =
996 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
997 struct sunxi_tve_reg * const tve =
998 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
999
1000 /* Clock on */
1001 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1002
Hans de Goede39920c82015-08-03 19:20:26 +02001003 switch (sunxi_display.monitor) {
1004 case sunxi_monitor_vga:
1005 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1006 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1007 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
1008 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1009 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1010 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1011 break;
1012 case sunxi_monitor_composite_pal_nc:
1013 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1014 /* Fall through */
1015 case sunxi_monitor_composite_pal:
1016 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1017 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1018 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1019 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1020 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1021 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1022 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1023 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1024 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1025 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1026 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1027 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1028 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1029 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1030 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1031 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1032 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1033 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1034 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1035 break;
1036 case sunxi_monitor_composite_pal_m:
1037 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1038 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1039 /* Fall through */
1040 case sunxi_monitor_composite_ntsc:
1041 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1042 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1043 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1044 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1045 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1046 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1047 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1048 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1049 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1050 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1051 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1052 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1053 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1054 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1055 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1056 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1057 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1058 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1059 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1060 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1061 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1062 break;
1063 case sunxi_monitor_none:
1064 case sunxi_monitor_dvi:
1065 case sunxi_monitor_hdmi:
1066 case sunxi_monitor_lcd:
1067 break;
1068 }
Hans de Goeded9786d22014-12-25 13:58:06 +01001069}
1070
Hans de Goede39920c82015-08-03 19:20:26 +02001071static void sunxi_tvencoder_enable(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001072{
1073 struct sunxi_tve_reg * const tve =
1074 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1075
1076 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1077}
1078
Hans de Goede39920c82015-08-03 19:20:26 +02001079#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +01001080
Hans de Goedee8400792014-12-23 18:39:52 +01001081static void sunxi_drc_init(void)
1082{
Hans de Goede44d8ae52015-04-06 20:33:34 +02001083#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedee8400792014-12-23 18:39:52 +01001084 struct sunxi_ccm_reg * const ccm =
1085 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1086
1087 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar8c3dacf2015-03-01 23:47:48 +05301088#ifdef CONFIG_MACH_SUN8I_A33
1089 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1090#endif
Hans de Goedee8400792014-12-23 18:39:52 +01001091 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1092 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1093#endif
1094}
1095
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001096#ifdef CONFIG_VIDEO_VGA_VIA_LCD
1097static void sunxi_vga_external_dac_enable(void)
1098{
1099 int pin;
1100
1101 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede15728192015-04-22 17:45:59 +02001102 if (pin >= 0) {
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001103 gpio_request(pin, "vga_enable");
1104 gpio_direction_output(pin, 1);
1105 }
1106}
1107#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1108
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001109#ifdef CONFIG_VIDEO_LCD_SSD2828
1110static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1111{
1112 struct ssd2828_config cfg = {
1113 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1114 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1115 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1116 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1117 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1118 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1119 .ssd2828_color_depth = 24,
1120#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1121 .mipi_dsi_number_of_data_lanes = 4,
1122 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1123 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1124 .mipi_dsi_delay_after_set_display_on_ms = 200
1125#else
1126#error MIPI LCD panel needs configuration parameters
1127#endif
1128 };
1129
1130 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1131 printf("SSD2828: SPI pins are not properly configured\n");
1132 return 1;
1133 }
1134 if (cfg.reset_pin == -1) {
1135 printf("SSD2828: Reset pin is not properly configured\n");
1136 return 1;
1137 }
1138
1139 return ssd2828_init(&cfg, mode);
1140}
1141#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1142
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001143static void sunxi_engines_init(void)
1144{
1145 sunxi_composer_init();
1146 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +01001147 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001148}
1149
Hans de Goede1c092202014-12-21 14:37:45 +01001150static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +01001151 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001152{
Hans de Goeded9786d22014-12-25 13:58:06 +01001153 int __maybe_unused clk_div, clk_double;
1154
Hans de Goede0e045212014-12-21 14:49:34 +01001155 switch (sunxi_display.monitor) {
1156 case sunxi_monitor_none:
1157 break;
1158 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001159 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001160#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001161 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001162 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001163 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1164 sunxi_composer_enable();
1165 sunxi_lcdc_enable();
1166 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001167#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001168 break;
1169 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001170 sunxi_lcdc_panel_enable();
Hans de Goede27515b22015-01-20 09:23:36 +01001171 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1172 mdelay(50); /* Wait for lcd controller power on */
1173 hitachi_tx18d42vm_init();
1174 }
Hans de Goedeaad2ac22015-02-16 17:49:47 +01001175 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1176 unsigned int orig_i2c_bus = i2c_get_bus_num();
1177 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1178 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1179 i2c_set_bus_num(orig_i2c_bus);
1180 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001181 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001182 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede2dae8002014-12-21 16:28:32 +01001183 sunxi_composer_enable();
1184 sunxi_lcdc_enable();
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001185#ifdef CONFIG_VIDEO_LCD_SSD2828
1186 sunxi_ssd2828_init(mode);
1187#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001188 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001189 break;
1190 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001191#ifdef CONFIG_VIDEO_VGA
1192 sunxi_composer_mode_set(mode, address);
1193 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goede39920c82015-08-03 19:20:26 +02001194 sunxi_tvencoder_mode_set();
Hans de Goeded9786d22014-12-25 13:58:06 +01001195 sunxi_composer_enable();
1196 sunxi_lcdc_enable();
Hans de Goede39920c82015-08-03 19:20:26 +02001197 sunxi_tvencoder_enable();
Hans de Goeded9786d22014-12-25 13:58:06 +01001198#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001199 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001200 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001201 sunxi_composer_enable();
1202 sunxi_lcdc_enable();
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001203 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001204#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001205 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001206 case sunxi_monitor_composite_pal:
1207 case sunxi_monitor_composite_ntsc:
1208 case sunxi_monitor_composite_pal_m:
1209 case sunxi_monitor_composite_pal_nc:
1210#ifdef CONFIG_VIDEO_COMPOSITE
1211 sunxi_composer_mode_set(mode, address);
1212 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1213 sunxi_tvencoder_mode_set();
1214 sunxi_composer_enable();
1215 sunxi_lcdc_enable();
1216 sunxi_tvencoder_enable();
1217#endif
1218 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001219 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001220}
1221
Hans de Goede1c092202014-12-21 14:37:45 +01001222static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1223{
1224 switch (monitor) {
Hans de Goede39920c82015-08-03 19:20:26 +02001225 case sunxi_monitor_none: return "none";
1226 case sunxi_monitor_dvi: return "dvi";
1227 case sunxi_monitor_hdmi: return "hdmi";
1228 case sunxi_monitor_lcd: return "lcd";
1229 case sunxi_monitor_vga: return "vga";
1230 case sunxi_monitor_composite_pal: return "composite-pal";
1231 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1232 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1233 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goede1c092202014-12-21 14:37:45 +01001234 }
1235 return NULL; /* never reached */
1236}
1237
Hans de Goede5633a292015-02-02 17:13:29 +01001238ulong board_get_usable_ram_top(ulong total_size)
1239{
1240 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1241}
1242
Hans de Goedebf689342015-08-03 23:01:38 +02001243static bool sunxi_has_hdmi(void)
1244{
1245#ifdef CONFIG_VIDEO_HDMI
1246 return true;
1247#else
1248 return false;
1249#endif
1250}
1251
1252static bool sunxi_has_lcd(void)
1253{
1254 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1255
1256 return lcd_mode[0] != 0;
1257}
1258
1259static bool sunxi_has_vga(void)
1260{
1261#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1262 return true;
1263#else
1264 return false;
1265#endif
1266}
1267
Hans de Goede39920c82015-08-03 19:20:26 +02001268static bool sunxi_has_composite(void)
1269{
1270#ifdef CONFIG_VIDEO_COMPOSITE
1271 return true;
1272#else
1273 return false;
1274#endif
1275}
1276
Hans de Goedebf689342015-08-03 23:01:38 +02001277static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1278{
1279 if (allow_hdmi && sunxi_has_hdmi())
1280 return sunxi_monitor_dvi;
1281 else if (sunxi_has_lcd())
1282 return sunxi_monitor_lcd;
1283 else if (sunxi_has_vga())
1284 return sunxi_monitor_vga;
Hans de Goede39920c82015-08-03 19:20:26 +02001285 else if (sunxi_has_composite())
1286 return sunxi_monitor_composite_pal;
Hans de Goedebf689342015-08-03 23:01:38 +02001287 else
1288 return sunxi_monitor_none;
1289}
1290
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001291void *video_hw_init(void)
1292{
1293 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001294 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001295 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001296 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001297#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001298 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001299#endif
Hans de Goede1c092202014-12-21 14:37:45 +01001300 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001301 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001302 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001303
1304 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1305
Hans de Goede2dae8002014-12-21 16:28:32 +01001306 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1307 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001308#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001309 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001310 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001311 edid = video_get_option_int(options, "edid", 1);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001312#endif
Hans de Goedebf689342015-08-03 23:01:38 +02001313 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goede1c092202014-12-21 14:37:45 +01001314 video_get_option_string(options, "monitor", mon, sizeof(mon),
1315 sunxi_get_mon_desc(sunxi_display.monitor));
1316 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1317 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1318 sunxi_display.monitor = i;
1319 break;
1320 }
1321 }
1322 if (i > SUNXI_MONITOR_LAST)
1323 printf("Unknown monitor: '%s', falling back to '%s'\n",
1324 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001325
Hans de Goede49d27032014-12-25 13:52:04 +01001326#ifdef CONFIG_VIDEO_HDMI
1327 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1328 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1329 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001330 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001331 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001332 if (ret) {
1333 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001334 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1335 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001336 } else if (hpd) {
1337 sunxi_hdmi_shutdown();
Hans de Goedebf689342015-08-03 23:01:38 +02001338 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede49d27032014-12-25 13:52:04 +01001339 } /* else continue with hdmi/dvi without a cable connected */
1340 }
1341#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001342
Hans de Goede49d27032014-12-25 13:52:04 +01001343 switch (sunxi_display.monitor) {
1344 case sunxi_monitor_none:
1345 return NULL;
1346 case sunxi_monitor_dvi:
1347 case sunxi_monitor_hdmi:
Hans de Goedebf689342015-08-03 23:01:38 +02001348 if (!sunxi_has_hdmi()) {
1349 printf("HDMI/DVI not supported on this board\n");
1350 sunxi_display.monitor = sunxi_monitor_none;
1351 return NULL;
Hans de Goede2dae8002014-12-21 16:28:32 +01001352 }
Hans de Goedebf689342015-08-03 23:01:38 +02001353 break;
1354 case sunxi_monitor_lcd:
1355 if (!sunxi_has_lcd()) {
1356 printf("LCD not supported on this board\n");
1357 sunxi_display.monitor = sunxi_monitor_none;
1358 return NULL;
1359 }
1360 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1361 mode = &custom;
1362 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001363 case sunxi_monitor_vga:
Hans de Goedebf689342015-08-03 23:01:38 +02001364 if (!sunxi_has_vga()) {
1365 printf("VGA not supported on this board\n");
1366 sunxi_display.monitor = sunxi_monitor_none;
1367 return NULL;
1368 }
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001369 sunxi_display.depth = 18;
1370 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001371 case sunxi_monitor_composite_pal:
1372 case sunxi_monitor_composite_ntsc:
1373 case sunxi_monitor_composite_pal_m:
1374 case sunxi_monitor_composite_pal_nc:
1375 if (!sunxi_has_composite()) {
1376 printf("Composite video not supported on this board\n");
1377 sunxi_display.monitor = sunxi_monitor_none;
1378 return NULL;
1379 }
1380 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1381 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1382 mode = &composite_video_modes[0];
1383 else
1384 mode = &composite_video_modes[1];
1385 sunxi_display.depth = 24;
1386 break;
Hans de Goede75481602014-12-19 16:05:12 +01001387 }
1388
Hans de Goede20779ec2015-02-02 18:00:53 +01001389 sunxi_display.fb_size =
1390 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1391 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1392 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1393 sunxi_display.fb_size >> 10,
1394 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1395 return NULL;
1396 }
1397
Hans de Goedef6d9d322015-08-02 16:49:29 +02001398 printf("Setting up a %dx%d%s %s console\n", mode->xres, mode->yres,
1399 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1400 sunxi_get_mon_desc(sunxi_display.monitor));
1401
Hans de Goede20779ec2015-02-02 18:00:53 +01001402 gd->fb_base = gd->bd->bi_dram[0].start +
1403 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001404 sunxi_engines_init();
Hans de Goede1c092202014-12-21 14:37:45 +01001405 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001406
1407 /*
1408 * These are the only members of this structure that are used. All the
1409 * others are driver specific. There is nothing to decribe pitch or
1410 * stride, but we are lucky with our hw.
1411 */
1412 graphic_device->frameAdrs = gd->fb_base;
1413 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1414 graphic_device->gdfBytesPP = 4;
Hans de Goedebe8ec632014-12-19 13:46:33 +01001415 graphic_device->winSizeX = mode->xres;
1416 graphic_device->winSizeY = mode->yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001417
1418 return graphic_device;
1419}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001420
1421/*
1422 * Simplefb support.
1423 */
1424#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1425int sunxi_simplefb_setup(void *blob)
1426{
1427 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1428 int offset, ret;
Hans de Goede5633a292015-02-02 17:13:29 +01001429 u64 start, size;
Hans de Goede2dae8002014-12-21 16:28:32 +01001430 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001431
Hans de Goede7cd6f922015-01-19 08:44:07 +01001432#ifdef CONFIG_MACH_SUN4I
1433#define PIPELINE_PREFIX "de_fe0-"
1434#else
1435#define PIPELINE_PREFIX
1436#endif
1437
Hans de Goede2dae8002014-12-21 16:28:32 +01001438 switch (sunxi_display.monitor) {
1439 case sunxi_monitor_none:
1440 return 0;
1441 case sunxi_monitor_dvi:
1442 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001443 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001444 break;
1445 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001446 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001447 break;
1448 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001449#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001450 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001451#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001452 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001453#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001454 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001455 case sunxi_monitor_composite_pal:
1456 case sunxi_monitor_composite_ntsc:
1457 case sunxi_monitor_composite_pal_m:
1458 case sunxi_monitor_composite_pal_nc:
1459 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1460 break;
Hans de Goede2dae8002014-12-21 16:28:32 +01001461 }
1462
1463 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001464 offset = fdt_node_offset_by_compatible(blob, -1,
1465 "allwinner,simple-framebuffer");
1466 while (offset >= 0) {
1467 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede2dae8002014-12-21 16:28:32 +01001468 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001469 if (ret == 0)
1470 break;
1471 offset = fdt_node_offset_by_compatible(blob, offset,
1472 "allwinner,simple-framebuffer");
1473 }
1474 if (offset < 0) {
1475 eprintf("Cannot setup simplefb: node not found\n");
1476 return 0; /* Keep older kernels working */
1477 }
1478
Hans de Goede5633a292015-02-02 17:13:29 +01001479 /*
1480 * Do not report the framebuffer as free RAM to the OS, note we cannot
1481 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1482 * and e.g. Linux refuses to iomap RAM on ARM, see:
1483 * linux/arch/arm/mm/ioremap.c around line 301.
1484 */
1485 start = gd->bd->bi_dram[0].start;
Hans de Goede20779ec2015-02-02 18:00:53 +01001486 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede5633a292015-02-02 17:13:29 +01001487 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1488 if (ret) {
1489 eprintf("Cannot setup simplefb: Error reserving memory\n");
1490 return ret;
1491 }
1492
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001493 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1494 graphic_device->winSizeX, graphic_device->winSizeY,
1495 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1496 "x8r8g8b8");
1497 if (ret)
1498 eprintf("Cannot setup simplefb: Error setting properties\n");
1499
1500 return ret;
1501}
1502#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */