blob: f3cc06e2ef370bc3053599561bf753faf4f98bbb [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);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200448 if (mode->vmode == FB_VMODE_INTERLACED)
449 setbits_le32(&de_be->mode,
450 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
451 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200452}
453
Hans de Goede4125f922014-12-21 14:49:34 +0100454static void sunxi_composer_enable(void)
455{
456 struct sunxi_de_be_reg * const de_be =
457 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
458
Hans de Goedec3cc4262015-01-19 08:44:07 +0100459 sunxi_frontend_enable();
460
Hans de Goede4125f922014-12-21 14:49:34 +0100461 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
462 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
463}
464
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200465/*
466 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
467 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100468static void sunxi_lcdc_pll_set(int tcon, int dotclock,
469 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200470{
471 struct sunxi_ccm_reg * const ccm =
472 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100473 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200474 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
475 int best_double = 0;
476
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100477 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100478#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100479 min_m = 6;
480 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100481#endif
482#ifdef CONFIG_VIDEO_LCD_IF_LVDS
483 min_m = max_m = 7;
484#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100485 } else {
486 min_m = 1;
487 max_m = 15;
488 }
489
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200490 /*
491 * Find the lowest divider resulting in a matching clock, if there
492 * is no match, pick the closest lower clock, as monitors tend to
493 * not sync to higher frequencies.
494 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100495 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200496 n = (m * dotclock) / 3000;
497
498 if ((n >= 9) && (n <= 127)) {
499 value = (3000 * n) / m;
500 diff = dotclock - value;
501 if (diff < best_diff) {
502 best_diff = diff;
503 best_m = m;
504 best_n = n;
505 best_double = 0;
506 }
507 }
508
509 /* These are just duplicates */
510 if (!(m & 1))
511 continue;
512
513 n = (m * dotclock) / 6000;
514 if ((n >= 9) && (n <= 127)) {
515 value = (6000 * n) / m;
516 diff = dotclock - value;
517 if (diff < best_diff) {
518 best_diff = diff;
519 best_m = m;
520 best_n = n;
521 best_double = 1;
522 }
523 }
524 }
525
526 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
527 dotclock, (best_double + 1) * 3000 * best_n / best_m,
528 best_double + 1, best_n, best_m);
529
530 clock_set_pll3(best_n * 3000000);
531
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100532 if (tcon == 0) {
533 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
534 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
535 CCM_LCD_CH0_CTRL_PLL3),
536 &ccm->lcd0_ch0_clk_cfg);
537 } else {
538 writel(CCM_LCD_CH1_CTRL_GATE |
539 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
540 CCM_LCD_CH1_CTRL_PLL3) |
541 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
542 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200543
544 *clk_div = best_m;
545 *clk_double = best_double;
546}
547
548static void sunxi_lcdc_init(void)
549{
550 struct sunxi_ccm_reg * const ccm =
551 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
552 struct sunxi_lcdc_reg * const lcdc =
553 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
554
555 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200556#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100557 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
558#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200559 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100560#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200561
562 /* Clock on */
563 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100564#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200565#ifdef CONFIG_SUNXI_GEN_SUN6I
566 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
567#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100568 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
569#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200570#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200571
572 /* Init lcdc */
573 writel(0, &lcdc->ctrl); /* Disable tcon */
574 writel(0, &lcdc->int0); /* Disable all interrupts */
575
576 /* Disable tcon0 dot clock */
577 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
578
579 /* Set all io lines to tristate */
580 writel(0xffffffff, &lcdc->tcon0_io_tristate);
581 writel(0xffffffff, &lcdc->tcon1_io_tristate);
582}
583
Hans de Goede4125f922014-12-21 14:49:34 +0100584static void sunxi_lcdc_enable(void)
585{
586 struct sunxi_lcdc_reg * const lcdc =
587 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
588
589 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede797a0f52015-01-01 22:04:34 +0100590#ifdef CONFIG_VIDEO_LCD_IF_LVDS
591 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
592 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede5f67b862015-05-14 18:52:54 +0200593#ifdef CONFIG_SUNXI_GEN_SUN6I
594 udelay(2); /* delay at least 1200 ns */
595 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
596 udelay(2); /* delay at least 1200 ns */
597 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
598 if (sunxi_display.depth == 18)
599 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
600 else
601 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
602#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100603 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
604 udelay(2); /* delay at least 1200 ns */
605 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
606 udelay(1); /* delay at least 120 ns */
607 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
608 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
609#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200610#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100611}
612
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100613static void sunxi_lcdc_panel_enable(void)
614{
Hans de Goedece9e3322015-02-16 17:26:41 +0100615 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100616
617 /*
618 * Start with backlight disabled to avoid the screen flashing to
619 * white while the lcd inits.
620 */
621 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200622 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100623 gpio_request(pin, "lcd_backlight_enable");
624 gpio_direction_output(pin, 0);
625 }
626
627 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200628 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100629 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100630 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100631 }
632
Hans de Goedece9e3322015-02-16 17:26:41 +0100633 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200634 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100635 gpio_request(reset_pin, "lcd_reset");
636 gpio_direction_output(reset_pin, 0); /* Assert reset */
637 }
638
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100639 /* Give the backlight some time to turn off and power up the panel. */
640 mdelay(40);
641 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200642 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100643 gpio_request(pin, "lcd_power");
644 gpio_direction_output(pin, 1);
645 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100646
Hans de Goede7783ab22015-04-22 17:45:59 +0200647 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100648 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100649}
650
651static void sunxi_lcdc_backlight_enable(void)
652{
653 int pin;
654
655 /*
656 * We want to have scanned out at least one frame before enabling the
657 * backlight to avoid the screen flashing to white when we enable it.
658 */
659 mdelay(40);
660
661 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200662 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100663 gpio_direction_output(pin, 1);
664
665 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200666 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100667 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100668}
669
Hans de Goede3cbcb272015-08-02 17:38:43 +0200670static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100671{
672 int delay;
673
Hans de Goede3cbcb272015-08-02 17:38:43 +0200674 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
Hans de Goede1977bbb2015-08-02 16:49:29 +0200675 if (mode->vmode == FB_VMODE_INTERLACED)
676 delay /= 2;
Hans de Goede3cbcb272015-08-02 17:38:43 +0200677 if (tcon == 1)
678 delay -= 2;
679
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100680 return (delay > 30) ? 30 : delay;
681}
682
Hans de Goede18366f72015-01-25 15:33:07 +0100683static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
684 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100685{
686 struct sunxi_lcdc_reg * const lcdc =
687 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
688 int bp, clk_delay, clk_div, clk_double, pin, total, val;
689
690 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede797a0f52015-01-01 22:04:34 +0100691#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100692 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100693#endif
694#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100695 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100696#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100697
698 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
699
700 /* Use tcon0 */
701 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
702 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
703
Hans de Goede3cbcb272015-08-02 17:38:43 +0200704 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100705 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
706 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
707
708 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
709 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
710
711 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
712 &lcdc->tcon0_timing_active);
713
714 bp = mode->hsync_len + mode->left_margin;
715 total = mode->xres + mode->right_margin + bp;
716 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
717 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
718
719 bp = mode->vsync_len + mode->upper_margin;
720 total = mode->yres + mode->lower_margin + bp;
721 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
722 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
723
Hans de Goede797a0f52015-01-01 22:04:34 +0100724#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100725 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
726 &lcdc->tcon0_timing_sync);
727
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100728 writel(0, &lcdc->tcon0_hv_intf);
729 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100730#endif
731#ifdef CONFIG_VIDEO_LCD_IF_LVDS
732 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede5f67b862015-05-14 18:52:54 +0200733 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
734 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100735#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100736
737 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
738 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
739 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
740 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
741 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
742 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
743 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
744 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
745 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
746 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
747 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
748 writel(((sunxi_display.depth == 18) ?
749 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
750 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
751 &lcdc->tcon0_frm_ctrl);
752 }
753
Hans de Goede481b6642015-01-13 13:21:46 +0100754 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100755 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
756 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
757 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
758 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goede18366f72015-01-25 15:33:07 +0100759
760#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
761 if (for_ext_vga_dac)
762 val = 0;
763#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100764 writel(val, &lcdc->tcon0_io_polarity);
765
766 writel(0, &lcdc->tcon0_io_tristate);
767}
768
Hans de Goede260f5202014-12-25 13:58:06 +0100769#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
Hans de Goede4125f922014-12-21 14:49:34 +0100770static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100771 int *clk_div, int *clk_double,
772 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200773{
774 struct sunxi_lcdc_reg * const lcdc =
775 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goede1977bbb2015-08-02 16:49:29 +0200776 int bp, clk_delay, total, val, yres;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200777
778 /* Use tcon1 */
779 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
780 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
781
Hans de Goede3cbcb272015-08-02 17:38:43 +0200782 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200783 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goede1977bbb2015-08-02 16:49:29 +0200784 ((mode->vmode == FB_VMODE_INTERLACED) ?
785 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
Hans de Goedeac5d43d2014-12-24 19:50:11 +0100786 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200787
Hans de Goede1977bbb2015-08-02 16:49:29 +0200788 yres = mode->yres;
789 if (mode->vmode == FB_VMODE_INTERLACED)
790 yres /= 2;
791 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200792 &lcdc->tcon1_timing_source);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200793 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200794 &lcdc->tcon1_timing_scale);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200795 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200796 &lcdc->tcon1_timing_out);
797
798 bp = mode->hsync_len + mode->left_margin;
799 total = mode->xres + mode->right_margin + bp;
800 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
801 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
802
803 bp = mode->vsync_len + mode->upper_margin;
804 total = mode->yres + mode->lower_margin + bp;
Hans de Goede1977bbb2015-08-02 16:49:29 +0200805 if (mode->vmode == FB_VMODE_NONINTERLACED)
806 total *= 2;
807 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200808 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
809
810 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
811 &lcdc->tcon1_timing_sync);
812
Hans de Goedec3d15042014-12-27 15:19:23 +0100813 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100814 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
815 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100816
817 val = 0;
818 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
819 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
820 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
821 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
822 writel(val, &lcdc->tcon1_io_polarity);
823
824 clrbits_le32(&lcdc->tcon1_io_tristate,
825 SUNXI_LCDC_TCON_VSYNC_MASK |
826 SUNXI_LCDC_TCON_HSYNC_MASK);
827 }
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100828 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200829}
Hans de Goede260f5202014-12-25 13:58:06 +0100830#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
831
832#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100833
Hans de Goedea2017e82014-12-20 13:38:06 +0100834static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
835{
836 struct sunxi_hdmi_reg * const hdmi =
837 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
838 u8 checksum = 0;
839 u8 avi_info_frame[17] = {
840 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
842 0x00
843 };
844 u8 vendor_info_frame[19] = {
845 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847 0x00, 0x00, 0x00
848 };
849 int i;
850
851 if (mode->pixclock_khz <= 27000)
852 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
853 else
854 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
855
856 if (mode->xres * 100 / mode->yres < 156)
857 avi_info_frame[5] |= 0x18; /* 4 : 3 */
858 else
859 avi_info_frame[5] |= 0x28; /* 16 : 9 */
860
861 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
862 checksum += avi_info_frame[i];
863
864 avi_info_frame[3] = 0x100 - checksum;
865
866 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
867 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
868
869 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
870 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
871
872 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
873 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
874
875 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
876 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
877
878 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
879}
880
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100881static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100882 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200883{
884 struct sunxi_hdmi_reg * const hdmi =
885 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
886 int x, y;
887
888 /* Write clear interrupt status bits */
889 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
890
Hans de Goedea0b1b732014-12-21 14:37:45 +0100891 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100892 sunxi_hdmi_setup_info_frames(mode);
893
Hans de Goede95576692014-12-20 13:51:16 +0100894 /* Set input sync enable */
895 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
896
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200897 /* Init various registers, select pll3 as clock source */
898 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
899 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
900 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
901 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
902 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
903
904 /* Setup clk div and doubler */
905 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
906 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
907 if (!clk_double)
908 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
909
910 /* Setup timing registers */
911 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
912 &hdmi->video_size);
913
914 x = mode->hsync_len + mode->left_margin;
915 y = mode->vsync_len + mode->upper_margin;
916 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
917
918 x = mode->right_margin;
919 y = mode->lower_margin;
920 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
921
922 x = mode->hsync_len;
923 y = mode->vsync_len;
924 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
925
926 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
927 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
928
929 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
930 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
931}
932
Hans de Goede4125f922014-12-21 14:49:34 +0100933static void sunxi_hdmi_enable(void)
934{
935 struct sunxi_hdmi_reg * const hdmi =
936 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
937
938 udelay(100);
939 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
940}
941
Hans de Goedee9544592014-12-23 23:04:35 +0100942#endif /* CONFIG_VIDEO_HDMI */
943
Hans de Goede260f5202014-12-25 13:58:06 +0100944#ifdef CONFIG_VIDEO_VGA
945
946static void sunxi_vga_mode_set(void)
947{
948 struct sunxi_ccm_reg * const ccm =
949 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
950 struct sunxi_tve_reg * const tve =
951 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
952
953 /* Clock on */
954 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
955
956 /* Set TVE in VGA mode */
957 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
958 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
959 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
Hans de Goedeead68b62015-08-03 19:45:37 +0200960 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
961 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
962 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
Hans de Goede260f5202014-12-25 13:58:06 +0100963}
964
965static void sunxi_vga_enable(void)
966{
967 struct sunxi_tve_reg * const tve =
968 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
969
970 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
971}
972
973#endif /* CONFIG_VIDEO_VGA */
974
Hans de Goede115e4b42014-12-23 18:39:52 +0100975static void sunxi_drc_init(void)
976{
Hans de Goedef07872b2015-04-06 20:33:34 +0200977#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +0100978 struct sunxi_ccm_reg * const ccm =
979 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
980
981 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +0530982#ifdef CONFIG_MACH_SUN8I_A33
983 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
984#endif
Hans de Goede115e4b42014-12-23 18:39:52 +0100985 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
986 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
987#endif
988}
989
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800990#ifdef CONFIG_VIDEO_VGA_VIA_LCD
991static void sunxi_vga_external_dac_enable(void)
992{
993 int pin;
994
995 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200996 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800997 gpio_request(pin, "vga_enable");
998 gpio_direction_output(pin, 1);
999 }
1000}
1001#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1002
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001003#ifdef CONFIG_VIDEO_LCD_SSD2828
1004static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1005{
1006 struct ssd2828_config cfg = {
1007 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1008 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1009 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1010 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1011 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1012 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1013 .ssd2828_color_depth = 24,
1014#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1015 .mipi_dsi_number_of_data_lanes = 4,
1016 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1017 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1018 .mipi_dsi_delay_after_set_display_on_ms = 200
1019#else
1020#error MIPI LCD panel needs configuration parameters
1021#endif
1022 };
1023
1024 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1025 printf("SSD2828: SPI pins are not properly configured\n");
1026 return 1;
1027 }
1028 if (cfg.reset_pin == -1) {
1029 printf("SSD2828: Reset pin is not properly configured\n");
1030 return 1;
1031 }
1032
1033 return ssd2828_init(&cfg, mode);
1034}
1035#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1036
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001037static void sunxi_engines_init(void)
1038{
1039 sunxi_composer_init();
1040 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +01001041 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001042}
1043
Hans de Goedea0b1b732014-12-21 14:37:45 +01001044static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +01001045 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001046{
Hans de Goede260f5202014-12-25 13:58:06 +01001047 int __maybe_unused clk_div, clk_double;
1048
Hans de Goede4125f922014-12-21 14:49:34 +01001049 switch (sunxi_display.monitor) {
1050 case sunxi_monitor_none:
1051 break;
1052 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001053 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001054#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001055 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001056 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001057 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1058 sunxi_composer_enable();
1059 sunxi_lcdc_enable();
1060 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001061#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001062 break;
1063 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001064 sunxi_lcdc_panel_enable();
Hans de Goede743fb9552015-01-20 09:23:36 +01001065 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1066 mdelay(50); /* Wait for lcd controller power on */
1067 hitachi_tx18d42vm_init();
1068 }
Hans de Goede613dade2015-02-16 17:49:47 +01001069 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1070 unsigned int orig_i2c_bus = i2c_get_bus_num();
1071 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1072 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1073 i2c_set_bus_num(orig_i2c_bus);
1074 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001075 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001076 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001077 sunxi_composer_enable();
1078 sunxi_lcdc_enable();
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001079#ifdef CONFIG_VIDEO_LCD_SSD2828
1080 sunxi_ssd2828_init(mode);
1081#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001082 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001083 break;
1084 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001085#ifdef CONFIG_VIDEO_VGA
1086 sunxi_composer_mode_set(mode, address);
1087 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1088 sunxi_vga_mode_set();
1089 sunxi_composer_enable();
1090 sunxi_lcdc_enable();
1091 sunxi_vga_enable();
1092#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001093 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001094 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001095 sunxi_composer_enable();
1096 sunxi_lcdc_enable();
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001097 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001098#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001099 break;
1100 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001101}
1102
Hans de Goedea0b1b732014-12-21 14:37:45 +01001103static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1104{
1105 switch (monitor) {
1106 case sunxi_monitor_none: return "none";
1107 case sunxi_monitor_dvi: return "dvi";
1108 case sunxi_monitor_hdmi: return "hdmi";
1109 case sunxi_monitor_lcd: return "lcd";
1110 case sunxi_monitor_vga: return "vga";
1111 }
1112 return NULL; /* never reached */
1113}
1114
Hans de Goede6c912862015-02-02 17:13:29 +01001115ulong board_get_usable_ram_top(ulong total_size)
1116{
1117 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1118}
1119
Hans de Goedea2bba492015-08-03 23:01:38 +02001120static bool sunxi_has_hdmi(void)
1121{
1122#ifdef CONFIG_VIDEO_HDMI
1123 return true;
1124#else
1125 return false;
1126#endif
1127}
1128
1129static bool sunxi_has_lcd(void)
1130{
1131 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1132
1133 return lcd_mode[0] != 0;
1134}
1135
1136static bool sunxi_has_vga(void)
1137{
1138#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1139 return true;
1140#else
1141 return false;
1142#endif
1143}
1144
1145static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1146{
1147 if (allow_hdmi && sunxi_has_hdmi())
1148 return sunxi_monitor_dvi;
1149 else if (sunxi_has_lcd())
1150 return sunxi_monitor_lcd;
1151 else if (sunxi_has_vga())
1152 return sunxi_monitor_vga;
1153 else
1154 return sunxi_monitor_none;
1155}
1156
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001157void *video_hw_init(void)
1158{
1159 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001160 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001161 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001162 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001163#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001164 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001165#endif
Hans de Goedea0b1b732014-12-21 14:37:45 +01001166 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001167 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Hans de Goedee9544592014-12-23 23:04:35 +01001168 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001169
1170 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1171
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001172 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1173 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001174#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001175 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001176 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001177 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001178#endif
Hans de Goedea2bba492015-08-03 23:01:38 +02001179 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001180 video_get_option_string(options, "monitor", mon, sizeof(mon),
1181 sunxi_get_mon_desc(sunxi_display.monitor));
1182 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1183 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1184 sunxi_display.monitor = i;
1185 break;
1186 }
1187 }
1188 if (i > SUNXI_MONITOR_LAST)
1189 printf("Unknown monitor: '%s', falling back to '%s'\n",
1190 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001191
Hans de Goede7977ec22014-12-25 13:52:04 +01001192#ifdef CONFIG_VIDEO_HDMI
1193 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1194 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1195 sunxi_display.monitor == sunxi_monitor_hdmi) {
1196 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001197 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001198 if (ret) {
1199 printf("HDMI connected: ");
1200 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1201 mode = &custom;
1202 } else if (hpd) {
1203 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001204 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001205 } /* else continue with hdmi/dvi without a cable connected */
1206 }
1207#endif
1208
Hans de Goede4125f922014-12-21 14:49:34 +01001209 switch (sunxi_display.monitor) {
1210 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001211 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001212 case sunxi_monitor_dvi:
1213 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001214 if (!sunxi_has_hdmi()) {
1215 printf("HDMI/DVI not supported on this board\n");
1216 sunxi_display.monitor = sunxi_monitor_none;
1217 return NULL;
1218 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001219 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001220 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001221 if (!sunxi_has_lcd()) {
1222 printf("LCD not supported on this board\n");
1223 sunxi_display.monitor = sunxi_monitor_none;
1224 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001225 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001226 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1227 mode = &custom;
1228 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001229 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001230 if (!sunxi_has_vga()) {
1231 printf("VGA not supported on this board\n");
1232 sunxi_display.monitor = sunxi_monitor_none;
1233 return NULL;
1234 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001235 sunxi_display.depth = 18;
1236 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001237 }
1238
Hans de Goede18799252015-02-02 18:00:53 +01001239 sunxi_display.fb_size =
1240 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1241 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1242 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1243 sunxi_display.fb_size >> 10,
1244 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1245 return NULL;
1246 }
1247
Hans de Goede1977bbb2015-08-02 16:49:29 +02001248 printf("Setting up a %dx%d%s %s console\n", mode->xres, mode->yres,
1249 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
1250 sunxi_get_mon_desc(sunxi_display.monitor));
1251
Hans de Goede18799252015-02-02 18:00:53 +01001252 gd->fb_base = gd->bd->bi_dram[0].start +
1253 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001254 sunxi_engines_init();
Hans de Goedea0b1b732014-12-21 14:37:45 +01001255 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001256
1257 /*
1258 * These are the only members of this structure that are used. All the
1259 * others are driver specific. There is nothing to decribe pitch or
1260 * stride, but we are lucky with our hw.
1261 */
1262 graphic_device->frameAdrs = gd->fb_base;
1263 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1264 graphic_device->gdfBytesPP = 4;
Hans de Goedeccb0ed52014-12-19 13:46:33 +01001265 graphic_device->winSizeX = mode->xres;
1266 graphic_device->winSizeY = mode->yres;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001267
1268 return graphic_device;
1269}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001270
1271/*
1272 * Simplefb support.
1273 */
1274#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1275int sunxi_simplefb_setup(void *blob)
1276{
1277 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1278 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001279 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001280 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001281
Hans de Goedec3cc4262015-01-19 08:44:07 +01001282#ifdef CONFIG_MACH_SUN4I
1283#define PIPELINE_PREFIX "de_fe0-"
1284#else
1285#define PIPELINE_PREFIX
1286#endif
1287
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001288 switch (sunxi_display.monitor) {
1289 case sunxi_monitor_none:
1290 return 0;
1291 case sunxi_monitor_dvi:
1292 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001293 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001294 break;
1295 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001296 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001297 break;
1298 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001299#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001300 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001301#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001302 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001303#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001304 break;
1305 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001306
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001307 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001308 offset = fdt_node_offset_by_compatible(blob, -1,
1309 "allwinner,simple-framebuffer");
1310 while (offset >= 0) {
1311 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001312 pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001313 if (ret == 0)
1314 break;
1315 offset = fdt_node_offset_by_compatible(blob, offset,
1316 "allwinner,simple-framebuffer");
1317 }
1318 if (offset < 0) {
1319 eprintf("Cannot setup simplefb: node not found\n");
1320 return 0; /* Keep older kernels working */
1321 }
1322
Hans de Goede6c912862015-02-02 17:13:29 +01001323 /*
1324 * Do not report the framebuffer as free RAM to the OS, note we cannot
1325 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1326 * and e.g. Linux refuses to iomap RAM on ARM, see:
1327 * linux/arch/arm/mm/ioremap.c around line 301.
1328 */
1329 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001330 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001331 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1332 if (ret) {
1333 eprintf("Cannot setup simplefb: Error reserving memory\n");
1334 return ret;
1335 }
1336
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001337 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1338 graphic_device->winSizeX, graphic_device->winSizeY,
1339 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1340 "x8r8g8b8");
1341 if (ret)
1342 eprintf("Cannot setup simplefb: Error setting properties\n");
1343
1344 return ret;
1345}
1346#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */