]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - drivers/video/mxsfb.c
use default fdtaddr if not set
[karo-tx-uboot.git] / drivers / video / mxsfb.c
1 /*
2  * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
3  *
4  * LCD driver for i.MX28
5  *
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.
9  *
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.
14  *
15  */
16
17 #include <common.h>
18 #include <errno.h>
19 #include <lcd.h>
20 #include <malloc.h>
21 #include <asm/io.h>
22 #include <asm/arch/imx-regs.h>
23 #include <asm/arch/mxsfb.h>
24 #include <asm/arch/sys_proto.h>
25
26 static ushort mxsfb_cmap[256];
27 vidinfo_t panel_info = {
28         /* set to max. size supported by SoC */
29         .vl_col = 800,
30         .vl_row = 480,
31
32         .vl_bpix = LCD_COLOR24,    /* Bits per pixel, 0: 1bpp, 1: 2bpp, 2: 4bpp, 3: 8bpp ... */
33         .cmap = mxsfb_cmap,
34 };
35
36 static int bits_per_pixel;
37 static int color_depth;
38 static uint32_t pix_fmt;
39 static struct fb_var_screeninfo mxsfb_var;
40
41 static struct mx28_lcdif_regs *lcd_regs = (void *)MXS_LCDIF_BASE;
42
43 void *lcd_base;                 /* Start of framebuffer memory  */
44 void *lcd_console_address;      /* Start of console buffer      */
45
46 int lcd_line_length;
47 int lcd_color_fg;
48 int lcd_color_bg;
49
50 short console_col;
51 short console_row;
52
53 void lcd_initcolregs(void)
54 {
55 }
56
57 void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
58 {
59 }
60
61 #define fourcc_str(fourcc)      ((fourcc) >> 0) & 0xff, \
62                 ((fourcc) >> 8) & 0xff,                 \
63                 ((fourcc) >> 16) & 0xff,                \
64                 ((fourcc) >> 24) & 0xff
65
66 #define LCD_CTRL_DEFAULT        (LCDIF_CTRL_LCDIF_MASTER |      \
67                                 LCDIF_CTRL_BYPASS_COUNT |       \
68                                 LCDIF_CTRL_DOTCLK_MODE)
69
70 #define LCD_CTRL1_DEFAULT       0
71 #define LCD_CTRL2_DEFAULT       LCDIF_CTRL2_OUTSTANDING_REQS_REQ_2
72
73 #define LCD_VDCTRL0_DEFAULT     (LCDIF_VDCTRL0_ENABLE_PRESENT |         \
74                                 LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |       \
75                                 LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT)
76 #define LCD_VDCTRL1_DEFAULT     0
77 #define LCD_VDCTRL2_DEFAULT     0
78 #define LCD_VDCTRL3_DEFAULT     0
79 #define LCD_VDCTRL4_DEFAULT     LCDIF_VDCTRL4_SYNC_SIGNALS_ON
80
81 void video_hw_init(void *lcdbase)
82 {
83         int ret;
84         unsigned int div = 0, best = 0, pix_clk;
85         u32 frac1;
86         const unsigned long lcd_clk = 480000000;
87         u32 lcd_ctrl = LCD_CTRL_DEFAULT | LCDIF_CTRL_RUN;
88         u32 lcd_ctrl1 = LCD_CTRL1_DEFAULT, lcd_ctrl2 = LCD_CTRL2_DEFAULT;
89         u32 lcd_vdctrl0 = LCD_VDCTRL0_DEFAULT;
90         u32 lcd_vdctrl1 = LCD_VDCTRL1_DEFAULT;
91         u32 lcd_vdctrl2 = LCD_VDCTRL2_DEFAULT;
92         u32 lcd_vdctrl3 = LCD_VDCTRL3_DEFAULT;
93         u32 lcd_vdctrl4 = LCD_VDCTRL4_DEFAULT;
94         struct mx28_clkctrl_regs *clk_regs = (void *)MXS_CLKCTRL_BASE;
95         char buf1[16], buf2[16];
96
97         /* pixel format in memory */
98         switch (color_depth) {
99         case 8:
100                 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_8BIT;
101                 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(1);
102                 break;
103
104         case 16:
105                 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_16BIT;
106                 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(3);
107                 break;
108
109         case 18:
110                 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_18BIT;
111                 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(7);
112                 break;
113
114         case 24:
115                 lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_24BIT;
116                 lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(7);
117                 break;
118
119         default:
120                 printf("Invalid bpp: %d\n", color_depth);
121                 return;
122         }
123
124         /* pixel format on the LCD data pins */
125         switch (pix_fmt) {
126         case PIX_FMT_RGB332:
127                 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_8BIT;
128                 break;
129
130         case PIX_FMT_RGB565:
131                 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_16BIT;
132                 break;
133
134         case PIX_FMT_BGR666:
135                 lcd_ctrl |= 1 << LCDIF_CTRL_INPUT_DATA_SWIZZLE_OFFSET;
136                 /* fallthru */
137         case PIX_FMT_RGB666:
138                 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_18BIT;
139                 break;
140
141         case PIX_FMT_BGR24:
142                 lcd_ctrl |= 1 << LCDIF_CTRL_INPUT_DATA_SWIZZLE_OFFSET;
143                 /* fallthru */
144         case PIX_FMT_RGB24:
145                 lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_24BIT;
146                 break;
147
148         default:
149                 printf("Invalid pixel format: %c%c%c%c\n", fourcc_str(pix_fmt));
150                 return;
151         }
152
153         pix_clk = PICOS2KHZ(mxsfb_var.pixclock);
154         debug("designated pix_clk: %sMHz\n", strmhz(buf1, pix_clk * 1000));
155
156         for (frac1 = 18; frac1 < 36; frac1++) {
157                 static unsigned int err = ~0;
158                 unsigned long clk = lcd_clk / 1000 * 18 / frac1;
159                 unsigned int d = (clk + pix_clk - 1) / pix_clk;
160                 unsigned int diff = abs(clk / d - pix_clk);
161
162                 debug("frac1=%u div=%u lcd_clk=%-8sMHz pix_clk=%-8sMHz diff=%u err=%u\n",
163                         frac1, d, strmhz(buf1, clk * 1000), strmhz(buf2, clk * 1000 / d),
164                         diff, err);
165
166                 if (clk < pix_clk)
167                         break;
168                 if (d > 255)
169                         continue;
170
171                 if (diff < err) {
172                         best = frac1;
173                         div = d;
174                         err = diff;
175                         if (err == 0)
176                                 break;
177                 }
178         }
179         if (div == 0) {
180                 printf("Requested pixel clock %sMHz out of range\n",
181                         strmhz(buf1, pix_clk * 1000));
182                 return;
183         }
184
185         debug("div=%lu(%u*%u/18) for pixel clock %sMHz with base clock %sMHz\n",
186                 lcd_clk / pix_clk / 1000, best, div,
187                 strmhz(buf1, lcd_clk / div * 18 / best),
188                 strmhz(buf2, lcd_clk));
189
190         frac1 = (readl(&clk_regs->hw_clkctrl_frac1_reg) & ~0xff) | best;
191         writel(frac1, &clk_regs->hw_clkctrl_frac1_reg);
192         writel(1 << 14, &clk_regs->hw_clkctrl_clkseq_clr);
193
194         /* enable LCD clk and fractional divider */
195         writel(div, &clk_regs->hw_clkctrl_lcdif_reg);
196         while (readl(&clk_regs->hw_clkctrl_lcdif_reg) & (1 << 29))
197                 ;
198
199         ret = mx28_reset_block(&lcd_regs->hw_lcdif_ctrl_reg);
200         if (ret) {
201                 printf("Failed to reset LCD controller: LCDIF_CTRL: %08x CLKCTRL_LCDIF: %08x\n",
202                         readl(&lcd_regs->hw_lcdif_ctrl_reg),
203                         readl(&clk_regs->hw_clkctrl_lcdif_reg));
204                 return;
205         }
206
207         if (mxsfb_var.sync & FB_SYNC_HOR_HIGH_ACT)
208                 lcd_vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL;
209
210         if (mxsfb_var.sync & FB_SYNC_VERT_HIGH_ACT)
211                 lcd_vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL;
212
213         if (mxsfb_var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT)
214                 lcd_vdctrl0 |= LCDIF_VDCTRL0_ENABLE_POL;
215
216         if (mxsfb_var.sync & FB_SYNC_DOTCLK_FALLING_ACT)
217                 lcd_vdctrl0 |= LCDIF_VDCTRL0_DOTCLK_POL;
218
219         lcd_vdctrl0 |= LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH(mxsfb_var.vsync_len);
220         lcd_vdctrl1 |= LCDIF_VDCTRL1_VSYNC_PERIOD(mxsfb_var.vsync_len +
221                                                 mxsfb_var.upper_margin +
222                                                 mxsfb_var.lower_margin +
223                                                 mxsfb_var.yres);
224         lcd_vdctrl2 |= LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH(mxsfb_var.hsync_len);
225         lcd_vdctrl2 |= LCDIF_VDCTRL2_HSYNC_PERIOD(mxsfb_var.hsync_len +
226                                                 mxsfb_var.left_margin +
227                                                 mxsfb_var.right_margin +
228                                                 mxsfb_var.xres);
229
230         lcd_vdctrl3 |= LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT(mxsfb_var.left_margin +
231                                                         mxsfb_var.hsync_len);
232         lcd_vdctrl3 |= LCDIF_VDCTRL3_VERTICAL_WAIT_CNT(mxsfb_var.upper_margin +
233                                                         mxsfb_var.vsync_len);
234
235         lcd_vdctrl4 |= LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT(mxsfb_var.xres);
236
237         writel((u32)lcdbase, &lcd_regs->hw_lcdif_next_buf_reg);
238         writel(LCDIF_TRANSFER_COUNT_H_COUNT(mxsfb_var.xres) |
239                 LCDIF_TRANSFER_COUNT_V_COUNT(mxsfb_var.yres),
240                 &lcd_regs->hw_lcdif_transfer_count_reg);
241
242         writel(lcd_vdctrl0, &lcd_regs->hw_lcdif_vdctrl0_reg);
243         writel(lcd_vdctrl1, &lcd_regs->hw_lcdif_vdctrl1_reg);
244         writel(lcd_vdctrl2, &lcd_regs->hw_lcdif_vdctrl2_reg);
245         writel(lcd_vdctrl3, &lcd_regs->hw_lcdif_vdctrl3_reg);
246         writel(lcd_vdctrl4, &lcd_regs->hw_lcdif_vdctrl4_reg);
247
248         writel(lcd_ctrl1, &lcd_regs->hw_lcdif_ctrl1_reg);
249         writel(lcd_ctrl2, &lcd_regs->hw_lcdif_ctrl2_reg);
250
251         writel(lcd_ctrl, &lcd_regs->hw_lcdif_ctrl_reg);
252
253         debug("mxsfb framebuffer driver initialized\n");
254 }
255
256 void mxsfb_disable(void)
257 {
258         u32 lcd_ctrl = readl(&lcd_regs->hw_lcdif_ctrl_reg);
259
260         writel(lcd_ctrl & ~LCDIF_CTRL_RUN, &lcd_regs->hw_lcdif_ctrl_reg);
261 }
262
263 int mxsfb_init(struct fb_videomode *mode, uint32_t pixfmt, int bpp)
264 {
265         switch (bpp) {
266         case 8:
267                 bits_per_pixel = 8;
268                 panel_info.vl_bpix = LCD_COLOR8;
269                 break;
270
271         case 16:
272                 bits_per_pixel = 16;
273                 panel_info.vl_bpix = LCD_COLOR16;
274                 break;
275
276         case 18:
277                 bits_per_pixel = 32;
278                 panel_info.vl_bpix = LCD_COLOR24;
279                 break;
280
281         case 24:
282                 bits_per_pixel = 32;
283                 panel_info.vl_bpix = LCD_COLOR24;
284                 break;
285
286         default:
287                 return -EINVAL;
288         }
289
290         pix_fmt = pixfmt;
291         color_depth = bpp;
292
293         lcd_line_length = bits_per_pixel / 8 * mode->xres;
294
295         mxsfb_var.xres = mode->xres;
296         mxsfb_var.yres = mode->yres;
297         mxsfb_var.xres_virtual = mode->xres;
298         mxsfb_var.yres_virtual = mode->yres;
299         mxsfb_var.pixclock = mode->pixclock;
300         mxsfb_var.left_margin = mode->left_margin;
301         mxsfb_var.right_margin = mode->right_margin;
302         mxsfb_var.upper_margin = mode->upper_margin;
303         mxsfb_var.lower_margin = mode->lower_margin;
304         mxsfb_var.hsync_len = mode->hsync_len;
305         mxsfb_var.vsync_len = mode->vsync_len;
306         mxsfb_var.sync = mode->sync;
307
308         panel_info.vl_col = mode->xres;
309         panel_info.vl_row = mode->yres;
310
311         return 0;
312 }