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 void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) 33 { 34 #if defined(CONFIG_ATMEL_LCD_BGR555) 35 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno), 36 (red >> 3) | ((green & 0xf8) << 2) | ((blue & 0xf8) << 7)); 37 #else 38 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno), 39 (blue >> 3) | ((green & 0xfc) << 3) | ((red & 0xf8) << 8)); 40 #endif 41 } 42 43 void lcd_ctrl_init(void *lcdbase) 44 { 45 unsigned long value; 46 47 /* Turn off the LCD controller and the DMA controller */ 48 lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON, 49 ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET); 50 51 /* Wait for the LCDC core to become idle */ 52 while (lcdc_readl(panel_info.mmio, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) 53 udelay(10); 54 55 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, 0); 56 57 /* Reset LCDC DMA */ 58 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMARST); 59 60 /* ...set frame size and burst length = 8 words (?) */ 61 value = (panel_info.vl_col * panel_info.vl_row * 62 NBITS(panel_info.vl_bpix)) / 32; 63 value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); 64 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMAFRMCFG, value); 65 66 /* Set pixel clock */ 67 value = get_lcdc_clk_rate(0) / panel_info.vl_clk; 68 if (get_lcdc_clk_rate(0) % panel_info.vl_clk) 69 value++; 70 value = (value / 2) - 1; 71 72 if (!value) { 73 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); 74 } else 75 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, 76 value << ATMEL_LCDC_CLKVAL_OFFSET); 77 78 /* Initialize control register 2 */ 79 #ifdef CONFIG_AVR32 80 value = ATMEL_LCDC_MEMOR_BIG | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE; 81 #else 82 value = ATMEL_LCDC_MEMOR_LITTLE | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE; 83 #endif 84 if (panel_info.vl_tft) 85 value |= ATMEL_LCDC_DISTYPE_TFT; 86 87 value |= panel_info.vl_sync; 88 value |= (panel_info.vl_bpix << 5); 89 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON2, value); 90 91 /* Vertical timing */ 92 value = (panel_info.vl_vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; 93 value |= panel_info.vl_upper_margin << ATMEL_LCDC_VBP_OFFSET; 94 value |= panel_info.vl_lower_margin; 95 lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM1, value); 96 97 /* Horizontal timing */ 98 value = (panel_info.vl_right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; 99 value |= (panel_info.vl_hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; 100 value |= (panel_info.vl_left_margin - 1); 101 lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM2, value); 102 103 /* Display size */ 104 value = (panel_info.vl_col - 1) << ATMEL_LCDC_HOZVAL_OFFSET; 105 value |= panel_info.vl_row - 1; 106 lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDFRMCFG, value); 107 108 /* FIFO Threshold: Use formula from data sheet */ 109 value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); 110 lcdc_writel(panel_info.mmio, ATMEL_LCDC_FIFO, value); 111 112 /* Toggle LCD_MODE every frame */ 113 lcdc_writel(panel_info.mmio, ATMEL_LCDC_MVAL, 0); 114 115 /* Disable all interrupts */ 116 lcdc_writel(panel_info.mmio, ATMEL_LCDC_IDR, ~0UL); 117 118 /* Set contrast */ 119 value = ATMEL_LCDC_PS_DIV8 | 120 ATMEL_LCDC_ENA_PWMENABLE; 121 if (!panel_info.vl_cont_pol_low) 122 value |= ATMEL_LCDC_POL_POSITIVE; 123 lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_CTR, value); 124 lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); 125 126 /* Set framebuffer DMA base address and pixel offset */ 127 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMABADDR1, (u_long)lcdbase); 128 129 lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMAEN); 130 lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON, 131 (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); 132 } 133 134 ulong calc_fbsize(void) 135 { 136 return ((panel_info.vl_col * panel_info.vl_row * 137 NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE; 138 } 139