Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: Add support for the display controllers in VT8500 and WM8505

This adds drivers for the LCD controller found in VIA VT8500 SoC,
GOVR display controller found in WonderMedia WM8505 SoC and for the
Graphics Engine present in both of them that provides hardware
accelerated raster operations (used for copyarea and fillrect).

Signed-off-by: Alexey Charkov <alchark@gmail.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

authored by

Alexey Charkov and committed by
Paul Mundt
d6ff7d0f a7bcf21e

+1205
+26
drivers/video/Kconfig
··· 186 186 depends on FB 187 187 default n 188 188 189 + config FB_WMT_GE_ROPS 190 + tristate 191 + depends on FB 192 + default n 193 + ---help--- 194 + Include functions for accelerated rectangle filling and area 195 + copying using WonderMedia Graphics Engine operations. 196 + 189 197 config FB_DEFERRED_IO 190 198 bool 191 199 depends on FB ··· 1729 1721 This is the framebuffer driver for the AMD Au1200 SOC. It can drive 1730 1722 various panels and CRTs by passing in kernel cmd line option 1731 1723 au1200fb:panel=<name>. 1724 + 1725 + config FB_VT8500 1726 + bool "VT8500 LCD Driver" 1727 + depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_VT8500 1728 + select FB_WMT_GE_ROPS 1729 + select FB_SYS_IMAGEBLIT 1730 + help 1731 + This is the framebuffer driver for VIA VT8500 integrated LCD 1732 + controller. 1733 + 1734 + config FB_WM8505 1735 + bool "WM8505 frame buffer support" 1736 + depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_WM8505 1737 + select FB_WMT_GE_ROPS 1738 + select FB_SYS_IMAGEBLIT 1739 + help 1740 + This is the framebuffer driver for WonderMedia WM8505 1741 + integrated LCD controller. 1732 1742 1733 1743 source "drivers/video/geode/Kconfig" 1734 1744
+3
drivers/video/Makefile
··· 26 26 obj-$(CONFIG_FB_MACMODES) += macmodes.o 27 27 obj-$(CONFIG_FB_DDC) += fb_ddc.o 28 28 obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o 29 + obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o 29 30 30 31 # Hardware specific drivers go first 31 32 obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o ··· 105 104 obj-$(CONFIG_FB_TMIO) += tmiofb.o 106 105 obj-$(CONFIG_FB_AU1100) += au1100fb.o 107 106 obj-$(CONFIG_FB_AU1200) += au1200fb.o 107 + obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o 108 + obj-$(CONFIG_FB_WM8505) += wm8505fb.o 108 109 obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o 109 110 obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o 110 111 obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o
+447
drivers/video/vt8500lcdfb.c
··· 1 + /* 2 + * linux/drivers/video/vt8500lcdfb.c 3 + * 4 + * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> 5 + * 6 + * Based on skeletonfb.c and pxafb.c 7 + * 8 + * This software is licensed under the terms of the GNU General Public 9 + * License version 2, as published by the Free Software Foundation, and 10 + * may be copied, distributed, and modified under those terms. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/kernel.h> 20 + #include <linux/errno.h> 21 + #include <linux/string.h> 22 + #include <linux/mm.h> 23 + #include <linux/slab.h> 24 + #include <linux/delay.h> 25 + #include <linux/fb.h> 26 + #include <linux/init.h> 27 + #include <linux/interrupt.h> 28 + #include <linux/io.h> 29 + #include <linux/dma-mapping.h> 30 + #include <linux/platform_device.h> 31 + #include <linux/wait.h> 32 + 33 + #include <mach/vt8500fb.h> 34 + 35 + #include "vt8500lcdfb.h" 36 + #include "wmt_ge_rops.h" 37 + 38 + #define to_vt8500lcd_info(__info) container_of(__info, \ 39 + struct vt8500lcd_info, fb) 40 + 41 + static int vt8500lcd_set_par(struct fb_info *info) 42 + { 43 + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); 44 + int reg_bpp = 5; /* 16bpp */ 45 + int i; 46 + unsigned long control0; 47 + 48 + if (!fbi) 49 + return -EINVAL; 50 + 51 + if (info->var.bits_per_pixel <= 8) { 52 + /* palettized */ 53 + info->var.red.offset = 0; 54 + info->var.red.length = info->var.bits_per_pixel; 55 + info->var.red.msb_right = 0; 56 + 57 + info->var.green.offset = 0; 58 + info->var.green.length = info->var.bits_per_pixel; 59 + info->var.green.msb_right = 0; 60 + 61 + info->var.blue.offset = 0; 62 + info->var.blue.length = info->var.bits_per_pixel; 63 + info->var.blue.msb_right = 0; 64 + 65 + info->var.transp.offset = 0; 66 + info->var.transp.length = 0; 67 + info->var.transp.msb_right = 0; 68 + 69 + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 70 + info->fix.line_length = info->var.xres_virtual / 71 + (8/info->var.bits_per_pixel); 72 + } else { 73 + /* non-palettized */ 74 + info->var.transp.offset = 0; 75 + info->var.transp.length = 0; 76 + info->var.transp.msb_right = 0; 77 + 78 + if (info->var.bits_per_pixel == 16) { 79 + /* RGB565 */ 80 + info->var.red.offset = 11; 81 + info->var.red.length = 5; 82 + info->var.red.msb_right = 0; 83 + info->var.green.offset = 5; 84 + info->var.green.length = 6; 85 + info->var.green.msb_right = 0; 86 + info->var.blue.offset = 0; 87 + info->var.blue.length = 5; 88 + info->var.blue.msb_right = 0; 89 + } else { 90 + /* Equal depths per channel */ 91 + info->var.red.offset = info->var.bits_per_pixel 92 + * 2 / 3; 93 + info->var.red.length = info->var.bits_per_pixel / 3; 94 + info->var.red.msb_right = 0; 95 + info->var.green.offset = info->var.bits_per_pixel / 3; 96 + info->var.green.length = info->var.bits_per_pixel / 3; 97 + info->var.green.msb_right = 0; 98 + info->var.blue.offset = 0; 99 + info->var.blue.length = info->var.bits_per_pixel / 3; 100 + info->var.blue.msb_right = 0; 101 + } 102 + 103 + info->fix.visual = FB_VISUAL_TRUECOLOR; 104 + info->fix.line_length = info->var.bits_per_pixel > 16 ? 105 + info->var.xres_virtual << 2 : 106 + info->var.xres_virtual << 1; 107 + } 108 + 109 + for (i = 0; i < 8; i++) { 110 + if (bpp_values[i] == info->var.bits_per_pixel) { 111 + reg_bpp = i; 112 + continue; 113 + } 114 + } 115 + 116 + control0 = readl(fbi->regbase) & ~0xf; 117 + writel(0, fbi->regbase); 118 + while (readl(fbi->regbase + 0x38) & 0x10) 119 + /* wait */; 120 + writel((((info->var.hsync_len - 1) & 0x3f) << 26) 121 + | ((info->var.left_margin & 0xff) << 18) 122 + | (((info->var.xres - 1) & 0x3ff) << 8) 123 + | (info->var.right_margin & 0xff), fbi->regbase + 0x4); 124 + writel((((info->var.vsync_len - 1) & 0x3f) << 26) 125 + | ((info->var.upper_margin & 0xff) << 18) 126 + | (((info->var.yres - 1) & 0x3ff) << 8) 127 + | (info->var.lower_margin & 0xff), fbi->regbase + 0x8); 128 + writel((((info->var.yres - 1) & 0x400) << 2) 129 + | ((info->var.xres - 1) & 0x400), fbi->regbase + 0x10); 130 + writel(0x80000000, fbi->regbase + 0x20); 131 + writel(control0 | (reg_bpp << 1) | 0x100, fbi->regbase); 132 + 133 + return 0; 134 + } 135 + 136 + static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) 137 + { 138 + chan &= 0xffff; 139 + chan >>= 16 - bf->length; 140 + return chan << bf->offset; 141 + } 142 + 143 + static int vt8500lcd_setcolreg(unsigned regno, unsigned red, unsigned green, 144 + unsigned blue, unsigned transp, 145 + struct fb_info *info) { 146 + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); 147 + int ret = 1; 148 + unsigned int val; 149 + if (regno >= 256) 150 + return -EINVAL; 151 + 152 + if (info->var.grayscale) 153 + red = green = blue = 154 + (19595 * red + 38470 * green + 7471 * blue) >> 16; 155 + 156 + switch (fbi->fb.fix.visual) { 157 + case FB_VISUAL_TRUECOLOR: 158 + if (regno < 16) { 159 + u32 *pal = fbi->fb.pseudo_palette; 160 + 161 + val = chan_to_field(red, &fbi->fb.var.red); 162 + val |= chan_to_field(green, &fbi->fb.var.green); 163 + val |= chan_to_field(blue, &fbi->fb.var.blue); 164 + 165 + pal[regno] = val; 166 + ret = 0; 167 + } 168 + break; 169 + 170 + case FB_VISUAL_STATIC_PSEUDOCOLOR: 171 + case FB_VISUAL_PSEUDOCOLOR: 172 + writew((red & 0xf800) 173 + | ((green >> 5) & 0x7e0) 174 + | ((blue >> 11) & 0x1f), 175 + fbi->palette_cpu + sizeof(u16) * regno); 176 + break; 177 + } 178 + 179 + return ret; 180 + } 181 + 182 + static int vt8500lcd_ioctl(struct fb_info *info, unsigned int cmd, 183 + unsigned long arg) 184 + { 185 + int ret = 0; 186 + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); 187 + 188 + if (cmd == FBIO_WAITFORVSYNC) { 189 + /* Unmask End of Frame interrupt */ 190 + writel(0xffffffff ^ (1 << 3), fbi->regbase + 0x3c); 191 + ret = wait_event_interruptible_timeout(fbi->wait, 192 + readl(fbi->regbase + 0x38) & (1 << 3), HZ / 10); 193 + /* Mask back to reduce unwanted interrupt traffic */ 194 + writel(0xffffffff, fbi->regbase + 0x3c); 195 + if (ret < 0) 196 + return ret; 197 + if (ret == 0) 198 + return -ETIMEDOUT; 199 + } 200 + 201 + return ret; 202 + } 203 + 204 + static int vt8500lcd_pan_display(struct fb_var_screeninfo *var, 205 + struct fb_info *info) 206 + { 207 + unsigned pixlen = info->fix.line_length / info->var.xres_virtual; 208 + unsigned off = pixlen * var->xoffset 209 + + info->fix.line_length * var->yoffset; 210 + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); 211 + 212 + writel((1 << 31) 213 + | (((var->xres_virtual - var->xres) * pixlen / 4) << 20) 214 + | (off >> 2), fbi->regbase + 0x20); 215 + return 0; 216 + } 217 + 218 + static struct fb_ops vt8500lcd_ops = { 219 + .owner = THIS_MODULE, 220 + .fb_set_par = vt8500lcd_set_par, 221 + .fb_setcolreg = vt8500lcd_setcolreg, 222 + .fb_fillrect = wmt_ge_fillrect, 223 + .fb_copyarea = wmt_ge_copyarea, 224 + .fb_imageblit = sys_imageblit, 225 + .fb_sync = wmt_ge_sync, 226 + .fb_ioctl = vt8500lcd_ioctl, 227 + .fb_pan_display = vt8500lcd_pan_display, 228 + }; 229 + 230 + static irqreturn_t vt8500lcd_handle_irq(int irq, void *dev_id) 231 + { 232 + struct vt8500lcd_info *fbi = dev_id; 233 + 234 + if (readl(fbi->regbase + 0x38) & (1 << 3)) 235 + wake_up_interruptible(&fbi->wait); 236 + 237 + writel(0xffffffff, fbi->regbase + 0x38); 238 + return IRQ_HANDLED; 239 + } 240 + 241 + static int __devinit vt8500lcd_probe(struct platform_device *pdev) 242 + { 243 + struct vt8500lcd_info *fbi; 244 + struct resource *res; 245 + struct vt8500fb_platform_data *pdata = pdev->dev.platform_data; 246 + void *addr; 247 + int irq, ret; 248 + 249 + ret = -ENOMEM; 250 + fbi = NULL; 251 + 252 + fbi = kzalloc(sizeof(struct vt8500lcd_info) + sizeof(u32) * 16, 253 + GFP_KERNEL); 254 + if (!fbi) { 255 + dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); 256 + ret = -ENOMEM; 257 + goto failed; 258 + } 259 + 260 + strcpy(fbi->fb.fix.id, "VT8500 LCD"); 261 + 262 + fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; 263 + fbi->fb.fix.xpanstep = 0; 264 + fbi->fb.fix.ypanstep = 1; 265 + fbi->fb.fix.ywrapstep = 0; 266 + fbi->fb.fix.accel = FB_ACCEL_NONE; 267 + 268 + fbi->fb.var.nonstd = 0; 269 + fbi->fb.var.activate = FB_ACTIVATE_NOW; 270 + fbi->fb.var.height = -1; 271 + fbi->fb.var.width = -1; 272 + fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; 273 + 274 + fbi->fb.fbops = &vt8500lcd_ops; 275 + fbi->fb.flags = FBINFO_DEFAULT 276 + | FBINFO_HWACCEL_COPYAREA 277 + | FBINFO_HWACCEL_FILLRECT 278 + | FBINFO_HWACCEL_YPAN 279 + | FBINFO_VIRTFB 280 + | FBINFO_PARTIAL_PAN_OK; 281 + fbi->fb.node = -1; 282 + 283 + addr = fbi; 284 + addr = addr + sizeof(struct vt8500lcd_info); 285 + fbi->fb.pseudo_palette = addr; 286 + 287 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 288 + if (res == NULL) { 289 + dev_err(&pdev->dev, "no I/O memory resource defined\n"); 290 + ret = -ENODEV; 291 + goto failed_fbi; 292 + } 293 + 294 + res = request_mem_region(res->start, resource_size(res), "vt8500lcd"); 295 + if (res == NULL) { 296 + dev_err(&pdev->dev, "failed to request I/O memory\n"); 297 + ret = -EBUSY; 298 + goto failed_fbi; 299 + } 300 + 301 + fbi->regbase = ioremap(res->start, resource_size(res)); 302 + if (fbi->regbase == NULL) { 303 + dev_err(&pdev->dev, "failed to map I/O memory\n"); 304 + ret = -EBUSY; 305 + goto failed_free_res; 306 + } 307 + 308 + fbi->fb.fix.smem_start = pdata->video_mem_phys; 309 + fbi->fb.fix.smem_len = pdata->video_mem_len; 310 + fbi->fb.screen_base = pdata->video_mem_virt; 311 + 312 + fbi->palette_size = PAGE_ALIGN(512); 313 + fbi->palette_cpu = dma_alloc_coherent(&pdev->dev, 314 + fbi->palette_size, 315 + &fbi->palette_phys, 316 + GFP_KERNEL); 317 + if (fbi->palette_cpu == NULL) { 318 + dev_err(&pdev->dev, "Failed to allocate palette buffer\n"); 319 + ret = -ENOMEM; 320 + goto failed_free_io; 321 + } 322 + 323 + irq = platform_get_irq(pdev, 0); 324 + if (irq < 0) { 325 + dev_err(&pdev->dev, "no IRQ defined\n"); 326 + ret = -ENODEV; 327 + goto failed_free_palette; 328 + } 329 + 330 + ret = request_irq(irq, vt8500lcd_handle_irq, IRQF_DISABLED, "LCD", fbi); 331 + if (ret) { 332 + dev_err(&pdev->dev, "request_irq failed: %d\n", ret); 333 + ret = -EBUSY; 334 + goto failed_free_palette; 335 + } 336 + 337 + init_waitqueue_head(&fbi->wait); 338 + 339 + if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { 340 + dev_err(&pdev->dev, "Failed to allocate color map\n"); 341 + ret = -ENOMEM; 342 + goto failed_free_irq; 343 + } 344 + 345 + fb_videomode_to_var(&fbi->fb.var, &pdata->mode); 346 + fbi->fb.var.bits_per_pixel = pdata->bpp; 347 + fbi->fb.var.xres_virtual = pdata->xres_virtual; 348 + fbi->fb.var.yres_virtual = pdata->yres_virtual; 349 + 350 + ret = vt8500lcd_set_par(&fbi->fb); 351 + if (ret) { 352 + dev_err(&pdev->dev, "Failed to set parameters\n"); 353 + goto failed_free_cmap; 354 + } 355 + 356 + writel(fbi->fb.fix.smem_start >> 22, fbi->regbase + 0x1c); 357 + writel((fbi->palette_phys & 0xfffffe00) | 1, fbi->regbase + 0x18); 358 + 359 + platform_set_drvdata(pdev, fbi); 360 + 361 + ret = register_framebuffer(&fbi->fb); 362 + if (ret < 0) { 363 + dev_err(&pdev->dev, 364 + "Failed to register framebuffer device: %d\n", ret); 365 + goto failed_free_cmap; 366 + } 367 + 368 + /* 369 + * Ok, now enable the LCD controller 370 + */ 371 + writel(readl(fbi->regbase) | 1, fbi->regbase); 372 + 373 + return 0; 374 + 375 + failed_free_cmap: 376 + if (fbi->fb.cmap.len) 377 + fb_dealloc_cmap(&fbi->fb.cmap); 378 + failed_free_irq: 379 + free_irq(irq, fbi); 380 + failed_free_palette: 381 + dma_free_coherent(&pdev->dev, fbi->palette_size, 382 + fbi->palette_cpu, fbi->palette_phys); 383 + failed_free_io: 384 + iounmap(fbi->regbase); 385 + failed_free_res: 386 + release_mem_region(res->start, resource_size(res)); 387 + failed_fbi: 388 + platform_set_drvdata(pdev, NULL); 389 + kfree(fbi); 390 + failed: 391 + return ret; 392 + } 393 + 394 + static int __devexit vt8500lcd_remove(struct platform_device *pdev) 395 + { 396 + struct vt8500lcd_info *fbi = platform_get_drvdata(pdev); 397 + struct resource *res; 398 + int irq; 399 + 400 + unregister_framebuffer(&fbi->fb); 401 + 402 + writel(0, fbi->regbase); 403 + 404 + if (fbi->fb.cmap.len) 405 + fb_dealloc_cmap(&fbi->fb.cmap); 406 + 407 + irq = platform_get_irq(pdev, 0); 408 + free_irq(irq, fbi); 409 + 410 + dma_free_coherent(&pdev->dev, fbi->palette_size, 411 + fbi->palette_cpu, fbi->palette_phys); 412 + 413 + iounmap(fbi->regbase); 414 + 415 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 416 + release_mem_region(res->start, resource_size(res)); 417 + 418 + kfree(fbi); 419 + 420 + return 0; 421 + } 422 + 423 + static struct platform_driver vt8500lcd_driver = { 424 + .probe = vt8500lcd_probe, 425 + .remove = __devexit_p(vt8500lcd_remove), 426 + .driver = { 427 + .owner = THIS_MODULE, 428 + .name = "vt8500-lcd", 429 + }, 430 + }; 431 + 432 + static int __init vt8500lcd_init(void) 433 + { 434 + return platform_driver_register(&vt8500lcd_driver); 435 + } 436 + 437 + static void __exit vt8500lcd_exit(void) 438 + { 439 + platform_driver_unregister(&vt8500lcd_driver); 440 + } 441 + 442 + module_init(vt8500lcd_init); 443 + module_exit(vt8500lcd_exit); 444 + 445 + MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); 446 + MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); 447 + MODULE_LICENSE("GPL");
+34
drivers/video/vt8500lcdfb.h
··· 1 + /* 2 + * linux/drivers/video/vt8500lcdfb.h 3 + * 4 + * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> 5 + * 6 + * This software is licensed under the terms of the GNU General Public 7 + * License version 2, as published by the Free Software Foundation, and 8 + * may be copied, distributed, and modified under those terms. 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 + struct vt8500lcd_info { 17 + struct fb_info fb; 18 + void __iomem *regbase; 19 + void __iomem *palette_cpu; 20 + dma_addr_t palette_phys; 21 + size_t palette_size; 22 + wait_queue_head_t wait; 23 + }; 24 + 25 + static int bpp_values[] = { 26 + 1, 27 + 2, 28 + 4, 29 + 8, 30 + 12, 31 + 16, 32 + 18, 33 + 24, 34 + };
+422
drivers/video/wm8505fb.c
··· 1 + /* 2 + * WonderMedia WM8505 Frame Buffer device driver 3 + * 4 + * Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com> 5 + * Based on vt8500lcdfb.c 6 + * 7 + * This software is licensed under the terms of the GNU General Public 8 + * License version 2, as published by the Free Software Foundation, and 9 + * may be copied, distributed, and modified under those terms. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #include <linux/module.h> 18 + #include <linux/kernel.h> 19 + #include <linux/errno.h> 20 + #include <linux/string.h> 21 + #include <linux/mm.h> 22 + #include <linux/slab.h> 23 + #include <linux/delay.h> 24 + #include <linux/fb.h> 25 + #include <linux/init.h> 26 + #include <linux/interrupt.h> 27 + #include <linux/io.h> 28 + #include <linux/dma-mapping.h> 29 + #include <linux/platform_device.h> 30 + #include <linux/wait.h> 31 + 32 + #include <mach/vt8500fb.h> 33 + 34 + #include "wm8505fb_regs.h" 35 + #include "wmt_ge_rops.h" 36 + 37 + #define DRIVER_NAME "wm8505-fb" 38 + 39 + #define to_wm8505fb_info(__info) container_of(__info, \ 40 + struct wm8505fb_info, fb) 41 + struct wm8505fb_info { 42 + struct fb_info fb; 43 + void __iomem *regbase; 44 + unsigned int contrast; 45 + }; 46 + 47 + 48 + static int wm8505fb_init_hw(struct fb_info *info) 49 + { 50 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 51 + 52 + int i; 53 + 54 + /* I know the purpose only of few registers, so clear unknown */ 55 + for (i = 0; i < 0x200; i += 4) 56 + writel(0, fbi->regbase + i); 57 + 58 + /* Set frame buffer address */ 59 + writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR); 60 + writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR1); 61 + 62 + /* Set in-memory picture format to RGB 32bpp */ 63 + writel(0x1c, fbi->regbase + WMT_GOVR_COLORSPACE); 64 + writel(1, fbi->regbase + WMT_GOVR_COLORSPACE1); 65 + 66 + /* Virtual buffer size */ 67 + writel(info->var.xres, fbi->regbase + WMT_GOVR_XRES); 68 + writel(info->var.xres_virtual, fbi->regbase + WMT_GOVR_XRES_VIRTUAL); 69 + 70 + /* black magic ;) */ 71 + writel(0xf, fbi->regbase + WMT_GOVR_FHI); 72 + writel(4, fbi->regbase + WMT_GOVR_DVO_SET); 73 + writel(1, fbi->regbase + WMT_GOVR_MIF_ENABLE); 74 + writel(1, fbi->regbase + WMT_GOVR_REG_UPDATE); 75 + 76 + return 0; 77 + } 78 + 79 + static int wm8505fb_set_timing(struct fb_info *info) 80 + { 81 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 82 + 83 + int h_start = info->var.left_margin; 84 + int h_end = h_start + info->var.xres; 85 + int h_all = h_end + info->var.right_margin; 86 + int h_sync = info->var.hsync_len; 87 + 88 + int v_start = info->var.upper_margin; 89 + int v_end = v_start + info->var.yres; 90 + int v_all = v_end + info->var.lower_margin; 91 + int v_sync = info->var.vsync_len + 1; 92 + 93 + writel(0, fbi->regbase + WMT_GOVR_TG); 94 + 95 + writel(h_start, fbi->regbase + WMT_GOVR_TIMING_H_START); 96 + writel(h_end, fbi->regbase + WMT_GOVR_TIMING_H_END); 97 + writel(h_all, fbi->regbase + WMT_GOVR_TIMING_H_ALL); 98 + writel(h_sync, fbi->regbase + WMT_GOVR_TIMING_H_SYNC); 99 + 100 + writel(v_start, fbi->regbase + WMT_GOVR_TIMING_V_START); 101 + writel(v_end, fbi->regbase + WMT_GOVR_TIMING_V_END); 102 + writel(v_all, fbi->regbase + WMT_GOVR_TIMING_V_ALL); 103 + writel(v_sync, fbi->regbase + WMT_GOVR_TIMING_V_SYNC); 104 + 105 + writel(1, fbi->regbase + WMT_GOVR_TG); 106 + 107 + return 0; 108 + } 109 + 110 + 111 + static int wm8505fb_set_par(struct fb_info *info) 112 + { 113 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 114 + 115 + if (!fbi) 116 + return -EINVAL; 117 + 118 + if (info->var.bits_per_pixel == 32) { 119 + info->var.red.offset = 16; 120 + info->var.red.length = 8; 121 + info->var.red.msb_right = 0; 122 + info->var.green.offset = 8; 123 + info->var.green.length = 8; 124 + info->var.green.msb_right = 0; 125 + info->var.blue.offset = 0; 126 + info->var.blue.length = 8; 127 + info->var.blue.msb_right = 0; 128 + info->fix.visual = FB_VISUAL_TRUECOLOR; 129 + info->fix.line_length = info->var.xres_virtual << 2; 130 + } 131 + 132 + wm8505fb_set_timing(info); 133 + 134 + writel(fbi->contrast<<16 | fbi->contrast<<8 | fbi->contrast, 135 + fbi->regbase + WMT_GOVR_CONTRAST); 136 + 137 + return 0; 138 + } 139 + 140 + static ssize_t contrast_show(struct device *dev, 141 + struct device_attribute *attr, char *buf) 142 + { 143 + struct fb_info *info = dev_get_drvdata(dev); 144 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 145 + 146 + return sprintf(buf, "%d\n", fbi->contrast); 147 + } 148 + 149 + static ssize_t contrast_store(struct device *dev, 150 + struct device_attribute *attr, 151 + const char *buf, size_t count) 152 + { 153 + struct fb_info *info = dev_get_drvdata(dev); 154 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 155 + unsigned long tmp; 156 + 157 + if (strict_strtoul(buf, 10, &tmp) || (tmp > 0xff)) 158 + return -EINVAL; 159 + fbi->contrast = tmp; 160 + 161 + wm8505fb_set_par(info); 162 + 163 + return count; 164 + } 165 + 166 + static DEVICE_ATTR(contrast, 0644, contrast_show, contrast_store); 167 + 168 + static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) 169 + { 170 + chan &= 0xffff; 171 + chan >>= 16 - bf->length; 172 + return chan << bf->offset; 173 + } 174 + 175 + static int wm8505fb_setcolreg(unsigned regno, unsigned red, unsigned green, 176 + unsigned blue, unsigned transp, 177 + struct fb_info *info) { 178 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 179 + int ret = 1; 180 + unsigned int val; 181 + if (regno >= 256) 182 + return -EINVAL; 183 + 184 + if (info->var.grayscale) 185 + red = green = blue = 186 + (19595 * red + 38470 * green + 7471 * blue) >> 16; 187 + 188 + switch (fbi->fb.fix.visual) { 189 + case FB_VISUAL_TRUECOLOR: 190 + if (regno < 16) { 191 + u32 *pal = info->pseudo_palette; 192 + 193 + val = chan_to_field(red, &fbi->fb.var.red); 194 + val |= chan_to_field(green, &fbi->fb.var.green); 195 + val |= chan_to_field(blue, &fbi->fb.var.blue); 196 + 197 + pal[regno] = val; 198 + ret = 0; 199 + } 200 + break; 201 + } 202 + 203 + return ret; 204 + } 205 + 206 + static int wm8505fb_pan_display(struct fb_var_screeninfo *var, 207 + struct fb_info *info) 208 + { 209 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 210 + 211 + writel(var->xoffset, fbi->regbase + WMT_GOVR_XPAN); 212 + writel(var->yoffset, fbi->regbase + WMT_GOVR_YPAN); 213 + return 0; 214 + } 215 + 216 + static int wm8505fb_blank(int blank, struct fb_info *info) 217 + { 218 + struct wm8505fb_info *fbi = to_wm8505fb_info(info); 219 + 220 + switch (blank) { 221 + case FB_BLANK_UNBLANK: 222 + wm8505fb_set_timing(info); 223 + break; 224 + default: 225 + writel(0, fbi->regbase + WMT_GOVR_TIMING_V_SYNC); 226 + break; 227 + } 228 + 229 + return 0; 230 + } 231 + 232 + static struct fb_ops wm8505fb_ops = { 233 + .owner = THIS_MODULE, 234 + .fb_set_par = wm8505fb_set_par, 235 + .fb_setcolreg = wm8505fb_setcolreg, 236 + .fb_fillrect = wmt_ge_fillrect, 237 + .fb_copyarea = wmt_ge_copyarea, 238 + .fb_imageblit = sys_imageblit, 239 + .fb_sync = wmt_ge_sync, 240 + .fb_pan_display = wm8505fb_pan_display, 241 + .fb_blank = wm8505fb_blank, 242 + }; 243 + 244 + static int __devinit wm8505fb_probe(struct platform_device *pdev) 245 + { 246 + struct wm8505fb_info *fbi; 247 + struct resource *res; 248 + void *addr; 249 + struct vt8500fb_platform_data *pdata; 250 + int ret; 251 + 252 + pdata = pdev->dev.platform_data; 253 + 254 + ret = -ENOMEM; 255 + fbi = NULL; 256 + 257 + fbi = kzalloc(sizeof(struct wm8505fb_info) + sizeof(u32) * 16, 258 + GFP_KERNEL); 259 + if (!fbi) { 260 + dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); 261 + ret = -ENOMEM; 262 + goto failed; 263 + } 264 + 265 + strcpy(fbi->fb.fix.id, DRIVER_NAME); 266 + 267 + fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; 268 + fbi->fb.fix.xpanstep = 1; 269 + fbi->fb.fix.ypanstep = 1; 270 + fbi->fb.fix.ywrapstep = 0; 271 + fbi->fb.fix.accel = FB_ACCEL_NONE; 272 + 273 + fbi->fb.fbops = &wm8505fb_ops; 274 + fbi->fb.flags = FBINFO_DEFAULT 275 + | FBINFO_HWACCEL_COPYAREA 276 + | FBINFO_HWACCEL_FILLRECT 277 + | FBINFO_HWACCEL_XPAN 278 + | FBINFO_HWACCEL_YPAN 279 + | FBINFO_VIRTFB 280 + | FBINFO_PARTIAL_PAN_OK; 281 + fbi->fb.node = -1; 282 + 283 + addr = fbi; 284 + addr = addr + sizeof(struct wm8505fb_info); 285 + fbi->fb.pseudo_palette = addr; 286 + 287 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 288 + if (res == NULL) { 289 + dev_err(&pdev->dev, "no I/O memory resource defined\n"); 290 + ret = -ENODEV; 291 + goto failed_fbi; 292 + } 293 + 294 + res = request_mem_region(res->start, resource_size(res), "wm8505fb"); 295 + if (res == NULL) { 296 + dev_err(&pdev->dev, "failed to request I/O memory\n"); 297 + ret = -EBUSY; 298 + goto failed_fbi; 299 + } 300 + 301 + fbi->regbase = ioremap(res->start, resource_size(res)); 302 + if (fbi->regbase == NULL) { 303 + dev_err(&pdev->dev, "failed to map I/O memory\n"); 304 + ret = -EBUSY; 305 + goto failed_free_res; 306 + } 307 + 308 + fb_videomode_to_var(&fbi->fb.var, &pdata->mode); 309 + 310 + fbi->fb.var.nonstd = 0; 311 + fbi->fb.var.activate = FB_ACTIVATE_NOW; 312 + 313 + fbi->fb.var.height = -1; 314 + fbi->fb.var.width = -1; 315 + fbi->fb.var.xres_virtual = pdata->xres_virtual; 316 + fbi->fb.var.yres_virtual = pdata->yres_virtual; 317 + fbi->fb.var.bits_per_pixel = pdata->bpp; 318 + 319 + fbi->fb.fix.smem_start = pdata->video_mem_phys; 320 + fbi->fb.fix.smem_len = pdata->video_mem_len; 321 + fbi->fb.screen_base = pdata->video_mem_virt; 322 + fbi->fb.screen_size = pdata->video_mem_len; 323 + 324 + if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { 325 + dev_err(&pdev->dev, "Failed to allocate color map\n"); 326 + ret = -ENOMEM; 327 + goto failed_free_io; 328 + } 329 + 330 + wm8505fb_init_hw(&fbi->fb); 331 + 332 + fbi->contrast = 0x80; 333 + ret = wm8505fb_set_par(&fbi->fb); 334 + if (ret) { 335 + dev_err(&pdev->dev, "Failed to set parameters\n"); 336 + goto failed_free_cmap; 337 + } 338 + 339 + platform_set_drvdata(pdev, fbi); 340 + 341 + ret = register_framebuffer(&fbi->fb); 342 + if (ret < 0) { 343 + dev_err(&pdev->dev, 344 + "Failed to register framebuffer device: %d\n", ret); 345 + goto failed_free_cmap; 346 + } 347 + 348 + ret = device_create_file(&pdev->dev, &dev_attr_contrast); 349 + if (ret < 0) { 350 + printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n", 351 + fbi->fb.node, ret); 352 + } 353 + 354 + printk(KERN_INFO "fb%d: %s frame buffer at 0x%lx-0x%lx\n", 355 + fbi->fb.node, fbi->fb.fix.id, fbi->fb.fix.smem_start, 356 + fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1); 357 + 358 + return 0; 359 + 360 + failed_free_cmap: 361 + if (fbi->fb.cmap.len) 362 + fb_dealloc_cmap(&fbi->fb.cmap); 363 + failed_free_io: 364 + iounmap(fbi->regbase); 365 + failed_free_res: 366 + release_mem_region(res->start, resource_size(res)); 367 + failed_fbi: 368 + platform_set_drvdata(pdev, NULL); 369 + kfree(fbi); 370 + failed: 371 + return ret; 372 + } 373 + 374 + static int __devexit wm8505fb_remove(struct platform_device *pdev) 375 + { 376 + struct wm8505fb_info *fbi = platform_get_drvdata(pdev); 377 + struct resource *res; 378 + 379 + device_remove_file(&pdev->dev, &dev_attr_contrast); 380 + 381 + unregister_framebuffer(&fbi->fb); 382 + 383 + writel(0, fbi->regbase); 384 + 385 + if (fbi->fb.cmap.len) 386 + fb_dealloc_cmap(&fbi->fb.cmap); 387 + 388 + iounmap(fbi->regbase); 389 + 390 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 391 + release_mem_region(res->start, resource_size(res)); 392 + 393 + kfree(fbi); 394 + 395 + return 0; 396 + } 397 + 398 + static struct platform_driver wm8505fb_driver = { 399 + .probe = wm8505fb_probe, 400 + .remove = __devexit_p(wm8505fb_remove), 401 + .driver = { 402 + .owner = THIS_MODULE, 403 + .name = DRIVER_NAME, 404 + }, 405 + }; 406 + 407 + static int __init wm8505fb_init(void) 408 + { 409 + return platform_driver_register(&wm8505fb_driver); 410 + } 411 + 412 + static void __exit wm8505fb_exit(void) 413 + { 414 + platform_driver_unregister(&wm8505fb_driver); 415 + } 416 + 417 + module_init(wm8505fb_init); 418 + module_exit(wm8505fb_exit); 419 + 420 + MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); 421 + MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); 422 + MODULE_LICENSE("GPL");
+76
drivers/video/wm8505fb_regs.h
··· 1 + /* 2 + * GOVR registers list for WM8505 chips 3 + * 4 + * Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com> 5 + * Based on VIA/WonderMedia wm8510-govrh-reg.h 6 + * http://github.com/projectgus/kernel_wm8505/blob/wm8505_2.6.29/ 7 + * drivers/video/wmt/register/wm8510/wm8510-govrh-reg.h 8 + * 9 + * This software is licensed under the terms of the GNU General Public 10 + * License version 2, as published by the Free Software Foundation, and 11 + * may be copied, distributed, and modified under those terms. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + */ 18 + 19 + #ifndef _WM8505FB_REGS_H 20 + #define _WM8505FB_REGS_H 21 + 22 + /* 23 + * Color space select register, default value 0x1c 24 + * BIT0 GOVRH_DVO_YUV2RGB_ENABLE 25 + * BIT1 GOVRH_VGA_YUV2RGB_ENABLE 26 + * BIT2 GOVRH_RGB_MODE 27 + * BIT3 GOVRH_DAC_CLKINV 28 + * BIT4 GOVRH_BLANK_ZERO 29 + */ 30 + #define WMT_GOVR_COLORSPACE 0x1e4 31 + /* 32 + * Another colorspace select register, default value 1 33 + * BIT0 GOVRH_DVO_RGB 34 + * BIT1 GOVRH_DVO_YUV422 35 + */ 36 + #define WMT_GOVR_COLORSPACE1 0x30 37 + 38 + #define WMT_GOVR_CONTRAST 0x1b8 39 + #define WMT_GOVR_BRGHTNESS 0x1bc /* incompatible with RGB? */ 40 + 41 + /* Framubeffer address */ 42 + #define WMT_GOVR_FBADDR 0x90 43 + #define WMT_GOVR_FBADDR1 0x94 /* UV offset in YUV mode */ 44 + 45 + /* Offset of visible window */ 46 + #define WMT_GOVR_XPAN 0xa4 47 + #define WMT_GOVR_YPAN 0xa0 48 + 49 + #define WMT_GOVR_XRES 0x98 50 + #define WMT_GOVR_XRES_VIRTUAL 0x9c 51 + 52 + #define WMT_GOVR_MIF_ENABLE 0x80 53 + #define WMT_GOVR_FHI 0xa8 54 + #define WMT_GOVR_REG_UPDATE 0xe4 55 + 56 + /* 57 + * BIT0 GOVRH_DVO_OUTWIDTH 58 + * BIT1 GOVRH_DVO_SYNC_POLAR 59 + * BIT2 GOVRH_DVO_ENABLE 60 + */ 61 + #define WMT_GOVR_DVO_SET 0x148 62 + 63 + /* Timing generator? */ 64 + #define WMT_GOVR_TG 0x100 65 + 66 + /* Timings */ 67 + #define WMT_GOVR_TIMING_H_ALL 0x108 68 + #define WMT_GOVR_TIMING_V_ALL 0x10c 69 + #define WMT_GOVR_TIMING_V_START 0x110 70 + #define WMT_GOVR_TIMING_V_END 0x114 71 + #define WMT_GOVR_TIMING_H_START 0x118 72 + #define WMT_GOVR_TIMING_H_END 0x11c 73 + #define WMT_GOVR_TIMING_V_SYNC 0x128 74 + #define WMT_GOVR_TIMING_H_SYNC 0x12c 75 + 76 + #endif /* _WM8505FB_REGS_H */
+192
drivers/video/wmt_ge_rops.c
··· 1 + /* 2 + * linux/drivers/video/wmt_ge_rops.c 3 + * 4 + * Accelerators for raster operations using WonderMedia Graphics Engine 5 + * 6 + * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> 7 + * 8 + * This software is licensed under the terms of the GNU General Public 9 + * License version 2, as published by the Free Software Foundation, and 10 + * may be copied, distributed, and modified under those terms. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/fb.h> 20 + #include <linux/platform_device.h> 21 + #include "fb_draw.h" 22 + 23 + #define GE_COMMAND_OFF 0x00 24 + #define GE_DEPTH_OFF 0x04 25 + #define GE_HIGHCOLOR_OFF 0x08 26 + #define GE_ROPCODE_OFF 0x14 27 + #define GE_FIRE_OFF 0x18 28 + #define GE_SRCBASE_OFF 0x20 29 + #define GE_SRCDISPW_OFF 0x24 30 + #define GE_SRCDISPH_OFF 0x28 31 + #define GE_SRCAREAX_OFF 0x2c 32 + #define GE_SRCAREAY_OFF 0x30 33 + #define GE_SRCAREAW_OFF 0x34 34 + #define GE_SRCAREAH_OFF 0x38 35 + #define GE_DESTBASE_OFF 0x3c 36 + #define GE_DESTDISPW_OFF 0x40 37 + #define GE_DESTDISPH_OFF 0x44 38 + #define GE_DESTAREAX_OFF 0x48 39 + #define GE_DESTAREAY_OFF 0x4c 40 + #define GE_DESTAREAW_OFF 0x50 41 + #define GE_DESTAREAH_OFF 0x54 42 + #define GE_PAT0C_OFF 0x88 /* Pattern 0 color */ 43 + #define GE_ENABLE_OFF 0xec 44 + #define GE_INTEN_OFF 0xf0 45 + #define GE_STATUS_OFF 0xf8 46 + 47 + static void __iomem *regbase; 48 + 49 + void wmt_ge_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 50 + { 51 + unsigned long fg, pat; 52 + 53 + if (p->state != FBINFO_STATE_RUNNING) 54 + return; 55 + 56 + if (p->fix.visual == FB_VISUAL_TRUECOLOR || 57 + p->fix.visual == FB_VISUAL_DIRECTCOLOR) 58 + fg = ((u32 *) (p->pseudo_palette))[rect->color]; 59 + else 60 + fg = rect->color; 61 + 62 + pat = pixel_to_pat(p->var.bits_per_pixel, fg); 63 + 64 + if (p->fbops->fb_sync) 65 + p->fbops->fb_sync(p); 66 + 67 + writel(p->var.bits_per_pixel == 32 ? 3 : 68 + (p->var.bits_per_pixel == 8 ? 0 : 1), regbase + GE_DEPTH_OFF); 69 + writel(p->var.bits_per_pixel == 15 ? 1 : 0, regbase + GE_HIGHCOLOR_OFF); 70 + writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF); 71 + writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF); 72 + writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF); 73 + writel(rect->dx, regbase + GE_DESTAREAX_OFF); 74 + writel(rect->dy, regbase + GE_DESTAREAY_OFF); 75 + writel(rect->width - 1, regbase + GE_DESTAREAW_OFF); 76 + writel(rect->height - 1, regbase + GE_DESTAREAH_OFF); 77 + 78 + writel(pat, regbase + GE_PAT0C_OFF); 79 + writel(1, regbase + GE_COMMAND_OFF); 80 + writel(rect->rop == ROP_XOR ? 0x5a : 0xf0, regbase + GE_ROPCODE_OFF); 81 + writel(1, regbase + GE_FIRE_OFF); 82 + } 83 + EXPORT_SYMBOL_GPL(wmt_ge_fillrect); 84 + 85 + void wmt_ge_copyarea(struct fb_info *p, const struct fb_copyarea *area) 86 + { 87 + if (p->state != FBINFO_STATE_RUNNING) 88 + return; 89 + 90 + if (p->fbops->fb_sync) 91 + p->fbops->fb_sync(p); 92 + 93 + writel(p->var.bits_per_pixel > 16 ? 3 : 94 + (p->var.bits_per_pixel > 8 ? 1 : 0), regbase + GE_DEPTH_OFF); 95 + 96 + writel(p->fix.smem_start, regbase + GE_SRCBASE_OFF); 97 + writel(p->var.xres_virtual - 1, regbase + GE_SRCDISPW_OFF); 98 + writel(p->var.yres_virtual - 1, regbase + GE_SRCDISPH_OFF); 99 + writel(area->sx, regbase + GE_SRCAREAX_OFF); 100 + writel(area->sy, regbase + GE_SRCAREAY_OFF); 101 + writel(area->width - 1, regbase + GE_SRCAREAW_OFF); 102 + writel(area->height - 1, regbase + GE_SRCAREAH_OFF); 103 + 104 + writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF); 105 + writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF); 106 + writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF); 107 + writel(area->dx, regbase + GE_DESTAREAX_OFF); 108 + writel(area->dy, regbase + GE_DESTAREAY_OFF); 109 + writel(area->width - 1, regbase + GE_DESTAREAW_OFF); 110 + writel(area->height - 1, regbase + GE_DESTAREAH_OFF); 111 + 112 + writel(0xcc, regbase + GE_ROPCODE_OFF); 113 + writel(1, regbase + GE_COMMAND_OFF); 114 + writel(1, regbase + GE_FIRE_OFF); 115 + } 116 + EXPORT_SYMBOL_GPL(wmt_ge_copyarea); 117 + 118 + int wmt_ge_sync(struct fb_info *p) 119 + { 120 + int loops = 5000000; 121 + while ((readl(regbase + GE_STATUS_OFF) & 4) && --loops) 122 + cpu_relax(); 123 + return loops > 0 ? 0 : -EBUSY; 124 + } 125 + EXPORT_SYMBOL_GPL(wmt_ge_sync); 126 + 127 + static int __devinit wmt_ge_rops_probe(struct platform_device *pdev) 128 + { 129 + struct resource *res; 130 + int ret; 131 + 132 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 133 + if (res == NULL) { 134 + dev_err(&pdev->dev, "no I/O memory resource defined\n"); 135 + ret = -ENODEV; 136 + goto error; 137 + } 138 + 139 + /* Only one ROP engine is presently supported. */ 140 + if (unlikely(regbase)) { 141 + WARN_ON(1); 142 + return -EBUSY; 143 + } 144 + 145 + regbase = ioremap(res->start, resource_size(res)); 146 + if (regbase == NULL) { 147 + dev_err(&pdev->dev, "failed to map I/O memory\n"); 148 + ret = -EBUSY; 149 + goto error; 150 + } 151 + 152 + writel(1, regbase + GE_ENABLE_OFF); 153 + printk(KERN_INFO "Enabled support for WMT GE raster acceleration\n"); 154 + 155 + return 0; 156 + 157 + error: 158 + return ret; 159 + } 160 + 161 + static int __devexit wmt_ge_rops_remove(struct platform_device *pdev) 162 + { 163 + iounmap(regbase); 164 + return 0; 165 + } 166 + 167 + static struct platform_driver wmt_ge_rops_driver = { 168 + .probe = wmt_ge_rops_probe, 169 + .remove = __devexit_p(wmt_ge_rops_remove), 170 + .driver = { 171 + .owner = THIS_MODULE, 172 + .name = "wmt_ge_rops", 173 + }, 174 + }; 175 + 176 + static int __init wmt_ge_rops_init(void) 177 + { 178 + return platform_driver_register(&wmt_ge_rops_driver); 179 + } 180 + 181 + static void __exit wmt_ge_rops_exit(void) 182 + { 183 + platform_driver_unregister(&wmt_ge_rops_driver); 184 + } 185 + 186 + module_init(wmt_ge_rops_init); 187 + module_exit(wmt_ge_rops_exit); 188 + 189 + MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); 190 + MODULE_DESCRIPTION("Accelerators for raster operations using " 191 + "WonderMedia Graphics Engine"); 192 + MODULE_LICENSE("GPL");
+5
drivers/video/wmt_ge_rops.h
··· 1 + extern void wmt_ge_fillrect(struct fb_info *info, 2 + const struct fb_fillrect *rect); 3 + extern void wmt_ge_copyarea(struct fb_info *info, 4 + const struct fb_copyarea *area); 5 + extern int wmt_ge_sync(struct fb_info *info);