blob: d3d07e5f83334ace424b13d514a25255fd391f4b [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roese913d1be2016-01-20 08:13:28 +01002/*
3 * Video driver for Marvell Armada XP SoC
4 *
5 * Initialization of LCD interface and setup of SPLASH screen image
Stefan Roese913d1be2016-01-20 08:13:28 +01006 */
7
8#include <common.h>
Stefan Roese6d9a98c2019-01-30 08:54:11 +01009#include <dm.h>
Simon Glasse6f6f9e2020-05-10 11:39:58 -060010#include <part.h>
Stefan Roese6d9a98c2019-01-30 08:54:11 +010011#include <video.h>
Simon Glass90526e92020-05-10 11:39:56 -060012#include <asm/cache.h>
Simon Glass336d4612020-02-03 07:36:16 -070013#include <dm/device_compat.h>
Simon Glassc05ed002020-05-10 11:40:11 -060014#include <linux/delay.h>
Stefan Roese913d1be2016-01-20 08:13:28 +010015#include <linux/mbus.h>
16#include <asm/io.h>
17#include <asm/arch/cpu.h>
18#include <asm/arch/soc.h>
19
Stefan Roese6d9a98c2019-01-30 08:54:11 +010020#define MVEBU_LCD_WIN_CONTROL(w) (0xf000 + ((w) << 4))
21#define MVEBU_LCD_WIN_BASE(w) (0xf004 + ((w) << 4))
22#define MVEBU_LCD_WIN_REMAP(w) (0xf00c + ((w) << 4))
Stefan Roese913d1be2016-01-20 08:13:28 +010023
Stefan Roese6d9a98c2019-01-30 08:54:11 +010024#define MVEBU_LCD_CFG_DMA_START_ADDR_0 0x00cc
25#define MVEBU_LCD_CFG_DMA_START_ADDR_1 0x00dc
Stefan Roese913d1be2016-01-20 08:13:28 +010026
Stefan Roese6d9a98c2019-01-30 08:54:11 +010027#define MVEBU_LCD_CFG_GRA_START_ADDR0 0x00f4
28#define MVEBU_LCD_CFG_GRA_START_ADDR1 0x00f8
29#define MVEBU_LCD_CFG_GRA_PITCH 0x00fc
30#define MVEBU_LCD_SPU_GRA_OVSA_HPXL_VLN 0x0100
31#define MVEBU_LCD_SPU_GRA_HPXL_VLN 0x0104
32#define MVEBU_LCD_SPU_GZM_HPXL_VLN 0x0108
33#define MVEBU_LCD_SPU_HWC_OVSA_HPXL_VLN 0x010c
34#define MVEBU_LCD_SPU_HWC_HPXL_VLN 0x0110
35#define MVEBU_LCD_SPUT_V_H_TOTAL 0x0114
36#define MVEBU_LCD_SPU_V_H_ACTIVE 0x0118
37#define MVEBU_LCD_SPU_H_PORCH 0x011c
38#define MVEBU_LCD_SPU_V_PORCH 0x0120
39#define MVEBU_LCD_SPU_BLANKCOLOR 0x0124
40#define MVEBU_LCD_SPU_ALPHA_COLOR1 0x0128
41#define MVEBU_LCD_SPU_ALPHA_COLOR2 0x012c
42#define MVEBU_LCD_SPU_COLORKEY_Y 0x0130
43#define MVEBU_LCD_SPU_COLORKEY_U 0x0134
44#define MVEBU_LCD_SPU_COLORKEY_V 0x0138
45#define MVEBU_LCD_CFG_RDREG4F 0x013c
46#define MVEBU_LCD_SPU_SPI_RXDATA 0x0140
47#define MVEBU_LCD_SPU_ISA_RXDATA 0x0144
48#define MVEBU_LCD_SPU_DBG_ISA 0x0148
Stefan Roese913d1be2016-01-20 08:13:28 +010049
Stefan Roese6d9a98c2019-01-30 08:54:11 +010050#define MVEBU_LCD_SPU_HWC_RDDAT 0x0158
51#define MVEBU_LCD_SPU_GAMMA_RDDAT 0x015c
52#define MVEBU_LCD_SPU_PALETTE_RDDAT 0x0160
53#define MVEBU_LCD_SPU_IOPAD_IN 0x0178
54#define MVEBU_LCD_FRAME_COUNT 0x017c
55#define MVEBU_LCD_SPU_DMA_CTRL0 0x0190
56#define MVEBU_LCD_SPU_DMA_CTRL1 0x0194
57#define MVEBU_LCD_SPU_SRAM_CTRL 0x0198
58#define MVEBU_LCD_SPU_SRAM_WRDAT 0x019c
59#define MVEBU_LCD_SPU_SRAM_PARA0 0x01a0
60#define MVEBU_LCD_SPU_SRAM_PARA1 0x01a4
61#define MVEBU_LCD_CFG_SCLK_DIV 0x01a8
62#define MVEBU_LCD_SPU_CONTRAST 0x01ac
63#define MVEBU_LCD_SPU_SATURATION 0x01b0
64#define MVEBU_LCD_SPU_CBSH_HUE 0x01b4
65#define MVEBU_LCD_SPU_DUMB_CTRL 0x01b8
66#define MVEBU_LCD_SPU_IOPAD_CONTROL 0x01bc
67#define MVEBU_LCD_SPU_IRQ_ENA_2 0x01d8
68#define MVEBU_LCD_SPU_IRQ_ISR_2 0x01dc
69#define MVEBU_LCD_SPU_IRQ_ENA 0x01c0
70#define MVEBU_LCD_SPU_IRQ_ISR 0x01c4
71#define MVEBU_LCD_ADLL_CTRL 0x01c8
72#define MVEBU_LCD_CLK_DIS 0x01cc
73#define MVEBU_LCD_VGA_HVSYNC_DELAY 0x01d4
74#define MVEBU_LCD_CLK_CFG_0 0xf0a0
75#define MVEBU_LCD_CLK_CFG_1 0xf0a4
76#define MVEBU_LCD_LVDS_CLK_CFG 0xf0ac
Stefan Roese913d1be2016-01-20 08:13:28 +010077
78#define MVEBU_LVDS_PADS_REG (MVEBU_SYSTEM_REG_BASE + 0xf0)
79
Stefan Roese6d9a98c2019-01-30 08:54:11 +010080enum {
81 /* Maximum LCD size we support */
82 LCD_MAX_WIDTH = 640,
83 LCD_MAX_HEIGHT = 480,
84 LCD_MAX_LOG2_BPP = VIDEO_BPP16,
85};
86
87struct mvebu_lcd_info {
88 u32 fb_base;
89 int x_res;
90 int y_res;
91 int x_fp;
92 int y_fp;
93 int x_bp;
94 int y_bp;
95};
96
97struct mvebu_video_priv {
98 uintptr_t regs;
99};
100
Stefan Roese913d1be2016-01-20 08:13:28 +0100101/* Setup Mbus Bridge Windows for LCD */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100102static void mvebu_lcd_conf_mbus_registers(uintptr_t regs)
Stefan Roese913d1be2016-01-20 08:13:28 +0100103{
104 const struct mbus_dram_target_info *dram;
105 int i;
106
107 dram = mvebu_mbus_dram_info();
108
109 /* Disable windows, set size/base/remap to 0 */
110 for (i = 0; i < 6; i++) {
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100111 writel(0, regs + MVEBU_LCD_WIN_CONTROL(i));
112 writel(0, regs + MVEBU_LCD_WIN_BASE(i));
113 writel(0, regs + MVEBU_LCD_WIN_REMAP(i));
Stefan Roese913d1be2016-01-20 08:13:28 +0100114 }
115
116 /* Write LCD bridge window registers */
117 for (i = 0; i < dram->num_cs; i++) {
118 const struct mbus_dram_window *cs = dram->cs + i;
119 writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
120 (dram->mbus_dram_target_id << 4) | 1,
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100121 regs + MVEBU_LCD_WIN_CONTROL(i));
Stefan Roese913d1be2016-01-20 08:13:28 +0100122
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100123 writel(cs->base & 0xffff0000, regs + MVEBU_LCD_WIN_BASE(i));
Stefan Roese913d1be2016-01-20 08:13:28 +0100124 }
125}
126
127/* Initialize LCD registers */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100128static void mvebu_lcd_register_init(struct mvebu_lcd_info *lcd_info,
129 uintptr_t regs)
Stefan Roese913d1be2016-01-20 08:13:28 +0100130{
131 /* Local variable for easier handling */
132 int x = lcd_info->x_res;
133 int y = lcd_info->y_res;
134 u32 val;
135
136 /* Setup Mbus Bridge Windows */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100137 mvebu_lcd_conf_mbus_registers(regs);
Stefan Roese913d1be2016-01-20 08:13:28 +0100138
139 /*
140 * Set LVDS Pads Control Register
141 * wr 0 182F0 FFE00000
142 */
143 clrbits_le32(MVEBU_LVDS_PADS_REG, 0x1f << 16);
144
145 /*
146 * Set the LCD_CFG_GRA_START_ADDR0/1 Registers
147 * This is supposed to point to the "physical" memory at memory
148 * end (currently 1GB-64MB but also may be 2GB-64MB).
149 * See also the Window 0 settings!
150 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100151 writel(lcd_info->fb_base, regs + MVEBU_LCD_CFG_GRA_START_ADDR0);
152 writel(lcd_info->fb_base, regs + MVEBU_LCD_CFG_GRA_START_ADDR1);
Stefan Roese913d1be2016-01-20 08:13:28 +0100153
154 /*
155 * Set the LCD_CFG_GRA_PITCH Register
156 * Bits 31-28: Duty Cycle of Backlight. value/16=High (0x8=Mid Setting)
157 * Bits 25-16: Backlight divider from 32kHz Clock
158 * (here 16=0x10 for 1kHz)
159 * Bits 15-00: Line Length in Bytes
160 * 240*2 (for RGB1555)=480=0x1E0
161 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100162 writel(0x80100000 + 2 * x, regs + MVEBU_LCD_CFG_GRA_PITCH);
Stefan Roese913d1be2016-01-20 08:13:28 +0100163
164 /*
165 * Set the LCD_SPU_GRA_OVSA_HPXL_VLN Register
166 * Bits 31-16: Vertical start of graphical overlay on screen
167 * Bits 15-00: Horizontal start of graphical overlay on screen
168 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100169 writel(0x00000000, regs + MVEBU_LCD_SPU_GRA_OVSA_HPXL_VLN);
Stefan Roese913d1be2016-01-20 08:13:28 +0100170
171 /*
172 * Set the LCD_SPU_GRA_HPXL_VLN Register
173 * Bits 31-16: Vertical size of graphical overlay 320=0x140
174 * Bits 15-00: Horizontal size of graphical overlay 240=0xF0
175 * Values before zooming
176 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100177 writel((y << 16) | x, regs + MVEBU_LCD_SPU_GRA_HPXL_VLN);
Stefan Roese913d1be2016-01-20 08:13:28 +0100178
179 /*
180 * Set the LCD_SPU_GZM_HPXL_VLN Register
181 * Bits 31-16: Vertical size of graphical overlay 320=0x140
182 * Bits 15-00: Horizontal size of graphical overlay 240=0xF0
183 * Values after zooming
184 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100185 writel((y << 16) | x, regs + MVEBU_LCD_SPU_GZM_HPXL_VLN);
Stefan Roese913d1be2016-01-20 08:13:28 +0100186
187 /*
188 * Set the LCD_SPU_HWC_OVSA_HPXL_VLN Register
189 * Bits 31-16: Vertical position of HW Cursor 320=0x140
190 * Bits 15-00: Horizontal position of HW Cursor 240=0xF0
191 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100192 writel((y << 16) | x, regs + MVEBU_LCD_SPU_HWC_OVSA_HPXL_VLN);
Stefan Roese913d1be2016-01-20 08:13:28 +0100193
194 /*
195 * Set the LCD_SPU_HWC_OVSA_HPXL_VLN Register
196 * Bits 31-16: Vertical size of HW Cursor
197 * Bits 15-00: Horizontal size of HW Cursor
198 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100199 writel(0x00000000, regs + MVEBU_LCD_SPU_HWC_HPXL_VLN);
Stefan Roese913d1be2016-01-20 08:13:28 +0100200
201 /*
202 * Set the LCD_SPU_HWC_OVSA_HPXL_VLN Register
203 * Bits 31-16: Screen total vertical lines:
204 * VSYNC = 1
205 * Vertical Front Porch = 2
206 * Vertical Lines = 320
207 * Vertical Back Porch = 2
208 * SUM = 325 = 0x0145
209 * Bits 15-00: Screen total horizontal pixels:
210 * HSYNC = 1
211 * Horizontal Front Porch = 44
212 * Horizontal Lines = 240
213 * Horizontal Back Porch = 2
214 * SUM = 287 = 0x011F
215 * Note: For the display the backporch is between SYNC and
216 * the start of the pixels.
217 * This is not certain for the Marvell (!?)
218 */
219 val = ((y + lcd_info->y_fp + lcd_info->y_bp + 1) << 16) |
220 (x + lcd_info->x_fp + lcd_info->x_bp + 1);
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100221 writel(val, regs + MVEBU_LCD_SPUT_V_H_TOTAL);
Stefan Roese913d1be2016-01-20 08:13:28 +0100222
223 /*
224 * Set the LCD_SPU_V_H_ACTIVE Register
225 * Bits 31-16: Screen active vertical lines 320=0x140
226 * Bits 15-00: Screen active horizontakl pixels 240=0x00F0
227 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100228 writel((y << 16) | x, regs + MVEBU_LCD_SPU_V_H_ACTIVE);
Stefan Roese913d1be2016-01-20 08:13:28 +0100229
230 /*
231 * Set the LCD_SPU_H_PORCH Register
232 * Bits 31-16: Screen horizontal backporch 44=0x2c
233 * Bits 15-00: Screen horizontal frontporch 2=0x02
234 * Note: The terms "front" and "back" for the Marvell seem to be
235 * exactly opposite to the display.
236 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100237 writel((lcd_info->x_fp << 16) | lcd_info->x_bp,
238 regs + MVEBU_LCD_SPU_H_PORCH);
Stefan Roese913d1be2016-01-20 08:13:28 +0100239
240 /*
241 * Set the LCD_SPU_V_PORCH Register
242 * Bits 31-16: Screen vertical backporch 2=0x02
243 * Bits 15-00: Screen vertical frontporch 2=0x02
244 * Note: The terms "front" and "back" for the Marvell seem to be exactly
245 * opposite to the display.
246 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100247 writel((lcd_info->y_fp << 16) | lcd_info->y_bp,
248 regs + MVEBU_LCD_SPU_V_PORCH);
Stefan Roese913d1be2016-01-20 08:13:28 +0100249
250 /*
251 * Set the LCD_SPU_BLANKCOLOR Register
252 * This should be black = 0
253 * For tests this is magenta=00FF00FF
254 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100255 writel(0x00FF00FF, regs + MVEBU_LCD_SPU_BLANKCOLOR);
Stefan Roese913d1be2016-01-20 08:13:28 +0100256
257 /*
258 * Registers in the range of 0x0128 to 0x012C are colors for the cursor
259 * Registers in the range of 0x0130 to 0x0138 are colors for video
260 * color keying
261 */
262
263 /*
264 * Set the LCD_SPU_RDREG4F Register
265 * Bits 31-12: Reservd
266 * Bit 11: SRAM Wait
267 * Bit 10: Smart display fast TX (must be 1)
268 * Bit 9: DMA Arbitration Video/Graphics overlay: 0=interleaved
269 * Bit 8: FIFO watermark for DMA: 0=disable
270 * Bits 07-00: Empty 8B FIFO entries to trigger DMA, default=0x80
271 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100272 writel(0x00000780, regs + MVEBU_LCD_CFG_RDREG4F);
Stefan Roese913d1be2016-01-20 08:13:28 +0100273
274 /*
275 * Set the LCD_SPU_DMACTRL 0 Register
276 * Bit 31: Disable overlay blending 1=disable
277 * Bit 30: Gamma correction enable, 0=disable
278 * Bit 29: Video Contrast/Saturation/Hue Adjust enable, 0=disable
279 * Bit 28: Color palette enable, 0=disable
280 * Bit 27: DMA AXI Arbiter, 1=default
281 * Bit 26: HW Cursor 1-bit mode
282 * Bit 25: HW Cursor or 1- or 2-bit mode
283 * Bit 24: HW Cursor enabled, 0=disable
284 * Bits 23-20: Graphics Memory Color Format: 0x1=RGB1555
285 * Bits 19-16: Video Memory Color Format: 0x1=RGB1555
286 * Bit 15: Memory Toggle between frame 0 and 1: 0=disable
287 * Bit 14: Graphics horizontal scaling enable: 0=disable
288 * Bit 13: Graphics test mode: 0=disable
289 * Bit 12: Graphics SWAP R and B: 0=disable
290 * Bit 11: Graphics SWAP U and V: 0=disable
291 * Bit 10: Graphics SWAP Y and U/V: 0=disable
292 * Bit 09: Graphic YUV to RGB Conversion: 0=disable
293 * Bit 08: Graphic Transfer: 1=enable
294 * Bit 07: Memory Toggle: 0=disable
295 * Bit 06: Video horizontal scaling enable: 0=disable
296 * Bit 05: Video test mode: 0=disable
297 * Bit 04: Video SWAP R and B: 0=disable
298 * Bit 03: Video SWAP U and V: 0=disable
299 * Bit 02: Video SWAP Y and U/V: 0=disable
300 * Bit 01: Video YUV to RGB Conversion: 0=disable
301 * Bit 00: Video Transfer: 0=disable
302 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100303 writel(0x88111100, regs + MVEBU_LCD_SPU_DMA_CTRL0);
Stefan Roese913d1be2016-01-20 08:13:28 +0100304
305 /*
306 * Set the LCD_SPU_DMA_CTRL1 Register
307 * Bit 31: Manual DMA Trigger = 0
308 * Bits 30-28: DMA Trigger Source: 0x2 VSYNC
309 * Bit 28: VSYNC_INV: 0=Rising Edge, 1=Falling Edge
310 * Bits 26-24: Color Key Mode: 0=disable
311 * Bit 23: Fill low bits: 0=fill with zeroes
312 * Bit 22: Reserved
313 * Bit 21: Gated Clock: 0=disable
314 * Bit 20: Power Save enable: 0=disable
315 * Bits 19-18: Reserved
316 * Bits 17-16: Configure Video/Graphic Path: 0x1: Graphic path alpha.
317 * Bits 15-08: Configure Alpha: 0x00.
318 * Bits 07-00: Reserved.
319 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100320 writel(0x20010000, regs + MVEBU_LCD_SPU_DMA_CTRL1);
Stefan Roese913d1be2016-01-20 08:13:28 +0100321
322 /*
323 * Set the LCD_SPU_SRAM_CTRL Register
324 * Reset to default = 0000C000
325 * Bits 15-14: SRAM control: init=0x3, Read=0, Write=2
326 * Bits 11-08: SRAM address ID: 0=gamma_yr, 1=gammy_ug, 2=gamma_vb,
327 * 3=palette, 15=cursor
328 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100329 writel(0x0000C000, regs + MVEBU_LCD_SPU_SRAM_CTRL);
Stefan Roese913d1be2016-01-20 08:13:28 +0100330
331 /*
332 * LCD_SPU_SRAM_WRDAT register: 019C
333 * LCD_SPU_SRAM_PARA0 register: 01A0
334 * LCD_SPU_SRAM_PARA1 register: 01A4 - Cursor control/Power settings
335 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100336 writel(0x00000000, regs + MVEBU_LCD_SPU_SRAM_PARA1);
Stefan Roese913d1be2016-01-20 08:13:28 +0100337
338
339 /* Clock settings in the at 01A8 and in the range F0A0 see below */
340
341 /*
342 * Set LCD_SPU_CONTRAST
343 * Bits 31-16: Brightness sign ext. 8-bit value +255 to -255: default=0
344 * Bits 15-00: Contrast sign ext. 8-bit value +255 to -255: default=0
345 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100346 writel(0x00000000, regs + MVEBU_LCD_SPU_CONTRAST);
Stefan Roese913d1be2016-01-20 08:13:28 +0100347
348 /*
349 * Set LCD_SPU_SATURATION
350 * Bits 31-16: Multiplier signed 4.12 fixed point value
351 * Bits 15-00: Saturation signed 4.12 fixed point value
352 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100353 writel(0x10001000, regs + MVEBU_LCD_SPU_SATURATION);
Stefan Roese913d1be2016-01-20 08:13:28 +0100354
355 /*
356 * Set LCD_SPU_HUE
357 * Bits 31-16: Sine signed 2.14 fixed point value
358 * Bits 15-00: Cosine signed 2.14 fixed point value
359 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100360 writel(0x00000000, regs + MVEBU_LCD_SPU_CBSH_HUE);
Stefan Roese913d1be2016-01-20 08:13:28 +0100361
362 /*
363 * Set LCD_SPU_DUMB_CTRL
364 * Bits 31-28: LCD Type: 3=18 bit RGB | 6=24 bit RGB888
365 * Bits 27-12: Reserved
366 * Bit 11: LCD DMA Pipeline Enable: 1=Enable
367 * Bits 10-09: Reserved
368 * Bit 8: LCD GPIO pin (??)
369 * Bit 7: Reverse RGB
370 * Bit 6: Invert composite blank signal DE/EN (??)
371 * Bit 5: Invert composite sync signal
372 * Bit 4: Invert Pixel Valid Enable DE/EN (??)
373 * Bit 3: Invert VSYNC
374 * Bit 2: Invert HSYNC
375 * Bit 1: Invert Pixel Clock
376 * Bit 0: Enable LCD Panel: 1=Enable
377 * Question: Do we have to disable Smart and Dumb LCD
378 * and separately enable LVDS?
379 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100380 writel(0x6000080F, regs + MVEBU_LCD_SPU_DUMB_CTRL);
Stefan Roese913d1be2016-01-20 08:13:28 +0100381
382 /*
383 * Set LCD_SPU_IOPAD_CTRL
384 * Bits 31-20: Reserved
385 * Bits 19-18: Vertical Interpolation: 0=Disable
386 * Bits 17-16: Reserved
387 * Bit 15: Graphics Vertical Mirror enable: 0=disable
388 * Bit 14: Reserved
389 * Bit 13: Video Vertical Mirror enable: 0=disable
390 * Bit 12: Reserved
391 * Bit 11: Command Vertical Mirror enable: 0=disable
392 * Bit 10: Reserved
393 * Bits 09-08: YUV to RGB Color space conversion: 0 (Not used)
394 * Bits 07-04: AXI Bus Master: 0x4: no crossing of 4k boundary,
395 * 128 Bytes burst
396 * Bits 03-00: LCD pins: ??? 0=24-bit Dump panel ??
397 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100398 writel(0x000000C0, regs + MVEBU_LCD_SPU_IOPAD_CONTROL);
Stefan Roese913d1be2016-01-20 08:13:28 +0100399
400 /*
401 * Set SUP_IRQ_ENA_2: Disable all interrupts
402 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100403 writel(0x00000000, regs + MVEBU_LCD_SPU_IRQ_ENA_2);
Stefan Roese913d1be2016-01-20 08:13:28 +0100404
405 /*
406 * Set SUP_IRQ_ENA: Disable all interrupts.
407 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100408 writel(0x00000000, regs + MVEBU_LCD_SPU_IRQ_ENA);
Stefan Roese913d1be2016-01-20 08:13:28 +0100409
410 /*
411 * Set up ADDL Control Register
412 * Bits 31-29: 0x0 = Fastest Delay Line (default)
413 * 0x3 = Slowest Delay Line (default)
414 * Bit 28: Calibration done status.
415 * Bit 27: Reserved
416 * Bit 26: Set Pixel Clock to ADDL output
417 * Bit 25: Reduce CAL Enable
418 * Bits 24-22: Manual calibration value.
419 * Bit 21: Manual calibration enable.
420 * Bit 20: Restart Auto Cal
421 * Bits 19-16: Calibration Threshold voltage, default= 0x2
422 * Bite 15-14: Reserved
423 * Bits 13-11: Divisor for ADDL Clock: 0x1=/2, 0x3=/8, 0x5=/16
424 * Bit 10: Power Down ADDL module, default = 1!
425 * Bits 09-08: Test point configuration: 0x2=Bias, 0x3=High-z
426 * Bit 07: Reset ADDL
427 * Bit 06: Invert ADLL Clock
428 * Bits 05-00: Delay taps, 0x3F=Half Cycle, 0x00=No delay
429 * Note: ADLL is used for a VGA interface with DAC - not used here
430 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100431 writel(0x00000000, regs + MVEBU_LCD_ADLL_CTRL);
Stefan Roese913d1be2016-01-20 08:13:28 +0100432
433 /*
434 * Set the LCD_CLK_DIS Register:
435 * Bits 3 and 4 must be 1
436 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100437 writel(0x00000018, regs + MVEBU_LCD_CLK_DIS);
Stefan Roese913d1be2016-01-20 08:13:28 +0100438
439 /*
440 * Set the LCD_VGA_HSYNC/VSYNC Delay Register:
441 * Bits 03-00: Sets the delay for the HSYNC and VSYNC signals
442 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100443 writel(0x00000000, regs + MVEBU_LCD_VGA_HVSYNC_DELAY);
Stefan Roese913d1be2016-01-20 08:13:28 +0100444
445 /*
446 * Clock registers
447 * See page 475 in the functional spec.
448 */
449
450 /* Step 1 and 2: Disable the PLL */
451
452 /*
453 * Disable PLL, see "LCD Clock Configuration 1 Register" below
454 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100455 writel(0x8FF40007, regs + MVEBU_LCD_CLK_CFG_1);
Stefan Roese913d1be2016-01-20 08:13:28 +0100456
457 /*
458 * Powerdown, see "LCD Clock Configuration 0 Register" below
459 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100460 writel(0x94000174, regs + MVEBU_LCD_CLK_CFG_0);
Stefan Roese913d1be2016-01-20 08:13:28 +0100461
462 /*
463 * Set the LCD_CFG_SCLK_DIV Register
464 * This is set fix to 0x40000001 for the LVDS output:
465 * Bits 31-30: SCLCK Source: 0=AXIBus, 1=AHBus, 2=PLLDivider0
466 * Bits 15-01: Clock Divider: Bypass for LVDS=0x0001
467 * See page 475 in section 28.5.
468 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100469 writel(0x80000001, regs + MVEBU_LCD_CFG_SCLK_DIV);
Stefan Roese913d1be2016-01-20 08:13:28 +0100470
471 /*
472 * Set the LCD Clock Configuration 0 Register:
473 * Bit 31: Powerdown: 0=Power up
474 * Bits 30-29: Reserved
475 * Bits 28-26: PLL_KDIV: This encodes K
476 * K=16 => 0x5
477 * Bits 25-17: PLL_MDIV: This is M-1:
478 * M=1 => 0x0
479 * Bits 16-13: VCO band: 0x1 for 700-920MHz
480 * Bits 12-04: PLL_NDIV: This is N-1 and corresponds to R1_CTRL!
481 * N=28=0x1C => 0x1B
482 * Bits 03-00: R1_CTRL (for N=28 => 0x4)
483 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100484 writel(0x940021B4, regs + MVEBU_LCD_CLK_CFG_0);
Stefan Roese913d1be2016-01-20 08:13:28 +0100485
486 /*
487 * Set the LCD Clock Configuration 1 Register:
488 * Bits 31-19: Reserved
489 * Bit 18: Select PLL: Core PLL, 1=Dedicated PPL
490 * Bit 17: Clock Output Enable: 0=disable, 1=enable
491 * Bit 16: Select RefClk: 0=RefClk (25MHz), 1=External
492 * Bit 15: Half-Div, Device Clock by DIV+0.5*Half-Dev
493 * Bits 14-13: Reserved
494 * Bits 12-00: PLL Full Divider [Note: Assumed to be the Post-Divider
495 * M' for LVDS=7!]
496 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100497 writel(0x8FF40007, regs + MVEBU_LCD_CLK_CFG_1);
Stefan Roese913d1be2016-01-20 08:13:28 +0100498
499 /*
500 * Set the LVDS Clock Configuration Register:
501 * Bit 31: Clock Gating for the input clock to the LVDS
502 * Bit 30: LVDS Serializer enable: 1=Enabled
503 * Bits 29-11: Reserved
504 * Bit 11-08: LVDS Clock delay: 0x02 (default): by 2 pixel clock/7
505 * Bits 07-02: Reserved
506 * Bit 01: 24bbp Option: 0=Option_1,1=Option2
507 * Bit 00: 1=24bbp Panel: 0=18bpp Panel
508 * Note: Bits 0 and must be verified with the help of the
509 * Interface/display
510 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100511 writel(0xC0000201, regs + MVEBU_LCD_LVDS_CLK_CFG);
Stefan Roese913d1be2016-01-20 08:13:28 +0100512
513 /*
514 * Power up PLL (Clock Config 0)
515 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100516 writel(0x140021B4, regs + MVEBU_LCD_CLK_CFG_0);
Stefan Roese913d1be2016-01-20 08:13:28 +0100517
518 /* wait 10 ms */
519 mdelay(10);
520
521 /*
522 * Enable PLL (Clock Config 1)
523 */
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100524 writel(0x8FF60007, regs + MVEBU_LCD_CLK_CFG_1);
525}
526
527static int mvebu_video_probe(struct udevice *dev)
528{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700529 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100530 struct video_priv *uc_priv = dev_get_uclass_priv(dev);
531 struct mvebu_video_priv *priv = dev_get_priv(dev);
532 struct mvebu_lcd_info lcd_info;
533 struct display_timing timings;
534 u32 fb_start, fb_end;
535 int ret;
536
537 priv->regs = dev_read_addr(dev);
538 if (priv->regs == FDT_ADDR_T_NONE) {
539 dev_err(dev, "failed to get LCD address\n");
540 return -ENXIO;
541 }
542
543 ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings);
544 if (ret) {
545 dev_err(dev, "failed to get any display timings\n");
546 return -EINVAL;
547 }
548
549 /* Use DT timing (resolution) in internal info struct */
550 lcd_info.fb_base = plat->base;
551 lcd_info.x_res = timings.hactive.typ;
552 lcd_info.x_fp = timings.hfront_porch.typ;
553 lcd_info.x_bp = timings.hback_porch.typ;
554 lcd_info.y_res = timings.vactive.typ;
555 lcd_info.y_fp = timings.vfront_porch.typ;
556 lcd_info.y_bp = timings.vback_porch.typ;
557
558 /* Initialize the LCD controller */
559 mvebu_lcd_register_init(&lcd_info, priv->regs);
560
561 /* Enable dcache for the frame buffer */
562 fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
563 fb_end = plat->base + plat->size;
564 fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT);
565 mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
566 DCACHE_WRITEBACK);
567 video_set_flush_dcache(dev, true);
568
569 uc_priv->xsize = lcd_info.x_res;
570 uc_priv->ysize = lcd_info.y_res;
571 uc_priv->bpix = VIDEO_BPP16; /* Uses RGB555 format */
Stefan Roese913d1be2016-01-20 08:13:28 +0100572
573 return 0;
574}
575
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100576static int mvebu_video_bind(struct udevice *dev)
Stefan Roese913d1be2016-01-20 08:13:28 +0100577{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700578 struct video_uc_plat *plat = dev_get_uclass_plat(dev);
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100579
580 plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
581 (1 << LCD_MAX_LOG2_BPP) / 8;
582
583 return 0;
Stefan Roese913d1be2016-01-20 08:13:28 +0100584}
585
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100586static const struct udevice_id mvebu_video_ids[] = {
587 { .compatible = "marvell,armada-xp-lcd" },
588 { }
589};
Stefan Roese913d1be2016-01-20 08:13:28 +0100590
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100591U_BOOT_DRIVER(mvebu_video) = {
592 .name = "mvebu_video",
593 .id = UCLASS_VIDEO,
594 .of_match = mvebu_video_ids,
595 .bind = mvebu_video_bind,
596 .probe = mvebu_video_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700597 .priv_auto = sizeof(struct mvebu_video_priv),
Stefan Roese6d9a98c2019-01-30 08:54:11 +0100598};