blob: 7c1ea8f2f6a903529398e036ac3e66eaffa5c29e [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>
Hans de Goedec06e00e2015-08-03 19:20:26 +02005 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02006 *
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>
Hans de Goeded955f442015-08-05 00:06:47 +020022#include <malloc.h>
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020023#include <video_fb.h>
Hans de Goedeccb0ed52014-12-19 13:46:33 +010024#include "videomodes.h"
Hans de Goede743fb9552015-01-20 09:23:36 +010025#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashkac02f0522015-01-19 05:23:33 +020026#include "ssd2828.h"
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020027
Hans de Goede2d5d3022015-01-22 21:02:42 +010028#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
29#define PWM_ON 0
30#define PWM_OFF 1
31#else
32#define PWM_ON 1
33#define PWM_OFF 0
34#endif
35
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020036DECLARE_GLOBAL_DATA_PTR;
37
Hans de Goedea0b1b732014-12-21 14:37:45 +010038enum sunxi_monitor {
39 sunxi_monitor_none,
40 sunxi_monitor_dvi,
41 sunxi_monitor_hdmi,
42 sunxi_monitor_lcd,
43 sunxi_monitor_vga,
Hans de Goedec06e00e2015-08-03 19:20:26 +020044 sunxi_monitor_composite_pal,
45 sunxi_monitor_composite_ntsc,
46 sunxi_monitor_composite_pal_m,
47 sunxi_monitor_composite_pal_nc,
Hans de Goedea0b1b732014-12-21 14:37:45 +010048};
Hans de Goedec06e00e2015-08-03 19:20:26 +020049#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goedea0b1b732014-12-21 14:37:45 +010050
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020051struct sunxi_display {
52 GraphicDevice graphic_device;
Hans de Goedea0b1b732014-12-21 14:37:45 +010053 enum sunxi_monitor monitor;
Hans de Goede7e68a1b2014-12-21 16:28:32 +010054 unsigned int depth;
Hans de Goeded955f442015-08-05 00:06:47 +020055 unsigned int fb_addr;
Hans de Goede18799252015-02-02 18:00:53 +010056 unsigned int fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020057} sunxi_display;
58
Hans de Goedec06e00e2015-08-03 19:20:26 +020059const struct ctfb_res_modes composite_video_modes[2] = {
60 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
61 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
62 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
63};
64
Hans de Goedee9544592014-12-23 23:04:35 +010065#ifdef CONFIG_VIDEO_HDMI
66
Hans de Goedea5aa95f2014-12-19 16:05:12 +010067/*
68 * Wait up to 200ms for value to be set in given part of reg.
69 */
70static int await_completion(u32 *reg, u32 mask, u32 val)
71{
72 unsigned long tmo = timer_get_us() + 200000;
73
74 while ((readl(reg) & mask) != val) {
75 if (timer_get_us() > tmo) {
76 printf("DDC: timeout reading EDID\n");
77 return -ETIME;
78 }
79 }
80 return 0;
81}
82
Hans de Goede91593712014-12-28 09:13:21 +010083static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020084{
85 struct sunxi_ccm_reg * const ccm =
86 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
87 struct sunxi_hdmi_reg * const hdmi =
88 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede91593712014-12-28 09:13:21 +010089 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +020090
91 /* Set pll3 to 300MHz */
92 clock_set_pll3(300000000);
93
94 /* Set hdmi parent to pll3 */
95 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
96 CCM_HDMI_CTRL_PLL3);
97
98 /* Set ahb gating to pass */
Hans de Goedef07872b2015-04-06 20:33:34 +020099#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100100 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
101#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200102 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
103
104 /* Clock on */
105 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
106
107 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
108 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
109
Hans de Goede205a30c2014-12-20 15:15:23 +0100110 while (timer_get_us() < tmo) {
111 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
112 return 1;
113 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200114
Hans de Goede205a30c2014-12-20 15:15:23 +0100115 return 0;
Hans de Goede695bda42014-12-19 15:13:57 +0100116}
117
118static void sunxi_hdmi_shutdown(void)
119{
120 struct sunxi_ccm_reg * const ccm =
121 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
122 struct sunxi_hdmi_reg * const hdmi =
123 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200124
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200125 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
126 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
127 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goedef07872b2015-04-06 20:33:34 +0200128#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100129 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
130#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200131 clock_set_pll3(0);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200132}
133
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100134static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
135{
136 struct sunxi_hdmi_reg * const hdmi =
137 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
138
139 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
140 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
141 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
142 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
143 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
144#ifndef CONFIG_MACH_SUN6I
145 writel(n, &hdmi->ddc_byte_count);
146 writel(cmnd, &hdmi->ddc_cmnd);
147#else
148 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
149#endif
150 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
151
152 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
153}
154
155static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
156{
157 struct sunxi_hdmi_reg * const hdmi =
158 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
159 int i, n;
160
161 while (count > 0) {
162 if (count > 16)
163 n = 16;
164 else
165 n = count;
166
167 if (sunxi_hdmi_ddc_do_command(
168 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
169 offset, n))
170 return -ETIME;
171
172 for (i = 0; i < n; i++)
173 *buf++ = readb(&hdmi->ddc_fifo_data);
174
175 offset += n;
176 count -= n;
177 }
178
179 return 0;
180}
181
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100182static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
183{
184 int r, retries = 2;
185
186 do {
187 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
188 if (r)
189 continue;
190 r = edid_check_checksum(buf);
191 if (r) {
192 printf("EDID block %d: checksum error%s\n",
193 block, retries ? ", retrying" : "");
194 }
195 } while (r && retries--);
196
197 return r;
198}
199
Hans de Goedea0b1b732014-12-21 14:37:45 +0100200static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100201{
202 struct edid1_info edid1;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100203 struct edid_cea861_info cea681[4];
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100204 struct edid_detailed_timing *t =
205 (struct edid_detailed_timing *)edid1.monitor_details.timing;
206 struct sunxi_hdmi_reg * const hdmi =
207 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
208 struct sunxi_ccm_reg * const ccm =
209 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100210 int i, r, ext_blocks = 0;
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100211
212 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
213 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
214 &hdmi->pad_ctrl1);
215 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
216 &hdmi->pll_ctrl);
217 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
218
219 /* Reset i2c controller */
220 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
221 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
222 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
223 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
224 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
225 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
226 return -EIO;
227
228 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
229#ifndef CONFIG_MACH_SUN6I
230 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
231 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
232#endif
233
Hans de Goede45b8f7b2014-12-20 14:01:48 +0100234 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100235 if (r == 0) {
236 r = edid_check_info(&edid1);
237 if (r) {
238 printf("EDID: invalid EDID data\n");
239 r = -EINVAL;
240 }
241 }
242 if (r == 0) {
243 ext_blocks = edid1.extension_flag;
244 if (ext_blocks > 4)
245 ext_blocks = 4;
246 for (i = 0; i < ext_blocks; i++) {
247 if (sunxi_hdmi_edid_get_block(1 + i,
248 (u8 *)&cea681[i]) != 0) {
249 ext_blocks = i;
250 break;
251 }
252 }
253 }
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100254
255 /* Disable DDC engine, no longer needed */
256 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
257 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
258
259 if (r)
260 return r;
261
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100262 /* We want version 1.3 or 1.2 with detailed timing info */
263 if (edid1.version != 1 || (edid1.revision < 3 &&
264 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
265 printf("EDID: unsupported version %d.%d\n",
266 edid1.version, edid1.revision);
267 return -EINVAL;
268 }
269
270 /* Take the first usable detailed timing */
271 for (i = 0; i < 4; i++, t++) {
272 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
273 if (r == 0)
274 break;
275 }
276 if (i == 4) {
277 printf("EDID: no usable detailed timing found\n");
278 return -ENOENT;
279 }
280
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100281 /* Check for basic audio support, if found enable hdmi output */
Hans de Goedea0b1b732014-12-21 14:37:45 +0100282 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100283 for (i = 0; i < ext_blocks; i++) {
284 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
285 cea681[i].revision < 2)
286 continue;
287
288 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goedea0b1b732014-12-21 14:37:45 +0100289 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goede1ff6cc42014-12-20 14:31:45 +0100290 }
291
Hans de Goedea5aa95f2014-12-19 16:05:12 +0100292 return 0;
293}
294
Hans de Goedee9544592014-12-23 23:04:35 +0100295#endif /* CONFIG_VIDEO_HDMI */
296
Hans de Goedec3cc4262015-01-19 08:44:07 +0100297#ifdef CONFIG_MACH_SUN4I
298/*
299 * Testing has shown that on sun4i the display backend engine does not have
300 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
301 * fifo underruns. So on sun4i we use the display frontend engine to do the
302 * dma from memory, as the frontend does have deep enough fifo-s.
303 */
304
305static const u32 sun4i_vert_coef[32] = {
306 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
307 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
308 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
309 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
310 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
311 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
312 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
313 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
314};
315
316static const u32 sun4i_horz_coef[64] = {
317 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
318 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
319 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
320 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
321 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
322 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
323 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
324 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
325 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
326 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
327 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
328 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
329 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
330 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
331 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
332 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
333};
334
335static void sunxi_frontend_init(void)
336{
337 struct sunxi_ccm_reg * const ccm =
338 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
339 struct sunxi_de_fe_reg * const de_fe =
340 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
341 int i;
342
343 /* Clocks on */
344 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
345 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
346 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
347
348 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
349
350 for (i = 0; i < 32; i++) {
351 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
352 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
353 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
354 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
355 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
356 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
357 }
358
359 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
360}
361
362static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
363 unsigned int address)
364{
365 struct sunxi_de_fe_reg * const de_fe =
366 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
367
368 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
369 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
370 writel(mode->xres * 4, &de_fe->ch0_stride);
371 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
372 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
373
374 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
375 &de_fe->ch0_insize);
376 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
377 &de_fe->ch0_outsize);
378 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
379 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
380
381 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
382 &de_fe->ch1_insize);
383 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
384 &de_fe->ch1_outsize);
385 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
386 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
387
388 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
389}
390
391static void sunxi_frontend_enable(void)
392{
393 struct sunxi_de_fe_reg * const de_fe =
394 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
395
396 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
397}
398#else
399static void sunxi_frontend_init(void) {}
400static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
401 unsigned int address) {}
402static void sunxi_frontend_enable(void) {}
403#endif
404
Hans de Goedec06e00e2015-08-03 19:20:26 +0200405static bool sunxi_is_composite(void)
406{
407 switch (sunxi_display.monitor) {
408 case sunxi_monitor_none:
409 case sunxi_monitor_dvi:
410 case sunxi_monitor_hdmi:
411 case sunxi_monitor_lcd:
412 case sunxi_monitor_vga:
413 return false;
414 case sunxi_monitor_composite_pal:
415 case sunxi_monitor_composite_ntsc:
416 case sunxi_monitor_composite_pal_m:
417 case sunxi_monitor_composite_pal_nc:
418 return true;
419 }
420
421 return false; /* Never reached */
422}
423
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200424/*
425 * This is the entity that mixes and matches the different layers and inputs.
426 * Allwinner calls it the back-end, but i like composer better.
427 */
428static void sunxi_composer_init(void)
429{
430 struct sunxi_ccm_reg * const ccm =
431 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
432 struct sunxi_de_be_reg * const de_be =
433 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
434 int i;
435
Hans de Goedec3cc4262015-01-19 08:44:07 +0100436 sunxi_frontend_init();
437
Hans de Goedef07872b2015-04-06 20:33:34 +0200438#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100439 /* Reset off */
440 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
441#endif
442
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200443 /* Clocks on */
444 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100445#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200446 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100447#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200448 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
449
450 /* Engine bug, clear registers after reset */
451 for (i = 0x0800; i < 0x1000; i += 4)
452 writel(0, SUNXI_DE_BE0_BASE + i);
453
454 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
455}
456
Hans de Goedec06e00e2015-08-03 19:20:26 +0200457static u32 sunxi_rgb2yuv_coef[12] = {
458 0x00000107, 0x00000204, 0x00000064, 0x00000108,
459 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
460 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
461};
462
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100463static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200464 unsigned int address)
465{
466 struct sunxi_de_be_reg * const de_be =
467 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goedec06e00e2015-08-03 19:20:26 +0200468 int i;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200469
Hans de Goedec3cc4262015-01-19 08:44:07 +0100470 sunxi_frontend_mode_set(mode, address);
471
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200472 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
473 &de_be->disp_size);
474 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
475 &de_be->layer0_size);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100476#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200477 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
478 writel(address << 3, &de_be->layer0_addr_low32b);
479 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goedec3cc4262015-01-19 08:44:07 +0100480#else
481 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
482#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200483 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
484
485 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200486 if (mode->vmode == FB_VMODE_INTERLACED)
487 setbits_le32(&de_be->mode,
488 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
489 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200490
491 if (sunxi_is_composite()) {
492 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
493 &de_be->output_color_ctrl);
494 for (i = 0; i < 12; i++)
495 writel(sunxi_rgb2yuv_coef[i],
496 &de_be->output_color_coef[i]);
497 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200498}
499
Hans de Goede4125f922014-12-21 14:49:34 +0100500static void sunxi_composer_enable(void)
501{
502 struct sunxi_de_be_reg * const de_be =
503 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
504
Hans de Goedec3cc4262015-01-19 08:44:07 +0100505 sunxi_frontend_enable();
506
Hans de Goede4125f922014-12-21 14:49:34 +0100507 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
508 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
509}
510
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200511/*
512 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
513 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100514static void sunxi_lcdc_pll_set(int tcon, int dotclock,
515 int *clk_div, int *clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200516{
517 struct sunxi_ccm_reg * const ccm =
518 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100519 int value, n, m, min_m, max_m, diff;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200520 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
521 int best_double = 0;
522
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100523 if (tcon == 0) {
Hans de Goede797a0f52015-01-01 22:04:34 +0100524#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100525 min_m = 6;
526 max_m = 127;
Hans de Goede797a0f52015-01-01 22:04:34 +0100527#endif
528#ifdef CONFIG_VIDEO_LCD_IF_LVDS
529 min_m = max_m = 7;
530#endif
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100531 } else {
532 min_m = 1;
533 max_m = 15;
534 }
535
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200536 /*
537 * Find the lowest divider resulting in a matching clock, if there
538 * is no match, pick the closest lower clock, as monitors tend to
539 * not sync to higher frequencies.
540 */
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100541 for (m = min_m; m <= max_m; m++) {
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200542 n = (m * dotclock) / 3000;
543
544 if ((n >= 9) && (n <= 127)) {
545 value = (3000 * n) / m;
546 diff = dotclock - value;
547 if (diff < best_diff) {
548 best_diff = diff;
549 best_m = m;
550 best_n = n;
551 best_double = 0;
552 }
553 }
554
555 /* These are just duplicates */
556 if (!(m & 1))
557 continue;
558
559 n = (m * dotclock) / 6000;
560 if ((n >= 9) && (n <= 127)) {
561 value = (6000 * n) / m;
562 diff = dotclock - value;
563 if (diff < best_diff) {
564 best_diff = diff;
565 best_m = m;
566 best_n = n;
567 best_double = 1;
568 }
569 }
570 }
571
572 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
573 dotclock, (best_double + 1) * 3000 * best_n / best_m,
574 best_double + 1, best_n, best_m);
575
576 clock_set_pll3(best_n * 3000000);
577
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100578 if (tcon == 0) {
579 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
580 (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
581 CCM_LCD_CH0_CTRL_PLL3),
582 &ccm->lcd0_ch0_clk_cfg);
583 } else {
584 writel(CCM_LCD_CH1_CTRL_GATE |
585 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
586 CCM_LCD_CH1_CTRL_PLL3) |
587 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goedec06e00e2015-08-03 19:20:26 +0200588 if (sunxi_is_composite())
589 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
590 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100591 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200592
593 *clk_div = best_m;
594 *clk_double = best_double;
595}
596
597static void sunxi_lcdc_init(void)
598{
599 struct sunxi_ccm_reg * const ccm =
600 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
601 struct sunxi_lcdc_reg * const lcdc =
602 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
603
604 /* Reset off */
Hans de Goedef07872b2015-04-06 20:33:34 +0200605#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedef651e0a2014-11-14 17:42:14 +0100606 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
607#else
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200608 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goedef651e0a2014-11-14 17:42:14 +0100609#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200610
611 /* Clock on */
612 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100613#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede5f67b862015-05-14 18:52:54 +0200614#ifdef CONFIG_SUNXI_GEN_SUN6I
615 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
616#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100617 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
618#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200619#endif
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200620
621 /* Init lcdc */
622 writel(0, &lcdc->ctrl); /* Disable tcon */
623 writel(0, &lcdc->int0); /* Disable all interrupts */
624
625 /* Disable tcon0 dot clock */
626 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
627
628 /* Set all io lines to tristate */
629 writel(0xffffffff, &lcdc->tcon0_io_tristate);
630 writel(0xffffffff, &lcdc->tcon1_io_tristate);
631}
632
Hans de Goede4125f922014-12-21 14:49:34 +0100633static void sunxi_lcdc_enable(void)
634{
635 struct sunxi_lcdc_reg * const lcdc =
636 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
637
638 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede797a0f52015-01-01 22:04:34 +0100639#ifdef CONFIG_VIDEO_LCD_IF_LVDS
640 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
641 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede5f67b862015-05-14 18:52:54 +0200642#ifdef CONFIG_SUNXI_GEN_SUN6I
643 udelay(2); /* delay at least 1200 ns */
644 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
645 udelay(2); /* delay at least 1200 ns */
646 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
647 if (sunxi_display.depth == 18)
648 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
649 else
650 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
651#else
Hans de Goede797a0f52015-01-01 22:04:34 +0100652 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
653 udelay(2); /* delay at least 1200 ns */
654 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
655 udelay(1); /* delay at least 120 ns */
656 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
657 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
658#endif
Hans de Goede5f67b862015-05-14 18:52:54 +0200659#endif
Hans de Goede4125f922014-12-21 14:49:34 +0100660}
661
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100662static void sunxi_lcdc_panel_enable(void)
663{
Hans de Goedece9e3322015-02-16 17:26:41 +0100664 int pin, reset_pin;
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100665
666 /*
667 * Start with backlight disabled to avoid the screen flashing to
668 * white while the lcd inits.
669 */
670 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200671 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100672 gpio_request(pin, "lcd_backlight_enable");
673 gpio_direction_output(pin, 0);
674 }
675
676 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200677 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100678 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goede2d5d3022015-01-22 21:02:42 +0100679 gpio_direction_output(pin, PWM_OFF);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100680 }
681
Hans de Goedece9e3322015-02-16 17:26:41 +0100682 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede7783ab22015-04-22 17:45:59 +0200683 if (reset_pin >= 0) {
Hans de Goedece9e3322015-02-16 17:26:41 +0100684 gpio_request(reset_pin, "lcd_reset");
685 gpio_direction_output(reset_pin, 0); /* Assert reset */
686 }
687
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100688 /* Give the backlight some time to turn off and power up the panel. */
689 mdelay(40);
690 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede7783ab22015-04-22 17:45:59 +0200691 if (pin >= 0) {
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100692 gpio_request(pin, "lcd_power");
693 gpio_direction_output(pin, 1);
694 }
Hans de Goedece9e3322015-02-16 17:26:41 +0100695
Hans de Goede7783ab22015-04-22 17:45:59 +0200696 if (reset_pin >= 0)
Hans de Goedece9e3322015-02-16 17:26:41 +0100697 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100698}
699
700static void sunxi_lcdc_backlight_enable(void)
701{
702 int pin;
703
704 /*
705 * We want to have scanned out at least one frame before enabling the
706 * backlight to avoid the screen flashing to white when we enable it.
707 */
708 mdelay(40);
709
710 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +0200711 if (pin >= 0)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100712 gpio_direction_output(pin, 1);
713
714 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede7783ab22015-04-22 17:45:59 +0200715 if (pin >= 0)
Hans de Goede2d5d3022015-01-22 21:02:42 +0100716 gpio_direction_output(pin, PWM_ON);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100717}
718
Hans de Goede3cbcb272015-08-02 17:38:43 +0200719static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100720{
721 int delay;
722
Hans de Goede3cbcb272015-08-02 17:38:43 +0200723 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
Hans de Goede1977bbb2015-08-02 16:49:29 +0200724 if (mode->vmode == FB_VMODE_INTERLACED)
725 delay /= 2;
Hans de Goede3cbcb272015-08-02 17:38:43 +0200726 if (tcon == 1)
727 delay -= 2;
728
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100729 return (delay > 30) ? 30 : delay;
730}
731
Hans de Goede18366f72015-01-25 15:33:07 +0100732static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
733 bool for_ext_vga_dac)
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100734{
735 struct sunxi_lcdc_reg * const lcdc =
736 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
737 int bp, clk_delay, clk_div, clk_double, pin, total, val;
738
739 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++)
Hans de Goede797a0f52015-01-01 22:04:34 +0100740#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100741 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100742#endif
743#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100744 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede797a0f52015-01-01 22:04:34 +0100745#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100746
747 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
748
749 /* Use tcon0 */
750 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
751 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
752
Hans de Goede3cbcb272015-08-02 17:38:43 +0200753 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100754 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
755 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
756
757 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
758 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
759
760 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
761 &lcdc->tcon0_timing_active);
762
763 bp = mode->hsync_len + mode->left_margin;
764 total = mode->xres + mode->right_margin + bp;
765 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
766 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
767
768 bp = mode->vsync_len + mode->upper_margin;
769 total = mode->yres + mode->lower_margin + bp;
770 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
771 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
772
Hans de Goede797a0f52015-01-01 22:04:34 +0100773#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100774 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
775 &lcdc->tcon0_timing_sync);
776
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100777 writel(0, &lcdc->tcon0_hv_intf);
778 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100779#endif
780#ifdef CONFIG_VIDEO_LCD_IF_LVDS
781 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede5f67b862015-05-14 18:52:54 +0200782 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
783 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede797a0f52015-01-01 22:04:34 +0100784#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100785
786 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
787 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
788 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
789 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
790 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
791 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
792 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
793 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
794 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
795 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
796 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
797 writel(((sunxi_display.depth == 18) ?
798 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
799 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
800 &lcdc->tcon0_frm_ctrl);
801 }
802
Hans de Goede481b6642015-01-13 13:21:46 +0100803 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100804 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
805 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
806 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
807 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goede18366f72015-01-25 15:33:07 +0100808
809#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
810 if (for_ext_vga_dac)
811 val = 0;
812#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +0100813 writel(val, &lcdc->tcon0_io_polarity);
814
815 writel(0, &lcdc->tcon0_io_tristate);
816}
817
Hans de Goedec06e00e2015-08-03 19:20:26 +0200818#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede4125f922014-12-21 14:49:34 +0100819static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedec3d15042014-12-27 15:19:23 +0100820 int *clk_div, int *clk_double,
821 bool use_portd_hvsync)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200822{
823 struct sunxi_lcdc_reg * const lcdc =
824 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goede1977bbb2015-08-02 16:49:29 +0200825 int bp, clk_delay, total, val, yres;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200826
827 /* Use tcon1 */
828 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
829 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
830
Hans de Goede3cbcb272015-08-02 17:38:43 +0200831 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200832 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goede1977bbb2015-08-02 16:49:29 +0200833 ((mode->vmode == FB_VMODE_INTERLACED) ?
834 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
Hans de Goedeac5d43d2014-12-24 19:50:11 +0100835 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200836
Hans de Goede1977bbb2015-08-02 16:49:29 +0200837 yres = mode->yres;
838 if (mode->vmode == FB_VMODE_INTERLACED)
839 yres /= 2;
840 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200841 &lcdc->tcon1_timing_source);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200842 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200843 &lcdc->tcon1_timing_scale);
Hans de Goede1977bbb2015-08-02 16:49:29 +0200844 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200845 &lcdc->tcon1_timing_out);
846
847 bp = mode->hsync_len + mode->left_margin;
848 total = mode->xres + mode->right_margin + bp;
849 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
850 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
851
852 bp = mode->vsync_len + mode->upper_margin;
853 total = mode->yres + mode->lower_margin + bp;
Hans de Goede1977bbb2015-08-02 16:49:29 +0200854 if (mode->vmode == FB_VMODE_NONINTERLACED)
855 total *= 2;
856 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200857 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
858
859 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
860 &lcdc->tcon1_timing_sync);
861
Hans de Goedec3d15042014-12-27 15:19:23 +0100862 if (use_portd_hvsync) {
Paul Kocialkowskiae358a42015-03-22 18:12:22 +0100863 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
864 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goedec3d15042014-12-27 15:19:23 +0100865
866 val = 0;
867 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
868 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
869 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
870 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
871 writel(val, &lcdc->tcon1_io_polarity);
872
873 clrbits_le32(&lcdc->tcon1_io_tristate,
874 SUNXI_LCDC_TCON_VSYNC_MASK |
875 SUNXI_LCDC_TCON_HSYNC_MASK);
876 }
Hans de Goedec5a3b4b2014-12-21 16:27:45 +0100877 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200878}
Hans de Goedec06e00e2015-08-03 19:20:26 +0200879#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +0100880
881#ifdef CONFIG_VIDEO_HDMI
Hans de Goedef651e0a2014-11-14 17:42:14 +0100882
Hans de Goedea2017e82014-12-20 13:38:06 +0100883static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
884{
885 struct sunxi_hdmi_reg * const hdmi =
886 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
887 u8 checksum = 0;
888 u8 avi_info_frame[17] = {
889 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
891 0x00
892 };
893 u8 vendor_info_frame[19] = {
894 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
896 0x00, 0x00, 0x00
897 };
898 int i;
899
900 if (mode->pixclock_khz <= 27000)
901 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
902 else
903 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
904
905 if (mode->xres * 100 / mode->yres < 156)
906 avi_info_frame[5] |= 0x18; /* 4 : 3 */
907 else
908 avi_info_frame[5] |= 0x28; /* 16 : 9 */
909
910 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
911 checksum += avi_info_frame[i];
912
913 avi_info_frame[3] = 0x100 - checksum;
914
915 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
916 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
917
918 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
919 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
920
921 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
922 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
923
924 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
925 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
926
927 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
928}
929
Hans de Goedeccb0ed52014-12-19 13:46:33 +0100930static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea0b1b732014-12-21 14:37:45 +0100931 int clk_div, int clk_double)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200932{
933 struct sunxi_hdmi_reg * const hdmi =
934 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
935 int x, y;
936
937 /* Write clear interrupt status bits */
938 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
939
Hans de Goedea0b1b732014-12-21 14:37:45 +0100940 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goedea2017e82014-12-20 13:38:06 +0100941 sunxi_hdmi_setup_info_frames(mode);
942
Hans de Goede95576692014-12-20 13:51:16 +0100943 /* Set input sync enable */
944 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
945
Luc Verhaegenb01df1e2014-08-13 07:55:06 +0200946 /* Init various registers, select pll3 as clock source */
947 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
948 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
949 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
950 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
951 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
952
953 /* Setup clk div and doubler */
954 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
955 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
956 if (!clk_double)
957 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
958
959 /* Setup timing registers */
960 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
961 &hdmi->video_size);
962
963 x = mode->hsync_len + mode->left_margin;
964 y = mode->vsync_len + mode->upper_margin;
965 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
966
967 x = mode->right_margin;
968 y = mode->lower_margin;
969 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
970
971 x = mode->hsync_len;
972 y = mode->vsync_len;
973 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
974
975 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
976 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
977
978 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
979 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
980}
981
Hans de Goede4125f922014-12-21 14:49:34 +0100982static void sunxi_hdmi_enable(void)
983{
984 struct sunxi_hdmi_reg * const hdmi =
985 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
986
987 udelay(100);
988 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
989}
990
Hans de Goedee9544592014-12-23 23:04:35 +0100991#endif /* CONFIG_VIDEO_HDMI */
992
Hans de Goedec06e00e2015-08-03 19:20:26 +0200993#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede260f5202014-12-25 13:58:06 +0100994
Hans de Goedec06e00e2015-08-03 19:20:26 +0200995static void sunxi_tvencoder_mode_set(void)
Hans de Goede260f5202014-12-25 13:58:06 +0100996{
997 struct sunxi_ccm_reg * const ccm =
998 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
999 struct sunxi_tve_reg * const tve =
1000 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1001
1002 /* Clock on */
1003 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1004
Hans de Goedec06e00e2015-08-03 19:20:26 +02001005 switch (sunxi_display.monitor) {
1006 case sunxi_monitor_vga:
1007 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1008 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1009 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
1010 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1011 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1012 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1013 break;
1014 case sunxi_monitor_composite_pal_nc:
1015 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1016 /* Fall through */
1017 case sunxi_monitor_composite_pal:
1018 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1019 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1020 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1021 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1022 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1023 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1024 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1025 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1026 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1027 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1028 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1029 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1030 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1031 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1032 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1033 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1034 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1035 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1036 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1037 break;
1038 case sunxi_monitor_composite_pal_m:
1039 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1040 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1041 /* Fall through */
1042 case sunxi_monitor_composite_ntsc:
1043 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1044 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1045 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1046 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1047 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1048 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1049 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1050 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1051 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1052 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1053 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1054 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1055 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1056 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1057 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1058 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1059 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1060 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1061 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1062 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1063 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1064 break;
1065 case sunxi_monitor_none:
1066 case sunxi_monitor_dvi:
1067 case sunxi_monitor_hdmi:
1068 case sunxi_monitor_lcd:
1069 break;
1070 }
Hans de Goede260f5202014-12-25 13:58:06 +01001071}
1072
Hans de Goedec06e00e2015-08-03 19:20:26 +02001073static void sunxi_tvencoder_enable(void)
Hans de Goede260f5202014-12-25 13:58:06 +01001074{
1075 struct sunxi_tve_reg * const tve =
1076 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1077
1078 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1079}
1080
Hans de Goedec06e00e2015-08-03 19:20:26 +02001081#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goede260f5202014-12-25 13:58:06 +01001082
Hans de Goede115e4b42014-12-23 18:39:52 +01001083static void sunxi_drc_init(void)
1084{
Hans de Goedef07872b2015-04-06 20:33:34 +02001085#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede115e4b42014-12-23 18:39:52 +01001086 struct sunxi_ccm_reg * const ccm =
1087 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1088
1089 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar3702f142015-03-01 23:47:48 +05301090#ifdef CONFIG_MACH_SUN8I_A33
1091 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1092#endif
Hans de Goede115e4b42014-12-23 18:39:52 +01001093 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1094 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1095#endif
1096}
1097
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001098#ifdef CONFIG_VIDEO_VGA_VIA_LCD
1099static void sunxi_vga_external_dac_enable(void)
1100{
1101 int pin;
1102
1103 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede7783ab22015-04-22 17:45:59 +02001104 if (pin >= 0) {
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001105 gpio_request(pin, "vga_enable");
1106 gpio_direction_output(pin, 1);
1107 }
1108}
1109#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1110
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001111#ifdef CONFIG_VIDEO_LCD_SSD2828
1112static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1113{
1114 struct ssd2828_config cfg = {
1115 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1116 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1117 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1118 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1119 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1120 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1121 .ssd2828_color_depth = 24,
1122#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1123 .mipi_dsi_number_of_data_lanes = 4,
1124 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1125 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1126 .mipi_dsi_delay_after_set_display_on_ms = 200
1127#else
1128#error MIPI LCD panel needs configuration parameters
1129#endif
1130 };
1131
1132 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1133 printf("SSD2828: SPI pins are not properly configured\n");
1134 return 1;
1135 }
1136 if (cfg.reset_pin == -1) {
1137 printf("SSD2828: Reset pin is not properly configured\n");
1138 return 1;
1139 }
1140
1141 return ssd2828_init(&cfg, mode);
1142}
1143#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1144
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001145static void sunxi_engines_init(void)
1146{
1147 sunxi_composer_init();
1148 sunxi_lcdc_init();
Hans de Goedef651e0a2014-11-14 17:42:14 +01001149 sunxi_drc_init();
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001150}
1151
Hans de Goedea0b1b732014-12-21 14:37:45 +01001152static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goedea2017e82014-12-20 13:38:06 +01001153 unsigned int address)
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001154{
Hans de Goede260f5202014-12-25 13:58:06 +01001155 int __maybe_unused clk_div, clk_double;
1156
Hans de Goede4125f922014-12-21 14:49:34 +01001157 switch (sunxi_display.monitor) {
1158 case sunxi_monitor_none:
1159 break;
1160 case sunxi_monitor_dvi:
Hans de Goede260f5202014-12-25 13:58:06 +01001161 case sunxi_monitor_hdmi:
Hans de Goedee9544592014-12-23 23:04:35 +01001162#ifdef CONFIG_VIDEO_HDMI
Hans de Goede4125f922014-12-21 14:49:34 +01001163 sunxi_composer_mode_set(mode, address);
Hans de Goedec3d15042014-12-27 15:19:23 +01001164 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede4125f922014-12-21 14:49:34 +01001165 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1166 sunxi_composer_enable();
1167 sunxi_lcdc_enable();
1168 sunxi_hdmi_enable();
Hans de Goedee9544592014-12-23 23:04:35 +01001169#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001170 break;
1171 case sunxi_monitor_lcd:
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001172 sunxi_lcdc_panel_enable();
Hans de Goede743fb9552015-01-20 09:23:36 +01001173 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1174 mdelay(50); /* Wait for lcd controller power on */
1175 hitachi_tx18d42vm_init();
1176 }
Hans de Goede613dade2015-02-16 17:49:47 +01001177 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1178 unsigned int orig_i2c_bus = i2c_get_bus_num();
1179 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1180 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1181 i2c_set_bus_num(orig_i2c_bus);
1182 }
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001183 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001184 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001185 sunxi_composer_enable();
1186 sunxi_lcdc_enable();
Siarhei Siamashkac02f0522015-01-19 05:23:33 +02001187#ifdef CONFIG_VIDEO_LCD_SSD2828
1188 sunxi_ssd2828_init(mode);
1189#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001190 sunxi_lcdc_backlight_enable();
Hans de Goede4125f922014-12-21 14:49:34 +01001191 break;
1192 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001193#ifdef CONFIG_VIDEO_VGA
1194 sunxi_composer_mode_set(mode, address);
1195 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goedec06e00e2015-08-03 19:20:26 +02001196 sunxi_tvencoder_mode_set();
Hans de Goede260f5202014-12-25 13:58:06 +01001197 sunxi_composer_enable();
1198 sunxi_lcdc_enable();
Hans de Goedec06e00e2015-08-03 19:20:26 +02001199 sunxi_tvencoder_enable();
Hans de Goede260f5202014-12-25 13:58:06 +01001200#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedeac1633c2014-12-24 12:17:07 +01001201 sunxi_composer_mode_set(mode, address);
Hans de Goede18366f72015-01-25 15:33:07 +01001202 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedeac1633c2014-12-24 12:17:07 +01001203 sunxi_composer_enable();
1204 sunxi_lcdc_enable();
Chen-Yu Tsai9ed19522015-01-12 18:02:11 +08001205 sunxi_vga_external_dac_enable();
Hans de Goedeac1633c2014-12-24 12:17:07 +01001206#endif
Hans de Goede4125f922014-12-21 14:49:34 +01001207 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001208 case sunxi_monitor_composite_pal:
1209 case sunxi_monitor_composite_ntsc:
1210 case sunxi_monitor_composite_pal_m:
1211 case sunxi_monitor_composite_pal_nc:
1212#ifdef CONFIG_VIDEO_COMPOSITE
1213 sunxi_composer_mode_set(mode, address);
1214 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1215 sunxi_tvencoder_mode_set();
1216 sunxi_composer_enable();
1217 sunxi_lcdc_enable();
1218 sunxi_tvencoder_enable();
1219#endif
1220 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001221 }
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001222}
1223
Hans de Goedea0b1b732014-12-21 14:37:45 +01001224static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1225{
1226 switch (monitor) {
Hans de Goedec06e00e2015-08-03 19:20:26 +02001227 case sunxi_monitor_none: return "none";
1228 case sunxi_monitor_dvi: return "dvi";
1229 case sunxi_monitor_hdmi: return "hdmi";
1230 case sunxi_monitor_lcd: return "lcd";
1231 case sunxi_monitor_vga: return "vga";
1232 case sunxi_monitor_composite_pal: return "composite-pal";
1233 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1234 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1235 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goedea0b1b732014-12-21 14:37:45 +01001236 }
1237 return NULL; /* never reached */
1238}
1239
Hans de Goede6c912862015-02-02 17:13:29 +01001240ulong board_get_usable_ram_top(ulong total_size)
1241{
1242 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1243}
1244
Hans de Goedea2bba492015-08-03 23:01:38 +02001245static bool sunxi_has_hdmi(void)
1246{
1247#ifdef CONFIG_VIDEO_HDMI
1248 return true;
1249#else
1250 return false;
1251#endif
1252}
1253
1254static bool sunxi_has_lcd(void)
1255{
1256 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1257
1258 return lcd_mode[0] != 0;
1259}
1260
1261static bool sunxi_has_vga(void)
1262{
1263#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1264 return true;
1265#else
1266 return false;
1267#endif
1268}
1269
Hans de Goedec06e00e2015-08-03 19:20:26 +02001270static bool sunxi_has_composite(void)
1271{
1272#ifdef CONFIG_VIDEO_COMPOSITE
1273 return true;
1274#else
1275 return false;
1276#endif
1277}
1278
Hans de Goedea2bba492015-08-03 23:01:38 +02001279static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1280{
1281 if (allow_hdmi && sunxi_has_hdmi())
1282 return sunxi_monitor_dvi;
1283 else if (sunxi_has_lcd())
1284 return sunxi_monitor_lcd;
1285 else if (sunxi_has_vga())
1286 return sunxi_monitor_vga;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001287 else if (sunxi_has_composite())
1288 return sunxi_monitor_composite_pal;
Hans de Goedea2bba492015-08-03 23:01:38 +02001289 else
1290 return sunxi_monitor_none;
1291}
1292
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001293void *video_hw_init(void)
1294{
1295 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001296 const struct ctfb_res_modes *mode;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001297 struct ctfb_res_modes custom;
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001298 const char *options;
Hans de Goedee9544592014-12-23 23:04:35 +01001299#ifdef CONFIG_VIDEO_HDMI
Hans de Goede91593712014-12-28 09:13:21 +01001300 int ret, hpd, hpd_delay, edid;
Hans de Goedee9544592014-12-23 23:04:35 +01001301#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001302 int i, overscan_offset, overscan_x, overscan_y;
1303 unsigned int fb_dma_addr;
Hans de Goedea0b1b732014-12-21 14:37:45 +01001304 char mon[16];
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001305 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001306
1307 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1308
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001309 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1310 &sunxi_display.depth, &options);
Hans de Goedee9544592014-12-23 23:04:35 +01001311#ifdef CONFIG_VIDEO_HDMI
Hans de Goede695bda42014-12-19 15:13:57 +01001312 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede91593712014-12-28 09:13:21 +01001313 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001314 edid = video_get_option_int(options, "edid", 1);
Hans de Goedee9544592014-12-23 23:04:35 +01001315#endif
Hans de Goeded955f442015-08-05 00:06:47 +02001316 overscan_x = video_get_option_int(options, "overscan_x", -1);
1317 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedea2bba492015-08-03 23:01:38 +02001318 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goedea0b1b732014-12-21 14:37:45 +01001319 video_get_option_string(options, "monitor", mon, sizeof(mon),
1320 sunxi_get_mon_desc(sunxi_display.monitor));
1321 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1322 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1323 sunxi_display.monitor = i;
1324 break;
1325 }
1326 }
1327 if (i > SUNXI_MONITOR_LAST)
1328 printf("Unknown monitor: '%s', falling back to '%s'\n",
1329 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede3f21d2a2014-12-19 14:03:40 +01001330
Hans de Goede7977ec22014-12-25 13:52:04 +01001331#ifdef CONFIG_VIDEO_HDMI
1332 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1333 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1334 sunxi_display.monitor == sunxi_monitor_hdmi) {
1335 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede91593712014-12-28 09:13:21 +01001336 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede7977ec22014-12-25 13:52:04 +01001337 if (ret) {
1338 printf("HDMI connected: ");
1339 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1340 mode = &custom;
1341 } else if (hpd) {
1342 sunxi_hdmi_shutdown();
Hans de Goedea2bba492015-08-03 23:01:38 +02001343 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede7977ec22014-12-25 13:52:04 +01001344 } /* else continue with hdmi/dvi without a cable connected */
1345 }
1346#endif
1347
Hans de Goede4125f922014-12-21 14:49:34 +01001348 switch (sunxi_display.monitor) {
1349 case sunxi_monitor_none:
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001350 return NULL;
Hans de Goede4125f922014-12-21 14:49:34 +01001351 case sunxi_monitor_dvi:
1352 case sunxi_monitor_hdmi:
Hans de Goedea2bba492015-08-03 23:01:38 +02001353 if (!sunxi_has_hdmi()) {
1354 printf("HDMI/DVI not supported on this board\n");
1355 sunxi_display.monitor = sunxi_monitor_none;
1356 return NULL;
1357 }
Hans de Goede7977ec22014-12-25 13:52:04 +01001358 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001359 case sunxi_monitor_lcd:
Hans de Goedea2bba492015-08-03 23:01:38 +02001360 if (!sunxi_has_lcd()) {
1361 printf("LCD not supported on this board\n");
1362 sunxi_display.monitor = sunxi_monitor_none;
1363 return NULL;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001364 }
Hans de Goedea2bba492015-08-03 23:01:38 +02001365 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1366 mode = &custom;
1367 break;
Hans de Goede4125f922014-12-21 14:49:34 +01001368 case sunxi_monitor_vga:
Hans de Goedea2bba492015-08-03 23:01:38 +02001369 if (!sunxi_has_vga()) {
1370 printf("VGA not supported on this board\n");
1371 sunxi_display.monitor = sunxi_monitor_none;
1372 return NULL;
1373 }
Hans de Goedeac1633c2014-12-24 12:17:07 +01001374 sunxi_display.depth = 18;
1375 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001376 case sunxi_monitor_composite_pal:
1377 case sunxi_monitor_composite_ntsc:
1378 case sunxi_monitor_composite_pal_m:
1379 case sunxi_monitor_composite_pal_nc:
1380 if (!sunxi_has_composite()) {
1381 printf("Composite video not supported on this board\n");
1382 sunxi_display.monitor = sunxi_monitor_none;
1383 return NULL;
1384 }
1385 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1386 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1387 mode = &composite_video_modes[0];
1388 else
1389 mode = &composite_video_modes[1];
1390 sunxi_display.depth = 24;
1391 break;
Hans de Goedea5aa95f2014-12-19 16:05:12 +01001392 }
1393
Hans de Goeded955f442015-08-05 00:06:47 +02001394 /* Yes these defaults are quite high, overscan on composite sucks... */
1395 if (overscan_x == -1)
1396 overscan_x = sunxi_is_composite() ? 32 : 0;
1397 if (overscan_y == -1)
1398 overscan_y = sunxi_is_composite() ? 20 : 0;
1399
Hans de Goede18799252015-02-02 18:00:53 +01001400 sunxi_display.fb_size =
1401 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goeded955f442015-08-05 00:06:47 +02001402 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1403 /* We want to keep the fb_base for simplefb page aligned, where as
1404 * the sunxi dma engines will happily accept an unaligned address. */
1405 if (overscan_offset)
1406 sunxi_display.fb_size += 0x1000;
1407
Hans de Goede18799252015-02-02 18:00:53 +01001408 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1409 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1410 sunxi_display.fb_size >> 10,
1411 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1412 return NULL;
1413 }
1414
Hans de Goeded955f442015-08-05 00:06:47 +02001415 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1416 mode->xres, mode->yres,
Hans de Goede1977bbb2015-08-02 16:49:29 +02001417 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goeded955f442015-08-05 00:06:47 +02001418 sunxi_get_mon_desc(sunxi_display.monitor),
1419 overscan_x, overscan_y);
Hans de Goede1977bbb2015-08-02 16:49:29 +02001420
Hans de Goede18799252015-02-02 18:00:53 +01001421 gd->fb_base = gd->bd->bi_dram[0].start +
1422 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001423 sunxi_engines_init();
Hans de Goeded955f442015-08-05 00:06:47 +02001424
1425 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1426 sunxi_display.fb_addr = gd->fb_base;
1427 if (overscan_offset) {
1428 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1429 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1430 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1431 flush_cache(gd->fb_base, sunxi_display.fb_size);
1432 }
1433 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001434
1435 /*
1436 * These are the only members of this structure that are used. All the
Hans de Goeded955f442015-08-05 00:06:47 +02001437 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001438 */
Hans de Goeded955f442015-08-05 00:06:47 +02001439 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001440 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1441 graphic_device->gdfBytesPP = 4;
Hans de Goeded955f442015-08-05 00:06:47 +02001442 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1443 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1444 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegenb01df1e2014-08-13 07:55:06 +02001445
1446 return graphic_device;
1447}
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001448
1449/*
1450 * Simplefb support.
1451 */
1452#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1453int sunxi_simplefb_setup(void *blob)
1454{
1455 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1456 int offset, ret;
Hans de Goede6c912862015-02-02 17:13:29 +01001457 u64 start, size;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001458 const char *pipeline = NULL;
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001459
Hans de Goedec3cc4262015-01-19 08:44:07 +01001460#ifdef CONFIG_MACH_SUN4I
1461#define PIPELINE_PREFIX "de_fe0-"
1462#else
1463#define PIPELINE_PREFIX
1464#endif
1465
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001466 switch (sunxi_display.monitor) {
1467 case sunxi_monitor_none:
1468 return 0;
1469 case sunxi_monitor_dvi:
1470 case sunxi_monitor_hdmi:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001471 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001472 break;
1473 case sunxi_monitor_lcd:
Hans de Goedec3cc4262015-01-19 08:44:07 +01001474 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001475 break;
1476 case sunxi_monitor_vga:
Hans de Goede260f5202014-12-25 13:58:06 +01001477#ifdef CONFIG_VIDEO_VGA
Hans de Goedec3cc4262015-01-19 08:44:07 +01001478 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goede260f5202014-12-25 13:58:06 +01001479#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedec3cc4262015-01-19 08:44:07 +01001480 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede260f5202014-12-25 13:58:06 +01001481#endif
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001482 break;
Hans de Goedec06e00e2015-08-03 19:20:26 +02001483 case sunxi_monitor_composite_pal:
1484 case sunxi_monitor_composite_ntsc:
1485 case sunxi_monitor_composite_pal_m:
1486 case sunxi_monitor_composite_pal_nc:
1487 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1488 break;
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001489 }
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001490
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001491 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001492 offset = fdt_node_offset_by_compatible(blob, -1,
1493 "allwinner,simple-framebuffer");
1494 while (offset >= 0) {
1495 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede7e68a1b2014-12-21 16:28:32 +01001496 pipeline);
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001497 if (ret == 0)
1498 break;
1499 offset = fdt_node_offset_by_compatible(blob, offset,
1500 "allwinner,simple-framebuffer");
1501 }
1502 if (offset < 0) {
1503 eprintf("Cannot setup simplefb: node not found\n");
1504 return 0; /* Keep older kernels working */
1505 }
1506
Hans de Goede6c912862015-02-02 17:13:29 +01001507 /*
1508 * Do not report the framebuffer as free RAM to the OS, note we cannot
1509 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1510 * and e.g. Linux refuses to iomap RAM on ARM, see:
1511 * linux/arch/arm/mm/ioremap.c around line 301.
1512 */
1513 start = gd->bd->bi_dram[0].start;
Hans de Goede18799252015-02-02 18:00:53 +01001514 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede6c912862015-02-02 17:13:29 +01001515 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1516 if (ret) {
1517 eprintf("Cannot setup simplefb: Error reserving memory\n");
1518 return ret;
1519 }
1520
Hans de Goeded955f442015-08-05 00:06:47 +02001521 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001522 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goeded955f442015-08-05 00:06:47 +02001523 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen4869a8c2014-08-13 07:55:07 +02001524 if (ret)
1525 eprintf("Cannot setup simplefb: Error setting properties\n");
1526
1527 return ret;
1528}
1529#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */