113402868SStefano Babic /* 213402868SStefano Babic * Porting to u-boot: 313402868SStefano Babic * 413402868SStefano Babic * (C) Copyright 2011 513402868SStefano Babic * Stefano Babic, DENX Software Engineering, sbabic@denx.de. 613402868SStefano Babic * 713402868SStefano Babic * Copyright (C) 2008-2009 MontaVista Software Inc. 813402868SStefano Babic * Copyright (C) 2008-2009 Texas Instruments Inc 913402868SStefano Babic * 1013402868SStefano Babic * Based on the LCD driver for TI Avalanche processors written by 1113402868SStefano Babic * Ajay Singh and Shalom Hai. 1213402868SStefano Babic * 131a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 1413402868SStefano Babic */ 1513402868SStefano Babic 1613402868SStefano Babic #include <common.h> 1713402868SStefano Babic #include <malloc.h> 1813402868SStefano Babic #include <video_fb.h> 1913402868SStefano Babic #include <linux/list.h> 2013402868SStefano Babic #include <linux/fb.h> 2113402868SStefano Babic 2213402868SStefano Babic #include <asm/errno.h> 2313402868SStefano Babic #include <asm/io.h> 2413402868SStefano Babic #include <asm/arch/hardware.h> 2513402868SStefano Babic 2613402868SStefano Babic #include "videomodes.h" 270017f9eeSHeiko Schocher #include "da8xx-fb.h" 2813402868SStefano Babic 29765f2f08SHeiko Schocher #if !defined(DA8XX_LCD_CNTL_BASE) 30765f2f08SHeiko Schocher #define DA8XX_LCD_CNTL_BASE DAVINCI_LCD_CNTL_BASE 31765f2f08SHeiko Schocher #endif 32765f2f08SHeiko Schocher 3313402868SStefano Babic #define DRIVER_NAME "da8xx_lcdc" 3413402868SStefano Babic 35765f2f08SHeiko Schocher #define LCD_VERSION_1 1 36765f2f08SHeiko Schocher #define LCD_VERSION_2 2 37765f2f08SHeiko Schocher 3813402868SStefano Babic /* LCD Status Register */ 3913402868SStefano Babic #define LCD_END_OF_FRAME1 (1 << 9) 4013402868SStefano Babic #define LCD_END_OF_FRAME0 (1 << 8) 4113402868SStefano Babic #define LCD_PL_LOAD_DONE (1 << 6) 4213402868SStefano Babic #define LCD_FIFO_UNDERFLOW (1 << 5) 4313402868SStefano Babic #define LCD_SYNC_LOST (1 << 2) 4413402868SStefano Babic 4513402868SStefano Babic /* LCD DMA Control Register */ 4613402868SStefano Babic #define LCD_DMA_BURST_SIZE(x) ((x) << 4) 4713402868SStefano Babic #define LCD_DMA_BURST_1 0x0 4813402868SStefano Babic #define LCD_DMA_BURST_2 0x1 4913402868SStefano Babic #define LCD_DMA_BURST_4 0x2 5013402868SStefano Babic #define LCD_DMA_BURST_8 0x3 5113402868SStefano Babic #define LCD_DMA_BURST_16 0x4 52765f2f08SHeiko Schocher #define LCD_V1_END_OF_FRAME_INT_ENA (1 << 2) 53765f2f08SHeiko Schocher #define LCD_V2_END_OF_FRAME0_INT_ENA (1 << 8) 54765f2f08SHeiko Schocher #define LCD_V2_END_OF_FRAME1_INT_ENA (1 << 9) 5513402868SStefano Babic #define LCD_DUAL_FRAME_BUFFER_ENABLE (1 << 0) 5613402868SStefano Babic 57765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_MODE (1 << 25) 58765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_UNPACK (1 << 26) 59765f2f08SHeiko Schocher 6013402868SStefano Babic /* LCD Control Register */ 6113402868SStefano Babic #define LCD_CLK_DIVISOR(x) ((x) << 8) 6213402868SStefano Babic #define LCD_RASTER_MODE 0x01 6313402868SStefano Babic 6413402868SStefano Babic /* LCD Raster Control Register */ 6513402868SStefano Babic #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) 6613402868SStefano Babic #define PALETTE_AND_DATA 0x00 6713402868SStefano Babic #define PALETTE_ONLY 0x01 6813402868SStefano Babic #define DATA_ONLY 0x02 6913402868SStefano Babic 7013402868SStefano Babic #define LCD_MONO_8BIT_MODE (1 << 9) 7113402868SStefano Babic #define LCD_RASTER_ORDER (1 << 8) 7213402868SStefano Babic #define LCD_TFT_MODE (1 << 7) 73765f2f08SHeiko Schocher #define LCD_V1_UNDERFLOW_INT_ENA (1 << 6) 74765f2f08SHeiko Schocher #define LCD_V2_UNDERFLOW_INT_ENA (1 << 5) 75765f2f08SHeiko Schocher #define LCD_V1_PL_INT_ENA (1 << 4) 76765f2f08SHeiko Schocher #define LCD_V2_PL_INT_ENA (1 << 6) 7713402868SStefano Babic #define LCD_MONOCHROME_MODE (1 << 1) 7813402868SStefano Babic #define LCD_RASTER_ENABLE (1 << 0) 7913402868SStefano Babic #define LCD_TFT_ALT_ENABLE (1 << 23) 8013402868SStefano Babic #define LCD_STN_565_ENABLE (1 << 24) 81765f2f08SHeiko Schocher #define LCD_V2_DMA_CLK_EN (1 << 2) 82765f2f08SHeiko Schocher #define LCD_V2_LIDD_CLK_EN (1 << 1) 83765f2f08SHeiko Schocher #define LCD_V2_CORE_CLK_EN (1 << 0) 84765f2f08SHeiko Schocher #define LCD_V2_LPP_B10 26 85765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_MODE (1 << 25) 86765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_UNPACK (1 << 26) 8713402868SStefano Babic 8813402868SStefano Babic /* LCD Raster Timing 2 Register */ 8913402868SStefano Babic #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) 9013402868SStefano Babic #define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8) 9113402868SStefano Babic #define LCD_SYNC_CTRL (1 << 25) 9213402868SStefano Babic #define LCD_SYNC_EDGE (1 << 24) 9313402868SStefano Babic #define LCD_INVERT_PIXEL_CLOCK (1 << 22) 9413402868SStefano Babic #define LCD_INVERT_LINE_CLOCK (1 << 21) 9513402868SStefano Babic #define LCD_INVERT_FRAME_CLOCK (1 << 20) 9613402868SStefano Babic 97765f2f08SHeiko Schocher /* Clock registers available only on Version 2 */ 98765f2f08SHeiko Schocher #define LCD_CLK_MAIN_RESET (1 << 3) 9913402868SStefano Babic /* LCD Block */ 10013402868SStefano Babic struct da8xx_lcd_regs { 10113402868SStefano Babic u32 revid; 10213402868SStefano Babic u32 ctrl; 10313402868SStefano Babic u32 stat; 10413402868SStefano Babic u32 lidd_ctrl; 10513402868SStefano Babic u32 lidd_cs0_conf; 10613402868SStefano Babic u32 lidd_cs0_addr; 10713402868SStefano Babic u32 lidd_cs0_data; 10813402868SStefano Babic u32 lidd_cs1_conf; 10913402868SStefano Babic u32 lidd_cs1_addr; 11013402868SStefano Babic u32 lidd_cs1_data; 11113402868SStefano Babic u32 raster_ctrl; 11213402868SStefano Babic u32 raster_timing_0; 11313402868SStefano Babic u32 raster_timing_1; 11413402868SStefano Babic u32 raster_timing_2; 11513402868SStefano Babic u32 raster_subpanel; 11613402868SStefano Babic u32 reserved; 11713402868SStefano Babic u32 dma_ctrl; 11813402868SStefano Babic u32 dma_frm_buf_base_addr_0; 11913402868SStefano Babic u32 dma_frm_buf_ceiling_addr_0; 12013402868SStefano Babic u32 dma_frm_buf_base_addr_1; 12113402868SStefano Babic u32 dma_frm_buf_ceiling_addr_1; 122765f2f08SHeiko Schocher u32 resv1; 123765f2f08SHeiko Schocher u32 raw_stat; 124765f2f08SHeiko Schocher u32 masked_stat; 125765f2f08SHeiko Schocher u32 int_ena_set; 126765f2f08SHeiko Schocher u32 int_ena_clr; 127765f2f08SHeiko Schocher u32 end_of_int_ind; 128765f2f08SHeiko Schocher /* Clock registers available only on Version 2 */ 129765f2f08SHeiko Schocher u32 clk_ena; 130765f2f08SHeiko Schocher u32 clk_reset; 13113402868SStefano Babic }; 13213402868SStefano Babic 13313402868SStefano Babic #define LCD_NUM_BUFFERS 1 13413402868SStefano Babic 13513402868SStefano Babic #define WSI_TIMEOUT 50 13613402868SStefano Babic #define PALETTE_SIZE 256 13713402868SStefano Babic #define LEFT_MARGIN 64 13813402868SStefano Babic #define RIGHT_MARGIN 64 13913402868SStefano Babic #define UPPER_MARGIN 32 14013402868SStefano Babic #define LOWER_MARGIN 32 141765f2f08SHeiko Schocher #define WAIT_FOR_FRAME_DONE true 142765f2f08SHeiko Schocher #define NO_WAIT_FOR_FRAME_DONE false 14313402868SStefano Babic 14413402868SStefano Babic #define calc_fbsize() (panel.plnSizeX * panel.plnSizeY * panel.gdfBytesPP) 14513402868SStefano Babic 14613402868SStefano Babic static struct da8xx_lcd_regs *da8xx_fb_reg_base; 14713402868SStefano Babic 14813402868SStefano Babic DECLARE_GLOBAL_DATA_PTR; 14913402868SStefano Babic 15013402868SStefano Babic /* graphics setup */ 15113402868SStefano Babic static GraphicDevice gpanel; 15213402868SStefano Babic static const struct da8xx_panel *lcd_panel; 15313402868SStefano Babic static struct fb_info *da8xx_fb_info; 15413402868SStefano Babic static int bits_x_pixel; 155765f2f08SHeiko Schocher static unsigned int lcd_revision; 156765f2f08SHeiko Schocher const struct lcd_ctrl_config *da8xx_lcd_cfg; 15713402868SStefano Babic 15813402868SStefano Babic static inline unsigned int lcdc_read(u32 *addr) 15913402868SStefano Babic { 16013402868SStefano Babic return (unsigned int)readl(addr); 16113402868SStefano Babic } 16213402868SStefano Babic 16313402868SStefano Babic static inline void lcdc_write(unsigned int val, u32 *addr) 16413402868SStefano Babic { 16513402868SStefano Babic writel(val, addr); 16613402868SStefano Babic } 16713402868SStefano Babic 16813402868SStefano Babic struct da8xx_fb_par { 16913402868SStefano Babic u32 p_palette_base; 17013402868SStefano Babic unsigned char *v_palette_base; 17113402868SStefano Babic dma_addr_t vram_phys; 17213402868SStefano Babic unsigned long vram_size; 17313402868SStefano Babic void *vram_virt; 17413402868SStefano Babic unsigned int dma_start; 17513402868SStefano Babic unsigned int dma_end; 17613402868SStefano Babic struct clk *lcdc_clk; 17713402868SStefano Babic int irq; 17813402868SStefano Babic unsigned short pseudo_palette[16]; 17913402868SStefano Babic unsigned int palette_sz; 18013402868SStefano Babic unsigned int pxl_clk; 18113402868SStefano Babic int blank; 18213402868SStefano Babic int vsync_flag; 18313402868SStefano Babic int vsync_timeout; 18413402868SStefano Babic }; 18513402868SStefano Babic 18613402868SStefano Babic 18713402868SStefano Babic /* Variable Screen Information */ 18813402868SStefano Babic static struct fb_var_screeninfo da8xx_fb_var = { 18913402868SStefano Babic .xoffset = 0, 19013402868SStefano Babic .yoffset = 0, 19113402868SStefano Babic .transp = {0, 0, 0}, 19213402868SStefano Babic .nonstd = 0, 19313402868SStefano Babic .activate = 0, 19413402868SStefano Babic .height = -1, 19513402868SStefano Babic .width = -1, 19613402868SStefano Babic .pixclock = 46666, /* 46us - AUO display */ 19713402868SStefano Babic .accel_flags = 0, 19813402868SStefano Babic .left_margin = LEFT_MARGIN, 19913402868SStefano Babic .right_margin = RIGHT_MARGIN, 20013402868SStefano Babic .upper_margin = UPPER_MARGIN, 20113402868SStefano Babic .lower_margin = LOWER_MARGIN, 20213402868SStefano Babic .sync = 0, 20313402868SStefano Babic .vmode = FB_VMODE_NONINTERLACED 20413402868SStefano Babic }; 20513402868SStefano Babic 20613402868SStefano Babic static struct fb_fix_screeninfo da8xx_fb_fix = { 20713402868SStefano Babic .id = "DA8xx FB Drv", 20813402868SStefano Babic .type = FB_TYPE_PACKED_PIXELS, 20913402868SStefano Babic .type_aux = 0, 21013402868SStefano Babic .visual = FB_VISUAL_PSEUDOCOLOR, 21113402868SStefano Babic .xpanstep = 0, 21213402868SStefano Babic .ypanstep = 1, 21313402868SStefano Babic .ywrapstep = 0, 21413402868SStefano Babic .accel = FB_ACCEL_NONE 21513402868SStefano Babic }; 21613402868SStefano Babic 21713402868SStefano Babic /* Enable the Raster Engine of the LCD Controller */ 21813402868SStefano Babic static inline void lcd_enable_raster(void) 21913402868SStefano Babic { 22013402868SStefano Babic u32 reg; 22113402868SStefano Babic 222765f2f08SHeiko Schocher /* Put LCDC in reset for several cycles */ 223765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2) 224765f2f08SHeiko Schocher lcdc_write(LCD_CLK_MAIN_RESET, 225765f2f08SHeiko Schocher &da8xx_fb_reg_base->clk_reset); 226765f2f08SHeiko Schocher 227765f2f08SHeiko Schocher udelay(1000); 228765f2f08SHeiko Schocher /* Bring LCDC out of reset */ 229765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2) 230765f2f08SHeiko Schocher lcdc_write(0, 231765f2f08SHeiko Schocher &da8xx_fb_reg_base->clk_reset); 232765f2f08SHeiko Schocher 233765f2f08SHeiko Schocher udelay(1000); 234765f2f08SHeiko Schocher 23513402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl); 23613402868SStefano Babic if (!(reg & LCD_RASTER_ENABLE)) 23713402868SStefano Babic lcdc_write(reg | LCD_RASTER_ENABLE, 23813402868SStefano Babic &da8xx_fb_reg_base->raster_ctrl); 23913402868SStefano Babic } 24013402868SStefano Babic 24113402868SStefano Babic /* Disable the Raster Engine of the LCD Controller */ 242765f2f08SHeiko Schocher static inline void lcd_disable_raster(bool wait_for_frame_done) 24313402868SStefano Babic { 24413402868SStefano Babic u32 reg; 245765f2f08SHeiko Schocher u32 loop_cnt = 0; 246765f2f08SHeiko Schocher u32 stat; 247765f2f08SHeiko Schocher u32 i = 0; 248765f2f08SHeiko Schocher 249765f2f08SHeiko Schocher if (wait_for_frame_done) 250765f2f08SHeiko Schocher loop_cnt = 5000; 25113402868SStefano Babic 25213402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl); 25313402868SStefano Babic if (reg & LCD_RASTER_ENABLE) 25413402868SStefano Babic lcdc_write(reg & ~LCD_RASTER_ENABLE, 25513402868SStefano Babic &da8xx_fb_reg_base->raster_ctrl); 256765f2f08SHeiko Schocher 257765f2f08SHeiko Schocher /* Wait for the current frame to complete */ 258765f2f08SHeiko Schocher do { 259765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) 260765f2f08SHeiko Schocher stat = lcdc_read(&da8xx_fb_reg_base->stat); 261765f2f08SHeiko Schocher else 262765f2f08SHeiko Schocher stat = lcdc_read(&da8xx_fb_reg_base->raw_stat); 263765f2f08SHeiko Schocher 264765f2f08SHeiko Schocher mdelay(1); 265765f2f08SHeiko Schocher } while (!(stat & 0x01) && (i++ < loop_cnt)); 266765f2f08SHeiko Schocher 267765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) 268765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->stat); 269765f2f08SHeiko Schocher else 270765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->raw_stat); 271765f2f08SHeiko Schocher 272765f2f08SHeiko Schocher if ((loop_cnt != 0) && (i >= loop_cnt)) { 273765f2f08SHeiko Schocher printf("LCD Controller timed out\n"); 274765f2f08SHeiko Schocher return; 275765f2f08SHeiko Schocher } 27613402868SStefano Babic } 27713402868SStefano Babic 27813402868SStefano Babic static void lcd_blit(int load_mode, struct da8xx_fb_par *par) 27913402868SStefano Babic { 28013402868SStefano Babic u32 start; 28113402868SStefano Babic u32 end; 28213402868SStefano Babic u32 reg_ras; 28313402868SStefano Babic u32 reg_dma; 284765f2f08SHeiko Schocher u32 reg_int; 28513402868SStefano Babic 28613402868SStefano Babic /* init reg to clear PLM (loading mode) fields */ 28713402868SStefano Babic reg_ras = lcdc_read(&da8xx_fb_reg_base->raster_ctrl); 28813402868SStefano Babic reg_ras &= ~(3 << 20); 28913402868SStefano Babic 29013402868SStefano Babic reg_dma = lcdc_read(&da8xx_fb_reg_base->dma_ctrl); 29113402868SStefano Babic 29213402868SStefano Babic if (load_mode == LOAD_DATA) { 29313402868SStefano Babic start = par->dma_start; 29413402868SStefano Babic end = par->dma_end; 29513402868SStefano Babic 29613402868SStefano Babic reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); 297765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) { 298765f2f08SHeiko Schocher reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA; 299765f2f08SHeiko Schocher } else { 300765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) | 301765f2f08SHeiko Schocher LCD_V2_END_OF_FRAME0_INT_ENA | 302765f2f08SHeiko Schocher LCD_V2_END_OF_FRAME1_INT_ENA | 303765f2f08SHeiko Schocher LCD_V2_UNDERFLOW_INT_ENA | LCD_SYNC_LOST; 304765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set); 305765f2f08SHeiko Schocher } 30613402868SStefano Babic 30713402868SStefano Babic #if (LCD_NUM_BUFFERS == 2) 30813402868SStefano Babic reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; 30913402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0); 31013402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0); 31113402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1); 31213402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1); 31313402868SStefano Babic #else 31413402868SStefano Babic reg_dma &= ~LCD_DUAL_FRAME_BUFFER_ENABLE; 31513402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0); 31613402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0); 31713402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1); 31813402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1); 31913402868SStefano Babic #endif 32013402868SStefano Babic 32113402868SStefano Babic } else if (load_mode == LOAD_PALETTE) { 32213402868SStefano Babic start = par->p_palette_base; 32313402868SStefano Babic end = start + par->palette_sz - 1; 32413402868SStefano Babic 32513402868SStefano Babic reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); 326765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) { 327765f2f08SHeiko Schocher reg_ras |= LCD_V1_PL_INT_ENA; 328765f2f08SHeiko Schocher } else { 329765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) | 330765f2f08SHeiko Schocher LCD_V2_PL_INT_ENA; 331765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set); 332765f2f08SHeiko Schocher } 33313402868SStefano Babic 33413402868SStefano Babic lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0); 33513402868SStefano Babic lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0); 33613402868SStefano Babic } 33713402868SStefano Babic 33813402868SStefano Babic lcdc_write(reg_dma, &da8xx_fb_reg_base->dma_ctrl); 33913402868SStefano Babic lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl); 34013402868SStefano Babic 34113402868SStefano Babic /* 34213402868SStefano Babic * The Raster enable bit must be set after all other control fields are 34313402868SStefano Babic * set. 34413402868SStefano Babic */ 34513402868SStefano Babic lcd_enable_raster(); 34613402868SStefano Babic } 34713402868SStefano Babic 34813402868SStefano Babic /* Configure the Burst Size of DMA */ 34913402868SStefano Babic static int lcd_cfg_dma(int burst_size) 35013402868SStefano Babic { 35113402868SStefano Babic u32 reg; 35213402868SStefano Babic 35313402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->dma_ctrl) & 0x00000001; 35413402868SStefano Babic switch (burst_size) { 35513402868SStefano Babic case 1: 35613402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1); 35713402868SStefano Babic break; 35813402868SStefano Babic case 2: 35913402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2); 36013402868SStefano Babic break; 36113402868SStefano Babic case 4: 36213402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4); 36313402868SStefano Babic break; 36413402868SStefano Babic case 8: 36513402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8); 36613402868SStefano Babic break; 36713402868SStefano Babic case 16: 36813402868SStefano Babic reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); 36913402868SStefano Babic break; 37013402868SStefano Babic default: 37113402868SStefano Babic return -EINVAL; 37213402868SStefano Babic } 37313402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->dma_ctrl); 37413402868SStefano Babic 37513402868SStefano Babic return 0; 37613402868SStefano Babic } 37713402868SStefano Babic 37813402868SStefano Babic static void lcd_cfg_ac_bias(int period, int transitions_per_int) 37913402868SStefano Babic { 38013402868SStefano Babic u32 reg; 38113402868SStefano Babic 38213402868SStefano Babic /* Set the AC Bias Period and Number of Transisitons per Interrupt */ 38313402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2) & 0xFFF00000; 38413402868SStefano Babic reg |= LCD_AC_BIAS_FREQUENCY(period) | 38513402868SStefano Babic LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int); 38613402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2); 38713402868SStefano Babic } 38813402868SStefano Babic 38913402868SStefano Babic static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width, 39013402868SStefano Babic int front_porch) 39113402868SStefano Babic { 39213402868SStefano Babic u32 reg; 39313402868SStefano Babic 39413402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0) & 0xf; 39513402868SStefano Babic reg |= ((back_porch & 0xff) << 24) 39613402868SStefano Babic | ((front_porch & 0xff) << 16) 39713402868SStefano Babic | ((pulse_width & 0x3f) << 10); 39813402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0); 39913402868SStefano Babic } 40013402868SStefano Babic 40113402868SStefano Babic static void lcd_cfg_vertical_sync(int back_porch, int pulse_width, 40213402868SStefano Babic int front_porch) 40313402868SStefano Babic { 40413402868SStefano Babic u32 reg; 40513402868SStefano Babic 40613402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1) & 0x3ff; 40713402868SStefano Babic reg |= ((back_porch & 0xff) << 24) 40813402868SStefano Babic | ((front_porch & 0xff) << 16) 40913402868SStefano Babic | ((pulse_width & 0x3f) << 10); 41013402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1); 41113402868SStefano Babic } 41213402868SStefano Babic 41313402868SStefano Babic static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) 41413402868SStefano Babic { 41513402868SStefano Babic u32 reg; 416765f2f08SHeiko Schocher u32 reg_int; 41713402868SStefano Babic 41813402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(LCD_TFT_MODE | 41913402868SStefano Babic LCD_MONO_8BIT_MODE | 42013402868SStefano Babic LCD_MONOCHROME_MODE); 42113402868SStefano Babic 42213402868SStefano Babic switch (cfg->p_disp_panel->panel_shade) { 42313402868SStefano Babic case MONOCHROME: 42413402868SStefano Babic reg |= LCD_MONOCHROME_MODE; 42513402868SStefano Babic if (cfg->mono_8bit_mode) 42613402868SStefano Babic reg |= LCD_MONO_8BIT_MODE; 42713402868SStefano Babic break; 42813402868SStefano Babic case COLOR_ACTIVE: 42913402868SStefano Babic reg |= LCD_TFT_MODE; 43013402868SStefano Babic if (cfg->tft_alt_mode) 43113402868SStefano Babic reg |= LCD_TFT_ALT_ENABLE; 43213402868SStefano Babic break; 43313402868SStefano Babic 43413402868SStefano Babic case COLOR_PASSIVE: 43513402868SStefano Babic if (cfg->stn_565_mode) 43613402868SStefano Babic reg |= LCD_STN_565_ENABLE; 43713402868SStefano Babic break; 43813402868SStefano Babic 43913402868SStefano Babic default: 44013402868SStefano Babic return -EINVAL; 44113402868SStefano Babic } 44213402868SStefano Babic 44313402868SStefano Babic /* enable additional interrupts here */ 444765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) { 445765f2f08SHeiko Schocher reg |= LCD_V1_UNDERFLOW_INT_ENA; 446765f2f08SHeiko Schocher } else { 447765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) | 448765f2f08SHeiko Schocher LCD_V2_UNDERFLOW_INT_ENA; 449765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set); 450765f2f08SHeiko Schocher } 45113402868SStefano Babic 45213402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl); 45313402868SStefano Babic 45413402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2); 45513402868SStefano Babic 45613402868SStefano Babic if (cfg->sync_ctrl) 45713402868SStefano Babic reg |= LCD_SYNC_CTRL; 45813402868SStefano Babic else 45913402868SStefano Babic reg &= ~LCD_SYNC_CTRL; 46013402868SStefano Babic 46113402868SStefano Babic if (cfg->sync_edge) 46213402868SStefano Babic reg |= LCD_SYNC_EDGE; 46313402868SStefano Babic else 46413402868SStefano Babic reg &= ~LCD_SYNC_EDGE; 46513402868SStefano Babic 46613402868SStefano Babic if (cfg->invert_line_clock) 46713402868SStefano Babic reg |= LCD_INVERT_LINE_CLOCK; 46813402868SStefano Babic else 46913402868SStefano Babic reg &= ~LCD_INVERT_LINE_CLOCK; 47013402868SStefano Babic 47113402868SStefano Babic if (cfg->invert_frm_clock) 47213402868SStefano Babic reg |= LCD_INVERT_FRAME_CLOCK; 47313402868SStefano Babic else 47413402868SStefano Babic reg &= ~LCD_INVERT_FRAME_CLOCK; 47513402868SStefano Babic 47613402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2); 47713402868SStefano Babic 47813402868SStefano Babic return 0; 47913402868SStefano Babic } 48013402868SStefano Babic 48113402868SStefano Babic static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, 48213402868SStefano Babic u32 bpp, u32 raster_order) 48313402868SStefano Babic { 48413402868SStefano Babic u32 reg; 48513402868SStefano Babic 48613402868SStefano Babic /* Set the Panel Width */ 48713402868SStefano Babic /* Pixels per line = (PPL + 1)*16 */ 488765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) { 489765f2f08SHeiko Schocher /* 490765f2f08SHeiko Schocher * 0x3F in bits 4..9 gives max horisontal resolution = 1024 491765f2f08SHeiko Schocher * pixels 492765f2f08SHeiko Schocher */ 49313402868SStefano Babic width &= 0x3f0; 494765f2f08SHeiko Schocher } else { 495765f2f08SHeiko Schocher /* 496765f2f08SHeiko Schocher * 0x7F in bits 4..10 gives max horizontal resolution = 2048 497765f2f08SHeiko Schocher * pixels. 498765f2f08SHeiko Schocher */ 499765f2f08SHeiko Schocher width &= 0x7f0; 500765f2f08SHeiko Schocher } 50113402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0); 50213402868SStefano Babic reg &= 0xfffffc00; 503765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) { 50413402868SStefano Babic reg |= ((width >> 4) - 1) << 4; 505765f2f08SHeiko Schocher } else { 506765f2f08SHeiko Schocher width = (width >> 4) - 1; 507765f2f08SHeiko Schocher reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3); 508765f2f08SHeiko Schocher } 50913402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0); 51013402868SStefano Babic 51113402868SStefano Babic /* Set the Panel Height */ 512765f2f08SHeiko Schocher /* Set bits 9:0 of Lines Per Pixel */ 51313402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1); 51413402868SStefano Babic reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00); 51513402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1); 51613402868SStefano Babic 517765f2f08SHeiko Schocher /* Set bit 10 of Lines Per Pixel */ 518765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2) { 519765f2f08SHeiko Schocher reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2); 520765f2f08SHeiko Schocher reg |= ((height - 1) & 0x400) << 16; 521765f2f08SHeiko Schocher lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2); 522765f2f08SHeiko Schocher } 523765f2f08SHeiko Schocher 52413402868SStefano Babic /* Set the Raster Order of the Frame Buffer */ 52513402868SStefano Babic reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(1 << 8); 52613402868SStefano Babic if (raster_order) 52713402868SStefano Babic reg |= LCD_RASTER_ORDER; 528765f2f08SHeiko Schocher 529765f2f08SHeiko Schocher if (bpp == 24) 530765f2f08SHeiko Schocher reg |= (LCD_TFT_MODE | LCD_V2_TFT_24BPP_MODE); 531765f2f08SHeiko Schocher else if (bpp == 32) 532765f2f08SHeiko Schocher reg |= (LCD_TFT_MODE | LCD_V2_TFT_24BPP_MODE 533765f2f08SHeiko Schocher | LCD_V2_TFT_24BPP_UNPACK); 534765f2f08SHeiko Schocher 53513402868SStefano Babic lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl); 53613402868SStefano Babic 53713402868SStefano Babic switch (bpp) { 53813402868SStefano Babic case 1: 53913402868SStefano Babic case 2: 54013402868SStefano Babic case 4: 54113402868SStefano Babic case 16: 542765f2f08SHeiko Schocher case 24: 543765f2f08SHeiko Schocher case 32: 54413402868SStefano Babic par->palette_sz = 16 * 2; 54513402868SStefano Babic break; 54613402868SStefano Babic 54713402868SStefano Babic case 8: 54813402868SStefano Babic par->palette_sz = 256 * 2; 54913402868SStefano Babic break; 55013402868SStefano Babic 55113402868SStefano Babic default: 55213402868SStefano Babic return -EINVAL; 55313402868SStefano Babic } 55413402868SStefano Babic 55513402868SStefano Babic return 0; 55613402868SStefano Babic } 55713402868SStefano Babic 55813402868SStefano Babic static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, 55913402868SStefano Babic unsigned blue, unsigned transp, 56013402868SStefano Babic struct fb_info *info) 56113402868SStefano Babic { 56213402868SStefano Babic struct da8xx_fb_par *par = info->par; 56313402868SStefano Babic unsigned short *palette = (unsigned short *) par->v_palette_base; 56413402868SStefano Babic u_short pal; 56513402868SStefano Babic int update_hw = 0; 56613402868SStefano Babic 56713402868SStefano Babic if (regno > 255) 56813402868SStefano Babic return 1; 56913402868SStefano Babic 57013402868SStefano Babic if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) 57113402868SStefano Babic return 1; 57213402868SStefano Babic 57313402868SStefano Babic if (info->var.bits_per_pixel == 8) { 57413402868SStefano Babic red >>= 4; 57513402868SStefano Babic green >>= 8; 57613402868SStefano Babic blue >>= 12; 57713402868SStefano Babic 57813402868SStefano Babic pal = (red & 0x0f00); 57913402868SStefano Babic pal |= (green & 0x00f0); 58013402868SStefano Babic pal |= (blue & 0x000f); 58113402868SStefano Babic 58213402868SStefano Babic if (palette[regno] != pal) { 58313402868SStefano Babic update_hw = 1; 58413402868SStefano Babic palette[regno] = pal; 58513402868SStefano Babic } 58613402868SStefano Babic } else if ((info->var.bits_per_pixel == 16) && regno < 16) { 58713402868SStefano Babic red >>= (16 - info->var.red.length); 58813402868SStefano Babic red <<= info->var.red.offset; 58913402868SStefano Babic 59013402868SStefano Babic green >>= (16 - info->var.green.length); 59113402868SStefano Babic green <<= info->var.green.offset; 59213402868SStefano Babic 59313402868SStefano Babic blue >>= (16 - info->var.blue.length); 59413402868SStefano Babic blue <<= info->var.blue.offset; 59513402868SStefano Babic 59613402868SStefano Babic par->pseudo_palette[regno] = red | green | blue; 59713402868SStefano Babic 59813402868SStefano Babic if (palette[0] != 0x4000) { 59913402868SStefano Babic update_hw = 1; 60013402868SStefano Babic palette[0] = 0x4000; 60113402868SStefano Babic } 602765f2f08SHeiko Schocher } else if (((info->var.bits_per_pixel == 32) && regno < 32) || 603765f2f08SHeiko Schocher ((info->var.bits_per_pixel == 24) && regno < 24)) { 604765f2f08SHeiko Schocher red >>= (24 - info->var.red.length); 605765f2f08SHeiko Schocher red <<= info->var.red.offset; 606765f2f08SHeiko Schocher 607765f2f08SHeiko Schocher green >>= (24 - info->var.green.length); 608765f2f08SHeiko Schocher green <<= info->var.green.offset; 609765f2f08SHeiko Schocher 610765f2f08SHeiko Schocher blue >>= (24 - info->var.blue.length); 611765f2f08SHeiko Schocher blue <<= info->var.blue.offset; 612765f2f08SHeiko Schocher 613765f2f08SHeiko Schocher par->pseudo_palette[regno] = red | green | blue; 614765f2f08SHeiko Schocher 615765f2f08SHeiko Schocher if (palette[0] != 0x4000) { 616765f2f08SHeiko Schocher update_hw = 1; 617765f2f08SHeiko Schocher palette[0] = 0x4000; 618765f2f08SHeiko Schocher } 61913402868SStefano Babic } 62013402868SStefano Babic 62113402868SStefano Babic /* Update the palette in the h/w as needed. */ 62213402868SStefano Babic if (update_hw) 62313402868SStefano Babic lcd_blit(LOAD_PALETTE, par); 62413402868SStefano Babic 62513402868SStefano Babic return 0; 62613402868SStefano Babic } 62713402868SStefano Babic 62813402868SStefano Babic static void lcd_reset(struct da8xx_fb_par *par) 62913402868SStefano Babic { 63013402868SStefano Babic /* Disable the Raster if previously Enabled */ 631765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE); 63213402868SStefano Babic 63313402868SStefano Babic /* DMA has to be disabled */ 63413402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->dma_ctrl); 63513402868SStefano Babic lcdc_write(0, &da8xx_fb_reg_base->raster_ctrl); 636765f2f08SHeiko Schocher 637765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2) { 638765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->int_ena_set); 639765f2f08SHeiko Schocher /* Write 1 to reset */ 640765f2f08SHeiko Schocher lcdc_write(LCD_CLK_MAIN_RESET, &da8xx_fb_reg_base->clk_reset); 641765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->clk_reset); 642765f2f08SHeiko Schocher } 64313402868SStefano Babic } 64413402868SStefano Babic 64513402868SStefano Babic static void lcd_calc_clk_divider(struct da8xx_fb_par *par) 64613402868SStefano Babic { 64713402868SStefano Babic unsigned int lcd_clk, div; 64813402868SStefano Babic 64913402868SStefano Babic /* Get clock from sysclk2 */ 65013402868SStefano Babic lcd_clk = clk_get(2); 65113402868SStefano Babic 65213402868SStefano Babic div = lcd_clk / par->pxl_clk; 653765f2f08SHeiko Schocher debug("LCD Clock: %d Divider: %d PixClk: %d\n", 65413402868SStefano Babic lcd_clk, div, par->pxl_clk); 65513402868SStefano Babic 65613402868SStefano Babic /* Configure the LCD clock divisor. */ 65713402868SStefano Babic lcdc_write(LCD_CLK_DIVISOR(div) | 65813402868SStefano Babic (LCD_RASTER_MODE & 0x1), &da8xx_fb_reg_base->ctrl); 659765f2f08SHeiko Schocher 660765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_2) 661765f2f08SHeiko Schocher lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | 662765f2f08SHeiko Schocher LCD_V2_CORE_CLK_EN, 663765f2f08SHeiko Schocher &da8xx_fb_reg_base->clk_ena); 66413402868SStefano Babic } 66513402868SStefano Babic 66613402868SStefano Babic static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, 66713402868SStefano Babic const struct da8xx_panel *panel) 66813402868SStefano Babic { 66913402868SStefano Babic u32 bpp; 67013402868SStefano Babic int ret = 0; 67113402868SStefano Babic 67213402868SStefano Babic lcd_reset(par); 67313402868SStefano Babic 67413402868SStefano Babic /* Calculate the divider */ 67513402868SStefano Babic lcd_calc_clk_divider(par); 67613402868SStefano Babic 67713402868SStefano Babic if (panel->invert_pxl_clk) 67813402868SStefano Babic lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) | 67913402868SStefano Babic LCD_INVERT_PIXEL_CLOCK), 68013402868SStefano Babic &da8xx_fb_reg_base->raster_timing_2); 68113402868SStefano Babic else 68213402868SStefano Babic lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) & 68313402868SStefano Babic ~LCD_INVERT_PIXEL_CLOCK), 68413402868SStefano Babic &da8xx_fb_reg_base->raster_timing_2); 68513402868SStefano Babic 68613402868SStefano Babic /* Configure the DMA burst size. */ 68713402868SStefano Babic ret = lcd_cfg_dma(cfg->dma_burst_sz); 68813402868SStefano Babic if (ret < 0) 68913402868SStefano Babic return ret; 69013402868SStefano Babic 69113402868SStefano Babic /* Configure the AC bias properties. */ 69213402868SStefano Babic lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt); 69313402868SStefano Babic 69413402868SStefano Babic /* Configure the vertical and horizontal sync properties. */ 69513402868SStefano Babic lcd_cfg_vertical_sync(panel->vbp, panel->vsw, panel->vfp); 69613402868SStefano Babic lcd_cfg_horizontal_sync(panel->hbp, panel->hsw, panel->hfp); 69713402868SStefano Babic 69813402868SStefano Babic /* Configure for disply */ 69913402868SStefano Babic ret = lcd_cfg_display(cfg); 70013402868SStefano Babic if (ret < 0) 70113402868SStefano Babic return ret; 70213402868SStefano Babic 703765f2f08SHeiko Schocher if ((QVGA != cfg->p_disp_panel->panel_type) && 704765f2f08SHeiko Schocher (WVGA != cfg->p_disp_panel->panel_type)) 70513402868SStefano Babic return -EINVAL; 70613402868SStefano Babic 70713402868SStefano Babic if (cfg->bpp <= cfg->p_disp_panel->max_bpp && 70813402868SStefano Babic cfg->bpp >= cfg->p_disp_panel->min_bpp) 70913402868SStefano Babic bpp = cfg->bpp; 71013402868SStefano Babic else 71113402868SStefano Babic bpp = cfg->p_disp_panel->max_bpp; 71213402868SStefano Babic if (bpp == 12) 71313402868SStefano Babic bpp = 16; 71413402868SStefano Babic ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->width, 71513402868SStefano Babic (unsigned int)panel->height, bpp, 71613402868SStefano Babic cfg->raster_order); 71713402868SStefano Babic if (ret < 0) 71813402868SStefano Babic return ret; 71913402868SStefano Babic 72013402868SStefano Babic /* Configure FDD */ 72113402868SStefano Babic lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & 0xfff00fff) | 72213402868SStefano Babic (cfg->fdd << 12), &da8xx_fb_reg_base->raster_ctrl); 72313402868SStefano Babic 72413402868SStefano Babic return 0; 72513402868SStefano Babic } 72613402868SStefano Babic 72713402868SStefano Babic static void lcdc_dma_start(void) 72813402868SStefano Babic { 72913402868SStefano Babic struct da8xx_fb_par *par = da8xx_fb_info->par; 73013402868SStefano Babic lcdc_write(par->dma_start, 73113402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_base_addr_0); 73213402868SStefano Babic lcdc_write(par->dma_end, 73313402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0); 73413402868SStefano Babic lcdc_write(0, 73513402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_base_addr_1); 73613402868SStefano Babic lcdc_write(0, 73713402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1); 73813402868SStefano Babic } 73913402868SStefano Babic 740765f2f08SHeiko Schocher static u32 lcdc_irq_handler_rev01(void) 74113402868SStefano Babic { 74213402868SStefano Babic struct da8xx_fb_par *par = da8xx_fb_info->par; 74313402868SStefano Babic u32 stat = lcdc_read(&da8xx_fb_reg_base->stat); 74413402868SStefano Babic u32 reg_ras; 74513402868SStefano Babic 74613402868SStefano Babic if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { 74713402868SStefano Babic debug("LCD_SYNC_LOST\n"); 748765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE); 74913402868SStefano Babic lcdc_write(stat, &da8xx_fb_reg_base->stat); 75013402868SStefano Babic lcd_enable_raster(); 75113402868SStefano Babic return LCD_SYNC_LOST; 75213402868SStefano Babic } else if (stat & LCD_PL_LOAD_DONE) { 75313402868SStefano Babic debug("LCD_PL_LOAD_DONE\n"); 75413402868SStefano Babic /* 75513402868SStefano Babic * Must disable raster before changing state of any control bit. 75613402868SStefano Babic * And also must be disabled before clearing the PL loading 75713402868SStefano Babic * interrupt via the following write to the status register. If 75813402868SStefano Babic * this is done after then one gets multiple PL done interrupts. 75913402868SStefano Babic */ 760765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE); 76113402868SStefano Babic 76213402868SStefano Babic lcdc_write(stat, &da8xx_fb_reg_base->stat); 76313402868SStefano Babic 76413402868SStefano Babic /* Disable PL completion inerrupt */ 76513402868SStefano Babic reg_ras = lcdc_read(&da8xx_fb_reg_base->raster_ctrl); 766765f2f08SHeiko Schocher reg_ras &= ~LCD_V1_PL_INT_ENA; 76713402868SStefano Babic lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl); 76813402868SStefano Babic 76913402868SStefano Babic /* Setup and start data loading mode */ 77013402868SStefano Babic lcd_blit(LOAD_DATA, par); 77113402868SStefano Babic return LCD_PL_LOAD_DONE; 77213402868SStefano Babic } else { 77313402868SStefano Babic lcdc_write(stat, &da8xx_fb_reg_base->stat); 77413402868SStefano Babic 77513402868SStefano Babic if (stat & LCD_END_OF_FRAME0) 77613402868SStefano Babic debug("LCD_END_OF_FRAME0\n"); 77713402868SStefano Babic 77813402868SStefano Babic lcdc_write(par->dma_start, 77913402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_base_addr_0); 78013402868SStefano Babic lcdc_write(par->dma_end, 78113402868SStefano Babic &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0); 78213402868SStefano Babic par->vsync_flag = 1; 78313402868SStefano Babic return LCD_END_OF_FRAME0; 78413402868SStefano Babic } 78513402868SStefano Babic return stat; 78613402868SStefano Babic } 78713402868SStefano Babic 788765f2f08SHeiko Schocher static u32 lcdc_irq_handler_rev02(void) 789765f2f08SHeiko Schocher { 790765f2f08SHeiko Schocher struct da8xx_fb_par *par = da8xx_fb_info->par; 791765f2f08SHeiko Schocher u32 stat = lcdc_read(&da8xx_fb_reg_base->masked_stat); 792765f2f08SHeiko Schocher u32 reg_int; 793765f2f08SHeiko Schocher 794765f2f08SHeiko Schocher if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { 795765f2f08SHeiko Schocher debug("LCD_SYNC_LOST\n"); 796765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE); 797765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->masked_stat); 798765f2f08SHeiko Schocher lcd_enable_raster(); 799765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind); 800765f2f08SHeiko Schocher return LCD_SYNC_LOST; 801765f2f08SHeiko Schocher } else if (stat & LCD_PL_LOAD_DONE) { 802765f2f08SHeiko Schocher debug("LCD_PL_LOAD_DONE\n"); 803765f2f08SHeiko Schocher /* 804765f2f08SHeiko Schocher * Must disable raster before changing state of any control bit. 805765f2f08SHeiko Schocher * And also must be disabled before clearing the PL loading 806765f2f08SHeiko Schocher * interrupt via the following write to the status register. If 807765f2f08SHeiko Schocher * this is done after then one gets multiple PL done interrupts. 808765f2f08SHeiko Schocher */ 809765f2f08SHeiko Schocher lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE); 810765f2f08SHeiko Schocher 811765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->masked_stat); 812765f2f08SHeiko Schocher 813765f2f08SHeiko Schocher /* Disable PL completion inerrupt */ 814765f2f08SHeiko Schocher reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_clr) | 815765f2f08SHeiko Schocher (LCD_V2_PL_INT_ENA); 816765f2f08SHeiko Schocher lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_clr); 817765f2f08SHeiko Schocher 818765f2f08SHeiko Schocher /* Setup and start data loading mode */ 819765f2f08SHeiko Schocher lcd_blit(LOAD_DATA, par); 820765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind); 821765f2f08SHeiko Schocher return LCD_PL_LOAD_DONE; 822765f2f08SHeiko Schocher } else { 823765f2f08SHeiko Schocher lcdc_write(stat, &da8xx_fb_reg_base->masked_stat); 824765f2f08SHeiko Schocher 825765f2f08SHeiko Schocher if (stat & LCD_END_OF_FRAME0) 826765f2f08SHeiko Schocher debug("LCD_END_OF_FRAME0\n"); 827765f2f08SHeiko Schocher 828765f2f08SHeiko Schocher lcdc_write(par->dma_start, 829765f2f08SHeiko Schocher &da8xx_fb_reg_base->dma_frm_buf_base_addr_0); 830765f2f08SHeiko Schocher lcdc_write(par->dma_end, 831765f2f08SHeiko Schocher &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0); 832765f2f08SHeiko Schocher par->vsync_flag = 1; 833765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind); 834765f2f08SHeiko Schocher return LCD_END_OF_FRAME0; 835765f2f08SHeiko Schocher } 836765f2f08SHeiko Schocher lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind); 837765f2f08SHeiko Schocher return stat; 838765f2f08SHeiko Schocher } 839765f2f08SHeiko Schocher 840765f2f08SHeiko Schocher static u32 lcdc_irq_handler(void) 841765f2f08SHeiko Schocher { 842765f2f08SHeiko Schocher if (lcd_revision == LCD_VERSION_1) 843765f2f08SHeiko Schocher return lcdc_irq_handler_rev01(); 844765f2f08SHeiko Schocher else 845765f2f08SHeiko Schocher return lcdc_irq_handler_rev02(); 846765f2f08SHeiko Schocher } 847765f2f08SHeiko Schocher 84813402868SStefano Babic static u32 wait_for_event(u32 event) 84913402868SStefano Babic { 85013402868SStefano Babic u32 timeout = 50000; 85113402868SStefano Babic u32 ret; 85213402868SStefano Babic 85313402868SStefano Babic do { 85413402868SStefano Babic ret = lcdc_irq_handler(); 85513402868SStefano Babic udelay(1000); 85613402868SStefano Babic } while (!(ret & event)); 85713402868SStefano Babic 85813402868SStefano Babic if (timeout <= 0) { 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 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); 92713402868SStefano Babic da8xx_fb_info = malloc(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 95213402868SStefano Babic par->vram_virt = malloc(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 } 962*4e023626SHeiko 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 */ 97513402868SStefano Babic par->v_palette_base = malloc(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 103813402868SStefano Babic void video_set_lut(unsigned int index, /* color number */ 103913402868SStefano Babic unsigned char r, /* red */ 104013402868SStefano Babic unsigned char g, /* green */ 104113402868SStefano Babic unsigned char b /* blue */ 104213402868SStefano Babic ) 104313402868SStefano Babic { 104413402868SStefano Babic 104513402868SStefano Babic return; 104613402868SStefano Babic } 104713402868SStefano Babic 1048765f2f08SHeiko Schocher void da8xx_video_init(const struct da8xx_panel *panel, 1049765f2f08SHeiko Schocher const struct lcd_ctrl_config *lcd_cfg, int bits_pixel) 105013402868SStefano Babic { 105113402868SStefano Babic lcd_panel = panel; 1052765f2f08SHeiko Schocher da8xx_lcd_cfg = lcd_cfg; 105313402868SStefano Babic bits_x_pixel = bits_pixel; 105413402868SStefano Babic } 1055