blob: af728b51c746783e46d3edc06b01538814dd44ea [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>
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 Goede2dae8002014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020015#include <asm/global_data.h>
Hans de Goede2dae8002014-12-21 16:28:32 +010016#include <asm/gpio.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020017#include <asm/io.h>
Hans de Goede75481602014-12-19 16:05:12 +010018#include <errno.h>
Luc Verhaegen2d7a0842014-08-13 07:55:07 +020019#include <fdtdec.h>
20#include <fdt_support.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020021#include <video_fb.h>
Hans de Goedebe8ec632014-12-19 13:46:33 +010022#include "videomodes.h"
Hans de Goede27515b22015-01-20 09:23:36 +010023#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashka97ece832015-01-19 05:23:33 +020024#include "ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020025
Hans de Goedea7403ae2015-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 Verhaegen7f2c5212014-08-13 07:55:06 +020034DECLARE_GLOBAL_DATA_PTR;
35
Hans de Goede1c092202014-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 Verhaegen7f2c5212014-08-13 07:55:06 +020045struct sunxi_display {
46 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010047 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010048 unsigned int depth;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020049} sunxi_display;
50
Hans de Goede2fbf0912014-12-23 23:04:35 +010051#ifdef CONFIG_VIDEO_HDMI
52
Hans de Goede75481602014-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 Goede7fad8a92014-12-28 09:13:21 +010069static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-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 Goede7fad8a92014-12-28 09:13:21 +010075 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-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 Goede211717a2014-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 Verhaegen7f2c5212014-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 Goede40f1b872014-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 Verhaegen7f2c5212014-08-13 07:55:06 +0200100
Hans de Goede40f1b872014-12-20 15:15:23 +0100101 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100102}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200103
Hans de Goede518cef22014-12-19 15:13:57 +0100104static 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;
110
Luc Verhaegen7f2c5212014-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 Goede211717a2014-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 Verhaegen7f2c5212014-08-13 07:55:06 +0200117 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200118}
119
Hans de Goede75481602014-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 Goede63c5fbd2014-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 Goede1c092202014-12-21 14:37:45 +0100186static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100187{
188 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100189 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-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 Goedef3000682014-12-20 14:31:45 +0100196 int i, r, ext_blocks = 0;
Hans de Goede75481602014-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 Goede63c5fbd2014-12-20 14:01:48 +0100220 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-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 Goede75481602014-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 Goede75481602014-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 Goedef3000682014-12-20 14:31:45 +0100267 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100268 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-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 Goede1c092202014-12-21 14:37:45 +0100275 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100276 }
277
Hans de Goede75481602014-12-19 16:05:12 +0100278 return 0;
279}
280
Hans de Goede2fbf0912014-12-23 23:04:35 +0100281#endif /* CONFIG_VIDEO_HDMI */
282
Hans de Goede7cd6f922015-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 Verhaegen7f2c5212014-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 Goede7cd6f922015-01-19 08:44:07 +0100403 sunxi_frontend_init();
404
Hans de Goede2fbf0912014-12-23 23:04:35 +0100405#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goede211717a2014-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 Verhaegen7f2c5212014-08-13 07:55:06 +0200410 /* Clocks on */
411 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100412#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200413 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100414#endif
Luc Verhaegen7f2c5212014-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 Goedebe8ec632014-12-19 13:46:33 +0100424static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-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 Goede7cd6f922015-01-19 08:44:07 +0100430 sunxi_frontend_mode_set(mode, address);
431
Luc Verhaegen7f2c5212014-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 Goede7cd6f922015-01-19 08:44:07 +0100436#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-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 Goede7cd6f922015-01-19 08:44:07 +0100440#else
441 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
442#endif
Luc Verhaegen7f2c5212014-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 Goede0e045212014-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 Goede7cd6f922015-01-19 08:44:07 +0100453 sunxi_frontend_enable();
454
Hans de Goede0e045212014-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 Verhaegen7f2c5212014-08-13 07:55:06 +0200459/*
460 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
461 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100462static void sunxi_lcdc_pll_set(int tcon, int dotclock,
463 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200464{
465 struct sunxi_ccm_reg * const ccm =
466 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100467 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200468 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
469 int best_double = 0;
470
Hans de Goede5489ebc2014-12-21 16:27:45 +0100471 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100472#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100473 min_m = 6;
474 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100475#endif
476#ifdef CONFIG_VIDEO_LCD_IF_LVDS
477 min_m = max_m = 7;
478#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100479 } else {
480 min_m = 1;
481 max_m = 15;
482 }
483
Luc Verhaegen7f2c5212014-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 Goede5489ebc2014-12-21 16:27:45 +0100489 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-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 Goede5489ebc2014-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 Verhaegen7f2c5212014-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 Goede2fbf0912014-12-23 23:04:35 +0100550#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goede211717a2014-11-14 17:42:14 +0100551 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
552#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200553 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100554#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200555
556 /* Clock on */
557 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-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 Verhaegen7f2c5212014-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 Goede0e045212014-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 Goede213480e2015-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 Goede0e045212014-12-21 14:49:34 +0100590}
591
Hans de Goede2dae8002014-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 Goedea7403ae2015-01-22 21:02:42 +0100609 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-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 Goedea7403ae2015-01-22 21:02:42 +0100636 if (pin != -1)
637 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-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
648static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode)
649{
650 struct sunxi_lcdc_reg * const lcdc =
651 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
652 int bp, clk_delay, clk_div, clk_double, pin, total, val;
653
654 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede213480e2015-01-01 22:04:34 +0100655#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100656 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100657#endif
658#ifdef CONFIG_VIDEO_LCD_IF_LVDS
659 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0);
660#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100661
662 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
663
664 /* Use tcon0 */
665 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
666 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
667
668 clk_delay = sunxi_lcdc_get_clk_delay(mode);
669 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
670 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
671
672 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
673 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
674
675 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
676 &lcdc->tcon0_timing_active);
677
678 bp = mode->hsync_len + mode->left_margin;
679 total = mode->xres + mode->right_margin + bp;
680 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
681 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
682
683 bp = mode->vsync_len + mode->upper_margin;
684 total = mode->yres + mode->lower_margin + bp;
685 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
686 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
687
Hans de Goede213480e2015-01-01 22:04:34 +0100688#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100689 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
690 &lcdc->tcon0_timing_sync);
691
Hans de Goede2dae8002014-12-21 16:28:32 +0100692 writel(0, &lcdc->tcon0_hv_intf);
693 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100694#endif
695#ifdef CONFIG_VIDEO_LCD_IF_LVDS
696 val = (sunxi_display.depth == 18) ? 1 : 0;
697 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf);
698#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100699
700 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
701 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
702 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
703 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
704 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
705 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
706 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
707 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
708 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
709 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
710 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
711 writel(((sunxi_display.depth == 18) ?
712 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
713 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
714 &lcdc->tcon0_frm_ctrl);
715 }
716
Hans de Goede65150322015-01-13 13:21:46 +0100717 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100718 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
719 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
720 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
721 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
722 writel(val, &lcdc->tcon0_io_polarity);
723
724 writel(0, &lcdc->tcon0_io_tristate);
725}
726
Hans de Goeded9786d22014-12-25 13:58:06 +0100727#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
Hans de Goede0e045212014-12-21 14:49:34 +0100728static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100729 int *clk_div, int *clk_double,
730 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200731{
732 struct sunxi_lcdc_reg * const lcdc =
733 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goede3ffbe472014-12-27 15:19:23 +0100734 int bp, clk_delay, total, val;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200735
736 /* Use tcon1 */
737 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
738 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
739
Hans de Goede6741cc72014-12-24 19:50:11 +0100740 clk_delay = sunxi_lcdc_get_clk_delay(mode);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200741 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goede6741cc72014-12-24 19:50:11 +0100742 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200743
744 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
745 &lcdc->tcon1_timing_source);
746 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
747 &lcdc->tcon1_timing_scale);
748 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
749 &lcdc->tcon1_timing_out);
750
751 bp = mode->hsync_len + mode->left_margin;
752 total = mode->xres + mode->right_margin + bp;
753 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
754 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
755
756 bp = mode->vsync_len + mode->upper_margin;
757 total = mode->yres + mode->lower_margin + bp;
758 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
759 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
760
761 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
762 &lcdc->tcon1_timing_sync);
763
Hans de Goede3ffbe472014-12-27 15:19:23 +0100764 if (use_portd_hvsync) {
765 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD0_LCD0);
766 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD0_LCD0);
767
768 val = 0;
769 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
770 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
771 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
772 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
773 writel(val, &lcdc->tcon1_io_polarity);
774
775 clrbits_le32(&lcdc->tcon1_io_tristate,
776 SUNXI_LCDC_TCON_VSYNC_MASK |
777 SUNXI_LCDC_TCON_HSYNC_MASK);
778 }
Hans de Goede5489ebc2014-12-21 16:27:45 +0100779 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200780}
Hans de Goeded9786d22014-12-25 13:58:06 +0100781#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
782
783#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200784
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100785static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
786{
787 struct sunxi_hdmi_reg * const hdmi =
788 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
789 u8 checksum = 0;
790 u8 avi_info_frame[17] = {
791 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
793 0x00
794 };
795 u8 vendor_info_frame[19] = {
796 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00
799 };
800 int i;
801
802 if (mode->pixclock_khz <= 27000)
803 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
804 else
805 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
806
807 if (mode->xres * 100 / mode->yres < 156)
808 avi_info_frame[5] |= 0x18; /* 4 : 3 */
809 else
810 avi_info_frame[5] |= 0x28; /* 16 : 9 */
811
812 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
813 checksum += avi_info_frame[i];
814
815 avi_info_frame[3] = 0x100 - checksum;
816
817 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
818 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
819
820 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
821 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
822
823 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
824 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
825
826 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
827 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
828
829 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
830}
831
Hans de Goedebe8ec632014-12-19 13:46:33 +0100832static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100833 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200834{
835 struct sunxi_hdmi_reg * const hdmi =
836 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
837 int x, y;
838
839 /* Write clear interrupt status bits */
840 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
841
Hans de Goede1c092202014-12-21 14:37:45 +0100842 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100843 sunxi_hdmi_setup_info_frames(mode);
844
Hans de Goede876aaaf2014-12-20 13:51:16 +0100845 /* Set input sync enable */
846 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
847
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200848 /* Init various registers, select pll3 as clock source */
849 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
850 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
851 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
852 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
853 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
854
855 /* Setup clk div and doubler */
856 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
857 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
858 if (!clk_double)
859 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
860
861 /* Setup timing registers */
862 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
863 &hdmi->video_size);
864
865 x = mode->hsync_len + mode->left_margin;
866 y = mode->vsync_len + mode->upper_margin;
867 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
868
869 x = mode->right_margin;
870 y = mode->lower_margin;
871 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
872
873 x = mode->hsync_len;
874 y = mode->vsync_len;
875 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
876
877 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
878 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
879
880 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
881 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
882}
883
Hans de Goede0e045212014-12-21 14:49:34 +0100884static void sunxi_hdmi_enable(void)
885{
886 struct sunxi_hdmi_reg * const hdmi =
887 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
888
889 udelay(100);
890 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
891}
892
Hans de Goede2fbf0912014-12-23 23:04:35 +0100893#endif /* CONFIG_VIDEO_HDMI */
894
Hans de Goeded9786d22014-12-25 13:58:06 +0100895#ifdef CONFIG_VIDEO_VGA
896
897static void sunxi_vga_mode_set(void)
898{
899 struct sunxi_ccm_reg * const ccm =
900 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
901 struct sunxi_tve_reg * const tve =
902 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
903
904 /* Clock on */
905 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
906
907 /* Set TVE in VGA mode */
908 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
909 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
910 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
911 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
912 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
913 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
914}
915
916static void sunxi_vga_enable(void)
917{
918 struct sunxi_tve_reg * const tve =
919 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
920
921 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
922}
923
924#endif /* CONFIG_VIDEO_VGA */
925
Hans de Goedee8400792014-12-23 18:39:52 +0100926static void sunxi_drc_init(void)
927{
Hans de Goede2fbf0912014-12-23 23:04:35 +0100928#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goedee8400792014-12-23 18:39:52 +0100929 struct sunxi_ccm_reg * const ccm =
930 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
931
932 /* On sun6i the drc must be clocked even when in pass-through mode */
933 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
934 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
935#endif
936}
937
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +0800938#ifdef CONFIG_VIDEO_VGA_VIA_LCD
939static void sunxi_vga_external_dac_enable(void)
940{
941 int pin;
942
943 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
944 if (pin != -1) {
945 gpio_request(pin, "vga_enable");
946 gpio_direction_output(pin, 1);
947 }
948}
949#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
950
Siarhei Siamashka97ece832015-01-19 05:23:33 +0200951#ifdef CONFIG_VIDEO_LCD_SSD2828
952static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
953{
954 struct ssd2828_config cfg = {
955 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
956 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
957 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
958 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
959 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
960 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
961 .ssd2828_color_depth = 24,
962#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
963 .mipi_dsi_number_of_data_lanes = 4,
964 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
965 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
966 .mipi_dsi_delay_after_set_display_on_ms = 200
967#else
968#error MIPI LCD panel needs configuration parameters
969#endif
970 };
971
972 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
973 printf("SSD2828: SPI pins are not properly configured\n");
974 return 1;
975 }
976 if (cfg.reset_pin == -1) {
977 printf("SSD2828: Reset pin is not properly configured\n");
978 return 1;
979 }
980
981 return ssd2828_init(&cfg, mode);
982}
983#endif /* CONFIG_VIDEO_LCD_SSD2828 */
984
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200985static void sunxi_engines_init(void)
986{
987 sunxi_composer_init();
988 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +0100989 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200990}
991
Hans de Goede1c092202014-12-21 14:37:45 +0100992static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100993 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200994{
Hans de Goeded9786d22014-12-25 13:58:06 +0100995 int __maybe_unused clk_div, clk_double;
996
Hans de Goede0e045212014-12-21 14:49:34 +0100997 switch (sunxi_display.monitor) {
998 case sunxi_monitor_none:
999 break;
1000 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001001 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001002#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001003 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001004 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001005 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1006 sunxi_composer_enable();
1007 sunxi_lcdc_enable();
1008 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001009#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001010 break;
1011 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001012 sunxi_lcdc_panel_enable();
Hans de Goede27515b22015-01-20 09:23:36 +01001013 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1014 mdelay(50); /* Wait for lcd controller power on */
1015 hitachi_tx18d42vm_init();
1016 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001017 sunxi_composer_mode_set(mode, address);
1018 sunxi_lcdc_tcon0_mode_set(mode);
1019 sunxi_composer_enable();
1020 sunxi_lcdc_enable();
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001021#ifdef CONFIG_VIDEO_LCD_SSD2828
1022 sunxi_ssd2828_init(mode);
1023#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001024 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001025 break;
1026 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001027#ifdef CONFIG_VIDEO_VGA
1028 sunxi_composer_mode_set(mode, address);
1029 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1030 sunxi_vga_mode_set();
1031 sunxi_composer_enable();
1032 sunxi_lcdc_enable();
1033 sunxi_vga_enable();
1034#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001035 sunxi_composer_mode_set(mode, address);
1036 sunxi_lcdc_tcon0_mode_set(mode);
1037 sunxi_composer_enable();
1038 sunxi_lcdc_enable();
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001039 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001040#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001041 break;
1042 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001043}
1044
Hans de Goede1c092202014-12-21 14:37:45 +01001045static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1046{
1047 switch (monitor) {
1048 case sunxi_monitor_none: return "none";
1049 case sunxi_monitor_dvi: return "dvi";
1050 case sunxi_monitor_hdmi: return "hdmi";
1051 case sunxi_monitor_lcd: return "lcd";
1052 case sunxi_monitor_vga: return "vga";
1053 }
1054 return NULL; /* never reached */
1055}
1056
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001057void *video_hw_init(void)
1058{
1059 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001060 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001061 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001062 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001063#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001064 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001065#endif
Hans de Goede1c092202014-12-21 14:37:45 +01001066 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001067 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001068 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001069
1070 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1071
1072 printf("Reserved %dkB of RAM for Framebuffer.\n",
1073 CONFIG_SUNXI_FB_SIZE >> 10);
1074 gd->fb_base = gd->ram_top;
1075
Hans de Goede2dae8002014-12-21 16:28:32 +01001076 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1077 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001078#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001079 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001080 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001081 edid = video_get_option_int(options, "edid", 1);
Hans de Goede1c092202014-12-21 14:37:45 +01001082 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001083#elif defined CONFIG_VIDEO_VGA_VIA_LCD
1084 sunxi_display.monitor = sunxi_monitor_vga;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001085#else
1086 sunxi_display.monitor = sunxi_monitor_lcd;
1087#endif
Hans de Goede1c092202014-12-21 14:37:45 +01001088 video_get_option_string(options, "monitor", mon, sizeof(mon),
1089 sunxi_get_mon_desc(sunxi_display.monitor));
1090 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1091 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1092 sunxi_display.monitor = i;
1093 break;
1094 }
1095 }
1096 if (i > SUNXI_MONITOR_LAST)
1097 printf("Unknown monitor: '%s', falling back to '%s'\n",
1098 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001099
Hans de Goede49d27032014-12-25 13:52:04 +01001100#ifdef CONFIG_VIDEO_HDMI
1101 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1102 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1103 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001104 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001105 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001106 if (ret) {
1107 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001108 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1109 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001110 } else if (hpd) {
1111 sunxi_hdmi_shutdown();
1112 /* Fallback to lcd / vga / none */
1113 if (lcd_mode[0]) {
1114 sunxi_display.monitor = sunxi_monitor_lcd;
1115 } else {
Hans de Goeded9786d22014-12-25 13:58:06 +01001116#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goede49d27032014-12-25 13:52:04 +01001117 sunxi_display.monitor = sunxi_monitor_vga;
1118#else
1119 sunxi_display.monitor = sunxi_monitor_none;
1120#endif
1121 }
1122 } /* else continue with hdmi/dvi without a cable connected */
1123 }
1124#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001125
Hans de Goede49d27032014-12-25 13:52:04 +01001126 switch (sunxi_display.monitor) {
1127 case sunxi_monitor_none:
1128 return NULL;
1129 case sunxi_monitor_dvi:
1130 case sunxi_monitor_hdmi:
1131#ifdef CONFIG_VIDEO_HDMI
1132 break;
1133#else
1134 printf("HDMI/DVI not supported on this board\n");
1135 sunxi_display.monitor = sunxi_monitor_none;
1136 return NULL;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001137#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001138 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001139 if (lcd_mode[0]) {
1140 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1141 mode = &custom;
1142 break;
1143 }
Hans de Goede0e045212014-12-21 14:49:34 +01001144 printf("LCD not supported on this board\n");
Hans de Goedeb98d0482014-12-24 19:47:14 +01001145 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede0e045212014-12-21 14:49:34 +01001146 return NULL;
1147 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001148#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001149 sunxi_display.depth = 18;
1150 break;
1151#else
Hans de Goede0e045212014-12-21 14:49:34 +01001152 printf("VGA not supported on this board\n");
Hans de Goedeb98d0482014-12-24 19:47:14 +01001153 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede0e045212014-12-21 14:49:34 +01001154 return NULL;
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001155#endif
Hans de Goede75481602014-12-19 16:05:12 +01001156 }
1157
Hans de Goede5f339932014-12-19 14:03:40 +01001158 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1159 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1160 mode = &res_mode_init[RES_MODE_1024x768];
1161 } else {
Hans de Goede1c092202014-12-21 14:37:45 +01001162 printf("Setting up a %dx%d %s console\n", mode->xres,
1163 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001164 }
1165
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001166 sunxi_engines_init();
Hans de Goede1c092202014-12-21 14:37:45 +01001167 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001168
1169 /*
1170 * These are the only members of this structure that are used. All the
1171 * others are driver specific. There is nothing to decribe pitch or
1172 * stride, but we are lucky with our hw.
1173 */
1174 graphic_device->frameAdrs = gd->fb_base;
1175 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1176 graphic_device->gdfBytesPP = 4;
Hans de Goedebe8ec632014-12-19 13:46:33 +01001177 graphic_device->winSizeX = mode->xres;
1178 graphic_device->winSizeY = mode->yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001179
1180 return graphic_device;
1181}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001182
1183/*
1184 * Simplefb support.
1185 */
1186#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1187int sunxi_simplefb_setup(void *blob)
1188{
1189 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1190 int offset, ret;
Hans de Goede2dae8002014-12-21 16:28:32 +01001191 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001192
Hans de Goede7cd6f922015-01-19 08:44:07 +01001193#ifdef CONFIG_MACH_SUN4I
1194#define PIPELINE_PREFIX "de_fe0-"
1195#else
1196#define PIPELINE_PREFIX
1197#endif
1198
Hans de Goede2dae8002014-12-21 16:28:32 +01001199 switch (sunxi_display.monitor) {
1200 case sunxi_monitor_none:
1201 return 0;
1202 case sunxi_monitor_dvi:
1203 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001204 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001205 break;
1206 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001207 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001208 break;
1209 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001210#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001211 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001212#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001213 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001214#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001215 break;
1216 }
1217
1218 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001219 offset = fdt_node_offset_by_compatible(blob, -1,
1220 "allwinner,simple-framebuffer");
1221 while (offset >= 0) {
1222 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede2dae8002014-12-21 16:28:32 +01001223 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001224 if (ret == 0)
1225 break;
1226 offset = fdt_node_offset_by_compatible(blob, offset,
1227 "allwinner,simple-framebuffer");
1228 }
1229 if (offset < 0) {
1230 eprintf("Cannot setup simplefb: node not found\n");
1231 return 0; /* Keep older kernels working */
1232 }
1233
1234 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1235 graphic_device->winSizeX, graphic_device->winSizeY,
1236 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1237 "x8r8g8b8");
1238 if (ret)
1239 eprintf("Cannot setup simplefb: Error setting properties\n");
1240
1241 return ret;
1242}
1243#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */