blob: 269083b6664ec4593de7d477d120ea3f7a8f860a [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>
Hans de Goedeaad2ac22015-02-16 17:49:47 +010021#include <i2c.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020022#include <video_fb.h>
Hans de Goedebe8ec632014-12-19 13:46:33 +010023#include "videomodes.h"
Hans de Goede27515b22015-01-20 09:23:36 +010024#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashka97ece832015-01-19 05:23:33 +020025#include "ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020026
Hans de Goedea7403ae2015-01-22 21:02:42 +010027#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
28#define PWM_ON 0
29#define PWM_OFF 1
30#else
31#define PWM_ON 1
32#define PWM_OFF 0
33#endif
34
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020035DECLARE_GLOBAL_DATA_PTR;
36
Hans de Goede1c092202014-12-21 14:37:45 +010037enum sunxi_monitor {
38 sunxi_monitor_none,
39 sunxi_monitor_dvi,
40 sunxi_monitor_hdmi,
41 sunxi_monitor_lcd,
42 sunxi_monitor_vga,
43};
44#define SUNXI_MONITOR_LAST sunxi_monitor_vga
45
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020046struct sunxi_display {
47 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010048 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010049 unsigned int depth;
Hans de Goede20779ec2015-02-02 18:00:53 +010050 unsigned int fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020051} sunxi_display;
52
Hans de Goede2fbf0912014-12-23 23:04:35 +010053#ifdef CONFIG_VIDEO_HDMI
54
Hans de Goede75481602014-12-19 16:05:12 +010055/*
56 * Wait up to 200ms for value to be set in given part of reg.
57 */
58static int await_completion(u32 *reg, u32 mask, u32 val)
59{
60 unsigned long tmo = timer_get_us() + 200000;
61
62 while ((readl(reg) & mask) != val) {
63 if (timer_get_us() > tmo) {
64 printf("DDC: timeout reading EDID\n");
65 return -ETIME;
66 }
67 }
68 return 0;
69}
70
Hans de Goede7fad8a92014-12-28 09:13:21 +010071static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020072{
73 struct sunxi_ccm_reg * const ccm =
74 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
75 struct sunxi_hdmi_reg * const hdmi =
76 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede7fad8a92014-12-28 09:13:21 +010077 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020078
79 /* Set pll3 to 300MHz */
80 clock_set_pll3(300000000);
81
82 /* Set hdmi parent to pll3 */
83 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
84 CCM_HDMI_CTRL_PLL3);
85
86 /* Set ahb gating to pass */
Hans de Goede44d8ae52015-04-06 20:33:34 +020087#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +010088 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
89#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020090 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
91
92 /* Clock on */
93 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
94
95 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
96 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
97
Hans de Goede40f1b872014-12-20 15:15:23 +010098 while (timer_get_us() < tmo) {
99 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
100 return 1;
101 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200102
Hans de Goede40f1b872014-12-20 15:15:23 +0100103 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100104}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200105
Hans de Goede518cef22014-12-19 15:13:57 +0100106static void sunxi_hdmi_shutdown(void)
107{
108 struct sunxi_ccm_reg * const ccm =
109 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
110 struct sunxi_hdmi_reg * const hdmi =
111 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
112
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200113 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
114 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
115 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goede44d8ae52015-04-06 20:33:34 +0200116#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100117 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
118#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200119 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200120}
121
Hans de Goede75481602014-12-19 16:05:12 +0100122static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
123{
124 struct sunxi_hdmi_reg * const hdmi =
125 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
126
127 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
128 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
129 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
130 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
131 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
132#ifndef CONFIG_MACH_SUN6I
133 writel(n, &hdmi->ddc_byte_count);
134 writel(cmnd, &hdmi->ddc_cmnd);
135#else
136 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
137#endif
138 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
139
140 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
141}
142
143static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
144{
145 struct sunxi_hdmi_reg * const hdmi =
146 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
147 int i, n;
148
149 while (count > 0) {
150 if (count > 16)
151 n = 16;
152 else
153 n = count;
154
155 if (sunxi_hdmi_ddc_do_command(
156 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
157 offset, n))
158 return -ETIME;
159
160 for (i = 0; i < n; i++)
161 *buf++ = readb(&hdmi->ddc_fifo_data);
162
163 offset += n;
164 count -= n;
165 }
166
167 return 0;
168}
169
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100170static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
171{
172 int r, retries = 2;
173
174 do {
175 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
176 if (r)
177 continue;
178 r = edid_check_checksum(buf);
179 if (r) {
180 printf("EDID block %d: checksum error%s\n",
181 block, retries ? ", retrying" : "");
182 }
183 } while (r && retries--);
184
185 return r;
186}
187
Hans de Goede1c092202014-12-21 14:37:45 +0100188static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100189{
190 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100191 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-12-19 16:05:12 +0100192 struct edid_detailed_timing *t =
193 (struct edid_detailed_timing *)edid1.monitor_details.timing;
194 struct sunxi_hdmi_reg * const hdmi =
195 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
196 struct sunxi_ccm_reg * const ccm =
197 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedef3000682014-12-20 14:31:45 +0100198 int i, r, ext_blocks = 0;
Hans de Goede75481602014-12-19 16:05:12 +0100199
200 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
201 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
202 &hdmi->pad_ctrl1);
203 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
204 &hdmi->pll_ctrl);
205 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
206
207 /* Reset i2c controller */
208 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
209 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
210 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
211 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
212 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
213 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
214 return -EIO;
215
216 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
217#ifndef CONFIG_MACH_SUN6I
218 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
219 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
220#endif
221
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100222 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-12-20 14:31:45 +0100223 if (r == 0) {
224 r = edid_check_info(&edid1);
225 if (r) {
226 printf("EDID: invalid EDID data\n");
227 r = -EINVAL;
228 }
229 }
230 if (r == 0) {
231 ext_blocks = edid1.extension_flag;
232 if (ext_blocks > 4)
233 ext_blocks = 4;
234 for (i = 0; i < ext_blocks; i++) {
235 if (sunxi_hdmi_edid_get_block(1 + i,
236 (u8 *)&cea681[i]) != 0) {
237 ext_blocks = i;
238 break;
239 }
240 }
241 }
Hans de Goede75481602014-12-19 16:05:12 +0100242
243 /* Disable DDC engine, no longer needed */
244 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
245 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
246
247 if (r)
248 return r;
249
Hans de Goede75481602014-12-19 16:05:12 +0100250 /* We want version 1.3 or 1.2 with detailed timing info */
251 if (edid1.version != 1 || (edid1.revision < 3 &&
252 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
253 printf("EDID: unsupported version %d.%d\n",
254 edid1.version, edid1.revision);
255 return -EINVAL;
256 }
257
258 /* Take the first usable detailed timing */
259 for (i = 0; i < 4; i++, t++) {
260 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
261 if (r == 0)
262 break;
263 }
264 if (i == 4) {
265 printf("EDID: no usable detailed timing found\n");
266 return -ENOENT;
267 }
268
Hans de Goedef3000682014-12-20 14:31:45 +0100269 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100270 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-12-20 14:31:45 +0100271 for (i = 0; i < ext_blocks; i++) {
272 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
273 cea681[i].revision < 2)
274 continue;
275
276 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goede1c092202014-12-21 14:37:45 +0100277 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100278 }
279
Hans de Goede75481602014-12-19 16:05:12 +0100280 return 0;
281}
282
Hans de Goede2fbf0912014-12-23 23:04:35 +0100283#endif /* CONFIG_VIDEO_HDMI */
284
Hans de Goede7cd6f922015-01-19 08:44:07 +0100285#ifdef CONFIG_MACH_SUN4I
286/*
287 * Testing has shown that on sun4i the display backend engine does not have
288 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
289 * fifo underruns. So on sun4i we use the display frontend engine to do the
290 * dma from memory, as the frontend does have deep enough fifo-s.
291 */
292
293static const u32 sun4i_vert_coef[32] = {
294 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
295 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
296 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
297 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
298 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
299 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
300 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
301 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
302};
303
304static const u32 sun4i_horz_coef[64] = {
305 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
306 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
307 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
308 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
309 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
310 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
311 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
312 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
313 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
314 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
315 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
316 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
317 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
318 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
319 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
320 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
321};
322
323static void sunxi_frontend_init(void)
324{
325 struct sunxi_ccm_reg * const ccm =
326 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
327 struct sunxi_de_fe_reg * const de_fe =
328 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
329 int i;
330
331 /* Clocks on */
332 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
333 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
334 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
335
336 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
337
338 for (i = 0; i < 32; i++) {
339 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
340 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
341 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
342 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
343 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
344 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
345 }
346
347 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
348}
349
350static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
351 unsigned int address)
352{
353 struct sunxi_de_fe_reg * const de_fe =
354 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
355
356 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
357 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
358 writel(mode->xres * 4, &de_fe->ch0_stride);
359 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
360 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
361
362 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
363 &de_fe->ch0_insize);
364 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
365 &de_fe->ch0_outsize);
366 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
367 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
368
369 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
370 &de_fe->ch1_insize);
371 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
372 &de_fe->ch1_outsize);
373 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
374 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
375
376 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
377}
378
379static void sunxi_frontend_enable(void)
380{
381 struct sunxi_de_fe_reg * const de_fe =
382 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
383
384 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
385}
386#else
387static void sunxi_frontend_init(void) {}
388static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
389 unsigned int address) {}
390static void sunxi_frontend_enable(void) {}
391#endif
392
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200393/*
394 * This is the entity that mixes and matches the different layers and inputs.
395 * Allwinner calls it the back-end, but i like composer better.
396 */
397static void sunxi_composer_init(void)
398{
399 struct sunxi_ccm_reg * const ccm =
400 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
401 struct sunxi_de_be_reg * const de_be =
402 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
403 int i;
404
Hans de Goede7cd6f922015-01-19 08:44:07 +0100405 sunxi_frontend_init();
406
Hans de Goede44d8ae52015-04-06 20:33:34 +0200407#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100408 /* Reset off */
409 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
410#endif
411
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200412 /* Clocks on */
413 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100414#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200415 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100416#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200417 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
418
419 /* Engine bug, clear registers after reset */
420 for (i = 0x0800; i < 0x1000; i += 4)
421 writel(0, SUNXI_DE_BE0_BASE + i);
422
423 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
424}
425
Hans de Goedebe8ec632014-12-19 13:46:33 +0100426static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200427 unsigned int address)
428{
429 struct sunxi_de_be_reg * const de_be =
430 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
431
Hans de Goede7cd6f922015-01-19 08:44:07 +0100432 sunxi_frontend_mode_set(mode, address);
433
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200434 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
435 &de_be->disp_size);
436 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
437 &de_be->layer0_size);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100438#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200439 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
440 writel(address << 3, &de_be->layer0_addr_low32b);
441 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100442#else
443 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
444#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200445 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
446
447 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
448}
449
Hans de Goede0e045212014-12-21 14:49:34 +0100450static void sunxi_composer_enable(void)
451{
452 struct sunxi_de_be_reg * const de_be =
453 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
454
Hans de Goede7cd6f922015-01-19 08:44:07 +0100455 sunxi_frontend_enable();
456
Hans de Goede0e045212014-12-21 14:49:34 +0100457 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
458 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
459}
460
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200461/*
462 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
463 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100464static void sunxi_lcdc_pll_set(int tcon, int dotclock,
465 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200466{
467 struct sunxi_ccm_reg * const ccm =
468 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100469 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200470 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
471 int best_double = 0;
472
Hans de Goede5489ebc2014-12-21 16:27:45 +0100473 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100474#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100475 min_m = 6;
476 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100477#endif
478#ifdef CONFIG_VIDEO_LCD_IF_LVDS
479 min_m = max_m = 7;
480#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100481 } else {
482 min_m = 1;
483 max_m = 15;
484 }
485
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200486 /*
487 * Find the lowest divider resulting in a matching clock, if there
488 * is no match, pick the closest lower clock, as monitors tend to
489 * not sync to higher frequencies.
490 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100491 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200492 n = (m * dotclock) / 3000;
493
494 if ((n >= 9) && (n <= 127)) {
495 value = (3000 * n) / m;
496 diff = dotclock - value;
497 if (diff < best_diff) {
498 best_diff = diff;
499 best_m = m;
500 best_n = n;
501 best_double = 0;
502 }
503 }
504
505 /* These are just duplicates */
506 if (!(m & 1))
507 continue;
508
509 n = (m * dotclock) / 6000;
510 if ((n >= 9) && (n <= 127)) {
511 value = (6000 * n) / m;
512 diff = dotclock - value;
513 if (diff < best_diff) {
514 best_diff = diff;
515 best_m = m;
516 best_n = n;
517 best_double = 1;
518 }
519 }
520 }
521
522 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
523 dotclock, (best_double + 1) * 3000 * best_n / best_m,
524 best_double + 1, best_n, best_m);
525
526 clock_set_pll3(best_n * 3000000);
527
Hans de Goede5489ebc2014-12-21 16:27:45 +0100528 if (tcon == 0) {
529 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
530 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
531 CCM_LCD_CH0_CTRL_PLL3),
532 &ccm->lcd0_ch0_clk_cfg);
533 } else {
534 writel(CCM_LCD_CH1_CTRL_GATE |
535 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
536 CCM_LCD_CH1_CTRL_PLL3) |
537 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
538 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200539
540 *clk_div = best_m;
541 *clk_double = best_double;
542}
543
544static void sunxi_lcdc_init(void)
545{
546 struct sunxi_ccm_reg * const ccm =
547 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
548 struct sunxi_lcdc_reg * const lcdc =
549 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
550
551 /* Reset off */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200552#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100553 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
554#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200555 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100556#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200557
558 /* Clock on */
559 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100560#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede83edb2a2015-05-14 18:52:54 +0200561#ifdef CONFIG_SUNXI_GEN_SUN6I
562 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
563#else
Hans de Goede213480e2015-01-01 22:04:34 +0100564 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
565#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200566#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200567
568 /* Init lcdc */
569 writel(0, &lcdc->ctrl); /* Disable tcon */
570 writel(0, &lcdc->int0); /* Disable all interrupts */
571
572 /* Disable tcon0 dot clock */
573 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
574
575 /* Set all io lines to tristate */
576 writel(0xffffffff, &lcdc->tcon0_io_tristate);
577 writel(0xffffffff, &lcdc->tcon1_io_tristate);
578}
579
Hans de Goede0e045212014-12-21 14:49:34 +0100580static void sunxi_lcdc_enable(void)
581{
582 struct sunxi_lcdc_reg * const lcdc =
583 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
584
585 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede213480e2015-01-01 22:04:34 +0100586#ifdef CONFIG_VIDEO_LCD_IF_LVDS
587 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
588 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede83edb2a2015-05-14 18:52:54 +0200589#ifdef CONFIG_SUNXI_GEN_SUN6I
590 udelay(2); /* delay at least 1200 ns */
591 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
592 udelay(2); /* delay at least 1200 ns */
593 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
594 if (sunxi_display.depth == 18)
595 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
596 else
597 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
598#else
Hans de Goede213480e2015-01-01 22:04:34 +0100599 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
600 udelay(2); /* delay at least 1200 ns */
601 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
602 udelay(1); /* delay at least 120 ns */
603 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
604 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
605#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200606#endif
Hans de Goede0e045212014-12-21 14:49:34 +0100607}
608
Hans de Goede2dae8002014-12-21 16:28:32 +0100609static void sunxi_lcdc_panel_enable(void)
610{
Hans de Goede242e3d82015-02-16 17:26:41 +0100611 int pin, reset_pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100612
613 /*
614 * Start with backlight disabled to avoid the screen flashing to
615 * white while the lcd inits.
616 */
617 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200618 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100619 gpio_request(pin, "lcd_backlight_enable");
620 gpio_direction_output(pin, 0);
621 }
622
623 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200624 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100625 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goedea7403ae2015-01-22 21:02:42 +0100626 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-12-21 16:28:32 +0100627 }
628
Hans de Goede242e3d82015-02-16 17:26:41 +0100629 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede15728192015-04-22 17:45:59 +0200630 if (reset_pin >= 0) {
Hans de Goede242e3d82015-02-16 17:26:41 +0100631 gpio_request(reset_pin, "lcd_reset");
632 gpio_direction_output(reset_pin, 0); /* Assert reset */
633 }
634
Hans de Goede2dae8002014-12-21 16:28:32 +0100635 /* Give the backlight some time to turn off and power up the panel. */
636 mdelay(40);
637 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede15728192015-04-22 17:45:59 +0200638 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100639 gpio_request(pin, "lcd_power");
640 gpio_direction_output(pin, 1);
641 }
Hans de Goede242e3d82015-02-16 17:26:41 +0100642
Hans de Goede15728192015-04-22 17:45:59 +0200643 if (reset_pin >= 0)
Hans de Goede242e3d82015-02-16 17:26:41 +0100644 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede2dae8002014-12-21 16:28:32 +0100645}
646
647static void sunxi_lcdc_backlight_enable(void)
648{
649 int pin;
650
651 /*
652 * We want to have scanned out at least one frame before enabling the
653 * backlight to avoid the screen flashing to white when we enable it.
654 */
655 mdelay(40);
656
657 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200658 if (pin >= 0)
Hans de Goede2dae8002014-12-21 16:28:32 +0100659 gpio_direction_output(pin, 1);
660
661 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200662 if (pin >= 0)
Hans de Goedea7403ae2015-01-22 21:02:42 +0100663 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-12-21 16:28:32 +0100664}
665
666static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
667{
668 int delay;
669
670 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
671 return (delay > 30) ? 30 : delay;
672}
673
Hans de Goedefb75d972015-01-25 15:33:07 +0100674static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
675 bool for_ext_vga_dac)
Hans de Goede2dae8002014-12-21 16:28:32 +0100676{
677 struct sunxi_lcdc_reg * const lcdc =
678 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
679 int bp, clk_delay, clk_div, clk_double, pin, total, val;
680
681 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede213480e2015-01-01 22:04:34 +0100682#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100683 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100684#endif
685#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100686 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede213480e2015-01-01 22:04:34 +0100687#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100688
689 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
690
691 /* Use tcon0 */
692 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
693 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
694
695 clk_delay = sunxi_lcdc_get_clk_delay(mode);
696 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
697 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
698
699 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
700 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
701
702 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
703 &lcdc->tcon0_timing_active);
704
705 bp = mode->hsync_len + mode->left_margin;
706 total = mode->xres + mode->right_margin + bp;
707 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
708 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
709
710 bp = mode->vsync_len + mode->upper_margin;
711 total = mode->yres + mode->lower_margin + bp;
712 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
713 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
714
Hans de Goede213480e2015-01-01 22:04:34 +0100715#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100716 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
717 &lcdc->tcon0_timing_sync);
718
Hans de Goede2dae8002014-12-21 16:28:32 +0100719 writel(0, &lcdc->tcon0_hv_intf);
720 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100721#endif
722#ifdef CONFIG_VIDEO_LCD_IF_LVDS
723 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede83edb2a2015-05-14 18:52:54 +0200724 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
725 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100726#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100727
728 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
729 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
730 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
731 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
732 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
733 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
734 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
735 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
736 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
737 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
738 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
739 writel(((sunxi_display.depth == 18) ?
740 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
741 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
742 &lcdc->tcon0_frm_ctrl);
743 }
744
Hans de Goede65150322015-01-13 13:21:46 +0100745 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100746 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
747 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
748 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
749 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goedefb75d972015-01-25 15:33:07 +0100750
751#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
752 if (for_ext_vga_dac)
753 val = 0;
754#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100755 writel(val, &lcdc->tcon0_io_polarity);
756
757 writel(0, &lcdc->tcon0_io_tristate);
758}
759
Hans de Goeded9786d22014-12-25 13:58:06 +0100760#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
Hans de Goede0e045212014-12-21 14:49:34 +0100761static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100762 int *clk_div, int *clk_double,
763 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200764{
765 struct sunxi_lcdc_reg * const lcdc =
766 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goede3ffbe472014-12-27 15:19:23 +0100767 int bp, clk_delay, total, val;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200768
769 /* Use tcon1 */
770 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
771 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
772
Hans de Goede6741cc72014-12-24 19:50:11 +0100773 clk_delay = sunxi_lcdc_get_clk_delay(mode);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200774 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goede6741cc72014-12-24 19:50:11 +0100775 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200776
777 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
778 &lcdc->tcon1_timing_source);
779 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
780 &lcdc->tcon1_timing_scale);
781 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
782 &lcdc->tcon1_timing_out);
783
784 bp = mode->hsync_len + mode->left_margin;
785 total = mode->xres + mode->right_margin + bp;
786 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
787 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
788
789 bp = mode->vsync_len + mode->upper_margin;
790 total = mode->yres + mode->lower_margin + bp;
791 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
792 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
793
794 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
795 &lcdc->tcon1_timing_sync);
796
Hans de Goede3ffbe472014-12-27 15:19:23 +0100797 if (use_portd_hvsync) {
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100798 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
799 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goede3ffbe472014-12-27 15:19:23 +0100800
801 val = 0;
802 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
803 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
804 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
805 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
806 writel(val, &lcdc->tcon1_io_polarity);
807
808 clrbits_le32(&lcdc->tcon1_io_tristate,
809 SUNXI_LCDC_TCON_VSYNC_MASK |
810 SUNXI_LCDC_TCON_HSYNC_MASK);
811 }
Hans de Goede5489ebc2014-12-21 16:27:45 +0100812 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200813}
Hans de Goeded9786d22014-12-25 13:58:06 +0100814#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
815
816#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200817
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100818static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
819{
820 struct sunxi_hdmi_reg * const hdmi =
821 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
822 u8 checksum = 0;
823 u8 avi_info_frame[17] = {
824 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
826 0x00
827 };
828 u8 vendor_info_frame[19] = {
829 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00
832 };
833 int i;
834
835 if (mode->pixclock_khz <= 27000)
836 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
837 else
838 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
839
840 if (mode->xres * 100 / mode->yres < 156)
841 avi_info_frame[5] |= 0x18; /* 4 : 3 */
842 else
843 avi_info_frame[5] |= 0x28; /* 16 : 9 */
844
845 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
846 checksum += avi_info_frame[i];
847
848 avi_info_frame[3] = 0x100 - checksum;
849
850 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
851 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
852
853 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
854 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
855
856 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
857 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
858
859 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
860 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
861
862 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
863}
864
Hans de Goedebe8ec632014-12-19 13:46:33 +0100865static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100866 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200867{
868 struct sunxi_hdmi_reg * const hdmi =
869 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
870 int x, y;
871
872 /* Write clear interrupt status bits */
873 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
874
Hans de Goede1c092202014-12-21 14:37:45 +0100875 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100876 sunxi_hdmi_setup_info_frames(mode);
877
Hans de Goede876aaaf2014-12-20 13:51:16 +0100878 /* Set input sync enable */
879 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
880
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200881 /* Init various registers, select pll3 as clock source */
882 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
883 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
884 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
885 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
886 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
887
888 /* Setup clk div and doubler */
889 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
890 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
891 if (!clk_double)
892 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
893
894 /* Setup timing registers */
895 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
896 &hdmi->video_size);
897
898 x = mode->hsync_len + mode->left_margin;
899 y = mode->vsync_len + mode->upper_margin;
900 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
901
902 x = mode->right_margin;
903 y = mode->lower_margin;
904 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
905
906 x = mode->hsync_len;
907 y = mode->vsync_len;
908 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
909
910 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
911 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
912
913 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
914 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
915}
916
Hans de Goede0e045212014-12-21 14:49:34 +0100917static void sunxi_hdmi_enable(void)
918{
919 struct sunxi_hdmi_reg * const hdmi =
920 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
921
922 udelay(100);
923 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
924}
925
Hans de Goede2fbf0912014-12-23 23:04:35 +0100926#endif /* CONFIG_VIDEO_HDMI */
927
Hans de Goeded9786d22014-12-25 13:58:06 +0100928#ifdef CONFIG_VIDEO_VGA
929
930static void sunxi_vga_mode_set(void)
931{
932 struct sunxi_ccm_reg * const ccm =
933 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
934 struct sunxi_tve_reg * const tve =
935 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
936
937 /* Clock on */
938 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
939
940 /* Set TVE in VGA mode */
941 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
942 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
943 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
944 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
945 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
946 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
947}
948
949static void sunxi_vga_enable(void)
950{
951 struct sunxi_tve_reg * const tve =
952 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
953
954 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
955}
956
957#endif /* CONFIG_VIDEO_VGA */
958
Hans de Goedee8400792014-12-23 18:39:52 +0100959static void sunxi_drc_init(void)
960{
Hans de Goede44d8ae52015-04-06 20:33:34 +0200961#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedee8400792014-12-23 18:39:52 +0100962 struct sunxi_ccm_reg * const ccm =
963 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
964
965 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar8c3dacf2015-03-01 23:47:48 +0530966#ifdef CONFIG_MACH_SUN8I_A33
967 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
968#endif
Hans de Goedee8400792014-12-23 18:39:52 +0100969 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
970 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
971#endif
972}
973
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +0800974#ifdef CONFIG_VIDEO_VGA_VIA_LCD
975static void sunxi_vga_external_dac_enable(void)
976{
977 int pin;
978
979 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200980 if (pin >= 0) {
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +0800981 gpio_request(pin, "vga_enable");
982 gpio_direction_output(pin, 1);
983 }
984}
985#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
986
Siarhei Siamashka97ece832015-01-19 05:23:33 +0200987#ifdef CONFIG_VIDEO_LCD_SSD2828
988static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
989{
990 struct ssd2828_config cfg = {
991 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
992 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
993 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
994 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
995 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
996 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
997 .ssd2828_color_depth = 24,
998#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
999 .mipi_dsi_number_of_data_lanes = 4,
1000 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1001 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1002 .mipi_dsi_delay_after_set_display_on_ms = 200
1003#else
1004#error MIPI LCD panel needs configuration parameters
1005#endif
1006 };
1007
1008 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1009 printf("SSD2828: SPI pins are not properly configured\n");
1010 return 1;
1011 }
1012 if (cfg.reset_pin == -1) {
1013 printf("SSD2828: Reset pin is not properly configured\n");
1014 return 1;
1015 }
1016
1017 return ssd2828_init(&cfg, mode);
1018}
1019#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1020
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001021static void sunxi_engines_init(void)
1022{
1023 sunxi_composer_init();
1024 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +01001025 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001026}
1027
Hans de Goede1c092202014-12-21 14:37:45 +01001028static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +01001029 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001030{
Hans de Goeded9786d22014-12-25 13:58:06 +01001031 int __maybe_unused clk_div, clk_double;
1032
Hans de Goede0e045212014-12-21 14:49:34 +01001033 switch (sunxi_display.monitor) {
1034 case sunxi_monitor_none:
1035 break;
1036 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001037 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001038#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001039 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001040 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001041 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1042 sunxi_composer_enable();
1043 sunxi_lcdc_enable();
1044 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001045#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001046 break;
1047 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001048 sunxi_lcdc_panel_enable();
Hans de Goede27515b22015-01-20 09:23:36 +01001049 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1050 mdelay(50); /* Wait for lcd controller power on */
1051 hitachi_tx18d42vm_init();
1052 }
Hans de Goedeaad2ac22015-02-16 17:49:47 +01001053 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1054 unsigned int orig_i2c_bus = i2c_get_bus_num();
1055 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1056 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1057 i2c_set_bus_num(orig_i2c_bus);
1058 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001059 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001060 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede2dae8002014-12-21 16:28:32 +01001061 sunxi_composer_enable();
1062 sunxi_lcdc_enable();
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001063#ifdef CONFIG_VIDEO_LCD_SSD2828
1064 sunxi_ssd2828_init(mode);
1065#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001066 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001067 break;
1068 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001069#ifdef CONFIG_VIDEO_VGA
1070 sunxi_composer_mode_set(mode, address);
1071 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1072 sunxi_vga_mode_set();
1073 sunxi_composer_enable();
1074 sunxi_lcdc_enable();
1075 sunxi_vga_enable();
1076#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001077 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001078 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001079 sunxi_composer_enable();
1080 sunxi_lcdc_enable();
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001081 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001082#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001083 break;
1084 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001085}
1086
Hans de Goede1c092202014-12-21 14:37:45 +01001087static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1088{
1089 switch (monitor) {
1090 case sunxi_monitor_none: return "none";
1091 case sunxi_monitor_dvi: return "dvi";
1092 case sunxi_monitor_hdmi: return "hdmi";
1093 case sunxi_monitor_lcd: return "lcd";
1094 case sunxi_monitor_vga: return "vga";
1095 }
1096 return NULL; /* never reached */
1097}
1098
Hans de Goede5633a292015-02-02 17:13:29 +01001099ulong board_get_usable_ram_top(ulong total_size)
1100{
1101 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1102}
1103
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001104void *video_hw_init(void)
1105{
1106 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001107 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001108 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001109 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001110#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001111 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001112#endif
Hans de Goede1c092202014-12-21 14:37:45 +01001113 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001114 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001115 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001116
1117 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1118
Hans de Goede2dae8002014-12-21 16:28:32 +01001119 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1120 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001121#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001122 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001123 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001124 edid = video_get_option_int(options, "edid", 1);
Hans de Goede1c092202014-12-21 14:37:45 +01001125 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001126#elif defined CONFIG_VIDEO_VGA_VIA_LCD
1127 sunxi_display.monitor = sunxi_monitor_vga;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001128#else
1129 sunxi_display.monitor = sunxi_monitor_lcd;
1130#endif
Hans de Goede1c092202014-12-21 14:37:45 +01001131 video_get_option_string(options, "monitor", mon, sizeof(mon),
1132 sunxi_get_mon_desc(sunxi_display.monitor));
1133 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1134 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1135 sunxi_display.monitor = i;
1136 break;
1137 }
1138 }
1139 if (i > SUNXI_MONITOR_LAST)
1140 printf("Unknown monitor: '%s', falling back to '%s'\n",
1141 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001142
Hans de Goede49d27032014-12-25 13:52:04 +01001143#ifdef CONFIG_VIDEO_HDMI
1144 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1145 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1146 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001147 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001148 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001149 if (ret) {
1150 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001151 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1152 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001153 } else if (hpd) {
1154 sunxi_hdmi_shutdown();
1155 /* Fallback to lcd / vga / none */
1156 if (lcd_mode[0]) {
1157 sunxi_display.monitor = sunxi_monitor_lcd;
1158 } else {
Hans de Goeded9786d22014-12-25 13:58:06 +01001159#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goede49d27032014-12-25 13:52:04 +01001160 sunxi_display.monitor = sunxi_monitor_vga;
1161#else
1162 sunxi_display.monitor = sunxi_monitor_none;
1163#endif
1164 }
1165 } /* else continue with hdmi/dvi without a cable connected */
1166 }
1167#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001168
Hans de Goede49d27032014-12-25 13:52:04 +01001169 switch (sunxi_display.monitor) {
1170 case sunxi_monitor_none:
1171 return NULL;
1172 case sunxi_monitor_dvi:
1173 case sunxi_monitor_hdmi:
1174#ifdef CONFIG_VIDEO_HDMI
1175 break;
1176#else
1177 printf("HDMI/DVI not supported on this board\n");
1178 sunxi_display.monitor = sunxi_monitor_none;
1179 return NULL;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001180#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001181 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001182 if (lcd_mode[0]) {
1183 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1184 mode = &custom;
1185 break;
1186 }
Hans de Goede0e045212014-12-21 14:49:34 +01001187 printf("LCD not supported on this board\n");
Hans de Goedeb98d0482014-12-24 19:47:14 +01001188 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede0e045212014-12-21 14:49:34 +01001189 return NULL;
1190 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001191#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001192 sunxi_display.depth = 18;
1193 break;
1194#else
Hans de Goede0e045212014-12-21 14:49:34 +01001195 printf("VGA not supported on this board\n");
Hans de Goedeb98d0482014-12-24 19:47:14 +01001196 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede0e045212014-12-21 14:49:34 +01001197 return NULL;
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001198#endif
Hans de Goede75481602014-12-19 16:05:12 +01001199 }
1200
Hans de Goede5f339932014-12-19 14:03:40 +01001201 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1202 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1203 mode = &res_mode_init[RES_MODE_1024x768];
1204 } else {
Hans de Goede1c092202014-12-21 14:37:45 +01001205 printf("Setting up a %dx%d %s console\n", mode->xres,
1206 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001207 }
1208
Hans de Goede20779ec2015-02-02 18:00:53 +01001209 sunxi_display.fb_size =
1210 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1211 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1212 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1213 sunxi_display.fb_size >> 10,
1214 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1215 return NULL;
1216 }
1217
1218 gd->fb_base = gd->bd->bi_dram[0].start +
1219 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001220 sunxi_engines_init();
Hans de Goede1c092202014-12-21 14:37:45 +01001221 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001222
1223 /*
1224 * These are the only members of this structure that are used. All the
1225 * others are driver specific. There is nothing to decribe pitch or
1226 * stride, but we are lucky with our hw.
1227 */
1228 graphic_device->frameAdrs = gd->fb_base;
1229 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1230 graphic_device->gdfBytesPP = 4;
Hans de Goedebe8ec632014-12-19 13:46:33 +01001231 graphic_device->winSizeX = mode->xres;
1232 graphic_device->winSizeY = mode->yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001233
1234 return graphic_device;
1235}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001236
1237/*
1238 * Simplefb support.
1239 */
1240#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1241int sunxi_simplefb_setup(void *blob)
1242{
1243 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1244 int offset, ret;
Hans de Goede5633a292015-02-02 17:13:29 +01001245 u64 start, size;
Hans de Goede2dae8002014-12-21 16:28:32 +01001246 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001247
Hans de Goede7cd6f922015-01-19 08:44:07 +01001248#ifdef CONFIG_MACH_SUN4I
1249#define PIPELINE_PREFIX "de_fe0-"
1250#else
1251#define PIPELINE_PREFIX
1252#endif
1253
Hans de Goede2dae8002014-12-21 16:28:32 +01001254 switch (sunxi_display.monitor) {
1255 case sunxi_monitor_none:
1256 return 0;
1257 case sunxi_monitor_dvi:
1258 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001259 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001260 break;
1261 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001262 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001263 break;
1264 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001265#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001266 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001267#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001268 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001269#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001270 break;
1271 }
1272
1273 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001274 offset = fdt_node_offset_by_compatible(blob, -1,
1275 "allwinner,simple-framebuffer");
1276 while (offset >= 0) {
1277 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede2dae8002014-12-21 16:28:32 +01001278 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001279 if (ret == 0)
1280 break;
1281 offset = fdt_node_offset_by_compatible(blob, offset,
1282 "allwinner,simple-framebuffer");
1283 }
1284 if (offset < 0) {
1285 eprintf("Cannot setup simplefb: node not found\n");
1286 return 0; /* Keep older kernels working */
1287 }
1288
Hans de Goede5633a292015-02-02 17:13:29 +01001289 /*
1290 * Do not report the framebuffer as free RAM to the OS, note we cannot
1291 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1292 * and e.g. Linux refuses to iomap RAM on ARM, see:
1293 * linux/arch/arm/mm/ioremap.c around line 301.
1294 */
1295 start = gd->bd->bi_dram[0].start;
Hans de Goede20779ec2015-02-02 18:00:53 +01001296 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede5633a292015-02-02 17:13:29 +01001297 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1298 if (ret) {
1299 eprintf("Cannot setup simplefb: Error reserving memory\n");
1300 return ret;
1301 }
1302
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001303 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1304 graphic_device->winSizeX, graphic_device->winSizeY,
1305 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1306 "x8r8g8b8");
1307 if (ret)
1308 eprintf("Cannot setup simplefb: Error setting properties\n");
1309
1310 return ret;
1311}
1312#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */