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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.4-rc1 411 lines 10 kB view raw
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) 41struct wm8505fb_info { 42 struct fb_info fb; 43 void __iomem *regbase; 44 unsigned int contrast; 45}; 46 47 48static 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 79static 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; 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 111static 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 140static 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 149static 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 166static DEVICE_ATTR(contrast, 0644, contrast_show, contrast_store); 167 168static 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 175static 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 206static 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 216static 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 232static 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 244static 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), DRIVER_NAME); 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 360failed_free_cmap: 361 if (fbi->fb.cmap.len) 362 fb_dealloc_cmap(&fbi->fb.cmap); 363failed_free_io: 364 iounmap(fbi->regbase); 365failed_free_res: 366 release_mem_region(res->start, resource_size(res)); 367failed_fbi: 368 platform_set_drvdata(pdev, NULL); 369 kfree(fbi); 370failed: 371 return ret; 372} 373 374static 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 398static 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 407module_platform_driver(wm8505fb_driver); 408 409MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); 410MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); 411MODULE_LICENSE("GPL");