Advertisement
Guest User

Untitled

a guest
Apr 10th, 2012
782
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.42 KB | None | 0 0
  1. /*
  2. * linux/drivers/video/bcm2708_fb.c
  3. *
  4. * Copyright (C) 2010 Broadcom
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file COPYING in the main directory of this archive
  8. * for more details.
  9. *
  10. * Broadcom simple framebuffer driver
  11. *
  12. * This file is derived from cirrusfb.c
  13. * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
  14. *
  15. */
  16. #include <linux/module.h>
  17. #include <linux/kernel.h>
  18. #include <linux/errno.h>
  19. #include <linux/string.h>
  20. #include <linux/slab.h>
  21. #include <linux/delay.h>
  22. #include <linux/mm.h>
  23. #include <linux/fb.h>
  24. #include <linux/init.h>
  25. #include <linux/ioport.h>
  26. #include <linux/list.h>
  27. #include <linux/platform_device.h>
  28. #include <linux/clk.h>
  29.  
  30. #include <mach/dma.h>
  31. #include <mach/platform.h>
  32. #include <mach/vcio.h>
  33.  
  34. #include <asm/sizes.h>
  35. #include <linux/io.h>
  36. #include <linux/dma-mapping.h>
  37.  
  38. /* This is limited to 16 characters when displayed by X startup */
  39. static const char *bcm2708_name = "BCM2708 FB";
  40.  
  41. #define DRIVER_NAME "bcm2708_fb"
  42.  
  43. /* this data structure describes each frame buffer device we find */
  44.  
  45. struct fbinfo_s {
  46. u32 xres, yres, xres_virtual, yres_virtual;
  47. u32 pitch, bpp;
  48. u32 xoffset, yoffset;
  49. u32 base;
  50. u32 screen_size;
  51. };
  52.  
  53. struct bcm2708_fb {
  54. struct fb_info fb;
  55. struct platform_device *dev;
  56. struct fbinfo_s *info;
  57. dma_addr_t dma;
  58. u32 cmap[16];
  59. int dma_chan;
  60. int dma_irq;
  61. void __iomem *dma_chan_base;
  62. void *cb_base; /* DMA control blocks */
  63. dma_addr_t cb_handle;
  64. };
  65.  
  66. #define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
  67.  
  68. static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var)
  69. {
  70. int ret = 0;
  71.  
  72. memset(&var->transp, 0, sizeof(var->transp));
  73.  
  74. var->red.msb_right = 0;
  75. var->green.msb_right = 0;
  76. var->blue.msb_right = 0;
  77.  
  78. switch (var->bits_per_pixel) {
  79. case 1:
  80. case 2:
  81. case 4:
  82. case 8:
  83. var->red.length = var->bits_per_pixel;
  84. var->red.offset = 0;
  85. var->green.length = var->bits_per_pixel;
  86. var->green.offset = 0;
  87. var->blue.length = var->bits_per_pixel;
  88. var->blue.offset = 0;
  89. break;
  90. case 16:
  91. var->red.length = 5;
  92. var->blue.length = 5;
  93. /*
  94. * Green length can be 5 or 6 depending whether
  95. * we're operating in RGB555 or RGB565 mode.
  96. */
  97. if (var->green.length != 5 && var->green.length != 6)
  98. var->green.length = 6;
  99. break;
  100. case 24:
  101. var->red.length = 8;
  102. var->blue.length = 8;
  103. var->green.length = 8;
  104. break;
  105. case 32:
  106. var->red.length = 8;
  107. var->green.length = 8;
  108. var->blue.length = 8;
  109. var->transp.length = 8;
  110. break;
  111. default:
  112. ret = -EINVAL;
  113. break;
  114. }
  115.  
  116. /*
  117. * >= 16bpp displays have separate colour component bitfields
  118. * encoded in the pixel data. Calculate their position from
  119. * the bitfield length defined above.
  120. */
  121. if (ret == 0 && var->bits_per_pixel >= 16) {
  122. var->blue.offset = 0;
  123. var->green.offset = var->blue.offset + var->blue.length;
  124. var->red.offset = var->green.offset + var->green.length;
  125. var->transp.offset = var->red.offset + var->red.length;
  126. }
  127.  
  128. return ret;
  129. }
  130.  
  131. static int bcm2708_fb_check_var(struct fb_var_screeninfo *var,
  132. struct fb_info *info)
  133. {
  134. /* info input, var output */
  135. int yres;
  136. /* memory size in pixels */
  137. unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
  138.  
  139. /* info input, var output */
  140. pr_info("bcm2708_fb_check_var info(%p) %dx%d (%dx%d), %d, %d\n", info,
  141. info->var.xres, info->var.yres, info->var.xres_virtual,
  142. info->var.yres_virtual, (int)info->screen_size,
  143. info->var.bits_per_pixel);
  144. pr_info("bcm2708_fb_check_var var(%p) %dx%d (%dx%d), %d, %d\n", var,
  145. var->xres, var->yres, var->xres_virtual, var->yres_virtual,
  146. var->bits_per_pixel, pixels);
  147.  
  148. if (!var->bits_per_pixel)
  149. var->bits_per_pixel = 16;
  150.  
  151. if (bcm2708_fb_set_bitfields(var) != 0) {
  152. pr_err("bcm2708_fb_check_var: invalid bits_per_pixel %d\n",
  153. var->bits_per_pixel);
  154. return -EINVAL;
  155. }
  156.  
  157. if (var->xres_virtual < var->xres)
  158. var->xres_virtual = var->xres;
  159. /* use highest possible virtual resolution */
  160. if (var->yres_virtual == -1) {
  161. var->yres_virtual = 480;
  162.  
  163. pr_err
  164. ("bcm2708_fb_check_var: virtual resolution set to maximum of %dx%d\n",
  165. var->xres_virtual, var->yres_virtual);
  166. }
  167. if (var->yres_virtual < var->yres)
  168. var->yres_virtual = var->yres;
  169.  
  170. if (var->xoffset < 0)
  171. var->xoffset = 0;
  172. if (var->yoffset < 0)
  173. var->yoffset = 0;
  174.  
  175. /* truncate xoffset and yoffset to maximum if too high */
  176. if (var->xoffset > var->xres_virtual - var->xres)
  177. var->xoffset = var->xres_virtual - var->xres - 1;
  178. if (var->yoffset > var->yres_virtual - var->yres)
  179. var->yoffset = var->yres_virtual - var->yres - 1;
  180.  
  181. yres = var->yres;
  182. if (var->vmode & FB_VMODE_DOUBLE)
  183. yres *= 2;
  184. else if (var->vmode & FB_VMODE_INTERLACED)
  185. yres = (yres + 1) / 2;
  186.  
  187. if (yres > 1200) {
  188. pr_err("bcm2708_fb_check_var: ERROR: VerticalTotal >= 1200; "
  189. "special treatment required! (TODO)\n");
  190. return -EINVAL;
  191. }
  192.  
  193. return 0;
  194. }
  195.  
  196. static int bcm2708_fb_set_par(struct fb_info *info)
  197. {
  198. uint32_t val = 0;
  199. struct bcm2708_fb *fb = to_bcm2708(info);
  200. volatile struct fbinfo_s *fbinfo = fb->info;
  201. fbinfo->xres = info->var.xres;
  202. fbinfo->yres = info->var.yres;
  203. fbinfo->xres_virtual = info->var.xres_virtual;
  204. fbinfo->yres_virtual = info->var.yres_virtual;
  205. fbinfo->bpp = info->var.bits_per_pixel;
  206. fbinfo->xoffset = info->var.xoffset;
  207. fbinfo->yoffset = info->var.yoffset;
  208. fbinfo->base = 0; /* filled in by VC */
  209. fbinfo->pitch = 0; /* filled in by VC */
  210.  
  211. pr_info("bcm2708_fb_set_par info(%p) %dx%d (%dx%d), %d, %d\n", info,
  212. info->var.xres, info->var.yres, info->var.xres_virtual,
  213. info->var.yres_virtual, (int)info->screen_size,
  214. info->var.bits_per_pixel);
  215.  
  216. /* ensure last write to fbinfo is visible to GPU */
  217. wmb();
  218.  
  219. /* inform vc about new framebuffer */
  220. bcm_mailbox_write(MBOX_CHAN_FB, fb->dma);
  221. msleep(10);
  222.  
  223. /* wait for response */
  224. bcm_mailbox_read(MBOX_CHAN_FB, &val);
  225.  
  226. /* ensure GPU writes are visible to us */
  227. rmb();
  228.  
  229. if (val == 0) {
  230. fb->fb.fix.line_length = fbinfo->pitch;
  231.  
  232. if (info->var.bits_per_pixel <= 8)
  233. fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
  234. else
  235. fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  236.  
  237. fb->fb.fix.smem_start = fbinfo->base;
  238. fb->fb.fix.smem_len = fbinfo->pitch * fbinfo->yres_virtual;
  239. fb->fb.screen_size = fbinfo->screen_size;
  240. if (fb->fb.screen_base)
  241. iounmap(fb->fb.screen_base);
  242. fb->fb.screen_base =
  243. (void *)ioremap_wc(fb->fb.fix.smem_start,
  244. fb->fb.screen_size);
  245. if (!fb->fb.screen_base)
  246. BUG(); /* what can we do here */
  247. }
  248. pr_info
  249. ("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d success=%d\n",
  250. (void *)fb->fb.screen_base, (void *)fb->fb.fix.smem_start,
  251. fbinfo->xres, fbinfo->yres, fbinfo->bpp,
  252. fbinfo->pitch, (int)fb->fb.screen_size, val);
  253.  
  254. return val;
  255. }
  256.  
  257. static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
  258. {
  259. unsigned int mask = (1 << bf->length) - 1;
  260.  
  261. return (val >> (16 - bf->length) & mask) << bf->offset;
  262. }
  263.  
  264. static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red,
  265. unsigned int green, unsigned int blue,
  266. unsigned int transp, struct fb_info *info)
  267. {
  268. struct bcm2708_fb *fb = to_bcm2708(info);
  269.  
  270. if (regno < 16)
  271. fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
  272. convert_bitfield(blue, &fb->fb.var.blue) |
  273. convert_bitfield(green, &fb->fb.var.green) |
  274. convert_bitfield(red, &fb->fb.var.red);
  275.  
  276. return regno > 255;
  277. }
  278.  
  279. static int bcm2708_fb_blank(int blank_mode, struct fb_info *info)
  280. {
  281. /*pr_info("bcm2708_fb_blank\n"); */
  282. return -1;
  283. }
  284.  
  285. static void bcm2708_fb_fillrect(struct fb_info *info,
  286. const struct fb_fillrect *rect)
  287. {
  288. struct bcm2708_fb *fb = to_bcm2708(info);
  289. struct bcm2708_dma_cb *cb = (struct bcm2708_dma_cb *)fb->cb_base;
  290. unsigned int *color = (unsigned int *)fb->cb_base + 8;
  291. unsigned int c = rect->color << 16 | rect->color;
  292.  
  293. if (rect->rop != ROP_COPY) {
  294. cfb_fillrect(info, rect);
  295. return;
  296. }
  297.  
  298. cb->info = BCM2708_DMA_BURST(0) |
  299. BCM2708_DMA_S_WIDTH |
  300. BCM2708_DMA_D_WIDTH |
  301. BCM2708_DMA_D_INC | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_TDMODE;
  302.  
  303. cb->dst =
  304. fb->fb.fix.smem_start + 2 * rect->dx +
  305. rect->dy * fb->fb.fix.line_length;
  306. cb->src = fb->cb_handle + 32;
  307. cb->length = BCM2708_DMA_TDMODE_LEN(2 * rect->width, rect->height);
  308. cb->stride = (fb->fb.fix.line_length - 2 * rect->width) << 16;
  309.  
  310. cb->next = 0;
  311. cb->pad[0] = 0;
  312. cb->pad[1] = 0;
  313.  
  314. color[0] = c;
  315. color[1] = c;
  316. color[2] = c;
  317. color[3] = c;
  318. color[4] = c;
  319. color[5] = c;
  320. color[6] = c;
  321. color[7] = c;
  322.  
  323. bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
  324. bcm_dma_wait_idle(fb->dma_chan_base);
  325. }
  326.  
  327. static void bcm2708_fb_copyarea(struct fb_info *info,
  328. const struct fb_copyarea *region)
  329. {
  330. struct bcm2708_fb *fb = to_bcm2708(info);
  331. struct bcm2708_dma_cb *cb = fb->cb_base;
  332. int bytes_per_pixel = (info->var.bits_per_pixel + 7)>>3;
  333.  
  334. cb->info = BCM2708_DMA_BURST(0) |
  335. BCM2708_DMA_S_WIDTH |
  336. BCM2708_DMA_S_INC |
  337. BCM2708_DMA_D_WIDTH |
  338. BCM2708_DMA_D_INC | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_TDMODE;
  339.  
  340. cb->dst =
  341. fb->fb.fix.smem_start + bytes_per_pixel * region->dx +
  342. region->dy * fb->fb.fix.line_length;
  343. cb->src =
  344. fb->fb.fix.smem_start + bytes_per_pixel * region->sx +
  345. region->sy * fb->fb.fix.line_length;
  346. cb->length = BCM2708_DMA_TDMODE_LEN(bytes_per_pixel * region->width, region->height);
  347. cb->stride =
  348. ((fb->fb.fix.line_length -
  349. bytes_per_pixel * region->width) << 16) | (fb->fb.fix.line_length -
  350. bytes_per_pixel * region->width);
  351.  
  352. cb->next = 0;
  353. cb->pad[0] = 0;
  354. cb->pad[1] = 0;
  355.  
  356. bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
  357. bcm_dma_wait_idle(fb->dma_chan_base);
  358. }
  359.  
  360. static void bcm2708_fb_imageblit(struct fb_info *info,
  361. const struct fb_image *image)
  362. {
  363. struct bcm2708_fb *fb = to_bcm2708(info);
  364. struct bcm2708_dma_cb *cb = fb->cb_base;
  365.  
  366. if (image->depth != 16) {
  367. cfb_imageblit(info, image);
  368. return;
  369. }
  370.  
  371. cb->info = BCM2708_DMA_BURST(0) |
  372. BCM2708_DMA_S_WIDTH |
  373. BCM2708_DMA_S_INC |
  374. BCM2708_DMA_D_WIDTH |
  375. BCM2708_DMA_D_INC | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_TDMODE;
  376.  
  377. cb->dst =
  378. fb->fb.fix.smem_start + 2 * image->dx +
  379. image->dy * fb->fb.fix.line_length;
  380. cb->src = (unsigned long)image->data;
  381. cb->length = BCM2708_DMA_TDMODE_LEN(2 * image->width, image->height);
  382. cb->stride =
  383. ((fb->fb.fix.line_length -
  384. 2 * image->width) << 16) | (image->width * 2);
  385.  
  386. cb->next = 0;
  387. cb->pad[0] = 0;
  388. cb->pad[1] = 0;
  389. // flush_kern_dcache_area(image->data, width * height);
  390. bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
  391. bcm_dma_wait_idle(fb->dma_chan_base);
  392. }
  393.  
  394. static void bcm2708_fb_destroy(struct fb_info *info)
  395. {
  396. pr_debug("bcm2708_fb_destroy\n");
  397. }
  398.  
  399. static struct fb_ops bcm2708_fb_ops = {
  400. .owner = THIS_MODULE,
  401. .fb_check_var = bcm2708_fb_check_var,
  402. .fb_set_par = bcm2708_fb_set_par,
  403. .fb_setcolreg = bcm2708_fb_setcolreg,
  404. .fb_blank = bcm2708_fb_blank,
  405. .fb_fillrect = bcm2708_fb_fillrect,
  406. .fb_copyarea = bcm2708_fb_copyarea,
  407. .fb_imageblit = bcm2708_fb_imageblit,
  408. .fb_destroy = bcm2708_fb_destroy,
  409. };
  410.  
  411. static int fbwidth = 800; /* module parameter */
  412. static int fbheight = 480; /* module parameter */
  413.  
  414. static int bcm2708_fb_register(struct bcm2708_fb *fb)
  415. {
  416. int ret;
  417. dma_addr_t dma;
  418. void *mem;
  419.  
  420. mem =
  421. dma_alloc_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), &dma,
  422. GFP_KERNEL);
  423.  
  424. if (NULL == mem) {
  425. pr_err(": unable to allocate fbinfo buffer\n");
  426. ret = -ENOMEM;
  427. } else {
  428. fb->info = (struct fbinfo_s *)mem;
  429. fb->dma = dma;
  430. }
  431. fb->fb.fbops = &bcm2708_fb_ops;
  432. fb->fb.flags =
  433. FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA |
  434. FBINFO_HWACCEL_FILLRECT /* | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST*/;
  435. fb->fb.pseudo_palette = fb->cmap;
  436.  
  437. strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id));
  438. fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
  439. fb->fb.fix.type_aux = 0;
  440. fb->fb.fix.xpanstep = 0;
  441. fb->fb.fix.ypanstep = 0;
  442. fb->fb.fix.ywrapstep = 0;
  443. fb->fb.fix.accel = FB_ACCEL_NONE;
  444.  
  445. fb->fb.var.xres = fbwidth;
  446. fb->fb.var.yres = fbheight;
  447. fb->fb.var.xres_virtual = fbwidth;
  448. fb->fb.var.yres_virtual = fbheight;
  449. fb->fb.var.bits_per_pixel = 16;
  450. fb->fb.var.vmode = FB_VMODE_NONINTERLACED;
  451. fb->fb.var.activate = FB_ACTIVATE_NOW;
  452. fb->fb.var.nonstd = 0;
  453. fb->fb.var.height = fbwidth;
  454. fb->fb.var.width = fbheight;
  455. fb->fb.var.accel_flags = 0;
  456.  
  457. fb->fb.monspecs.hfmin = 0;
  458. fb->fb.monspecs.hfmax = 100000;
  459. fb->fb.monspecs.vfmin = 0;
  460. fb->fb.monspecs.vfmax = 400;
  461. fb->fb.monspecs.dclkmin = 1000000;
  462. fb->fb.monspecs.dclkmax = 100000000;
  463.  
  464. bcm2708_fb_set_bitfields(&fb->fb.var);
  465.  
  466. /*
  467. * Allocate colourmap.
  468. */
  469.  
  470. fb_set_var(&fb->fb, &fb->fb.var);
  471.  
  472. pr_info("BCM2708FB: registering framebuffer (%d, %d)\n", fbwidth,
  473. fbheight);
  474.  
  475. ret = register_framebuffer(&fb->fb);
  476. pr_info("BCM2708FB: register framebuffer (%d)\n", ret);
  477. if (ret == 0)
  478. goto out;
  479.  
  480. pr_info("BCM2708FB: cannot register framebuffer (%d)\n", ret);
  481. out:
  482. return ret;
  483. }
  484.  
  485. static int bcm2708_fb_probe(struct platform_device *dev)
  486. {
  487. struct bcm2708_fb *fb;
  488. int ret;
  489.  
  490. fb = kmalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
  491. if (!fb) {
  492. dev_err(&dev->dev,
  493. "could not allocate new bcm2708_fb struct\n");
  494. ret = -ENOMEM;
  495. goto free_region;
  496. }
  497. memset(fb, 0, sizeof(struct bcm2708_fb));
  498.  
  499. fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_4K,
  500. &fb->cb_handle, GFP_KERNEL);
  501. if (!fb->cb_base) {
  502. dev_err(&dev->dev, "cannot allocate DMA CBs\n");
  503. ret = -ENOMEM;
  504. goto free_fb;
  505. }
  506.  
  507. pr_info("BCM2708FB: allocated DMA memory %08x\n",
  508. fb->cb_handle);
  509.  
  510. ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_FAST,
  511. &fb->dma_chan_base, &fb->dma_irq);
  512. if (ret < 0) {
  513. dev_err(&dev->dev, "couldn't allocate a DMA channel\n");
  514. goto free_cb;
  515. }
  516. fb->dma_chan = ret;
  517.  
  518. pr_info("BCM2708FB: allocated DMA channel %d @ %p\n",
  519. fb->dma_chan, fb->dma_chan_base);
  520.  
  521. fb->dev = dev;
  522.  
  523. ret = bcm2708_fb_register(fb);
  524. if (ret == 0) {
  525. platform_set_drvdata(dev, fb);
  526. goto out;
  527. }
  528.  
  529. free_cb:
  530. dma_free_writecombine(&dev->dev, SZ_4K, fb->cb_base, fb->cb_handle);
  531. free_fb:
  532. kfree(fb);
  533. free_region:
  534. dev_err(&dev->dev, "probe failed, err %d\n", ret);
  535. out:
  536. return ret;
  537. }
  538.  
  539. static int bcm2708_fb_remove(struct platform_device *dev)
  540. {
  541. struct bcm2708_fb *fb = platform_get_drvdata(dev);
  542.  
  543. platform_set_drvdata(dev, NULL);
  544.  
  545. if (fb->fb.screen_base)
  546. iounmap(fb->fb.screen_base);
  547. unregister_framebuffer(&fb->fb);
  548.  
  549. dma_free_writecombine(&dev->dev, SZ_4K, fb->cb_base, fb->cb_handle);
  550.  
  551. bcm_dma_chan_free(fb->dma_chan);
  552.  
  553. dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info,
  554. fb->dma);
  555. kfree(fb);
  556.  
  557. return 0;
  558. }
  559.  
  560. static struct platform_driver bcm2708_fb_driver = {
  561. .probe = bcm2708_fb_probe,
  562. .remove = bcm2708_fb_remove,
  563. .driver = {
  564. .name = DRIVER_NAME,
  565. .owner = THIS_MODULE,
  566. },
  567. };
  568.  
  569. static int __init bcm2708_fb_init(void)
  570. {
  571. return platform_driver_register(&bcm2708_fb_driver);
  572. }
  573.  
  574. module_init(bcm2708_fb_init);
  575.  
  576. static void __exit bcm2708_fb_exit(void)
  577. {
  578. platform_driver_unregister(&bcm2708_fb_driver);
  579. }
  580.  
  581. module_exit(bcm2708_fb_exit);
  582.  
  583. module_param(fbwidth, int, 0644);
  584. module_param(fbheight, int, 0644);
  585.  
  586. MODULE_DESCRIPTION("BCM2708 framebuffer driver");
  587. MODULE_LICENSE("GPL");
  588.  
  589. MODULE_PARM_DESC(fbwidth, "Width of ARM Framebuffer");
  590. MODULE_PARM_DESC(fbheight, "Height of ARM Framebuffer");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement