2 * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
22 #include <asm/arch/imx-regs.h>
23 #include <asm/arch/mxsfb.h>
24 #include <asm/arch/sys_proto.h>
26 vidinfo_t panel_info = {
27 /* set to max. size supported by SoC */
31 .vl_bpix = LCD_COLOR24, /* Bits per pixel, 0: 1bpp, 1: 2bpp, 2: 4bpp, 3: 8bpp ... */
34 static int bits_per_pixel;
35 static int color_depth;
36 static uint32_t pix_fmt;
37 static struct fb_var_screeninfo mxsfb_var;
39 static struct mxs_lcdif_regs *lcd_regs = (void *)MXS_LCDIF_BASE;
41 void *lcd_base; /* Start of framebuffer memory */
42 void *lcd_console_address; /* Start of console buffer */
51 void lcd_initcolregs(void)
55 void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
59 #define fourcc_str(fourcc) ((fourcc) >> 0) & 0xff, \
60 ((fourcc) >> 8) & 0xff, \
61 ((fourcc) >> 16) & 0xff, \
62 ((fourcc) >> 24) & 0xff
64 #define LCD_CTRL_DEFAULT (LCDIF_CTRL_LCDIF_MASTER | \
65 LCDIF_CTRL_BYPASS_COUNT | \
66 LCDIF_CTRL_DOTCLK_MODE)
68 #define LCD_CTRL1_DEFAULT 0
69 #define LCD_CTRL2_DEFAULT LCDIF_CTRL2_OUTSTANDING_REQS_REQ_2
71 #define LCD_VDCTRL0_DEFAULT (LCDIF_VDCTRL0_ENABLE_PRESENT | \
72 LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT | \
73 LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT)
74 #define LCD_VDCTRL1_DEFAULT 0
75 #define LCD_VDCTRL2_DEFAULT 0
76 #define LCD_VDCTRL3_DEFAULT 0
77 #define LCD_VDCTRL4_DEFAULT LCDIF_VDCTRL4_SYNC_SIGNALS_ON
79 void video_hw_init(void *lcdbase)
82 unsigned int div = 0, best = 0, pix_clk;
84 const unsigned long lcd_clk = 480000000;
85 u32 lcd_ctrl = LCD_CTRL_DEFAULT | LCDIF_CTRL_RUN;
86 u32 lcd_ctrl1 = LCD_CTRL1_DEFAULT, lcd_ctrl2 = LCD_CTRL2_DEFAULT;
87 u32 lcd_vdctrl0 = LCD_VDCTRL0_DEFAULT;
88 u32 lcd_vdctrl1 = LCD_VDCTRL1_DEFAULT;
89 u32 lcd_vdctrl2 = LCD_VDCTRL2_DEFAULT;
90 u32 lcd_vdctrl3 = LCD_VDCTRL3_DEFAULT;
91 u32 lcd_vdctrl4 = LCD_VDCTRL4_DEFAULT;
92 struct mxs_clkctrl_regs *clk_regs = (void *)MXS_CLKCTRL_BASE;
93 char buf1[16], buf2[16];
95 /* pixel format in memory */
96 switch (color_depth) {
98 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_8BIT;
99 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(1);
103 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_16BIT;
104 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(3);
108 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_18BIT;
109 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(7);
113 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_24BIT;
114 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(7);
118 printf("Invalid bpp: %d\n", color_depth);
122 /* pixel format on the LCD data pins */
125 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_8BIT;
129 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_16BIT;
133 lcd_ctrl |= 1 << LCDIF_CTRL_INPUT_DATA_SWIZZLE_OFFSET;
136 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_18BIT;
140 lcd_ctrl |= 1 << LCDIF_CTRL_INPUT_DATA_SWIZZLE_OFFSET;
143 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_24BIT;
147 printf("Invalid pixel format: %c%c%c%c\n", fourcc_str(pix_fmt));
151 pix_clk = PICOS2KHZ(mxsfb_var.pixclock);
152 debug("designated pix_clk: %sMHz\n", strmhz(buf1, pix_clk * 1000));
154 for (frac1 = 18; frac1 < 36; frac1++) {
155 static unsigned int err = ~0;
156 unsigned long clk = lcd_clk / 1000 * 18 / frac1;
157 unsigned int d = (clk + pix_clk - 1) / pix_clk;
158 unsigned int diff = abs(clk / d - pix_clk);
160 debug("frac1=%u div=%u lcd_clk=%-8sMHz pix_clk=%-8sMHz diff=%u err=%u\n",
161 frac1, d, strmhz(buf1, clk * 1000), strmhz(buf2, clk * 1000 / d),
178 printf("Requested pixel clock %sMHz out of range\n",
179 strmhz(buf1, pix_clk * 1000));
183 debug("div=%lu(%u*%u/18) for pixel clock %sMHz with base clock %sMHz\n",
184 lcd_clk / pix_clk / 1000, best, div,
185 strmhz(buf1, lcd_clk / div * 18 / best),
186 strmhz(buf2, lcd_clk));
188 frac1 = (readl(&clk_regs->hw_clkctrl_frac1_reg) & ~0xff) | best;
189 writel(frac1, &clk_regs->hw_clkctrl_frac1_reg);
190 writel(1 << 14, &clk_regs->hw_clkctrl_clkseq_clr);
192 /* enable LCD clk and fractional divider */
193 writel(div, &clk_regs->hw_clkctrl_lcdif_reg);
194 while (readl(&clk_regs->hw_clkctrl_lcdif_reg) & (1 << 29))
197 ret = mxs_reset_block(&lcd_regs->hw_lcdif_ctrl_reg);
199 printf("Failed to reset LCD controller: LCDIF_CTRL: %08x CLKCTRL_LCDIF: %08x\n",
200 readl(&lcd_regs->hw_lcdif_ctrl_reg),
201 readl(&clk_regs->hw_clkctrl_lcdif_reg));
205 if (mxsfb_var.sync & FB_SYNC_HOR_HIGH_ACT)
206 lcd_vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL;
208 if (mxsfb_var.sync & FB_SYNC_VERT_HIGH_ACT)
209 lcd_vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL;
211 if (mxsfb_var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT)
212 lcd_vdctrl0 |= LCDIF_VDCTRL0_ENABLE_POL;
214 if (mxsfb_var.sync & FB_SYNC_DOTCLK_FALLING_ACT)
215 lcd_vdctrl0 |= LCDIF_VDCTRL0_DOTCLK_POL;
217 lcd_vdctrl0 |= LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH(mxsfb_var.vsync_len);
218 lcd_vdctrl1 |= LCDIF_VDCTRL1_VSYNC_PERIOD(mxsfb_var.vsync_len +
219 mxsfb_var.upper_margin +
220 mxsfb_var.lower_margin +
222 lcd_vdctrl2 |= LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH(mxsfb_var.hsync_len);
223 lcd_vdctrl2 |= LCDIF_VDCTRL2_HSYNC_PERIOD(mxsfb_var.hsync_len +
224 mxsfb_var.left_margin +
225 mxsfb_var.right_margin +
228 lcd_vdctrl3 |= LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT(mxsfb_var.left_margin +
229 mxsfb_var.hsync_len);
230 lcd_vdctrl3 |= LCDIF_VDCTRL3_VERTICAL_WAIT_CNT(mxsfb_var.upper_margin +
231 mxsfb_var.vsync_len);
233 lcd_vdctrl4 |= LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT(mxsfb_var.xres);
235 writel((u32)lcdbase, &lcd_regs->hw_lcdif_next_buf_reg);
236 writel(LCDIF_TRANSFER_COUNT_H_COUNT(mxsfb_var.xres) |
237 LCDIF_TRANSFER_COUNT_V_COUNT(mxsfb_var.yres),
238 &lcd_regs->hw_lcdif_transfer_count_reg);
240 writel(lcd_vdctrl0, &lcd_regs->hw_lcdif_vdctrl0_reg);
241 writel(lcd_vdctrl1, &lcd_regs->hw_lcdif_vdctrl1_reg);
242 writel(lcd_vdctrl2, &lcd_regs->hw_lcdif_vdctrl2_reg);
243 writel(lcd_vdctrl3, &lcd_regs->hw_lcdif_vdctrl3_reg);
244 writel(lcd_vdctrl4, &lcd_regs->hw_lcdif_vdctrl4_reg);
246 writel(lcd_ctrl1, &lcd_regs->hw_lcdif_ctrl1_reg);
247 writel(lcd_ctrl2, &lcd_regs->hw_lcdif_ctrl2_reg);
249 writel(lcd_ctrl, &lcd_regs->hw_lcdif_ctrl_reg);
251 debug("mxsfb framebuffer driver initialized\n");
254 void mxsfb_disable(void)
256 u32 lcd_ctrl = readl(&lcd_regs->hw_lcdif_ctrl_reg);
258 writel(lcd_ctrl & ~LCDIF_CTRL_RUN, &lcd_regs->hw_lcdif_ctrl_reg);
261 int mxsfb_init(struct fb_videomode *mode, uint32_t pixfmt, int bpp)
266 panel_info.vl_bpix = LCD_COLOR8;
271 panel_info.vl_bpix = LCD_COLOR16;
276 panel_info.vl_bpix = LCD_COLOR24;
281 panel_info.vl_bpix = LCD_COLOR24;
291 lcd_line_length = bits_per_pixel / 8 * mode->xres;
293 mxsfb_var.xres = mode->xres;
294 mxsfb_var.yres = mode->yres;
295 mxsfb_var.xres_virtual = mode->xres;
296 mxsfb_var.yres_virtual = mode->yres;
297 mxsfb_var.pixclock = mode->pixclock;
298 mxsfb_var.left_margin = mode->left_margin;
299 mxsfb_var.right_margin = mode->right_margin;
300 mxsfb_var.upper_margin = mode->upper_margin;
301 mxsfb_var.lower_margin = mode->lower_margin;
302 mxsfb_var.hsync_len = mode->hsync_len;
303 mxsfb_var.vsync_len = mode->vsync_len;
304 mxsfb_var.sync = mode->sync;
306 panel_info.vl_col = mode->xres;
307 panel_info.vl_row = mode->yres;