blob: 50b16a9129f8e10aa19bc9507ce2ed33d2e41444 [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>
Hans de Goede421c98d2016-08-19 15:25:41 +020015#include <asm/arch/pwm.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020016#include <asm/global_data.h>
Hans de Goede2dae8002014-12-21 16:28:32 +010017#include <asm/gpio.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020018#include <asm/io.h>
Hans de Goede6944aff2015-10-03 15:18:33 +020019#include <axp_pmic.h>
Hans de Goede75481602014-12-19 16:05:12 +010020#include <errno.h>
Luc Verhaegen2d7a0842014-08-13 07:55:07 +020021#include <fdtdec.h>
22#include <fdt_support.h>
Hans de Goedeaad2ac22015-02-16 17:49:47 +010023#include <i2c.h>
Hans de Goede58332f82015-08-05 00:06:47 +020024#include <malloc.h>
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020025#include <video_fb.h>
Hans de Goedebe8ec632014-12-19 13:46:33 +010026#include "videomodes.h"
Hans de Goedec1cfd512015-08-08 16:13:53 +020027#include "anx9804.h"
Hans de Goede27515b22015-01-20 09:23:36 +010028#include "hitachi_tx18d42vm_lcd.h"
Siarhei Siamashka97ece832015-01-19 05:23:33 +020029#include "ssd2828.h"
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020030
Hans de Goedea7403ae2015-01-22 21:02:42 +010031#ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW
32#define PWM_ON 0
33#define PWM_OFF 1
34#else
35#define PWM_ON 1
36#define PWM_OFF 0
37#endif
38
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020039DECLARE_GLOBAL_DATA_PTR;
40
Hans de Goede1c092202014-12-21 14:37:45 +010041enum sunxi_monitor {
42 sunxi_monitor_none,
43 sunxi_monitor_dvi,
44 sunxi_monitor_hdmi,
45 sunxi_monitor_lcd,
46 sunxi_monitor_vga,
Hans de Goede39920c82015-08-03 19:20:26 +020047 sunxi_monitor_composite_pal,
48 sunxi_monitor_composite_ntsc,
49 sunxi_monitor_composite_pal_m,
50 sunxi_monitor_composite_pal_nc,
Hans de Goede1c092202014-12-21 14:37:45 +010051};
Hans de Goede39920c82015-08-03 19:20:26 +020052#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
Hans de Goede1c092202014-12-21 14:37:45 +010053
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020054struct sunxi_display {
55 GraphicDevice graphic_device;
Hans de Goede1c092202014-12-21 14:37:45 +010056 enum sunxi_monitor monitor;
Hans de Goede2dae8002014-12-21 16:28:32 +010057 unsigned int depth;
Hans de Goede58332f82015-08-05 00:06:47 +020058 unsigned int fb_addr;
Hans de Goede20779ec2015-02-02 18:00:53 +010059 unsigned int fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020060} sunxi_display;
61
Hans de Goede39920c82015-08-03 19:20:26 +020062const struct ctfb_res_modes composite_video_modes[2] = {
63 /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
64 { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
65 { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
66};
67
Hans de Goede2fbf0912014-12-23 23:04:35 +010068#ifdef CONFIG_VIDEO_HDMI
69
Hans de Goede75481602014-12-19 16:05:12 +010070/*
71 * Wait up to 200ms for value to be set in given part of reg.
72 */
73static int await_completion(u32 *reg, u32 mask, u32 val)
74{
75 unsigned long tmo = timer_get_us() + 200000;
76
77 while ((readl(reg) & mask) != val) {
78 if (timer_get_us() > tmo) {
79 printf("DDC: timeout reading EDID\n");
80 return -ETIME;
81 }
82 }
83 return 0;
84}
85
Hans de Goede7fad8a92014-12-28 09:13:21 +010086static int sunxi_hdmi_hpd_detect(int hpd_delay)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020087{
88 struct sunxi_ccm_reg * const ccm =
89 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
90 struct sunxi_hdmi_reg * const hdmi =
91 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
Hans de Goede7fad8a92014-12-28 09:13:21 +010092 unsigned long tmo = timer_get_us() + hpd_delay * 1000;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +020093
94 /* Set pll3 to 300MHz */
95 clock_set_pll3(300000000);
96
97 /* Set hdmi parent to pll3 */
98 clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
99 CCM_HDMI_CTRL_PLL3);
100
101 /* Set ahb gating to pass */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200102#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100103 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
104#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200105 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
106
107 /* Clock on */
108 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
109
110 writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl);
111 writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
112
Hans de Goede40f1b872014-12-20 15:15:23 +0100113 while (timer_get_us() < tmo) {
114 if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT)
115 return 1;
116 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200117
Hans de Goede40f1b872014-12-20 15:15:23 +0100118 return 0;
Hans de Goede518cef22014-12-19 15:13:57 +0100119}
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200120
Hans de Goede518cef22014-12-19 15:13:57 +0100121static void sunxi_hdmi_shutdown(void)
122{
123 struct sunxi_ccm_reg * const ccm =
124 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
125 struct sunxi_hdmi_reg * const hdmi =
126 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
127
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200128 clrbits_le32(&hdmi->ctrl, SUNXI_HDMI_CTRL_ENABLE);
129 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
130 clrbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
Hans de Goede44d8ae52015-04-06 20:33:34 +0200131#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100132 clrbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
133#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200134 clock_set_pll3(0);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200135}
136
Hans de Goede75481602014-12-19 16:05:12 +0100137static int sunxi_hdmi_ddc_do_command(u32 cmnd, int offset, int n)
138{
139 struct sunxi_hdmi_reg * const hdmi =
140 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
141
142 setbits_le32(&hdmi->ddc_fifo_ctrl, SUNXI_HDMI_DDC_FIFO_CTRL_CLEAR);
143 writel(SUNXI_HMDI_DDC_ADDR_EDDC_SEGMENT(offset >> 8) |
144 SUNXI_HMDI_DDC_ADDR_EDDC_ADDR |
145 SUNXI_HMDI_DDC_ADDR_OFFSET(offset) |
146 SUNXI_HMDI_DDC_ADDR_SLAVE_ADDR, &hdmi->ddc_addr);
147#ifndef CONFIG_MACH_SUN6I
148 writel(n, &hdmi->ddc_byte_count);
149 writel(cmnd, &hdmi->ddc_cmnd);
150#else
151 writel(n << 16 | cmnd, &hdmi->ddc_cmnd);
152#endif
153 setbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START);
154
155 return await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_START, 0);
156}
157
158static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count)
159{
160 struct sunxi_hdmi_reg * const hdmi =
161 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
162 int i, n;
163
164 while (count > 0) {
165 if (count > 16)
166 n = 16;
167 else
168 n = count;
169
170 if (sunxi_hdmi_ddc_do_command(
171 SUNXI_HDMI_DDC_CMND_EXPLICIT_EDDC_READ,
172 offset, n))
173 return -ETIME;
174
175 for (i = 0; i < n; i++)
176 *buf++ = readb(&hdmi->ddc_fifo_data);
177
178 offset += n;
179 count -= n;
180 }
181
182 return 0;
183}
184
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100185static int sunxi_hdmi_edid_get_block(int block, u8 *buf)
186{
187 int r, retries = 2;
188
189 do {
190 r = sunxi_hdmi_ddc_read(block * 128, buf, 128);
191 if (r)
192 continue;
193 r = edid_check_checksum(buf);
194 if (r) {
195 printf("EDID block %d: checksum error%s\n",
196 block, retries ? ", retrying" : "");
197 }
198 } while (r && retries--);
199
200 return r;
201}
202
Hans de Goede1c092202014-12-21 14:37:45 +0100203static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode)
Hans de Goede75481602014-12-19 16:05:12 +0100204{
205 struct edid1_info edid1;
Hans de Goedef3000682014-12-20 14:31:45 +0100206 struct edid_cea861_info cea681[4];
Hans de Goede75481602014-12-19 16:05:12 +0100207 struct edid_detailed_timing *t =
208 (struct edid_detailed_timing *)edid1.monitor_details.timing;
209 struct sunxi_hdmi_reg * const hdmi =
210 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
211 struct sunxi_ccm_reg * const ccm =
212 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goedef3000682014-12-20 14:31:45 +0100213 int i, r, ext_blocks = 0;
Hans de Goede75481602014-12-19 16:05:12 +0100214
215 /* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */
216 writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE,
217 &hdmi->pad_ctrl1);
218 writel(SUNXI_HDMI_PLL_CTRL | SUNXI_HDMI_PLL_CTRL_DIV(15),
219 &hdmi->pll_ctrl);
220 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
221
222 /* Reset i2c controller */
223 setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
224 writel(SUNXI_HMDI_DDC_CTRL_ENABLE |
225 SUNXI_HMDI_DDC_CTRL_SDA_ENABLE |
226 SUNXI_HMDI_DDC_CTRL_SCL_ENABLE |
227 SUNXI_HMDI_DDC_CTRL_RESET, &hdmi->ddc_ctrl);
228 if (await_completion(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_RESET, 0))
229 return -EIO;
230
231 writel(SUNXI_HDMI_DDC_CLOCK, &hdmi->ddc_clock);
232#ifndef CONFIG_MACH_SUN6I
233 writel(SUNXI_HMDI_DDC_LINE_CTRL_SDA_ENABLE |
234 SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl);
235#endif
236
Hans de Goede63c5fbd2014-12-20 14:01:48 +0100237 r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
Hans de Goedef3000682014-12-20 14:31:45 +0100238 if (r == 0) {
239 r = edid_check_info(&edid1);
240 if (r) {
241 printf("EDID: invalid EDID data\n");
242 r = -EINVAL;
243 }
244 }
245 if (r == 0) {
246 ext_blocks = edid1.extension_flag;
247 if (ext_blocks > 4)
248 ext_blocks = 4;
249 for (i = 0; i < ext_blocks; i++) {
250 if (sunxi_hdmi_edid_get_block(1 + i,
251 (u8 *)&cea681[i]) != 0) {
252 ext_blocks = i;
253 break;
254 }
255 }
256 }
Hans de Goede75481602014-12-19 16:05:12 +0100257
258 /* Disable DDC engine, no longer needed */
259 clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);
260 clrbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_DDC_GATE);
261
262 if (r)
263 return r;
264
Hans de Goede75481602014-12-19 16:05:12 +0100265 /* We want version 1.3 or 1.2 with detailed timing info */
266 if (edid1.version != 1 || (edid1.revision < 3 &&
267 !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) {
268 printf("EDID: unsupported version %d.%d\n",
269 edid1.version, edid1.revision);
270 return -EINVAL;
271 }
272
273 /* Take the first usable detailed timing */
274 for (i = 0; i < 4; i++, t++) {
275 r = video_edid_dtd_to_ctfb_res_modes(t, mode);
276 if (r == 0)
277 break;
278 }
279 if (i == 4) {
280 printf("EDID: no usable detailed timing found\n");
281 return -ENOENT;
282 }
283
Hans de Goedef3000682014-12-20 14:31:45 +0100284 /* Check for basic audio support, if found enable hdmi output */
Hans de Goede1c092202014-12-21 14:37:45 +0100285 sunxi_display.monitor = sunxi_monitor_dvi;
Hans de Goedef3000682014-12-20 14:31:45 +0100286 for (i = 0; i < ext_blocks; i++) {
287 if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG ||
288 cea681[i].revision < 2)
289 continue;
290
291 if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i]))
Hans de Goede1c092202014-12-21 14:37:45 +0100292 sunxi_display.monitor = sunxi_monitor_hdmi;
Hans de Goedef3000682014-12-20 14:31:45 +0100293 }
294
Hans de Goede75481602014-12-19 16:05:12 +0100295 return 0;
296}
297
Hans de Goede2fbf0912014-12-23 23:04:35 +0100298#endif /* CONFIG_VIDEO_HDMI */
299
Hans de Goede7cd6f922015-01-19 08:44:07 +0100300#ifdef CONFIG_MACH_SUN4I
301/*
302 * Testing has shown that on sun4i the display backend engine does not have
303 * deep enough fifo-s causing flickering / tearing in full-hd mode due to
304 * fifo underruns. So on sun4i we use the display frontend engine to do the
305 * dma from memory, as the frontend does have deep enough fifo-s.
306 */
307
308static const u32 sun4i_vert_coef[32] = {
309 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
310 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
311 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
312 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
313 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
314 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
315 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
316 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
317};
318
319static const u32 sun4i_horz_coef[64] = {
320 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
321 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
322 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
323 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
324 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
325 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
326 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
327 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
328 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
329 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
330 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
331 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
332 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
333 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
334 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
335 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
336};
337
338static void sunxi_frontend_init(void)
339{
340 struct sunxi_ccm_reg * const ccm =
341 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
342 struct sunxi_de_fe_reg * const de_fe =
343 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
344 int i;
345
346 /* Clocks on */
347 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_FE0);
348 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_FE0);
349 clock_set_de_mod_clock(&ccm->fe0_clk_cfg, 300000000);
350
351 setbits_le32(&de_fe->enable, SUNXI_DE_FE_ENABLE_EN);
352
353 for (i = 0; i < 32; i++) {
354 writel(sun4i_horz_coef[2 * i], &de_fe->ch0_horzcoef0[i]);
355 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch0_horzcoef1[i]);
356 writel(sun4i_vert_coef[i], &de_fe->ch0_vertcoef[i]);
357 writel(sun4i_horz_coef[2 * i], &de_fe->ch1_horzcoef0[i]);
358 writel(sun4i_horz_coef[2 * i + 1], &de_fe->ch1_horzcoef1[i]);
359 writel(sun4i_vert_coef[i], &de_fe->ch1_vertcoef[i]);
360 }
361
362 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_COEF_RDY);
363}
364
365static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
366 unsigned int address)
367{
368 struct sunxi_de_fe_reg * const de_fe =
369 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
370
371 setbits_le32(&de_fe->bypass, SUNXI_DE_FE_BYPASS_CSC_BYPASS);
372 writel(CONFIG_SYS_SDRAM_BASE + address, &de_fe->ch0_addr);
373 writel(mode->xres * 4, &de_fe->ch0_stride);
374 writel(SUNXI_DE_FE_INPUT_FMT_ARGB8888, &de_fe->input_fmt);
375 writel(SUNXI_DE_FE_OUTPUT_FMT_ARGB8888, &de_fe->output_fmt);
376
377 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
378 &de_fe->ch0_insize);
379 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
380 &de_fe->ch0_outsize);
381 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_horzfact);
382 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch0_vertfact);
383
384 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
385 &de_fe->ch1_insize);
386 writel(SUNXI_DE_FE_HEIGHT(mode->yres) | SUNXI_DE_FE_WIDTH(mode->xres),
387 &de_fe->ch1_outsize);
388 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_horzfact);
389 writel(SUNXI_DE_FE_FACTOR_INT(1), &de_fe->ch1_vertfact);
390
391 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_REG_RDY);
392}
393
394static void sunxi_frontend_enable(void)
395{
396 struct sunxi_de_fe_reg * const de_fe =
397 (struct sunxi_de_fe_reg *)SUNXI_DE_FE0_BASE;
398
399 setbits_le32(&de_fe->frame_ctrl, SUNXI_DE_FE_FRAME_CTRL_FRM_START);
400}
401#else
402static void sunxi_frontend_init(void) {}
403static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode,
404 unsigned int address) {}
405static void sunxi_frontend_enable(void) {}
406#endif
407
Hans de Goede39920c82015-08-03 19:20:26 +0200408static bool sunxi_is_composite(void)
409{
410 switch (sunxi_display.monitor) {
411 case sunxi_monitor_none:
412 case sunxi_monitor_dvi:
413 case sunxi_monitor_hdmi:
414 case sunxi_monitor_lcd:
415 case sunxi_monitor_vga:
416 return false;
417 case sunxi_monitor_composite_pal:
418 case sunxi_monitor_composite_ntsc:
419 case sunxi_monitor_composite_pal_m:
420 case sunxi_monitor_composite_pal_nc:
421 return true;
422 }
423
424 return false; /* Never reached */
425}
426
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200427/*
428 * This is the entity that mixes and matches the different layers and inputs.
429 * Allwinner calls it the back-end, but i like composer better.
430 */
431static void sunxi_composer_init(void)
432{
433 struct sunxi_ccm_reg * const ccm =
434 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
435 struct sunxi_de_be_reg * const de_be =
436 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
437 int i;
438
Hans de Goede7cd6f922015-01-19 08:44:07 +0100439 sunxi_frontend_init();
440
Hans de Goede44d8ae52015-04-06 20:33:34 +0200441#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100442 /* Reset off */
443 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE_BE0);
444#endif
445
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200446 /* Clocks on */
447 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100448#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200449 setbits_le32(&ccm->dram_clk_gate, 1 << CCM_DRAM_GATE_OFFSET_DE_BE0);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100450#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200451 clock_set_de_mod_clock(&ccm->be0_clk_cfg, 300000000);
452
453 /* Engine bug, clear registers after reset */
454 for (i = 0x0800; i < 0x1000; i += 4)
455 writel(0, SUNXI_DE_BE0_BASE + i);
456
457 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
458}
459
Hans de Goede39920c82015-08-03 19:20:26 +0200460static u32 sunxi_rgb2yuv_coef[12] = {
461 0x00000107, 0x00000204, 0x00000064, 0x00000108,
462 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
463 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
464};
465
Hans de Goedebe8ec632014-12-19 13:46:33 +0100466static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200467 unsigned int address)
468{
469 struct sunxi_de_be_reg * const de_be =
470 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
Hans de Goede39920c82015-08-03 19:20:26 +0200471 int i;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200472
Hans de Goede7cd6f922015-01-19 08:44:07 +0100473 sunxi_frontend_mode_set(mode, address);
474
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200475 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
476 &de_be->disp_size);
477 writel(SUNXI_DE_BE_HEIGHT(mode->yres) | SUNXI_DE_BE_WIDTH(mode->xres),
478 &de_be->layer0_size);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100479#ifndef CONFIG_MACH_SUN4I /* On sun4i the frontend does the dma */
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200480 writel(SUNXI_DE_BE_LAYER_STRIDE(mode->xres), &de_be->layer0_stride);
481 writel(address << 3, &de_be->layer0_addr_low32b);
482 writel(address >> 29, &de_be->layer0_addr_high4b);
Hans de Goede7cd6f922015-01-19 08:44:07 +0100483#else
484 writel(SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0, &de_be->layer0_attr0_ctrl);
485#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200486 writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl);
487
488 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200489 if (mode->vmode == FB_VMODE_INTERLACED)
490 setbits_le32(&de_be->mode,
Hans de Goeded8d07992015-08-06 12:08:33 +0200491#ifndef CONFIG_MACH_SUN5I
Hans de Goedef6d9d322015-08-02 16:49:29 +0200492 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
Hans de Goeded8d07992015-08-06 12:08:33 +0200493#endif
Hans de Goedef6d9d322015-08-02 16:49:29 +0200494 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
Hans de Goede39920c82015-08-03 19:20:26 +0200495
496 if (sunxi_is_composite()) {
497 writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
498 &de_be->output_color_ctrl);
499 for (i = 0; i < 12; i++)
500 writel(sunxi_rgb2yuv_coef[i],
501 &de_be->output_color_coef[i]);
502 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200503}
504
Hans de Goede0e045212014-12-21 14:49:34 +0100505static void sunxi_composer_enable(void)
506{
507 struct sunxi_de_be_reg * const de_be =
508 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
509
Hans de Goede7cd6f922015-01-19 08:44:07 +0100510 sunxi_frontend_enable();
511
Hans de Goede0e045212014-12-21 14:49:34 +0100512 setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS);
513 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START);
514}
515
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200516/*
517 * LCDC, what allwinner calls a CRTC, so timing controller and serializer.
518 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100519static void sunxi_lcdc_pll_set(int tcon, int dotclock,
520 int *clk_div, int *clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200521{
522 struct sunxi_ccm_reg * const ccm =
523 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede5489ebc2014-12-21 16:27:45 +0100524 int value, n, m, min_m, max_m, diff;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200525 int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
526 int best_double = 0;
Hans de Goedefb685d32015-08-08 14:08:21 +0200527 bool use_mipi_pll = false;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200528
Hans de Goede5489ebc2014-12-21 16:27:45 +0100529 if (tcon == 0) {
Hans de Goede213480e2015-01-01 22:04:34 +0100530#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede5489ebc2014-12-21 16:27:45 +0100531 min_m = 6;
532 max_m = 127;
Hans de Goede213480e2015-01-01 22:04:34 +0100533#endif
534#ifdef CONFIG_VIDEO_LCD_IF_LVDS
535 min_m = max_m = 7;
536#endif
Hans de Goede5489ebc2014-12-21 16:27:45 +0100537 } else {
538 min_m = 1;
539 max_m = 15;
540 }
541
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200542 /*
543 * Find the lowest divider resulting in a matching clock, if there
544 * is no match, pick the closest lower clock, as monitors tend to
545 * not sync to higher frequencies.
546 */
Hans de Goede5489ebc2014-12-21 16:27:45 +0100547 for (m = min_m; m <= max_m; m++) {
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200548 n = (m * dotclock) / 3000;
549
550 if ((n >= 9) && (n <= 127)) {
551 value = (3000 * n) / m;
552 diff = dotclock - value;
553 if (diff < best_diff) {
554 best_diff = diff;
555 best_m = m;
556 best_n = n;
557 best_double = 0;
558 }
559 }
560
561 /* These are just duplicates */
562 if (!(m & 1))
563 continue;
564
565 n = (m * dotclock) / 6000;
566 if ((n >= 9) && (n <= 127)) {
567 value = (6000 * n) / m;
568 diff = dotclock - value;
569 if (diff < best_diff) {
570 best_diff = diff;
571 best_m = m;
572 best_n = n;
573 best_double = 1;
574 }
575 }
576 }
577
Hans de Goedefb685d32015-08-08 14:08:21 +0200578#ifdef CONFIG_MACH_SUN6I
579 /*
580 * Use the MIPI pll if we've been unable to find any matching setting
581 * for PLL3, this happens with high dotclocks because of min_m = 6.
582 */
583 if (tcon == 0 && best_n == 0) {
584 use_mipi_pll = true;
585 best_m = 6; /* Minimum m for tcon0 */
586 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200587
Hans de Goedefb685d32015-08-08 14:08:21 +0200588 if (use_mipi_pll) {
589 clock_set_pll3(297000000); /* Fix the video pll at 297 MHz */
590 clock_set_mipi_pll(best_m * dotclock * 1000);
591 debug("dotclock: %dkHz = %dkHz via mipi pll\n",
592 dotclock, clock_get_mipi_pll() / best_m / 1000);
593 } else
594#endif
595 {
596 clock_set_pll3(best_n * 3000000);
597 debug("dotclock: %dkHz = %dkHz: (%d * 3MHz * %d) / %d\n",
598 dotclock,
599 (best_double + 1) * clock_get_pll3() / best_m / 1000,
600 best_double + 1, best_n, best_m);
601 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200602
Hans de Goede5489ebc2014-12-21 16:27:45 +0100603 if (tcon == 0) {
Hans de Goedefb685d32015-08-08 14:08:21 +0200604 u32 pll;
605
606 if (use_mipi_pll)
607 pll = CCM_LCD_CH0_CTRL_MIPI_PLL;
608 else if (best_double)
609 pll = CCM_LCD_CH0_CTRL_PLL3_2X;
610 else
611 pll = CCM_LCD_CH0_CTRL_PLL3;
612
613 writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll,
Hans de Goede5489ebc2014-12-21 16:27:45 +0100614 &ccm->lcd0_ch0_clk_cfg);
615 } else {
616 writel(CCM_LCD_CH1_CTRL_GATE |
617 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
618 CCM_LCD_CH1_CTRL_PLL3) |
619 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
Hans de Goede39920c82015-08-03 19:20:26 +0200620 if (sunxi_is_composite())
621 setbits_le32(&ccm->lcd0_ch1_clk_cfg,
622 CCM_LCD_CH1_CTRL_HALF_SCLK1);
Hans de Goede5489ebc2014-12-21 16:27:45 +0100623 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200624
625 *clk_div = best_m;
626 *clk_double = best_double;
627}
628
629static void sunxi_lcdc_init(void)
630{
631 struct sunxi_ccm_reg * const ccm =
632 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
633 struct sunxi_lcdc_reg * const lcdc =
634 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
635
636 /* Reset off */
Hans de Goede44d8ae52015-04-06 20:33:34 +0200637#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goede211717a2014-11-14 17:42:14 +0100638 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0);
639#else
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200640 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_RST);
Hans de Goede211717a2014-11-14 17:42:14 +0100641#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200642
643 /* Clock on */
644 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100645#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Hans de Goede83edb2a2015-05-14 18:52:54 +0200646#ifdef CONFIG_SUNXI_GEN_SUN6I
647 setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS);
648#else
Hans de Goede213480e2015-01-01 22:04:34 +0100649 setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST);
650#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200651#endif
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200652
653 /* Init lcdc */
654 writel(0, &lcdc->ctrl); /* Disable tcon */
655 writel(0, &lcdc->int0); /* Disable all interrupts */
656
657 /* Disable tcon0 dot clock */
658 clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE);
659
660 /* Set all io lines to tristate */
661 writel(0xffffffff, &lcdc->tcon0_io_tristate);
662 writel(0xffffffff, &lcdc->tcon1_io_tristate);
663}
664
Hans de Goede0e045212014-12-21 14:49:34 +0100665static void sunxi_lcdc_enable(void)
666{
667 struct sunxi_lcdc_reg * const lcdc =
668 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
669
670 setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
Hans de Goede213480e2015-01-01 22:04:34 +0100671#ifdef CONFIG_VIDEO_LCD_IF_LVDS
672 setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE);
673 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0);
Hans de Goede83edb2a2015-05-14 18:52:54 +0200674#ifdef CONFIG_SUNXI_GEN_SUN6I
675 udelay(2); /* delay at least 1200 ns */
676 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB);
677 udelay(2); /* delay at least 1200 ns */
678 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC);
679 if (sunxi_display.depth == 18)
680 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7));
681 else
682 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf));
683#else
Hans de Goede213480e2015-01-01 22:04:34 +0100684 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
685 udelay(2); /* delay at least 1200 ns */
686 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1);
687 udelay(1); /* delay at least 120 ns */
688 setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2);
689 setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE);
690#endif
Hans de Goede83edb2a2015-05-14 18:52:54 +0200691#endif
Hans de Goede0e045212014-12-21 14:49:34 +0100692}
693
Hans de Goede2dae8002014-12-21 16:28:32 +0100694static void sunxi_lcdc_panel_enable(void)
695{
Hans de Goede242e3d82015-02-16 17:26:41 +0100696 int pin, reset_pin;
Hans de Goede2dae8002014-12-21 16:28:32 +0100697
698 /*
699 * Start with backlight disabled to avoid the screen flashing to
700 * white while the lcd inits.
701 */
702 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200703 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100704 gpio_request(pin, "lcd_backlight_enable");
705 gpio_direction_output(pin, 0);
706 }
707
708 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede15728192015-04-22 17:45:59 +0200709 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100710 gpio_request(pin, "lcd_backlight_pwm");
Hans de Goedea7403ae2015-01-22 21:02:42 +0100711 gpio_direction_output(pin, PWM_OFF);
Hans de Goede2dae8002014-12-21 16:28:32 +0100712 }
713
Hans de Goede242e3d82015-02-16 17:26:41 +0100714 reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_RESET);
Hans de Goede15728192015-04-22 17:45:59 +0200715 if (reset_pin >= 0) {
Hans de Goede242e3d82015-02-16 17:26:41 +0100716 gpio_request(reset_pin, "lcd_reset");
717 gpio_direction_output(reset_pin, 0); /* Assert reset */
718 }
719
Hans de Goede2dae8002014-12-21 16:28:32 +0100720 /* Give the backlight some time to turn off and power up the panel. */
721 mdelay(40);
722 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_POWER);
Hans de Goede15728192015-04-22 17:45:59 +0200723 if (pin >= 0) {
Hans de Goede2dae8002014-12-21 16:28:32 +0100724 gpio_request(pin, "lcd_power");
725 gpio_direction_output(pin, 1);
726 }
Hans de Goede242e3d82015-02-16 17:26:41 +0100727
Hans de Goede15728192015-04-22 17:45:59 +0200728 if (reset_pin >= 0)
Hans de Goede242e3d82015-02-16 17:26:41 +0100729 gpio_direction_output(reset_pin, 1); /* De-assert reset */
Hans de Goede2dae8002014-12-21 16:28:32 +0100730}
731
732static void sunxi_lcdc_backlight_enable(void)
733{
734 int pin;
735
736 /*
737 * We want to have scanned out at least one frame before enabling the
738 * backlight to avoid the screen flashing to white when we enable it.
739 */
740 mdelay(40);
741
742 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_EN);
Hans de Goede15728192015-04-22 17:45:59 +0200743 if (pin >= 0)
Hans de Goede2dae8002014-12-21 16:28:32 +0100744 gpio_direction_output(pin, 1);
745
746 pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_BL_PWM);
Hans de Goede421c98d2016-08-19 15:25:41 +0200747#ifdef SUNXI_PWM_PIN0
748 if (pin == SUNXI_PWM_PIN0) {
749 writel(SUNXI_PWM_CTRL_POLARITY0(PWM_ON) |
750 SUNXI_PWM_CTRL_ENABLE0 |
751 SUNXI_PWM_CTRL_PRESCALE0(0xf), SUNXI_PWM_CTRL_REG);
752 writel(SUNXI_PWM_PERIOD_80PCT, SUNXI_PWM_CH0_PERIOD);
753 sunxi_gpio_set_cfgpin(pin, SUNXI_PWM_MUX);
754 return;
755 }
756#endif
Hans de Goede15728192015-04-22 17:45:59 +0200757 if (pin >= 0)
Hans de Goedea7403ae2015-01-22 21:02:42 +0100758 gpio_direction_output(pin, PWM_ON);
Hans de Goede2dae8002014-12-21 16:28:32 +0100759}
760
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200761static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon)
Hans de Goede2dae8002014-12-21 16:28:32 +0100762{
763 int delay;
764
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200765 delay = mode->lower_margin + mode->vsync_len + mode->upper_margin;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200766 if (mode->vmode == FB_VMODE_INTERLACED)
767 delay /= 2;
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200768 if (tcon == 1)
769 delay -= 2;
770
Hans de Goede2dae8002014-12-21 16:28:32 +0100771 return (delay > 30) ? 30 : delay;
772}
773
Hans de Goedefb75d972015-01-25 15:33:07 +0100774static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
775 bool for_ext_vga_dac)
Hans de Goede2dae8002014-12-21 16:28:32 +0100776{
777 struct sunxi_lcdc_reg * const lcdc =
778 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
779 int bp, clk_delay, clk_div, clk_double, pin, total, val;
780
Lawrence Yucf6eca72016-03-04 09:08:56 -0800781#if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS
782 for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) {
783#else
Hans de Goedec1cfd512015-08-08 16:13:53 +0200784 for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) {
Lawrence Yucf6eca72016-03-04 09:08:56 -0800785#endif
Hans de Goede213480e2015-01-01 22:04:34 +0100786#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100787 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0);
Hans de Goede213480e2015-01-01 22:04:34 +0100788#endif
789#ifdef CONFIG_VIDEO_LCD_IF_LVDS
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100790 sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0);
Hans de Goede213480e2015-01-01 22:04:34 +0100791#endif
Hans de Goedec1cfd512015-08-08 16:13:53 +0200792#ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804
793 sunxi_gpio_set_drv(pin, 3);
794#endif
795 }
Hans de Goede2dae8002014-12-21 16:28:32 +0100796
797 sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double);
798
799 /* Use tcon0 */
800 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
801 SUNXI_LCDC_CTRL_IO_MAP_TCON0);
802
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200803 clk_delay = sunxi_lcdc_get_clk_delay(mode, 0);
Hans de Goede2dae8002014-12-21 16:28:32 +0100804 writel(SUNXI_LCDC_TCON0_CTRL_ENABLE |
805 SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl);
806
807 writel(SUNXI_LCDC_TCON0_DCLK_ENABLE |
808 SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk);
809
810 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres),
811 &lcdc->tcon0_timing_active);
812
813 bp = mode->hsync_len + mode->left_margin;
814 total = mode->xres + mode->right_margin + bp;
815 writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) |
816 SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h);
817
818 bp = mode->vsync_len + mode->upper_margin;
819 total = mode->yres + mode->lower_margin + bp;
820 writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) |
821 SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v);
822
Hans de Goede213480e2015-01-01 22:04:34 +0100823#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL
Hans de Goede2dae8002014-12-21 16:28:32 +0100824 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
825 &lcdc->tcon0_timing_sync);
826
Hans de Goede2dae8002014-12-21 16:28:32 +0100827 writel(0, &lcdc->tcon0_hv_intf);
828 writel(0, &lcdc->tcon0_cpu_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100829#endif
830#ifdef CONFIG_VIDEO_LCD_IF_LVDS
831 val = (sunxi_display.depth == 18) ? 1 : 0;
Hans de Goede83edb2a2015-05-14 18:52:54 +0200832 writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) |
833 SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf);
Hans de Goede213480e2015-01-01 22:04:34 +0100834#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100835
836 if (sunxi_display.depth == 18 || sunxi_display.depth == 16) {
837 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]);
838 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]);
839 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]);
840 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]);
841 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]);
842 writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]);
843 writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]);
844 writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]);
845 writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]);
846 writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]);
847 writel(((sunxi_display.depth == 18) ?
848 SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 :
849 SUNXI_LCDC_TCON0_FRM_CTRL_RGB565),
850 &lcdc->tcon0_frm_ctrl);
851 }
852
Hans de Goede65150322015-01-13 13:21:46 +0100853 val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE);
Hans de Goede2dae8002014-12-21 16:28:32 +0100854 if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
855 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
856 if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
857 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
Hans de Goedefb75d972015-01-25 15:33:07 +0100858
859#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH
860 if (for_ext_vga_dac)
861 val = 0;
862#endif
Hans de Goede2dae8002014-12-21 16:28:32 +0100863 writel(val, &lcdc->tcon0_io_polarity);
864
865 writel(0, &lcdc->tcon0_io_tristate);
866}
867
Hans de Goede39920c82015-08-03 19:20:26 +0200868#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goede0e045212014-12-21 14:49:34 +0100869static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede3ffbe472014-12-27 15:19:23 +0100870 int *clk_div, int *clk_double,
871 bool use_portd_hvsync)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200872{
873 struct sunxi_lcdc_reg * const lcdc =
874 (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200875 int bp, clk_delay, total, val, yres;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200876
877 /* Use tcon1 */
878 clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK,
879 SUNXI_LCDC_CTRL_IO_MAP_TCON1);
880
Hans de Goedeab2a2be2015-08-02 17:38:43 +0200881 clk_delay = sunxi_lcdc_get_clk_delay(mode, 1);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200882 writel(SUNXI_LCDC_TCON1_CTRL_ENABLE |
Hans de Goedef6d9d322015-08-02 16:49:29 +0200883 ((mode->vmode == FB_VMODE_INTERLACED) ?
884 SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) |
Hans de Goede6741cc72014-12-24 19:50:11 +0100885 SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200886
Hans de Goedef6d9d322015-08-02 16:49:29 +0200887 yres = mode->yres;
888 if (mode->vmode == FB_VMODE_INTERLACED)
889 yres /= 2;
890 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200891 &lcdc->tcon1_timing_source);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200892 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200893 &lcdc->tcon1_timing_scale);
Hans de Goedef6d9d322015-08-02 16:49:29 +0200894 writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres),
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200895 &lcdc->tcon1_timing_out);
896
897 bp = mode->hsync_len + mode->left_margin;
898 total = mode->xres + mode->right_margin + bp;
899 writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) |
900 SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h);
901
902 bp = mode->vsync_len + mode->upper_margin;
903 total = mode->yres + mode->lower_margin + bp;
Hans de Goedef6d9d322015-08-02 16:49:29 +0200904 if (mode->vmode == FB_VMODE_NONINTERLACED)
905 total *= 2;
906 writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) |
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200907 SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v);
908
909 writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
910 &lcdc->tcon1_timing_sync);
911
Hans de Goede3ffbe472014-12-27 15:19:23 +0100912 if (use_portd_hvsync) {
Paul Kocialkowski487b3272015-03-22 18:12:22 +0100913 sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0);
914 sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0);
Hans de Goede3ffbe472014-12-27 15:19:23 +0100915
916 val = 0;
917 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
918 val |= SUNXI_LCDC_TCON_HSYNC_MASK;
919 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
920 val |= SUNXI_LCDC_TCON_VSYNC_MASK;
921 writel(val, &lcdc->tcon1_io_polarity);
922
923 clrbits_le32(&lcdc->tcon1_io_tristate,
924 SUNXI_LCDC_TCON_VSYNC_MASK |
925 SUNXI_LCDC_TCON_HSYNC_MASK);
926 }
Hans de Goeded8d07992015-08-06 12:08:33 +0200927
928#ifdef CONFIG_MACH_SUN5I
929 if (sunxi_is_composite())
930 clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK,
931 SUNXI_LCDC_MUX_CTRL_SRC0(1));
932#endif
933
Hans de Goede5489ebc2014-12-21 16:27:45 +0100934 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200935}
Hans de Goede39920c82015-08-03 19:20:26 +0200936#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +0100937
938#ifdef CONFIG_VIDEO_HDMI
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200939
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100940static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode)
941{
942 struct sunxi_hdmi_reg * const hdmi =
943 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
944 u8 checksum = 0;
945 u8 avi_info_frame[17] = {
946 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00,
947 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
948 0x00
949 };
950 u8 vendor_info_frame[19] = {
951 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40,
952 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
953 0x00, 0x00, 0x00
954 };
955 int i;
956
957 if (mode->pixclock_khz <= 27000)
958 avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */
959 else
960 avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */
961
962 if (mode->xres * 100 / mode->yres < 156)
963 avi_info_frame[5] |= 0x18; /* 4 : 3 */
964 else
965 avi_info_frame[5] |= 0x28; /* 16 : 9 */
966
967 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
968 checksum += avi_info_frame[i];
969
970 avi_info_frame[3] = 0x100 - checksum;
971
972 for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++)
973 writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]);
974
975 writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0);
976 writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1);
977
978 for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++)
979 writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]);
980
981 writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0);
982 writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1);
983
984 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI);
985}
986
Hans de Goedebe8ec632014-12-19 13:46:33 +0100987static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede1c092202014-12-21 14:37:45 +0100988 int clk_div, int clk_double)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +0200989{
990 struct sunxi_hdmi_reg * const hdmi =
991 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
992 int x, y;
993
994 /* Write clear interrupt status bits */
995 writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
996
Hans de Goede1c092202014-12-21 14:37:45 +0100997 if (sunxi_display.monitor == sunxi_monitor_hdmi)
Hans de Goede5ee0bea2014-12-20 13:38:06 +0100998 sunxi_hdmi_setup_info_frames(mode);
999
Hans de Goede876aaaf2014-12-20 13:51:16 +01001000 /* Set input sync enable */
1001 writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown);
1002
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001003 /* Init various registers, select pll3 as clock source */
1004 writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity);
1005 writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0);
1006 writel(SUNXI_HDMI_PAD_CTRL1, &hdmi->pad_ctrl1);
1007 writel(SUNXI_HDMI_PLL_CTRL, &hdmi->pll_ctrl);
1008 writel(SUNXI_HDMI_PLL_DBG0_PLL3, &hdmi->pll_dbg0);
1009
1010 /* Setup clk div and doubler */
1011 clrsetbits_le32(&hdmi->pll_ctrl, SUNXI_HDMI_PLL_CTRL_DIV_MASK,
1012 SUNXI_HDMI_PLL_CTRL_DIV(clk_div));
1013 if (!clk_double)
1014 setbits_le32(&hdmi->pad_ctrl1, SUNXI_HDMI_PAD_CTRL1_HALVE);
1015
1016 /* Setup timing registers */
1017 writel(SUNXI_HDMI_Y(mode->yres) | SUNXI_HDMI_X(mode->xres),
1018 &hdmi->video_size);
1019
1020 x = mode->hsync_len + mode->left_margin;
1021 y = mode->vsync_len + mode->upper_margin;
1022 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_bp);
1023
1024 x = mode->right_margin;
1025 y = mode->lower_margin;
1026 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_fp);
1027
1028 x = mode->hsync_len;
1029 y = mode->vsync_len;
1030 writel(SUNXI_HDMI_Y(y) | SUNXI_HDMI_X(x), &hdmi->video_spw);
1031
1032 if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
1033 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_HOR);
1034
1035 if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
1036 setbits_le32(&hdmi->video_polarity, SUNXI_HDMI_VIDEO_POL_VER);
1037}
1038
Hans de Goede0e045212014-12-21 14:49:34 +01001039static void sunxi_hdmi_enable(void)
1040{
1041 struct sunxi_hdmi_reg * const hdmi =
1042 (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE;
1043
1044 udelay(100);
1045 setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE);
1046}
1047
Hans de Goede2fbf0912014-12-23 23:04:35 +01001048#endif /* CONFIG_VIDEO_HDMI */
1049
Hans de Goede39920c82015-08-03 19:20:26 +02001050#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
Hans de Goeded9786d22014-12-25 13:58:06 +01001051
Hans de Goede39920c82015-08-03 19:20:26 +02001052static void sunxi_tvencoder_mode_set(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001053{
1054 struct sunxi_ccm_reg * const ccm =
1055 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1056 struct sunxi_tve_reg * const tve =
1057 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1058
Hans de Goeded8d07992015-08-06 12:08:33 +02001059 /* Reset off */
1060 setbits_le32(&ccm->lcd0_ch0_clk_cfg, CCM_LCD_CH0_CTRL_TVE_RST);
Hans de Goeded9786d22014-12-25 13:58:06 +01001061 /* Clock on */
1062 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
1063
Hans de Goede39920c82015-08-03 19:20:26 +02001064 switch (sunxi_display.monitor) {
1065 case sunxi_monitor_vga:
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), &tve->gctrl);
1069 writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
1070 writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
1071 writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
1072 break;
1073 case sunxi_monitor_composite_pal_nc:
1074 writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
1075 /* Fall through */
1076 case sunxi_monitor_composite_pal:
1077 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1078 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1079 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1080 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1081 writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
1082 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1083 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1084 writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
1085 writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
1086 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
1087 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1088 writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
1089 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1090 writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
1091 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1092 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1093 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1094 writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
1095 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1096 break;
1097 case sunxi_monitor_composite_pal_m:
1098 writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
1099 writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
1100 /* Fall through */
1101 case sunxi_monitor_composite_ntsc:
1102 writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
1103 SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
1104 SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
1105 SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
1106 writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
1107 writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
1108 writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
1109 writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
1110 writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
1111 writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
1112 writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
1113 writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
1114 writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
1115 writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
1116 writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
1117 writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
1118 writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
1119 writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
1120 writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
1121 writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
1122 writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
1123 break;
1124 case sunxi_monitor_none:
1125 case sunxi_monitor_dvi:
1126 case sunxi_monitor_hdmi:
1127 case sunxi_monitor_lcd:
1128 break;
1129 }
Hans de Goeded9786d22014-12-25 13:58:06 +01001130}
1131
Hans de Goede39920c82015-08-03 19:20:26 +02001132static void sunxi_tvencoder_enable(void)
Hans de Goeded9786d22014-12-25 13:58:06 +01001133{
1134 struct sunxi_tve_reg * const tve =
1135 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
1136
1137 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
1138}
1139
Hans de Goede39920c82015-08-03 19:20:26 +02001140#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
Hans de Goeded9786d22014-12-25 13:58:06 +01001141
Hans de Goedee8400792014-12-23 18:39:52 +01001142static void sunxi_drc_init(void)
1143{
Hans de Goede44d8ae52015-04-06 20:33:34 +02001144#ifdef CONFIG_SUNXI_GEN_SUN6I
Hans de Goedee8400792014-12-23 18:39:52 +01001145 struct sunxi_ccm_reg * const ccm =
1146 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
1147
1148 /* On sun6i the drc must be clocked even when in pass-through mode */
Vishnu Patekar8c3dacf2015-03-01 23:47:48 +05301149#ifdef CONFIG_MACH_SUN8I_A33
1150 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_SAT);
1151#endif
Hans de Goedee8400792014-12-23 18:39:52 +01001152 setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DRC0);
1153 clock_set_de_mod_clock(&ccm->iep_drc0_clk_cfg, 300000000);
1154#endif
1155}
1156
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001157#ifdef CONFIG_VIDEO_VGA_VIA_LCD
1158static void sunxi_vga_external_dac_enable(void)
1159{
1160 int pin;
1161
1162 pin = sunxi_name_to_gpio(CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN);
Hans de Goede15728192015-04-22 17:45:59 +02001163 if (pin >= 0) {
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001164 gpio_request(pin, "vga_enable");
1165 gpio_direction_output(pin, 1);
1166 }
1167}
1168#endif /* CONFIG_VIDEO_VGA_VIA_LCD */
1169
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001170#ifdef CONFIG_VIDEO_LCD_SSD2828
1171static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode)
1172{
1173 struct ssd2828_config cfg = {
1174 .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS),
1175 .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK),
1176 .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI),
1177 .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO),
1178 .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET),
1179 .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000,
1180 .ssd2828_color_depth = 24,
1181#ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828
1182 .mipi_dsi_number_of_data_lanes = 4,
1183 .mipi_dsi_bitrate_per_data_lane_mbps = 513,
1184 .mipi_dsi_delay_after_exit_sleep_mode_ms = 100,
1185 .mipi_dsi_delay_after_set_display_on_ms = 200
1186#else
1187#error MIPI LCD panel needs configuration parameters
1188#endif
1189 };
1190
1191 if (cfg.csx_pin == -1 || cfg.sck_pin == -1 || cfg.sdi_pin == -1) {
1192 printf("SSD2828: SPI pins are not properly configured\n");
1193 return 1;
1194 }
1195 if (cfg.reset_pin == -1) {
1196 printf("SSD2828: Reset pin is not properly configured\n");
1197 return 1;
1198 }
1199
1200 return ssd2828_init(&cfg, mode);
1201}
1202#endif /* CONFIG_VIDEO_LCD_SSD2828 */
1203
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001204static void sunxi_engines_init(void)
1205{
1206 sunxi_composer_init();
1207 sunxi_lcdc_init();
Hans de Goede211717a2014-11-14 17:42:14 +01001208 sunxi_drc_init();
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001209}
1210
Hans de Goede1c092202014-12-21 14:37:45 +01001211static void sunxi_mode_set(const struct ctfb_res_modes *mode,
Hans de Goede5ee0bea2014-12-20 13:38:06 +01001212 unsigned int address)
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001213{
Hans de Goeded9786d22014-12-25 13:58:06 +01001214 int __maybe_unused clk_div, clk_double;
1215
Hans de Goede0e045212014-12-21 14:49:34 +01001216 switch (sunxi_display.monitor) {
1217 case sunxi_monitor_none:
1218 break;
1219 case sunxi_monitor_dvi:
Hans de Goeded9786d22014-12-25 13:58:06 +01001220 case sunxi_monitor_hdmi:
Hans de Goede2fbf0912014-12-23 23:04:35 +01001221#ifdef CONFIG_VIDEO_HDMI
Hans de Goede0e045212014-12-21 14:49:34 +01001222 sunxi_composer_mode_set(mode, address);
Hans de Goede3ffbe472014-12-27 15:19:23 +01001223 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
Hans de Goede0e045212014-12-21 14:49:34 +01001224 sunxi_hdmi_mode_set(mode, clk_div, clk_double);
1225 sunxi_composer_enable();
1226 sunxi_lcdc_enable();
1227 sunxi_hdmi_enable();
Hans de Goede2fbf0912014-12-23 23:04:35 +01001228#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001229 break;
1230 case sunxi_monitor_lcd:
Hans de Goede2dae8002014-12-21 16:28:32 +01001231 sunxi_lcdc_panel_enable();
Hans de Goedec1cfd512015-08-08 16:13:53 +02001232 if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) {
1233 /*
1234 * The anx9804 needs 1.8V from eldo3, we do this here
Hans de Goede6944aff2015-10-03 15:18:33 +02001235 * and not via CONFIG_AXP_ELDO3_VOLT from board_init()
Hans de Goedec1cfd512015-08-08 16:13:53 +02001236 * to avoid turning this on when using hdmi output.
1237 */
Hans de Goede6944aff2015-10-03 15:18:33 +02001238 axp_set_eldo(3, 1800);
Hans de Goedec1cfd512015-08-08 16:13:53 +02001239 anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4,
1240 ANX9804_DATA_RATE_1620M,
1241 sunxi_display.depth);
1242 }
Hans de Goede27515b22015-01-20 09:23:36 +01001243 if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) {
1244 mdelay(50); /* Wait for lcd controller power on */
1245 hitachi_tx18d42vm_init();
1246 }
Hans de Goedeaad2ac22015-02-16 17:49:47 +01001247 if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) {
1248 unsigned int orig_i2c_bus = i2c_get_bus_num();
1249 i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS);
1250 i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */
1251 i2c_set_bus_num(orig_i2c_bus);
1252 }
Hans de Goede2dae8002014-12-21 16:28:32 +01001253 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001254 sunxi_lcdc_tcon0_mode_set(mode, false);
Hans de Goede2dae8002014-12-21 16:28:32 +01001255 sunxi_composer_enable();
1256 sunxi_lcdc_enable();
Siarhei Siamashka97ece832015-01-19 05:23:33 +02001257#ifdef CONFIG_VIDEO_LCD_SSD2828
1258 sunxi_ssd2828_init(mode);
1259#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001260 sunxi_lcdc_backlight_enable();
Hans de Goede0e045212014-12-21 14:49:34 +01001261 break;
1262 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001263#ifdef CONFIG_VIDEO_VGA
1264 sunxi_composer_mode_set(mode, address);
1265 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
Hans de Goede39920c82015-08-03 19:20:26 +02001266 sunxi_tvencoder_mode_set();
Hans de Goeded9786d22014-12-25 13:58:06 +01001267 sunxi_composer_enable();
1268 sunxi_lcdc_enable();
Hans de Goede39920c82015-08-03 19:20:26 +02001269 sunxi_tvencoder_enable();
Hans de Goeded9786d22014-12-25 13:58:06 +01001270#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001271 sunxi_composer_mode_set(mode, address);
Hans de Goedefb75d972015-01-25 15:33:07 +01001272 sunxi_lcdc_tcon0_mode_set(mode, true);
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001273 sunxi_composer_enable();
1274 sunxi_lcdc_enable();
Chen-Yu Tsai507e27d2015-01-12 18:02:11 +08001275 sunxi_vga_external_dac_enable();
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001276#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001277 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001278 case sunxi_monitor_composite_pal:
1279 case sunxi_monitor_composite_ntsc:
1280 case sunxi_monitor_composite_pal_m:
1281 case sunxi_monitor_composite_pal_nc:
1282#ifdef CONFIG_VIDEO_COMPOSITE
1283 sunxi_composer_mode_set(mode, address);
1284 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
1285 sunxi_tvencoder_mode_set();
1286 sunxi_composer_enable();
1287 sunxi_lcdc_enable();
1288 sunxi_tvencoder_enable();
1289#endif
1290 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001291 }
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001292}
1293
Hans de Goede1c092202014-12-21 14:37:45 +01001294static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1295{
1296 switch (monitor) {
Hans de Goede39920c82015-08-03 19:20:26 +02001297 case sunxi_monitor_none: return "none";
1298 case sunxi_monitor_dvi: return "dvi";
1299 case sunxi_monitor_hdmi: return "hdmi";
1300 case sunxi_monitor_lcd: return "lcd";
1301 case sunxi_monitor_vga: return "vga";
1302 case sunxi_monitor_composite_pal: return "composite-pal";
1303 case sunxi_monitor_composite_ntsc: return "composite-ntsc";
1304 case sunxi_monitor_composite_pal_m: return "composite-pal-m";
1305 case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
Hans de Goede1c092202014-12-21 14:37:45 +01001306 }
1307 return NULL; /* never reached */
1308}
1309
Hans de Goede5633a292015-02-02 17:13:29 +01001310ulong board_get_usable_ram_top(ulong total_size)
1311{
1312 return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE;
1313}
1314
Hans de Goedebf689342015-08-03 23:01:38 +02001315static bool sunxi_has_hdmi(void)
1316{
1317#ifdef CONFIG_VIDEO_HDMI
1318 return true;
1319#else
1320 return false;
1321#endif
1322}
1323
1324static bool sunxi_has_lcd(void)
1325{
1326 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
1327
1328 return lcd_mode[0] != 0;
1329}
1330
1331static bool sunxi_has_vga(void)
1332{
1333#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD
1334 return true;
1335#else
1336 return false;
1337#endif
1338}
1339
Hans de Goede39920c82015-08-03 19:20:26 +02001340static bool sunxi_has_composite(void)
1341{
1342#ifdef CONFIG_VIDEO_COMPOSITE
1343 return true;
1344#else
1345 return false;
1346#endif
1347}
1348
Hans de Goedebf689342015-08-03 23:01:38 +02001349static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1350{
1351 if (allow_hdmi && sunxi_has_hdmi())
1352 return sunxi_monitor_dvi;
1353 else if (sunxi_has_lcd())
1354 return sunxi_monitor_lcd;
1355 else if (sunxi_has_vga())
1356 return sunxi_monitor_vga;
Hans de Goede39920c82015-08-03 19:20:26 +02001357 else if (sunxi_has_composite())
1358 return sunxi_monitor_composite_pal;
Hans de Goedebf689342015-08-03 23:01:38 +02001359 else
1360 return sunxi_monitor_none;
1361}
1362
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001363void *video_hw_init(void)
1364{
1365 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
Hans de Goede5f339932014-12-19 14:03:40 +01001366 const struct ctfb_res_modes *mode;
Hans de Goede2dae8002014-12-21 16:28:32 +01001367 struct ctfb_res_modes custom;
Hans de Goede5f339932014-12-19 14:03:40 +01001368 const char *options;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001369#ifdef CONFIG_VIDEO_HDMI
Hans de Goede7fad8a92014-12-28 09:13:21 +01001370 int ret, hpd, hpd_delay, edid;
Hans de Goede2fbf0912014-12-23 23:04:35 +01001371#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001372 int i, overscan_offset, overscan_x, overscan_y;
1373 unsigned int fb_dma_addr;
Hans de Goede1c092202014-12-21 14:37:45 +01001374 char mon[16];
Hans de Goede2dae8002014-12-21 16:28:32 +01001375 char *lcd_mode = CONFIG_VIDEO_LCD_MODE;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001376
1377 memset(&sunxi_display, 0, sizeof(struct sunxi_display));
1378
Hans de Goede2dae8002014-12-21 16:28:32 +01001379 video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode,
1380 &sunxi_display.depth, &options);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001381#ifdef CONFIG_VIDEO_HDMI
Hans de Goede518cef22014-12-19 15:13:57 +01001382 hpd = video_get_option_int(options, "hpd", 1);
Hans de Goede7fad8a92014-12-28 09:13:21 +01001383 hpd_delay = video_get_option_int(options, "hpd_delay", 500);
Hans de Goede75481602014-12-19 16:05:12 +01001384 edid = video_get_option_int(options, "edid", 1);
Hans de Goede2fbf0912014-12-23 23:04:35 +01001385#endif
Hans de Goede58332f82015-08-05 00:06:47 +02001386 overscan_x = video_get_option_int(options, "overscan_x", -1);
1387 overscan_y = video_get_option_int(options, "overscan_y", -1);
Hans de Goedebf689342015-08-03 23:01:38 +02001388 sunxi_display.monitor = sunxi_get_default_mon(true);
Hans de Goede1c092202014-12-21 14:37:45 +01001389 video_get_option_string(options, "monitor", mon, sizeof(mon),
1390 sunxi_get_mon_desc(sunxi_display.monitor));
1391 for (i = 0; i <= SUNXI_MONITOR_LAST; i++) {
1392 if (strcmp(mon, sunxi_get_mon_desc(i)) == 0) {
1393 sunxi_display.monitor = i;
1394 break;
1395 }
1396 }
1397 if (i > SUNXI_MONITOR_LAST)
1398 printf("Unknown monitor: '%s', falling back to '%s'\n",
1399 mon, sunxi_get_mon_desc(sunxi_display.monitor));
Hans de Goede5f339932014-12-19 14:03:40 +01001400
Hans de Goede49d27032014-12-25 13:52:04 +01001401#ifdef CONFIG_VIDEO_HDMI
1402 /* If HDMI/DVI is selected do HPD & EDID, and handle fallback */
1403 if (sunxi_display.monitor == sunxi_monitor_dvi ||
1404 sunxi_display.monitor == sunxi_monitor_hdmi) {
Hans de Goede0e045212014-12-21 14:49:34 +01001405 /* Always call hdp_detect, as it also enables clocks, etc. */
Hans de Goede7fad8a92014-12-28 09:13:21 +01001406 ret = sunxi_hdmi_hpd_detect(hpd_delay);
Hans de Goede0e045212014-12-21 14:49:34 +01001407 if (ret) {
1408 printf("HDMI connected: ");
Hans de Goede2dae8002014-12-21 16:28:32 +01001409 if (edid && sunxi_hdmi_edid_get_mode(&custom) == 0)
1410 mode = &custom;
Hans de Goede49d27032014-12-25 13:52:04 +01001411 } else if (hpd) {
1412 sunxi_hdmi_shutdown();
Hans de Goedebf689342015-08-03 23:01:38 +02001413 sunxi_display.monitor = sunxi_get_default_mon(false);
Hans de Goede49d27032014-12-25 13:52:04 +01001414 } /* else continue with hdmi/dvi without a cable connected */
1415 }
1416#endif
Hans de Goede0e045212014-12-21 14:49:34 +01001417
Hans de Goede49d27032014-12-25 13:52:04 +01001418 switch (sunxi_display.monitor) {
1419 case sunxi_monitor_none:
1420 return NULL;
1421 case sunxi_monitor_dvi:
1422 case sunxi_monitor_hdmi:
Hans de Goedebf689342015-08-03 23:01:38 +02001423 if (!sunxi_has_hdmi()) {
1424 printf("HDMI/DVI not supported on this board\n");
1425 sunxi_display.monitor = sunxi_monitor_none;
1426 return NULL;
Hans de Goede2dae8002014-12-21 16:28:32 +01001427 }
Hans de Goedebf689342015-08-03 23:01:38 +02001428 break;
1429 case sunxi_monitor_lcd:
1430 if (!sunxi_has_lcd()) {
1431 printf("LCD not supported on this board\n");
1432 sunxi_display.monitor = sunxi_monitor_none;
1433 return NULL;
1434 }
1435 sunxi_display.depth = video_get_params(&custom, lcd_mode);
1436 mode = &custom;
1437 break;
Hans de Goede0e045212014-12-21 14:49:34 +01001438 case sunxi_monitor_vga:
Hans de Goedebf689342015-08-03 23:01:38 +02001439 if (!sunxi_has_vga()) {
1440 printf("VGA not supported on this board\n");
1441 sunxi_display.monitor = sunxi_monitor_none;
1442 return NULL;
1443 }
Hans de Goedee2bbdfb2014-12-24 12:17:07 +01001444 sunxi_display.depth = 18;
1445 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001446 case sunxi_monitor_composite_pal:
1447 case sunxi_monitor_composite_ntsc:
1448 case sunxi_monitor_composite_pal_m:
1449 case sunxi_monitor_composite_pal_nc:
1450 if (!sunxi_has_composite()) {
1451 printf("Composite video not supported on this board\n");
1452 sunxi_display.monitor = sunxi_monitor_none;
1453 return NULL;
1454 }
1455 if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
1456 sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
1457 mode = &composite_video_modes[0];
1458 else
1459 mode = &composite_video_modes[1];
1460 sunxi_display.depth = 24;
1461 break;
Hans de Goede75481602014-12-19 16:05:12 +01001462 }
1463
Hans de Goede58332f82015-08-05 00:06:47 +02001464 /* Yes these defaults are quite high, overscan on composite sucks... */
1465 if (overscan_x == -1)
1466 overscan_x = sunxi_is_composite() ? 32 : 0;
1467 if (overscan_y == -1)
1468 overscan_y = sunxi_is_composite() ? 20 : 0;
1469
Hans de Goede20779ec2015-02-02 18:00:53 +01001470 sunxi_display.fb_size =
1471 (mode->xres * mode->yres * 4 + 0xfff) & ~0xfff;
Hans de Goede58332f82015-08-05 00:06:47 +02001472 overscan_offset = (overscan_y * mode->xres + overscan_x) * 4;
1473 /* We want to keep the fb_base for simplefb page aligned, where as
1474 * the sunxi dma engines will happily accept an unaligned address. */
1475 if (overscan_offset)
1476 sunxi_display.fb_size += 0x1000;
1477
Hans de Goede20779ec2015-02-02 18:00:53 +01001478 if (sunxi_display.fb_size > CONFIG_SUNXI_MAX_FB_SIZE) {
1479 printf("Error need %dkB for fb, but only %dkB is reserved\n",
1480 sunxi_display.fb_size >> 10,
1481 CONFIG_SUNXI_MAX_FB_SIZE >> 10);
1482 return NULL;
1483 }
1484
Hans de Goede58332f82015-08-05 00:06:47 +02001485 printf("Setting up a %dx%d%s %s console (overscan %dx%d)\n",
1486 mode->xres, mode->yres,
Hans de Goedef6d9d322015-08-02 16:49:29 +02001487 (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "",
Hans de Goede58332f82015-08-05 00:06:47 +02001488 sunxi_get_mon_desc(sunxi_display.monitor),
1489 overscan_x, overscan_y);
Hans de Goedef6d9d322015-08-02 16:49:29 +02001490
Hans de Goede20779ec2015-02-02 18:00:53 +01001491 gd->fb_base = gd->bd->bi_dram[0].start +
1492 gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001493 sunxi_engines_init();
Hans de Goede58332f82015-08-05 00:06:47 +02001494
1495 fb_dma_addr = gd->fb_base - CONFIG_SYS_SDRAM_BASE;
1496 sunxi_display.fb_addr = gd->fb_base;
1497 if (overscan_offset) {
1498 fb_dma_addr += 0x1000 - (overscan_offset & 0xfff);
1499 sunxi_display.fb_addr += (overscan_offset + 0xfff) & ~0xfff;
1500 memset((void *)gd->fb_base, 0, sunxi_display.fb_size);
1501 flush_cache(gd->fb_base, sunxi_display.fb_size);
1502 }
1503 sunxi_mode_set(mode, fb_dma_addr);
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001504
1505 /*
1506 * These are the only members of this structure that are used. All the
Hans de Goede58332f82015-08-05 00:06:47 +02001507 * others are driver specific. The pitch is stored in plnSizeX.
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001508 */
Hans de Goede58332f82015-08-05 00:06:47 +02001509 graphic_device->frameAdrs = sunxi_display.fb_addr;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001510 graphic_device->gdfIndex = GDF_32BIT_X888RGB;
1511 graphic_device->gdfBytesPP = 4;
Hans de Goede58332f82015-08-05 00:06:47 +02001512 graphic_device->winSizeX = mode->xres - 2 * overscan_x;
1513 graphic_device->winSizeY = mode->yres - 2 * overscan_y;
1514 graphic_device->plnSizeX = mode->xres * graphic_device->gdfBytesPP;
Luc Verhaegen7f2c5212014-08-13 07:55:06 +02001515
1516 return graphic_device;
1517}
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001518
1519/*
1520 * Simplefb support.
1521 */
1522#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_VIDEO_DT_SIMPLEFB)
1523int sunxi_simplefb_setup(void *blob)
1524{
1525 static GraphicDevice *graphic_device = &sunxi_display.graphic_device;
1526 int offset, ret;
Hans de Goede5633a292015-02-02 17:13:29 +01001527 u64 start, size;
Hans de Goede2dae8002014-12-21 16:28:32 +01001528 const char *pipeline = NULL;
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001529
Hans de Goede7cd6f922015-01-19 08:44:07 +01001530#ifdef CONFIG_MACH_SUN4I
1531#define PIPELINE_PREFIX "de_fe0-"
1532#else
1533#define PIPELINE_PREFIX
1534#endif
1535
Hans de Goede2dae8002014-12-21 16:28:32 +01001536 switch (sunxi_display.monitor) {
1537 case sunxi_monitor_none:
1538 return 0;
1539 case sunxi_monitor_dvi:
1540 case sunxi_monitor_hdmi:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001541 pipeline = PIPELINE_PREFIX "de_be0-lcd0-hdmi";
Hans de Goede2dae8002014-12-21 16:28:32 +01001542 break;
1543 case sunxi_monitor_lcd:
Hans de Goede7cd6f922015-01-19 08:44:07 +01001544 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goede2dae8002014-12-21 16:28:32 +01001545 break;
1546 case sunxi_monitor_vga:
Hans de Goeded9786d22014-12-25 13:58:06 +01001547#ifdef CONFIG_VIDEO_VGA
Hans de Goede7cd6f922015-01-19 08:44:07 +01001548 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001549#elif defined CONFIG_VIDEO_VGA_VIA_LCD
Hans de Goede7cd6f922015-01-19 08:44:07 +01001550 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
Hans de Goeded9786d22014-12-25 13:58:06 +01001551#endif
Hans de Goede2dae8002014-12-21 16:28:32 +01001552 break;
Hans de Goede39920c82015-08-03 19:20:26 +02001553 case sunxi_monitor_composite_pal:
1554 case sunxi_monitor_composite_ntsc:
1555 case sunxi_monitor_composite_pal_m:
1556 case sunxi_monitor_composite_pal_nc:
1557 pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1558 break;
Hans de Goede2dae8002014-12-21 16:28:32 +01001559 }
1560
1561 /* Find a prefilled simpefb node, matching out pipeline config */
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001562 offset = fdt_node_offset_by_compatible(blob, -1,
1563 "allwinner,simple-framebuffer");
1564 while (offset >= 0) {
1565 ret = fdt_find_string(blob, offset, "allwinner,pipeline",
Hans de Goede2dae8002014-12-21 16:28:32 +01001566 pipeline);
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001567 if (ret == 0)
1568 break;
1569 offset = fdt_node_offset_by_compatible(blob, offset,
1570 "allwinner,simple-framebuffer");
1571 }
1572 if (offset < 0) {
1573 eprintf("Cannot setup simplefb: node not found\n");
1574 return 0; /* Keep older kernels working */
1575 }
1576
Hans de Goede5633a292015-02-02 17:13:29 +01001577 /*
1578 * Do not report the framebuffer as free RAM to the OS, note we cannot
1579 * use fdt_add_mem_rsv() here, because then it is still seen as RAM,
1580 * and e.g. Linux refuses to iomap RAM on ARM, see:
1581 * linux/arch/arm/mm/ioremap.c around line 301.
1582 */
1583 start = gd->bd->bi_dram[0].start;
Hans de Goede20779ec2015-02-02 18:00:53 +01001584 size = gd->bd->bi_dram[0].size - sunxi_display.fb_size;
Hans de Goede5633a292015-02-02 17:13:29 +01001585 ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
1586 if (ret) {
1587 eprintf("Cannot setup simplefb: Error reserving memory\n");
1588 return ret;
1589 }
1590
Hans de Goede58332f82015-08-05 00:06:47 +02001591 ret = fdt_setup_simplefb_node(blob, offset, sunxi_display.fb_addr,
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001592 graphic_device->winSizeX, graphic_device->winSizeY,
Hans de Goede58332f82015-08-05 00:06:47 +02001593 graphic_device->plnSizeX, "x8r8g8b8");
Luc Verhaegen2d7a0842014-08-13 07:55:07 +02001594 if (ret)
1595 eprintf("Cannot setup simplefb: Error setting properties\n");
1596
1597 return ret;
1598}
1599#endif /* CONFIG_OF_BOARD_SETUP && CONFIG_VIDEO_DT_SIMPLEFB */