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