aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Mallon <ryan@bluewatersys.com>2009-09-22 19:47:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:51 -0400
commit88017bda96a5fd568a982b01546c8fb1782dda62 (patch)
treefb31f14c593f882dac2db7acdfadbc469240dd6d
parentc6012189a40d33213ead5d15769fab615443206f (diff)
ep93xx video driver
EP93xx video driver plus documentation. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com> Cc: Daniele Venzano <linux@brownhat.org> Cc: Russell King <rmk@arm.linux.org.uk> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/fb/ep93xx-fb.txt135
-rw-r--r--drivers/video/Kconfig11
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/ep93xx-fb.c646
4 files changed, 793 insertions, 0 deletions
diff --git a/Documentation/fb/ep93xx-fb.txt b/Documentation/fb/ep93xx-fb.txt
new file mode 100644
index 000000000000..5af1bd9effae
--- /dev/null
+++ b/Documentation/fb/ep93xx-fb.txt
@@ -0,0 +1,135 @@
1================================
2Driver for EP93xx LCD controller
3================================
4
5The EP93xx LCD controller can drive both standard desktop monitors and
6embedded LCD displays. If you have a standard desktop monitor then you
7can use the standard Linux video mode database. In your board file:
8
9 static struct ep93xxfb_mach_info some_board_fb_info = {
10 .num_modes = EP93XXFB_USE_MODEDB,
11 .bpp = 16,
12 };
13
14If you have an embedded LCD display then you need to define a video
15mode for it as follows:
16
17 static struct fb_videomode some_board_video_modes[] = {
18 {
19 .name = "some_lcd_name",
20 /* Pixel clock, porches, etc */
21 },
22 };
23
24Note that the pixel clock value is in pico-seconds. You can use the
25KHZ2PICOS macro to convert the pixel clock value. Most other values
26are in pixel clocks. See Documentation/fb/framebuffer.txt for further
27details.
28
29The ep93xxfb_mach_info structure for your board should look like the
30following:
31
32 static struct ep93xxfb_mach_info some_board_fb_info = {
33 .num_modes = ARRAY_SIZE(some_board_video_modes),
34 .modes = some_board_video_modes,
35 .default_mode = &some_board_video_modes[0],
36 .bpp = 16,
37 };
38
39The framebuffer device can be registered by adding the following to
40your board initialisation function:
41
42 ep93xx_register_fb(&some_board_fb_info);
43
44=====================
45Video Attribute Flags
46=====================
47
48The ep93xxfb_mach_info structure has a flags field which can be used
49to configure the controller. The video attributes flags are fully
50documented in section 7 of the EP93xx users' guide. The following
51flags are available:
52
53EP93XXFB_PCLK_FALLING Clock data on the falling edge of the
54 pixel clock. The default is to clock
55 data on the rising edge.
56
57EP93XXFB_SYNC_BLANK_HIGH Blank signal is active high. By
58 default the blank signal is active low.
59
60EP93XXFB_SYNC_HORIZ_HIGH Horizontal sync is active high. By
61 default the horizontal sync is active low.
62
63EP93XXFB_SYNC_VERT_HIGH Vertical sync is active high. By
64 default the vertical sync is active high.
65
66The physical address of the framebuffer can be controlled using the
67following flags:
68
69EP93XXFB_USE_SDCSN0 Use SDCSn[0] for the framebuffer. This
70 is the default setting.
71
72EP93XXFB_USE_SDCSN1 Use SDCSn[1] for the framebuffer.
73
74EP93XXFB_USE_SDCSN2 Use SDCSn[2] for the framebuffer.
75
76EP93XXFB_USE_SDCSN3 Use SDCSn[3] for the framebuffer.
77
78==================
79Platform callbacks
80==================
81
82The EP93xx framebuffer driver supports three optional platform
83callbacks: setup, teardown and blank. The setup and teardown functions
84are called when the framebuffer driver is installed and removed
85respectively. The blank function is called whenever the display is
86blanked or unblanked.
87
88The setup and teardown devices pass the platform_device structure as
89an argument. The fb_info and ep93xxfb_mach_info structures can be
90obtained as follows:
91
92 static int some_board_fb_setup(struct platform_device *pdev)
93 {
94 struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
95 struct fb_info *fb_info = platform_get_drvdata(pdev);
96
97 /* Board specific framebuffer setup */
98 }
99
100======================
101Setting the video mode
102======================
103
104The video mode is set using the following syntax:
105
106 video=XRESxYRES[-BPP][@REFRESH]
107
108If the EP93xx video driver is built-in then the video mode is set on
109the Linux kernel command line, for example:
110
111 video=ep93xx-fb:800x600-16@60
112
113If the EP93xx video driver is built as a module then the video mode is
114set when the module is installed:
115
116 modprobe ep93xx-fb video=320x240
117
118==============
119Screenpage bug
120==============
121
122At least on the EP9315 there is a silicon bug which causes bit 27 of
123the VIDSCRNPAGE (framebuffer physical offset) to be tied low. There is
124an unofficial errata for this bug at:
125 http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
126
127By default the EP93xx framebuffer driver checks if the allocated physical
128address has bit 27 set. If it does, then the memory is freed and an
129error is returned. The check can be disabled by adding the following
130option when loading the driver:
131
132 ep93xx-fb.check_screenpage_bug=0
133
134In some cases it may be possible to reconfigure your SDRAM layout to
135avoid this bug. See section 13 of the EP93xx users' guide for details.
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a7944ef48a2a..7be506262284 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2128,6 +2128,17 @@ config FB_MB862XX_LIME
2128 ---help--- 2128 ---help---
2129 Framebuffer support for Fujitsu Lime GDC on host CPU bus. 2129 Framebuffer support for Fujitsu Lime GDC on host CPU bus.
2130 2130
2131config FB_EP93XX
2132 tristate "EP93XX frame buffer support"
2133 depends on FB && ARCH_EP93XX
2134 select FB_CFB_FILLRECT
2135 select FB_CFB_COPYAREA
2136 select FB_CFB_IMAGEBLIT
2137 ---help---
2138 Framebuffer driver for the Cirrus Logic EP93XX series of processors.
2139 This driver is also available as a module. The module will be called
2140 ep93xx-fb.
2141
2131config FB_PRE_INIT_FB 2142config FB_PRE_INIT_FB
2132 bool "Don't reinitialize, use bootloader's GDC/Display configuration" 2143 bool "Don't reinitialize, use bootloader's GDC/Display configuration"
2133 depends on FB_MB862XX_LIME 2144 depends on FB_MB862XX_LIME
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 85b2d2322dc7..80232e124889 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_FB_Q40) += q40fb.o
85obj-$(CONFIG_FB_TGA) += tgafb.o 85obj-$(CONFIG_FB_TGA) += tgafb.o
86obj-$(CONFIG_FB_HP300) += hpfb.o 86obj-$(CONFIG_FB_HP300) += hpfb.o
87obj-$(CONFIG_FB_G364) += g364fb.o 87obj-$(CONFIG_FB_G364) += g364fb.o
88obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o
88obj-$(CONFIG_FB_SA1100) += sa1100fb.o 89obj-$(CONFIG_FB_SA1100) += sa1100fb.o
89obj-$(CONFIG_FB_HIT) += hitfb.o 90obj-$(CONFIG_FB_HIT) += hitfb.o
90obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o 91obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c
new file mode 100644
index 000000000000..bd9d46f95291
--- /dev/null
+++ b/drivers/video/ep93xx-fb.c
@@ -0,0 +1,646 @@
1/*
2 * linux/drivers/video/ep93xx-fb.c
3 *
4 * Framebuffer support for the EP93xx series.
5 *
6 * Copyright (C) 2007 Bluewater Systems Ltd
7 * Author: Ryan Mallon <ryan@bluewatersys.com>
8 *
9 * Copyright (c) 2009 H Hartley Sweeten <hsweeten@visionengravers.com>
10 *
11 * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb
12 * drivers.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 *
18 */
19
20#include <linux/platform_device.h>
21#include <linux/dma-mapping.h>
22#include <linux/clk.h>
23#include <linux/fb.h>
24
25#include <mach/fb.h>
26
27/* Vertical Frame Timing Registers */
28#define EP93XXFB_VLINES_TOTAL 0x0000 /* SW locked */
29#define EP93XXFB_VSYNC 0x0004 /* SW locked */
30#define EP93XXFB_VACTIVE 0x0008 /* SW locked */
31#define EP93XXFB_VBLANK 0x0228 /* SW locked */
32#define EP93XXFB_VCLK 0x000c /* SW locked */
33
34/* Horizontal Frame Timing Registers */
35#define EP93XXFB_HCLKS_TOTAL 0x0010 /* SW locked */
36#define EP93XXFB_HSYNC 0x0014 /* SW locked */
37#define EP93XXFB_HACTIVE 0x0018 /* SW locked */
38#define EP93XXFB_HBLANK 0x022c /* SW locked */
39#define EP93XXFB_HCLK 0x001c /* SW locked */
40
41/* Frame Buffer Memory Configuration Registers */
42#define EP93XXFB_SCREEN_PAGE 0x0028
43#define EP93XXFB_SCREEN_HPAGE 0x002c
44#define EP93XXFB_SCREEN_LINES 0x0030
45#define EP93XXFB_LINE_LENGTH 0x0034
46#define EP93XXFB_VLINE_STEP 0x0038
47#define EP93XXFB_LINE_CARRY 0x003c /* SW locked */
48#define EP93XXFB_EOL_OFFSET 0x0230
49
50/* Other Video Registers */
51#define EP93XXFB_BRIGHTNESS 0x0020
52#define EP93XXFB_ATTRIBS 0x0024 /* SW locked */
53#define EP93XXFB_SWLOCK 0x007c /* SW locked */
54#define EP93XXFB_AC_RATE 0x0214
55#define EP93XXFB_FIFO_LEVEL 0x0234
56#define EP93XXFB_PIXELMODE 0x0054
57#define EP93XXFB_PIXELMODE_32BPP (0x7 << 0)
58#define EP93XXFB_PIXELMODE_24BPP (0x6 << 0)
59#define EP93XXFB_PIXELMODE_16BPP (0x4 << 0)
60#define EP93XXFB_PIXELMODE_8BPP (0x2 << 0)
61#define EP93XXFB_PIXELMODE_SHIFT_1P_24B (0x0 << 3)
62#define EP93XXFB_PIXELMODE_SHIFT_1P_18B (0x1 << 3)
63#define EP93XXFB_PIXELMODE_COLOR_LUT (0x0 << 10)
64#define EP93XXFB_PIXELMODE_COLOR_888 (0x4 << 10)
65#define EP93XXFB_PIXELMODE_COLOR_555 (0x5 << 10)
66#define EP93XXFB_PARL_IF_OUT 0x0058
67#define EP93XXFB_PARL_IF_IN 0x005c
68
69/* Blink Control Registers */
70#define EP93XXFB_BLINK_RATE 0x0040
71#define EP93XXFB_BLINK_MASK 0x0044
72#define EP93XXFB_BLINK_PATTRN 0x0048
73#define EP93XXFB_PATTRN_MASK 0x004c
74#define EP93XXFB_BKGRND_OFFSET 0x0050
75
76/* Hardware Cursor Registers */
77#define EP93XXFB_CURSOR_ADR_START 0x0060
78#define EP93XXFB_CURSOR_ADR_RESET 0x0064
79#define EP93XXFB_CURSOR_SIZE 0x0068
80#define EP93XXFB_CURSOR_COLOR1 0x006c
81#define EP93XXFB_CURSOR_COLOR2 0x0070
82#define EP93XXFB_CURSOR_BLINK_COLOR1 0x021c
83#define EP93XXFB_CURSOR_BLINK_COLOR2 0x0220
84#define EP93XXFB_CURSOR_XY_LOC 0x0074
85#define EP93XXFB_CURSOR_DSCAN_HY_LOC 0x0078
86#define EP93XXFB_CURSOR_BLINK_RATE_CTRL 0x0224
87
88/* LUT Registers */
89#define EP93XXFB_GRY_SCL_LUTR 0x0080
90#define EP93XXFB_GRY_SCL_LUTG 0x0280
91#define EP93XXFB_GRY_SCL_LUTB 0x0300
92#define EP93XXFB_LUT_SW_CONTROL 0x0218
93#define EP93XXFB_LUT_SW_CONTROL_SWTCH (1 << 0)
94#define EP93XXFB_LUT_SW_CONTROL_SSTAT (1 << 1)
95#define EP93XXFB_COLOR_LUT 0x0400
96
97/* Video Signature Registers */
98#define EP93XXFB_VID_SIG_RSLT_VAL 0x0200
99#define EP93XXFB_VID_SIG_CTRL 0x0204
100#define EP93XXFB_VSIG 0x0208
101#define EP93XXFB_HSIG 0x020c
102#define EP93XXFB_SIG_CLR_STR 0x0210
103
104/* Minimum / Maximum resolutions supported */
105#define EP93XXFB_MIN_XRES 64
106#define EP93XXFB_MIN_YRES 64
107#define EP93XXFB_MAX_XRES 1024
108#define EP93XXFB_MAX_YRES 768
109
110struct ep93xx_fbi {
111 struct ep93xxfb_mach_info *mach_info;
112 struct clk *clk;
113 struct resource *res;
114 void __iomem *mmio_base;
115 unsigned int pseudo_palette[256];
116};
117
118static int check_screenpage_bug = 1;
119module_param(check_screenpage_bug, int, 0644);
120MODULE_PARM_DESC(check_screenpage_bug,
121 "Check for bit 27 screen page bug. Default = 1");
122
123static inline unsigned int ep93xxfb_readl(struct ep93xx_fbi *fbi,
124 unsigned int off)
125{
126 return __raw_readl(fbi->mmio_base + off);
127}
128
129static inline void ep93xxfb_writel(struct ep93xx_fbi *fbi,
130 unsigned int val, unsigned int off)
131{
132 __raw_writel(val, fbi->mmio_base + off);
133}
134
135/*
136 * Write to one of the locked raster registers.
137 */
138static inline void ep93xxfb_out_locked(struct ep93xx_fbi *fbi,
139 unsigned int val, unsigned int reg)
140{
141 /*
142 * We don't need a lock or delay here since the raster register
143 * block will remain unlocked until the next access.
144 */
145 ep93xxfb_writel(fbi, 0xaa, EP93XXFB_SWLOCK);
146 ep93xxfb_writel(fbi, val, reg);
147}
148
149static void ep93xxfb_set_video_attribs(struct fb_info *info)
150{
151 struct ep93xx_fbi *fbi = info->par;
152 unsigned int attribs;
153
154 attribs = EP93XXFB_ENABLE;
155 attribs |= fbi->mach_info->flags;
156 ep93xxfb_out_locked(fbi, attribs, EP93XXFB_ATTRIBS);
157}
158
159static int ep93xxfb_set_pixelmode(struct fb_info *info)
160{
161 struct ep93xx_fbi *fbi = info->par;
162 unsigned int val;
163
164 info->var.transp.offset = 0;
165 info->var.transp.length = 0;
166
167 switch (info->var.bits_per_pixel) {
168 case 8:
169 val = EP93XXFB_PIXELMODE_8BPP | EP93XXFB_PIXELMODE_COLOR_LUT |
170 EP93XXFB_PIXELMODE_SHIFT_1P_18B;
171
172 info->var.red.offset = 0;
173 info->var.red.length = 8;
174 info->var.green.offset = 0;
175 info->var.green.length = 8;
176 info->var.blue.offset = 0;
177 info->var.blue.length = 8;
178 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
179 break;
180
181 case 16:
182 val = EP93XXFB_PIXELMODE_16BPP | EP93XXFB_PIXELMODE_COLOR_555 |
183 EP93XXFB_PIXELMODE_SHIFT_1P_18B;
184
185 info->var.red.offset = 11;
186 info->var.red.length = 5;
187 info->var.green.offset = 5;
188 info->var.green.length = 6;
189 info->var.blue.offset = 0;
190 info->var.blue.length = 5;
191 info->fix.visual = FB_VISUAL_TRUECOLOR;
192 break;
193
194 case 24:
195 val = EP93XXFB_PIXELMODE_24BPP | EP93XXFB_PIXELMODE_COLOR_888 |
196 EP93XXFB_PIXELMODE_SHIFT_1P_24B;
197
198 info->var.red.offset = 16;
199 info->var.red.length = 8;
200 info->var.green.offset = 8;
201 info->var.green.length = 8;
202 info->var.blue.offset = 0;
203 info->var.blue.length = 8;
204 info->fix.visual = FB_VISUAL_TRUECOLOR;
205 break;
206
207 case 32:
208 val = EP93XXFB_PIXELMODE_32BPP | EP93XXFB_PIXELMODE_COLOR_888 |
209 EP93XXFB_PIXELMODE_SHIFT_1P_24B;
210
211 info->var.red.offset = 16;
212 info->var.red.length = 8;
213 info->var.green.offset = 8;
214 info->var.green.length = 8;
215 info->var.blue.offset = 0;
216 info->var.blue.length = 8;
217 info->fix.visual = FB_VISUAL_TRUECOLOR;
218 break;
219
220 default:
221 return -EINVAL;
222 }
223
224 ep93xxfb_writel(fbi, val, EP93XXFB_PIXELMODE);
225 return 0;
226}
227
228static void ep93xxfb_set_timing(struct fb_info *info)
229{
230 struct ep93xx_fbi *fbi = info->par;
231 unsigned int vlines_total, hclks_total, start, stop;
232
233 vlines_total = info->var.yres + info->var.upper_margin +
234 info->var.lower_margin + info->var.vsync_len - 1;
235
236 hclks_total = info->var.xres + info->var.left_margin +
237 info->var.right_margin + info->var.hsync_len - 1;
238
239 ep93xxfb_out_locked(fbi, vlines_total, EP93XXFB_VLINES_TOTAL);
240 ep93xxfb_out_locked(fbi, hclks_total, EP93XXFB_HCLKS_TOTAL);
241
242 start = vlines_total;
243 stop = vlines_total - info->var.vsync_len;
244 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VSYNC);
245
246 start = vlines_total - info->var.vsync_len - info->var.upper_margin;
247 stop = info->var.lower_margin - 1;
248 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VBLANK);
249 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VACTIVE);
250
251 start = vlines_total;
252 stop = vlines_total + 1;
253 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VCLK);
254
255 start = hclks_total;
256 stop = hclks_total - info->var.hsync_len;
257 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HSYNC);
258
259 start = hclks_total - info->var.hsync_len - info->var.left_margin;
260 stop = info->var.right_margin - 1;
261 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HBLANK);
262 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HACTIVE);
263
264 start = hclks_total;
265 stop = hclks_total;
266 ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HCLK);
267
268 ep93xxfb_out_locked(fbi, 0x0, EP93XXFB_LINE_CARRY);
269}
270
271static int ep93xxfb_set_par(struct fb_info *info)
272{
273 struct ep93xx_fbi *fbi = info->par;
274
275 clk_set_rate(fbi->clk, 1000 * PICOS2KHZ(info->var.pixclock));
276
277 ep93xxfb_set_timing(info);
278
279 info->fix.line_length = info->var.xres_virtual *
280 info->var.bits_per_pixel / 8;
281
282 ep93xxfb_writel(fbi, info->fix.smem_start, EP93XXFB_SCREEN_PAGE);
283 ep93xxfb_writel(fbi, info->var.yres - 1, EP93XXFB_SCREEN_LINES);
284 ep93xxfb_writel(fbi, ((info->var.xres * info->var.bits_per_pixel)
285 / 32) - 1, EP93XXFB_LINE_LENGTH);
286 ep93xxfb_writel(fbi, info->fix.line_length / 4, EP93XXFB_VLINE_STEP);
287 ep93xxfb_set_video_attribs(info);
288 return 0;
289}
290
291static int ep93xxfb_check_var(struct fb_var_screeninfo *var,
292 struct fb_info *info)
293{
294 int err;
295
296 err = ep93xxfb_set_pixelmode(info);
297 if (err)
298 return err;
299
300 var->xres = max_t(unsigned int, var->xres, EP93XXFB_MIN_XRES);
301 var->xres = min_t(unsigned int, var->xres, EP93XXFB_MAX_XRES);
302 var->xres_virtual = max(var->xres_virtual, var->xres);
303
304 var->yres = max_t(unsigned int, var->yres, EP93XXFB_MIN_YRES);
305 var->yres = min_t(unsigned int, var->yres, EP93XXFB_MAX_YRES);
306 var->yres_virtual = max(var->yres_virtual, var->yres);
307
308 return 0;
309}
310
311static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
312{
313 unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;
314
315 if (offset < info->fix.smem_len) {
316 return dma_mmap_writecombine(info->dev, vma, info->screen_base,
317 info->fix.smem_start,
318 info->fix.smem_len);
319 }
320
321 return -EINVAL;
322}
323
324static int ep93xxfb_blank(int blank_mode, struct fb_info *info)
325{
326 struct ep93xx_fbi *fbi = info->par;
327 unsigned int attribs = ep93xxfb_readl(fbi, EP93XXFB_ATTRIBS);
328
329 if (blank_mode) {
330 if (fbi->mach_info->blank)
331 fbi->mach_info->blank(blank_mode, info);
332 ep93xxfb_out_locked(fbi, attribs & ~EP93XXFB_ENABLE,
333 EP93XXFB_ATTRIBS);
334 clk_disable(fbi->clk);
335 } else {
336 clk_enable(fbi->clk);
337 ep93xxfb_out_locked(fbi, attribs | EP93XXFB_ENABLE,
338 EP93XXFB_ATTRIBS);
339 if (fbi->mach_info->blank)
340 fbi->mach_info->blank(blank_mode, info);
341 }
342
343 return 0;
344}
345
346static inline int ep93xxfb_convert_color(int val, int width)
347{
348 return ((val << width) + 0x7fff - val) >> 16;
349}
350
351static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red,
352 unsigned int green, unsigned int blue,
353 unsigned int transp, struct fb_info *info)
354{
355 struct ep93xx_fbi *fbi = info->par;
356 unsigned int *pal = info->pseudo_palette;
357 unsigned int ctrl, i, rgb, lut_current, lut_stat;
358
359 switch (info->fix.visual) {
360 case FB_VISUAL_PSEUDOCOLOR:
361 rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
362 ((blue & 0xff00) >> 8);
363
364 pal[regno] = rgb;
365 ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2)));
366 ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL);
367 lut_stat = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SSTAT);
368 lut_current = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SWTCH);
369
370 if (lut_stat == lut_current) {
371 for (i = 0; i < 256; i++) {
372 ep93xxfb_writel(fbi, pal[i],
373 EP93XXFB_COLOR_LUT + (i << 2));
374 }
375
376 ep93xxfb_writel(fbi,
377 ctrl ^ EP93XXFB_LUT_SW_CONTROL_SWTCH,
378 EP93XXFB_LUT_SW_CONTROL);
379 }
380 break;
381
382 case FB_VISUAL_TRUECOLOR:
383 if (regno > 16)
384 return 1;
385
386 red = ep93xxfb_convert_color(red, info->var.red.length);
387 green = ep93xxfb_convert_color(green, info->var.green.length);
388 blue = ep93xxfb_convert_color(blue, info->var.blue.length);
389 transp = ep93xxfb_convert_color(transp,
390 info->var.transp.length);
391
392 pal[regno] = (red << info->var.red.offset) |
393 (green << info->var.green.offset) |
394 (blue << info->var.blue.offset) |
395 (transp << info->var.transp.offset);
396 break;
397
398 default:
399 return 1;
400 }
401
402 return 0;
403}
404
405static struct fb_ops ep93xxfb_ops = {
406 .owner = THIS_MODULE,
407 .fb_check_var = ep93xxfb_check_var,
408 .fb_set_par = ep93xxfb_set_par,
409 .fb_blank = ep93xxfb_blank,
410 .fb_fillrect = cfb_fillrect,
411 .fb_copyarea = cfb_copyarea,
412 .fb_imageblit = cfb_imageblit,
413 .fb_setcolreg = ep93xxfb_setcolreg,
414 .fb_mmap = ep93xxfb_mmap,
415};
416
417static int __init ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info)
418{
419 int i, fb_size = 0;
420
421 if (mach_info->num_modes == EP93XXFB_USE_MODEDB) {
422 fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES *
423 mach_info->bpp / 8;
424 } else {
425 for (i = 0; i < mach_info->num_modes; i++) {
426 const struct fb_videomode *mode;
427 int size;
428
429 mode = &mach_info->modes[i];
430 size = mode->xres * mode->yres * mach_info->bpp / 8;
431 if (size > fb_size)
432 fb_size = size;
433 }
434 }
435
436 return fb_size;
437}
438
439static int __init ep93xxfb_alloc_videomem(struct fb_info *info)
440{
441 struct ep93xx_fbi *fbi = info->par;
442 char __iomem *virt_addr;
443 dma_addr_t phys_addr;
444 unsigned int fb_size;
445
446 fb_size = ep93xxfb_calc_fbsize(fbi->mach_info);
447 virt_addr = dma_alloc_writecombine(info->dev, fb_size,
448 &phys_addr, GFP_KERNEL);
449 if (!virt_addr)
450 return -ENOMEM;
451
452 /*
453 * There is a bug in the ep93xx framebuffer which causes problems
454 * if bit 27 of the physical address is set.
455 * See: http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
456 * There does not seem to be any offical errata for this, but I
457 * have confirmed the problem exists on my hardware (ep9315) at
458 * least.
459 */
460 if (check_screenpage_bug && phys_addr & (1 << 27)) {
461 dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) "
462 "has bit 27 set: cannot init framebuffer\n",
463 phys_addr);
464
465 dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr);
466 return -ENOMEM;
467 }
468
469 info->fix.smem_start = phys_addr;
470 info->fix.smem_len = fb_size;
471 info->screen_base = virt_addr;
472
473 return 0;
474}
475
476static void ep93xxfb_dealloc_videomem(struct fb_info *info)
477{
478 if (info->screen_base)
479 dma_free_coherent(info->dev, info->fix.smem_len,
480 info->screen_base, info->fix.smem_start);
481}
482
483static int __init ep93xxfb_probe(struct platform_device *pdev)
484{
485 struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
486 struct fb_info *info;
487 struct ep93xx_fbi *fbi;
488 struct resource *res;
489 char *video_mode;
490 int err;
491
492 if (!mach_info)
493 return -EINVAL;
494
495 info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev);
496 if (!info)
497 return -ENOMEM;
498
499 info->dev = &pdev->dev;
500 platform_set_drvdata(pdev, info);
501 fbi = info->par;
502 fbi->mach_info = mach_info;
503
504 err = fb_alloc_cmap(&info->cmap, 256, 0);
505 if (err)
506 goto failed;
507
508 err = ep93xxfb_alloc_videomem(info);
509 if (err)
510 goto failed;
511
512 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
513 if (!res) {
514 err = -ENXIO;
515 goto failed;
516 }
517
518 res = request_mem_region(res->start, resource_size(res), pdev->name);
519 if (!res) {
520 err = -EBUSY;
521 goto failed;
522 }
523
524 fbi->res = res;
525 fbi->mmio_base = ioremap(res->start, resource_size(res));
526 if (!fbi->mmio_base) {
527 err = -ENXIO;
528 goto failed;
529 }
530
531 strcpy(info->fix.id, pdev->name);
532 info->fbops = &ep93xxfb_ops;
533 info->fix.type = FB_TYPE_PACKED_PIXELS;
534 info->fix.accel = FB_ACCEL_NONE;
535 info->var.activate = FB_ACTIVATE_NOW;
536 info->var.vmode = FB_VMODE_NONINTERLACED;
537 info->flags = FBINFO_DEFAULT;
538 info->node = -1;
539 info->state = FBINFO_STATE_RUNNING;
540 info->pseudo_palette = &fbi->pseudo_palette;
541
542 fb_get_options("ep93xx-fb", &video_mode);
543 err = fb_find_mode(&info->var, info, video_mode,
544 fbi->mach_info->modes, fbi->mach_info->num_modes,
545 fbi->mach_info->default_mode, fbi->mach_info->bpp);
546 if (err == 0) {
547 dev_err(info->dev, "No suitable video mode found\n");
548 err = -EINVAL;
549 goto failed;
550 }
551
552 if (mach_info->setup) {
553 err = mach_info->setup(pdev);
554 if (err)
555 return err;
556 }
557
558 err = ep93xxfb_check_var(&info->var, info);
559 if (err)
560 goto failed;
561
562 fbi->clk = clk_get(info->dev, NULL);
563 if (IS_ERR(fbi->clk)) {
564 err = PTR_ERR(fbi->clk);
565 fbi->clk = NULL;
566 goto failed;
567 }
568
569 ep93xxfb_set_par(info);
570 clk_enable(fbi->clk);
571
572 err = register_framebuffer(info);
573 if (err)
574 goto failed;
575
576 dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
577 info->var.xres, info->var.yres, info->var.bits_per_pixel);
578 return 0;
579
580failed:
581 if (fbi->clk)
582 clk_put(fbi->clk);
583 if (fbi->mmio_base)
584 iounmap(fbi->mmio_base);
585 if (fbi->res)
586 release_mem_region(fbi->res->start, resource_size(fbi->res));
587 ep93xxfb_dealloc_videomem(info);
588 if (&info->cmap)
589 fb_dealloc_cmap(&info->cmap);
590 if (fbi->mach_info->teardown)
591 fbi->mach_info->teardown(pdev);
592 kfree(info);
593 platform_set_drvdata(pdev, NULL);
594
595 return err;
596}
597
598static int ep93xxfb_remove(struct platform_device *pdev)
599{
600 struct fb_info *info = platform_get_drvdata(pdev);
601 struct ep93xx_fbi *fbi = info->par;
602
603 unregister_framebuffer(info);
604 clk_disable(fbi->clk);
605 clk_put(fbi->clk);
606 iounmap(fbi->mmio_base);
607 release_mem_region(fbi->res->start, resource_size(fbi->res));
608 ep93xxfb_dealloc_videomem(info);
609 fb_dealloc_cmap(&info->cmap);
610
611 if (fbi->mach_info->teardown)
612 fbi->mach_info->teardown(pdev);
613
614 kfree(info);
615 platform_set_drvdata(pdev, NULL);
616
617 return 0;
618}
619
620static struct platform_driver ep93xxfb_driver = {
621 .probe = ep93xxfb_probe,
622 .remove = ep93xxfb_remove,
623 .driver = {
624 .name = "ep93xx-fb",
625 .owner = THIS_MODULE,
626 },
627};
628
629static int __devinit ep93xxfb_init(void)
630{
631 return platform_driver_register(&ep93xxfb_driver);
632}
633
634static void __exit ep93xxfb_exit(void)
635{
636 platform_driver_unregister(&ep93xxfb_driver);
637}
638
639module_init(ep93xxfb_init);
640module_exit(ep93xxfb_exit);
641
642MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
643MODULE_ALIAS("platform:ep93xx-fb");
644MODULE_AUTHOR("Ryan Mallon <ryan&bluewatersys.com>, "
645 "H Hartley Sweeten <hsweeten@visionengravers.com");
646MODULE_LICENSE("GPL");