1 /* 2 * Driver for AT91/AT32 LCD Controller 3 * 4 * Copyright (C) 2007 Atmel Corporation 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <asm/io.h> 11 #include <asm/arch/gpio.h> 12 #include <asm/arch/clk.h> 13 #include <lcd.h> 14 #include <atmel_lcdc.h> 15 16 /* configurable parameters */ 17 #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 18 #define ATMEL_LCDC_DMA_BURST_LEN 8 19 #ifndef ATMEL_LCDC_GUARD_TIME 20 #define ATMEL_LCDC_GUARD_TIME 1 21 #endif 22 23 #if defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91CAP9) 24 #define ATMEL_LCDC_FIFO_SIZE 2048 25 #else 26 #define ATMEL_LCDC_FIFO_SIZE 512 27 #endif 28 29 #define lcdc_readl(mmio, reg) __raw_readl((mmio)+(reg)) 30 #define lcdc_writel(mmio, reg, val) __raw_writel((val), (mmio)+(reg)) 31 32 ushort *configuration_get_cmap(void) 33 { 34 return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0)); 35 } 36 37 #if defined(CONFIG_BMP_16BPP) && defined(CONFIG_ATMEL_LCD_BGR555) 38 void fb_put_word(uchar **fb, uchar **from) 39 { 40 *(*fb)++ = (((*from)[0] & 0x1f) << 2) | ((*from)[1] & 0x03); 41 *(*fb)++ = ((*from)[0] & 0xe0) | (((*from)[1] & 0x7c) >> 2); 42 *from += 2; 43 } 44 #endif 45 46 void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) 47 { 48 #if defined(CONFIG_ATMEL_LCD_BGR555) 49 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno), 50 (red >> 3) | ((green & 0xf8) << 2) | ((blue & 0xf8) << 7)); 51 #else 52 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno), 53 (blue >> 3) | ((green & 0xfc) << 3) | ((red & 0xf8) << 8)); 54 #endif 55 } 56 57 void lcd_ctrl_init(void *lcdbase) 58 { 59 unsigned long value; 60 61 /* Turn off the LCD controller and the DMA controller */ 62 lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON, 63 ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET); 64 65 /* Wait for the LCDC core to become idle */ 66 while (lcdc_readl(panel_info.mmio, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) 67 udelay(10); 68 69 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, 0); 70 71 /* Reset LCDC DMA */ 72 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMARST); 73 74 /* ...set frame size and burst length = 8 words (?) */ 75 value = (panel_info.vl_col * panel_info.vl_row * 76 NBITS(panel_info.vl_bpix)) / 32; 77 value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); 78 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMAFRMCFG, value); 79 80 /* Set pixel clock */ 81 value = get_lcdc_clk_rate(0) / panel_info.vl_clk; 82 if (get_lcdc_clk_rate(0) % panel_info.vl_clk) 83 value++; 84 value = (value / 2) - 1; 85 86 if (!value) { 87 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); 88 } else 89 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, 90 value << ATMEL_LCDC_CLKVAL_OFFSET); 91 92 /* Initialize control register 2 */ 93 #ifdef CONFIG_AVR32 94 value = ATMEL_LCDC_MEMOR_BIG | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE; 95 #else 96 value = ATMEL_LCDC_MEMOR_LITTLE | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE; 97 #endif 98 if (panel_info.vl_tft) 99 value |= ATMEL_LCDC_DISTYPE_TFT; 100 101 value |= panel_info.vl_sync; 102 value |= (panel_info.vl_bpix << 5); 103 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON2, value); 104 105 /* Vertical timing */ 106 value = (panel_info.vl_vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; 107 value |= panel_info.vl_upper_margin << ATMEL_LCDC_VBP_OFFSET; 108 value |= panel_info.vl_lower_margin; 109 lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM1, value); 110 111 /* Horizontal timing */ 112 value = (panel_info.vl_right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; 113 value |= (panel_info.vl_hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; 114 value |= (panel_info.vl_left_margin - 1); 115 lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM2, value); 116 117 /* Display size */ 118 value = (panel_info.vl_col - 1) << ATMEL_LCDC_HOZVAL_OFFSET; 119 value |= panel_info.vl_row - 1; 120 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDFRMCFG, value); 121 122 /* FIFO Threshold: Use formula from data sheet */ 123 value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); 124 lcdc_writel(panel_info.mmio, ATMEL_LCDC_FIFO, value); 125 126 /* Toggle LCD_MODE every frame */ 127 lcdc_writel(panel_info.mmio, ATMEL_LCDC_MVAL, 0); 128 129 /* Disable all interrupts */ 130 lcdc_writel(panel_info.mmio, ATMEL_LCDC_IDR, ~0UL); 131 132 /* Set contrast */ 133 value = ATMEL_LCDC_PS_DIV8 | 134 ATMEL_LCDC_ENA_PWMENABLE; 135 if (!panel_info.vl_cont_pol_low) 136 value |= ATMEL_LCDC_POL_POSITIVE; 137 lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_CTR, value); 138 lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); 139 140 /* Set framebuffer DMA base address and pixel offset */ 141 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMABADDR1, (u_long)lcdbase); 142 143 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMAEN); 144 lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON, 145 (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); 146 } 147 148 ulong calc_fbsize(void) 149 { 150 return ((panel_info.vl_col * panel_info.vl_row * 151 NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE; 152 } 153