1f6b690e6SBo Shen /* 2f6b690e6SBo Shen * Driver for AT91/AT32 MULTI LAYER LCD Controller 3f6b690e6SBo Shen * 4f6b690e6SBo Shen * Copyright (C) 2012 Atmel Corporation 5f6b690e6SBo Shen * 61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 7f6b690e6SBo Shen */ 8f6b690e6SBo Shen 9f6b690e6SBo Shen #include <common.h> 10f6b690e6SBo Shen #include <asm/io.h> 11f6b690e6SBo Shen #include <asm/arch/gpio.h> 12f6b690e6SBo Shen #include <asm/arch/clk.h> 137927831eSSongjun Wu #include <clk.h> 147927831eSSongjun Wu #include <dm.h> 157927831eSSongjun Wu #include <fdtdec.h> 16f6b690e6SBo Shen #include <lcd.h> 177927831eSSongjun Wu #include <video.h> 187927831eSSongjun Wu #include <wait_bit.h> 19f6b690e6SBo Shen #include <atmel_hlcdc.h> 20f6b690e6SBo Shen 2138b55087SNikita Kiryanov #if defined(CONFIG_LCD_LOGO) 2238b55087SNikita Kiryanov #include <bmp_logo.h> 2338b55087SNikita Kiryanov #endif 2438b55087SNikita Kiryanov 257927831eSSongjun Wu DECLARE_GLOBAL_DATA_PTR; 267927831eSSongjun Wu 277927831eSSongjun Wu #ifndef CONFIG_DM_VIDEO 287927831eSSongjun Wu 29f6b690e6SBo Shen /* configurable parameters */ 30f6b690e6SBo Shen #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 31f6b690e6SBo Shen #define ATMEL_LCDC_DMA_BURST_LEN 8 32f6b690e6SBo Shen #ifndef ATMEL_LCDC_GUARD_TIME 33f6b690e6SBo Shen #define ATMEL_LCDC_GUARD_TIME 1 34f6b690e6SBo Shen #endif 35f6b690e6SBo Shen 36f6b690e6SBo Shen #define ATMEL_LCDC_FIFO_SIZE 512 37f6b690e6SBo Shen 38cfcd1c03SBo Shen /* 39cfcd1c03SBo Shen * the CLUT register map as following 40cfcd1c03SBo Shen * RCLUT(24 ~ 16), GCLUT(15 ~ 8), BCLUT(7 ~ 0) 41cfcd1c03SBo Shen */ 42cfcd1c03SBo Shen void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) 43cfcd1c03SBo Shen { 447927831eSSongjun Wu writel(panel_info.mmio + ATMEL_LCDC_LUT(regno), 457927831eSSongjun Wu ((red << LCDC_BASECLUT_RCLUT_Pos) & LCDC_BASECLUT_RCLUT_Msk) 46cfcd1c03SBo Shen | ((green << LCDC_BASECLUT_GCLUT_Pos) & LCDC_BASECLUT_GCLUT_Msk) 477927831eSSongjun Wu | ((blue << LCDC_BASECLUT_BCLUT_Pos) & LCDC_BASECLUT_BCLUT_Msk)); 48cfcd1c03SBo Shen } 49cfcd1c03SBo Shen 5038b55087SNikita Kiryanov ushort *configuration_get_cmap(void) 5138b55087SNikita Kiryanov { 5238b55087SNikita Kiryanov #if defined(CONFIG_LCD_LOGO) 5338b55087SNikita Kiryanov return bmp_logo_palette; 5438b55087SNikita Kiryanov #else 5538b55087SNikita Kiryanov return NULL; 5638b55087SNikita Kiryanov #endif 5738b55087SNikita Kiryanov } 5838b55087SNikita Kiryanov 59f6b690e6SBo Shen void lcd_ctrl_init(void *lcdbase) 60f6b690e6SBo Shen { 61f6b690e6SBo Shen unsigned long value; 62f6b690e6SBo Shen struct lcd_dma_desc *desc; 63f6b690e6SBo Shen struct atmel_hlcd_regs *regs; 647927831eSSongjun Wu int ret; 65f6b690e6SBo Shen 66f6b690e6SBo Shen if (!has_lcdc()) 67f6b690e6SBo Shen return; /* No lcdc */ 68f6b690e6SBo Shen 69f6b690e6SBo Shen regs = (struct atmel_hlcd_regs *)panel_info.mmio; 70f6b690e6SBo Shen 71f6b690e6SBo Shen /* Disable DISP signal */ 727927831eSSongjun Wu writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); 737927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, 747927831eSSongjun Wu false, 1000, false); 757927831eSSongjun Wu if (ret) 767927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 77f6b690e6SBo Shen /* Disable synchronization */ 787927831eSSongjun Wu writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); 797927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, 807927831eSSongjun Wu false, 1000, false); 817927831eSSongjun Wu if (ret) 827927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 83f6b690e6SBo Shen /* Disable pixel clock */ 847927831eSSongjun Wu writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); 857927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, 867927831eSSongjun Wu false, 1000, false); 877927831eSSongjun Wu if (ret) 887927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 89f6b690e6SBo Shen /* Disable PWM */ 907927831eSSongjun Wu writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); 917927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, 927927831eSSongjun Wu false, 1000, false); 937927831eSSongjun Wu if (ret) 947927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 95f6b690e6SBo Shen 96f6b690e6SBo Shen /* Set pixel clock */ 97f6b690e6SBo Shen value = get_lcdc_clk_rate(0) / panel_info.vl_clk; 98f6b690e6SBo Shen if (get_lcdc_clk_rate(0) % panel_info.vl_clk) 99f6b690e6SBo Shen value++; 100f6b690e6SBo Shen 101f6b690e6SBo Shen if (value < 1) { 102f6b690e6SBo Shen /* Using system clock as pixel clock */ 1037927831eSSongjun Wu writel(LCDC_LCDCFG0_CLKDIV(0) 104f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHCR 105f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHEO 106f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISOVR1 107f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISBASE 108f6b690e6SBo Shen | panel_info.vl_clk_pol 1097927831eSSongjun Wu | LCDC_LCDCFG0_CLKSEL, 1107927831eSSongjun Wu ®s->lcdc_lcdcfg0); 111f6b690e6SBo Shen 112f6b690e6SBo Shen } else { 1137927831eSSongjun Wu writel(LCDC_LCDCFG0_CLKDIV(value - 2) 114f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHCR 115f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISHEO 116f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISOVR1 117f6b690e6SBo Shen | LCDC_LCDCFG0_CGDISBASE 1187927831eSSongjun Wu | panel_info.vl_clk_pol, 1197927831eSSongjun Wu ®s->lcdc_lcdcfg0); 120f6b690e6SBo Shen } 121f6b690e6SBo Shen 122f6b690e6SBo Shen /* Initialize control register 5 */ 123f6b690e6SBo Shen value = 0; 124f6b690e6SBo Shen 125f6b690e6SBo Shen value |= panel_info.vl_sync; 126f6b690e6SBo Shen 127f6b690e6SBo Shen #ifndef LCD_OUTPUT_BPP 128f6b690e6SBo Shen /* Output is 24bpp */ 129f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; 130f6b690e6SBo Shen #else 131f6b690e6SBo Shen switch (LCD_OUTPUT_BPP) { 132f6b690e6SBo Shen case 12: 133f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; 134f6b690e6SBo Shen break; 135f6b690e6SBo Shen case 16: 136f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; 137f6b690e6SBo Shen break; 138f6b690e6SBo Shen case 18: 139f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; 140f6b690e6SBo Shen break; 141f6b690e6SBo Shen case 24: 142f6b690e6SBo Shen value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; 143f6b690e6SBo Shen break; 144f6b690e6SBo Shen default: 145f6b690e6SBo Shen BUG(); 146f6b690e6SBo Shen break; 147f6b690e6SBo Shen } 148f6b690e6SBo Shen #endif 149f6b690e6SBo Shen 150f6b690e6SBo Shen value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME); 151f6b690e6SBo Shen value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); 1527927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg5); 153f6b690e6SBo Shen 154f6b690e6SBo Shen /* Vertical & Horizontal Timing */ 155f6b690e6SBo Shen value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1); 156f6b690e6SBo Shen value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1); 1577927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg1); 158f6b690e6SBo Shen 1591161f98dSWu, Josh value = LCDC_LCDCFG2_VBPW(panel_info.vl_upper_margin); 1601161f98dSWu, Josh value |= LCDC_LCDCFG2_VFPW(panel_info.vl_lower_margin - 1); 1617927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg2); 162f6b690e6SBo Shen 1631161f98dSWu, Josh value = LCDC_LCDCFG3_HBPW(panel_info.vl_left_margin - 1); 1641161f98dSWu, Josh value |= LCDC_LCDCFG3_HFPW(panel_info.vl_right_margin - 1); 1657927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg3); 166f6b690e6SBo Shen 167f6b690e6SBo Shen /* Display size */ 168f6b690e6SBo Shen value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1); 169f6b690e6SBo Shen value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1); 1707927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg4); 171f6b690e6SBo Shen 1727927831eSSongjun Wu writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO, 1737927831eSSongjun Wu ®s->lcdc_basecfg0); 174f6b690e6SBo Shen 175f6b690e6SBo Shen switch (NBITS(panel_info.vl_bpix)) { 176f6b690e6SBo Shen case 16: 1777927831eSSongjun Wu writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565, 1787927831eSSongjun Wu ®s->lcdc_basecfg1); 179f6b690e6SBo Shen break; 1808c1b7172SMarek Vasut case 32: 1817927831eSSongjun Wu writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888, 1827927831eSSongjun Wu ®s->lcdc_basecfg1); 1838c1b7172SMarek Vasut break; 184f6b690e6SBo Shen default: 185f6b690e6SBo Shen BUG(); 186f6b690e6SBo Shen break; 187f6b690e6SBo Shen } 188f6b690e6SBo Shen 1897927831eSSongjun Wu writel(LCDC_BASECFG2_XSTRIDE(0), ®s->lcdc_basecfg2); 1907927831eSSongjun Wu writel(0, ®s->lcdc_basecfg3); 1917927831eSSongjun Wu writel(LCDC_BASECFG4_DMA, ®s->lcdc_basecfg4); 192f6b690e6SBo Shen 193f6b690e6SBo Shen /* Disable all interrupts */ 1947927831eSSongjun Wu writel(~0UL, ®s->lcdc_lcdidr); 1957927831eSSongjun Wu writel(~0UL, ®s->lcdc_baseidr); 196f6b690e6SBo Shen 197f6b690e6SBo Shen /* Setup the DMA descriptor, this descriptor will loop to itself */ 198f6b690e6SBo Shen desc = (struct lcd_dma_desc *)(lcdbase - 16); 199f6b690e6SBo Shen 200f6b690e6SBo Shen desc->address = (u32)lcdbase; 201f6b690e6SBo Shen /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ 202f6b690e6SBo Shen desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN 203f6b690e6SBo Shen | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; 204f6b690e6SBo Shen desc->next = (u32)desc; 205f6b690e6SBo Shen 206b137bd8cSWu, Josh /* Flush the DMA descriptor if we enabled dcache */ 207b137bd8cSWu, Josh flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); 208b137bd8cSWu, Josh 2097927831eSSongjun Wu writel(desc->address, ®s->lcdc_baseaddr); 2107927831eSSongjun Wu writel(desc->control, ®s->lcdc_basectrl); 2117927831eSSongjun Wu writel(desc->next, ®s->lcdc_basenext); 2127927831eSSongjun Wu writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN, 2137927831eSSongjun Wu ®s->lcdc_basecher); 214f6b690e6SBo Shen 215f6b690e6SBo Shen /* Enable LCD */ 2167927831eSSongjun Wu value = readl(®s->lcdc_lcden); 2177927831eSSongjun Wu writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); 2187927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, 2197927831eSSongjun Wu true, 1000, false); 2207927831eSSongjun Wu if (ret) 2217927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 2227927831eSSongjun Wu value = readl(®s->lcdc_lcden); 2237927831eSSongjun Wu writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); 2247927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, 2257927831eSSongjun Wu true, 1000, false); 2267927831eSSongjun Wu if (ret) 2277927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 2287927831eSSongjun Wu value = readl(®s->lcdc_lcden); 2297927831eSSongjun Wu writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); 2307927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, 2317927831eSSongjun Wu true, 1000, false); 2327927831eSSongjun Wu if (ret) 2337927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 2347927831eSSongjun Wu value = readl(®s->lcdc_lcden); 2357927831eSSongjun Wu writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); 2367927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, 2377927831eSSongjun Wu true, 1000, false); 2387927831eSSongjun Wu if (ret) 2397927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 240b137bd8cSWu, Josh 241b137bd8cSWu, Josh /* Enable flushing if we enabled dcache */ 242b137bd8cSWu, Josh lcd_set_flush_dcache(1); 243f6b690e6SBo Shen } 2447927831eSSongjun Wu 2457927831eSSongjun Wu #else 2467927831eSSongjun Wu 2477927831eSSongjun Wu enum { 2487927831eSSongjun Wu LCD_MAX_WIDTH = 1024, 2497927831eSSongjun Wu LCD_MAX_HEIGHT = 768, 2507927831eSSongjun Wu LCD_MAX_LOG2_BPP = VIDEO_BPP16, 2517927831eSSongjun Wu }; 2527927831eSSongjun Wu 2537927831eSSongjun Wu struct atmel_hlcdc_priv { 2547927831eSSongjun Wu struct atmel_hlcd_regs *regs; 2557927831eSSongjun Wu struct display_timing timing; 2567927831eSSongjun Wu unsigned int vl_bpix; 2577927831eSSongjun Wu unsigned int output_mode; 2587927831eSSongjun Wu unsigned int guard_time; 2597927831eSSongjun Wu ulong clk_rate; 2607927831eSSongjun Wu }; 2617927831eSSongjun Wu 2627927831eSSongjun Wu static int at91_hlcdc_enable_clk(struct udevice *dev) 2637927831eSSongjun Wu { 2647927831eSSongjun Wu struct atmel_hlcdc_priv *priv = dev_get_priv(dev); 2657927831eSSongjun Wu struct clk clk; 2667927831eSSongjun Wu ulong clk_rate; 2677927831eSSongjun Wu int ret; 2687927831eSSongjun Wu 2697927831eSSongjun Wu ret = clk_get_by_index(dev, 0, &clk); 2707927831eSSongjun Wu if (ret) 2717927831eSSongjun Wu return -EINVAL; 2727927831eSSongjun Wu 2737927831eSSongjun Wu ret = clk_enable(&clk); 2747927831eSSongjun Wu if (ret) 2757927831eSSongjun Wu return ret; 2767927831eSSongjun Wu 2777927831eSSongjun Wu clk_rate = clk_get_rate(&clk); 2787927831eSSongjun Wu if (!clk_rate) { 2797927831eSSongjun Wu clk_disable(&clk); 2807927831eSSongjun Wu return -ENODEV; 2817927831eSSongjun Wu } 2827927831eSSongjun Wu 2837927831eSSongjun Wu priv->clk_rate = clk_rate; 2847927831eSSongjun Wu 2857927831eSSongjun Wu clk_free(&clk); 2867927831eSSongjun Wu 2877927831eSSongjun Wu return 0; 2887927831eSSongjun Wu } 2897927831eSSongjun Wu 2907927831eSSongjun Wu static void atmel_hlcdc_init(struct udevice *dev) 2917927831eSSongjun Wu { 2927927831eSSongjun Wu struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); 2937927831eSSongjun Wu struct atmel_hlcdc_priv *priv = dev_get_priv(dev); 2947927831eSSongjun Wu struct atmel_hlcd_regs *regs = priv->regs; 2957927831eSSongjun Wu struct display_timing *timing = &priv->timing; 2967927831eSSongjun Wu struct lcd_dma_desc *desc; 2977927831eSSongjun Wu unsigned long value, vl_clk_pol; 2987927831eSSongjun Wu int ret; 2997927831eSSongjun Wu 3007927831eSSongjun Wu /* Disable DISP signal */ 3017927831eSSongjun Wu writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); 3027927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, 3037927831eSSongjun Wu false, 1000, false); 3047927831eSSongjun Wu if (ret) 3057927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 3067927831eSSongjun Wu /* Disable synchronization */ 3077927831eSSongjun Wu writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); 3087927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, 3097927831eSSongjun Wu false, 1000, false); 3107927831eSSongjun Wu if (ret) 3117927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 3127927831eSSongjun Wu /* Disable pixel clock */ 3137927831eSSongjun Wu writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); 3147927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, 3157927831eSSongjun Wu false, 1000, false); 3167927831eSSongjun Wu if (ret) 3177927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 3187927831eSSongjun Wu /* Disable PWM */ 3197927831eSSongjun Wu writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); 3207927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, 3217927831eSSongjun Wu false, 1000, false); 3227927831eSSongjun Wu if (ret) 3237927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 3247927831eSSongjun Wu 3257927831eSSongjun Wu /* Set pixel clock */ 3267927831eSSongjun Wu value = priv->clk_rate / timing->pixelclock.typ; 3277927831eSSongjun Wu if (priv->clk_rate % timing->pixelclock.typ) 3287927831eSSongjun Wu value++; 3297927831eSSongjun Wu 3307927831eSSongjun Wu vl_clk_pol = 0; 3317927831eSSongjun Wu if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) 3327927831eSSongjun Wu vl_clk_pol = LCDC_LCDCFG0_CLKPOL; 3337927831eSSongjun Wu 3347927831eSSongjun Wu if (value < 1) { 3357927831eSSongjun Wu /* Using system clock as pixel clock */ 3367927831eSSongjun Wu writel(LCDC_LCDCFG0_CLKDIV(0) 3377927831eSSongjun Wu | LCDC_LCDCFG0_CGDISHCR 3387927831eSSongjun Wu | LCDC_LCDCFG0_CGDISHEO 3397927831eSSongjun Wu | LCDC_LCDCFG0_CGDISOVR1 3407927831eSSongjun Wu | LCDC_LCDCFG0_CGDISBASE 3417927831eSSongjun Wu | vl_clk_pol 3427927831eSSongjun Wu | LCDC_LCDCFG0_CLKSEL, 3437927831eSSongjun Wu ®s->lcdc_lcdcfg0); 3447927831eSSongjun Wu 3457927831eSSongjun Wu } else { 3467927831eSSongjun Wu writel(LCDC_LCDCFG0_CLKDIV(value - 2) 3477927831eSSongjun Wu | LCDC_LCDCFG0_CGDISHCR 3487927831eSSongjun Wu | LCDC_LCDCFG0_CGDISHEO 3497927831eSSongjun Wu | LCDC_LCDCFG0_CGDISOVR1 3507927831eSSongjun Wu | LCDC_LCDCFG0_CGDISBASE 3517927831eSSongjun Wu | vl_clk_pol, 3527927831eSSongjun Wu ®s->lcdc_lcdcfg0); 3537927831eSSongjun Wu } 3547927831eSSongjun Wu 3557927831eSSongjun Wu /* Initialize control register 5 */ 3567927831eSSongjun Wu value = 0; 3577927831eSSongjun Wu 3587927831eSSongjun Wu if (!(timing->flags & DISPLAY_FLAGS_HSYNC_HIGH)) 3597927831eSSongjun Wu value |= LCDC_LCDCFG5_HSPOL; 3607927831eSSongjun Wu if (!(timing->flags & DISPLAY_FLAGS_VSYNC_HIGH)) 3617927831eSSongjun Wu value |= LCDC_LCDCFG5_VSPOL; 3627927831eSSongjun Wu 3637927831eSSongjun Wu switch (priv->output_mode) { 3647927831eSSongjun Wu case 12: 3657927831eSSongjun Wu value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; 3667927831eSSongjun Wu break; 3677927831eSSongjun Wu case 16: 3687927831eSSongjun Wu value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; 3697927831eSSongjun Wu break; 3707927831eSSongjun Wu case 18: 3717927831eSSongjun Wu value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; 3727927831eSSongjun Wu break; 3737927831eSSongjun Wu case 24: 3747927831eSSongjun Wu value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; 3757927831eSSongjun Wu break; 3767927831eSSongjun Wu default: 3777927831eSSongjun Wu BUG(); 3787927831eSSongjun Wu break; 3797927831eSSongjun Wu } 3807927831eSSongjun Wu 3817927831eSSongjun Wu value |= LCDC_LCDCFG5_GUARDTIME(priv->guard_time); 3827927831eSSongjun Wu value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); 3837927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg5); 3847927831eSSongjun Wu 3857927831eSSongjun Wu /* Vertical & Horizontal Timing */ 3867927831eSSongjun Wu value = LCDC_LCDCFG1_VSPW(timing->vsync_len.typ - 1); 3877927831eSSongjun Wu value |= LCDC_LCDCFG1_HSPW(timing->hsync_len.typ - 1); 3887927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg1); 3897927831eSSongjun Wu 3907927831eSSongjun Wu value = LCDC_LCDCFG2_VBPW(timing->vback_porch.typ); 3917927831eSSongjun Wu value |= LCDC_LCDCFG2_VFPW(timing->vfront_porch.typ - 1); 3927927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg2); 3937927831eSSongjun Wu 3947927831eSSongjun Wu value = LCDC_LCDCFG3_HBPW(timing->hback_porch.typ - 1); 3957927831eSSongjun Wu value |= LCDC_LCDCFG3_HFPW(timing->hfront_porch.typ - 1); 3967927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg3); 3977927831eSSongjun Wu 3987927831eSSongjun Wu /* Display size */ 3997927831eSSongjun Wu value = LCDC_LCDCFG4_RPF(timing->vactive.typ - 1); 4007927831eSSongjun Wu value |= LCDC_LCDCFG4_PPL(timing->hactive.typ - 1); 4017927831eSSongjun Wu writel(value, ®s->lcdc_lcdcfg4); 4027927831eSSongjun Wu 4037927831eSSongjun Wu writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO, 4047927831eSSongjun Wu ®s->lcdc_basecfg0); 4057927831eSSongjun Wu 4067927831eSSongjun Wu switch (VNBITS(priv->vl_bpix)) { 4077927831eSSongjun Wu case 16: 4087927831eSSongjun Wu writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565, 4097927831eSSongjun Wu ®s->lcdc_basecfg1); 4107927831eSSongjun Wu break; 4117927831eSSongjun Wu case 32: 4127927831eSSongjun Wu writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888, 4137927831eSSongjun Wu ®s->lcdc_basecfg1); 4147927831eSSongjun Wu break; 4157927831eSSongjun Wu default: 4167927831eSSongjun Wu BUG(); 4177927831eSSongjun Wu break; 4187927831eSSongjun Wu } 4197927831eSSongjun Wu 4207927831eSSongjun Wu writel(LCDC_BASECFG2_XSTRIDE(0), ®s->lcdc_basecfg2); 4217927831eSSongjun Wu writel(0, ®s->lcdc_basecfg3); 4227927831eSSongjun Wu writel(LCDC_BASECFG4_DMA, ®s->lcdc_basecfg4); 4237927831eSSongjun Wu 4247927831eSSongjun Wu /* Disable all interrupts */ 4257927831eSSongjun Wu writel(~0UL, ®s->lcdc_lcdidr); 4267927831eSSongjun Wu writel(~0UL, ®s->lcdc_baseidr); 4277927831eSSongjun Wu 4287927831eSSongjun Wu /* Setup the DMA descriptor, this descriptor will loop to itself */ 4297927831eSSongjun Wu desc = (struct lcd_dma_desc *)(uc_plat->base - 16); 4307927831eSSongjun Wu 4317927831eSSongjun Wu desc->address = (u32)uc_plat->base; 4327927831eSSongjun Wu 4337927831eSSongjun Wu /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ 4347927831eSSongjun Wu desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN 4357927831eSSongjun Wu | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; 4367927831eSSongjun Wu desc->next = (u32)desc; 4377927831eSSongjun Wu 4387927831eSSongjun Wu /* Flush the DMA descriptor if we enabled dcache */ 4397927831eSSongjun Wu flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); 4407927831eSSongjun Wu 4417927831eSSongjun Wu writel(desc->address, ®s->lcdc_baseaddr); 4427927831eSSongjun Wu writel(desc->control, ®s->lcdc_basectrl); 4437927831eSSongjun Wu writel(desc->next, ®s->lcdc_basenext); 4447927831eSSongjun Wu writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN, 4457927831eSSongjun Wu ®s->lcdc_basecher); 4467927831eSSongjun Wu 4477927831eSSongjun Wu /* Enable LCD */ 4487927831eSSongjun Wu value = readl(®s->lcdc_lcden); 4497927831eSSongjun Wu writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); 4507927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, 4517927831eSSongjun Wu true, 1000, false); 4527927831eSSongjun Wu if (ret) 4537927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 4547927831eSSongjun Wu value = readl(®s->lcdc_lcden); 4557927831eSSongjun Wu writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); 4567927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, 4577927831eSSongjun Wu true, 1000, false); 4587927831eSSongjun Wu if (ret) 4597927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 4607927831eSSongjun Wu value = readl(®s->lcdc_lcden); 4617927831eSSongjun Wu writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); 4627927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, 4637927831eSSongjun Wu true, 1000, false); 4647927831eSSongjun Wu if (ret) 4657927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 4667927831eSSongjun Wu value = readl(®s->lcdc_lcden); 4677927831eSSongjun Wu writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); 4687927831eSSongjun Wu ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, 4697927831eSSongjun Wu true, 1000, false); 4707927831eSSongjun Wu if (ret) 4717927831eSSongjun Wu printf("%s: %d: Timeout!\n", __func__, __LINE__); 4727927831eSSongjun Wu } 4737927831eSSongjun Wu 4747927831eSSongjun Wu static int atmel_hlcdc_probe(struct udevice *dev) 4757927831eSSongjun Wu { 4767927831eSSongjun Wu struct video_priv *uc_priv = dev_get_uclass_priv(dev); 4777927831eSSongjun Wu struct atmel_hlcdc_priv *priv = dev_get_priv(dev); 4787927831eSSongjun Wu int ret; 4797927831eSSongjun Wu 4807927831eSSongjun Wu ret = at91_hlcdc_enable_clk(dev); 4817927831eSSongjun Wu if (ret) 4827927831eSSongjun Wu return ret; 4837927831eSSongjun Wu 4847927831eSSongjun Wu atmel_hlcdc_init(dev); 4857927831eSSongjun Wu 4867927831eSSongjun Wu uc_priv->xsize = priv->timing.hactive.typ; 4877927831eSSongjun Wu uc_priv->ysize = priv->timing.vactive.typ; 4887927831eSSongjun Wu uc_priv->bpix = priv->vl_bpix; 4897927831eSSongjun Wu 4907927831eSSongjun Wu /* Enable flushing if we enabled dcache */ 4917927831eSSongjun Wu video_set_flush_dcache(dev, true); 4927927831eSSongjun Wu 4937927831eSSongjun Wu return 0; 4947927831eSSongjun Wu } 4957927831eSSongjun Wu 4967927831eSSongjun Wu static int atmel_hlcdc_ofdata_to_platdata(struct udevice *dev) 4977927831eSSongjun Wu { 4987927831eSSongjun Wu struct atmel_hlcdc_priv *priv = dev_get_priv(dev); 4997927831eSSongjun Wu const void *blob = gd->fdt_blob; 500*da409cccSSimon Glass int node = dev_of_offset(dev); 5017927831eSSongjun Wu 502a821c4afSSimon Glass priv->regs = (struct atmel_hlcd_regs *)devfdt_get_addr(dev); 5037927831eSSongjun Wu if (!priv->regs) { 5047927831eSSongjun Wu debug("%s: No display controller address\n", __func__); 5057927831eSSongjun Wu return -EINVAL; 5067927831eSSongjun Wu } 5077927831eSSongjun Wu 508*da409cccSSimon Glass if (fdtdec_decode_display_timing(blob, dev_of_offset(dev), 5097927831eSSongjun Wu 0, &priv->timing)) { 5107927831eSSongjun Wu debug("%s: Failed to decode display timing\n", __func__); 5117927831eSSongjun Wu return -EINVAL; 5127927831eSSongjun Wu } 5137927831eSSongjun Wu 5147927831eSSongjun Wu if (priv->timing.hactive.typ > LCD_MAX_WIDTH) 5157927831eSSongjun Wu priv->timing.hactive.typ = LCD_MAX_WIDTH; 5167927831eSSongjun Wu 5177927831eSSongjun Wu if (priv->timing.vactive.typ > LCD_MAX_HEIGHT) 5187927831eSSongjun Wu priv->timing.vactive.typ = LCD_MAX_HEIGHT; 5197927831eSSongjun Wu 5207927831eSSongjun Wu priv->vl_bpix = fdtdec_get_int(blob, node, "atmel,vl-bpix", 0); 5217927831eSSongjun Wu if (!priv->vl_bpix) { 5227927831eSSongjun Wu debug("%s: Failed to get bits per pixel\n", __func__); 5237927831eSSongjun Wu return -EINVAL; 5247927831eSSongjun Wu } 5257927831eSSongjun Wu 5267927831eSSongjun Wu priv->output_mode = fdtdec_get_int(blob, node, "atmel,output-mode", 24); 5277927831eSSongjun Wu priv->guard_time = fdtdec_get_int(blob, node, "atmel,guard-time", 1); 5287927831eSSongjun Wu 5297927831eSSongjun Wu return 0; 5307927831eSSongjun Wu } 5317927831eSSongjun Wu 5327927831eSSongjun Wu static int atmel_hlcdc_bind(struct udevice *dev) 5337927831eSSongjun Wu { 5347927831eSSongjun Wu struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); 5357927831eSSongjun Wu 5367927831eSSongjun Wu uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * 5377927831eSSongjun Wu (1 << LCD_MAX_LOG2_BPP) / 8; 5387927831eSSongjun Wu 5397927831eSSongjun Wu debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); 5407927831eSSongjun Wu 5417927831eSSongjun Wu return 0; 5427927831eSSongjun Wu } 5437927831eSSongjun Wu 5447927831eSSongjun Wu static const struct udevice_id atmel_hlcdc_ids[] = { 5457927831eSSongjun Wu { .compatible = "atmel,sama5d2-hlcdc" }, 5467927831eSSongjun Wu { .compatible = "atmel,at91sam9x5-hlcdc" }, 5477927831eSSongjun Wu { } 5487927831eSSongjun Wu }; 5497927831eSSongjun Wu 5507927831eSSongjun Wu U_BOOT_DRIVER(atmel_hlcdfb) = { 5517927831eSSongjun Wu .name = "atmel_hlcdfb", 5527927831eSSongjun Wu .id = UCLASS_VIDEO, 5537927831eSSongjun Wu .of_match = atmel_hlcdc_ids, 5547927831eSSongjun Wu .bind = atmel_hlcdc_bind, 5557927831eSSongjun Wu .probe = atmel_hlcdc_probe, 5567927831eSSongjun Wu .ofdata_to_platdata = atmel_hlcdc_ofdata_to_platdata, 5577927831eSSongjun Wu .priv_auto_alloc_size = sizeof(struct atmel_hlcdc_priv), 5587927831eSSongjun Wu }; 5597927831eSSongjun Wu 5607927831eSSongjun Wu #endif 561