blob: f5f24fc020bd793d2e1de7914f99d032e55a5743 [file] [log] [blame]
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001/*
2 * Display driver for Allwinner SoCs.
3 *
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
5 * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 */
9
10#include <common.h>
11
12#include <asm/arch/clock.h>
13#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020015#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010016#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020017#include <asm/io.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010018#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020019#include <fdtdec.h>
20#include <fdt_support.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020021#include <video_fb.h>
Hans de Goedeccb0ed52014-12-19 13:46:33 +010022#include "videomodes.h"
Hans de Goede743fb9552015-01-20 09:23:36 +010023#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashkac02f0522015-01-19 05:23:33 +020024#include "ssd2828.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020025
Hans de Goede2d5d3022015-01-22 21:02:42 +010026#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
27#define PWM_ON 0
28#define PWM_OFF 1
29#else
30#define PWM_ON 1
31#define PWM_OFF 0
32#endif
33
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020034DECLARE_GLOBAL_DATA_PTR;
35
Hans de Goedea0b1b732014-12-21 14:37:45 +010036enum sunxi_monitor {
37 sunxi_monitor_none,
38 sunxi_monitor_dvi,
39 sunxi_monitor_hdmi,
40 sunxi_monitor_lcd,
41 sunxi_monitor_vga,
42};
43#define SUNXI_MONITOR_LAST sunxi_monitor_vga
44
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020045struct sunxi_display {
46 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010047 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010048 unsigned int depth;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020049} sunxi_display;
50
Hans de Goedee9544592014-12-23 23:04:35 +010051#ifdef CONFIG_VIDEO_HDMI
52
Hans de Goedea5aa95f2014-12-19 16:05:12 +010053/*
54 * Wait up to 200ms for value to be set in given part of reg.
55 */
56static int await_completion(u32 *reg, u32 mask, u32 val)
57{
58 unsigned long tmo = timer_get_us() + 200000;
59
60 while ((readl(reg) & mask) != val) {
61 if (timer_get_us() > tmo) {
62 printf("DDC: timeout reading EDID\n");
63 return -ETIME;
64 }
65 }
66 return 0;
67}
68
Hans de Goede91593712014-12-28 09:13:21 +010069static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020070{
71 struct sunxi_ccm_reg * const ccm =
72 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
73 struct sunxi_hdmi_reg * const hdmi =
74 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010075 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020076
77 /* Set pll3 to 300MHz */
78 clock_set_pll3(300000000);
79
80 /* Set hdmi parent to pll3 */
81 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
82 CCM_HDMI_CTRL_PLL3);
83
84 /* Set ahb gating to pass */
Hans de Goedef651e0a2014-11-14 17:42:14 +010085#ifdef CONFIG_MACH_SUN6I
86 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
87#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020088 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
89
90 /* Clock on */
91 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
92
93 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
94 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
95
Hans de Goede205a30c2014-12-20 15:15:23 +010096 while (timer_get_us() < tmo) {
97 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
98 return 1;
99 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200100
Hans de Goede205a30c2014-12-20 15:15:23 +0100101 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100102}
103
104static void sunxi_hdmi_shutdown(void)
105{
106 struct sunxi_ccm_reg * const ccm =
107 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
108 struct sunxi_hdmi_reg * const hdmi =
109 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200110
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200111 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
112 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
113 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100114#ifdef CONFIG_MACH_SUN6I
115 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
116#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200117 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200118}
119
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100120static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
121{
122 struct sunxi_hdmi_reg * const hdmi =
123 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
124
125 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
126 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
127 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
128 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
129 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
130#ifndef CONFIG_MACH_SUN6I
131 writel(n, &hdmi->ddc_byte_count);
132 writel(cmnd, &hdmi->ddc_cmnd);
133#else
134 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
135#endif
136 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
137
138 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
139}
140
141static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
142{
143 struct sunxi_hdmi_reg * const hdmi =
144 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
145 int i, n;
146
147 while (count > 0) {
148 if (count > 16)
149 n = 16;
150 else
151 n = count;
152
153 if (sunxi_hdmi_ddc_do_command(
154 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
155 offset, n))
156 return -ETIME;
157
158 for (i = 0; i < n; i++)
159 *buf++ = readb(&hdmi->ddc_fifo_data);
160
161 offset += n;
162 count -= n;
163 }
164
165 return 0;
166}
167
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100168static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
169{
170 int r, retries = 2;
171
172 do {
173 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
174 if (r)
175 continue;
176 r = edid_check_checksum(buf);
177 if (r) {
178 printf("EDID block %d: checksum error%s\n",
179 block, retries ? ", retrying" : "");
180 }
181 } while (r && retries--);
182
183 return r;
184}
185
Hans de Goedea0b1b732014-12-21 14:37:45 +0100186static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100187{
188 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100189 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100190 struct edid_detailed_timing *t =
191 (struct edid_detailed_timing *)edid1.monitor_details.timing;
192 struct sunxi_hdmi_reg * const hdmi =
193 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
194 struct sunxi_ccm_reg * const ccm =
195 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100196 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100197
198 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
199 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
200 &hdmi->pad_ctrl1);
201 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
202 &hdmi->pll_ctrl);
203 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
204
205 /* Reset i2c controller */
206 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
207 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
208 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
209 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
210 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
211 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
212 return -EIO;
213
214 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
215#ifndef CONFIG_MACH_SUN6I
216 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
217 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
218#endif
219
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100220 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100221 if (r == 0) {
222 r = edid_check_info(&edid1);
223 if (r) {
224 printf("EDID: invalid EDID data\n");
225 r = -EINVAL;
226 }
227 }
228 if (r == 0) {
229 ext_blocks = edid1.extension_flag;
230 if (ext_blocks > 4)
231 ext_blocks = 4;
232 for (i = 0; i < ext_blocks; i++) {
233 if (sunxi_hdmi_edid_get_block(1 + i,
234 (u8 *)&cea681[i]) != 0) {
235 ext_blocks = i;
236 break;
237 }
238 }
239 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100240
241 /* Disable DDC engine, no longer needed */
242 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
243 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
244
245 if (r)
246 return r;
247
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100248 /* We want version 1.3 or 1.2 with detailed timing info */
249 if (edid1.version != 1 || (edid1.revision < 3 &&
250 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
251 printf("EDID: unsupported version %d.%d\n",
252 edid1.version, edid1.revision);
253 return -EINVAL;
254 }
255
256 /* Take the first usable detailed timing */
257 for (i = 0; i < 4; i++, t++) {
258 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
259 if (r == 0)
260 break;
261 }
262 if (i == 4) {
263 printf("EDID: no usable detailed timing found\n");
264 return -ENOENT;
265 }
266
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100267 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100268 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100269 for (i = 0; i < ext_blocks; i++) {
270 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
271 cea681[i].revision < 2)
272 continue;
273
274 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100275 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100276 }
277
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100278 return 0;
279}
280
Hans de Goedee9544592014-12-23 23:04:35 +0100281#endif /* CONFIG_VIDEO_HDMI */
282
Hans de Goedec3cc4262015-01-19 08:44:07 +0100283#ifdef CONFIG_MACH_SUN4I
284/*
285 * Testing has shown that on sun4i the display backend engine does not have
286 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
287 * fifo underruns. So on sun4i we use the display frontend engine to do the
288 * dma from memory, as the frontend does have deep enough fifo-s.
289 */
290
291static const u32 sun4i_vert_coef[32] = {
292 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
293 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
294 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
295 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
296 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
297 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
298 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
299 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
300};
301
302static const u32 sun4i_horz_coef[64] = {
303 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
304 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
305 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
306 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
307 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
308 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
309 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
310 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
311 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
312 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
313 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
314 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
315 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
316 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
317 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
318 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
319};
320
321static void sunxi_frontend_init(void)
322{
323 struct sunxi_ccm_reg * const ccm =
324 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
325 struct sunxi_de_fe_reg * const de_fe =
326 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
327 int i;
328
329 /* Clocks on */
330 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
331 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
332 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
333
334 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
335
336 for (i = 0; i < 32; i++) {
337 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
338 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
339 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
340 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
341 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
342 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
343 }
344
345 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
346}
347
348static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
349 unsigned int address)
350{
351 struct sunxi_de_fe_reg * const de_fe =
352 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
353
354 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
355 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
356 writel(mode->xres * 4, &de_fe->ch0_stride);
357 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
358 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
359
360 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
361 &de_fe->ch0_insize);
362 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
363 &de_fe->ch0_outsize);
364 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
365 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
366
367 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
368 &de_fe->ch1_insize);
369 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
370 &de_fe->ch1_outsize);
371 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
372 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
373
374 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
375}
376
377static void sunxi_frontend_enable(void)
378{
379 struct sunxi_de_fe_reg * const de_fe =
380 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
381
382 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
383}
384#else
385static void sunxi_frontend_init(void) {}
386static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
387 unsigned int address) {}
388static void sunxi_frontend_enable(void) {}
389#endif
390
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200391/*
392 * This is the entity that mixes and matches the different layers and inputs.
393 * Allwinner calls it the back-end, but i like composer better.
394 */
395static void sunxi_composer_init(void)
396{
397 struct sunxi_ccm_reg * const ccm =
398 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
399 struct sunxi_de_be_reg * const de_be =
400 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
401 int i;
402
Hans de Goedec3cc4262015-01-19 08:44:07 +0100403 sunxi_frontend_init();
404
Hans de Goedee9544592014-12-23 23:04:35 +0100405#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100406 /* Reset off */
407 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
408#endif
409
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200410 /* Clocks on */
411 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100412#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200413 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100414#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200415 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
416
417 /* Engine bug, clear registers after reset */
418 for (i = 0x0800; i < 0x1000; i += 4)
419 writel(0, SUNXI_DE_BE0_BASE + i);
420
421 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
422}
423
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100424static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200425 unsigned int address)
426{
427 struct sunxi_de_be_reg * const de_be =
428 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
429
Hans de Goedec3cc4262015-01-19 08:44:07 +0100430 sunxi_frontend_mode_set(mode, address);
431
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200432 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
433 &de_be->disp_size);
434 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
435 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100436#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200437 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
438 writel(address << 3, &de_be->layer0_addr_low32b);
439 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100440#else
441 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
442#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200443 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
444
445 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
446}
447
Hans de Goede4125f922014-12-21 14:49:34 +0100448static void sunxi_composer_enable(void)
449{
450 struct sunxi_de_be_reg * const de_be =
451 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
452
Hans de Goedec3cc4262015-01-19 08:44:07 +0100453 sunxi_frontend_enable();
454
Hans de Goede4125f922014-12-21 14:49:34 +0100455 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
456 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
457}
458
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200459/*
460 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
461 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100462static void sunxi_lcdc_pll_set(int tcon, int dotclock,
463 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200464{
465 struct sunxi_ccm_reg * const ccm =
466 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100467 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200468 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
469 int best_double = 0;
470
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100471 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100472#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100473 min_m = 6;
474 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100475#endif
476#ifdef CONFIG_VIDEO_LCD_IF_LVDS
477 min_m = max_m = 7;
478#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100479 } else {
480 min_m = 1;
481 max_m = 15;
482 }
483
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200484 /*
485 * Find the lowest divider resulting in a matching clock, if there
486 * is no match, pick the closest lower clock, as monitors tend to
487 * not sync to higher frequencies.
488 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100489 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200490 n = (m * dotclock) / 3000;
491
492 if ((n >= 9) && (n <= 127)) {
493 value = (3000 * n) / m;
494 diff = dotclock - value;
495 if (diff < best_diff) {
496 best_diff = diff;
497 best_m = m;
498 best_n = n;
499 best_double = 0;
500 }
501 }
502
503 /* These are just duplicates */
504 if (!(m & 1))
505 continue;
506
507 n = (m * dotclock) / 6000;
508 if ((n >= 9) && (n <= 127)) {
509 value = (6000 * n) / m;
510 diff = dotclock - value;
511 if (diff < best_diff) {
512 best_diff = diff;
513 best_m = m;
514 best_n = n;
515 best_double = 1;
516 }
517 }
518 }
519
520 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
521 dotclock, (best_double + 1) * 3000 * best_n / best_m,
522 best_double + 1, best_n, best_m);
523
524 clock_set_pll3(best_n * 3000000);
525
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100526 if (tcon == 0) {
527 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
528 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
529 CCM_LCD_CH0_CTRL_PLL3),
530 &ccm->lcd0_ch0_clk_cfg);
531 } else {
532 writel(CCM_LCD_CH1_CTRL_GATE |
533 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
534 CCM_LCD_CH1_CTRL_PLL3) |
535 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
536 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200537
538 *clk_div = best_m;
539 *clk_double = best_double;
540}
541
542static void sunxi_lcdc_init(void)
543{
544 struct sunxi_ccm_reg * const ccm =
545 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
546 struct sunxi_lcdc_reg * const lcdc =
547 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
548
549 /* Reset off */
Hans de Goedee9544592014-12-23 23:04:35 +0100550#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100551 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
552#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200553 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100554#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200555
556 /* Clock on */
557 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100558#ifdef CONFIG_VIDEO_LCD_IF_LVDS
559 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
560#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200561
562 /* Init lcdc */
563 writel(0, &lcdc->ctrl); /* Disable tcon */
564 writel(0, &lcdc->int0); /* Disable all interrupts */
565
566 /* Disable tcon0 dot clock */
567 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
568
569 /* Set all io lines to tristate */
570 writel(0xffffffff, &lcdc->tcon0_io_tristate);
571 writel(0xffffffff, &lcdc->tcon1_io_tristate);
572}
573
Hans de Goede4125f922014-12-21 14:49:34 +0100574static void sunxi_lcdc_enable(void)
575{
576 struct sunxi_lcdc_reg * const lcdc =
577 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
578
579 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede797a0f52015-01-01 22:04:34 +0100580#ifdef CONFIG_VIDEO_LCD_IF_LVDS
581 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
582 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
583 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
584 udelay(2); /* delay at least 1200 ns */
585 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
586 udelay(1); /* delay at least 120 ns */
587 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
588 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
589#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100590}
591
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100592static void sunxi_lcdc_panel_enable(void)
593{
594 int pin;
595
596 /*
597 * Start with backlight disabled to avoid the screen flashing to
598 * white while the lcd inits.
599 */
600 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
601 if (pin != -1) {
602 gpio_request(pin, "lcd_backlight_enable");
603 gpio_direction_output(pin, 0);
604 }
605
606 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
607 if (pin != -1) {
608 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100609 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100610 }
611
612 /* Give the backlight some time to turn off and power up the panel. */
613 mdelay(40);
614 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
615 if (pin != -1) {
616 gpio_request(pin, "lcd_power");
617 gpio_direction_output(pin, 1);
618 }
619}
620
621static void sunxi_lcdc_backlight_enable(void)
622{
623 int pin;
624
625 /*
626 * We want to have scanned out at least one frame before enabling the
627 * backlight to avoid the screen flashing to white when we enable it.
628 */
629 mdelay(40);
630
631 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
632 if (pin != -1)
633 gpio_direction_output(pin, 1);
634
635 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede2d5d3022015-01-22 21:02:42 +0100636 if (pin != -1)
637 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100638}
639
640static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
641{
642 int delay;
643
644 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
645 return (delay > 30) ? 30 : delay;
646}
647
Hans de Goede18366f72015-01-25 15:33:07 +0100648static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
649 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100650{
651 struct sunxi_lcdc_reg * const lcdc =
652 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
653 int bp, clk_delay, clk_div, clk_double, pin, total, val;
654
655 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede797a0f52015-01-01 22:04:34 +0100656#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100657 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100658#endif
659#ifdef CONFIG_VIDEO_LCD_IF_LVDS
660 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0);
661#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100662
663 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
664
665 /* Use tcon0 */
666 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
667 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
668
669 clk_delay = sunxi_lcdc_get_clk_delay(mode);
670 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
671 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
672
673 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
674 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
675
676 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
677 &lcdc->tcon0_timing_active);
678
679 bp = mode->hsync_len + mode->left_margin;
680 total = mode->xres + mode->right_margin + bp;
681 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
682 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
683
684 bp = mode->vsync_len + mode->upper_margin;
685 total = mode->yres + mode->lower_margin + bp;
686 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
687 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
688
Hans de Goede797a0f52015-01-01 22:04:34 +0100689#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100690 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
691 &lcdc->tcon0_timing_sync);
692
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100693 writel(0, &lcdc->tcon0_hv_intf);
694 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100695#endif
696#ifdef CONFIG_VIDEO_LCD_IF_LVDS
697 val = (sunxi_display.depth == 18) ? 1 : 0;
698 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf);
699#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100700
701 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
702 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
703 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
704 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
705 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
706 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
707 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
708 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
709 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
710 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
711 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
712 writel(((sunxi_display.depth == 18) ?
713 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
714 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
715 &lcdc->tcon0_frm_ctrl);
716 }
717
Hans de Goede481b6642015-01-13 13:21:46 +0100718 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100719 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
720 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
721 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
722 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goede18366f72015-01-25 15:33:07 +0100723
724#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
725 if (for_ext_vga_dac)
726 val = 0;
727#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100728 writel(val, &lcdc->tcon0_io_polarity);
729
730 writel(0, &lcdc->tcon0_io_tristate);
731}
732
Hans de Goede260f5202014-12-25 13:58:06 +0100733#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
Hans de Goede4125f922014-12-21 14:49:34 +0100734static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100735 int *clk_div, int *clk_double,
736 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200737{
738 struct sunxi_lcdc_reg * const lcdc =
739 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedec3d15042014-12-27 15:19:23 +0100740 int bp, clk_delay, total, val;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200741
742 /* Use tcon1 */
743 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
744 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
745
Hans de Goedeac5d43d2014-12-24 19:50:11 +0100746 clk_delay = sunxi_lcdc_get_clk_delay(mode);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200747 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedeac5d43d2014-12-24 19:50:11 +0100748 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200749
750 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
751 &lcdc->tcon1_timing_source);
752 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
753 &lcdc->tcon1_timing_scale);
754 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
755 &lcdc->tcon1_timing_out);
756
757 bp = mode->hsync_len + mode->left_margin;
758 total = mode->xres + mode->right_margin + bp;
759 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
760 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
761
762 bp = mode->vsync_len + mode->upper_margin;
763 total = mode->yres + mode->lower_margin + bp;
764 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
765 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
766
767 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
768 &lcdc->tcon1_timing_sync);
769
Hans de Goedec3d15042014-12-27 15:19:23 +0100770 if (use_portd_hvsync) {
771 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD0_LCD0);
772 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD0_LCD0);
773
774 val = 0;
775 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
776 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
777 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
778 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
779 writel(val, &lcdc->tcon1_io_polarity);
780
781 clrbits_le32(&lcdc->tcon1_io_tristate,
782 SUNXI_LCDC_TCON_VSYNC_MASK |
783 SUNXI_LCDC_TCON_HSYNC_MASK);
784 }
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100785 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200786}
Hans de Goede260f5202014-12-25 13:58:06 +0100787#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
788
789#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100790
Hans de Goedea2017e82014-12-20 13:38:06 +0100791static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
792{
793 struct sunxi_hdmi_reg * const hdmi =
794 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
795 u8 checksum = 0;
796 u8 avi_info_frame[17] = {
797 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799 0x00
800 };
801 u8 vendor_info_frame[19] = {
802 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
804 0x00, 0x00, 0x00
805 };
806 int i;
807
808 if (mode->pixclock_khz <= 27000)
809 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
810 else
811 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
812
813 if (mode->xres * 100 / mode->yres < 156)
814 avi_info_frame[5] |= 0x18; /* 4 : 3 */
815 else
816 avi_info_frame[5] |= 0x28; /* 16 : 9 */
817
818 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
819 checksum += avi_info_frame[i];
820
821 avi_info_frame[3] = 0x100 - checksum;
822
823 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
824 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
825
826 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
827 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
828
829 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
830 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
831
832 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
833 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
834
835 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
836}
837
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100838static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100839 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200840{
841 struct sunxi_hdmi_reg * const hdmi =
842 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
843 int x, y;
844
845 /* Write clear interrupt status bits */
846 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
847
Hans de Goedea0b1b732014-12-21 14:37:45 +0100848 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100849 sunxi_hdmi_setup_info_frames(mode);
850
Hans de Goede95576692014-12-20 13:51:16 +0100851 /* Set input sync enable */
852 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
853
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200854 /* Init various registers, select pll3 as clock source */
855 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
856 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
857 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
858 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
859 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
860
861 /* Setup clk div and doubler */
862 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
863 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
864 if (!clk_double)
865 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
866
867 /* Setup timing registers */
868 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
869 &hdmi->video_size);
870
871 x = mode->hsync_len + mode->left_margin;
872 y = mode->vsync_len + mode->upper_margin;
873 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
874
875 x = mode->right_margin;
876 y = mode->lower_margin;
877 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
878
879 x = mode->hsync_len;
880 y = mode->vsync_len;
881 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
882
883 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
884 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
885
886 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
887 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
888}
889
Hans de Goede4125f922014-12-21 14:49:34 +0100890static void sunxi_hdmi_enable(void)
891{
892 struct sunxi_hdmi_reg * const hdmi =
893 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
894
895 udelay(100);
896 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
897}
898
Hans de Goedee9544592014-12-23 23:04:35 +0100899#endif /* CONFIG_VIDEO_HDMI */
900
Hans de Goede260f5202014-12-25 13:58:06 +0100901#ifdef CONFIG_VIDEO_VGA
902
903static void sunxi_vga_mode_set(void)
904{
905 struct sunxi_ccm_reg * const ccm =
906 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
907 struct sunxi_tve_reg * const tve =
908 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
909
910 /* Clock on */
911 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
912
913 /* Set TVE in VGA mode */
914 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
915 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
916 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
917 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
918 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
919 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
920}
921
922static void sunxi_vga_enable(void)
923{
924 struct sunxi_tve_reg * const tve =
925 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
926
927 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
928}
929
930#endif /* CONFIG_VIDEO_VGA */
931
Hans de Goede115e4b42014-12-23 18:39:52 +0100932static void sunxi_drc_init(void)
933{
Hans de Goedee9544592014-12-23 23:04:35 +0100934#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goede115e4b42014-12-23 18:39:52 +0100935 struct sunxi_ccm_reg * const ccm =
936 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
937
938 /* On sun6i the drc must be clocked even when in pass-through mode */
939 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
940 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
941#endif
942}
943
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800944#ifdef CONFIG_VIDEO_VGA_VIA_LCD
945static void sunxi_vga_external_dac_enable(void)
946{
947 int pin;
948
949 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
950 if (pin != -1) {
951 gpio_request(pin, "vga_enable");
952 gpio_direction_output(pin, 1);
953 }
954}
955#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
956
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200957#ifdef CONFIG_VIDEO_LCD_SSD2828
958static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
959{
960 struct ssd2828_config cfg = {
961 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
962 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
963 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
964 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
965 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
966 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
967 .ssd2828_color_depth = 24,
968#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
969 .mipi_dsi_number_of_data_lanes = 4,
970 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
971 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
972 .mipi_dsi_delay_after_set_display_on_ms = 200
973#else
974#error MIPI LCD panel needs configuration parameters
975#endif
976 };
977
978 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
979 printf("SSD2828: SPI pins are not properly configured\n");
980 return 1;
981 }
982 if (cfg.reset_pin == -1) {
983 printf("SSD2828: Reset pin is not properly configured\n");
984 return 1;
985 }
986
987 return ssd2828_init(&cfg, mode);
988}
989#endif /* CONFIG_VIDEO_LCD_SSD2828 */
990
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200991static void sunxi_engines_init(void)
992{
993 sunxi_composer_init();
994 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100995 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200996}
997
Hans de Goedea0b1b732014-12-21 14:37:45 +0100998static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +0100999 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001000{
Hans de Goede260f5202014-12-25 13:58:06 +01001001 int __maybe_unused clk_div, clk_double;
1002
Hans de Goede4125f922014-12-21 14:49:34 +01001003 switch (sunxi_display.monitor) {
1004 case sunxi_monitor_none:
1005 break;
1006 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001007 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001008#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001009 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001010 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001011 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1012 sunxi_composer_enable();
1013 sunxi_lcdc_enable();
1014 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001015#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001016 break;
1017 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001018 sunxi_lcdc_panel_enable();
Hans de Goede743fb9552015-01-20 09:23:36 +01001019 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1020 mdelay(50); /* Wait for lcd controller power on */
1021 hitachi_tx18d42vm_init();
1022 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001023 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001024 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001025 sunxi_composer_enable();
1026 sunxi_lcdc_enable();
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001027#ifdef CONFIG_VIDEO_LCD_SSD2828
1028 sunxi_ssd2828_init(mode);
1029#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001030 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001031 break;
1032 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001033#ifdef CONFIG_VIDEO_VGA
1034 sunxi_composer_mode_set(mode, address);
1035 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1036 sunxi_vga_mode_set();
1037 sunxi_composer_enable();
1038 sunxi_lcdc_enable();
1039 sunxi_vga_enable();
1040#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001041 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001042 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001043 sunxi_composer_enable();
1044 sunxi_lcdc_enable();
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001045 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001046#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001047 break;
1048 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001049}
1050
Hans de Goedea0b1b732014-12-21 14:37:45 +01001051static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1052{
1053 switch (monitor) {
1054 case sunxi_monitor_none: return "none";
1055 case sunxi_monitor_dvi: return "dvi";
1056 case sunxi_monitor_hdmi: return "hdmi";
1057 case sunxi_monitor_lcd: return "lcd";
1058 case sunxi_monitor_vga: return "vga";
1059 }
1060 return NULL; /* never reached */
1061}
1062
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001063void *video_hw_init(void)
1064{
1065 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001066 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001067 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001068 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001069#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001070 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001071#endif
Hans de Goedea0b1b732014-12-21 14:37:45 +01001072 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001073 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Hans de Goedee9544592014-12-23 23:04:35 +01001074 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001075
1076 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1077
1078 printf("Reserved %dkB of RAM for Framebuffer.\n",
1079 CONFIG_SUNXI_FB_SIZE >> 10);
1080 gd->fb_base = gd->ram_top;
1081
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001082 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1083 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001084#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001085 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001086 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001087 edid = video_get_option_int(options, "edid", 1);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001088 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedeac1633c2014-12-24 12:17:07 +01001089#elif defined CONFIG_VIDEO_VGA_VIA_LCD
1090 sunxi_display.monitor = sunxi_monitor_vga;
Hans de Goedee9544592014-12-23 23:04:35 +01001091#else
1092 sunxi_display.monitor = sunxi_monitor_lcd;
1093#endif
Hans de Goedea0b1b732014-12-21 14:37:45 +01001094 video_get_option_string(options, "monitor", mon, sizeof(mon),
1095 sunxi_get_mon_desc(sunxi_display.monitor));
1096 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1097 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1098 sunxi_display.monitor = i;
1099 break;
1100 }
1101 }
1102 if (i > SUNXI_MONITOR_LAST)
1103 printf("Unknown monitor: '%s', falling back to '%s'\n",
1104 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001105
Hans de Goede7977ec22014-12-25 13:52:04 +01001106#ifdef CONFIG_VIDEO_HDMI
1107 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1108 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1109 sunxi_display.monitor == sunxi_monitor_hdmi) {
1110 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001111 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001112 if (ret) {
1113 printf("HDMI connected: ");
1114 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1115 mode = &custom;
1116 } else if (hpd) {
1117 sunxi_hdmi_shutdown();
1118 /* Fallback to lcd / vga / none */
1119 if (lcd_mode[0]) {
1120 sunxi_display.monitor = sunxi_monitor_lcd;
1121 } else {
Hans de Goede260f5202014-12-25 13:58:06 +01001122#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goede7977ec22014-12-25 13:52:04 +01001123 sunxi_display.monitor = sunxi_monitor_vga;
1124#else
1125 sunxi_display.monitor = sunxi_monitor_none;
1126#endif
1127 }
1128 } /* else continue with hdmi/dvi without a cable connected */
1129 }
1130#endif
1131
Hans de Goede4125f922014-12-21 14:49:34 +01001132 switch (sunxi_display.monitor) {
1133 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001134 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001135 case sunxi_monitor_dvi:
1136 case sunxi_monitor_hdmi:
Hans de Goede7977ec22014-12-25 13:52:04 +01001137#ifdef CONFIG_VIDEO_HDMI
1138 break;
1139#else
Hans de Goedee9544592014-12-23 23:04:35 +01001140 printf("HDMI/DVI not supported on this board\n");
Hans de Goede83243c42014-12-24 19:47:14 +01001141 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goedee9544592014-12-23 23:04:35 +01001142 return NULL;
Hans de Goedee9544592014-12-23 23:04:35 +01001143#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001144 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001145 if (lcd_mode[0]) {
1146 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1147 mode = &custom;
1148 break;
1149 }
Hans de Goede4125f922014-12-21 14:49:34 +01001150 printf("LCD not supported on this board\n");
Hans de Goede83243c42014-12-24 19:47:14 +01001151 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede4125f922014-12-21 14:49:34 +01001152 return NULL;
1153 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001154#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goedeac1633c2014-12-24 12:17:07 +01001155 sunxi_display.depth = 18;
1156 break;
1157#else
Hans de Goede4125f922014-12-21 14:49:34 +01001158 printf("VGA not supported on this board\n");
Hans de Goede83243c42014-12-24 19:47:14 +01001159 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede4125f922014-12-21 14:49:34 +01001160 return NULL;
Hans de Goedeac1633c2014-12-24 12:17:07 +01001161#endif
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001162 }
1163
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001164 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1165 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1166 mode = &res_mode_init[RES_MODE_1024x768];
1167 } else {
Hans de Goedea0b1b732014-12-21 14:37:45 +01001168 printf("Setting up a %dx%d %s console\n", mode->xres,
1169 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001170 }
1171
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001172 sunxi_engines_init();
Hans de Goedea0b1b732014-12-21 14:37:45 +01001173 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001174
1175 /*
1176 * These are the only members of this structure that are used. All the
1177 * others are driver specific. There is nothing to decribe pitch or
1178 * stride, but we are lucky with our hw.
1179 */
1180 graphic_device->frameAdrs = gd->fb_base;
1181 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1182 graphic_device->gdfBytesPP = 4;
Hans de Goedeccb0ed52014-12-19 13:46:33 +01001183 graphic_device->winSizeX = mode->xres;
1184 graphic_device->winSizeY = mode->yres;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001185
1186 return graphic_device;
1187}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001188
1189/*
1190 * Simplefb support.
1191 */
1192#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1193int sunxi_simplefb_setup(void *blob)
1194{
1195 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1196 int offset, ret;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001197 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001198
Hans de Goedec3cc4262015-01-19 08:44:07 +01001199#ifdef CONFIG_MACH_SUN4I
1200#define PIPELINE_PREFIX "de_fe0-"
1201#else
1202#define PIPELINE_PREFIX
1203#endif
1204
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001205 switch (sunxi_display.monitor) {
1206 case sunxi_monitor_none:
1207 return 0;
1208 case sunxi_monitor_dvi:
1209 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001210 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001211 break;
1212 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001213 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001214 break;
1215 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001216#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001217 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001218#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001219 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001220#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001221 break;
1222 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001223
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001224 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001225 offset = fdt_node_offset_by_compatible(blob, -1,
1226 "allwinner,simple-framebuffer");
1227 while (offset >= 0) {
1228 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001229 pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001230 if (ret == 0)
1231 break;
1232 offset = fdt_node_offset_by_compatible(blob, offset,
1233 "allwinner,simple-framebuffer");
1234 }
1235 if (offset < 0) {
1236 eprintf("Cannot setup simplefb: node not found\n");
1237 return 0; /* Keep older kernels working */
1238 }
1239
1240 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1241 graphic_device->winSizeX, graphic_device->winSizeY,
1242 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1243 "x8r8g8b8");
1244 if (ret)
1245 eprintf("Cannot setup simplefb: Error setting properties\n");
1246
1247 return ret;
1248}
1249#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */