blob: fa4241ef580be82844bfd1de0ae5939067143c82 [file] [log] [blame]
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001/*
2 * Display driver for Allwinner SoCs.
3 *
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
5 * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 */
9
10#include <common.h>
11
12#include <asm/arch/clock.h>
13#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020015#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010016#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020017#include <asm/io.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010018#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020019#include <fdtdec.h>
20#include <fdt_support.h>
Hans de Goede613dade2015-02-16 17:49:47 +010021#include <i2c.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020022#include <video_fb.h>
Hans de Goedeccb0ed52014-12-19 13:46:33 +010023#include "videomodes.h"
Hans de Goede743fb9552015-01-20 09:23:36 +010024#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashkac02f0522015-01-19 05:23:33 +020025#include "ssd2828.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020026
Hans de Goede2d5d3022015-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 Verhaegenb01df1e2014-08-13 07:55:06 +020035DECLARE_GLOBAL_DATA_PTR;
36
Hans de Goedea0b1b732014-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 Verhaegenb01df1e2014-08-13 07:55:06 +020046struct sunxi_display {
47 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010048 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010049 unsigned int depth;
Hans de Goede18799252015-02-02 18:00:53 +010050 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020051} sunxi_display;
52
Hans de Goedee9544592014-12-23 23:04:35 +010053#ifdef CONFIG_VIDEO_HDMI
54
Hans de Goedea5aa95f2014-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 Goede91593712014-12-28 09:13:21 +010071static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-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 Goede91593712014-12-28 09:13:21 +010077 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-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 Goedef07872b2015-04-06 20:33:34 +020087#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +010088 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
89#endif
Luc Verhaegenb01df1e2014-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 Goede205a30c2014-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200102
Hans de Goede205a30c2014-12-20 15:15:23 +0100103 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100104}
105
106static 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;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200112
Luc Verhaegenb01df1e2014-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 Goedef07872b2015-04-06 20:33:34 +0200116#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100117 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
118#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200119 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200120}
121
Hans de Goedea5aa95f2014-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 Goede45b8f7b2014-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 Goedea0b1b732014-12-21 14:37:45 +0100188static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100189{
190 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100191 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-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 Goede1ff6cc42014-12-20 14:31:45 +0100198 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-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 Goede45b8f7b2014-12-20 14:01:48 +0100222 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-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 Goedea5aa95f2014-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 Goedea5aa95f2014-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 Goede1ff6cc42014-12-20 14:31:45 +0100269 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100270 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-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 Goedea0b1b732014-12-21 14:37:45 +0100277 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100278 }
279
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100280 return 0;
281}
282
Hans de Goedee9544592014-12-23 23:04:35 +0100283#endif /* CONFIG_VIDEO_HDMI */
284
Hans de Goedec3cc4262015-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 Verhaegenb01df1e2014-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 Goedec3cc4262015-01-19 08:44:07 +0100405 sunxi_frontend_init();
406
Hans de Goedef07872b2015-04-06 20:33:34 +0200407#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200412 /* Clocks on */
413 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100414#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200415 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100416#endif
Luc Verhaegenb01df1e2014-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 Goedeccb0ed52014-12-19 13:46:33 +0100426static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-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 Goedec3cc4262015-01-19 08:44:07 +0100432 sunxi_frontend_mode_set(mode, address);
433
Luc Verhaegenb01df1e2014-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 Goedec3cc4262015-01-19 08:44:07 +0100438#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-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 Goedec3cc4262015-01-19 08:44:07 +0100442#else
443 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
444#endif
Luc Verhaegenb01df1e2014-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 Goede4125f922014-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 Goedec3cc4262015-01-19 08:44:07 +0100455 sunxi_frontend_enable();
456
Hans de Goede4125f922014-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 Verhaegenb01df1e2014-08-13 07:55:06 +0200461/*
462 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
463 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100464static void sunxi_lcdc_pll_set(int tcon, int dotclock,
465 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200466{
467 struct sunxi_ccm_reg * const ccm =
468 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100469 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200470 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
471 int best_double = 0;
472
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100473 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100474#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100475 min_m = 6;
476 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100477#endif
478#ifdef CONFIG_VIDEO_LCD_IF_LVDS
479 min_m = max_m = 7;
480#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100481 } else {
482 min_m = 1;
483 max_m = 15;
484 }
485
Luc Verhaegenb01df1e2014-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 Goedec5a3b4b2014-12-21 16:27:45 +0100491 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-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 Goedec5a3b4b2014-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 Verhaegenb01df1e2014-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 Goedef07872b2015-04-06 20:33:34 +0200552#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100553 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
554#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200555 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100556#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200557
558 /* Clock on */
559 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100560#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-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 Goede797a0f52015-01-01 22:04:34 +0100564 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
565#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200566#endif
Luc Verhaegenb01df1e2014-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 Goede4125f922014-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 Goede797a0f52015-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 Goede5f67b862015-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 Goede797a0f52015-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 Goede5f67b862015-05-14 18:52:54 +0200606#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100607}
608
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100609static void sunxi_lcdc_panel_enable(void)
610{
Hans de Goedece9e3322015-02-16 17:26:41 +0100611 int pin, reset_pin;
Hans de Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200618 if (pin >= 0) {
Hans de Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200624 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100625 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100626 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100627 }
628
Hans de Goedece9e3322015-02-16 17:26:41 +0100629 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200630 if (reset_pin >= 0) {
Hans de Goedece9e3322015-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 Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200638 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100639 gpio_request(pin, "lcd_power");
640 gpio_direction_output(pin, 1);
641 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100642
Hans de Goede7783ab22015-04-22 17:45:59 +0200643 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100644 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200658 if (pin >= 0)
Hans de Goede7e68a1b2014-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 Goede7783ab22015-04-22 17:45:59 +0200662 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100663 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100664}
665
Hans de Goede3cbcb272015-08-02 17:38:43 +0200666static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100667{
668 int delay;
669
Hans de Goede3cbcb272015-08-02 17:38:43 +0200670 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
671 if (tcon == 1)
672 delay -= 2;
673
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100674 return (delay > 30) ? 30 : delay;
675}
676
Hans de Goede18366f72015-01-25 15:33:07 +0100677static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
678 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100679{
680 struct sunxi_lcdc_reg * const lcdc =
681 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
682 int bp, clk_delay, clk_div, clk_double, pin, total, val;
683
684 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede797a0f52015-01-01 22:04:34 +0100685#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100686 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100687#endif
688#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100689 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100690#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100691
692 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
693
694 /* Use tcon0 */
695 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
696 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
697
Hans de Goede3cbcb272015-08-02 17:38:43 +0200698 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100699 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
700 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
701
702 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
703 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
704
705 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
706 &lcdc->tcon0_timing_active);
707
708 bp = mode->hsync_len + mode->left_margin;
709 total = mode->xres + mode->right_margin + bp;
710 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
711 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
712
713 bp = mode->vsync_len + mode->upper_margin;
714 total = mode->yres + mode->lower_margin + bp;
715 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
716 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
717
Hans de Goede797a0f52015-01-01 22:04:34 +0100718#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100719 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
720 &lcdc->tcon0_timing_sync);
721
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100722 writel(0, &lcdc->tcon0_hv_intf);
723 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100724#endif
725#ifdef CONFIG_VIDEO_LCD_IF_LVDS
726 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede5f67b862015-05-14 18:52:54 +0200727 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
728 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100729#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100730
731 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
732 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
733 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
734 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
735 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
736 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
737 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
738 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
739 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
740 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
741 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
742 writel(((sunxi_display.depth == 18) ?
743 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
744 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
745 &lcdc->tcon0_frm_ctrl);
746 }
747
Hans de Goede481b6642015-01-13 13:21:46 +0100748 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100749 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
750 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
751 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
752 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goede18366f72015-01-25 15:33:07 +0100753
754#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
755 if (for_ext_vga_dac)
756 val = 0;
757#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100758 writel(val, &lcdc->tcon0_io_polarity);
759
760 writel(0, &lcdc->tcon0_io_tristate);
761}
762
Hans de Goede260f5202014-12-25 13:58:06 +0100763#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
Hans de Goede4125f922014-12-21 14:49:34 +0100764static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100765 int *clk_div, int *clk_double,
766 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200767{
768 struct sunxi_lcdc_reg * const lcdc =
769 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedec3d15042014-12-27 15:19:23 +0100770 int bp, clk_delay, total, val;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200771
772 /* Use tcon1 */
773 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
774 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
775
Hans de Goede3cbcb272015-08-02 17:38:43 +0200776 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200777 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedeac5d43d2014-12-24 19:50:11 +0100778 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200779
780 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
781 &lcdc->tcon1_timing_source);
782 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
783 &lcdc->tcon1_timing_scale);
784 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
785 &lcdc->tcon1_timing_out);
786
787 bp = mode->hsync_len + mode->left_margin;
788 total = mode->xres + mode->right_margin + bp;
789 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
790 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
791
792 bp = mode->vsync_len + mode->upper_margin;
793 total = mode->yres + mode->lower_margin + bp;
794 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
795 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
796
797 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
798 &lcdc->tcon1_timing_sync);
799
Hans de Goedec3d15042014-12-27 15:19:23 +0100800 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100801 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
802 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100803
804 val = 0;
805 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
806 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
807 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
808 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
809 writel(val, &lcdc->tcon1_io_polarity);
810
811 clrbits_le32(&lcdc->tcon1_io_tristate,
812 SUNXI_LCDC_TCON_VSYNC_MASK |
813 SUNXI_LCDC_TCON_HSYNC_MASK);
814 }
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100815 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200816}
Hans de Goede260f5202014-12-25 13:58:06 +0100817#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
818
819#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100820
Hans de Goedea2017e82014-12-20 13:38:06 +0100821static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
822{
823 struct sunxi_hdmi_reg * const hdmi =
824 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
825 u8 checksum = 0;
826 u8 avi_info_frame[17] = {
827 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829 0x00
830 };
831 u8 vendor_info_frame[19] = {
832 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834 0x00, 0x00, 0x00
835 };
836 int i;
837
838 if (mode->pixclock_khz <= 27000)
839 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
840 else
841 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
842
843 if (mode->xres * 100 / mode->yres < 156)
844 avi_info_frame[5] |= 0x18; /* 4 : 3 */
845 else
846 avi_info_frame[5] |= 0x28; /* 16 : 9 */
847
848 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
849 checksum += avi_info_frame[i];
850
851 avi_info_frame[3] = 0x100 - checksum;
852
853 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
854 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
855
856 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
857 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
858
859 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
860 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
861
862 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
863 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
864
865 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
866}
867
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100868static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100869 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200870{
871 struct sunxi_hdmi_reg * const hdmi =
872 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
873 int x, y;
874
875 /* Write clear interrupt status bits */
876 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
877
Hans de Goedea0b1b732014-12-21 14:37:45 +0100878 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100879 sunxi_hdmi_setup_info_frames(mode);
880
Hans de Goede95576692014-12-20 13:51:16 +0100881 /* Set input sync enable */
882 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
883
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200884 /* Init various registers, select pll3 as clock source */
885 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
886 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
887 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
888 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
889 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
890
891 /* Setup clk div and doubler */
892 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
893 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
894 if (!clk_double)
895 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
896
897 /* Setup timing registers */
898 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
899 &hdmi->video_size);
900
901 x = mode->hsync_len + mode->left_margin;
902 y = mode->vsync_len + mode->upper_margin;
903 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
904
905 x = mode->right_margin;
906 y = mode->lower_margin;
907 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
908
909 x = mode->hsync_len;
910 y = mode->vsync_len;
911 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
912
913 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
914 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
915
916 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
917 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
918}
919
Hans de Goede4125f922014-12-21 14:49:34 +0100920static void sunxi_hdmi_enable(void)
921{
922 struct sunxi_hdmi_reg * const hdmi =
923 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
924
925 udelay(100);
926 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
927}
928
Hans de Goedee9544592014-12-23 23:04:35 +0100929#endif /* CONFIG_VIDEO_HDMI */
930
Hans de Goede260f5202014-12-25 13:58:06 +0100931#ifdef CONFIG_VIDEO_VGA
932
933static void sunxi_vga_mode_set(void)
934{
935 struct sunxi_ccm_reg * const ccm =
936 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
937 struct sunxi_tve_reg * const tve =
938 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
939
940 /* Clock on */
941 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
942
943 /* Set TVE in VGA mode */
944 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
945 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
946 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
947 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
948 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
949 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
950}
951
952static void sunxi_vga_enable(void)
953{
954 struct sunxi_tve_reg * const tve =
955 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
956
957 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
958}
959
960#endif /* CONFIG_VIDEO_VGA */
961
Hans de Goede115e4b42014-12-23 18:39:52 +0100962static void sunxi_drc_init(void)
963{
Hans de Goedef07872b2015-04-06 20:33:34 +0200964#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100965 struct sunxi_ccm_reg * const ccm =
966 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
967
968 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530969#ifdef CONFIG_MACH_SUN8I_A33
970 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
971#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100972 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
973 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
974#endif
975}
976
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800977#ifdef CONFIG_VIDEO_VGA_VIA_LCD
978static void sunxi_vga_external_dac_enable(void)
979{
980 int pin;
981
982 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200983 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800984 gpio_request(pin, "vga_enable");
985 gpio_direction_output(pin, 1);
986 }
987}
988#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
989
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200990#ifdef CONFIG_VIDEO_LCD_SSD2828
991static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
992{
993 struct ssd2828_config cfg = {
994 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
995 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
996 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
997 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
998 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
999 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1000 .ssd2828_color_depth = 24,
1001#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1002 .mipi_dsi_number_of_data_lanes = 4,
1003 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1004 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1005 .mipi_dsi_delay_after_set_display_on_ms = 200
1006#else
1007#error MIPI LCD panel needs configuration parameters
1008#endif
1009 };
1010
1011 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1012 printf("SSD2828: SPI pins are not properly configured\n");
1013 return 1;
1014 }
1015 if (cfg.reset_pin == -1) {
1016 printf("SSD2828: Reset pin is not properly configured\n");
1017 return 1;
1018 }
1019
1020 return ssd2828_init(&cfg, mode);
1021}
1022#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1023
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001024static void sunxi_engines_init(void)
1025{
1026 sunxi_composer_init();
1027 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +01001028 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001029}
1030
Hans de Goedea0b1b732014-12-21 14:37:45 +01001031static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +01001032 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001033{
Hans de Goede260f5202014-12-25 13:58:06 +01001034 int __maybe_unused clk_div, clk_double;
1035
Hans de Goede4125f922014-12-21 14:49:34 +01001036 switch (sunxi_display.monitor) {
1037 case sunxi_monitor_none:
1038 break;
1039 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001040 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001041#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001042 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001043 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001044 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1045 sunxi_composer_enable();
1046 sunxi_lcdc_enable();
1047 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001048#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001049 break;
1050 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001051 sunxi_lcdc_panel_enable();
Hans de Goede743fb9552015-01-20 09:23:36 +01001052 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1053 mdelay(50); /* Wait for lcd controller power on */
1054 hitachi_tx18d42vm_init();
1055 }
Hans de Goede613dade2015-02-16 17:49:47 +01001056 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1057 unsigned int orig_i2c_bus = i2c_get_bus_num();
1058 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1059 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1060 i2c_set_bus_num(orig_i2c_bus);
1061 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001062 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001063 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001064 sunxi_composer_enable();
1065 sunxi_lcdc_enable();
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001066#ifdef CONFIG_VIDEO_LCD_SSD2828
1067 sunxi_ssd2828_init(mode);
1068#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001069 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001070 break;
1071 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001072#ifdef CONFIG_VIDEO_VGA
1073 sunxi_composer_mode_set(mode, address);
1074 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1075 sunxi_vga_mode_set();
1076 sunxi_composer_enable();
1077 sunxi_lcdc_enable();
1078 sunxi_vga_enable();
1079#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001080 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001081 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001082 sunxi_composer_enable();
1083 sunxi_lcdc_enable();
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001084 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001085#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001086 break;
1087 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001088}
1089
Hans de Goedea0b1b732014-12-21 14:37:45 +01001090static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1091{
1092 switch (monitor) {
1093 case sunxi_monitor_none: return "none";
1094 case sunxi_monitor_dvi: return "dvi";
1095 case sunxi_monitor_hdmi: return "hdmi";
1096 case sunxi_monitor_lcd: return "lcd";
1097 case sunxi_monitor_vga: return "vga";
1098 }
1099 return NULL; /* never reached */
1100}
1101
Hans de Goede6c912862015-02-02 17:13:29 +01001102ulong board_get_usable_ram_top(ulong total_size)
1103{
1104 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1105}
1106
Hans de Goedea2bba492015-08-03 23:01:38 +02001107static bool sunxi_has_hdmi(void)
1108{
1109#ifdef CONFIG_VIDEO_HDMI
1110 return true;
1111#else
1112 return false;
1113#endif
1114}
1115
1116static bool sunxi_has_lcd(void)
1117{
1118 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1119
1120 return lcd_mode[0] != 0;
1121}
1122
1123static bool sunxi_has_vga(void)
1124{
1125#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1126 return true;
1127#else
1128 return false;
1129#endif
1130}
1131
1132static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1133{
1134 if (allow_hdmi && sunxi_has_hdmi())
1135 return sunxi_monitor_dvi;
1136 else if (sunxi_has_lcd())
1137 return sunxi_monitor_lcd;
1138 else if (sunxi_has_vga())
1139 return sunxi_monitor_vga;
1140 else
1141 return sunxi_monitor_none;
1142}
1143
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001144void *video_hw_init(void)
1145{
1146 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001147 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001148 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001149 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001150#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001151 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001152#endif
Hans de Goedea0b1b732014-12-21 14:37:45 +01001153 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001154 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Hans de Goedee9544592014-12-23 23:04:35 +01001155 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001156
1157 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1158
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001159 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1160 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001161#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001162 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001163 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001164 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001165#endif
Hans de Goedea2bba492015-08-03 23:01:38 +02001166 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001167 video_get_option_string(options, "monitor", mon, sizeof(mon),
1168 sunxi_get_mon_desc(sunxi_display.monitor));
1169 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1170 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1171 sunxi_display.monitor = i;
1172 break;
1173 }
1174 }
1175 if (i > SUNXI_MONITOR_LAST)
1176 printf("Unknown monitor: '%s', falling back to '%s'\n",
1177 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001178
Hans de Goede7977ec22014-12-25 13:52:04 +01001179#ifdef CONFIG_VIDEO_HDMI
1180 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1181 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1182 sunxi_display.monitor == sunxi_monitor_hdmi) {
1183 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001184 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001185 if (ret) {
1186 printf("HDMI connected: ");
1187 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1188 mode = &custom;
1189 } else if (hpd) {
1190 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001191 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001192 } /* else continue with hdmi/dvi without a cable connected */
1193 }
1194#endif
1195
Hans de Goede4125f922014-12-21 14:49:34 +01001196 switch (sunxi_display.monitor) {
1197 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001198 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001199 case sunxi_monitor_dvi:
1200 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001201 if (!sunxi_has_hdmi()) {
1202 printf("HDMI/DVI not supported on this board\n");
1203 sunxi_display.monitor = sunxi_monitor_none;
1204 return NULL;
1205 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001206 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001207 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001208 if (!sunxi_has_lcd()) {
1209 printf("LCD not supported on this board\n");
1210 sunxi_display.monitor = sunxi_monitor_none;
1211 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001212 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001213 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1214 mode = &custom;
1215 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001216 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001217 if (!sunxi_has_vga()) {
1218 printf("VGA not supported on this board\n");
1219 sunxi_display.monitor = sunxi_monitor_none;
1220 return NULL;
1221 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001222 sunxi_display.depth = 18;
1223 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001224 }
1225
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001226 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1227 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1228 mode = &res_mode_init[RES_MODE_1024x768];
1229 } else {
Hans de Goedea0b1b732014-12-21 14:37:45 +01001230 printf("Setting up a %dx%d %s console\n", mode->xres,
1231 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001232 }
1233
Hans de Goede18799252015-02-02 18:00:53 +01001234 sunxi_display.fb_size =
1235 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1236 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1237 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1238 sunxi_display.fb_size >> 10,
1239 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1240 return NULL;
1241 }
1242
1243 gd->fb_base = gd->bd->bi_dram[0].start +
1244 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001245 sunxi_engines_init();
Hans de Goedea0b1b732014-12-21 14:37:45 +01001246 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001247
1248 /*
1249 * These are the only members of this structure that are used. All the
1250 * others are driver specific. There is nothing to decribe pitch or
1251 * stride, but we are lucky with our hw.
1252 */
1253 graphic_device->frameAdrs = gd->fb_base;
1254 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1255 graphic_device->gdfBytesPP = 4;
Hans de Goedeccb0ed52014-12-19 13:46:33 +01001256 graphic_device->winSizeX = mode->xres;
1257 graphic_device->winSizeY = mode->yres;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001258
1259 return graphic_device;
1260}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001261
1262/*
1263 * Simplefb support.
1264 */
1265#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1266int sunxi_simplefb_setup(void *blob)
1267{
1268 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1269 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001270 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001271 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001272
Hans de Goedec3cc4262015-01-19 08:44:07 +01001273#ifdef CONFIG_MACH_SUN4I
1274#define PIPELINE_PREFIX "de_fe0-"
1275#else
1276#define PIPELINE_PREFIX
1277#endif
1278
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001279 switch (sunxi_display.monitor) {
1280 case sunxi_monitor_none:
1281 return 0;
1282 case sunxi_monitor_dvi:
1283 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001284 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001285 break;
1286 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001287 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001288 break;
1289 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001290#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001291 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001292#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001293 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001294#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001295 break;
1296 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001297
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001298 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001299 offset = fdt_node_offset_by_compatible(blob, -1,
1300 "allwinner,simple-framebuffer");
1301 while (offset >= 0) {
1302 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001303 pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001304 if (ret == 0)
1305 break;
1306 offset = fdt_node_offset_by_compatible(blob, offset,
1307 "allwinner,simple-framebuffer");
1308 }
1309 if (offset < 0) {
1310 eprintf("Cannot setup simplefb: node not found\n");
1311 return 0; /* Keep older kernels working */
1312 }
1313
Hans de Goede6c912862015-02-02 17:13:29 +01001314 /*
1315 * Do not report the framebuffer as free RAM to the OS, note we cannot
1316 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1317 * and e.g. Linux refuses to iomap RAM on ARM, see:
1318 * linux/arch/arm/mm/ioremap.c around line 301.
1319 */
1320 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001321 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001322 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1323 if (ret) {
1324 eprintf("Cannot setup simplefb: Error reserving memory\n");
1325 return ret;
1326 }
1327
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001328 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1329 graphic_device->winSizeX, graphic_device->winSizeY,
1330 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1331 "x8r8g8b8");
1332 if (ret)
1333 eprintf("Cannot setup simplefb: Error setting properties\n");
1334
1335 return ret;
1336}
1337#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */