imacfb.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * framebuffer driver for Intel Based Mac's
  3. *
  4. * (c) 2006 Edgar Hucek <gimli@dark-green.com>
  5. * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
  6. *
  7. */
  8. #include <linux/delay.h>
  9. #include <linux/errno.h>
  10. #include <linux/fb.h>
  11. #include <linux/kernel.h>
  12. #include <linux/init.h>
  13. #include <linux/ioport.h>
  14. #include <linux/mm.h>
  15. #include <linux/module.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/slab.h>
  18. #include <linux/string.h>
  19. #include <linux/tty.h>
  20. #include <asm/io.h>
  21. #include <video/vga.h>
  22. typedef enum _MAC_TYPE {
  23. M_I17,
  24. M_I20,
  25. M_MINI,
  26. M_MACBOOK,
  27. M_NEW
  28. } MAC_TYPE;
  29. /* --------------------------------------------------------------------- */
  30. static struct fb_var_screeninfo imacfb_defined __initdata = {
  31. .activate = FB_ACTIVATE_NOW,
  32. .height = -1,
  33. .width = -1,
  34. .right_margin = 32,
  35. .upper_margin = 16,
  36. .lower_margin = 4,
  37. .vsync_len = 4,
  38. .vmode = FB_VMODE_NONINTERLACED,
  39. };
  40. static struct fb_fix_screeninfo imacfb_fix __initdata = {
  41. .id = "IMAC VGA",
  42. .type = FB_TYPE_PACKED_PIXELS,
  43. .accel = FB_ACCEL_NONE,
  44. .visual = FB_VISUAL_TRUECOLOR,
  45. };
  46. static int inverse;
  47. static int model = M_NEW;
  48. static int manual_height;
  49. static int manual_width;
  50. #define DEFAULT_FB_MEM 1024*1024*16
  51. /* --------------------------------------------------------------------- */
  52. static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green,
  53. unsigned blue, unsigned transp,
  54. struct fb_info *info)
  55. {
  56. /*
  57. * Set a single color register. The values supplied are
  58. * already rounded down to the hardware's capabilities
  59. * (according to the entries in the `var' structure). Return
  60. * != 0 for invalid regno.
  61. */
  62. if (regno >= info->cmap.len)
  63. return 1;
  64. if (regno < 16) {
  65. red >>= 8;
  66. green >>= 8;
  67. blue >>= 8;
  68. ((u32 *)(info->pseudo_palette))[regno] =
  69. (red << info->var.red.offset) |
  70. (green << info->var.green.offset) |
  71. (blue << info->var.blue.offset);
  72. }
  73. return 0;
  74. }
  75. static struct fb_ops imacfb_ops = {
  76. .owner = THIS_MODULE,
  77. .fb_setcolreg = imacfb_setcolreg,
  78. .fb_fillrect = cfb_fillrect,
  79. .fb_copyarea = cfb_copyarea,
  80. .fb_imageblit = cfb_imageblit,
  81. };
  82. static int __init imacfb_setup(char *options)
  83. {
  84. char *this_opt;
  85. if (!options || !*options)
  86. return 0;
  87. while ((this_opt = strsep(&options, ",")) != NULL) {
  88. if (!*this_opt) continue;
  89. if (!strcmp(this_opt, "inverse"))
  90. inverse = 1;
  91. else if (!strcmp(this_opt, "i17"))
  92. model = M_I17;
  93. else if (!strcmp(this_opt, "i20"))
  94. model = M_I20;
  95. else if (!strcmp(this_opt, "mini"))
  96. model = M_MINI;
  97. else if (!strcmp(this_opt, "macbook"))
  98. model = M_MACBOOK;
  99. else if (!strncmp(this_opt, "height:", 7))
  100. manual_height = simple_strtoul(this_opt+7, NULL, 0);
  101. else if (!strncmp(this_opt, "width:", 6))
  102. manual_width = simple_strtoul(this_opt+6, NULL, 0);
  103. }
  104. return 0;
  105. }
  106. static int __init imacfb_probe(struct platform_device *dev)
  107. {
  108. struct fb_info *info;
  109. int err;
  110. unsigned int size_vmode;
  111. unsigned int size_remap;
  112. unsigned int size_total;
  113. screen_info.lfb_depth = 32;
  114. screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
  115. screen_info.pages=1;
  116. screen_info.blue_size = 8;
  117. screen_info.blue_pos = 0;
  118. screen_info.green_size = 8;
  119. screen_info.green_pos = 8;
  120. screen_info.red_size = 8;
  121. screen_info.red_pos = 16;
  122. screen_info.rsvd_size = 8;
  123. screen_info.rsvd_pos = 24;
  124. switch (model) {
  125. case M_I17:
  126. screen_info.lfb_width = 1440;
  127. screen_info.lfb_height = 900;
  128. screen_info.lfb_linelength = 1472 * 4;
  129. screen_info.lfb_base = 0x80010000;
  130. break;
  131. case M_NEW:
  132. case M_I20:
  133. screen_info.lfb_width = 1680;
  134. screen_info.lfb_height = 1050;
  135. screen_info.lfb_linelength = 1728 * 4;
  136. screen_info.lfb_base = 0x80010000;
  137. break;
  138. case M_MINI:
  139. screen_info.lfb_width = 1024;
  140. screen_info.lfb_height = 768;
  141. screen_info.lfb_linelength = 2048 * 4;
  142. screen_info.lfb_base = 0x80000000;
  143. break;
  144. case M_MACBOOK:
  145. screen_info.lfb_width = 1280;
  146. screen_info.lfb_height = 800;
  147. screen_info.lfb_linelength = 2048 * 4;
  148. screen_info.lfb_base = 0x80000000;
  149. break;
  150. }
  151. /* if the user wants to manually specify height/width,
  152. we will override the defaults */
  153. /* TODO: eventually get auto-detection working */
  154. if (manual_height > 0)
  155. screen_info.lfb_height = manual_height;
  156. if (manual_width > 0)
  157. screen_info.lfb_width = manual_width;
  158. imacfb_fix.smem_start = screen_info.lfb_base;
  159. imacfb_defined.bits_per_pixel = screen_info.lfb_depth;
  160. imacfb_defined.xres = screen_info.lfb_width;
  161. imacfb_defined.yres = screen_info.lfb_height;
  162. imacfb_fix.line_length = screen_info.lfb_linelength;
  163. /* size_vmode -- that is the amount of memory needed for the
  164. * used video mode, i.e. the minimum amount of
  165. * memory we need. */
  166. size_vmode = imacfb_defined.yres * imacfb_fix.line_length;
  167. /* size_total -- all video memory we have. Used for
  168. * entries, ressource allocation and bounds
  169. * checking. */
  170. size_total = screen_info.lfb_size * 65536;
  171. if (size_total < size_vmode)
  172. size_total = size_vmode;
  173. /* size_remap -- the amount of video memory we are going to
  174. * use for imacfb. With modern cards it is no
  175. * option to simply use size_total as that
  176. * wastes plenty of kernel address space. */
  177. size_remap = size_vmode * 2;
  178. if (size_remap < size_vmode)
  179. size_remap = size_vmode;
  180. if (size_remap > size_total)
  181. size_remap = size_total;
  182. imacfb_fix.smem_len = size_remap;
  183. if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) {
  184. printk(KERN_WARNING
  185. "imacfb: cannot reserve video memory at 0x%lx\n",
  186. imacfb_fix.smem_start);
  187. /* We cannot make this fatal. Sometimes this comes from magic
  188. spaces our resource handlers simply don't know about */
  189. }
  190. info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
  191. if (!info) {
  192. err = -ENOMEM;
  193. goto err_release_mem;
  194. }
  195. info->pseudo_palette = info->par;
  196. info->par = NULL;
  197. info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len);
  198. if (!info->screen_base) {
  199. printk(KERN_ERR "imacfb: abort, cannot ioremap video memory "
  200. "0x%x @ 0x%lx\n",
  201. imacfb_fix.smem_len, imacfb_fix.smem_start);
  202. err = -EIO;
  203. goto err_unmap;
  204. }
  205. printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, "
  206. "using %dk, total %dk\n",
  207. imacfb_fix.smem_start, info->screen_base,
  208. size_remap/1024, size_total/1024);
  209. printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
  210. imacfb_defined.xres, imacfb_defined.yres,
  211. imacfb_defined.bits_per_pixel, imacfb_fix.line_length,
  212. screen_info.pages);
  213. imacfb_defined.xres_virtual = imacfb_defined.xres;
  214. imacfb_defined.yres_virtual = imacfb_fix.smem_len /
  215. imacfb_fix.line_length;
  216. printk(KERN_INFO "imacfb: scrolling: redraw\n");
  217. imacfb_defined.yres_virtual = imacfb_defined.yres;
  218. /* some dummy values for timing to make fbset happy */
  219. imacfb_defined.pixclock = 10000000 / imacfb_defined.xres *
  220. 1000 / imacfb_defined.yres;
  221. imacfb_defined.left_margin = (imacfb_defined.xres / 8) & 0xf8;
  222. imacfb_defined.hsync_len = (imacfb_defined.xres / 8) & 0xf8;
  223. imacfb_defined.red.offset = screen_info.red_pos;
  224. imacfb_defined.red.length = screen_info.red_size;
  225. imacfb_defined.green.offset = screen_info.green_pos;
  226. imacfb_defined.green.length = screen_info.green_size;
  227. imacfb_defined.blue.offset = screen_info.blue_pos;
  228. imacfb_defined.blue.length = screen_info.blue_size;
  229. imacfb_defined.transp.offset = screen_info.rsvd_pos;
  230. imacfb_defined.transp.length = screen_info.rsvd_size;
  231. printk(KERN_INFO "imacfb: %s: "
  232. "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
  233. "Truecolor",
  234. screen_info.rsvd_size,
  235. screen_info.red_size,
  236. screen_info.green_size,
  237. screen_info.blue_size,
  238. screen_info.rsvd_pos,
  239. screen_info.red_pos,
  240. screen_info.green_pos,
  241. screen_info.blue_pos);
  242. imacfb_fix.ypanstep = 0;
  243. imacfb_fix.ywrapstep = 0;
  244. /* request failure does not faze us, as vgacon probably has this
  245. * region already (FIXME) */
  246. request_region(0x3c0, 32, "imacfb");
  247. info->fbops = &imacfb_ops;
  248. info->var = imacfb_defined;
  249. info->fix = imacfb_fix;
  250. info->flags = FBINFO_FLAG_DEFAULT;
  251. if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
  252. err = -ENOMEM;
  253. goto err_unmap;
  254. }
  255. if (register_framebuffer(info)<0) {
  256. err = -EINVAL;
  257. goto err_fb_dealoc;
  258. }
  259. printk(KERN_INFO "fb%d: %s frame buffer device\n",
  260. info->node, info->fix.id);
  261. return 0;
  262. err_fb_dealoc:
  263. fb_dealloc_cmap(&info->cmap);
  264. err_unmap:
  265. iounmap(info->screen_base);
  266. framebuffer_release(info);
  267. err_release_mem:
  268. release_mem_region(imacfb_fix.smem_start, size_total);
  269. return err;
  270. }
  271. static struct platform_driver imacfb_driver = {
  272. .probe = imacfb_probe,
  273. .driver = {
  274. .name = "imacfb",
  275. },
  276. };
  277. static struct platform_device imacfb_device = {
  278. .name = "imacfb",
  279. };
  280. static int __init imacfb_init(void)
  281. {
  282. int ret;
  283. char *option = NULL;
  284. /* ignore error return of fb_get_options */
  285. fb_get_options("imacfb", &option);
  286. imacfb_setup(option);
  287. ret = platform_driver_register(&imacfb_driver);
  288. if (!ret) {
  289. ret = platform_device_register(&imacfb_device);
  290. if (ret)
  291. platform_driver_unregister(&imacfb_driver);
  292. }
  293. return ret;
  294. }
  295. module_init(imacfb_init);
  296. MODULE_LICENSE("GPL");