simplefb.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * Simplest possible simple frame-buffer driver, as a platform device
  3. *
  4. * Copyright (c) 2013, Stephen Warren
  5. *
  6. * Based on q40fb.c, which was:
  7. * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org>
  8. *
  9. * Also based on offb.c, which was:
  10. * Copyright (C) 1997 Geert Uytterhoeven
  11. * Copyright (C) 1996 Paul Mackerras
  12. *
  13. * This program is free software; you can redistribute it and/or modify it
  14. * under the terms and conditions of the GNU General Public License,
  15. * version 2, as published by the Free Software Foundation.
  16. *
  17. * This program is distributed in the hope it will be useful, but WITHOUT
  18. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  20. * more details.
  21. */
  22. #include <linux/errno.h>
  23. #include <linux/fb.h>
  24. #include <linux/io.h>
  25. #include <linux/module.h>
  26. #include <linux/platform_data/simplefb.h>
  27. #include <linux/platform_device.h>
  28. static struct fb_fix_screeninfo simplefb_fix = {
  29. .id = "simple",
  30. .type = FB_TYPE_PACKED_PIXELS,
  31. .visual = FB_VISUAL_TRUECOLOR,
  32. .accel = FB_ACCEL_NONE,
  33. };
  34. static struct fb_var_screeninfo simplefb_var = {
  35. .height = -1,
  36. .width = -1,
  37. .activate = FB_ACTIVATE_NOW,
  38. .vmode = FB_VMODE_NONINTERLACED,
  39. };
  40. static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  41. u_int transp, struct fb_info *info)
  42. {
  43. u32 *pal = info->pseudo_palette;
  44. u32 cr = red >> (16 - info->var.red.length);
  45. u32 cg = green >> (16 - info->var.green.length);
  46. u32 cb = blue >> (16 - info->var.blue.length);
  47. u32 value;
  48. if (regno >= 16)
  49. return -EINVAL;
  50. value = (cr << info->var.red.offset) |
  51. (cg << info->var.green.offset) |
  52. (cb << info->var.blue.offset);
  53. if (info->var.transp.length > 0) {
  54. u32 mask = (1 << info->var.transp.length) - 1;
  55. mask <<= info->var.transp.offset;
  56. value |= mask;
  57. }
  58. pal[regno] = value;
  59. return 0;
  60. }
  61. static void simplefb_destroy(struct fb_info *info)
  62. {
  63. if (info->screen_base)
  64. iounmap(info->screen_base);
  65. }
  66. static struct fb_ops simplefb_ops = {
  67. .owner = THIS_MODULE,
  68. .fb_destroy = simplefb_destroy,
  69. .fb_setcolreg = simplefb_setcolreg,
  70. .fb_fillrect = cfb_fillrect,
  71. .fb_copyarea = cfb_copyarea,
  72. .fb_imageblit = cfb_imageblit,
  73. };
  74. static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
  75. struct simplefb_params {
  76. u32 width;
  77. u32 height;
  78. u32 stride;
  79. struct simplefb_format *format;
  80. };
  81. static int simplefb_parse_dt(struct platform_device *pdev,
  82. struct simplefb_params *params)
  83. {
  84. struct device_node *np = pdev->dev.of_node;
  85. int ret;
  86. const char *format;
  87. int i;
  88. ret = of_property_read_u32(np, "width", &params->width);
  89. if (ret) {
  90. dev_err(&pdev->dev, "Can't parse width property\n");
  91. return ret;
  92. }
  93. ret = of_property_read_u32(np, "height", &params->height);
  94. if (ret) {
  95. dev_err(&pdev->dev, "Can't parse height property\n");
  96. return ret;
  97. }
  98. ret = of_property_read_u32(np, "stride", &params->stride);
  99. if (ret) {
  100. dev_err(&pdev->dev, "Can't parse stride property\n");
  101. return ret;
  102. }
  103. ret = of_property_read_string(np, "format", &format);
  104. if (ret) {
  105. dev_err(&pdev->dev, "Can't parse format property\n");
  106. return ret;
  107. }
  108. params->format = NULL;
  109. for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
  110. if (strcmp(format, simplefb_formats[i].name))
  111. continue;
  112. params->format = &simplefb_formats[i];
  113. break;
  114. }
  115. if (!params->format) {
  116. dev_err(&pdev->dev, "Invalid format value\n");
  117. return -EINVAL;
  118. }
  119. return 0;
  120. }
  121. static int simplefb_parse_pd(struct platform_device *pdev,
  122. struct simplefb_params *params)
  123. {
  124. struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev);
  125. int i;
  126. params->width = pd->width;
  127. params->height = pd->height;
  128. params->stride = pd->stride;
  129. params->format = NULL;
  130. for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
  131. if (strcmp(pd->format, simplefb_formats[i].name))
  132. continue;
  133. params->format = &simplefb_formats[i];
  134. break;
  135. }
  136. if (!params->format) {
  137. dev_err(&pdev->dev, "Invalid format value\n");
  138. return -EINVAL;
  139. }
  140. return 0;
  141. }
  142. static int simplefb_probe(struct platform_device *pdev)
  143. {
  144. int ret;
  145. struct simplefb_params params;
  146. struct fb_info *info;
  147. struct resource *mem;
  148. if (fb_get_options("simplefb", NULL))
  149. return -ENODEV;
  150. ret = -ENODEV;
  151. if (dev_get_platdata(&pdev->dev))
  152. ret = simplefb_parse_pd(pdev, &params);
  153. else if (pdev->dev.of_node)
  154. ret = simplefb_parse_dt(pdev, &params);
  155. if (ret)
  156. return ret;
  157. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  158. if (!mem) {
  159. dev_err(&pdev->dev, "No memory resource\n");
  160. return -EINVAL;
  161. }
  162. info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
  163. if (!info)
  164. return -ENOMEM;
  165. platform_set_drvdata(pdev, info);
  166. info->fix = simplefb_fix;
  167. info->fix.smem_start = mem->start;
  168. info->fix.smem_len = resource_size(mem);
  169. info->fix.line_length = params.stride;
  170. info->var = simplefb_var;
  171. info->var.xres = params.width;
  172. info->var.yres = params.height;
  173. info->var.xres_virtual = params.width;
  174. info->var.yres_virtual = params.height;
  175. info->var.bits_per_pixel = params.format->bits_per_pixel;
  176. info->var.red = params.format->red;
  177. info->var.green = params.format->green;
  178. info->var.blue = params.format->blue;
  179. info->var.transp = params.format->transp;
  180. info->apertures = alloc_apertures(1);
  181. if (!info->apertures) {
  182. framebuffer_release(info);
  183. return -ENOMEM;
  184. }
  185. info->apertures->ranges[0].base = info->fix.smem_start;
  186. info->apertures->ranges[0].size = info->fix.smem_len;
  187. info->fbops = &simplefb_ops;
  188. info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
  189. info->screen_base = ioremap_wc(info->fix.smem_start,
  190. info->fix.smem_len);
  191. if (!info->screen_base) {
  192. framebuffer_release(info);
  193. return -ENODEV;
  194. }
  195. info->pseudo_palette = (void *)(info + 1);
  196. dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
  197. info->fix.smem_start, info->fix.smem_len,
  198. info->screen_base);
  199. dev_info(&pdev->dev, "format=%s, mode=%dx%dx%d, linelength=%d\n",
  200. params.format->name,
  201. info->var.xres, info->var.yres,
  202. info->var.bits_per_pixel, info->fix.line_length);
  203. ret = register_framebuffer(info);
  204. if (ret < 0) {
  205. dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
  206. iounmap(info->screen_base);
  207. framebuffer_release(info);
  208. return ret;
  209. }
  210. dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
  211. return 0;
  212. }
  213. static int simplefb_remove(struct platform_device *pdev)
  214. {
  215. struct fb_info *info = platform_get_drvdata(pdev);
  216. unregister_framebuffer(info);
  217. framebuffer_release(info);
  218. return 0;
  219. }
  220. static const struct of_device_id simplefb_of_match[] = {
  221. { .compatible = "simple-framebuffer", },
  222. { },
  223. };
  224. MODULE_DEVICE_TABLE(of, simplefb_of_match);
  225. static struct platform_driver simplefb_driver = {
  226. .driver = {
  227. .name = "simple-framebuffer",
  228. .owner = THIS_MODULE,
  229. .of_match_table = simplefb_of_match,
  230. },
  231. .probe = simplefb_probe,
  232. .remove = simplefb_remove,
  233. };
  234. module_platform_driver(simplefb_driver);
  235. MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
  236. MODULE_DESCRIPTION("Simple framebuffer driver");
  237. MODULE_LICENSE("GPL v2");