blob: 06ed5c760318a765d0f30489569601f0f2a62269 [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>
Hans de Goede58332f82015-08-05 00:06:47 +020022#include <malloc.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020023#include <video_fb.h>
Hans de Goedebe8ec632014-12-19 13:46:33 +010024#include "videomodes.h"
Hans de Goede27515b22015-01-20 09:23:36 +010025#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashka97ece832015-01-19 05:23:33 +020026#include "ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020027
Hans de Goedea7403ae2015-01-22 21:02:42 +010028#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
29#define PWM_ON 0
30#define PWM_OFF 1
31#else
32#define PWM_ON 1
33#define PWM_OFF 0
34#endif
35
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020036DECLARE_GLOBAL_DATA_PTR;
37
Hans de Goede1c092202014-12-21 14:37:45 +010038enum sunxi_monitor {
39 sunxi_monitor_none,
40 sunxi_monitor_dvi,
41 sunxi_monitor_hdmi,
42 sunxi_monitor_lcd,
43 sunxi_monitor_vga,
Hans de Goede39920c82015-08-03 19:20:26 +020044 sunxi_monitor_composite_pal,
45 sunxi_monitor_composite_ntsc,
46 sunxi_monitor_composite_pal_m,
47 sunxi_monitor_composite_pal_nc,
Hans de Goede1c092202014-12-21 14:37:45 +010048};
Hans de Goede39920c82015-08-03 19:20:26 +020049#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goede1c092202014-12-21 14:37:45 +010050
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020051struct sunxi_display {
52 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010053 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010054 unsigned int depth;
Hans de Goede58332f82015-08-05 00:06:47 +020055 unsigned int fb_addr;
Hans de Goede20779ec2015-02-02 18:00:53 +010056 unsigned int fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020057} sunxi_display;
58
Hans de Goede39920c82015-08-03 19:20:26 +020059const struct ctfb_res_modes composite_video_modes[2] = {
60 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
61 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
62 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
63};
64
Hans de Goede2fbf0912014-12-23 23:04:35 +010065#ifdef CONFIG_VIDEO_HDMI
66
Hans de Goede75481602014-12-19 16:05:12 +010067/*
68 * Wait up to 200ms for value to be set in given part of reg.
69 */
70static int await_completion(u32 *reg, u32 mask, u32 val)
71{
72 unsigned long tmo = timer_get_us() + 200000;
73
74 while ((readl(reg) & mask) != val) {
75 if (timer_get_us() > tmo) {
76 printf("DDC: timeout reading EDID\n");
77 return -ETIME;
78 }
79 }
80 return 0;
81}
82
Hans de Goede7fad8a92014-12-28 09:13:21 +010083static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020084{
85 struct sunxi_ccm_reg * const ccm =
86 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
87 struct sunxi_hdmi_reg * const hdmi =
88 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede7fad8a92014-12-28 09:13:21 +010089 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020090
91 /* Set pll3 to 300MHz */
92 clock_set_pll3(300000000);
93
94 /* Set hdmi parent to pll3 */
95 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
96 CCM_HDMI_CTRL_PLL3);
97
98 /* Set ahb gating to pass */
Hans de Goede44d8ae52015-04-06 20:33:34 +020099#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100100 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
101#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200102 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
103
104 /* Clock on */
105 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
106
107 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
108 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
109
Hans de Goede40f1b872014-12-20 15:15:23 +0100110 while (timer_get_us() < tmo) {
111 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
112 return 1;
113 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200114
Hans de Goede40f1b872014-12-20 15:15:23 +0100115 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100116}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200117
Hans de Goede518cef22014-12-19 15:13:57 +0100118static void sunxi_hdmi_shutdown(void)
119{
120 struct sunxi_ccm_reg * const ccm =
121 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
122 struct sunxi_hdmi_reg * const hdmi =
123 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
124
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200125 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
126 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
127 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goede44d8ae52015-04-06 20:33:34 +0200128#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100129 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
130#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200131 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200132}
133
Hans de Goede75481602014-12-19 16:05:12 +0100134static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
135{
136 struct sunxi_hdmi_reg * const hdmi =
137 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
138
139 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
140 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
141 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
142 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
143 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
144#ifndef CONFIG_MACH_SUN6I
145 writel(n, &hdmi->ddc_byte_count);
146 writel(cmnd, &hdmi->ddc_cmnd);
147#else
148 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
149#endif
150 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
151
152 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
153}
154
155static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
156{
157 struct sunxi_hdmi_reg * const hdmi =
158 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
159 int i, n;
160
161 while (count > 0) {
162 if (count > 16)
163 n = 16;
164 else
165 n = count;
166
167 if (sunxi_hdmi_ddc_do_command(
168 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
169 offset, n))
170 return -ETIME;
171
172 for (i = 0; i < n; i++)
173 *buf++ = readb(&hdmi->ddc_fifo_data);
174
175 offset += n;
176 count -= n;
177 }
178
179 return 0;
180}
181
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100182static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
183{
184 int r, retries = 2;
185
186 do {
187 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
188 if (r)
189 continue;
190 r = edid_check_checksum(buf);
191 if (r) {
192 printf("EDID block %d: checksum error%s\n",
193 block, retries ? ", retrying" : "");
194 }
195 } while (r && retries--);
196
197 return r;
198}
199
Hans de Goede1c092202014-12-21 14:37:45 +0100200static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100201{
202 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100203 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-12-19 16:05:12 +0100204 struct edid_detailed_timing *t =
205 (struct edid_detailed_timing *)edid1.monitor_details.timing;
206 struct sunxi_hdmi_reg * const hdmi =
207 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
208 struct sunxi_ccm_reg * const ccm =
209 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedef3000682014-12-20 14:31:45 +0100210 int i, r, ext_blocks = 0;
Hans de Goede75481602014-12-19 16:05:12 +0100211
212 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
213 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
214 &hdmi->pad_ctrl1);
215 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
216 &hdmi->pll_ctrl);
217 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
218
219 /* Reset i2c controller */
220 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
221 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
222 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
223 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
224 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
225 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
226 return -EIO;
227
228 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
229#ifndef CONFIG_MACH_SUN6I
230 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
231 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
232#endif
233
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100234 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-12-20 14:31:45 +0100235 if (r == 0) {
236 r = edid_check_info(&edid1);
237 if (r) {
238 printf("EDID: invalid EDID data\n");
239 r = -EINVAL;
240 }
241 }
242 if (r == 0) {
243 ext_blocks = edid1.extension_flag;
244 if (ext_blocks > 4)
245 ext_blocks = 4;
246 for (i = 0; i < ext_blocks; i++) {
247 if (sunxi_hdmi_edid_get_block(1 + i,
248 (u8 *)&cea681[i]) != 0) {
249 ext_blocks = i;
250 break;
251 }
252 }
253 }
Hans de Goede75481602014-12-19 16:05:12 +0100254
255 /* Disable DDC engine, no longer needed */
256 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
257 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
258
259 if (r)
260 return r;
261
Hans de Goede75481602014-12-19 16:05:12 +0100262 /* We want version 1.3 or 1.2 with detailed timing info */
263 if (edid1.version != 1 || (edid1.revision < 3 &&
264 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
265 printf("EDID: unsupported version %d.%d\n",
266 edid1.version, edid1.revision);
267 return -EINVAL;
268 }
269
270 /* Take the first usable detailed timing */
271 for (i = 0; i < 4; i++, t++) {
272 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
273 if (r == 0)
274 break;
275 }
276 if (i == 4) {
277 printf("EDID: no usable detailed timing found\n");
278 return -ENOENT;
279 }
280
Hans de Goedef3000682014-12-20 14:31:45 +0100281 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100282 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-12-20 14:31:45 +0100283 for (i = 0; i < ext_blocks; i++) {
284 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
285 cea681[i].revision < 2)
286 continue;
287
288 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goede1c092202014-12-21 14:37:45 +0100289 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100290 }
291
Hans de Goede75481602014-12-19 16:05:12 +0100292 return 0;
293}
294
Hans de Goede2fbf0912014-12-23 23:04:35 +0100295#endif /* CONFIG_VIDEO_HDMI */
296
Hans de Goede7cd6f922015-01-19 08:44:07 +0100297#ifdef CONFIG_MACH_SUN4I
298/*
299 * Testing has shown that on sun4i the display backend engine does not have
300 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
301 * fifo underruns. So on sun4i we use the display frontend engine to do the
302 * dma from memory, as the frontend does have deep enough fifo-s.
303 */
304
305static const u32 sun4i_vert_coef[32] = {
306 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
307 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
308 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
309 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
310 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
311 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
312 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
313 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
314};
315
316static const u32 sun4i_horz_coef[64] = {
317 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
318 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
319 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
320 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
321 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
322 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
323 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
324 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
325 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
326 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
327 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
328 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
329 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
330 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
331 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
332 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
333};
334
335static void sunxi_frontend_init(void)
336{
337 struct sunxi_ccm_reg * const ccm =
338 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
339 struct sunxi_de_fe_reg * const de_fe =
340 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
341 int i;
342
343 /* Clocks on */
344 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
345 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
346 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
347
348 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
349
350 for (i = 0; i < 32; i++) {
351 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
352 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
353 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
354 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
355 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
356 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
357 }
358
359 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
360}
361
362static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
363 unsigned int address)
364{
365 struct sunxi_de_fe_reg * const de_fe =
366 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
367
368 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
369 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
370 writel(mode->xres * 4, &de_fe->ch0_stride);
371 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
372 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
373
374 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
375 &de_fe->ch0_insize);
376 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
377 &de_fe->ch0_outsize);
378 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
379 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
380
381 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
382 &de_fe->ch1_insize);
383 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
384 &de_fe->ch1_outsize);
385 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
386 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
387
388 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
389}
390
391static void sunxi_frontend_enable(void)
392{
393 struct sunxi_de_fe_reg * const de_fe =
394 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
395
396 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
397}
398#else
399static void sunxi_frontend_init(void) {}
400static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
401 unsigned int address) {}
402static void sunxi_frontend_enable(void) {}
403#endif
404
Hans de Goede39920c82015-08-03 19:20:26 +0200405static bool sunxi_is_composite(void)
406{
407 switch (sunxi_display.monitor) {
408 case sunxi_monitor_none:
409 case sunxi_monitor_dvi:
410 case sunxi_monitor_hdmi:
411 case sunxi_monitor_lcd:
412 case sunxi_monitor_vga:
413 return false;
414 case sunxi_monitor_composite_pal:
415 case sunxi_monitor_composite_ntsc:
416 case sunxi_monitor_composite_pal_m:
417 case sunxi_monitor_composite_pal_nc:
418 return true;
419 }
420
421 return false; /* Never reached */
422}
423
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200424/*
425 * This is the entity that mixes and matches the different layers and inputs.
426 * Allwinner calls it the back-end, but i like composer better.
427 */
428static void sunxi_composer_init(void)
429{
430 struct sunxi_ccm_reg * const ccm =
431 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
432 struct sunxi_de_be_reg * const de_be =
433 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
434 int i;
435
Hans de Goede7cd6f922015-01-19 08:44:07 +0100436 sunxi_frontend_init();
437
Hans de Goede44d8ae52015-04-06 20:33:34 +0200438#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100439 /* Reset off */
440 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
441#endif
442
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200443 /* Clocks on */
444 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100445#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200446 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100447#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200448 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
449
450 /* Engine bug, clear registers after reset */
451 for (i = 0x0800; i < 0x1000; i += 4)
452 writel(0, SUNXI_DE_BE0_BASE + i);
453
454 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
455}
456
Hans de Goede39920c82015-08-03 19:20:26 +0200457static u32 sunxi_rgb2yuv_coef[12] = {
458 0x00000107, 0x00000204, 0x00000064, 0x00000108,
459 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
460 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
461};
462
Hans de Goedebe8ec632014-12-19 13:46:33 +0100463static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200464 unsigned int address)
465{
466 struct sunxi_de_be_reg * const de_be =
467 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goede39920c82015-08-03 19:20:26 +0200468 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200469
Hans de Goede7cd6f922015-01-19 08:44:07 +0100470 sunxi_frontend_mode_set(mode, address);
471
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200472 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
473 &de_be->disp_size);
474 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
475 &de_be->layer0_size);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100476#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200477 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
478 writel(address << 3, &de_be->layer0_addr_low32b);
479 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100480#else
481 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
482#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200483 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
484
485 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200486 if (mode->vmode == FB_VMODE_INTERLACED)
487 setbits_le32(&de_be->mode,
Hans de Goeded8d07992015-08-06 12:08:33 +0200488#ifndef CONFIG_MACH_SUN5I
Hans de Goedef6d9d322015-08-02 16:49:29 +0200489 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goeded8d07992015-08-06 12:08:33 +0200490#endif
Hans de Goedef6d9d322015-08-02 16:49:29 +0200491 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goede39920c82015-08-03 19:20:26 +0200492
493 if (sunxi_is_composite()) {
494 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
495 &de_be->output_color_ctrl);
496 for (i = 0; i < 12; i++)
497 writel(sunxi_rgb2yuv_coef[i],
498 &de_be->output_color_coef[i]);
499 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200500}
501
Hans de Goede0e045212014-12-21 14:49:34 +0100502static void sunxi_composer_enable(void)
503{
504 struct sunxi_de_be_reg * const de_be =
505 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
506
Hans de Goede7cd6f922015-01-19 08:44:07 +0100507 sunxi_frontend_enable();
508
Hans de Goede0e045212014-12-21 14:49:34 +0100509 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
510 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
511}
512
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200513/*
514 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
515 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100516static void sunxi_lcdc_pll_set(int tcon, int dotclock,
517 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200518{
519 struct sunxi_ccm_reg * const ccm =
520 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100521 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200522 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
523 int best_double = 0;
Hans de Goedefb685d32015-08-08 14:08:21 +0200524 bool use_mipi_pll = false;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200525
Hans de Goede5489ebc2014-12-21 16:27:45 +0100526 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100527#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100528 min_m = 6;
529 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100530#endif
531#ifdef CONFIG_VIDEO_LCD_IF_LVDS
532 min_m = max_m = 7;
533#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100534 } else {
535 min_m = 1;
536 max_m = 15;
537 }
538
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200539 /*
540 * Find the lowest divider resulting in a matching clock, if there
541 * is no match, pick the closest lower clock, as monitors tend to
542 * not sync to higher frequencies.
543 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100544 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200545 n = (m * dotclock) / 3000;
546
547 if ((n >= 9) && (n <= 127)) {
548 value = (3000 * n) / m;
549 diff = dotclock - value;
550 if (diff < best_diff) {
551 best_diff = diff;
552 best_m = m;
553 best_n = n;
554 best_double = 0;
555 }
556 }
557
558 /* These are just duplicates */
559 if (!(m & 1))
560 continue;
561
562 n = (m * dotclock) / 6000;
563 if ((n >= 9) && (n <= 127)) {
564 value = (6000 * n) / m;
565 diff = dotclock - value;
566 if (diff < best_diff) {
567 best_diff = diff;
568 best_m = m;
569 best_n = n;
570 best_double = 1;
571 }
572 }
573 }
574
Hans de Goedefb685d32015-08-08 14:08:21 +0200575#ifdef CONFIG_MACH_SUN6I
576 /*
577 * Use the MIPI pll if we've been unable to find any matching setting
578 * for PLL3, this happens with high dotclocks because of min_m = 6.
579 */
580 if (tcon == 0 && best_n == 0) {
581 use_mipi_pll = true;
582 best_m = 6; /* Minimum m for tcon0 */
583 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200584
Hans de Goedefb685d32015-08-08 14:08:21 +0200585 if (use_mipi_pll) {
586 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
587 clock_set_mipi_pll(best_m * dotclock * 1000);
588 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
589 dotclock, clock_get_mipi_pll() / best_m / 1000);
590 } else
591#endif
592 {
593 clock_set_pll3(best_n * 3000000);
594 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
595 dotclock,
596 (best_double + 1) * clock_get_pll3() / best_m / 1000,
597 best_double + 1, best_n, best_m);
598 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200599
Hans de Goede5489ebc2014-12-21 16:27:45 +0100600 if (tcon == 0) {
Hans de Goedefb685d32015-08-08 14:08:21 +0200601 u32 pll;
602
603 if (use_mipi_pll)
604 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
605 else if (best_double)
606 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
607 else
608 pll = CCM_LCD_CH0_CTRL_PLL3;
609
610 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
Hans de Goede5489ebc2014-12-21 16:27:45 +0100611 &ccm->lcd0_ch0_clk_cfg);
612 } else {
613 writel(CCM_LCD_CH1_CTRL_GATE |
614 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
615 CCM_LCD_CH1_CTRL_PLL3) |
616 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goede39920c82015-08-03 19:20:26 +0200617 if (sunxi_is_composite())
618 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
619 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goede5489ebc2014-12-21 16:27:45 +0100620 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200621
622 *clk_div = best_m;
623 *clk_double = best_double;
624}
625
626static void sunxi_lcdc_init(void)
627{
628 struct sunxi_ccm_reg * const ccm =
629 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
630 struct sunxi_lcdc_reg * const lcdc =
631 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
632
633 /* Reset off */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200634#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100635 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
636#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200637 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100638#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200639
640 /* Clock on */
641 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100642#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede83edb2a2015-05-14 18:52:54 +0200643#ifdef CONFIG_SUNXI_GEN_SUN6I
644 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
645#else
Hans de Goede213480e2015-01-01 22:04:34 +0100646 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
647#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200648#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200649
650 /* Init lcdc */
651 writel(0, &lcdc->ctrl); /* Disable tcon */
652 writel(0, &lcdc->int0); /* Disable all interrupts */
653
654 /* Disable tcon0 dot clock */
655 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
656
657 /* Set all io lines to tristate */
658 writel(0xffffffff, &lcdc->tcon0_io_tristate);
659 writel(0xffffffff, &lcdc->tcon1_io_tristate);
660}
661
Hans de Goede0e045212014-12-21 14:49:34 +0100662static void sunxi_lcdc_enable(void)
663{
664 struct sunxi_lcdc_reg * const lcdc =
665 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
666
667 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede213480e2015-01-01 22:04:34 +0100668#ifdef CONFIG_VIDEO_LCD_IF_LVDS
669 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
670 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede83edb2a2015-05-14 18:52:54 +0200671#ifdef CONFIG_SUNXI_GEN_SUN6I
672 udelay(2); /* delay at least 1200 ns */
673 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
674 udelay(2); /* delay at least 1200 ns */
675 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
676 if (sunxi_display.depth == 18)
677 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
678 else
679 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
680#else
Hans de Goede213480e2015-01-01 22:04:34 +0100681 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
682 udelay(2); /* delay at least 1200 ns */
683 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
684 udelay(1); /* delay at least 120 ns */
685 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
686 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
687#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200688#endif
Hans de Goede0e045212014-12-21 14:49:34 +0100689}
690
Hans de Goede2dae8002014-12-21 16:28:32 +0100691static void sunxi_lcdc_panel_enable(void)
692{
Hans de Goede242e3d82015-02-16 17:26:41 +0100693 int pin, reset_pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100694
695 /*
696 * Start with backlight disabled to avoid the screen flashing to
697 * white while the lcd inits.
698 */
699 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200700 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100701 gpio_request(pin, "lcd_backlight_enable");
702 gpio_direction_output(pin, 0);
703 }
704
705 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200706 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100707 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goedea7403ae2015-01-22 21:02:42 +0100708 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-12-21 16:28:32 +0100709 }
710
Hans de Goede242e3d82015-02-16 17:26:41 +0100711 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede15728192015-04-22 17:45:59 +0200712 if (reset_pin >= 0) {
Hans de Goede242e3d82015-02-16 17:26:41 +0100713 gpio_request(reset_pin, "lcd_reset");
714 gpio_direction_output(reset_pin, 0); /* Assert reset */
715 }
716
Hans de Goede2dae8002014-12-21 16:28:32 +0100717 /* Give the backlight some time to turn off and power up the panel. */
718 mdelay(40);
719 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede15728192015-04-22 17:45:59 +0200720 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100721 gpio_request(pin, "lcd_power");
722 gpio_direction_output(pin, 1);
723 }
Hans de Goede242e3d82015-02-16 17:26:41 +0100724
Hans de Goede15728192015-04-22 17:45:59 +0200725 if (reset_pin >= 0)
Hans de Goede242e3d82015-02-16 17:26:41 +0100726 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede2dae8002014-12-21 16:28:32 +0100727}
728
729static void sunxi_lcdc_backlight_enable(void)
730{
731 int pin;
732
733 /*
734 * We want to have scanned out at least one frame before enabling the
735 * backlight to avoid the screen flashing to white when we enable it.
736 */
737 mdelay(40);
738
739 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200740 if (pin >= 0)
Hans de Goede2dae8002014-12-21 16:28:32 +0100741 gpio_direction_output(pin, 1);
742
743 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200744 if (pin >= 0)
Hans de Goedea7403ae2015-01-22 21:02:42 +0100745 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-12-21 16:28:32 +0100746}
747
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200748static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede2dae8002014-12-21 16:28:32 +0100749{
750 int delay;
751
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200752 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200753 if (mode->vmode == FB_VMODE_INTERLACED)
754 delay /= 2;
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200755 if (tcon == 1)
756 delay -= 2;
757
Hans de Goede2dae8002014-12-21 16:28:32 +0100758 return (delay > 30) ? 30 : delay;
759}
760
Hans de Goedefb75d972015-01-25 15:33:07 +0100761static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
762 bool for_ext_vga_dac)
Hans de Goede2dae8002014-12-21 16:28:32 +0100763{
764 struct sunxi_lcdc_reg * const lcdc =
765 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
766 int bp, clk_delay, clk_div, clk_double, pin, total, val;
767
768 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede213480e2015-01-01 22:04:34 +0100769#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100770 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100771#endif
772#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100773 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede213480e2015-01-01 22:04:34 +0100774#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100775
776 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
777
778 /* Use tcon0 */
779 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
780 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
781
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200782 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede2dae8002014-12-21 16:28:32 +0100783 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
784 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
785
786 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
787 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
788
789 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
790 &lcdc->tcon0_timing_active);
791
792 bp = mode->hsync_len + mode->left_margin;
793 total = mode->xres + mode->right_margin + bp;
794 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
795 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
796
797 bp = mode->vsync_len + mode->upper_margin;
798 total = mode->yres + mode->lower_margin + bp;
799 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
800 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
801
Hans de Goede213480e2015-01-01 22:04:34 +0100802#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100803 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
804 &lcdc->tcon0_timing_sync);
805
Hans de Goede2dae8002014-12-21 16:28:32 +0100806 writel(0, &lcdc->tcon0_hv_intf);
807 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100808#endif
809#ifdef CONFIG_VIDEO_LCD_IF_LVDS
810 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede83edb2a2015-05-14 18:52:54 +0200811 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
812 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100813#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100814
815 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
816 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
817 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
818 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
819 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
820 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
821 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
822 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
823 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
824 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
825 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
826 writel(((sunxi_display.depth == 18) ?
827 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
828 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
829 &lcdc->tcon0_frm_ctrl);
830 }
831
Hans de Goede65150322015-01-13 13:21:46 +0100832 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100833 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
834 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
835 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
836 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goedefb75d972015-01-25 15:33:07 +0100837
838#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
839 if (for_ext_vga_dac)
840 val = 0;
841#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100842 writel(val, &lcdc->tcon0_io_polarity);
843
844 writel(0, &lcdc->tcon0_io_tristate);
845}
846
Hans de Goede39920c82015-08-03 19:20:26 +0200847#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede0e045212014-12-21 14:49:34 +0100848static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100849 int *clk_div, int *clk_double,
850 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200851{
852 struct sunxi_lcdc_reg * const lcdc =
853 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200854 int bp, clk_delay, total, val, yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200855
856 /* Use tcon1 */
857 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
858 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
859
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200860 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200861 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedef6d9d322015-08-02 16:49:29 +0200862 ((mode->vmode == FB_VMODE_INTERLACED) ?
863 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
Hans de Goede6741cc72014-12-24 19:50:11 +0100864 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200865
Hans de Goedef6d9d322015-08-02 16:49:29 +0200866 yres = mode->yres;
867 if (mode->vmode == FB_VMODE_INTERLACED)
868 yres /= 2;
869 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200870 &lcdc->tcon1_timing_source);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200871 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200872 &lcdc->tcon1_timing_scale);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200873 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200874 &lcdc->tcon1_timing_out);
875
876 bp = mode->hsync_len + mode->left_margin;
877 total = mode->xres + mode->right_margin + bp;
878 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
879 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
880
881 bp = mode->vsync_len + mode->upper_margin;
882 total = mode->yres + mode->lower_margin + bp;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200883 if (mode->vmode == FB_VMODE_NONINTERLACED)
884 total *= 2;
885 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200886 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
887
888 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
889 &lcdc->tcon1_timing_sync);
890
Hans de Goede3ffbe472014-12-27 15:19:23 +0100891 if (use_portd_hvsync) {
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100892 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
893 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goede3ffbe472014-12-27 15:19:23 +0100894
895 val = 0;
896 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
897 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
898 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
899 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
900 writel(val, &lcdc->tcon1_io_polarity);
901
902 clrbits_le32(&lcdc->tcon1_io_tristate,
903 SUNXI_LCDC_TCON_VSYNC_MASK |
904 SUNXI_LCDC_TCON_HSYNC_MASK);
905 }
Hans de Goeded8d07992015-08-06 12:08:33 +0200906
907#ifdef CONFIG_MACH_SUN5I
908 if (sunxi_is_composite())
909 clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK,
910 SUNXI_LCDC_MUX_CTRL_SRC0(1));
911#endif
912
Hans de Goede5489ebc2014-12-21 16:27:45 +0100913 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200914}
Hans de Goede39920c82015-08-03 19:20:26 +0200915#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +0100916
917#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200918
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100919static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
920{
921 struct sunxi_hdmi_reg * const hdmi =
922 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
923 u8 checksum = 0;
924 u8 avi_info_frame[17] = {
925 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
927 0x00
928 };
929 u8 vendor_info_frame[19] = {
930 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
931 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
932 0x00, 0x00, 0x00
933 };
934 int i;
935
936 if (mode->pixclock_khz <= 27000)
937 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
938 else
939 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
940
941 if (mode->xres * 100 / mode->yres < 156)
942 avi_info_frame[5] |= 0x18; /* 4 : 3 */
943 else
944 avi_info_frame[5] |= 0x28; /* 16 : 9 */
945
946 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
947 checksum += avi_info_frame[i];
948
949 avi_info_frame[3] = 0x100 - checksum;
950
951 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
952 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
953
954 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
955 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
956
957 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
958 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
959
960 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
961 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
962
963 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
964}
965
Hans de Goedebe8ec632014-12-19 13:46:33 +0100966static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100967 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200968{
969 struct sunxi_hdmi_reg * const hdmi =
970 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
971 int x, y;
972
973 /* Write clear interrupt status bits */
974 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
975
Hans de Goede1c092202014-12-21 14:37:45 +0100976 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100977 sunxi_hdmi_setup_info_frames(mode);
978
Hans de Goede876aaaf2014-12-20 13:51:16 +0100979 /* Set input sync enable */
980 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
981
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200982 /* Init various registers, select pll3 as clock source */
983 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
984 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
985 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
986 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
987 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
988
989 /* Setup clk div and doubler */
990 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
991 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
992 if (!clk_double)
993 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
994
995 /* Setup timing registers */
996 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
997 &hdmi->video_size);
998
999 x = mode->hsync_len + mode->left_margin;
1000 y = mode->vsync_len + mode->upper_margin;
1001 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
1002
1003 x = mode->right_margin;
1004 y = mode->lower_margin;
1005 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
1006
1007 x = mode->hsync_len;
1008 y = mode->vsync_len;
1009 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
1010
1011 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
1012 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
1013
1014 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
1015 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
1016}
1017
Hans de Goede0e045212014-12-21 14:49:34 +01001018static void sunxi_hdmi_enable(void)
1019{
1020 struct sunxi_hdmi_reg * const hdmi =
1021 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
1022
1023 udelay(100);
1024 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
1025}
1026
Hans de Goede2fbf0912014-12-23 23:04:35 +01001027#endif /* CONFIG_VIDEO_HDMI */
1028
Hans de Goede39920c82015-08-03 19:20:26 +02001029#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goeded9786d22014-12-25 13:58:06 +01001030
Hans de Goede39920c82015-08-03 19:20:26 +02001031static void sunxi_tvencoder_mode_set(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001032{
1033 struct sunxi_ccm_reg * const ccm =
1034 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1035 struct sunxi_tve_reg * const tve =
1036 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1037
Hans de Goeded8d07992015-08-06 12:08:33 +02001038 /* Reset off */
1039 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goeded9786d22014-12-25 13:58:06 +01001040 /* Clock on */
1041 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1042
Hans de Goede39920c82015-08-03 19:20:26 +02001043 switch (sunxi_display.monitor) {
1044 case sunxi_monitor_vga:
1045 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1046 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1047 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
1048 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1049 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1050 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1051 break;
1052 case sunxi_monitor_composite_pal_nc:
1053 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1054 /* Fall through */
1055 case sunxi_monitor_composite_pal:
1056 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1057 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1058 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1059 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1060 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1061 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1062 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1063 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1064 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1065 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1066 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1067 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1068 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1069 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1070 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1071 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1072 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1073 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1074 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1075 break;
1076 case sunxi_monitor_composite_pal_m:
1077 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1078 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1079 /* Fall through */
1080 case sunxi_monitor_composite_ntsc:
1081 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1082 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1083 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1084 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1085 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1086 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1087 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1088 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1089 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1090 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1091 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1092 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1093 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1094 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1095 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1096 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1097 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1098 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1099 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1100 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1101 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1102 break;
1103 case sunxi_monitor_none:
1104 case sunxi_monitor_dvi:
1105 case sunxi_monitor_hdmi:
1106 case sunxi_monitor_lcd:
1107 break;
1108 }
Hans de Goeded9786d22014-12-25 13:58:06 +01001109}
1110
Hans de Goede39920c82015-08-03 19:20:26 +02001111static void sunxi_tvencoder_enable(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001112{
1113 struct sunxi_tve_reg * const tve =
1114 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1115
1116 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1117}
1118
Hans de Goede39920c82015-08-03 19:20:26 +02001119#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +01001120
Hans de Goedee8400792014-12-23 18:39:52 +01001121static void sunxi_drc_init(void)
1122{
Hans de Goede44d8ae52015-04-06 20:33:34 +02001123#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedee8400792014-12-23 18:39:52 +01001124 struct sunxi_ccm_reg * const ccm =
1125 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1126
1127 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar8c3dacf2015-03-01 23:47:48 +05301128#ifdef CONFIG_MACH_SUN8I_A33
1129 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1130#endif
Hans de Goedee8400792014-12-23 18:39:52 +01001131 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1132 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1133#endif
1134}
1135
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001136#ifdef CONFIG_VIDEO_VGA_VIA_LCD
1137static void sunxi_vga_external_dac_enable(void)
1138{
1139 int pin;
1140
1141 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede15728192015-04-22 17:45:59 +02001142 if (pin >= 0) {
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001143 gpio_request(pin, "vga_enable");
1144 gpio_direction_output(pin, 1);
1145 }
1146}
1147#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1148
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001149#ifdef CONFIG_VIDEO_LCD_SSD2828
1150static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1151{
1152 struct ssd2828_config cfg = {
1153 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1154 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1155 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1156 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1157 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1158 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1159 .ssd2828_color_depth = 24,
1160#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1161 .mipi_dsi_number_of_data_lanes = 4,
1162 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1163 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1164 .mipi_dsi_delay_after_set_display_on_ms = 200
1165#else
1166#error MIPI LCD panel needs configuration parameters
1167#endif
1168 };
1169
1170 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1171 printf("SSD2828: SPI pins are not properly configured\n");
1172 return 1;
1173 }
1174 if (cfg.reset_pin == -1) {
1175 printf("SSD2828: Reset pin is not properly configured\n");
1176 return 1;
1177 }
1178
1179 return ssd2828_init(&cfg, mode);
1180}
1181#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1182
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001183static void sunxi_engines_init(void)
1184{
1185 sunxi_composer_init();
1186 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +01001187 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001188}
1189
Hans de Goede1c092202014-12-21 14:37:45 +01001190static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +01001191 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001192{
Hans de Goeded9786d22014-12-25 13:58:06 +01001193 int __maybe_unused clk_div, clk_double;
1194
Hans de Goede0e045212014-12-21 14:49:34 +01001195 switch (sunxi_display.monitor) {
1196 case sunxi_monitor_none:
1197 break;
1198 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001199 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001200#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001201 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001202 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001203 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1204 sunxi_composer_enable();
1205 sunxi_lcdc_enable();
1206 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001207#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001208 break;
1209 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001210 sunxi_lcdc_panel_enable();
Hans de Goede27515b22015-01-20 09:23:36 +01001211 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1212 mdelay(50); /* Wait for lcd controller power on */
1213 hitachi_tx18d42vm_init();
1214 }
Hans de Goedeaad2ac22015-02-16 17:49:47 +01001215 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1216 unsigned int orig_i2c_bus = i2c_get_bus_num();
1217 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1218 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1219 i2c_set_bus_num(orig_i2c_bus);
1220 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001221 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001222 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede2dae8002014-12-21 16:28:32 +01001223 sunxi_composer_enable();
1224 sunxi_lcdc_enable();
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001225#ifdef CONFIG_VIDEO_LCD_SSD2828
1226 sunxi_ssd2828_init(mode);
1227#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001228 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001229 break;
1230 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001231#ifdef CONFIG_VIDEO_VGA
1232 sunxi_composer_mode_set(mode, address);
1233 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goede39920c82015-08-03 19:20:26 +02001234 sunxi_tvencoder_mode_set();
Hans de Goeded9786d22014-12-25 13:58:06 +01001235 sunxi_composer_enable();
1236 sunxi_lcdc_enable();
Hans de Goede39920c82015-08-03 19:20:26 +02001237 sunxi_tvencoder_enable();
Hans de Goeded9786d22014-12-25 13:58:06 +01001238#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001239 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001240 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001241 sunxi_composer_enable();
1242 sunxi_lcdc_enable();
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001243 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001244#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001245 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001246 case sunxi_monitor_composite_pal:
1247 case sunxi_monitor_composite_ntsc:
1248 case sunxi_monitor_composite_pal_m:
1249 case sunxi_monitor_composite_pal_nc:
1250#ifdef CONFIG_VIDEO_COMPOSITE
1251 sunxi_composer_mode_set(mode, address);
1252 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1253 sunxi_tvencoder_mode_set();
1254 sunxi_composer_enable();
1255 sunxi_lcdc_enable();
1256 sunxi_tvencoder_enable();
1257#endif
1258 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001259 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001260}
1261
Hans de Goede1c092202014-12-21 14:37:45 +01001262static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1263{
1264 switch (monitor) {
Hans de Goede39920c82015-08-03 19:20:26 +02001265 case sunxi_monitor_none: return "none";
1266 case sunxi_monitor_dvi: return "dvi";
1267 case sunxi_monitor_hdmi: return "hdmi";
1268 case sunxi_monitor_lcd: return "lcd";
1269 case sunxi_monitor_vga: return "vga";
1270 case sunxi_monitor_composite_pal: return "composite-pal";
1271 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1272 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1273 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goede1c092202014-12-21 14:37:45 +01001274 }
1275 return NULL; /* never reached */
1276}
1277
Hans de Goede5633a292015-02-02 17:13:29 +01001278ulong board_get_usable_ram_top(ulong total_size)
1279{
1280 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1281}
1282
Hans de Goedebf689342015-08-03 23:01:38 +02001283static bool sunxi_has_hdmi(void)
1284{
1285#ifdef CONFIG_VIDEO_HDMI
1286 return true;
1287#else
1288 return false;
1289#endif
1290}
1291
1292static bool sunxi_has_lcd(void)
1293{
1294 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1295
1296 return lcd_mode[0] != 0;
1297}
1298
1299static bool sunxi_has_vga(void)
1300{
1301#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1302 return true;
1303#else
1304 return false;
1305#endif
1306}
1307
Hans de Goede39920c82015-08-03 19:20:26 +02001308static bool sunxi_has_composite(void)
1309{
1310#ifdef CONFIG_VIDEO_COMPOSITE
1311 return true;
1312#else
1313 return false;
1314#endif
1315}
1316
Hans de Goedebf689342015-08-03 23:01:38 +02001317static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1318{
1319 if (allow_hdmi && sunxi_has_hdmi())
1320 return sunxi_monitor_dvi;
1321 else if (sunxi_has_lcd())
1322 return sunxi_monitor_lcd;
1323 else if (sunxi_has_vga())
1324 return sunxi_monitor_vga;
Hans de Goede39920c82015-08-03 19:20:26 +02001325 else if (sunxi_has_composite())
1326 return sunxi_monitor_composite_pal;
Hans de Goedebf689342015-08-03 23:01:38 +02001327 else
1328 return sunxi_monitor_none;
1329}
1330
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001331void *video_hw_init(void)
1332{
1333 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001334 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001335 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001336 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001337#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001338 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001339#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001340 int i, overscan_offset, overscan_x, overscan_y;
1341 unsigned int fb_dma_addr;
Hans de Goede1c092202014-12-21 14:37:45 +01001342 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001343 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001344
1345 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1346
Hans de Goede2dae8002014-12-21 16:28:32 +01001347 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1348 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001349#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001350 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001351 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001352 edid = video_get_option_int(options, "edid", 1);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001353#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001354 overscan_x = video_get_option_int(options, "overscan_x", -1);
1355 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedebf689342015-08-03 23:01:38 +02001356 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goede1c092202014-12-21 14:37:45 +01001357 video_get_option_string(options, "monitor", mon, sizeof(mon),
1358 sunxi_get_mon_desc(sunxi_display.monitor));
1359 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1360 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1361 sunxi_display.monitor = i;
1362 break;
1363 }
1364 }
1365 if (i > SUNXI_MONITOR_LAST)
1366 printf("Unknown monitor: '%s', falling back to '%s'\n",
1367 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001368
Hans de Goede49d27032014-12-25 13:52:04 +01001369#ifdef CONFIG_VIDEO_HDMI
1370 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1371 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1372 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001373 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001374 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001375 if (ret) {
1376 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001377 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1378 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001379 } else if (hpd) {
1380 sunxi_hdmi_shutdown();
Hans de Goedebf689342015-08-03 23:01:38 +02001381 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede49d27032014-12-25 13:52:04 +01001382 } /* else continue with hdmi/dvi without a cable connected */
1383 }
1384#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001385
Hans de Goede49d27032014-12-25 13:52:04 +01001386 switch (sunxi_display.monitor) {
1387 case sunxi_monitor_none:
1388 return NULL;
1389 case sunxi_monitor_dvi:
1390 case sunxi_monitor_hdmi:
Hans de Goedebf689342015-08-03 23:01:38 +02001391 if (!sunxi_has_hdmi()) {
1392 printf("HDMI/DVI not supported on this board\n");
1393 sunxi_display.monitor = sunxi_monitor_none;
1394 return NULL;
Hans de Goede2dae8002014-12-21 16:28:32 +01001395 }
Hans de Goedebf689342015-08-03 23:01:38 +02001396 break;
1397 case sunxi_monitor_lcd:
1398 if (!sunxi_has_lcd()) {
1399 printf("LCD not supported on this board\n");
1400 sunxi_display.monitor = sunxi_monitor_none;
1401 return NULL;
1402 }
1403 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1404 mode = &custom;
1405 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001406 case sunxi_monitor_vga:
Hans de Goedebf689342015-08-03 23:01:38 +02001407 if (!sunxi_has_vga()) {
1408 printf("VGA not supported on this board\n");
1409 sunxi_display.monitor = sunxi_monitor_none;
1410 return NULL;
1411 }
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001412 sunxi_display.depth = 18;
1413 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001414 case sunxi_monitor_composite_pal:
1415 case sunxi_monitor_composite_ntsc:
1416 case sunxi_monitor_composite_pal_m:
1417 case sunxi_monitor_composite_pal_nc:
1418 if (!sunxi_has_composite()) {
1419 printf("Composite video not supported on this board\n");
1420 sunxi_display.monitor = sunxi_monitor_none;
1421 return NULL;
1422 }
1423 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1424 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1425 mode = &composite_video_modes[0];
1426 else
1427 mode = &composite_video_modes[1];
1428 sunxi_display.depth = 24;
1429 break;
Hans de Goede75481602014-12-19 16:05:12 +01001430 }
1431
Hans de Goede58332f82015-08-05 00:06:47 +02001432 /* Yes these defaults are quite high, overscan on composite sucks... */
1433 if (overscan_x == -1)
1434 overscan_x = sunxi_is_composite() ? 32 : 0;
1435 if (overscan_y == -1)
1436 overscan_y = sunxi_is_composite() ? 20 : 0;
1437
Hans de Goede20779ec2015-02-02 18:00:53 +01001438 sunxi_display.fb_size =
1439 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goede58332f82015-08-05 00:06:47 +02001440 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1441 /* We want to keep the fb_base for simplefb page aligned, where as
1442 * the sunxi dma engines will happily accept an unaligned address. */
1443 if (overscan_offset)
1444 sunxi_display.fb_size += 0x1000;
1445
Hans de Goede20779ec2015-02-02 18:00:53 +01001446 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1447 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1448 sunxi_display.fb_size >> 10,
1449 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1450 return NULL;
1451 }
1452
Hans de Goede58332f82015-08-05 00:06:47 +02001453 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1454 mode->xres, mode->yres,
Hans de Goedef6d9d322015-08-02 16:49:29 +02001455 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goede58332f82015-08-05 00:06:47 +02001456 sunxi_get_mon_desc(sunxi_display.monitor),
1457 overscan_x, overscan_y);
Hans de Goedef6d9d322015-08-02 16:49:29 +02001458
Hans de Goede20779ec2015-02-02 18:00:53 +01001459 gd->fb_base = gd->bd->bi_dram[0].start +
1460 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001461 sunxi_engines_init();
Hans de Goede58332f82015-08-05 00:06:47 +02001462
1463 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1464 sunxi_display.fb_addr = gd->fb_base;
1465 if (overscan_offset) {
1466 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1467 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1468 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1469 flush_cache(gd->fb_base, sunxi_display.fb_size);
1470 }
1471 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001472
1473 /*
1474 * These are the only members of this structure that are used. All the
Hans de Goede58332f82015-08-05 00:06:47 +02001475 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001476 */
Hans de Goede58332f82015-08-05 00:06:47 +02001477 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001478 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1479 graphic_device->gdfBytesPP = 4;
Hans de Goede58332f82015-08-05 00:06:47 +02001480 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1481 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1482 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001483
1484 return graphic_device;
1485}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001486
1487/*
1488 * Simplefb support.
1489 */
1490#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1491int sunxi_simplefb_setup(void *blob)
1492{
1493 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1494 int offset, ret;
Hans de Goede5633a292015-02-02 17:13:29 +01001495 u64 start, size;
Hans de Goede2dae8002014-12-21 16:28:32 +01001496 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001497
Hans de Goede7cd6f922015-01-19 08:44:07 +01001498#ifdef CONFIG_MACH_SUN4I
1499#define PIPELINE_PREFIX "de_fe0-"
1500#else
1501#define PIPELINE_PREFIX
1502#endif
1503
Hans de Goede2dae8002014-12-21 16:28:32 +01001504 switch (sunxi_display.monitor) {
1505 case sunxi_monitor_none:
1506 return 0;
1507 case sunxi_monitor_dvi:
1508 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001509 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001510 break;
1511 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001512 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001513 break;
1514 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001515#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001516 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001517#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001518 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001519#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001520 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001521 case sunxi_monitor_composite_pal:
1522 case sunxi_monitor_composite_ntsc:
1523 case sunxi_monitor_composite_pal_m:
1524 case sunxi_monitor_composite_pal_nc:
1525 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1526 break;
Hans de Goede2dae8002014-12-21 16:28:32 +01001527 }
1528
1529 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001530 offset = fdt_node_offset_by_compatible(blob, -1,
1531 "allwinner,simple-framebuffer");
1532 while (offset >= 0) {
1533 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede2dae8002014-12-21 16:28:32 +01001534 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001535 if (ret == 0)
1536 break;
1537 offset = fdt_node_offset_by_compatible(blob, offset,
1538 "allwinner,simple-framebuffer");
1539 }
1540 if (offset < 0) {
1541 eprintf("Cannot setup simplefb: node not found\n");
1542 return 0; /* Keep older kernels working */
1543 }
1544
Hans de Goede5633a292015-02-02 17:13:29 +01001545 /*
1546 * Do not report the framebuffer as free RAM to the OS, note we cannot
1547 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1548 * and e.g. Linux refuses to iomap RAM on ARM, see:
1549 * linux/arch/arm/mm/ioremap.c around line 301.
1550 */
1551 start = gd->bd->bi_dram[0].start;
Hans de Goede20779ec2015-02-02 18:00:53 +01001552 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede5633a292015-02-02 17:13:29 +01001553 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1554 if (ret) {
1555 eprintf("Cannot setup simplefb: Error reserving memory\n");
1556 return ret;
1557 }
1558
Hans de Goede58332f82015-08-05 00:06:47 +02001559 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001560 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goede58332f82015-08-05 00:06:47 +02001561 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001562 if (ret)
1563 eprintf("Cannot setup simplefb: Error setting properties\n");
1564
1565 return ret;
1566}
1567#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */