blob: 9fee66a2a450b84645e855e0a0c9fc7f4593112a [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 Goede6944aff2015-10-03 15:18:33 +020018#include <axp_pmic.h>
Hans de Goede75481602014-12-19 16:05:12 +010019#include <errno.h>
Luc Verhaegen2d7a0842014-08-13 07:55:07 +020020#include <fdtdec.h>
21#include <fdt_support.h>
Hans de Goedeaad2ac22015-02-16 17:49:47 +010022#include <i2c.h>
Hans de Goede58332f82015-08-05 00:06:47 +020023#include <malloc.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020024#include <video_fb.h>
Hans de Goedebe8ec632014-12-19 13:46:33 +010025#include "videomodes.h"
Hans de Goedec1cfd512015-08-08 16:13:53 +020026#include "anx9804.h"
Hans de Goede27515b22015-01-20 09:23:36 +010027#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashka97ece832015-01-19 05:23:33 +020028#include "ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020029
Hans de Goedea7403ae2015-01-22 21:02:42 +010030#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
31#define PWM_ON 0
32#define PWM_OFF 1
33#else
34#define PWM_ON 1
35#define PWM_OFF 0
36#endif
37
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020038DECLARE_GLOBAL_DATA_PTR;
39
Hans de Goede1c092202014-12-21 14:37:45 +010040enum sunxi_monitor {
41 sunxi_monitor_none,
42 sunxi_monitor_dvi,
43 sunxi_monitor_hdmi,
44 sunxi_monitor_lcd,
45 sunxi_monitor_vga,
Hans de Goede39920c82015-08-03 19:20:26 +020046 sunxi_monitor_composite_pal,
47 sunxi_monitor_composite_ntsc,
48 sunxi_monitor_composite_pal_m,
49 sunxi_monitor_composite_pal_nc,
Hans de Goede1c092202014-12-21 14:37:45 +010050};
Hans de Goede39920c82015-08-03 19:20:26 +020051#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goede1c092202014-12-21 14:37:45 +010052
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020053struct sunxi_display {
54 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010055 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010056 unsigned int depth;
Hans de Goede58332f82015-08-05 00:06:47 +020057 unsigned int fb_addr;
Hans de Goede20779ec2015-02-02 18:00:53 +010058 unsigned int fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020059} sunxi_display;
60
Hans de Goede39920c82015-08-03 19:20:26 +020061const struct ctfb_res_modes composite_video_modes[2] = {
62 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
63 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
64 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
65};
66
Hans de Goede2fbf0912014-12-23 23:04:35 +010067#ifdef CONFIG_VIDEO_HDMI
68
Hans de Goede75481602014-12-19 16:05:12 +010069/*
70 * Wait up to 200ms for value to be set in given part of reg.
71 */
72static int await_completion(u32 *reg, u32 mask, u32 val)
73{
74 unsigned long tmo = timer_get_us() + 200000;
75
76 while ((readl(reg) & mask) != val) {
77 if (timer_get_us() > tmo) {
78 printf("DDC: timeout reading EDID\n");
79 return -ETIME;
80 }
81 }
82 return 0;
83}
84
Hans de Goede7fad8a92014-12-28 09:13:21 +010085static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020086{
87 struct sunxi_ccm_reg * const ccm =
88 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
89 struct sunxi_hdmi_reg * const hdmi =
90 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede7fad8a92014-12-28 09:13:21 +010091 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020092
93 /* Set pll3 to 300MHz */
94 clock_set_pll3(300000000);
95
96 /* Set hdmi parent to pll3 */
97 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
98 CCM_HDMI_CTRL_PLL3);
99
100 /* Set ahb gating to pass */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200101#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100102 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
103#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200104 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
105
106 /* Clock on */
107 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
108
109 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
110 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
111
Hans de Goede40f1b872014-12-20 15:15:23 +0100112 while (timer_get_us() < tmo) {
113 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
114 return 1;
115 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200116
Hans de Goede40f1b872014-12-20 15:15:23 +0100117 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100118}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200119
Hans de Goede518cef22014-12-19 15:13:57 +0100120static void sunxi_hdmi_shutdown(void)
121{
122 struct sunxi_ccm_reg * const ccm =
123 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
124 struct sunxi_hdmi_reg * const hdmi =
125 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
126
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200127 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
128 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
129 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goede44d8ae52015-04-06 20:33:34 +0200130#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100131 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
132#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200133 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200134}
135
Hans de Goede75481602014-12-19 16:05:12 +0100136static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
137{
138 struct sunxi_hdmi_reg * const hdmi =
139 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
140
141 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
142 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
143 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
144 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
145 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
146#ifndef CONFIG_MACH_SUN6I
147 writel(n, &hdmi->ddc_byte_count);
148 writel(cmnd, &hdmi->ddc_cmnd);
149#else
150 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
151#endif
152 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
153
154 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
155}
156
157static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
158{
159 struct sunxi_hdmi_reg * const hdmi =
160 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
161 int i, n;
162
163 while (count > 0) {
164 if (count > 16)
165 n = 16;
166 else
167 n = count;
168
169 if (sunxi_hdmi_ddc_do_command(
170 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
171 offset, n))
172 return -ETIME;
173
174 for (i = 0; i < n; i++)
175 *buf++ = readb(&hdmi->ddc_fifo_data);
176
177 offset += n;
178 count -= n;
179 }
180
181 return 0;
182}
183
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100184static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
185{
186 int r, retries = 2;
187
188 do {
189 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
190 if (r)
191 continue;
192 r = edid_check_checksum(buf);
193 if (r) {
194 printf("EDID block %d: checksum error%s\n",
195 block, retries ? ", retrying" : "");
196 }
197 } while (r && retries--);
198
199 return r;
200}
201
Hans de Goede1c092202014-12-21 14:37:45 +0100202static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100203{
204 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100205 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-12-19 16:05:12 +0100206 struct edid_detailed_timing *t =
207 (struct edid_detailed_timing *)edid1.monitor_details.timing;
208 struct sunxi_hdmi_reg * const hdmi =
209 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
210 struct sunxi_ccm_reg * const ccm =
211 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedef3000682014-12-20 14:31:45 +0100212 int i, r, ext_blocks = 0;
Hans de Goede75481602014-12-19 16:05:12 +0100213
214 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
215 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
216 &hdmi->pad_ctrl1);
217 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
218 &hdmi->pll_ctrl);
219 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
220
221 /* Reset i2c controller */
222 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
223 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
224 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
225 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
226 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
227 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
228 return -EIO;
229
230 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
231#ifndef CONFIG_MACH_SUN6I
232 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
233 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
234#endif
235
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100236 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-12-20 14:31:45 +0100237 if (r == 0) {
238 r = edid_check_info(&edid1);
239 if (r) {
240 printf("EDID: invalid EDID data\n");
241 r = -EINVAL;
242 }
243 }
244 if (r == 0) {
245 ext_blocks = edid1.extension_flag;
246 if (ext_blocks > 4)
247 ext_blocks = 4;
248 for (i = 0; i < ext_blocks; i++) {
249 if (sunxi_hdmi_edid_get_block(1 + i,
250 (u8 *)&cea681[i]) != 0) {
251 ext_blocks = i;
252 break;
253 }
254 }
255 }
Hans de Goede75481602014-12-19 16:05:12 +0100256
257 /* Disable DDC engine, no longer needed */
258 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
259 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
260
261 if (r)
262 return r;
263
Hans de Goede75481602014-12-19 16:05:12 +0100264 /* We want version 1.3 or 1.2 with detailed timing info */
265 if (edid1.version != 1 || (edid1.revision < 3 &&
266 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
267 printf("EDID: unsupported version %d.%d\n",
268 edid1.version, edid1.revision);
269 return -EINVAL;
270 }
271
272 /* Take the first usable detailed timing */
273 for (i = 0; i < 4; i++, t++) {
274 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
275 if (r == 0)
276 break;
277 }
278 if (i == 4) {
279 printf("EDID: no usable detailed timing found\n");
280 return -ENOENT;
281 }
282
Hans de Goedef3000682014-12-20 14:31:45 +0100283 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100284 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-12-20 14:31:45 +0100285 for (i = 0; i < ext_blocks; i++) {
286 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
287 cea681[i].revision < 2)
288 continue;
289
290 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goede1c092202014-12-21 14:37:45 +0100291 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100292 }
293
Hans de Goede75481602014-12-19 16:05:12 +0100294 return 0;
295}
296
Hans de Goede2fbf0912014-12-23 23:04:35 +0100297#endif /* CONFIG_VIDEO_HDMI */
298
Hans de Goede7cd6f922015-01-19 08:44:07 +0100299#ifdef CONFIG_MACH_SUN4I
300/*
301 * Testing has shown that on sun4i the display backend engine does not have
302 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
303 * fifo underruns. So on sun4i we use the display frontend engine to do the
304 * dma from memory, as the frontend does have deep enough fifo-s.
305 */
306
307static const u32 sun4i_vert_coef[32] = {
308 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
309 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
310 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
311 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
312 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
313 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
314 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
315 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
316};
317
318static const u32 sun4i_horz_coef[64] = {
319 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
320 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
321 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
322 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
323 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
324 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
325 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
326 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
327 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
328 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
329 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
330 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
331 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
332 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
333 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
334 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
335};
336
337static void sunxi_frontend_init(void)
338{
339 struct sunxi_ccm_reg * const ccm =
340 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
341 struct sunxi_de_fe_reg * const de_fe =
342 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
343 int i;
344
345 /* Clocks on */
346 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
347 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
348 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
349
350 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
351
352 for (i = 0; i < 32; i++) {
353 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
354 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
355 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
356 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
357 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
358 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
359 }
360
361 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
362}
363
364static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
365 unsigned int address)
366{
367 struct sunxi_de_fe_reg * const de_fe =
368 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
369
370 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
371 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
372 writel(mode->xres * 4, &de_fe->ch0_stride);
373 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
374 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
375
376 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
377 &de_fe->ch0_insize);
378 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
379 &de_fe->ch0_outsize);
380 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
381 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
382
383 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
384 &de_fe->ch1_insize);
385 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
386 &de_fe->ch1_outsize);
387 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
388 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
389
390 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
391}
392
393static void sunxi_frontend_enable(void)
394{
395 struct sunxi_de_fe_reg * const de_fe =
396 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
397
398 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
399}
400#else
401static void sunxi_frontend_init(void) {}
402static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
403 unsigned int address) {}
404static void sunxi_frontend_enable(void) {}
405#endif
406
Hans de Goede39920c82015-08-03 19:20:26 +0200407static bool sunxi_is_composite(void)
408{
409 switch (sunxi_display.monitor) {
410 case sunxi_monitor_none:
411 case sunxi_monitor_dvi:
412 case sunxi_monitor_hdmi:
413 case sunxi_monitor_lcd:
414 case sunxi_monitor_vga:
415 return false;
416 case sunxi_monitor_composite_pal:
417 case sunxi_monitor_composite_ntsc:
418 case sunxi_monitor_composite_pal_m:
419 case sunxi_monitor_composite_pal_nc:
420 return true;
421 }
422
423 return false; /* Never reached */
424}
425
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200426/*
427 * This is the entity that mixes and matches the different layers and inputs.
428 * Allwinner calls it the back-end, but i like composer better.
429 */
430static void sunxi_composer_init(void)
431{
432 struct sunxi_ccm_reg * const ccm =
433 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
434 struct sunxi_de_be_reg * const de_be =
435 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
436 int i;
437
Hans de Goede7cd6f922015-01-19 08:44:07 +0100438 sunxi_frontend_init();
439
Hans de Goede44d8ae52015-04-06 20:33:34 +0200440#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100441 /* Reset off */
442 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
443#endif
444
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200445 /* Clocks on */
446 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100447#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200448 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100449#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200450 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
451
452 /* Engine bug, clear registers after reset */
453 for (i = 0x0800; i < 0x1000; i += 4)
454 writel(0, SUNXI_DE_BE0_BASE + i);
455
456 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
457}
458
Hans de Goede39920c82015-08-03 19:20:26 +0200459static u32 sunxi_rgb2yuv_coef[12] = {
460 0x00000107, 0x00000204, 0x00000064, 0x00000108,
461 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
462 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
463};
464
Hans de Goedebe8ec632014-12-19 13:46:33 +0100465static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200466 unsigned int address)
467{
468 struct sunxi_de_be_reg * const de_be =
469 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goede39920c82015-08-03 19:20:26 +0200470 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200471
Hans de Goede7cd6f922015-01-19 08:44:07 +0100472 sunxi_frontend_mode_set(mode, address);
473
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200474 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
475 &de_be->disp_size);
476 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
477 &de_be->layer0_size);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100478#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200479 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
480 writel(address << 3, &de_be->layer0_addr_low32b);
481 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100482#else
483 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
484#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200485 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
486
487 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200488 if (mode->vmode == FB_VMODE_INTERLACED)
489 setbits_le32(&de_be->mode,
Hans de Goeded8d07992015-08-06 12:08:33 +0200490#ifndef CONFIG_MACH_SUN5I
Hans de Goedef6d9d322015-08-02 16:49:29 +0200491 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goeded8d07992015-08-06 12:08:33 +0200492#endif
Hans de Goedef6d9d322015-08-02 16:49:29 +0200493 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goede39920c82015-08-03 19:20:26 +0200494
495 if (sunxi_is_composite()) {
496 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
497 &de_be->output_color_ctrl);
498 for (i = 0; i < 12; i++)
499 writel(sunxi_rgb2yuv_coef[i],
500 &de_be->output_color_coef[i]);
501 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200502}
503
Hans de Goede0e045212014-12-21 14:49:34 +0100504static void sunxi_composer_enable(void)
505{
506 struct sunxi_de_be_reg * const de_be =
507 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
508
Hans de Goede7cd6f922015-01-19 08:44:07 +0100509 sunxi_frontend_enable();
510
Hans de Goede0e045212014-12-21 14:49:34 +0100511 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
512 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
513}
514
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200515/*
516 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
517 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100518static void sunxi_lcdc_pll_set(int tcon, int dotclock,
519 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200520{
521 struct sunxi_ccm_reg * const ccm =
522 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100523 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200524 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
525 int best_double = 0;
Hans de Goedefb685d32015-08-08 14:08:21 +0200526 bool use_mipi_pll = false;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200527
Hans de Goede5489ebc2014-12-21 16:27:45 +0100528 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100529#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100530 min_m = 6;
531 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100532#endif
533#ifdef CONFIG_VIDEO_LCD_IF_LVDS
534 min_m = max_m = 7;
535#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100536 } else {
537 min_m = 1;
538 max_m = 15;
539 }
540
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200541 /*
542 * Find the lowest divider resulting in a matching clock, if there
543 * is no match, pick the closest lower clock, as monitors tend to
544 * not sync to higher frequencies.
545 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100546 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200547 n = (m * dotclock) / 3000;
548
549 if ((n >= 9) && (n <= 127)) {
550 value = (3000 * n) / m;
551 diff = dotclock - value;
552 if (diff < best_diff) {
553 best_diff = diff;
554 best_m = m;
555 best_n = n;
556 best_double = 0;
557 }
558 }
559
560 /* These are just duplicates */
561 if (!(m & 1))
562 continue;
563
564 n = (m * dotclock) / 6000;
565 if ((n >= 9) && (n <= 127)) {
566 value = (6000 * n) / m;
567 diff = dotclock - value;
568 if (diff < best_diff) {
569 best_diff = diff;
570 best_m = m;
571 best_n = n;
572 best_double = 1;
573 }
574 }
575 }
576
Hans de Goedefb685d32015-08-08 14:08:21 +0200577#ifdef CONFIG_MACH_SUN6I
578 /*
579 * Use the MIPI pll if we've been unable to find any matching setting
580 * for PLL3, this happens with high dotclocks because of min_m = 6.
581 */
582 if (tcon == 0 && best_n == 0) {
583 use_mipi_pll = true;
584 best_m = 6; /* Minimum m for tcon0 */
585 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200586
Hans de Goedefb685d32015-08-08 14:08:21 +0200587 if (use_mipi_pll) {
588 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
589 clock_set_mipi_pll(best_m * dotclock * 1000);
590 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
591 dotclock, clock_get_mipi_pll() / best_m / 1000);
592 } else
593#endif
594 {
595 clock_set_pll3(best_n * 3000000);
596 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
597 dotclock,
598 (best_double + 1) * clock_get_pll3() / best_m / 1000,
599 best_double + 1, best_n, best_m);
600 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200601
Hans de Goede5489ebc2014-12-21 16:27:45 +0100602 if (tcon == 0) {
Hans de Goedefb685d32015-08-08 14:08:21 +0200603 u32 pll;
604
605 if (use_mipi_pll)
606 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
607 else if (best_double)
608 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
609 else
610 pll = CCM_LCD_CH0_CTRL_PLL3;
611
612 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
Hans de Goede5489ebc2014-12-21 16:27:45 +0100613 &ccm->lcd0_ch0_clk_cfg);
614 } else {
615 writel(CCM_LCD_CH1_CTRL_GATE |
616 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
617 CCM_LCD_CH1_CTRL_PLL3) |
618 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goede39920c82015-08-03 19:20:26 +0200619 if (sunxi_is_composite())
620 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
621 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goede5489ebc2014-12-21 16:27:45 +0100622 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200623
624 *clk_div = best_m;
625 *clk_double = best_double;
626}
627
628static void sunxi_lcdc_init(void)
629{
630 struct sunxi_ccm_reg * const ccm =
631 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
632 struct sunxi_lcdc_reg * const lcdc =
633 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
634
635 /* Reset off */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200636#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100637 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
638#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200639 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100640#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200641
642 /* Clock on */
643 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100644#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede83edb2a2015-05-14 18:52:54 +0200645#ifdef CONFIG_SUNXI_GEN_SUN6I
646 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
647#else
Hans de Goede213480e2015-01-01 22:04:34 +0100648 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
649#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200650#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200651
652 /* Init lcdc */
653 writel(0, &lcdc->ctrl); /* Disable tcon */
654 writel(0, &lcdc->int0); /* Disable all interrupts */
655
656 /* Disable tcon0 dot clock */
657 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
658
659 /* Set all io lines to tristate */
660 writel(0xffffffff, &lcdc->tcon0_io_tristate);
661 writel(0xffffffff, &lcdc->tcon1_io_tristate);
662}
663
Hans de Goede0e045212014-12-21 14:49:34 +0100664static void sunxi_lcdc_enable(void)
665{
666 struct sunxi_lcdc_reg * const lcdc =
667 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
668
669 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede213480e2015-01-01 22:04:34 +0100670#ifdef CONFIG_VIDEO_LCD_IF_LVDS
671 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
672 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede83edb2a2015-05-14 18:52:54 +0200673#ifdef CONFIG_SUNXI_GEN_SUN6I
674 udelay(2); /* delay at least 1200 ns */
675 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
676 udelay(2); /* delay at least 1200 ns */
677 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
678 if (sunxi_display.depth == 18)
679 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
680 else
681 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
682#else
Hans de Goede213480e2015-01-01 22:04:34 +0100683 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
684 udelay(2); /* delay at least 1200 ns */
685 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
686 udelay(1); /* delay at least 120 ns */
687 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
688 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
689#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200690#endif
Hans de Goede0e045212014-12-21 14:49:34 +0100691}
692
Hans de Goede2dae8002014-12-21 16:28:32 +0100693static void sunxi_lcdc_panel_enable(void)
694{
Hans de Goede242e3d82015-02-16 17:26:41 +0100695 int pin, reset_pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100696
697 /*
698 * Start with backlight disabled to avoid the screen flashing to
699 * white while the lcd inits.
700 */
701 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200702 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100703 gpio_request(pin, "lcd_backlight_enable");
704 gpio_direction_output(pin, 0);
705 }
706
707 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200708 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100709 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goedea7403ae2015-01-22 21:02:42 +0100710 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-12-21 16:28:32 +0100711 }
712
Hans de Goede242e3d82015-02-16 17:26:41 +0100713 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede15728192015-04-22 17:45:59 +0200714 if (reset_pin >= 0) {
Hans de Goede242e3d82015-02-16 17:26:41 +0100715 gpio_request(reset_pin, "lcd_reset");
716 gpio_direction_output(reset_pin, 0); /* Assert reset */
717 }
718
Hans de Goede2dae8002014-12-21 16:28:32 +0100719 /* Give the backlight some time to turn off and power up the panel. */
720 mdelay(40);
721 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede15728192015-04-22 17:45:59 +0200722 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100723 gpio_request(pin, "lcd_power");
724 gpio_direction_output(pin, 1);
725 }
Hans de Goede242e3d82015-02-16 17:26:41 +0100726
Hans de Goede15728192015-04-22 17:45:59 +0200727 if (reset_pin >= 0)
Hans de Goede242e3d82015-02-16 17:26:41 +0100728 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede2dae8002014-12-21 16:28:32 +0100729}
730
731static void sunxi_lcdc_backlight_enable(void)
732{
733 int pin;
734
735 /*
736 * We want to have scanned out at least one frame before enabling the
737 * backlight to avoid the screen flashing to white when we enable it.
738 */
739 mdelay(40);
740
741 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200742 if (pin >= 0)
Hans de Goede2dae8002014-12-21 16:28:32 +0100743 gpio_direction_output(pin, 1);
744
745 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200746 if (pin >= 0)
Hans de Goedea7403ae2015-01-22 21:02:42 +0100747 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-12-21 16:28:32 +0100748}
749
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200750static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede2dae8002014-12-21 16:28:32 +0100751{
752 int delay;
753
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200754 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200755 if (mode->vmode == FB_VMODE_INTERLACED)
756 delay /= 2;
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200757 if (tcon == 1)
758 delay -= 2;
759
Hans de Goede2dae8002014-12-21 16:28:32 +0100760 return (delay > 30) ? 30 : delay;
761}
762
Hans de Goedefb75d972015-01-25 15:33:07 +0100763static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
764 bool for_ext_vga_dac)
Hans de Goede2dae8002014-12-21 16:28:32 +0100765{
766 struct sunxi_lcdc_reg * const lcdc =
767 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
768 int bp, clk_delay, clk_div, clk_double, pin, total, val;
769
Hans de Goedec1cfd512015-08-08 16:13:53 +0200770 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Hans de Goede213480e2015-01-01 22:04:34 +0100771#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100772 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100773#endif
774#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100775 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede213480e2015-01-01 22:04:34 +0100776#endif
Hans de Goedec1cfd512015-08-08 16:13:53 +0200777#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
778 sunxi_gpio_set_drv(pin, 3);
779#endif
780 }
Hans de Goede2dae8002014-12-21 16:28:32 +0100781
782 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
783
784 /* Use tcon0 */
785 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
786 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
787
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200788 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede2dae8002014-12-21 16:28:32 +0100789 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
790 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
791
792 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
793 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
794
795 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
796 &lcdc->tcon0_timing_active);
797
798 bp = mode->hsync_len + mode->left_margin;
799 total = mode->xres + mode->right_margin + bp;
800 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
801 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
802
803 bp = mode->vsync_len + mode->upper_margin;
804 total = mode->yres + mode->lower_margin + bp;
805 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
806 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
807
Hans de Goede213480e2015-01-01 22:04:34 +0100808#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100809 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
810 &lcdc->tcon0_timing_sync);
811
Hans de Goede2dae8002014-12-21 16:28:32 +0100812 writel(0, &lcdc->tcon0_hv_intf);
813 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100814#endif
815#ifdef CONFIG_VIDEO_LCD_IF_LVDS
816 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede83edb2a2015-05-14 18:52:54 +0200817 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
818 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100819#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100820
821 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
822 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
823 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
824 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
825 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
826 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
827 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
828 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
829 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
830 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
831 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
832 writel(((sunxi_display.depth == 18) ?
833 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
834 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
835 &lcdc->tcon0_frm_ctrl);
836 }
837
Hans de Goede65150322015-01-13 13:21:46 +0100838 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100839 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
840 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
841 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
842 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goedefb75d972015-01-25 15:33:07 +0100843
844#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
845 if (for_ext_vga_dac)
846 val = 0;
847#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100848 writel(val, &lcdc->tcon0_io_polarity);
849
850 writel(0, &lcdc->tcon0_io_tristate);
851}
852
Hans de Goede39920c82015-08-03 19:20:26 +0200853#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede0e045212014-12-21 14:49:34 +0100854static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100855 int *clk_div, int *clk_double,
856 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200857{
858 struct sunxi_lcdc_reg * const lcdc =
859 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200860 int bp, clk_delay, total, val, yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200861
862 /* Use tcon1 */
863 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
864 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
865
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200866 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200867 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedef6d9d322015-08-02 16:49:29 +0200868 ((mode->vmode == FB_VMODE_INTERLACED) ?
869 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
Hans de Goede6741cc72014-12-24 19:50:11 +0100870 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200871
Hans de Goedef6d9d322015-08-02 16:49:29 +0200872 yres = mode->yres;
873 if (mode->vmode == FB_VMODE_INTERLACED)
874 yres /= 2;
875 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200876 &lcdc->tcon1_timing_source);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200877 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200878 &lcdc->tcon1_timing_scale);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200879 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200880 &lcdc->tcon1_timing_out);
881
882 bp = mode->hsync_len + mode->left_margin;
883 total = mode->xres + mode->right_margin + bp;
884 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
885 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
886
887 bp = mode->vsync_len + mode->upper_margin;
888 total = mode->yres + mode->lower_margin + bp;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200889 if (mode->vmode == FB_VMODE_NONINTERLACED)
890 total *= 2;
891 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200892 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
893
894 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
895 &lcdc->tcon1_timing_sync);
896
Hans de Goede3ffbe472014-12-27 15:19:23 +0100897 if (use_portd_hvsync) {
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100898 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
899 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goede3ffbe472014-12-27 15:19:23 +0100900
901 val = 0;
902 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
903 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
904 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
905 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
906 writel(val, &lcdc->tcon1_io_polarity);
907
908 clrbits_le32(&lcdc->tcon1_io_tristate,
909 SUNXI_LCDC_TCON_VSYNC_MASK |
910 SUNXI_LCDC_TCON_HSYNC_MASK);
911 }
Hans de Goeded8d07992015-08-06 12:08:33 +0200912
913#ifdef CONFIG_MACH_SUN5I
914 if (sunxi_is_composite())
915 clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK,
916 SUNXI_LCDC_MUX_CTRL_SRC0(1));
917#endif
918
Hans de Goede5489ebc2014-12-21 16:27:45 +0100919 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200920}
Hans de Goede39920c82015-08-03 19:20:26 +0200921#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +0100922
923#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200924
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100925static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
926{
927 struct sunxi_hdmi_reg * const hdmi =
928 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
929 u8 checksum = 0;
930 u8 avi_info_frame[17] = {
931 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
932 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
933 0x00
934 };
935 u8 vendor_info_frame[19] = {
936 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
938 0x00, 0x00, 0x00
939 };
940 int i;
941
942 if (mode->pixclock_khz <= 27000)
943 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
944 else
945 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
946
947 if (mode->xres * 100 / mode->yres < 156)
948 avi_info_frame[5] |= 0x18; /* 4 : 3 */
949 else
950 avi_info_frame[5] |= 0x28; /* 16 : 9 */
951
952 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
953 checksum += avi_info_frame[i];
954
955 avi_info_frame[3] = 0x100 - checksum;
956
957 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
958 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
959
960 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
961 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
962
963 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
964 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
965
966 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
967 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
968
969 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
970}
971
Hans de Goedebe8ec632014-12-19 13:46:33 +0100972static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100973 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200974{
975 struct sunxi_hdmi_reg * const hdmi =
976 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
977 int x, y;
978
979 /* Write clear interrupt status bits */
980 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
981
Hans de Goede1c092202014-12-21 14:37:45 +0100982 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100983 sunxi_hdmi_setup_info_frames(mode);
984
Hans de Goede876aaaf2014-12-20 13:51:16 +0100985 /* Set input sync enable */
986 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
987
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200988 /* Init various registers, select pll3 as clock source */
989 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
990 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
991 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
992 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
993 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
994
995 /* Setup clk div and doubler */
996 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
997 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
998 if (!clk_double)
999 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
1000
1001 /* Setup timing registers */
1002 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
1003 &hdmi->video_size);
1004
1005 x = mode->hsync_len + mode->left_margin;
1006 y = mode->vsync_len + mode->upper_margin;
1007 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
1008
1009 x = mode->right_margin;
1010 y = mode->lower_margin;
1011 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
1012
1013 x = mode->hsync_len;
1014 y = mode->vsync_len;
1015 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
1016
1017 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
1018 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
1019
1020 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
1021 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
1022}
1023
Hans de Goede0e045212014-12-21 14:49:34 +01001024static void sunxi_hdmi_enable(void)
1025{
1026 struct sunxi_hdmi_reg * const hdmi =
1027 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
1028
1029 udelay(100);
1030 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
1031}
1032
Hans de Goede2fbf0912014-12-23 23:04:35 +01001033#endif /* CONFIG_VIDEO_HDMI */
1034
Hans de Goede39920c82015-08-03 19:20:26 +02001035#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goeded9786d22014-12-25 13:58:06 +01001036
Hans de Goede39920c82015-08-03 19:20:26 +02001037static void sunxi_tvencoder_mode_set(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001038{
1039 struct sunxi_ccm_reg * const ccm =
1040 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1041 struct sunxi_tve_reg * const tve =
1042 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1043
Hans de Goeded8d07992015-08-06 12:08:33 +02001044 /* Reset off */
1045 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goeded9786d22014-12-25 13:58:06 +01001046 /* Clock on */
1047 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1048
Hans de Goede39920c82015-08-03 19:20:26 +02001049 switch (sunxi_display.monitor) {
1050 case sunxi_monitor_vga:
1051 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1052 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1053 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
1054 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1055 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1056 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1057 break;
1058 case sunxi_monitor_composite_pal_nc:
1059 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1060 /* Fall through */
1061 case sunxi_monitor_composite_pal:
1062 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1063 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1064 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1065 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1066 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1067 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1068 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1069 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1070 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1071 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1072 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1073 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1074 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1075 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1076 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1077 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1078 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1079 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1080 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1081 break;
1082 case sunxi_monitor_composite_pal_m:
1083 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1084 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1085 /* Fall through */
1086 case sunxi_monitor_composite_ntsc:
1087 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1088 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1089 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1090 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1091 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1092 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1093 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1094 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1095 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1096 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1097 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1098 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1099 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1100 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1101 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1102 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1103 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1104 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1105 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1106 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1107 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1108 break;
1109 case sunxi_monitor_none:
1110 case sunxi_monitor_dvi:
1111 case sunxi_monitor_hdmi:
1112 case sunxi_monitor_lcd:
1113 break;
1114 }
Hans de Goeded9786d22014-12-25 13:58:06 +01001115}
1116
Hans de Goede39920c82015-08-03 19:20:26 +02001117static void sunxi_tvencoder_enable(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001118{
1119 struct sunxi_tve_reg * const tve =
1120 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1121
1122 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1123}
1124
Hans de Goede39920c82015-08-03 19:20:26 +02001125#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +01001126
Hans de Goedee8400792014-12-23 18:39:52 +01001127static void sunxi_drc_init(void)
1128{
Hans de Goede44d8ae52015-04-06 20:33:34 +02001129#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedee8400792014-12-23 18:39:52 +01001130 struct sunxi_ccm_reg * const ccm =
1131 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1132
1133 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar8c3dacf2015-03-01 23:47:48 +05301134#ifdef CONFIG_MACH_SUN8I_A33
1135 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1136#endif
Hans de Goedee8400792014-12-23 18:39:52 +01001137 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1138 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1139#endif
1140}
1141
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001142#ifdef CONFIG_VIDEO_VGA_VIA_LCD
1143static void sunxi_vga_external_dac_enable(void)
1144{
1145 int pin;
1146
1147 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede15728192015-04-22 17:45:59 +02001148 if (pin >= 0) {
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001149 gpio_request(pin, "vga_enable");
1150 gpio_direction_output(pin, 1);
1151 }
1152}
1153#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1154
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001155#ifdef CONFIG_VIDEO_LCD_SSD2828
1156static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1157{
1158 struct ssd2828_config cfg = {
1159 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1160 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1161 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1162 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1163 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1164 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1165 .ssd2828_color_depth = 24,
1166#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1167 .mipi_dsi_number_of_data_lanes = 4,
1168 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1169 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1170 .mipi_dsi_delay_after_set_display_on_ms = 200
1171#else
1172#error MIPI LCD panel needs configuration parameters
1173#endif
1174 };
1175
1176 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1177 printf("SSD2828: SPI pins are not properly configured\n");
1178 return 1;
1179 }
1180 if (cfg.reset_pin == -1) {
1181 printf("SSD2828: Reset pin is not properly configured\n");
1182 return 1;
1183 }
1184
1185 return ssd2828_init(&cfg, mode);
1186}
1187#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1188
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001189static void sunxi_engines_init(void)
1190{
1191 sunxi_composer_init();
1192 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +01001193 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001194}
1195
Hans de Goede1c092202014-12-21 14:37:45 +01001196static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +01001197 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001198{
Hans de Goeded9786d22014-12-25 13:58:06 +01001199 int __maybe_unused clk_div, clk_double;
1200
Hans de Goede0e045212014-12-21 14:49:34 +01001201 switch (sunxi_display.monitor) {
1202 case sunxi_monitor_none:
1203 break;
1204 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001205 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001206#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001207 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001208 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001209 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1210 sunxi_composer_enable();
1211 sunxi_lcdc_enable();
1212 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001213#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001214 break;
1215 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001216 sunxi_lcdc_panel_enable();
Hans de Goedec1cfd512015-08-08 16:13:53 +02001217 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1218 /*
1219 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goede6944aff2015-10-03 15:18:33 +02001220 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goedec1cfd512015-08-08 16:13:53 +02001221 * to avoid turning this on when using hdmi output.
1222 */
Hans de Goede6944aff2015-10-03 15:18:33 +02001223 axp_set_eldo(3, 1800);
Hans de Goedec1cfd512015-08-08 16:13:53 +02001224 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1225 ANX9804_DATA_RATE_1620M,
1226 sunxi_display.depth);
1227 }
Hans de Goede27515b22015-01-20 09:23:36 +01001228 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1229 mdelay(50); /* Wait for lcd controller power on */
1230 hitachi_tx18d42vm_init();
1231 }
Hans de Goedeaad2ac22015-02-16 17:49:47 +01001232 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1233 unsigned int orig_i2c_bus = i2c_get_bus_num();
1234 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1235 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1236 i2c_set_bus_num(orig_i2c_bus);
1237 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001238 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001239 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede2dae8002014-12-21 16:28:32 +01001240 sunxi_composer_enable();
1241 sunxi_lcdc_enable();
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001242#ifdef CONFIG_VIDEO_LCD_SSD2828
1243 sunxi_ssd2828_init(mode);
1244#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001245 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001246 break;
1247 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001248#ifdef CONFIG_VIDEO_VGA
1249 sunxi_composer_mode_set(mode, address);
1250 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goede39920c82015-08-03 19:20:26 +02001251 sunxi_tvencoder_mode_set();
Hans de Goeded9786d22014-12-25 13:58:06 +01001252 sunxi_composer_enable();
1253 sunxi_lcdc_enable();
Hans de Goede39920c82015-08-03 19:20:26 +02001254 sunxi_tvencoder_enable();
Hans de Goeded9786d22014-12-25 13:58:06 +01001255#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001256 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001257 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001258 sunxi_composer_enable();
1259 sunxi_lcdc_enable();
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001260 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001261#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001262 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001263 case sunxi_monitor_composite_pal:
1264 case sunxi_monitor_composite_ntsc:
1265 case sunxi_monitor_composite_pal_m:
1266 case sunxi_monitor_composite_pal_nc:
1267#ifdef CONFIG_VIDEO_COMPOSITE
1268 sunxi_composer_mode_set(mode, address);
1269 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1270 sunxi_tvencoder_mode_set();
1271 sunxi_composer_enable();
1272 sunxi_lcdc_enable();
1273 sunxi_tvencoder_enable();
1274#endif
1275 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001276 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001277}
1278
Hans de Goede1c092202014-12-21 14:37:45 +01001279static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1280{
1281 switch (monitor) {
Hans de Goede39920c82015-08-03 19:20:26 +02001282 case sunxi_monitor_none: return "none";
1283 case sunxi_monitor_dvi: return "dvi";
1284 case sunxi_monitor_hdmi: return "hdmi";
1285 case sunxi_monitor_lcd: return "lcd";
1286 case sunxi_monitor_vga: return "vga";
1287 case sunxi_monitor_composite_pal: return "composite-pal";
1288 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1289 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1290 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goede1c092202014-12-21 14:37:45 +01001291 }
1292 return NULL; /* never reached */
1293}
1294
Hans de Goede5633a292015-02-02 17:13:29 +01001295ulong board_get_usable_ram_top(ulong total_size)
1296{
1297 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1298}
1299
Hans de Goedebf689342015-08-03 23:01:38 +02001300static bool sunxi_has_hdmi(void)
1301{
1302#ifdef CONFIG_VIDEO_HDMI
1303 return true;
1304#else
1305 return false;
1306#endif
1307}
1308
1309static bool sunxi_has_lcd(void)
1310{
1311 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1312
1313 return lcd_mode[0] != 0;
1314}
1315
1316static bool sunxi_has_vga(void)
1317{
1318#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1319 return true;
1320#else
1321 return false;
1322#endif
1323}
1324
Hans de Goede39920c82015-08-03 19:20:26 +02001325static bool sunxi_has_composite(void)
1326{
1327#ifdef CONFIG_VIDEO_COMPOSITE
1328 return true;
1329#else
1330 return false;
1331#endif
1332}
1333
Hans de Goedebf689342015-08-03 23:01:38 +02001334static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1335{
1336 if (allow_hdmi && sunxi_has_hdmi())
1337 return sunxi_monitor_dvi;
1338 else if (sunxi_has_lcd())
1339 return sunxi_monitor_lcd;
1340 else if (sunxi_has_vga())
1341 return sunxi_monitor_vga;
Hans de Goede39920c82015-08-03 19:20:26 +02001342 else if (sunxi_has_composite())
1343 return sunxi_monitor_composite_pal;
Hans de Goedebf689342015-08-03 23:01:38 +02001344 else
1345 return sunxi_monitor_none;
1346}
1347
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001348void *video_hw_init(void)
1349{
1350 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001351 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001352 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001353 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001354#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001355 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001356#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001357 int i, overscan_offset, overscan_x, overscan_y;
1358 unsigned int fb_dma_addr;
Hans de Goede1c092202014-12-21 14:37:45 +01001359 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001360 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001361
1362 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1363
Hans de Goede2dae8002014-12-21 16:28:32 +01001364 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1365 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001366#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001367 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001368 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001369 edid = video_get_option_int(options, "edid", 1);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001370#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001371 overscan_x = video_get_option_int(options, "overscan_x", -1);
1372 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedebf689342015-08-03 23:01:38 +02001373 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goede1c092202014-12-21 14:37:45 +01001374 video_get_option_string(options, "monitor", mon, sizeof(mon),
1375 sunxi_get_mon_desc(sunxi_display.monitor));
1376 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1377 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1378 sunxi_display.monitor = i;
1379 break;
1380 }
1381 }
1382 if (i > SUNXI_MONITOR_LAST)
1383 printf("Unknown monitor: '%s', falling back to '%s'\n",
1384 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001385
Hans de Goede49d27032014-12-25 13:52:04 +01001386#ifdef CONFIG_VIDEO_HDMI
1387 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1388 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1389 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001390 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001391 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001392 if (ret) {
1393 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001394 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1395 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001396 } else if (hpd) {
1397 sunxi_hdmi_shutdown();
Hans de Goedebf689342015-08-03 23:01:38 +02001398 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede49d27032014-12-25 13:52:04 +01001399 } /* else continue with hdmi/dvi without a cable connected */
1400 }
1401#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001402
Hans de Goede49d27032014-12-25 13:52:04 +01001403 switch (sunxi_display.monitor) {
1404 case sunxi_monitor_none:
1405 return NULL;
1406 case sunxi_monitor_dvi:
1407 case sunxi_monitor_hdmi:
Hans de Goedebf689342015-08-03 23:01:38 +02001408 if (!sunxi_has_hdmi()) {
1409 printf("HDMI/DVI not supported on this board\n");
1410 sunxi_display.monitor = sunxi_monitor_none;
1411 return NULL;
Hans de Goede2dae8002014-12-21 16:28:32 +01001412 }
Hans de Goedebf689342015-08-03 23:01:38 +02001413 break;
1414 case sunxi_monitor_lcd:
1415 if (!sunxi_has_lcd()) {
1416 printf("LCD not supported on this board\n");
1417 sunxi_display.monitor = sunxi_monitor_none;
1418 return NULL;
1419 }
1420 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1421 mode = &custom;
1422 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001423 case sunxi_monitor_vga:
Hans de Goedebf689342015-08-03 23:01:38 +02001424 if (!sunxi_has_vga()) {
1425 printf("VGA not supported on this board\n");
1426 sunxi_display.monitor = sunxi_monitor_none;
1427 return NULL;
1428 }
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001429 sunxi_display.depth = 18;
1430 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001431 case sunxi_monitor_composite_pal:
1432 case sunxi_monitor_composite_ntsc:
1433 case sunxi_monitor_composite_pal_m:
1434 case sunxi_monitor_composite_pal_nc:
1435 if (!sunxi_has_composite()) {
1436 printf("Composite video not supported on this board\n");
1437 sunxi_display.monitor = sunxi_monitor_none;
1438 return NULL;
1439 }
1440 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1441 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1442 mode = &composite_video_modes[0];
1443 else
1444 mode = &composite_video_modes[1];
1445 sunxi_display.depth = 24;
1446 break;
Hans de Goede75481602014-12-19 16:05:12 +01001447 }
1448
Hans de Goede58332f82015-08-05 00:06:47 +02001449 /* Yes these defaults are quite high, overscan on composite sucks... */
1450 if (overscan_x == -1)
1451 overscan_x = sunxi_is_composite() ? 32 : 0;
1452 if (overscan_y == -1)
1453 overscan_y = sunxi_is_composite() ? 20 : 0;
1454
Hans de Goede20779ec2015-02-02 18:00:53 +01001455 sunxi_display.fb_size =
1456 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goede58332f82015-08-05 00:06:47 +02001457 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1458 /* We want to keep the fb_base for simplefb page aligned, where as
1459 * the sunxi dma engines will happily accept an unaligned address. */
1460 if (overscan_offset)
1461 sunxi_display.fb_size += 0x1000;
1462
Hans de Goede20779ec2015-02-02 18:00:53 +01001463 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1464 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1465 sunxi_display.fb_size >> 10,
1466 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1467 return NULL;
1468 }
1469
Hans de Goede58332f82015-08-05 00:06:47 +02001470 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1471 mode->xres, mode->yres,
Hans de Goedef6d9d322015-08-02 16:49:29 +02001472 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goede58332f82015-08-05 00:06:47 +02001473 sunxi_get_mon_desc(sunxi_display.monitor),
1474 overscan_x, overscan_y);
Hans de Goedef6d9d322015-08-02 16:49:29 +02001475
Hans de Goede20779ec2015-02-02 18:00:53 +01001476 gd->fb_base = gd->bd->bi_dram[0].start +
1477 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001478 sunxi_engines_init();
Hans de Goede58332f82015-08-05 00:06:47 +02001479
1480 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1481 sunxi_display.fb_addr = gd->fb_base;
1482 if (overscan_offset) {
1483 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1484 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1485 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1486 flush_cache(gd->fb_base, sunxi_display.fb_size);
1487 }
1488 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001489
1490 /*
1491 * These are the only members of this structure that are used. All the
Hans de Goede58332f82015-08-05 00:06:47 +02001492 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001493 */
Hans de Goede58332f82015-08-05 00:06:47 +02001494 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001495 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1496 graphic_device->gdfBytesPP = 4;
Hans de Goede58332f82015-08-05 00:06:47 +02001497 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1498 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1499 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001500
1501 return graphic_device;
1502}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001503
1504/*
1505 * Simplefb support.
1506 */
1507#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1508int sunxi_simplefb_setup(void *blob)
1509{
1510 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1511 int offset, ret;
Hans de Goede5633a292015-02-02 17:13:29 +01001512 u64 start, size;
Hans de Goede2dae8002014-12-21 16:28:32 +01001513 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001514
Hans de Goede7cd6f922015-01-19 08:44:07 +01001515#ifdef CONFIG_MACH_SUN4I
1516#define PIPELINE_PREFIX "de_fe0-"
1517#else
1518#define PIPELINE_PREFIX
1519#endif
1520
Hans de Goede2dae8002014-12-21 16:28:32 +01001521 switch (sunxi_display.monitor) {
1522 case sunxi_monitor_none:
1523 return 0;
1524 case sunxi_monitor_dvi:
1525 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001526 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001527 break;
1528 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001529 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001530 break;
1531 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001532#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001533 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001534#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001535 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001536#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001537 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001538 case sunxi_monitor_composite_pal:
1539 case sunxi_monitor_composite_ntsc:
1540 case sunxi_monitor_composite_pal_m:
1541 case sunxi_monitor_composite_pal_nc:
1542 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1543 break;
Hans de Goede2dae8002014-12-21 16:28:32 +01001544 }
1545
1546 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001547 offset = fdt_node_offset_by_compatible(blob, -1,
1548 "allwinner,simple-framebuffer");
1549 while (offset >= 0) {
1550 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede2dae8002014-12-21 16:28:32 +01001551 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001552 if (ret == 0)
1553 break;
1554 offset = fdt_node_offset_by_compatible(blob, offset,
1555 "allwinner,simple-framebuffer");
1556 }
1557 if (offset < 0) {
1558 eprintf("Cannot setup simplefb: node not found\n");
1559 return 0; /* Keep older kernels working */
1560 }
1561
Hans de Goede5633a292015-02-02 17:13:29 +01001562 /*
1563 * Do not report the framebuffer as free RAM to the OS, note we cannot
1564 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1565 * and e.g. Linux refuses to iomap RAM on ARM, see:
1566 * linux/arch/arm/mm/ioremap.c around line 301.
1567 */
1568 start = gd->bd->bi_dram[0].start;
Hans de Goede20779ec2015-02-02 18:00:53 +01001569 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede5633a292015-02-02 17:13:29 +01001570 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1571 if (ret) {
1572 eprintf("Cannot setup simplefb: Error reserving memory\n");
1573 return ret;
1574 }
1575
Hans de Goede58332f82015-08-05 00:06:47 +02001576 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001577 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goede58332f82015-08-05 00:06:47 +02001578 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001579 if (ret)
1580 eprintf("Cannot setup simplefb: Error setting properties\n");
1581
1582 return ret;
1583}
1584#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */