imacfb.c 10 KB

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