blob: 56f6c8e3497377653a076852875750e112813bb0 [file] [log] [blame]
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001/*
2 * Display driver for Allwinner SoCs.
3 *
4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
Hans de Goede39920c82015-08-03 19:20:26 +02005 * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
Luc Verhaegen7f2c5212014-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 Goede2dae8002014-12-21 16:28:32 +010014#include <asm/arch/gpio.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020015#include <asm/global_data.h>
Hans de Goede2dae8002014-12-21 16:28:32 +010016#include <asm/gpio.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020017#include <asm/io.h>
Hans de Goede6944aff2015-10-03 15:18:33 +020018#include <axp_pmic.h>
Hans de Goede75481602014-12-19 16:05:12 +010019#include <errno.h>
Luc Verhaegen2d7a0842014-08-13 07:55:07 +020020#include <fdtdec.h>
21#include <fdt_support.h>
Hans de Goedeaad2ac22015-02-16 17:49:47 +010022#include <i2c.h>
Hans de Goede58332f82015-08-05 00:06:47 +020023#include <malloc.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020024#include <video_fb.h>
Hans de Goedebe8ec632014-12-19 13:46:33 +010025#include "videomodes.h"
Hans de Goedec1cfd512015-08-08 16:13:53 +020026#include "anx9804.h"
Hans de Goede27515b22015-01-20 09:23:36 +010027#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashka97ece832015-01-19 05:23:33 +020028#include "ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020029
Hans de Goedea7403ae2015-01-22 21:02:42 +010030#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
31#define PWM_ON 0
32#define PWM_OFF 1
33#else
34#define PWM_ON 1
35#define PWM_OFF 0
36#endif
37
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020038DECLARE_GLOBAL_DATA_PTR;
39
Hans de Goede1c092202014-12-21 14:37:45 +010040enum sunxi_monitor {
41 sunxi_monitor_none,
42 sunxi_monitor_dvi,
43 sunxi_monitor_hdmi,
44 sunxi_monitor_lcd,
45 sunxi_monitor_vga,
Hans de Goede39920c82015-08-03 19:20:26 +020046 sunxi_monitor_composite_pal,
47 sunxi_monitor_composite_ntsc,
48 sunxi_monitor_composite_pal_m,
49 sunxi_monitor_composite_pal_nc,
Hans de Goede1c092202014-12-21 14:37:45 +010050};
Hans de Goede39920c82015-08-03 19:20:26 +020051#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goede1c092202014-12-21 14:37:45 +010052
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020053struct sunxi_display {
54 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010055 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010056 unsigned int depth;
Hans de Goede58332f82015-08-05 00:06:47 +020057 unsigned int fb_addr;
Hans de Goede20779ec2015-02-02 18:00:53 +010058 unsigned int fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020059} sunxi_display;
60
Hans de Goede39920c82015-08-03 19:20:26 +020061const struct ctfb_res_modes composite_video_modes[2] = {
62 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
63 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
64 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
65};
66
Hans de Goede2fbf0912014-12-23 23:04:35 +010067#ifdef CONFIG_VIDEO_HDMI
68
Hans de Goede75481602014-12-19 16:05:12 +010069/*
70 * Wait up to 200ms for value to be set in given part of reg.
71 */
72static int await_completion(u32 *reg, u32 mask, u32 val)
73{
74 unsigned long tmo = timer_get_us() + 200000;
75
76 while ((readl(reg) & mask) != val) {
77 if (timer_get_us() > tmo) {
78 printf("DDC: timeout reading EDID\n");
79 return -ETIME;
80 }
81 }
82 return 0;
83}
84
Hans de Goede7fad8a92014-12-28 09:13:21 +010085static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020086{
87 struct sunxi_ccm_reg * const ccm =
88 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
89 struct sunxi_hdmi_reg * const hdmi =
90 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede7fad8a92014-12-28 09:13:21 +010091 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020092
93 /* Set pll3 to 300MHz */
94 clock_set_pll3(300000000);
95
96 /* Set hdmi parent to pll3 */
97 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
98 CCM_HDMI_CTRL_PLL3);
99
100 /* Set ahb gating to pass */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200101#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100102 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
103#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200104 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
105
106 /* Clock on */
107 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
108
109 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
110 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
111
Hans de Goede40f1b872014-12-20 15:15:23 +0100112 while (timer_get_us() < tmo) {
113 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
114 return 1;
115 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200116
Hans de Goede40f1b872014-12-20 15:15:23 +0100117 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100118}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200119
Hans de Goede518cef22014-12-19 15:13:57 +0100120static void sunxi_hdmi_shutdown(void)
121{
122 struct sunxi_ccm_reg * const ccm =
123 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
124 struct sunxi_hdmi_reg * const hdmi =
125 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
126
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200127 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
128 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
129 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goede44d8ae52015-04-06 20:33:34 +0200130#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100131 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
132#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200133 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200134}
135
Hans de Goede75481602014-12-19 16:05:12 +0100136static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
137{
138 struct sunxi_hdmi_reg * const hdmi =
139 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
140
141 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
142 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
143 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
144 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
145 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
146#ifndef CONFIG_MACH_SUN6I
147 writel(n, &hdmi->ddc_byte_count);
148 writel(cmnd, &hdmi->ddc_cmnd);
149#else
150 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
151#endif
152 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
153
154 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
155}
156
157static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
158{
159 struct sunxi_hdmi_reg * const hdmi =
160 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
161 int i, n;
162
163 while (count > 0) {
164 if (count > 16)
165 n = 16;
166 else
167 n = count;
168
169 if (sunxi_hdmi_ddc_do_command(
170 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
171 offset, n))
172 return -ETIME;
173
174 for (i = 0; i < n; i++)
175 *buf++ = readb(&hdmi->ddc_fifo_data);
176
177 offset += n;
178 count -= n;
179 }
180
181 return 0;
182}
183
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100184static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
185{
186 int r, retries = 2;
187
188 do {
189 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
190 if (r)
191 continue;
192 r = edid_check_checksum(buf);
193 if (r) {
194 printf("EDID block %d: checksum error%s\n",
195 block, retries ? ", retrying" : "");
196 }
197 } while (r && retries--);
198
199 return r;
200}
201
Hans de Goede1c092202014-12-21 14:37:45 +0100202static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100203{
204 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100205 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-12-19 16:05:12 +0100206 struct edid_detailed_timing *t =
207 (struct edid_detailed_timing *)edid1.monitor_details.timing;
208 struct sunxi_hdmi_reg * const hdmi =
209 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
210 struct sunxi_ccm_reg * const ccm =
211 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedef3000682014-12-20 14:31:45 +0100212 int i, r, ext_blocks = 0;
Hans de Goede75481602014-12-19 16:05:12 +0100213
214 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
215 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
216 &hdmi->pad_ctrl1);
217 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
218 &hdmi->pll_ctrl);
219 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
220
221 /* Reset i2c controller */
222 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
223 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
224 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
225 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
226 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
227 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
228 return -EIO;
229
230 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
231#ifndef CONFIG_MACH_SUN6I
232 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
233 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
234#endif
235
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100236 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-12-20 14:31:45 +0100237 if (r == 0) {
238 r = edid_check_info(&edid1);
239 if (r) {
240 printf("EDID: invalid EDID data\n");
241 r = -EINVAL;
242 }
243 }
244 if (r == 0) {
245 ext_blocks = edid1.extension_flag;
246 if (ext_blocks > 4)
247 ext_blocks = 4;
248 for (i = 0; i < ext_blocks; i++) {
249 if (sunxi_hdmi_edid_get_block(1 + i,
250 (u8 *)&cea681[i]) != 0) {
251 ext_blocks = i;
252 break;
253 }
254 }
255 }
Hans de Goede75481602014-12-19 16:05:12 +0100256
257 /* Disable DDC engine, no longer needed */
258 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
259 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
260
261 if (r)
262 return r;
263
Hans de Goede75481602014-12-19 16:05:12 +0100264 /* We want version 1.3 or 1.2 with detailed timing info */
265 if (edid1.version != 1 || (edid1.revision < 3 &&
266 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
267 printf("EDID: unsupported version %d.%d\n",
268 edid1.version, edid1.revision);
269 return -EINVAL;
270 }
271
272 /* Take the first usable detailed timing */
273 for (i = 0; i < 4; i++, t++) {
274 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
275 if (r == 0)
276 break;
277 }
278 if (i == 4) {
279 printf("EDID: no usable detailed timing found\n");
280 return -ENOENT;
281 }
282
Hans de Goedef3000682014-12-20 14:31:45 +0100283 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100284 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-12-20 14:31:45 +0100285 for (i = 0; i < ext_blocks; i++) {
286 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
287 cea681[i].revision < 2)
288 continue;
289
290 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goede1c092202014-12-21 14:37:45 +0100291 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100292 }
293
Hans de Goede75481602014-12-19 16:05:12 +0100294 return 0;
295}
296
Hans de Goede2fbf0912014-12-23 23:04:35 +0100297#endif /* CONFIG_VIDEO_HDMI */
298
Hans de Goede7cd6f922015-01-19 08:44:07 +0100299#ifdef CONFIG_MACH_SUN4I
300/*
301 * Testing has shown that on sun4i the display backend engine does not have
302 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
303 * fifo underruns. So on sun4i we use the display frontend engine to do the
304 * dma from memory, as the frontend does have deep enough fifo-s.
305 */
306
307static const u32 sun4i_vert_coef[32] = {
308 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
309 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
310 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
311 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
312 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
313 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
314 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
315 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
316};
317
318static const u32 sun4i_horz_coef[64] = {
319 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
320 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
321 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
322 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
323 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
324 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
325 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
326 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
327 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
328 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
329 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
330 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
331 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
332 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
333 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
334 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
335};
336
337static void sunxi_frontend_init(void)
338{
339 struct sunxi_ccm_reg * const ccm =
340 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
341 struct sunxi_de_fe_reg * const de_fe =
342 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
343 int i;
344
345 /* Clocks on */
346 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
347 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
348 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
349
350 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
351
352 for (i = 0; i < 32; i++) {
353 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
354 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
355 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
356 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
357 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
358 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
359 }
360
361 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
362}
363
364static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
365 unsigned int address)
366{
367 struct sunxi_de_fe_reg * const de_fe =
368 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
369
370 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
371 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
372 writel(mode->xres * 4, &de_fe->ch0_stride);
373 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
374 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
375
376 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
377 &de_fe->ch0_insize);
378 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
379 &de_fe->ch0_outsize);
380 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
381 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
382
383 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
384 &de_fe->ch1_insize);
385 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
386 &de_fe->ch1_outsize);
387 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
388 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
389
390 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
391}
392
393static void sunxi_frontend_enable(void)
394{
395 struct sunxi_de_fe_reg * const de_fe =
396 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
397
398 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
399}
400#else
401static void sunxi_frontend_init(void) {}
402static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
403 unsigned int address) {}
404static void sunxi_frontend_enable(void) {}
405#endif
406
Hans de Goede39920c82015-08-03 19:20:26 +0200407static bool sunxi_is_composite(void)
408{
409 switch (sunxi_display.monitor) {
410 case sunxi_monitor_none:
411 case sunxi_monitor_dvi:
412 case sunxi_monitor_hdmi:
413 case sunxi_monitor_lcd:
414 case sunxi_monitor_vga:
415 return false;
416 case sunxi_monitor_composite_pal:
417 case sunxi_monitor_composite_ntsc:
418 case sunxi_monitor_composite_pal_m:
419 case sunxi_monitor_composite_pal_nc:
420 return true;
421 }
422
423 return false; /* Never reached */
424}
425
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200426/*
427 * This is the entity that mixes and matches the different layers and inputs.
428 * Allwinner calls it the back-end, but i like composer better.
429 */
430static void sunxi_composer_init(void)
431{
432 struct sunxi_ccm_reg * const ccm =
433 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
434 struct sunxi_de_be_reg * const de_be =
435 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
436 int i;
437
Hans de Goede7cd6f922015-01-19 08:44:07 +0100438 sunxi_frontend_init();
439
Hans de Goede44d8ae52015-04-06 20:33:34 +0200440#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100441 /* Reset off */
442 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
443#endif
444
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200445 /* Clocks on */
446 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100447#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200448 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100449#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200450 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
451
452 /* Engine bug, clear registers after reset */
453 for (i = 0x0800; i < 0x1000; i += 4)
454 writel(0, SUNXI_DE_BE0_BASE + i);
455
456 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
457}
458
Hans de Goede39920c82015-08-03 19:20:26 +0200459static u32 sunxi_rgb2yuv_coef[12] = {
460 0x00000107, 0x00000204, 0x00000064, 0x00000108,
461 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
462 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
463};
464
Hans de Goedebe8ec632014-12-19 13:46:33 +0100465static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200466 unsigned int address)
467{
468 struct sunxi_de_be_reg * const de_be =
469 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goede39920c82015-08-03 19:20:26 +0200470 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200471
Hans de Goede7cd6f922015-01-19 08:44:07 +0100472 sunxi_frontend_mode_set(mode, address);
473
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200474 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
475 &de_be->disp_size);
476 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
477 &de_be->layer0_size);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100478#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200479 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
480 writel(address << 3, &de_be->layer0_addr_low32b);
481 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100482#else
483 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
484#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200485 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
486
487 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200488 if (mode->vmode == FB_VMODE_INTERLACED)
489 setbits_le32(&de_be->mode,
Hans de Goeded8d07992015-08-06 12:08:33 +0200490#ifndef CONFIG_MACH_SUN5I
Hans de Goedef6d9d322015-08-02 16:49:29 +0200491 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goeded8d07992015-08-06 12:08:33 +0200492#endif
Hans de Goedef6d9d322015-08-02 16:49:29 +0200493 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goede39920c82015-08-03 19:20:26 +0200494
495 if (sunxi_is_composite()) {
496 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
497 &de_be->output_color_ctrl);
498 for (i = 0; i < 12; i++)
499 writel(sunxi_rgb2yuv_coef[i],
500 &de_be->output_color_coef[i]);
501 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200502}
503
Hans de Goede0e045212014-12-21 14:49:34 +0100504static void sunxi_composer_enable(void)
505{
506 struct sunxi_de_be_reg * const de_be =
507 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
508
Hans de Goede7cd6f922015-01-19 08:44:07 +0100509 sunxi_frontend_enable();
510
Hans de Goede0e045212014-12-21 14:49:34 +0100511 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
512 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
513}
514
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200515/*
516 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
517 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100518static void sunxi_lcdc_pll_set(int tcon, int dotclock,
519 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200520{
521 struct sunxi_ccm_reg * const ccm =
522 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100523 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200524 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
525 int best_double = 0;
Hans de Goedefb685d32015-08-08 14:08:21 +0200526 bool use_mipi_pll = false;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200527
Hans de Goede5489ebc2014-12-21 16:27:45 +0100528 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100529#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100530 min_m = 6;
531 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100532#endif
533#ifdef CONFIG_VIDEO_LCD_IF_LVDS
534 min_m = max_m = 7;
535#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100536 } else {
537 min_m = 1;
538 max_m = 15;
539 }
540
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200541 /*
542 * Find the lowest divider resulting in a matching clock, if there
543 * is no match, pick the closest lower clock, as monitors tend to
544 * not sync to higher frequencies.
545 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100546 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200547 n = (m * dotclock) / 3000;
548
549 if ((n >= 9) && (n <= 127)) {
550 value = (3000 * n) / m;
551 diff = dotclock - value;
552 if (diff < best_diff) {
553 best_diff = diff;
554 best_m = m;
555 best_n = n;
556 best_double = 0;
557 }
558 }
559
560 /* These are just duplicates */
561 if (!(m & 1))
562 continue;
563
564 n = (m * dotclock) / 6000;
565 if ((n >= 9) && (n <= 127)) {
566 value = (6000 * n) / m;
567 diff = dotclock - value;
568 if (diff < best_diff) {
569 best_diff = diff;
570 best_m = m;
571 best_n = n;
572 best_double = 1;
573 }
574 }
575 }
576
Hans de Goedefb685d32015-08-08 14:08:21 +0200577#ifdef CONFIG_MACH_SUN6I
578 /*
579 * Use the MIPI pll if we've been unable to find any matching setting
580 * for PLL3, this happens with high dotclocks because of min_m = 6.
581 */
582 if (tcon == 0 && best_n == 0) {
583 use_mipi_pll = true;
584 best_m = 6; /* Minimum m for tcon0 */
585 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200586
Hans de Goedefb685d32015-08-08 14:08:21 +0200587 if (use_mipi_pll) {
588 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
589 clock_set_mipi_pll(best_m * dotclock * 1000);
590 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
591 dotclock, clock_get_mipi_pll() / best_m / 1000);
592 } else
593#endif
594 {
595 clock_set_pll3(best_n * 3000000);
596 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
597 dotclock,
598 (best_double + 1) * clock_get_pll3() / best_m / 1000,
599 best_double + 1, best_n, best_m);
600 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200601
Hans de Goede5489ebc2014-12-21 16:27:45 +0100602 if (tcon == 0) {
Hans de Goedefb685d32015-08-08 14:08:21 +0200603 u32 pll;
604
605 if (use_mipi_pll)
606 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
607 else if (best_double)
608 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
609 else
610 pll = CCM_LCD_CH0_CTRL_PLL3;
611
612 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
Hans de Goede5489ebc2014-12-21 16:27:45 +0100613 &ccm->lcd0_ch0_clk_cfg);
614 } else {
615 writel(CCM_LCD_CH1_CTRL_GATE |
616 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
617 CCM_LCD_CH1_CTRL_PLL3) |
618 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goede39920c82015-08-03 19:20:26 +0200619 if (sunxi_is_composite())
620 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
621 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goede5489ebc2014-12-21 16:27:45 +0100622 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200623
624 *clk_div = best_m;
625 *clk_double = best_double;
626}
627
628static void sunxi_lcdc_init(void)
629{
630 struct sunxi_ccm_reg * const ccm =
631 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
632 struct sunxi_lcdc_reg * const lcdc =
633 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
634
635 /* Reset off */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200636#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100637 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
638#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200639 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100640#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200641
642 /* Clock on */
643 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100644#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede83edb2a2015-05-14 18:52:54 +0200645#ifdef CONFIG_SUNXI_GEN_SUN6I
646 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
647#else
Hans de Goede213480e2015-01-01 22:04:34 +0100648 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
649#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200650#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200651
652 /* Init lcdc */
653 writel(0, &lcdc->ctrl); /* Disable tcon */
654 writel(0, &lcdc->int0); /* Disable all interrupts */
655
656 /* Disable tcon0 dot clock */
657 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
658
659 /* Set all io lines to tristate */
660 writel(0xffffffff, &lcdc->tcon0_io_tristate);
661 writel(0xffffffff, &lcdc->tcon1_io_tristate);
662}
663
Hans de Goede0e045212014-12-21 14:49:34 +0100664static void sunxi_lcdc_enable(void)
665{
666 struct sunxi_lcdc_reg * const lcdc =
667 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
668
669 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede213480e2015-01-01 22:04:34 +0100670#ifdef CONFIG_VIDEO_LCD_IF_LVDS
671 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
672 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede83edb2a2015-05-14 18:52:54 +0200673#ifdef CONFIG_SUNXI_GEN_SUN6I
674 udelay(2); /* delay at least 1200 ns */
675 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
676 udelay(2); /* delay at least 1200 ns */
677 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
678 if (sunxi_display.depth == 18)
679 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
680 else
681 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
682#else
Hans de Goede213480e2015-01-01 22:04:34 +0100683 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
684 udelay(2); /* delay at least 1200 ns */
685 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
686 udelay(1); /* delay at least 120 ns */
687 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
688 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
689#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200690#endif
Hans de Goede0e045212014-12-21 14:49:34 +0100691}
692
Hans de Goede2dae8002014-12-21 16:28:32 +0100693static void sunxi_lcdc_panel_enable(void)
694{
Hans de Goede242e3d82015-02-16 17:26:41 +0100695 int pin, reset_pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100696
697 /*
698 * Start with backlight disabled to avoid the screen flashing to
699 * white while the lcd inits.
700 */
701 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200702 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100703 gpio_request(pin, "lcd_backlight_enable");
704 gpio_direction_output(pin, 0);
705 }
706
707 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200708 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100709 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goedea7403ae2015-01-22 21:02:42 +0100710 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-12-21 16:28:32 +0100711 }
712
Hans de Goede242e3d82015-02-16 17:26:41 +0100713 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede15728192015-04-22 17:45:59 +0200714 if (reset_pin >= 0) {
Hans de Goede242e3d82015-02-16 17:26:41 +0100715 gpio_request(reset_pin, "lcd_reset");
716 gpio_direction_output(reset_pin, 0); /* Assert reset */
717 }
718
Hans de Goede2dae8002014-12-21 16:28:32 +0100719 /* Give the backlight some time to turn off and power up the panel. */
720 mdelay(40);
721 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede15728192015-04-22 17:45:59 +0200722 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100723 gpio_request(pin, "lcd_power");
724 gpio_direction_output(pin, 1);
725 }
Hans de Goede242e3d82015-02-16 17:26:41 +0100726
Hans de Goede15728192015-04-22 17:45:59 +0200727 if (reset_pin >= 0)
Hans de Goede242e3d82015-02-16 17:26:41 +0100728 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede2dae8002014-12-21 16:28:32 +0100729}
730
731static void sunxi_lcdc_backlight_enable(void)
732{
733 int pin;
734
735 /*
736 * We want to have scanned out at least one frame before enabling the
737 * backlight to avoid the screen flashing to white when we enable it.
738 */
739 mdelay(40);
740
741 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200742 if (pin >= 0)
Hans de Goede2dae8002014-12-21 16:28:32 +0100743 gpio_direction_output(pin, 1);
744
745 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200746 if (pin >= 0)
Hans de Goedea7403ae2015-01-22 21:02:42 +0100747 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-12-21 16:28:32 +0100748}
749
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200750static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede2dae8002014-12-21 16:28:32 +0100751{
752 int delay;
753
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200754 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200755 if (mode->vmode == FB_VMODE_INTERLACED)
756 delay /= 2;
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200757 if (tcon == 1)
758 delay -= 2;
759
Hans de Goede2dae8002014-12-21 16:28:32 +0100760 return (delay > 30) ? 30 : delay;
761}
762
Hans de Goedefb75d972015-01-25 15:33:07 +0100763static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
764 bool for_ext_vga_dac)
Hans de Goede2dae8002014-12-21 16:28:32 +0100765{
766 struct sunxi_lcdc_reg * const lcdc =
767 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
768 int bp, clk_delay, clk_div, clk_double, pin, total, val;
769
Lawrence Yucf6eca72016-03-04 09:08:56 -0800770#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
771 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
772#else
Hans de Goedec1cfd512015-08-08 16:13:53 +0200773 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yucf6eca72016-03-04 09:08:56 -0800774#endif
Hans de Goede213480e2015-01-01 22:04:34 +0100775#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100776 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100777#endif
778#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100779 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede213480e2015-01-01 22:04:34 +0100780#endif
Hans de Goedec1cfd512015-08-08 16:13:53 +0200781#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
782 sunxi_gpio_set_drv(pin, 3);
783#endif
784 }
Hans de Goede2dae8002014-12-21 16:28:32 +0100785
786 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
787
788 /* Use tcon0 */
789 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
790 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
791
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200792 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede2dae8002014-12-21 16:28:32 +0100793 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
794 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
795
796 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
797 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
798
799 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
800 &lcdc->tcon0_timing_active);
801
802 bp = mode->hsync_len + mode->left_margin;
803 total = mode->xres + mode->right_margin + bp;
804 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
805 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
806
807 bp = mode->vsync_len + mode->upper_margin;
808 total = mode->yres + mode->lower_margin + bp;
809 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
810 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
811
Hans de Goede213480e2015-01-01 22:04:34 +0100812#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100813 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
814 &lcdc->tcon0_timing_sync);
815
Hans de Goede2dae8002014-12-21 16:28:32 +0100816 writel(0, &lcdc->tcon0_hv_intf);
817 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100818#endif
819#ifdef CONFIG_VIDEO_LCD_IF_LVDS
820 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede83edb2a2015-05-14 18:52:54 +0200821 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
822 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100823#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100824
825 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
826 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
827 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
828 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
829 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
830 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
831 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
832 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
833 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
834 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
835 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
836 writel(((sunxi_display.depth == 18) ?
837 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
838 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
839 &lcdc->tcon0_frm_ctrl);
840 }
841
Hans de Goede65150322015-01-13 13:21:46 +0100842 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100843 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
844 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
845 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
846 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goedefb75d972015-01-25 15:33:07 +0100847
848#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
849 if (for_ext_vga_dac)
850 val = 0;
851#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100852 writel(val, &lcdc->tcon0_io_polarity);
853
854 writel(0, &lcdc->tcon0_io_tristate);
855}
856
Hans de Goede39920c82015-08-03 19:20:26 +0200857#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede0e045212014-12-21 14:49:34 +0100858static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100859 int *clk_div, int *clk_double,
860 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200861{
862 struct sunxi_lcdc_reg * const lcdc =
863 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200864 int bp, clk_delay, total, val, yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200865
866 /* Use tcon1 */
867 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
868 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
869
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200870 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200871 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedef6d9d322015-08-02 16:49:29 +0200872 ((mode->vmode == FB_VMODE_INTERLACED) ?
873 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
Hans de Goede6741cc72014-12-24 19:50:11 +0100874 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200875
Hans de Goedef6d9d322015-08-02 16:49:29 +0200876 yres = mode->yres;
877 if (mode->vmode == FB_VMODE_INTERLACED)
878 yres /= 2;
879 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200880 &lcdc->tcon1_timing_source);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200881 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200882 &lcdc->tcon1_timing_scale);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200883 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200884 &lcdc->tcon1_timing_out);
885
886 bp = mode->hsync_len + mode->left_margin;
887 total = mode->xres + mode->right_margin + bp;
888 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
889 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
890
891 bp = mode->vsync_len + mode->upper_margin;
892 total = mode->yres + mode->lower_margin + bp;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200893 if (mode->vmode == FB_VMODE_NONINTERLACED)
894 total *= 2;
895 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200896 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
897
898 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
899 &lcdc->tcon1_timing_sync);
900
Hans de Goede3ffbe472014-12-27 15:19:23 +0100901 if (use_portd_hvsync) {
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100902 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
903 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goede3ffbe472014-12-27 15:19:23 +0100904
905 val = 0;
906 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
907 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
908 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
909 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
910 writel(val, &lcdc->tcon1_io_polarity);
911
912 clrbits_le32(&lcdc->tcon1_io_tristate,
913 SUNXI_LCDC_TCON_VSYNC_MASK |
914 SUNXI_LCDC_TCON_HSYNC_MASK);
915 }
Hans de Goeded8d07992015-08-06 12:08:33 +0200916
917#ifdef CONFIG_MACH_SUN5I
918 if (sunxi_is_composite())
919 clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK,
920 SUNXI_LCDC_MUX_CTRL_SRC0(1));
921#endif
922
Hans de Goede5489ebc2014-12-21 16:27:45 +0100923 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200924}
Hans de Goede39920c82015-08-03 19:20:26 +0200925#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +0100926
927#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200928
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100929static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
930{
931 struct sunxi_hdmi_reg * const hdmi =
932 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
933 u8 checksum = 0;
934 u8 avi_info_frame[17] = {
935 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
936 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
937 0x00
938 };
939 u8 vendor_info_frame[19] = {
940 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
941 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
942 0x00, 0x00, 0x00
943 };
944 int i;
945
946 if (mode->pixclock_khz <= 27000)
947 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
948 else
949 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
950
951 if (mode->xres * 100 / mode->yres < 156)
952 avi_info_frame[5] |= 0x18; /* 4 : 3 */
953 else
954 avi_info_frame[5] |= 0x28; /* 16 : 9 */
955
956 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
957 checksum += avi_info_frame[i];
958
959 avi_info_frame[3] = 0x100 - checksum;
960
961 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
962 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
963
964 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
965 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
966
967 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
968 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
969
970 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
971 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
972
973 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
974}
975
Hans de Goedebe8ec632014-12-19 13:46:33 +0100976static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100977 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200978{
979 struct sunxi_hdmi_reg * const hdmi =
980 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
981 int x, y;
982
983 /* Write clear interrupt status bits */
984 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
985
Hans de Goede1c092202014-12-21 14:37:45 +0100986 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100987 sunxi_hdmi_setup_info_frames(mode);
988
Hans de Goede876aaaf2014-12-20 13:51:16 +0100989 /* Set input sync enable */
990 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
991
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200992 /* Init various registers, select pll3 as clock source */
993 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
994 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
995 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
996 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
997 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
998
999 /* Setup clk div and doubler */
1000 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
1001 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
1002 if (!clk_double)
1003 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
1004
1005 /* Setup timing registers */
1006 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
1007 &hdmi->video_size);
1008
1009 x = mode->hsync_len + mode->left_margin;
1010 y = mode->vsync_len + mode->upper_margin;
1011 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
1012
1013 x = mode->right_margin;
1014 y = mode->lower_margin;
1015 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
1016
1017 x = mode->hsync_len;
1018 y = mode->vsync_len;
1019 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
1020
1021 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
1022 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
1023
1024 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
1025 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
1026}
1027
Hans de Goede0e045212014-12-21 14:49:34 +01001028static void sunxi_hdmi_enable(void)
1029{
1030 struct sunxi_hdmi_reg * const hdmi =
1031 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
1032
1033 udelay(100);
1034 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
1035}
1036
Hans de Goede2fbf0912014-12-23 23:04:35 +01001037#endif /* CONFIG_VIDEO_HDMI */
1038
Hans de Goede39920c82015-08-03 19:20:26 +02001039#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goeded9786d22014-12-25 13:58:06 +01001040
Hans de Goede39920c82015-08-03 19:20:26 +02001041static void sunxi_tvencoder_mode_set(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001042{
1043 struct sunxi_ccm_reg * const ccm =
1044 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1045 struct sunxi_tve_reg * const tve =
1046 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1047
Hans de Goeded8d07992015-08-06 12:08:33 +02001048 /* Reset off */
1049 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goeded9786d22014-12-25 13:58:06 +01001050 /* Clock on */
1051 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1052
Hans de Goede39920c82015-08-03 19:20:26 +02001053 switch (sunxi_display.monitor) {
1054 case sunxi_monitor_vga:
1055 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1056 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1057 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
1058 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1059 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1060 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1061 break;
1062 case sunxi_monitor_composite_pal_nc:
1063 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1064 /* Fall through */
1065 case sunxi_monitor_composite_pal:
1066 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1067 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1068 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1069 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1070 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1071 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1072 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1073 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1074 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1075 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1076 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1077 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1078 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1079 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1080 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1081 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1082 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1083 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1084 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1085 break;
1086 case sunxi_monitor_composite_pal_m:
1087 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1088 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1089 /* Fall through */
1090 case sunxi_monitor_composite_ntsc:
1091 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1092 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1093 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1094 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1095 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1096 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1097 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1098 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1099 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1100 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1101 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1102 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1103 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1104 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1105 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1106 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1107 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1108 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1109 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1110 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1111 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1112 break;
1113 case sunxi_monitor_none:
1114 case sunxi_monitor_dvi:
1115 case sunxi_monitor_hdmi:
1116 case sunxi_monitor_lcd:
1117 break;
1118 }
Hans de Goeded9786d22014-12-25 13:58:06 +01001119}
1120
Hans de Goede39920c82015-08-03 19:20:26 +02001121static void sunxi_tvencoder_enable(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001122{
1123 struct sunxi_tve_reg * const tve =
1124 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1125
1126 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1127}
1128
Hans de Goede39920c82015-08-03 19:20:26 +02001129#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +01001130
Hans de Goedee8400792014-12-23 18:39:52 +01001131static void sunxi_drc_init(void)
1132{
Hans de Goede44d8ae52015-04-06 20:33:34 +02001133#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedee8400792014-12-23 18:39:52 +01001134 struct sunxi_ccm_reg * const ccm =
1135 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1136
1137 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar8c3dacf2015-03-01 23:47:48 +05301138#ifdef CONFIG_MACH_SUN8I_A33
1139 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1140#endif
Hans de Goedee8400792014-12-23 18:39:52 +01001141 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1142 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1143#endif
1144}
1145
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001146#ifdef CONFIG_VIDEO_VGA_VIA_LCD
1147static void sunxi_vga_external_dac_enable(void)
1148{
1149 int pin;
1150
1151 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede15728192015-04-22 17:45:59 +02001152 if (pin >= 0) {
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001153 gpio_request(pin, "vga_enable");
1154 gpio_direction_output(pin, 1);
1155 }
1156}
1157#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1158
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001159#ifdef CONFIG_VIDEO_LCD_SSD2828
1160static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1161{
1162 struct ssd2828_config cfg = {
1163 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1164 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1165 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1166 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1167 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1168 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1169 .ssd2828_color_depth = 24,
1170#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1171 .mipi_dsi_number_of_data_lanes = 4,
1172 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1173 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1174 .mipi_dsi_delay_after_set_display_on_ms = 200
1175#else
1176#error MIPI LCD panel needs configuration parameters
1177#endif
1178 };
1179
1180 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1181 printf("SSD2828: SPI pins are not properly configured\n");
1182 return 1;
1183 }
1184 if (cfg.reset_pin == -1) {
1185 printf("SSD2828: Reset pin is not properly configured\n");
1186 return 1;
1187 }
1188
1189 return ssd2828_init(&cfg, mode);
1190}
1191#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1192
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001193static void sunxi_engines_init(void)
1194{
1195 sunxi_composer_init();
1196 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +01001197 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001198}
1199
Hans de Goede1c092202014-12-21 14:37:45 +01001200static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +01001201 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001202{
Hans de Goeded9786d22014-12-25 13:58:06 +01001203 int __maybe_unused clk_div, clk_double;
1204
Hans de Goede0e045212014-12-21 14:49:34 +01001205 switch (sunxi_display.monitor) {
1206 case sunxi_monitor_none:
1207 break;
1208 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001209 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001210#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001211 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001212 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001213 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1214 sunxi_composer_enable();
1215 sunxi_lcdc_enable();
1216 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001217#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001218 break;
1219 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001220 sunxi_lcdc_panel_enable();
Hans de Goedec1cfd512015-08-08 16:13:53 +02001221 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1222 /*
1223 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goede6944aff2015-10-03 15:18:33 +02001224 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goedec1cfd512015-08-08 16:13:53 +02001225 * to avoid turning this on when using hdmi output.
1226 */
Hans de Goede6944aff2015-10-03 15:18:33 +02001227 axp_set_eldo(3, 1800);
Hans de Goedec1cfd512015-08-08 16:13:53 +02001228 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1229 ANX9804_DATA_RATE_1620M,
1230 sunxi_display.depth);
1231 }
Hans de Goede27515b22015-01-20 09:23:36 +01001232 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1233 mdelay(50); /* Wait for lcd controller power on */
1234 hitachi_tx18d42vm_init();
1235 }
Hans de Goedeaad2ac22015-02-16 17:49:47 +01001236 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1237 unsigned int orig_i2c_bus = i2c_get_bus_num();
1238 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1239 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1240 i2c_set_bus_num(orig_i2c_bus);
1241 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001242 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001243 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede2dae8002014-12-21 16:28:32 +01001244 sunxi_composer_enable();
1245 sunxi_lcdc_enable();
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001246#ifdef CONFIG_VIDEO_LCD_SSD2828
1247 sunxi_ssd2828_init(mode);
1248#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001249 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001250 break;
1251 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001252#ifdef CONFIG_VIDEO_VGA
1253 sunxi_composer_mode_set(mode, address);
1254 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goede39920c82015-08-03 19:20:26 +02001255 sunxi_tvencoder_mode_set();
Hans de Goeded9786d22014-12-25 13:58:06 +01001256 sunxi_composer_enable();
1257 sunxi_lcdc_enable();
Hans de Goede39920c82015-08-03 19:20:26 +02001258 sunxi_tvencoder_enable();
Hans de Goeded9786d22014-12-25 13:58:06 +01001259#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001260 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001261 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001262 sunxi_composer_enable();
1263 sunxi_lcdc_enable();
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001264 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001265#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001266 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001267 case sunxi_monitor_composite_pal:
1268 case sunxi_monitor_composite_ntsc:
1269 case sunxi_monitor_composite_pal_m:
1270 case sunxi_monitor_composite_pal_nc:
1271#ifdef CONFIG_VIDEO_COMPOSITE
1272 sunxi_composer_mode_set(mode, address);
1273 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1274 sunxi_tvencoder_mode_set();
1275 sunxi_composer_enable();
1276 sunxi_lcdc_enable();
1277 sunxi_tvencoder_enable();
1278#endif
1279 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001280 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001281}
1282
Hans de Goede1c092202014-12-21 14:37:45 +01001283static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1284{
1285 switch (monitor) {
Hans de Goede39920c82015-08-03 19:20:26 +02001286 case sunxi_monitor_none: return "none";
1287 case sunxi_monitor_dvi: return "dvi";
1288 case sunxi_monitor_hdmi: return "hdmi";
1289 case sunxi_monitor_lcd: return "lcd";
1290 case sunxi_monitor_vga: return "vga";
1291 case sunxi_monitor_composite_pal: return "composite-pal";
1292 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1293 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1294 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goede1c092202014-12-21 14:37:45 +01001295 }
1296 return NULL; /* never reached */
1297}
1298
Hans de Goede5633a292015-02-02 17:13:29 +01001299ulong board_get_usable_ram_top(ulong total_size)
1300{
1301 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1302}
1303
Hans de Goedebf689342015-08-03 23:01:38 +02001304static bool sunxi_has_hdmi(void)
1305{
1306#ifdef CONFIG_VIDEO_HDMI
1307 return true;
1308#else
1309 return false;
1310#endif
1311}
1312
1313static bool sunxi_has_lcd(void)
1314{
1315 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1316
1317 return lcd_mode[0] != 0;
1318}
1319
1320static bool sunxi_has_vga(void)
1321{
1322#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1323 return true;
1324#else
1325 return false;
1326#endif
1327}
1328
Hans de Goede39920c82015-08-03 19:20:26 +02001329static bool sunxi_has_composite(void)
1330{
1331#ifdef CONFIG_VIDEO_COMPOSITE
1332 return true;
1333#else
1334 return false;
1335#endif
1336}
1337
Hans de Goedebf689342015-08-03 23:01:38 +02001338static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1339{
1340 if (allow_hdmi && sunxi_has_hdmi())
1341 return sunxi_monitor_dvi;
1342 else if (sunxi_has_lcd())
1343 return sunxi_monitor_lcd;
1344 else if (sunxi_has_vga())
1345 return sunxi_monitor_vga;
Hans de Goede39920c82015-08-03 19:20:26 +02001346 else if (sunxi_has_composite())
1347 return sunxi_monitor_composite_pal;
Hans de Goedebf689342015-08-03 23:01:38 +02001348 else
1349 return sunxi_monitor_none;
1350}
1351
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001352void *video_hw_init(void)
1353{
1354 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001355 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001356 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001357 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001358#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001359 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001360#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001361 int i, overscan_offset, overscan_x, overscan_y;
1362 unsigned int fb_dma_addr;
Hans de Goede1c092202014-12-21 14:37:45 +01001363 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001364 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001365
1366 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1367
Hans de Goede2dae8002014-12-21 16:28:32 +01001368 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1369 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001370#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001371 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001372 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001373 edid = video_get_option_int(options, "edid", 1);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001374#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001375 overscan_x = video_get_option_int(options, "overscan_x", -1);
1376 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedebf689342015-08-03 23:01:38 +02001377 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goede1c092202014-12-21 14:37:45 +01001378 video_get_option_string(options, "monitor", mon, sizeof(mon),
1379 sunxi_get_mon_desc(sunxi_display.monitor));
1380 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1381 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1382 sunxi_display.monitor = i;
1383 break;
1384 }
1385 }
1386 if (i > SUNXI_MONITOR_LAST)
1387 printf("Unknown monitor: '%s', falling back to '%s'\n",
1388 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001389
Hans de Goede49d27032014-12-25 13:52:04 +01001390#ifdef CONFIG_VIDEO_HDMI
1391 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1392 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1393 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001394 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001395 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001396 if (ret) {
1397 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001398 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1399 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001400 } else if (hpd) {
1401 sunxi_hdmi_shutdown();
Hans de Goedebf689342015-08-03 23:01:38 +02001402 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede49d27032014-12-25 13:52:04 +01001403 } /* else continue with hdmi/dvi without a cable connected */
1404 }
1405#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001406
Hans de Goede49d27032014-12-25 13:52:04 +01001407 switch (sunxi_display.monitor) {
1408 case sunxi_monitor_none:
1409 return NULL;
1410 case sunxi_monitor_dvi:
1411 case sunxi_monitor_hdmi:
Hans de Goedebf689342015-08-03 23:01:38 +02001412 if (!sunxi_has_hdmi()) {
1413 printf("HDMI/DVI not supported on this board\n");
1414 sunxi_display.monitor = sunxi_monitor_none;
1415 return NULL;
Hans de Goede2dae8002014-12-21 16:28:32 +01001416 }
Hans de Goedebf689342015-08-03 23:01:38 +02001417 break;
1418 case sunxi_monitor_lcd:
1419 if (!sunxi_has_lcd()) {
1420 printf("LCD not supported on this board\n");
1421 sunxi_display.monitor = sunxi_monitor_none;
1422 return NULL;
1423 }
1424 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1425 mode = &custom;
1426 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001427 case sunxi_monitor_vga:
Hans de Goedebf689342015-08-03 23:01:38 +02001428 if (!sunxi_has_vga()) {
1429 printf("VGA not supported on this board\n");
1430 sunxi_display.monitor = sunxi_monitor_none;
1431 return NULL;
1432 }
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001433 sunxi_display.depth = 18;
1434 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001435 case sunxi_monitor_composite_pal:
1436 case sunxi_monitor_composite_ntsc:
1437 case sunxi_monitor_composite_pal_m:
1438 case sunxi_monitor_composite_pal_nc:
1439 if (!sunxi_has_composite()) {
1440 printf("Composite video not supported on this board\n");
1441 sunxi_display.monitor = sunxi_monitor_none;
1442 return NULL;
1443 }
1444 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1445 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1446 mode = &composite_video_modes[0];
1447 else
1448 mode = &composite_video_modes[1];
1449 sunxi_display.depth = 24;
1450 break;
Hans de Goede75481602014-12-19 16:05:12 +01001451 }
1452
Hans de Goede58332f82015-08-05 00:06:47 +02001453 /* Yes these defaults are quite high, overscan on composite sucks... */
1454 if (overscan_x == -1)
1455 overscan_x = sunxi_is_composite() ? 32 : 0;
1456 if (overscan_y == -1)
1457 overscan_y = sunxi_is_composite() ? 20 : 0;
1458
Hans de Goede20779ec2015-02-02 18:00:53 +01001459 sunxi_display.fb_size =
1460 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goede58332f82015-08-05 00:06:47 +02001461 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1462 /* We want to keep the fb_base for simplefb page aligned, where as
1463 * the sunxi dma engines will happily accept an unaligned address. */
1464 if (overscan_offset)
1465 sunxi_display.fb_size += 0x1000;
1466
Hans de Goede20779ec2015-02-02 18:00:53 +01001467 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1468 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1469 sunxi_display.fb_size >> 10,
1470 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1471 return NULL;
1472 }
1473
Hans de Goede58332f82015-08-05 00:06:47 +02001474 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1475 mode->xres, mode->yres,
Hans de Goedef6d9d322015-08-02 16:49:29 +02001476 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goede58332f82015-08-05 00:06:47 +02001477 sunxi_get_mon_desc(sunxi_display.monitor),
1478 overscan_x, overscan_y);
Hans de Goedef6d9d322015-08-02 16:49:29 +02001479
Hans de Goede20779ec2015-02-02 18:00:53 +01001480 gd->fb_base = gd->bd->bi_dram[0].start +
1481 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001482 sunxi_engines_init();
Hans de Goede58332f82015-08-05 00:06:47 +02001483
1484 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1485 sunxi_display.fb_addr = gd->fb_base;
1486 if (overscan_offset) {
1487 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1488 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1489 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1490 flush_cache(gd->fb_base, sunxi_display.fb_size);
1491 }
1492 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001493
1494 /*
1495 * These are the only members of this structure that are used. All the
Hans de Goede58332f82015-08-05 00:06:47 +02001496 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001497 */
Hans de Goede58332f82015-08-05 00:06:47 +02001498 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001499 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1500 graphic_device->gdfBytesPP = 4;
Hans de Goede58332f82015-08-05 00:06:47 +02001501 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1502 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1503 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001504
1505 return graphic_device;
1506}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001507
1508/*
1509 * Simplefb support.
1510 */
1511#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1512int sunxi_simplefb_setup(void *blob)
1513{
1514 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1515 int offset, ret;
Hans de Goede5633a292015-02-02 17:13:29 +01001516 u64 start, size;
Hans de Goede2dae8002014-12-21 16:28:32 +01001517 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001518
Hans de Goede7cd6f922015-01-19 08:44:07 +01001519#ifdef CONFIG_MACH_SUN4I
1520#define PIPELINE_PREFIX "de_fe0-"
1521#else
1522#define PIPELINE_PREFIX
1523#endif
1524
Hans de Goede2dae8002014-12-21 16:28:32 +01001525 switch (sunxi_display.monitor) {
1526 case sunxi_monitor_none:
1527 return 0;
1528 case sunxi_monitor_dvi:
1529 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001530 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001531 break;
1532 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001533 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001534 break;
1535 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001536#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001537 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001538#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001539 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001540#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001541 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001542 case sunxi_monitor_composite_pal:
1543 case sunxi_monitor_composite_ntsc:
1544 case sunxi_monitor_composite_pal_m:
1545 case sunxi_monitor_composite_pal_nc:
1546 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1547 break;
Hans de Goede2dae8002014-12-21 16:28:32 +01001548 }
1549
1550 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001551 offset = fdt_node_offset_by_compatible(blob, -1,
1552 "allwinner,simple-framebuffer");
1553 while (offset >= 0) {
1554 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede2dae8002014-12-21 16:28:32 +01001555 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001556 if (ret == 0)
1557 break;
1558 offset = fdt_node_offset_by_compatible(blob, offset,
1559 "allwinner,simple-framebuffer");
1560 }
1561 if (offset < 0) {
1562 eprintf("Cannot setup simplefb: node not found\n");
1563 return 0; /* Keep older kernels working */
1564 }
1565
Hans de Goede5633a292015-02-02 17:13:29 +01001566 /*
1567 * Do not report the framebuffer as free RAM to the OS, note we cannot
1568 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1569 * and e.g. Linux refuses to iomap RAM on ARM, see:
1570 * linux/arch/arm/mm/ioremap.c around line 301.
1571 */
1572 start = gd->bd->bi_dram[0].start;
Hans de Goede20779ec2015-02-02 18:00:53 +01001573 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede5633a292015-02-02 17:13:29 +01001574 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1575 if (ret) {
1576 eprintf("Cannot setup simplefb: Error reserving memory\n");
1577 return ret;
1578 }
1579
Hans de Goede58332f82015-08-05 00:06:47 +02001580 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001581 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goede58332f82015-08-05 00:06:47 +02001582 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001583 if (ret)
1584 eprintf("Cannot setup simplefb: Error setting properties\n");
1585
1586 return ret;
1587}
1588#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */