blob: dbda97e746b97b5dc2a729198738c449e59163c7 [file] [log] [blame]
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001/*
2 * Display driver for Allwinner SoCs.
3 *
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
5 * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 */
9
10#include <common.h>
11
12#include <asm/arch/clock.h>
13#include <asm/arch/display.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020015#include <asm/global_data.h>
Hans de Goede7e68a1b2014-12-21 16:28:32 +010016#include <asm/gpio.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020017#include <asm/io.h>
Hans de Goedea5aa95f2014-12-19 16:05:12 +010018#include <errno.h>
Luc Verhaegen4869a8c2014-08-13 07:55:07 +020019#include <fdtdec.h>
20#include <fdt_support.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020021#include <video_fb.h>
Hans de Goedeccb0ed52014-12-19 13:46:33 +010022#include "videomodes.h"
Hans de Goede743fb9552015-01-20 09:23:36 +010023#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashkac02f0522015-01-19 05:23:33 +020024#include "ssd2828.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020025
Hans de Goede2d5d3022015-01-22 21:02:42 +010026#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
27#define PWM_ON 0
28#define PWM_OFF 1
29#else
30#define PWM_ON 1
31#define PWM_OFF 0
32#endif
33
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020034DECLARE_GLOBAL_DATA_PTR;
35
Hans de Goedea0b1b732014-12-21 14:37:45 +010036enum sunxi_monitor {
37 sunxi_monitor_none,
38 sunxi_monitor_dvi,
39 sunxi_monitor_hdmi,
40 sunxi_monitor_lcd,
41 sunxi_monitor_vga,
42};
43#define SUNXI_MONITOR_LAST sunxi_monitor_vga
44
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020045struct sunxi_display {
46 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010047 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010048 unsigned int depth;
Hans de Goede18799252015-02-02 18:00:53 +010049 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020050} sunxi_display;
51
Hans de Goedee9544592014-12-23 23:04:35 +010052#ifdef CONFIG_VIDEO_HDMI
53
Hans de Goedea5aa95f2014-12-19 16:05:12 +010054/*
55 * Wait up to 200ms for value to be set in given part of reg.
56 */
57static int await_completion(u32 *reg, u32 mask, u32 val)
58{
59 unsigned long tmo = timer_get_us() + 200000;
60
61 while ((readl(reg) & mask) != val) {
62 if (timer_get_us() > tmo) {
63 printf("DDC: timeout reading EDID\n");
64 return -ETIME;
65 }
66 }
67 return 0;
68}
69
Hans de Goede91593712014-12-28 09:13:21 +010070static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020071{
72 struct sunxi_ccm_reg * const ccm =
73 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
74 struct sunxi_hdmi_reg * const hdmi =
75 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010076 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020077
78 /* Set pll3 to 300MHz */
79 clock_set_pll3(300000000);
80
81 /* Set hdmi parent to pll3 */
82 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
83 CCM_HDMI_CTRL_PLL3);
84
85 /* Set ahb gating to pass */
Hans de Goedef651e0a2014-11-14 17:42:14 +010086#ifdef CONFIG_MACH_SUN6I
87 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
88#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020089 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
90
91 /* Clock on */
92 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
93
94 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
95 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
96
Hans de Goede205a30c2014-12-20 15:15:23 +010097 while (timer_get_us() < tmo) {
98 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
99 return 1;
100 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200101
Hans de Goede205a30c2014-12-20 15:15:23 +0100102 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100103}
104
105static void sunxi_hdmi_shutdown(void)
106{
107 struct sunxi_ccm_reg * const ccm =
108 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
109 struct sunxi_hdmi_reg * const hdmi =
110 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200111
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200112 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
113 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
114 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100115#ifdef CONFIG_MACH_SUN6I
116 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
117#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200118 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200119}
120
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100121static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
122{
123 struct sunxi_hdmi_reg * const hdmi =
124 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
125
126 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
127 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
128 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
129 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
130 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
131#ifndef CONFIG_MACH_SUN6I
132 writel(n, &hdmi->ddc_byte_count);
133 writel(cmnd, &hdmi->ddc_cmnd);
134#else
135 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
136#endif
137 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
138
139 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
140}
141
142static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
143{
144 struct sunxi_hdmi_reg * const hdmi =
145 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
146 int i, n;
147
148 while (count > 0) {
149 if (count > 16)
150 n = 16;
151 else
152 n = count;
153
154 if (sunxi_hdmi_ddc_do_command(
155 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
156 offset, n))
157 return -ETIME;
158
159 for (i = 0; i < n; i++)
160 *buf++ = readb(&hdmi->ddc_fifo_data);
161
162 offset += n;
163 count -= n;
164 }
165
166 return 0;
167}
168
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100169static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
170{
171 int r, retries = 2;
172
173 do {
174 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
175 if (r)
176 continue;
177 r = edid_check_checksum(buf);
178 if (r) {
179 printf("EDID block %d: checksum error%s\n",
180 block, retries ? ", retrying" : "");
181 }
182 } while (r && retries--);
183
184 return r;
185}
186
Hans de Goedea0b1b732014-12-21 14:37:45 +0100187static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100188{
189 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100190 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100191 struct edid_detailed_timing *t =
192 (struct edid_detailed_timing *)edid1.monitor_details.timing;
193 struct sunxi_hdmi_reg * const hdmi =
194 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
195 struct sunxi_ccm_reg * const ccm =
196 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100197 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100198
199 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
200 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
201 &hdmi->pad_ctrl1);
202 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
203 &hdmi->pll_ctrl);
204 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
205
206 /* Reset i2c controller */
207 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
208 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
209 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
210 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
211 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
212 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
213 return -EIO;
214
215 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
216#ifndef CONFIG_MACH_SUN6I
217 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
218 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
219#endif
220
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100221 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100222 if (r == 0) {
223 r = edid_check_info(&edid1);
224 if (r) {
225 printf("EDID: invalid EDID data\n");
226 r = -EINVAL;
227 }
228 }
229 if (r == 0) {
230 ext_blocks = edid1.extension_flag;
231 if (ext_blocks > 4)
232 ext_blocks = 4;
233 for (i = 0; i < ext_blocks; i++) {
234 if (sunxi_hdmi_edid_get_block(1 + i,
235 (u8 *)&cea681[i]) != 0) {
236 ext_blocks = i;
237 break;
238 }
239 }
240 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100241
242 /* Disable DDC engine, no longer needed */
243 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
244 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
245
246 if (r)
247 return r;
248
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100249 /* We want version 1.3 or 1.2 with detailed timing info */
250 if (edid1.version != 1 || (edid1.revision < 3 &&
251 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
252 printf("EDID: unsupported version %d.%d\n",
253 edid1.version, edid1.revision);
254 return -EINVAL;
255 }
256
257 /* Take the first usable detailed timing */
258 for (i = 0; i < 4; i++, t++) {
259 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
260 if (r == 0)
261 break;
262 }
263 if (i == 4) {
264 printf("EDID: no usable detailed timing found\n");
265 return -ENOENT;
266 }
267
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100268 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100269 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100270 for (i = 0; i < ext_blocks; i++) {
271 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
272 cea681[i].revision < 2)
273 continue;
274
275 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100276 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100277 }
278
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100279 return 0;
280}
281
Hans de Goedee9544592014-12-23 23:04:35 +0100282#endif /* CONFIG_VIDEO_HDMI */
283
Hans de Goedec3cc4262015-01-19 08:44:07 +0100284#ifdef CONFIG_MACH_SUN4I
285/*
286 * Testing has shown that on sun4i the display backend engine does not have
287 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
288 * fifo underruns. So on sun4i we use the display frontend engine to do the
289 * dma from memory, as the frontend does have deep enough fifo-s.
290 */
291
292static const u32 sun4i_vert_coef[32] = {
293 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
294 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
295 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
296 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
297 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
298 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
299 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
300 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
301};
302
303static const u32 sun4i_horz_coef[64] = {
304 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
305 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
306 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
307 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
308 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
309 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
310 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
311 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
312 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
313 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
314 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
315 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
316 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
317 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
318 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
319 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
320};
321
322static void sunxi_frontend_init(void)
323{
324 struct sunxi_ccm_reg * const ccm =
325 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
326 struct sunxi_de_fe_reg * const de_fe =
327 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
328 int i;
329
330 /* Clocks on */
331 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
332 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
333 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
334
335 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
336
337 for (i = 0; i < 32; i++) {
338 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
339 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
340 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
341 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
342 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
343 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
344 }
345
346 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
347}
348
349static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
350 unsigned int address)
351{
352 struct sunxi_de_fe_reg * const de_fe =
353 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
354
355 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
356 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
357 writel(mode->xres * 4, &de_fe->ch0_stride);
358 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
359 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
360
361 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
362 &de_fe->ch0_insize);
363 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
364 &de_fe->ch0_outsize);
365 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
366 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
367
368 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
369 &de_fe->ch1_insize);
370 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
371 &de_fe->ch1_outsize);
372 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
373 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
374
375 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
376}
377
378static void sunxi_frontend_enable(void)
379{
380 struct sunxi_de_fe_reg * const de_fe =
381 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
382
383 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
384}
385#else
386static void sunxi_frontend_init(void) {}
387static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
388 unsigned int address) {}
389static void sunxi_frontend_enable(void) {}
390#endif
391
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200392/*
393 * This is the entity that mixes and matches the different layers and inputs.
394 * Allwinner calls it the back-end, but i like composer better.
395 */
396static void sunxi_composer_init(void)
397{
398 struct sunxi_ccm_reg * const ccm =
399 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
400 struct sunxi_de_be_reg * const de_be =
401 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
402 int i;
403
Hans de Goedec3cc4262015-01-19 08:44:07 +0100404 sunxi_frontend_init();
405
Hans de Goedee9544592014-12-23 23:04:35 +0100406#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100407 /* Reset off */
408 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
409#endif
410
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200411 /* Clocks on */
412 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100413#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200414 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100415#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200416 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
417
418 /* Engine bug, clear registers after reset */
419 for (i = 0x0800; i < 0x1000; i += 4)
420 writel(0, SUNXI_DE_BE0_BASE + i);
421
422 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
423}
424
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100425static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200426 unsigned int address)
427{
428 struct sunxi_de_be_reg * const de_be =
429 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
430
Hans de Goedec3cc4262015-01-19 08:44:07 +0100431 sunxi_frontend_mode_set(mode, address);
432
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200433 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
434 &de_be->disp_size);
435 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
436 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100437#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200438 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
439 writel(address << 3, &de_be->layer0_addr_low32b);
440 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100441#else
442 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
443#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200444 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
445
446 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
447}
448
Hans de Goede4125f922014-12-21 14:49:34 +0100449static void sunxi_composer_enable(void)
450{
451 struct sunxi_de_be_reg * const de_be =
452 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
453
Hans de Goedec3cc4262015-01-19 08:44:07 +0100454 sunxi_frontend_enable();
455
Hans de Goede4125f922014-12-21 14:49:34 +0100456 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
457 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
458}
459
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200460/*
461 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
462 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100463static void sunxi_lcdc_pll_set(int tcon, int dotclock,
464 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200465{
466 struct sunxi_ccm_reg * const ccm =
467 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100468 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200469 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
470 int best_double = 0;
471
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100472 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100473#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100474 min_m = 6;
475 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100476#endif
477#ifdef CONFIG_VIDEO_LCD_IF_LVDS
478 min_m = max_m = 7;
479#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100480 } else {
481 min_m = 1;
482 max_m = 15;
483 }
484
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200485 /*
486 * Find the lowest divider resulting in a matching clock, if there
487 * is no match, pick the closest lower clock, as monitors tend to
488 * not sync to higher frequencies.
489 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100490 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200491 n = (m * dotclock) / 3000;
492
493 if ((n >= 9) && (n <= 127)) {
494 value = (3000 * n) / m;
495 diff = dotclock - value;
496 if (diff < best_diff) {
497 best_diff = diff;
498 best_m = m;
499 best_n = n;
500 best_double = 0;
501 }
502 }
503
504 /* These are just duplicates */
505 if (!(m & 1))
506 continue;
507
508 n = (m * dotclock) / 6000;
509 if ((n >= 9) && (n <= 127)) {
510 value = (6000 * n) / m;
511 diff = dotclock - value;
512 if (diff < best_diff) {
513 best_diff = diff;
514 best_m = m;
515 best_n = n;
516 best_double = 1;
517 }
518 }
519 }
520
521 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
522 dotclock, (best_double + 1) * 3000 * best_n / best_m,
523 best_double + 1, best_n, best_m);
524
525 clock_set_pll3(best_n * 3000000);
526
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100527 if (tcon == 0) {
528 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
529 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
530 CCM_LCD_CH0_CTRL_PLL3),
531 &ccm->lcd0_ch0_clk_cfg);
532 } else {
533 writel(CCM_LCD_CH1_CTRL_GATE |
534 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
535 CCM_LCD_CH1_CTRL_PLL3) |
536 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
537 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200538
539 *clk_div = best_m;
540 *clk_double = best_double;
541}
542
543static void sunxi_lcdc_init(void)
544{
545 struct sunxi_ccm_reg * const ccm =
546 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
547 struct sunxi_lcdc_reg * const lcdc =
548 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
549
550 /* Reset off */
Hans de Goedee9544592014-12-23 23:04:35 +0100551#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100552 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
553#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200554 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100555#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200556
557 /* Clock on */
558 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100559#ifdef CONFIG_VIDEO_LCD_IF_LVDS
560 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
561#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200562
563 /* Init lcdc */
564 writel(0, &lcdc->ctrl); /* Disable tcon */
565 writel(0, &lcdc->int0); /* Disable all interrupts */
566
567 /* Disable tcon0 dot clock */
568 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
569
570 /* Set all io lines to tristate */
571 writel(0xffffffff, &lcdc->tcon0_io_tristate);
572 writel(0xffffffff, &lcdc->tcon1_io_tristate);
573}
574
Hans de Goede4125f922014-12-21 14:49:34 +0100575static void sunxi_lcdc_enable(void)
576{
577 struct sunxi_lcdc_reg * const lcdc =
578 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
579
580 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede797a0f52015-01-01 22:04:34 +0100581#ifdef CONFIG_VIDEO_LCD_IF_LVDS
582 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
583 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
584 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
585 udelay(2); /* delay at least 1200 ns */
586 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
587 udelay(1); /* delay at least 120 ns */
588 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
589 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
590#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100591}
592
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100593static void sunxi_lcdc_panel_enable(void)
594{
595 int pin;
596
597 /*
598 * Start with backlight disabled to avoid the screen flashing to
599 * white while the lcd inits.
600 */
601 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
602 if (pin != -1) {
603 gpio_request(pin, "lcd_backlight_enable");
604 gpio_direction_output(pin, 0);
605 }
606
607 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
608 if (pin != -1) {
609 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100610 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100611 }
612
613 /* Give the backlight some time to turn off and power up the panel. */
614 mdelay(40);
615 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
616 if (pin != -1) {
617 gpio_request(pin, "lcd_power");
618 gpio_direction_output(pin, 1);
619 }
620}
621
622static void sunxi_lcdc_backlight_enable(void)
623{
624 int pin;
625
626 /*
627 * We want to have scanned out at least one frame before enabling the
628 * backlight to avoid the screen flashing to white when we enable it.
629 */
630 mdelay(40);
631
632 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
633 if (pin != -1)
634 gpio_direction_output(pin, 1);
635
636 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede2d5d3022015-01-22 21:02:42 +0100637 if (pin != -1)
638 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100639}
640
641static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode)
642{
643 int delay;
644
645 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2;
646 return (delay > 30) ? 30 : delay;
647}
648
Hans de Goede18366f72015-01-25 15:33:07 +0100649static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
650 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100651{
652 struct sunxi_lcdc_reg * const lcdc =
653 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
654 int bp, clk_delay, clk_div, clk_double, pin, total, val;
655
656 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede797a0f52015-01-01 22:04:34 +0100657#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100658 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100659#endif
660#ifdef CONFIG_VIDEO_LCD_IF_LVDS
661 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0);
662#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100663
664 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
665
666 /* Use tcon0 */
667 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
668 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
669
670 clk_delay = sunxi_lcdc_get_clk_delay(mode);
671 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
672 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
673
674 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
675 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
676
677 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
678 &lcdc->tcon0_timing_active);
679
680 bp = mode->hsync_len + mode->left_margin;
681 total = mode->xres + mode->right_margin + bp;
682 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
683 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
684
685 bp = mode->vsync_len + mode->upper_margin;
686 total = mode->yres + mode->lower_margin + bp;
687 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
688 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
689
Hans de Goede797a0f52015-01-01 22:04:34 +0100690#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100691 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
692 &lcdc->tcon0_timing_sync);
693
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100694 writel(0, &lcdc->tcon0_hv_intf);
695 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100696#endif
697#ifdef CONFIG_VIDEO_LCD_IF_LVDS
698 val = (sunxi_display.depth == 18) ? 1 : 0;
699 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf);
700#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100701
702 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
703 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
704 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
705 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
706 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
707 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
708 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
709 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
710 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
711 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
712 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
713 writel(((sunxi_display.depth == 18) ?
714 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
715 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
716 &lcdc->tcon0_frm_ctrl);
717 }
718
Hans de Goede481b6642015-01-13 13:21:46 +0100719 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100720 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
721 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
722 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
723 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goede18366f72015-01-25 15:33:07 +0100724
725#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
726 if (for_ext_vga_dac)
727 val = 0;
728#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100729 writel(val, &lcdc->tcon0_io_polarity);
730
731 writel(0, &lcdc->tcon0_io_tristate);
732}
733
Hans de Goede260f5202014-12-25 13:58:06 +0100734#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
Hans de Goede4125f922014-12-21 14:49:34 +0100735static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100736 int *clk_div, int *clk_double,
737 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200738{
739 struct sunxi_lcdc_reg * const lcdc =
740 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedec3d15042014-12-27 15:19:23 +0100741 int bp, clk_delay, total, val;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200742
743 /* Use tcon1 */
744 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
745 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
746
Hans de Goedeac5d43d2014-12-24 19:50:11 +0100747 clk_delay = sunxi_lcdc_get_clk_delay(mode);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200748 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedeac5d43d2014-12-24 19:50:11 +0100749 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200750
751 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
752 &lcdc->tcon1_timing_source);
753 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
754 &lcdc->tcon1_timing_scale);
755 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
756 &lcdc->tcon1_timing_out);
757
758 bp = mode->hsync_len + mode->left_margin;
759 total = mode->xres + mode->right_margin + bp;
760 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
761 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
762
763 bp = mode->vsync_len + mode->upper_margin;
764 total = mode->yres + mode->lower_margin + bp;
765 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
766 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
767
768 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
769 &lcdc->tcon1_timing_sync);
770
Hans de Goedec3d15042014-12-27 15:19:23 +0100771 if (use_portd_hvsync) {
772 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD0_LCD0);
773 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD0_LCD0);
774
775 val = 0;
776 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
777 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
778 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
779 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
780 writel(val, &lcdc->tcon1_io_polarity);
781
782 clrbits_le32(&lcdc->tcon1_io_tristate,
783 SUNXI_LCDC_TCON_VSYNC_MASK |
784 SUNXI_LCDC_TCON_HSYNC_MASK);
785 }
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100786 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200787}
Hans de Goede260f5202014-12-25 13:58:06 +0100788#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
789
790#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100791
Hans de Goedea2017e82014-12-20 13:38:06 +0100792static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
793{
794 struct sunxi_hdmi_reg * const hdmi =
795 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
796 u8 checksum = 0;
797 u8 avi_info_frame[17] = {
798 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
800 0x00
801 };
802 u8 vendor_info_frame[19] = {
803 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
805 0x00, 0x00, 0x00
806 };
807 int i;
808
809 if (mode->pixclock_khz <= 27000)
810 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
811 else
812 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
813
814 if (mode->xres * 100 / mode->yres < 156)
815 avi_info_frame[5] |= 0x18; /* 4 : 3 */
816 else
817 avi_info_frame[5] |= 0x28; /* 16 : 9 */
818
819 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
820 checksum += avi_info_frame[i];
821
822 avi_info_frame[3] = 0x100 - checksum;
823
824 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
825 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
826
827 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
828 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
829
830 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
831 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
832
833 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
834 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
835
836 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
837}
838
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100839static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100840 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200841{
842 struct sunxi_hdmi_reg * const hdmi =
843 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
844 int x, y;
845
846 /* Write clear interrupt status bits */
847 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
848
Hans de Goedea0b1b732014-12-21 14:37:45 +0100849 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100850 sunxi_hdmi_setup_info_frames(mode);
851
Hans de Goede95576692014-12-20 13:51:16 +0100852 /* Set input sync enable */
853 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
854
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200855 /* Init various registers, select pll3 as clock source */
856 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
857 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
858 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
859 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
860 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
861
862 /* Setup clk div and doubler */
863 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
864 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
865 if (!clk_double)
866 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
867
868 /* Setup timing registers */
869 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
870 &hdmi->video_size);
871
872 x = mode->hsync_len + mode->left_margin;
873 y = mode->vsync_len + mode->upper_margin;
874 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
875
876 x = mode->right_margin;
877 y = mode->lower_margin;
878 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
879
880 x = mode->hsync_len;
881 y = mode->vsync_len;
882 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
883
884 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
885 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
886
887 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
888 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
889}
890
Hans de Goede4125f922014-12-21 14:49:34 +0100891static void sunxi_hdmi_enable(void)
892{
893 struct sunxi_hdmi_reg * const hdmi =
894 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
895
896 udelay(100);
897 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
898}
899
Hans de Goedee9544592014-12-23 23:04:35 +0100900#endif /* CONFIG_VIDEO_HDMI */
901
Hans de Goede260f5202014-12-25 13:58:06 +0100902#ifdef CONFIG_VIDEO_VGA
903
904static void sunxi_vga_mode_set(void)
905{
906 struct sunxi_ccm_reg * const ccm =
907 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
908 struct sunxi_tve_reg * const tve =
909 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
910
911 /* Clock on */
912 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
913
914 /* Set TVE in VGA mode */
915 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
916 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
917 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
918 writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0);
919 writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0);
920 writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1);
921}
922
923static void sunxi_vga_enable(void)
924{
925 struct sunxi_tve_reg * const tve =
926 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
927
928 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
929}
930
931#endif /* CONFIG_VIDEO_VGA */
932
Hans de Goede115e4b42014-12-23 18:39:52 +0100933static void sunxi_drc_init(void)
934{
Hans de Goedee9544592014-12-23 23:04:35 +0100935#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I
Hans de Goede115e4b42014-12-23 18:39:52 +0100936 struct sunxi_ccm_reg * const ccm =
937 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
938
939 /* On sun6i the drc must be clocked even when in pass-through mode */
940 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
941 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
942#endif
943}
944
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +0800945#ifdef CONFIG_VIDEO_VGA_VIA_LCD
946static void sunxi_vga_external_dac_enable(void)
947{
948 int pin;
949
950 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
951 if (pin != -1) {
952 gpio_request(pin, "vga_enable");
953 gpio_direction_output(pin, 1);
954 }
955}
956#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
957
Siarhei Siamashkac02f0522015-01-19 05:23:33 +0200958#ifdef CONFIG_VIDEO_LCD_SSD2828
959static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
960{
961 struct ssd2828_config cfg = {
962 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
963 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
964 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
965 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
966 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
967 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
968 .ssd2828_color_depth = 24,
969#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
970 .mipi_dsi_number_of_data_lanes = 4,
971 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
972 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
973 .mipi_dsi_delay_after_set_display_on_ms = 200
974#else
975#error MIPI LCD panel needs configuration parameters
976#endif
977 };
978
979 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
980 printf("SSD2828: SPI pins are not properly configured\n");
981 return 1;
982 }
983 if (cfg.reset_pin == -1) {
984 printf("SSD2828: Reset pin is not properly configured\n");
985 return 1;
986 }
987
988 return ssd2828_init(&cfg, mode);
989}
990#endif /* CONFIG_VIDEO_LCD_SSD2828 */
991
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200992static void sunxi_engines_init(void)
993{
994 sunxi_composer_init();
995 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +0100996 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200997}
998
Hans de Goedea0b1b732014-12-21 14:37:45 +0100999static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +01001000 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001001{
Hans de Goede260f5202014-12-25 13:58:06 +01001002 int __maybe_unused clk_div, clk_double;
1003
Hans de Goede4125f922014-12-21 14:49:34 +01001004 switch (sunxi_display.monitor) {
1005 case sunxi_monitor_none:
1006 break;
1007 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001008 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001009#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001010 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001011 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001012 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1013 sunxi_composer_enable();
1014 sunxi_lcdc_enable();
1015 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001016#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001017 break;
1018 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001019 sunxi_lcdc_panel_enable();
Hans de Goede743fb9552015-01-20 09:23:36 +01001020 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1021 mdelay(50); /* Wait for lcd controller power on */
1022 hitachi_tx18d42vm_init();
1023 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001024 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001025 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001026 sunxi_composer_enable();
1027 sunxi_lcdc_enable();
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001028#ifdef CONFIG_VIDEO_LCD_SSD2828
1029 sunxi_ssd2828_init(mode);
1030#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001031 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001032 break;
1033 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001034#ifdef CONFIG_VIDEO_VGA
1035 sunxi_composer_mode_set(mode, address);
1036 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1037 sunxi_vga_mode_set();
1038 sunxi_composer_enable();
1039 sunxi_lcdc_enable();
1040 sunxi_vga_enable();
1041#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001042 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001043 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001044 sunxi_composer_enable();
1045 sunxi_lcdc_enable();
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001046 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001047#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001048 break;
1049 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001050}
1051
Hans de Goedea0b1b732014-12-21 14:37:45 +01001052static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1053{
1054 switch (monitor) {
1055 case sunxi_monitor_none: return "none";
1056 case sunxi_monitor_dvi: return "dvi";
1057 case sunxi_monitor_hdmi: return "hdmi";
1058 case sunxi_monitor_lcd: return "lcd";
1059 case sunxi_monitor_vga: return "vga";
1060 }
1061 return NULL; /* never reached */
1062}
1063
Hans de Goede6c912862015-02-02 17:13:29 +01001064ulong board_get_usable_ram_top(ulong total_size)
1065{
1066 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1067}
1068
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001069void *video_hw_init(void)
1070{
1071 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001072 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001073 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001074 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001075#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001076 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001077#endif
Hans de Goedea0b1b732014-12-21 14:37:45 +01001078 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001079 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Hans de Goedee9544592014-12-23 23:04:35 +01001080 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001081
1082 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1083
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001084 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1085 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001086#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001087 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001088 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001089 edid = video_get_option_int(options, "edid", 1);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001090 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedeac1633c2014-12-24 12:17:07 +01001091#elif defined CONFIG_VIDEO_VGA_VIA_LCD
1092 sunxi_display.monitor = sunxi_monitor_vga;
Hans de Goedee9544592014-12-23 23:04:35 +01001093#else
1094 sunxi_display.monitor = sunxi_monitor_lcd;
1095#endif
Hans de Goedea0b1b732014-12-21 14:37:45 +01001096 video_get_option_string(options, "monitor", mon, sizeof(mon),
1097 sunxi_get_mon_desc(sunxi_display.monitor));
1098 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1099 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1100 sunxi_display.monitor = i;
1101 break;
1102 }
1103 }
1104 if (i > SUNXI_MONITOR_LAST)
1105 printf("Unknown monitor: '%s', falling back to '%s'\n",
1106 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001107
Hans de Goede7977ec22014-12-25 13:52:04 +01001108#ifdef CONFIG_VIDEO_HDMI
1109 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1110 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1111 sunxi_display.monitor == sunxi_monitor_hdmi) {
1112 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001113 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001114 if (ret) {
1115 printf("HDMI connected: ");
1116 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1117 mode = &custom;
1118 } else if (hpd) {
1119 sunxi_hdmi_shutdown();
1120 /* Fallback to lcd / vga / none */
1121 if (lcd_mode[0]) {
1122 sunxi_display.monitor = sunxi_monitor_lcd;
1123 } else {
Hans de Goede260f5202014-12-25 13:58:06 +01001124#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goede7977ec22014-12-25 13:52:04 +01001125 sunxi_display.monitor = sunxi_monitor_vga;
1126#else
1127 sunxi_display.monitor = sunxi_monitor_none;
1128#endif
1129 }
1130 } /* else continue with hdmi/dvi without a cable connected */
1131 }
1132#endif
1133
Hans de Goede4125f922014-12-21 14:49:34 +01001134 switch (sunxi_display.monitor) {
1135 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001136 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001137 case sunxi_monitor_dvi:
1138 case sunxi_monitor_hdmi:
Hans de Goede7977ec22014-12-25 13:52:04 +01001139#ifdef CONFIG_VIDEO_HDMI
1140 break;
1141#else
Hans de Goedee9544592014-12-23 23:04:35 +01001142 printf("HDMI/DVI not supported on this board\n");
Hans de Goede83243c42014-12-24 19:47:14 +01001143 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goedee9544592014-12-23 23:04:35 +01001144 return NULL;
Hans de Goedee9544592014-12-23 23:04:35 +01001145#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001146 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001147 if (lcd_mode[0]) {
1148 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1149 mode = &custom;
1150 break;
1151 }
Hans de Goede4125f922014-12-21 14:49:34 +01001152 printf("LCD not supported on this board\n");
Hans de Goede83243c42014-12-24 19:47:14 +01001153 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede4125f922014-12-21 14:49:34 +01001154 return NULL;
1155 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001156#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA
Hans de Goedeac1633c2014-12-24 12:17:07 +01001157 sunxi_display.depth = 18;
1158 break;
1159#else
Hans de Goede4125f922014-12-21 14:49:34 +01001160 printf("VGA not supported on this board\n");
Hans de Goede83243c42014-12-24 19:47:14 +01001161 sunxi_display.monitor = sunxi_monitor_none;
Hans de Goede4125f922014-12-21 14:49:34 +01001162 return NULL;
Hans de Goedeac1633c2014-12-24 12:17:07 +01001163#endif
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001164 }
1165
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001166 if (mode->vmode != FB_VMODE_NONINTERLACED) {
1167 printf("Only non-interlaced modes supported, falling back to 1024x768\n");
1168 mode = &res_mode_init[RES_MODE_1024x768];
1169 } else {
Hans de Goedea0b1b732014-12-21 14:37:45 +01001170 printf("Setting up a %dx%d %s console\n", mode->xres,
1171 mode->yres, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001172 }
1173
Hans de Goede18799252015-02-02 18:00:53 +01001174 sunxi_display.fb_size =
1175 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
1176 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1177 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1178 sunxi_display.fb_size >> 10,
1179 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1180 return NULL;
1181 }
1182
1183 gd->fb_base = gd->bd->bi_dram[0].start +
1184 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001185 sunxi_engines_init();
Hans de Goedea0b1b732014-12-21 14:37:45 +01001186 sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001187
1188 /*
1189 * These are the only members of this structure that are used. All the
1190 * others are driver specific. There is nothing to decribe pitch or
1191 * stride, but we are lucky with our hw.
1192 */
1193 graphic_device->frameAdrs = gd->fb_base;
1194 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1195 graphic_device->gdfBytesPP = 4;
Hans de Goedeccb0ed52014-12-19 13:46:33 +01001196 graphic_device->winSizeX = mode->xres;
1197 graphic_device->winSizeY = mode->yres;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001198
1199 return graphic_device;
1200}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001201
1202/*
1203 * Simplefb support.
1204 */
1205#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1206int sunxi_simplefb_setup(void *blob)
1207{
1208 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1209 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001210 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001211 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001212
Hans de Goedec3cc4262015-01-19 08:44:07 +01001213#ifdef CONFIG_MACH_SUN4I
1214#define PIPELINE_PREFIX "de_fe0-"
1215#else
1216#define PIPELINE_PREFIX
1217#endif
1218
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001219 switch (sunxi_display.monitor) {
1220 case sunxi_monitor_none:
1221 return 0;
1222 case sunxi_monitor_dvi:
1223 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001224 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001225 break;
1226 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001227 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001228 break;
1229 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001230#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001231 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001232#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001233 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001234#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001235 break;
1236 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001237
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001238 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001239 offset = fdt_node_offset_by_compatible(blob, -1,
1240 "allwinner,simple-framebuffer");
1241 while (offset >= 0) {
1242 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001243 pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001244 if (ret == 0)
1245 break;
1246 offset = fdt_node_offset_by_compatible(blob, offset,
1247 "allwinner,simple-framebuffer");
1248 }
1249 if (offset < 0) {
1250 eprintf("Cannot setup simplefb: node not found\n");
1251 return 0; /* Keep older kernels working */
1252 }
1253
Hans de Goede6c912862015-02-02 17:13:29 +01001254 /*
1255 * Do not report the framebuffer as free RAM to the OS, note we cannot
1256 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1257 * and e.g. Linux refuses to iomap RAM on ARM, see:
1258 * linux/arch/arm/mm/ioremap.c around line 301.
1259 */
1260 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001261 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001262 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1263 if (ret) {
1264 eprintf("Cannot setup simplefb: Error reserving memory\n");
1265 return ret;
1266 }
1267
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001268 ret = fdt_setup_simplefb_node(blob, offset, gd->fb_base,
1269 graphic_device->winSizeX, graphic_device->winSizeY,
1270 graphic_device->winSizeX * graphic_device->gdfBytesPP,
1271 "x8r8g8b8");
1272 if (ret)
1273 eprintf("Cannot setup simplefb: Error setting properties\n");
1274
1275 return ret;
1276}
1277#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */