1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
213402868SStefano Babic /*
313402868SStefano Babic * Porting to u-boot:
413402868SStefano Babic *
513402868SStefano Babic * (C) Copyright 2011
613402868SStefano Babic * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
713402868SStefano Babic *
813402868SStefano Babic * Copyright (C) 2008-2009 MontaVista Software Inc.
913402868SStefano Babic * Copyright (C) 2008-2009 Texas Instruments Inc
1013402868SStefano Babic *
1113402868SStefano Babic * Based on the LCD driver for TI Avalanche processors written by
1213402868SStefano Babic * Ajay Singh and Shalom Hai.
1313402868SStefano Babic */
1413402868SStefano Babic
1513402868SStefano Babic #include <common.h>
16963be689SNiko Mauno #include <memalign.h>
1713402868SStefano Babic #include <video_fb.h>
1813402868SStefano Babic #include <linux/list.h>
1913402868SStefano Babic #include <linux/fb.h>
2013402868SStefano Babic
211221ce45SMasahiro Yamada #include <linux/errno.h>
2213402868SStefano Babic #include <asm/io.h>
2313402868SStefano Babic #include <asm/arch/hardware.h>
2413402868SStefano Babic
2513402868SStefano Babic #include "videomodes.h"
260017f9eeSHeiko Schocher #include "da8xx-fb.h"
2713402868SStefano Babic
28765f2f08SHeiko Schocher #if !defined(DA8XX_LCD_CNTL_BASE)
29765f2f08SHeiko Schocher #define DA8XX_LCD_CNTL_BASE DAVINCI_LCD_CNTL_BASE
30765f2f08SHeiko Schocher #endif
31765f2f08SHeiko Schocher
3213402868SStefano Babic #define DRIVER_NAME "da8xx_lcdc"
3313402868SStefano Babic
34765f2f08SHeiko Schocher #define LCD_VERSION_1 1
35765f2f08SHeiko Schocher #define LCD_VERSION_2 2
36765f2f08SHeiko Schocher
3713402868SStefano Babic /* LCD Status Register */
3813402868SStefano Babic #define LCD_END_OF_FRAME1 (1 << 9)
3913402868SStefano Babic #define LCD_END_OF_FRAME0 (1 << 8)
4013402868SStefano Babic #define LCD_PL_LOAD_DONE (1 << 6)
4113402868SStefano Babic #define LCD_FIFO_UNDERFLOW (1 << 5)
4213402868SStefano Babic #define LCD_SYNC_LOST (1 << 2)
4313402868SStefano Babic
4413402868SStefano Babic /* LCD DMA Control Register */
4513402868SStefano Babic #define LCD_DMA_BURST_SIZE(x) ((x) << 4)
4613402868SStefano Babic #define LCD_DMA_BURST_1 0x0
4713402868SStefano Babic #define LCD_DMA_BURST_2 0x1
4813402868SStefano Babic #define LCD_DMA_BURST_4 0x2
4913402868SStefano Babic #define LCD_DMA_BURST_8 0x3
5013402868SStefano Babic #define LCD_DMA_BURST_16 0x4
51765f2f08SHeiko Schocher #define LCD_V1_END_OF_FRAME_INT_ENA (1 << 2)
52765f2f08SHeiko Schocher #define LCD_V2_END_OF_FRAME0_INT_ENA (1 << 8)
53765f2f08SHeiko Schocher #define LCD_V2_END_OF_FRAME1_INT_ENA (1 << 9)
5413402868SStefano Babic #define LCD_DUAL_FRAME_BUFFER_ENABLE (1 << 0)
5513402868SStefano Babic
56765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_MODE (1 << 25)
57765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_UNPACK (1 << 26)
58765f2f08SHeiko Schocher
5913402868SStefano Babic /* LCD Control Register */
6013402868SStefano Babic #define LCD_CLK_DIVISOR(x) ((x) << 8)
6113402868SStefano Babic #define LCD_RASTER_MODE 0x01
6213402868SStefano Babic
6313402868SStefano Babic /* LCD Raster Control Register */
6413402868SStefano Babic #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20)
6513402868SStefano Babic #define PALETTE_AND_DATA 0x00
6613402868SStefano Babic #define PALETTE_ONLY 0x01
6713402868SStefano Babic #define DATA_ONLY 0x02
6813402868SStefano Babic
6913402868SStefano Babic #define LCD_MONO_8BIT_MODE (1 << 9)
7013402868SStefano Babic #define LCD_RASTER_ORDER (1 << 8)
7113402868SStefano Babic #define LCD_TFT_MODE (1 << 7)
72765f2f08SHeiko Schocher #define LCD_V1_UNDERFLOW_INT_ENA (1 << 6)
73765f2f08SHeiko Schocher #define LCD_V2_UNDERFLOW_INT_ENA (1 << 5)
74765f2f08SHeiko Schocher #define LCD_V1_PL_INT_ENA (1 << 4)
75765f2f08SHeiko Schocher #define LCD_V2_PL_INT_ENA (1 << 6)
7613402868SStefano Babic #define LCD_MONOCHROME_MODE (1 << 1)
7713402868SStefano Babic #define LCD_RASTER_ENABLE (1 << 0)
7813402868SStefano Babic #define LCD_TFT_ALT_ENABLE (1 << 23)
7913402868SStefano Babic #define LCD_STN_565_ENABLE (1 << 24)
80765f2f08SHeiko Schocher #define LCD_V2_DMA_CLK_EN (1 << 2)
81765f2f08SHeiko Schocher #define LCD_V2_LIDD_CLK_EN (1 << 1)
82765f2f08SHeiko Schocher #define LCD_V2_CORE_CLK_EN (1 << 0)
83765f2f08SHeiko Schocher #define LCD_V2_LPP_B10 26
84765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_MODE (1 << 25)
85765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_UNPACK (1 << 26)
8613402868SStefano Babic
8713402868SStefano Babic /* LCD Raster Timing 2 Register */
8813402868SStefano Babic #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
8913402868SStefano Babic #define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8)
9013402868SStefano Babic #define LCD_SYNC_CTRL (1 << 25)
9113402868SStefano Babic #define LCD_SYNC_EDGE (1 << 24)
9213402868SStefano Babic #define LCD_INVERT_PIXEL_CLOCK (1 << 22)
9313402868SStefano Babic #define LCD_INVERT_LINE_CLOCK (1 << 21)
9413402868SStefano Babic #define LCD_INVERT_FRAME_CLOCK (1 << 20)
9513402868SStefano Babic
96765f2f08SHeiko Schocher /* Clock registers available only on Version 2 */
97765f2f08SHeiko Schocher #define LCD_CLK_MAIN_RESET (1 << 3)
9813402868SStefano Babic /* LCD Block */
9913402868SStefano Babic struct da8xx_lcd_regs {
10013402868SStefano Babic u32 revid;
10113402868SStefano Babic u32 ctrl;
10213402868SStefano Babic u32 stat;
10313402868SStefano Babic u32 lidd_ctrl;
10413402868SStefano Babic u32 lidd_cs0_conf;
10513402868SStefano Babic u32 lidd_cs0_addr;
10613402868SStefano Babic u32 lidd_cs0_data;
10713402868SStefano Babic u32 lidd_cs1_conf;
10813402868SStefano Babic u32 lidd_cs1_addr;
10913402868SStefano Babic u32 lidd_cs1_data;
11013402868SStefano Babic u32 raster_ctrl;
11113402868SStefano Babic u32 raster_timing_0;
11213402868SStefano Babic u32 raster_timing_1;
11313402868SStefano Babic u32 raster_timing_2;
11413402868SStefano Babic u32 raster_subpanel;
11513402868SStefano Babic u32 reserved;
11613402868SStefano Babic u32 dma_ctrl;
11713402868SStefano Babic u32 dma_frm_buf_base_addr_0;
11813402868SStefano Babic u32 dma_frm_buf_ceiling_addr_0;
11913402868SStefano Babic u32 dma_frm_buf_base_addr_1;
12013402868SStefano Babic u32 dma_frm_buf_ceiling_addr_1;
121765f2f08SHeiko Schocher u32 resv1;
122765f2f08SHeiko Schocher u32 raw_stat;
123765f2f08SHeiko Schocher u32 masked_stat;
124765f2f08SHeiko Schocher u32 int_ena_set;
125765f2f08SHeiko Schocher u32 int_ena_clr;
126765f2f08SHeiko Schocher u32 end_of_int_ind;
127765f2f08SHeiko Schocher /* Clock registers available only on Version 2 */
128765f2f08SHeiko Schocher u32 clk_ena;
129765f2f08SHeiko Schocher u32 clk_reset;
13013402868SStefano Babic };
13113402868SStefano Babic
13213402868SStefano Babic #define LCD_NUM_BUFFERS 1
13313402868SStefano Babic
13413402868SStefano Babic #define WSI_TIMEOUT 50
13513402868SStefano Babic #define PALETTE_SIZE 256
13613402868SStefano Babic #define LEFT_MARGIN 64
13713402868SStefano Babic #define RIGHT_MARGIN 64
13813402868SStefano Babic #define UPPER_MARGIN 32
13913402868SStefano Babic #define LOWER_MARGIN 32
140765f2f08SHeiko Schocher #define WAIT_FOR_FRAME_DONE true
141765f2f08SHeiko Schocher #define NO_WAIT_FOR_FRAME_DONE false
14213402868SStefano Babic
14313402868SStefano Babic #define calc_fbsize() (panel.plnSizeX * panel.plnSizeY * panel.gdfBytesPP)
14413402868SStefano Babic
14513402868SStefano Babic static struct da8xx_lcd_regs *da8xx_fb_reg_base;
14613402868SStefano Babic
14713402868SStefano Babic DECLARE_GLOBAL_DATA_PTR;
14813402868SStefano Babic
14913402868SStefano Babic /* graphics setup */
15013402868SStefano Babic static GraphicDevice gpanel;
15113402868SStefano Babic static const struct da8xx_panel *lcd_panel;
15213402868SStefano Babic static struct fb_info *da8xx_fb_info;
15313402868SStefano Babic static int bits_x_pixel;
154765f2f08SHeiko Schocher static unsigned int lcd_revision;
155765f2f08SHeiko Schocher const struct lcd_ctrl_config *da8xx_lcd_cfg;
15613402868SStefano Babic
lcdc_read(u32 * addr)15713402868SStefano Babic static inline unsigned int lcdc_read(u32 *addr)
15813402868SStefano Babic {
15913402868SStefano Babic return (unsigned int)readl(addr);
16013402868SStefano Babic }
16113402868SStefano Babic
lcdc_write(unsigned int val,u32 * addr)16213402868SStefano Babic static inline void lcdc_write(unsigned int val, u32 *addr)
16313402868SStefano Babic {
16413402868SStefano Babic writel(val, addr);
16513402868SStefano Babic }
16613402868SStefano Babic
16713402868SStefano Babic struct da8xx_fb_par {
16813402868SStefano Babic u32 p_palette_base;
16913402868SStefano Babic unsigned char *v_palette_base;
17013402868SStefano Babic dma_addr_t vram_phys;
17113402868SStefano Babic unsigned long vram_size;
17213402868SStefano Babic void *vram_virt;
17313402868SStefano Babic unsigned int dma_start;
17413402868SStefano Babic unsigned int dma_end;
17513402868SStefano Babic struct clk *lcdc_clk;
17613402868SStefano Babic int irq;
17713402868SStefano Babic unsigned short pseudo_palette[16];
17813402868SStefano Babic unsigned int palette_sz;
17913402868SStefano Babic unsigned int pxl_clk;
18013402868SStefano Babic int blank;
18113402868SStefano Babic int vsync_flag;
18213402868SStefano Babic int vsync_timeout;
18313402868SStefano Babic };
18413402868SStefano Babic
18513402868SStefano Babic
18613402868SStefano Babic /* Variable Screen Information */
18713402868SStefano Babic static struct fb_var_screeninfo da8xx_fb_var = {
18813402868SStefano Babic .xoffset = 0,
18913402868SStefano Babic .yoffset = 0,
19013402868SStefano Babic .transp = {0, 0, 0},
19113402868SStefano Babic .nonstd = 0,
19213402868SStefano Babic .activate = 0,
19313402868SStefano Babic .height = -1,
19413402868SStefano Babic .width = -1,
19513402868SStefano Babic .pixclock = 46666, /* 46us - AUO display */
19613402868SStefano Babic .accel_flags = 0,
19713402868SStefano Babic .left_margin = LEFT_MARGIN,
19813402868SStefano Babic .right_margin = RIGHT_MARGIN,
19913402868SStefano Babic .upper_margin = UPPER_MARGIN,
20013402868SStefano Babic .lower_margin = LOWER_MARGIN,
20113402868SStefano Babic .sync = 0,
20213402868SStefano Babic .vmode = FB_VMODE_NONINTERLACED
20313402868SStefano Babic };
20413402868SStefano Babic
20513402868SStefano Babic static struct fb_fix_screeninfo da8xx_fb_fix = {
20613402868SStefano Babic .id = "DA8xx FB Drv",
20713402868SStefano Babic .type = FB_TYPE_PACKED_PIXELS,
20813402868SStefano Babic .type_aux = 0,
20913402868SStefano Babic .visual = FB_VISUAL_PSEUDOCOLOR,
21013402868SStefano Babic .xpanstep = 0,
21113402868SStefano Babic .ypanstep = 1,
21213402868SStefano Babic .ywrapstep = 0,
21313402868SStefano Babic .accel = FB_ACCEL_NONE
21413402868SStefano Babic };
21513402868SStefano Babic
21613402868SStefano Babic /* Enable the Raster Engine of the LCD Controller */
lcd_enable_raster(void)21713402868SStefano Babic static inline void lcd_enable_raster(void)
21813402868SStefano Babic {
21913402868SStefano Babic u32 reg;
22013402868SStefano Babic
221765f2f08SHeiko Schocher /* Put LCDC in reset for several cycles */
222765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2)
223765f2f08SHeiko Schocher lcdc_write(LCD_CLK_MAIN_RESET,
224765f2f08SHeiko Schocher &da8xx_fb_reg_base->clk_reset);
225765f2f08SHeiko Schocher
226765f2f08SHeiko Schocher udelay(1000);
227765f2f08SHeiko Schocher /* Bring LCDC out of reset */
228765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2)
229765f2f08SHeiko Schocher lcdc_write(0,
230765f2f08SHeiko Schocher &da8xx_fb_reg_base->clk_reset);
231765f2f08SHeiko Schocher
232765f2f08SHeiko Schocher udelay(1000);
233765f2f08SHeiko Schocher
23413402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
23513402868SStefano Babic if (!(reg & LCD_RASTER_ENABLE))
23613402868SStefano Babic lcdc_write(reg | LCD_RASTER_ENABLE,
23713402868SStefano Babic &da8xx_fb_reg_base->raster_ctrl);
23813402868SStefano Babic }
23913402868SStefano Babic
24013402868SStefano Babic /* Disable the Raster Engine of the LCD Controller */
lcd_disable_raster(bool wait_for_frame_done)241765f2f08SHeiko Schocher static inline void lcd_disable_raster(bool wait_for_frame_done)
24213402868SStefano Babic {
24313402868SStefano Babic u32 reg;
244765f2f08SHeiko Schocher u32 loop_cnt = 0;
245765f2f08SHeiko Schocher u32 stat;
246765f2f08SHeiko Schocher u32 i = 0;
247765f2f08SHeiko Schocher
248765f2f08SHeiko Schocher if (wait_for_frame_done)
249765f2f08SHeiko Schocher loop_cnt = 5000;
25013402868SStefano Babic
25113402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
25213402868SStefano Babic if (reg & LCD_RASTER_ENABLE)
25313402868SStefano Babic lcdc_write(reg & ~LCD_RASTER_ENABLE,
25413402868SStefano Babic &da8xx_fb_reg_base->raster_ctrl);
255765f2f08SHeiko Schocher
256765f2f08SHeiko Schocher /* Wait for the current frame to complete */
257765f2f08SHeiko Schocher do {
258765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1)
259765f2f08SHeiko Schocher stat = lcdc_read(&da8xx_fb_reg_base->stat);
260765f2f08SHeiko Schocher else
261765f2f08SHeiko Schocher stat = lcdc_read(&da8xx_fb_reg_base->raw_stat);
262765f2f08SHeiko Schocher
263765f2f08SHeiko Schocher mdelay(1);
264765f2f08SHeiko Schocher } while (!(stat & 0x01) && (i++ < loop_cnt));
265765f2f08SHeiko Schocher
266765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1)
267765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->stat);
268765f2f08SHeiko Schocher else
269765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->raw_stat);
270765f2f08SHeiko Schocher
271765f2f08SHeiko Schocher if ((loop_cnt != 0) && (i >= loop_cnt)) {
272765f2f08SHeiko Schocher printf("LCD Controller timed out\n");
273765f2f08SHeiko Schocher return;
274765f2f08SHeiko Schocher }
27513402868SStefano Babic }
27613402868SStefano Babic
lcd_blit(int load_mode,struct da8xx_fb_par * par)27713402868SStefano Babic static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
27813402868SStefano Babic {
27913402868SStefano Babic u32 start;
28013402868SStefano Babic u32 end;
28113402868SStefano Babic u32 reg_ras;
28213402868SStefano Babic u32 reg_dma;
283765f2f08SHeiko Schocher u32 reg_int;
28413402868SStefano Babic
28513402868SStefano Babic /* init reg to clear PLM (loading mode) fields */
28613402868SStefano Babic reg_ras = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
28713402868SStefano Babic reg_ras &= ~(3 << 20);
28813402868SStefano Babic
28913402868SStefano Babic reg_dma = lcdc_read(&da8xx_fb_reg_base->dma_ctrl);
29013402868SStefano Babic
29113402868SStefano Babic if (load_mode == LOAD_DATA) {
29213402868SStefano Babic start = par->dma_start;
29313402868SStefano Babic end = par->dma_end;
29413402868SStefano Babic
29513402868SStefano Babic reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
296765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) {
297765f2f08SHeiko Schocher reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA;
298765f2f08SHeiko Schocher } else {
299765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) |
300765f2f08SHeiko Schocher LCD_V2_END_OF_FRAME0_INT_ENA |
301765f2f08SHeiko Schocher LCD_V2_END_OF_FRAME1_INT_ENA |
302765f2f08SHeiko Schocher LCD_V2_UNDERFLOW_INT_ENA | LCD_SYNC_LOST;
303765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set);
304765f2f08SHeiko Schocher }
30513402868SStefano Babic
30613402868SStefano Babic #if (LCD_NUM_BUFFERS == 2)
30713402868SStefano Babic reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
30813402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
30913402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
31013402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
31113402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
31213402868SStefano Babic #else
31313402868SStefano Babic reg_dma &= ~LCD_DUAL_FRAME_BUFFER_ENABLE;
31413402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
31513402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
31613402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
31713402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
31813402868SStefano Babic #endif
31913402868SStefano Babic
32013402868SStefano Babic } else if (load_mode == LOAD_PALETTE) {
32113402868SStefano Babic start = par->p_palette_base;
32213402868SStefano Babic end = start + par->palette_sz - 1;
32313402868SStefano Babic
32413402868SStefano Babic reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
325765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) {
326765f2f08SHeiko Schocher reg_ras |= LCD_V1_PL_INT_ENA;
327765f2f08SHeiko Schocher } else {
328765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) |
329765f2f08SHeiko Schocher LCD_V2_PL_INT_ENA;
330765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set);
331765f2f08SHeiko Schocher }
33213402868SStefano Babic
33313402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
33413402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
33513402868SStefano Babic }
33613402868SStefano Babic
33713402868SStefano Babic lcdc_write(reg_dma, &da8xx_fb_reg_base->dma_ctrl);
33813402868SStefano Babic lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl);
33913402868SStefano Babic
34013402868SStefano Babic /*
34113402868SStefano Babic * The Raster enable bit must be set after all other control fields are
34213402868SStefano Babic * set.
34313402868SStefano Babic */
34413402868SStefano Babic lcd_enable_raster();
34513402868SStefano Babic }
34613402868SStefano Babic
34713402868SStefano Babic /* Configure the Burst Size of DMA */
lcd_cfg_dma(int burst_size)34813402868SStefano Babic static int lcd_cfg_dma(int burst_size)
34913402868SStefano Babic {
35013402868SStefano Babic u32 reg;
35113402868SStefano Babic
35213402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->dma_ctrl) & 0x00000001;
35313402868SStefano Babic switch (burst_size) {
35413402868SStefano Babic case 1:
35513402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1);
35613402868SStefano Babic break;
35713402868SStefano Babic case 2:
35813402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2);
35913402868SStefano Babic break;
36013402868SStefano Babic case 4:
36113402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4);
36213402868SStefano Babic break;
36313402868SStefano Babic case 8:
36413402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8);
36513402868SStefano Babic break;
36613402868SStefano Babic case 16:
36713402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
36813402868SStefano Babic break;
36913402868SStefano Babic default:
37013402868SStefano Babic return -EINVAL;
37113402868SStefano Babic }
37213402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->dma_ctrl);
37313402868SStefano Babic
37413402868SStefano Babic return 0;
37513402868SStefano Babic }
37613402868SStefano Babic
lcd_cfg_ac_bias(int period,int transitions_per_int)37713402868SStefano Babic static void lcd_cfg_ac_bias(int period, int transitions_per_int)
37813402868SStefano Babic {
37913402868SStefano Babic u32 reg;
38013402868SStefano Babic
381535cce0fSRobert P. J. Day /* Set the AC Bias Period and Number of Transitions per Interrupt */
38213402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2) & 0xFFF00000;
38313402868SStefano Babic reg |= LCD_AC_BIAS_FREQUENCY(period) |
38413402868SStefano Babic LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int);
38513402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
38613402868SStefano Babic }
38713402868SStefano Babic
lcd_cfg_horizontal_sync(int back_porch,int pulse_width,int front_porch)38813402868SStefano Babic static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
38913402868SStefano Babic int front_porch)
39013402868SStefano Babic {
39113402868SStefano Babic u32 reg;
39213402868SStefano Babic
39313402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0) & 0xf;
39413402868SStefano Babic reg |= ((back_porch & 0xff) << 24)
39513402868SStefano Babic | ((front_porch & 0xff) << 16)
39613402868SStefano Babic | ((pulse_width & 0x3f) << 10);
39713402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0);
39813402868SStefano Babic }
39913402868SStefano Babic
lcd_cfg_vertical_sync(int back_porch,int pulse_width,int front_porch)40013402868SStefano Babic static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
40113402868SStefano Babic int front_porch)
40213402868SStefano Babic {
40313402868SStefano Babic u32 reg;
40413402868SStefano Babic
40513402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1) & 0x3ff;
40613402868SStefano Babic reg |= ((back_porch & 0xff) << 24)
40713402868SStefano Babic | ((front_porch & 0xff) << 16)
40813402868SStefano Babic | ((pulse_width & 0x3f) << 10);
40913402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1);
41013402868SStefano Babic }
41113402868SStefano Babic
lcd_cfg_display(const struct lcd_ctrl_config * cfg)41213402868SStefano Babic static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
41313402868SStefano Babic {
41413402868SStefano Babic u32 reg;
415765f2f08SHeiko Schocher u32 reg_int;
41613402868SStefano Babic
41713402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(LCD_TFT_MODE |
41813402868SStefano Babic LCD_MONO_8BIT_MODE |
41913402868SStefano Babic LCD_MONOCHROME_MODE);
42013402868SStefano Babic
42113402868SStefano Babic switch (cfg->p_disp_panel->panel_shade) {
42213402868SStefano Babic case MONOCHROME:
42313402868SStefano Babic reg |= LCD_MONOCHROME_MODE;
42413402868SStefano Babic if (cfg->mono_8bit_mode)
42513402868SStefano Babic reg |= LCD_MONO_8BIT_MODE;
42613402868SStefano Babic break;
42713402868SStefano Babic case COLOR_ACTIVE:
42813402868SStefano Babic reg |= LCD_TFT_MODE;
42913402868SStefano Babic if (cfg->tft_alt_mode)
43013402868SStefano Babic reg |= LCD_TFT_ALT_ENABLE;
43113402868SStefano Babic break;
43213402868SStefano Babic
43313402868SStefano Babic case COLOR_PASSIVE:
43413402868SStefano Babic if (cfg->stn_565_mode)
43513402868SStefano Babic reg |= LCD_STN_565_ENABLE;
43613402868SStefano Babic break;
43713402868SStefano Babic
43813402868SStefano Babic default:
43913402868SStefano Babic return -EINVAL;
44013402868SStefano Babic }
44113402868SStefano Babic
44213402868SStefano Babic /* enable additional interrupts here */
443765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) {
444765f2f08SHeiko Schocher reg |= LCD_V1_UNDERFLOW_INT_ENA;
445765f2f08SHeiko Schocher } else {
446765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) |
447765f2f08SHeiko Schocher LCD_V2_UNDERFLOW_INT_ENA;
448765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set);
449765f2f08SHeiko Schocher }
45013402868SStefano Babic
45113402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl);
45213402868SStefano Babic
45313402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2);
45413402868SStefano Babic
45513402868SStefano Babic if (cfg->sync_ctrl)
45613402868SStefano Babic reg |= LCD_SYNC_CTRL;
45713402868SStefano Babic else
45813402868SStefano Babic reg &= ~LCD_SYNC_CTRL;
45913402868SStefano Babic
46013402868SStefano Babic if (cfg->sync_edge)
46113402868SStefano Babic reg |= LCD_SYNC_EDGE;
46213402868SStefano Babic else
46313402868SStefano Babic reg &= ~LCD_SYNC_EDGE;
46413402868SStefano Babic
46513402868SStefano Babic if (cfg->invert_line_clock)
46613402868SStefano Babic reg |= LCD_INVERT_LINE_CLOCK;
46713402868SStefano Babic else
46813402868SStefano Babic reg &= ~LCD_INVERT_LINE_CLOCK;
46913402868SStefano Babic
47013402868SStefano Babic if (cfg->invert_frm_clock)
47113402868SStefano Babic reg |= LCD_INVERT_FRAME_CLOCK;
47213402868SStefano Babic else
47313402868SStefano Babic reg &= ~LCD_INVERT_FRAME_CLOCK;
47413402868SStefano Babic
47513402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
47613402868SStefano Babic
47713402868SStefano Babic return 0;
47813402868SStefano Babic }
47913402868SStefano Babic
lcd_cfg_frame_buffer(struct da8xx_fb_par * par,u32 width,u32 height,u32 bpp,u32 raster_order)48013402868SStefano Babic static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
48113402868SStefano Babic u32 bpp, u32 raster_order)
48213402868SStefano Babic {
48313402868SStefano Babic u32 reg;
48413402868SStefano Babic
48513402868SStefano Babic /* Set the Panel Width */
48613402868SStefano Babic /* Pixels per line = (PPL + 1)*16 */
487765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) {
488765f2f08SHeiko Schocher /*
489535cce0fSRobert P. J. Day * 0x3F in bits 4..9 gives max horizontal resolution = 1024
490765f2f08SHeiko Schocher * pixels
491765f2f08SHeiko Schocher */
49213402868SStefano Babic width &= 0x3f0;
493765f2f08SHeiko Schocher } else {
494765f2f08SHeiko Schocher /*
495765f2f08SHeiko Schocher * 0x7F in bits 4..10 gives max horizontal resolution = 2048
496765f2f08SHeiko Schocher * pixels.
497765f2f08SHeiko Schocher */
498765f2f08SHeiko Schocher width &= 0x7f0;
499765f2f08SHeiko Schocher }
50013402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0);
50113402868SStefano Babic reg &= 0xfffffc00;
502765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) {
50313402868SStefano Babic reg |= ((width >> 4) - 1) << 4;
504765f2f08SHeiko Schocher } else {
505765f2f08SHeiko Schocher width = (width >> 4) - 1;
506765f2f08SHeiko Schocher reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3);
507765f2f08SHeiko Schocher }
50813402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0);
50913402868SStefano Babic
51013402868SStefano Babic /* Set the Panel Height */
511765f2f08SHeiko Schocher /* Set bits 9:0 of Lines Per Pixel */
51213402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1);
51313402868SStefano Babic reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
51413402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1);
51513402868SStefano Babic
516765f2f08SHeiko Schocher /* Set bit 10 of Lines Per Pixel */
517765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2) {
518765f2f08SHeiko Schocher reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2);
519765f2f08SHeiko Schocher reg |= ((height - 1) & 0x400) << 16;
520765f2f08SHeiko Schocher lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
521765f2f08SHeiko Schocher }
522765f2f08SHeiko Schocher
52313402868SStefano Babic /* Set the Raster Order of the Frame Buffer */
52413402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(1 << 8);
52513402868SStefano Babic if (raster_order)
52613402868SStefano Babic reg |= LCD_RASTER_ORDER;
527765f2f08SHeiko Schocher
528765f2f08SHeiko Schocher if (bpp == 24)
529765f2f08SHeiko Schocher reg |= (LCD_TFT_MODE | LCD_V2_TFT_24BPP_MODE);
530765f2f08SHeiko Schocher else if (bpp == 32)
531765f2f08SHeiko Schocher reg |= (LCD_TFT_MODE | LCD_V2_TFT_24BPP_MODE
532765f2f08SHeiko Schocher | LCD_V2_TFT_24BPP_UNPACK);
533765f2f08SHeiko Schocher
53413402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl);
53513402868SStefano Babic
53613402868SStefano Babic switch (bpp) {
53713402868SStefano Babic case 1:
53813402868SStefano Babic case 2:
53913402868SStefano Babic case 4:
54013402868SStefano Babic case 16:
541765f2f08SHeiko Schocher case 24:
542765f2f08SHeiko Schocher case 32:
54313402868SStefano Babic par->palette_sz = 16 * 2;
54413402868SStefano Babic break;
54513402868SStefano Babic
54613402868SStefano Babic case 8:
54713402868SStefano Babic par->palette_sz = 256 * 2;
54813402868SStefano Babic break;
54913402868SStefano Babic
55013402868SStefano Babic default:
55113402868SStefano Babic return -EINVAL;
55213402868SStefano Babic }
55313402868SStefano Babic
55413402868SStefano Babic return 0;
55513402868SStefano Babic }
55613402868SStefano Babic
fb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * info)55713402868SStefano Babic static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
55813402868SStefano Babic unsigned blue, unsigned transp,
55913402868SStefano Babic struct fb_info *info)
56013402868SStefano Babic {
56113402868SStefano Babic struct da8xx_fb_par *par = info->par;
56213402868SStefano Babic unsigned short *palette = (unsigned short *) par->v_palette_base;
56313402868SStefano Babic u_short pal;
56413402868SStefano Babic int update_hw = 0;
56513402868SStefano Babic
56613402868SStefano Babic if (regno > 255)
56713402868SStefano Babic return 1;
56813402868SStefano Babic
56913402868SStefano Babic if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
57013402868SStefano Babic return 1;
57113402868SStefano Babic
57213402868SStefano Babic if (info->var.bits_per_pixel == 8) {
57313402868SStefano Babic red >>= 4;
57413402868SStefano Babic green >>= 8;
57513402868SStefano Babic blue >>= 12;
57613402868SStefano Babic
57713402868SStefano Babic pal = (red & 0x0f00);
57813402868SStefano Babic pal |= (green & 0x00f0);
57913402868SStefano Babic pal |= (blue & 0x000f);
58013402868SStefano Babic
58113402868SStefano Babic if (palette[regno] != pal) {
58213402868SStefano Babic update_hw = 1;
58313402868SStefano Babic palette[regno] = pal;
58413402868SStefano Babic }
58513402868SStefano Babic } else if ((info->var.bits_per_pixel == 16) && regno < 16) {
58613402868SStefano Babic red >>= (16 - info->var.red.length);
58713402868SStefano Babic red <<= info->var.red.offset;
58813402868SStefano Babic
58913402868SStefano Babic green >>= (16 - info->var.green.length);
59013402868SStefano Babic green <<= info->var.green.offset;
59113402868SStefano Babic
59213402868SStefano Babic blue >>= (16 - info->var.blue.length);
59313402868SStefano Babic blue <<= info->var.blue.offset;
59413402868SStefano Babic
59513402868SStefano Babic par->pseudo_palette[regno] = red | green | blue;
59613402868SStefano Babic
59713402868SStefano Babic if (palette[0] != 0x4000) {
59813402868SStefano Babic update_hw = 1;
59913402868SStefano Babic palette[0] = 0x4000;
60013402868SStefano Babic }
601765f2f08SHeiko Schocher } else if (((info->var.bits_per_pixel == 32) && regno < 32) ||
602765f2f08SHeiko Schocher ((info->var.bits_per_pixel == 24) && regno < 24)) {
603765f2f08SHeiko Schocher red >>= (24 - info->var.red.length);
604765f2f08SHeiko Schocher red <<= info->var.red.offset;
605765f2f08SHeiko Schocher
606765f2f08SHeiko Schocher green >>= (24 - info->var.green.length);
607765f2f08SHeiko Schocher green <<= info->var.green.offset;
608765f2f08SHeiko Schocher
609765f2f08SHeiko Schocher blue >>= (24 - info->var.blue.length);
610765f2f08SHeiko Schocher blue <<= info->var.blue.offset;
611765f2f08SHeiko Schocher
612765f2f08SHeiko Schocher par->pseudo_palette[regno] = red | green | blue;
613765f2f08SHeiko Schocher
614765f2f08SHeiko Schocher if (palette[0] != 0x4000) {
615765f2f08SHeiko Schocher update_hw = 1;
616765f2f08SHeiko Schocher palette[0] = 0x4000;
617765f2f08SHeiko Schocher }
61813402868SStefano Babic }
61913402868SStefano Babic
62013402868SStefano Babic /* Update the palette in the h/w as needed. */
62113402868SStefano Babic if (update_hw)
62213402868SStefano Babic lcd_blit(LOAD_PALETTE, par);
62313402868SStefano Babic
62413402868SStefano Babic return 0;
62513402868SStefano Babic }
62613402868SStefano Babic
lcd_reset(struct da8xx_fb_par * par)62713402868SStefano Babic static void lcd_reset(struct da8xx_fb_par *par)
62813402868SStefano Babic {
62913402868SStefano Babic /* Disable the Raster if previously Enabled */
630765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
63113402868SStefano Babic
63213402868SStefano Babic /* DMA has to be disabled */
63313402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->dma_ctrl);
63413402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->raster_ctrl);
635765f2f08SHeiko Schocher
636765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2) {
637765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->int_ena_set);
638765f2f08SHeiko Schocher /* Write 1 to reset */
639765f2f08SHeiko Schocher lcdc_write(LCD_CLK_MAIN_RESET, &da8xx_fb_reg_base->clk_reset);
640765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->clk_reset);
641765f2f08SHeiko Schocher }
64213402868SStefano Babic }
64313402868SStefano Babic
lcd_calc_clk_divider(struct da8xx_fb_par * par)64413402868SStefano Babic static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
64513402868SStefano Babic {
64613402868SStefano Babic unsigned int lcd_clk, div;
64713402868SStefano Babic
64813402868SStefano Babic /* Get clock from sysclk2 */
64913402868SStefano Babic lcd_clk = clk_get(2);
65013402868SStefano Babic
65113402868SStefano Babic div = lcd_clk / par->pxl_clk;
652765f2f08SHeiko Schocher debug("LCD Clock: %d Divider: %d PixClk: %d\n",
65313402868SStefano Babic lcd_clk, div, par->pxl_clk);
65413402868SStefano Babic
65513402868SStefano Babic /* Configure the LCD clock divisor. */
65613402868SStefano Babic lcdc_write(LCD_CLK_DIVISOR(div) |
65713402868SStefano Babic (LCD_RASTER_MODE & 0x1), &da8xx_fb_reg_base->ctrl);
658765f2f08SHeiko Schocher
659765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2)
660765f2f08SHeiko Schocher lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
661765f2f08SHeiko Schocher LCD_V2_CORE_CLK_EN,
662765f2f08SHeiko Schocher &da8xx_fb_reg_base->clk_ena);
66313402868SStefano Babic }
66413402868SStefano Babic
lcd_init(struct da8xx_fb_par * par,const struct lcd_ctrl_config * cfg,const struct da8xx_panel * panel)66513402868SStefano Babic static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
66613402868SStefano Babic const struct da8xx_panel *panel)
66713402868SStefano Babic {
66813402868SStefano Babic u32 bpp;
66913402868SStefano Babic int ret = 0;
67013402868SStefano Babic
67113402868SStefano Babic lcd_reset(par);
67213402868SStefano Babic
67313402868SStefano Babic /* Calculate the divider */
67413402868SStefano Babic lcd_calc_clk_divider(par);
67513402868SStefano Babic
67613402868SStefano Babic if (panel->invert_pxl_clk)
67713402868SStefano Babic lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) |
67813402868SStefano Babic LCD_INVERT_PIXEL_CLOCK),
67913402868SStefano Babic &da8xx_fb_reg_base->raster_timing_2);
68013402868SStefano Babic else
68113402868SStefano Babic lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) &
68213402868SStefano Babic ~LCD_INVERT_PIXEL_CLOCK),
68313402868SStefano Babic &da8xx_fb_reg_base->raster_timing_2);
68413402868SStefano Babic
68513402868SStefano Babic /* Configure the DMA burst size. */
68613402868SStefano Babic ret = lcd_cfg_dma(cfg->dma_burst_sz);
68713402868SStefano Babic if (ret < 0)
68813402868SStefano Babic return ret;
68913402868SStefano Babic
69013402868SStefano Babic /* Configure the AC bias properties. */
69113402868SStefano Babic lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt);
69213402868SStefano Babic
69313402868SStefano Babic /* Configure the vertical and horizontal sync properties. */
69413402868SStefano Babic lcd_cfg_vertical_sync(panel->vbp, panel->vsw, panel->vfp);
69513402868SStefano Babic lcd_cfg_horizontal_sync(panel->hbp, panel->hsw, panel->hfp);
69613402868SStefano Babic
697535cce0fSRobert P. J. Day /* Configure for display */
69813402868SStefano Babic ret = lcd_cfg_display(cfg);
69913402868SStefano Babic if (ret < 0)
70013402868SStefano Babic return ret;
70113402868SStefano Babic
702765f2f08SHeiko Schocher if ((QVGA != cfg->p_disp_panel->panel_type) &&
703765f2f08SHeiko Schocher (WVGA != cfg->p_disp_panel->panel_type))
70413402868SStefano Babic return -EINVAL;
70513402868SStefano Babic
70613402868SStefano Babic if (cfg->bpp <= cfg->p_disp_panel->max_bpp &&
70713402868SStefano Babic cfg->bpp >= cfg->p_disp_panel->min_bpp)
70813402868SStefano Babic bpp = cfg->bpp;
70913402868SStefano Babic else
71013402868SStefano Babic bpp = cfg->p_disp_panel->max_bpp;
71113402868SStefano Babic if (bpp == 12)
71213402868SStefano Babic bpp = 16;
71313402868SStefano Babic ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->width,
71413402868SStefano Babic (unsigned int)panel->height, bpp,
71513402868SStefano Babic cfg->raster_order);
71613402868SStefano Babic if (ret < 0)
71713402868SStefano Babic return ret;
71813402868SStefano Babic
71913402868SStefano Babic /* Configure FDD */
72013402868SStefano Babic lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & 0xfff00fff) |
72113402868SStefano Babic (cfg->fdd << 12), &da8xx_fb_reg_base->raster_ctrl);
72213402868SStefano Babic
72313402868SStefano Babic return 0;
72413402868SStefano Babic }
72513402868SStefano Babic
lcdc_dma_start(void)72613402868SStefano Babic static void lcdc_dma_start(void)
72713402868SStefano Babic {
72813402868SStefano Babic struct da8xx_fb_par *par = da8xx_fb_info->par;
72913402868SStefano Babic lcdc_write(par->dma_start,
73013402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
73113402868SStefano Babic lcdc_write(par->dma_end,
73213402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
73313402868SStefano Babic lcdc_write(0,
73413402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
73513402868SStefano Babic lcdc_write(0,
73613402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
73713402868SStefano Babic }
73813402868SStefano Babic
lcdc_irq_handler_rev01(void)739765f2f08SHeiko Schocher static u32 lcdc_irq_handler_rev01(void)
74013402868SStefano Babic {
74113402868SStefano Babic struct da8xx_fb_par *par = da8xx_fb_info->par;
74213402868SStefano Babic u32 stat = lcdc_read(&da8xx_fb_reg_base->stat);
74313402868SStefano Babic u32 reg_ras;
74413402868SStefano Babic
74513402868SStefano Babic if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
74613402868SStefano Babic debug("LCD_SYNC_LOST\n");
747765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
74813402868SStefano Babic lcdc_write(stat, &da8xx_fb_reg_base->stat);
74913402868SStefano Babic lcd_enable_raster();
75013402868SStefano Babic return LCD_SYNC_LOST;
75113402868SStefano Babic } else if (stat & LCD_PL_LOAD_DONE) {
75213402868SStefano Babic debug("LCD_PL_LOAD_DONE\n");
75313402868SStefano Babic /*
75413402868SStefano Babic * Must disable raster before changing state of any control bit.
75513402868SStefano Babic * And also must be disabled before clearing the PL loading
75613402868SStefano Babic * interrupt via the following write to the status register. If
75713402868SStefano Babic * this is done after then one gets multiple PL done interrupts.
75813402868SStefano Babic */
759765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
76013402868SStefano Babic
76113402868SStefano Babic lcdc_write(stat, &da8xx_fb_reg_base->stat);
76213402868SStefano Babic
763535cce0fSRobert P. J. Day /* Disable PL completion interrupt */
76413402868SStefano Babic reg_ras = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
765765f2f08SHeiko Schocher reg_ras &= ~LCD_V1_PL_INT_ENA;
76613402868SStefano Babic lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl);
76713402868SStefano Babic
76813402868SStefano Babic /* Setup and start data loading mode */
76913402868SStefano Babic lcd_blit(LOAD_DATA, par);
77013402868SStefano Babic return LCD_PL_LOAD_DONE;
77113402868SStefano Babic } else {
77213402868SStefano Babic lcdc_write(stat, &da8xx_fb_reg_base->stat);
77313402868SStefano Babic
77413402868SStefano Babic if (stat & LCD_END_OF_FRAME0)
77513402868SStefano Babic debug("LCD_END_OF_FRAME0\n");
77613402868SStefano Babic
77713402868SStefano Babic lcdc_write(par->dma_start,
77813402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
77913402868SStefano Babic lcdc_write(par->dma_end,
78013402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
78113402868SStefano Babic par->vsync_flag = 1;
78213402868SStefano Babic return LCD_END_OF_FRAME0;
78313402868SStefano Babic }
78413402868SStefano Babic return stat;
78513402868SStefano Babic }
78613402868SStefano Babic
lcdc_irq_handler_rev02(void)787765f2f08SHeiko Schocher static u32 lcdc_irq_handler_rev02(void)
788765f2f08SHeiko Schocher {
789765f2f08SHeiko Schocher struct da8xx_fb_par *par = da8xx_fb_info->par;
790765f2f08SHeiko Schocher u32 stat = lcdc_read(&da8xx_fb_reg_base->masked_stat);
791765f2f08SHeiko Schocher u32 reg_int;
792765f2f08SHeiko Schocher
793765f2f08SHeiko Schocher if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
794765f2f08SHeiko Schocher debug("LCD_SYNC_LOST\n");
795765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
796765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->masked_stat);
797765f2f08SHeiko Schocher lcd_enable_raster();
798765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
799765f2f08SHeiko Schocher return LCD_SYNC_LOST;
800765f2f08SHeiko Schocher } else if (stat & LCD_PL_LOAD_DONE) {
801765f2f08SHeiko Schocher debug("LCD_PL_LOAD_DONE\n");
802765f2f08SHeiko Schocher /*
803765f2f08SHeiko Schocher * Must disable raster before changing state of any control bit.
804765f2f08SHeiko Schocher * And also must be disabled before clearing the PL loading
805765f2f08SHeiko Schocher * interrupt via the following write to the status register. If
806765f2f08SHeiko Schocher * this is done after then one gets multiple PL done interrupts.
807765f2f08SHeiko Schocher */
808765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
809765f2f08SHeiko Schocher
810765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->masked_stat);
811765f2f08SHeiko Schocher
812535cce0fSRobert P. J. Day /* Disable PL completion interrupt */
813765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_clr) |
814765f2f08SHeiko Schocher (LCD_V2_PL_INT_ENA);
815765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_clr);
816765f2f08SHeiko Schocher
817765f2f08SHeiko Schocher /* Setup and start data loading mode */
818765f2f08SHeiko Schocher lcd_blit(LOAD_DATA, par);
819765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
820765f2f08SHeiko Schocher return LCD_PL_LOAD_DONE;
821765f2f08SHeiko Schocher } else {
822765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->masked_stat);
823765f2f08SHeiko Schocher
824765f2f08SHeiko Schocher if (stat & LCD_END_OF_FRAME0)
825765f2f08SHeiko Schocher debug("LCD_END_OF_FRAME0\n");
826765f2f08SHeiko Schocher
827765f2f08SHeiko Schocher lcdc_write(par->dma_start,
828765f2f08SHeiko Schocher &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
829765f2f08SHeiko Schocher lcdc_write(par->dma_end,
830765f2f08SHeiko Schocher &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
831765f2f08SHeiko Schocher par->vsync_flag = 1;
832765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
833765f2f08SHeiko Schocher return LCD_END_OF_FRAME0;
834765f2f08SHeiko Schocher }
835765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
836765f2f08SHeiko Schocher return stat;
837765f2f08SHeiko Schocher }
838765f2f08SHeiko Schocher
lcdc_irq_handler(void)839765f2f08SHeiko Schocher static u32 lcdc_irq_handler(void)
840765f2f08SHeiko Schocher {
841765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1)
842765f2f08SHeiko Schocher return lcdc_irq_handler_rev01();
843765f2f08SHeiko Schocher else
844765f2f08SHeiko Schocher return lcdc_irq_handler_rev02();
845765f2f08SHeiko Schocher }
846765f2f08SHeiko Schocher
wait_for_event(u32 event)84713402868SStefano Babic static u32 wait_for_event(u32 event)
84813402868SStefano Babic {
84913402868SStefano Babic u32 timeout = 50000;
85013402868SStefano Babic u32 ret;
85113402868SStefano Babic
85213402868SStefano Babic do {
85313402868SStefano Babic ret = lcdc_irq_handler();
85413402868SStefano Babic udelay(1000);
855c16b342dSHeinrich Schuchardt --timeout;
856c16b342dSHeinrich Schuchardt } while (!(ret & event) && timeout);
85713402868SStefano Babic
858c16b342dSHeinrich Schuchardt if (!(ret & event)) {
85913402868SStefano Babic printf("%s: event %d not hit\n", __func__, event);
86013402868SStefano Babic return -1;
86113402868SStefano Babic }
86213402868SStefano Babic
86313402868SStefano Babic return 0;
86413402868SStefano Babic
86513402868SStefano Babic }
86613402868SStefano Babic
video_hw_init(void)86713402868SStefano Babic void *video_hw_init(void)
86813402868SStefano Babic {
86913402868SStefano Babic struct da8xx_fb_par *par;
87013402868SStefano Babic u32 size;
871765f2f08SHeiko Schocher u32 rev;
87213402868SStefano Babic char *p;
87313402868SStefano Babic
87413402868SStefano Babic if (!lcd_panel) {
87513402868SStefano Babic printf("Display not initialized\n");
87613402868SStefano Babic return NULL;
87713402868SStefano Babic }
87813402868SStefano Babic gpanel.winSizeX = lcd_panel->width;
87913402868SStefano Babic gpanel.winSizeY = lcd_panel->height;
88013402868SStefano Babic gpanel.plnSizeX = lcd_panel->width;
88113402868SStefano Babic gpanel.plnSizeY = lcd_panel->height;
88213402868SStefano Babic
88313402868SStefano Babic switch (bits_x_pixel) {
884765f2f08SHeiko Schocher case 32:
885765f2f08SHeiko Schocher gpanel.gdfBytesPP = 4;
886765f2f08SHeiko Schocher gpanel.gdfIndex = GDF_32BIT_X888RGB;
887765f2f08SHeiko Schocher break;
88813402868SStefano Babic case 24:
88913402868SStefano Babic gpanel.gdfBytesPP = 4;
89013402868SStefano Babic gpanel.gdfIndex = GDF_32BIT_X888RGB;
89113402868SStefano Babic break;
89213402868SStefano Babic case 16:
89313402868SStefano Babic gpanel.gdfBytesPP = 2;
89413402868SStefano Babic gpanel.gdfIndex = GDF_16BIT_565RGB;
89513402868SStefano Babic break;
89613402868SStefano Babic default:
89713402868SStefano Babic gpanel.gdfBytesPP = 1;
89813402868SStefano Babic gpanel.gdfIndex = GDF__8BIT_INDEX;
89913402868SStefano Babic break;
90013402868SStefano Babic }
90113402868SStefano Babic
902765f2f08SHeiko Schocher da8xx_fb_reg_base = (struct da8xx_lcd_regs *)DA8XX_LCD_CNTL_BASE;
90313402868SStefano Babic
904765f2f08SHeiko Schocher /* Determine LCD IP Version */
905765f2f08SHeiko Schocher rev = lcdc_read(&da8xx_fb_reg_base->revid);
906765f2f08SHeiko Schocher switch (rev) {
907765f2f08SHeiko Schocher case 0x4C100102:
908765f2f08SHeiko Schocher lcd_revision = LCD_VERSION_1;
909765f2f08SHeiko Schocher break;
910765f2f08SHeiko Schocher case 0x4F200800:
911765f2f08SHeiko Schocher case 0x4F201000:
912765f2f08SHeiko Schocher lcd_revision = LCD_VERSION_2;
913765f2f08SHeiko Schocher break;
914765f2f08SHeiko Schocher default:
915765f2f08SHeiko Schocher printf("Unknown PID Reg value 0x%x, defaulting to LCD revision 1\n",
916765f2f08SHeiko Schocher rev);
917765f2f08SHeiko Schocher lcd_revision = LCD_VERSION_1;
918765f2f08SHeiko Schocher break;
919765f2f08SHeiko Schocher }
920765f2f08SHeiko Schocher
921765f2f08SHeiko Schocher debug("rev: 0x%x Resolution: %dx%d %d\n", rev,
92213402868SStefano Babic gpanel.winSizeX,
92313402868SStefano Babic gpanel.winSizeY,
924765f2f08SHeiko Schocher da8xx_lcd_cfg->bpp);
92513402868SStefano Babic
92613402868SStefano Babic size = sizeof(struct fb_info) + sizeof(struct da8xx_fb_par);
927963be689SNiko Mauno da8xx_fb_info = malloc_cache_aligned(size);
92813402868SStefano Babic debug("da8xx_fb_info at %x\n", (unsigned int)da8xx_fb_info);
92913402868SStefano Babic
93013402868SStefano Babic if (!da8xx_fb_info) {
93113402868SStefano Babic printf("Memory allocation failed for fb_info\n");
93213402868SStefano Babic return NULL;
93313402868SStefano Babic }
93413402868SStefano Babic memset(da8xx_fb_info, 0, size);
93513402868SStefano Babic p = (char *)da8xx_fb_info;
93613402868SStefano Babic da8xx_fb_info->par = p + sizeof(struct fb_info);
93713402868SStefano Babic debug("da8xx_par at %x\n", (unsigned int)da8xx_fb_info->par);
93813402868SStefano Babic
93913402868SStefano Babic par = da8xx_fb_info->par;
94013402868SStefano Babic par->pxl_clk = lcd_panel->pxl_clk;
94113402868SStefano Babic
942765f2f08SHeiko Schocher if (lcd_init(par, da8xx_lcd_cfg, lcd_panel) < 0) {
94313402868SStefano Babic printf("lcd_init failed\n");
94413402868SStefano Babic goto err_release_fb;
94513402868SStefano Babic }
94613402868SStefano Babic
94713402868SStefano Babic /* allocate frame buffer */
948765f2f08SHeiko Schocher par->vram_size = lcd_panel->width * lcd_panel->height *
949765f2f08SHeiko Schocher da8xx_lcd_cfg->bpp;
95013402868SStefano Babic par->vram_size = par->vram_size * LCD_NUM_BUFFERS / 8;
95113402868SStefano Babic
952963be689SNiko Mauno par->vram_virt = malloc_cache_aligned(par->vram_size);
95313402868SStefano Babic
95413402868SStefano Babic par->vram_phys = (dma_addr_t) par->vram_virt;
95513402868SStefano Babic debug("Requesting 0x%x bytes for framebuffer at 0x%x\n",
95613402868SStefano Babic (unsigned int)par->vram_size,
95713402868SStefano Babic (unsigned int)par->vram_virt);
95813402868SStefano Babic if (!par->vram_virt) {
95913402868SStefano Babic printf("GLCD: malloc for frame buffer failed\n");
96013402868SStefano Babic goto err_release_fb;
96113402868SStefano Babic }
9624e023626SHeiko Schocher gd->fb_base = (int)par->vram_virt;
96313402868SStefano Babic
96413402868SStefano Babic gpanel.frameAdrs = (unsigned int)par->vram_virt;
96513402868SStefano Babic da8xx_fb_info->screen_base = (char *) par->vram_virt;
96613402868SStefano Babic da8xx_fb_fix.smem_start = gpanel.frameAdrs;
96713402868SStefano Babic da8xx_fb_fix.smem_len = par->vram_size;
968765f2f08SHeiko Schocher da8xx_fb_fix.line_length = (lcd_panel->width * da8xx_lcd_cfg->bpp) / 8;
96913402868SStefano Babic
97013402868SStefano Babic par->dma_start = par->vram_phys;
97113402868SStefano Babic par->dma_end = par->dma_start + lcd_panel->height *
97213402868SStefano Babic da8xx_fb_fix.line_length - 1;
97313402868SStefano Babic
97413402868SStefano Babic /* allocate palette buffer */
975963be689SNiko Mauno par->v_palette_base = malloc_cache_aligned(PALETTE_SIZE);
97613402868SStefano Babic if (!par->v_palette_base) {
97713402868SStefano Babic printf("GLCD: malloc for palette buffer failed\n");
97813402868SStefano Babic goto err_release_fb_mem;
97913402868SStefano Babic }
98013402868SStefano Babic memset(par->v_palette_base, 0, PALETTE_SIZE);
98113402868SStefano Babic par->p_palette_base = (unsigned int)par->v_palette_base;
98213402868SStefano Babic
98313402868SStefano Babic /* Initialize par */
984765f2f08SHeiko Schocher da8xx_fb_info->var.bits_per_pixel = da8xx_lcd_cfg->bpp;
98513402868SStefano Babic
98613402868SStefano Babic da8xx_fb_var.xres = lcd_panel->width;
98713402868SStefano Babic da8xx_fb_var.xres_virtual = lcd_panel->width;
98813402868SStefano Babic
98913402868SStefano Babic da8xx_fb_var.yres = lcd_panel->height;
99013402868SStefano Babic da8xx_fb_var.yres_virtual = lcd_panel->height * LCD_NUM_BUFFERS;
99113402868SStefano Babic
99213402868SStefano Babic da8xx_fb_var.grayscale =
993765f2f08SHeiko Schocher da8xx_lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
994765f2f08SHeiko Schocher da8xx_fb_var.bits_per_pixel = da8xx_lcd_cfg->bpp;
99513402868SStefano Babic
99613402868SStefano Babic da8xx_fb_var.hsync_len = lcd_panel->hsw;
99713402868SStefano Babic da8xx_fb_var.vsync_len = lcd_panel->vsw;
99813402868SStefano Babic
99913402868SStefano Babic /* Initialize fbinfo */
100013402868SStefano Babic da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
100113402868SStefano Babic da8xx_fb_info->fix = da8xx_fb_fix;
100213402868SStefano Babic da8xx_fb_info->var = da8xx_fb_var;
100313402868SStefano Babic da8xx_fb_info->pseudo_palette = par->pseudo_palette;
100413402868SStefano Babic da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
100513402868SStefano Babic FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
100613402868SStefano Babic
100713402868SStefano Babic /* Clear interrupt */
100813402868SStefano Babic memset((void *)par->vram_virt, 0, par->vram_size);
1009765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
1010765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1)
101113402868SStefano Babic lcdc_write(0xFFFF, &da8xx_fb_reg_base->stat);
1012765f2f08SHeiko Schocher else
1013765f2f08SHeiko Schocher lcdc_write(0xFFFF, &da8xx_fb_reg_base->masked_stat);
101413402868SStefano Babic debug("Palette at 0x%x size %d\n", par->p_palette_base,
101513402868SStefano Babic par->palette_sz);
101613402868SStefano Babic lcdc_dma_start();
101713402868SStefano Babic
101813402868SStefano Babic /* Load a default palette */
101913402868SStefano Babic fb_setcolreg(0, 0, 0, 0, 0xffff, da8xx_fb_info);
102013402868SStefano Babic
102113402868SStefano Babic /* Check that the palette is loaded */
102213402868SStefano Babic wait_for_event(LCD_PL_LOAD_DONE);
102313402868SStefano Babic
102413402868SStefano Babic /* Wait until DMA is working */
102513402868SStefano Babic wait_for_event(LCD_END_OF_FRAME0);
102613402868SStefano Babic
102713402868SStefano Babic return (void *)&gpanel;
102813402868SStefano Babic
102913402868SStefano Babic err_release_fb_mem:
103013402868SStefano Babic free(par->vram_virt);
103113402868SStefano Babic
103213402868SStefano Babic err_release_fb:
103313402868SStefano Babic free(da8xx_fb_info);
103413402868SStefano Babic
103513402868SStefano Babic return NULL;
103613402868SStefano Babic }
103713402868SStefano Babic
da8xx_video_init(const struct da8xx_panel * panel,const struct lcd_ctrl_config * lcd_cfg,int bits_pixel)1038765f2f08SHeiko Schocher void da8xx_video_init(const struct da8xx_panel *panel,
1039765f2f08SHeiko Schocher const struct lcd_ctrl_config *lcd_cfg, int bits_pixel)
104013402868SStefano Babic {
104113402868SStefano Babic lcd_panel = panel;
1042765f2f08SHeiko Schocher da8xx_lcd_cfg = lcd_cfg;
104313402868SStefano Babic bits_x_pixel = bits_pixel;
104413402868SStefano Babic }
1045