1*f6b690e6SBo Shen /* 2*f6b690e6SBo Shen * Driver for AT91/AT32 MULTI LAYER LCD Controller 3*f6b690e6SBo Shen * 4*f6b690e6SBo Shen * Copyright (C) 2012 Atmel Corporation 5*f6b690e6SBo Shen * 6*f6b690e6SBo Shen * See file CREDITS for list of people who contributed to this 7*f6b690e6SBo Shen * project. 8*f6b690e6SBo Shen * 9*f6b690e6SBo Shen * This program is free software; you can redistribute it and/or 10*f6b690e6SBo Shen * modify it under the terms of the GNU General Public License as 11*f6b690e6SBo Shen * published by the Free Software Foundation; either version 2 of 12*f6b690e6SBo Shen * the License, or (at your option) any later version. 13*f6b690e6SBo Shen * 14*f6b690e6SBo Shen * This program is distributed in the hope that it will be useful, 15*f6b690e6SBo Shen * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*f6b690e6SBo Shen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*f6b690e6SBo Shen * GNU General Public License for more details. 18*f6b690e6SBo Shen * 19*f6b690e6SBo Shen * You should have received a copy of the GNU General Public License 20*f6b690e6SBo Shen * along with this program; if not, write to the Free Software 21*f6b690e6SBo Shen * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22*f6b690e6SBo Shen * MA 02111-1307 USA 23*f6b690e6SBo Shen */ 24*f6b690e6SBo Shen 25*f6b690e6SBo Shen #include <common.h> 26*f6b690e6SBo Shen #include <asm/io.h> 27*f6b690e6SBo Shen #include <asm/arch/gpio.h> 28*f6b690e6SBo Shen #include <asm/arch/clk.h> 29*f6b690e6SBo Shen #include <lcd.h> 30*f6b690e6SBo Shen #include <atmel_hlcdc.h> 31*f6b690e6SBo Shen 32*f6b690e6SBo Shen int lcd_line_length; 33*f6b690e6SBo Shen int lcd_color_fg; 34*f6b690e6SBo Shen int lcd_color_bg; 35*f6b690e6SBo Shen 36*f6b690e6SBo Shen void *lcd_base; /* Start of framebuffer memory */ 37*f6b690e6SBo Shen void *lcd_console_address; /* Start of console buffer */ 38*f6b690e6SBo Shen 39*f6b690e6SBo Shen short console_col; 40*f6b690e6SBo Shen short console_row; 41*f6b690e6SBo Shen 42*f6b690e6SBo Shen /* configurable parameters */ 43*f6b690e6SBo Shen #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 44*f6b690e6SBo Shen #define ATMEL_LCDC_DMA_BURST_LEN 8 45*f6b690e6SBo Shen #ifndef ATMEL_LCDC_GUARD_TIME 46*f6b690e6SBo Shen #define ATMEL_LCDC_GUARD_TIME 1 47*f6b690e6SBo Shen #endif 48*f6b690e6SBo Shen 49*f6b690e6SBo Shen #define ATMEL_LCDC_FIFO_SIZE 512 50*f6b690e6SBo Shen 51*f6b690e6SBo Shen #define lcdc_readl(reg) __raw_readl((reg)) 52*f6b690e6SBo Shen #define lcdc_writel(reg, val) __raw_writel((val), (reg)) 53*f6b690e6SBo Shen 54*f6b690e6SBo Shen void lcd_ctrl_init(void *lcdbase) 55*f6b690e6SBo Shen { 56*f6b690e6SBo Shen unsigned long value; 57*f6b690e6SBo Shen struct lcd_dma_desc *desc; 58*f6b690e6SBo Shen struct atmel_hlcd_regs *regs; 59*f6b690e6SBo Shen 60*f6b690e6SBo Shen if (!has_lcdc()) 61*f6b690e6SBo Shen return; /* No lcdc */ 62*f6b690e6SBo Shen 63*f6b690e6SBo Shen regs = (struct atmel_hlcd_regs *)panel_info.mmio; 64*f6b690e6SBo Shen 65*f6b690e6SBo Shen /* Disable DISP signal */ 66*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_DISPDIS); 67*f6b690e6SBo Shen while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS)) 68*f6b690e6SBo Shen udelay(1); 69*f6b690e6SBo Shen /* Disable synchronization */ 70*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_SYNCDIS); 71*f6b690e6SBo Shen while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS)) 72*f6b690e6SBo Shen udelay(1); 73*f6b690e6SBo Shen /* Disable pixel clock */ 74*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_CLKDIS); 75*f6b690e6SBo Shen while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS)) 76*f6b690e6SBo Shen udelay(1); 77*f6b690e6SBo Shen /* Disable PWM */ 78*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_PWMDIS); 79*f6b690e6SBo Shen while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) 80*f6b690e6SBo Shen udelay(1); 81*f6b690e6SBo Shen 82*f6b690e6SBo Shen /* Set pixel clock */ 83*f6b690e6SBo Shen value = get_lcdc_clk_rate(0) / panel_info.vl_clk; 84*f6b690e6SBo Shen if (get_lcdc_clk_rate(0) % panel_info.vl_clk) 85*f6b690e6SBo Shen value++; 86*f6b690e6SBo Shen 87*f6b690e6SBo Shen if (value < 1) { 88*f6b690e6SBo Shen /* Using system clock as pixel clock */ 89*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdcfg0, 90*f6b690e6SBo Shen LCDC_LCDCFG0_CLKDIV(0) 91*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHCR 92*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHEO 93*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISOVR1 94*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISBASE 95*f6b690e6SBo Shen | panel_info.vl_clk_pol 96*f6b690e6SBo Shen | LCDC_LCDCFG0_CLKSEL); 97*f6b690e6SBo Shen 98*f6b690e6SBo Shen } else { 99*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdcfg0, 100*f6b690e6SBo Shen LCDC_LCDCFG0_CLKDIV(value - 2) 101*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHCR 102*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHEO 103*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISOVR1 104*f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISBASE 105*f6b690e6SBo Shen | panel_info.vl_clk_pol); 106*f6b690e6SBo Shen } 107*f6b690e6SBo Shen 108*f6b690e6SBo Shen /* Initialize control register 5 */ 109*f6b690e6SBo Shen value = 0; 110*f6b690e6SBo Shen 111*f6b690e6SBo Shen value |= panel_info.vl_sync; 112*f6b690e6SBo Shen 113*f6b690e6SBo Shen #ifndef LCD_OUTPUT_BPP 114*f6b690e6SBo Shen /* Output is 24bpp */ 115*f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; 116*f6b690e6SBo Shen #else 117*f6b690e6SBo Shen switch (LCD_OUTPUT_BPP) { 118*f6b690e6SBo Shen case 12: 119*f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; 120*f6b690e6SBo Shen break; 121*f6b690e6SBo Shen case 16: 122*f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; 123*f6b690e6SBo Shen break; 124*f6b690e6SBo Shen case 18: 125*f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; 126*f6b690e6SBo Shen break; 127*f6b690e6SBo Shen case 24: 128*f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; 129*f6b690e6SBo Shen break; 130*f6b690e6SBo Shen default: 131*f6b690e6SBo Shen BUG(); 132*f6b690e6SBo Shen break; 133*f6b690e6SBo Shen } 134*f6b690e6SBo Shen #endif 135*f6b690e6SBo Shen 136*f6b690e6SBo Shen value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME); 137*f6b690e6SBo Shen value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); 138*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdcfg5, value); 139*f6b690e6SBo Shen 140*f6b690e6SBo Shen /* Vertical & Horizontal Timing */ 141*f6b690e6SBo Shen value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1); 142*f6b690e6SBo Shen value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1); 143*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdcfg1, value); 144*f6b690e6SBo Shen 145*f6b690e6SBo Shen value = LCDC_LCDCFG2_VBPW(panel_info.vl_lower_margin); 146*f6b690e6SBo Shen value |= LCDC_LCDCFG2_VFPW(panel_info.vl_upper_margin - 1); 147*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdcfg2, value); 148*f6b690e6SBo Shen 149*f6b690e6SBo Shen value = LCDC_LCDCFG3_HBPW(panel_info.vl_right_margin - 1); 150*f6b690e6SBo Shen value |= LCDC_LCDCFG3_HFPW(panel_info.vl_left_margin - 1); 151*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdcfg3, value); 152*f6b690e6SBo Shen 153*f6b690e6SBo Shen /* Display size */ 154*f6b690e6SBo Shen value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1); 155*f6b690e6SBo Shen value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1); 156*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdcfg4, value); 157*f6b690e6SBo Shen 158*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basecfg0, 159*f6b690e6SBo Shen LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO); 160*f6b690e6SBo Shen 161*f6b690e6SBo Shen switch (NBITS(panel_info.vl_bpix)) { 162*f6b690e6SBo Shen case 16: 163*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basecfg1, 164*f6b690e6SBo Shen LCDC_BASECFG1_RGBMODE_16BPP_RGB_565); 165*f6b690e6SBo Shen break; 166*f6b690e6SBo Shen default: 167*f6b690e6SBo Shen BUG(); 168*f6b690e6SBo Shen break; 169*f6b690e6SBo Shen } 170*f6b690e6SBo Shen 171*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basecfg2, LCDC_BASECFG2_XSTRIDE(0)); 172*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basecfg3, 0); 173*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basecfg4, LCDC_BASECFG4_DMA); 174*f6b690e6SBo Shen 175*f6b690e6SBo Shen /* Disable all interrupts */ 176*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcdidr, ~0UL); 177*f6b690e6SBo Shen lcdc_writel(®s->lcdc_baseidr, ~0UL); 178*f6b690e6SBo Shen 179*f6b690e6SBo Shen /* Setup the DMA descriptor, this descriptor will loop to itself */ 180*f6b690e6SBo Shen desc = (struct lcd_dma_desc *)(lcdbase - 16); 181*f6b690e6SBo Shen 182*f6b690e6SBo Shen desc->address = (u32)lcdbase; 183*f6b690e6SBo Shen /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ 184*f6b690e6SBo Shen desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN 185*f6b690e6SBo Shen | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; 186*f6b690e6SBo Shen desc->next = (u32)desc; 187*f6b690e6SBo Shen 188*f6b690e6SBo Shen lcdc_writel(®s->lcdc_baseaddr, desc->address); 189*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basectrl, desc->control); 190*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basenext, desc->next); 191*f6b690e6SBo Shen lcdc_writel(®s->lcdc_basecher, LCDC_BASECHER_CHEN | 192*f6b690e6SBo Shen LCDC_BASECHER_UPDATEEN); 193*f6b690e6SBo Shen 194*f6b690e6SBo Shen /* Enable LCD */ 195*f6b690e6SBo Shen value = lcdc_readl(®s->lcdc_lcden); 196*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_CLKEN); 197*f6b690e6SBo Shen while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS)) 198*f6b690e6SBo Shen udelay(1); 199*f6b690e6SBo Shen value = lcdc_readl(®s->lcdc_lcden); 200*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_SYNCEN); 201*f6b690e6SBo Shen while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS)) 202*f6b690e6SBo Shen udelay(1); 203*f6b690e6SBo Shen value = lcdc_readl(®s->lcdc_lcden); 204*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_DISPEN); 205*f6b690e6SBo Shen while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS)) 206*f6b690e6SBo Shen udelay(1); 207*f6b690e6SBo Shen value = lcdc_readl(®s->lcdc_lcden); 208*f6b690e6SBo Shen lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_PWMEN); 209*f6b690e6SBo Shen while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) 210*f6b690e6SBo Shen udelay(1); 211*f6b690e6SBo Shen } 212