Linux/m68k driver for MNT ZZ9000
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

458 lines
12 KiB

  1. /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
  2. #include <drm/drm_fourcc.h>
  3. #include <linux/console.h>
  4. #include <linux/fb.h>
  5. #include <linux/module.h>
  6. #include <linux/zorro.h>
  7. #include <asm/amigahw.h>
  8. #include <asm/amigaints.h>
  9. #include "zz9000.h"
  10. #define PSEUDO_PALETTE_SIZE 16
  11. struct zz9000fb_par {
  12. u32 palette[PSEUDO_PALETTE_SIZE];
  13. };
  14. static const struct fb_fix_screeninfo zz9000fb_fix = {
  15. .id = "ZZ9000",
  16. .type = FB_TYPE_PACKED_PIXELS,
  17. .visual = FB_VISUAL_TRUECOLOR,
  18. .accel = FB_ACCEL_NONE,
  19. };
  20. static const struct fb_var_screeninfo zz9000fb_var = {
  21. .height = -1,
  22. .width = -1,
  23. .activate = FB_ACTIVATE_NOW,
  24. .vmode = FB_VMODE_NONINTERLACED,
  25. };
  26. struct zz9000fb_format {
  27. const char *name;
  28. u32 bits_per_pixel;
  29. struct fb_bitfield red;
  30. struct fb_bitfield green;
  31. struct fb_bitfield blue;
  32. struct fb_bitfield transp;
  33. u32 fourcc;
  34. };
  35. struct zz9000fb_format zz9000fb_formats[3] = {
  36. { "16bit RGB(5:6:5)", 16, {11, 5}, {5, 6}, {0, 5}, { 0, 0}, DRM_FORMAT_RGB565 },
  37. { "15bit RGB(5:5:5)", 16, {10, 5}, {5, 5}, {0, 5}, { 0, 0}, DRM_FORMAT_XRGB1555 },
  38. { "32bit BGRA(8:8:8:8)", 32, {16, 8}, {8, 8}, {24, 8}, {0, 8}, DRM_FORMAT_BGRA8888 },
  39. };
  40. #define MHz * 1024 * 1024
  41. static struct fb_videomode zz9000fb_modedb[] __initdata = {
  42. { "1280x720p60", 60, 1280, 720, 13426, 192, 64, 22, 1, 136, 3,
  43. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  44. { "800x600p60", 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
  45. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  46. { "640x480p60", 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
  47. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  48. { "640x512p60", 60, 640, 512, 41667, 113, 87, 18, 1, 56, 3, // fake, values are @50Hz
  49. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  50. { "720x480p60", 60, 720, 480, 37037, 68, 12, 39, 5, 64, 5,
  51. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  52. { "1024x768p60", 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
  53. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  54. { "1280x1024p60", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
  55. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  56. { "1920x1080p50", 50, 1920, 1080, 6734, 148, 528, 36, 4, 44, 5,
  57. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  58. { "1920x1080p60", 60, 1920, 1080, 5787, 328, 120, 34, 1, 208, 3,
  59. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED },
  60. { "720x576p50", 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5,
  61. FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }
  62. };
  63. #define NUM_TOTAL_MODES ARRAY_SIZE(zz9000fb_modedb)
  64. static int defmode = 0;
  65. #define DEFAULT_BPP 16
  66. struct zz9000_platform_data *zz9000_data;
  67. static char *mode = NULL;
  68. static int zz9000_accel = 0;
  69. static int mntzz_vmode = MNTZZ_MODE_1280x720, mntzz_cmode = MNTZZ_MODE_COLOR_16BIT;
  70. static struct zz9000fb_format *format = NULL;
  71. static int zz9000fb_setcolreg(unsigned regno, unsigned red, unsigned green,
  72. unsigned blue, unsigned transp,
  73. struct fb_info *info)
  74. {
  75. u32 *pal = info->pseudo_palette;
  76. u32 cr = red >> (16 - info->var.red.length);
  77. u32 cg = green >> (16 - info->var.green.length);
  78. u32 cb = blue >> (16 - info->var.blue.length);
  79. u32 value;
  80. if (regno >= PSEUDO_PALETTE_SIZE)
  81. return -EINVAL;
  82. value = (cr << info->var.red.offset) |
  83. (cg << info->var.green.offset) | (cb << info->var.blue.offset);
  84. if (info->var.transp.length > 0) {
  85. u32 mask = (1 << info->var.transp.length) - 1;
  86. mask <<= info->var.transp.offset;
  87. value |= mask;
  88. }
  89. pal[regno] = value;
  90. return 0;
  91. }
  92. /* fb_try_mode says: Returns 1 on success.
  93. * However, all the drivers I looked at return -EINVAL or 0.
  94. */
  95. static int zz9000fb_check_var(struct fb_var_screeninfo *var,
  96. struct fb_info *info)
  97. {
  98. int bytes = 0;
  99. mntzz_vmode = -1;
  100. mntzz_cmode = -1;
  101. if (var->xres == 1280 && var->yres == 720)
  102. mntzz_vmode = MNTZZ_MODE_1280x720;
  103. if (var->xres == 800 && var->yres == 600)
  104. mntzz_vmode = MNTZZ_MODE_800x600;
  105. if (var->xres == 640 && var->yres == 480)
  106. mntzz_vmode = MNTZZ_MODE_640x480;
  107. if (var->xres == 1024 && var->yres == 768)
  108. mntzz_vmode = MNTZZ_MODE_1024x768;
  109. if (var->xres == 1280 && var->yres == 1024)
  110. mntzz_vmode = MNTZZ_MODE_1280x1024;
  111. if (var->xres == 1920 && var->yres == 1080)
  112. if (var->bits_per_pixel <= 16)
  113. mntzz_vmode = MNTZZ_MODE_1920x1080;
  114. if (var->xres == 720 && var->yres == 576)
  115. mntzz_vmode = MNTZZ_MODE_720x576p50;
  116. // FIXME MNTZZ_MODE_1920x1080p50 do we know refresh here?
  117. if (var->xres == 720 && var->yres == 480)
  118. mntzz_vmode = MNTZZ_MODE_720x480;
  119. if (var->xres == 640 && var->yres == 512)
  120. mntzz_vmode = MNTZZ_MODE_640x512;
  121. if (mntzz_vmode == -1)
  122. return -EINVAL;
  123. switch (var->bits_per_pixel) {
  124. case 8:
  125. // Not yet implemented
  126. break;
  127. case 15:
  128. bytes = 2;
  129. mntzz_cmode = MNTZZ_MODE_COLOR_15BIT;
  130. format = &zz9000fb_formats[1];
  131. break;
  132. case 16:
  133. bytes = 2;
  134. mntzz_cmode = MNTZZ_MODE_COLOR_16BIT;
  135. format = &zz9000fb_formats[0];
  136. break;
  137. case 32:
  138. bytes = 4;
  139. mntzz_cmode = MNTZZ_MODE_COLOR_32BIT;
  140. format = &zz9000fb_formats[2];
  141. break;
  142. default:
  143. // Nothing to do
  144. break;
  145. }
  146. // TODO on ZII, check if mode requires more memory than we mapped
  147. if (mntzz_cmode == -1)
  148. return -EINVAL;
  149. var->red = format->red;
  150. var->green = format->green;
  151. var->blue = format->blue;
  152. var->transp = format->transp;
  153. info->fix.line_length = bytes * var->xres;
  154. return 0;
  155. }
  156. /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
  157. static int zz9000fb_blank(int blank, struct fb_info *info)
  158. {
  159. pr_debug("zz9000fb: %sblank.\n", blank ? "" : "un");
  160. return 0;
  161. }
  162. static void zz9000fb_fill_rectangle(struct fb_info *info, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint32_t color)
  163. {
  164. zz_writew(x, MNTZZ_BLITTER_X1);
  165. zz_writew(y, MNTZZ_BLITTER_Y1);
  166. zz_writew(w, MNTZZ_BLITTER_X2);
  167. zz_writew(h, MNTZZ_BLITTER_Y2);
  168. zz_writew(info->fix.line_length >> 2, MNTZZ_BLITTER_ROW_PITCH);
  169. zz_writew(mntzz_cmode, MNTZZ_BLITTER_COLORMODE);
  170. zz_writew(color >> 16, MNTZZ_BLITTER_RGB_HI);
  171. zz_writew(color & 0xffff, MNTZZ_BLITTER_RGB_LO);
  172. zz_writew(0x00ff, MNTZZ_BLITTER_OP_FILLRECT);
  173. }
  174. static void zz9000fb_fillrect(struct fb_info *info,
  175. const struct fb_fillrect *region)
  176. {
  177. if (zz9000_accel) {
  178. if (region->rop == ROP_COPY)
  179. zz9000fb_fill_rectangle(info, region->dx, region->dy,
  180. region->width, region->height, region->color);
  181. else
  182. cfb_fillrect(info, region);
  183. } else
  184. cfb_fillrect(info, region);
  185. }
  186. static void zz9000fb_copyarea(struct fb_info *info,
  187. const struct fb_copyarea *area)
  188. {
  189. if (zz9000_accel) {
  190. zz_writew(area->dx, MNTZZ_BLITTER_X1);
  191. zz_writew(area->dy, MNTZZ_BLITTER_Y1);
  192. zz_writew(area->width, MNTZZ_BLITTER_X2);
  193. zz_writew(area->height, MNTZZ_BLITTER_Y2);
  194. zz_writew(area->sx, MNTZZ_BLITTER_X3);
  195. zz_writew(area->sy, MNTZZ_BLITTER_Y3);
  196. zz_writew(info->fix.line_length >> 2, MNTZZ_BLITTER_ROW_PITCH);
  197. zz_writew(0xff00 | mntzz_cmode, MNTZZ_BLITTER_COLORMODE);
  198. zz_writew(0x0001, MNTZZ_BLITTER_OP_COPYRECT);
  199. } else
  200. cfb_copyarea(info, area);
  201. }
  202. static void
  203. zz9000fb_imageblit(struct fb_info *info, const struct fb_image *image)
  204. {
  205. // TODO accelerated implementation
  206. cfb_imageblit(info, image);
  207. return;
  208. }
  209. void zz9000fb_fix_vsync(void)
  210. {
  211. /* The AmigaOS driver does this 100x */
  212. int i;
  213. for (i = 0; i < 100; i++) {
  214. zz_writew(0x0000, MNTZZ_VIDEO_CTRL_DATA_HI);
  215. zz_writew(0x0001, MNTZZ_VIDEO_CTRL_DATA_LO);
  216. zz_writew(MNTZZ_OP_VSYNC, MNTZZ_VIDEO_CTRL_OP);
  217. zz_writew(MNTZZ_OP_NOP, MNTZZ_VIDEO_CTRL_OP);
  218. zz_writew(0x0000, MNTZZ_VIDEO_CTRL_DATA_LO);
  219. }
  220. }
  221. void zz9000fb_setmode(struct fb_info *info)
  222. {
  223. zz_writew(MNTZZ_CAPTURE_OFF, MNTZZ_VIDEO_CAPTURE_MODE);
  224. zz_writew(0x0000, MNTZZ_PAN_PTR_HI);
  225. zz_writew(0x0000, MNTZZ_PAN_PTR_LO);
  226. zz_writew(0x0000, MNTZZ_BLITTER_SRC_HI);
  227. zz_writew(0x0000, MNTZZ_BLITTER_SRC_LO);
  228. zz_writew(0x0000, MNTZZ_BLITTER_DST_HI);
  229. zz_writew(0x0000, MNTZZ_BLITTER_DST_LO);
  230. zz_writew(MNTZZ_MODE_SCALE_0 | mntzz_cmode | mntzz_vmode,
  231. MNTZZ_MODE);
  232. zz9000fb_fix_vsync();
  233. zz9000fb_fill_rectangle(info, 0,0, info->var.xres, info->var.yres, 0xaaaaaa); // 0xad55?
  234. }
  235. static void
  236. zz9000_capture_mode(uint32_t capture_mode)
  237. {
  238. uint16_t panPtrHi;
  239. uint16_t panPtrLo;
  240. uint16_t scaleMode;
  241. uint16_t colorMode;
  242. uint16_t dispMode;
  243. switch (capture_mode) {
  244. case MNTZZ_VMODE_720x576:
  245. panPtrHi = MNTZZ_CAPTURE_PAN_PAL >> 16;
  246. panPtrLo = MNTZZ_CAPTURE_PAN_PAL & 0xffff;
  247. dispMode = MNTZZ_MODE_720x576p50;
  248. break;
  249. case MMNTZ_VMODE_800x600:
  250. panPtrHi = MNTZZ_CAPTURE_PAN_VGA >> 16;
  251. panPtrLo = MNTZZ_CAPTURE_PAN_VGA & 0xffff;
  252. dispMode = MNTZZ_MODE_800x600;
  253. break;
  254. default:
  255. panPtrHi = MNTZZ_CAPTURE_PAN_PAL >> 16;
  256. panPtrLo = MNTZZ_CAPTURE_PAN_PAL & 0xffff;
  257. dispMode = MNTZZ_MODE_720x576p50;
  258. break;
  259. }
  260. colorMode = MNTZZ_MODE_COLOR_32BIT;
  261. scaleMode = MNTZZ_MODE_SCALE_2;
  262. zz_writew(panPtrHi, MNTZZ_PAN_PTR_HI);
  263. zz_writew(panPtrLo, MNTZZ_PAN_PTR_LO);
  264. zz_writew(dispMode, MNTZZ_VIDEOCAP_VMODE);
  265. zz_writew(scaleMode | colorMode | dispMode, MNTZZ_MODE);
  266. zz_writew(MNTZZ_CAPTURE_ON, MNTZZ_VIDEO_CAPTURE_MODE);
  267. zz9000fb_fix_vsync();
  268. }
  269. static int zz9000fb_set_par(struct fb_info *info)
  270. {
  271. zz9000fb_setmode(info);
  272. dev_info(&zz9000_data->zdev->dev,
  273. "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
  274. info->fix.smem_start, info->fix.smem_len, info->screen_base);
  275. dev_info(&zz9000_data->zdev->dev, "format=%s, mode=%dx%dx%d, linelength=%d\n",
  276. format->name, info->var.xres, info->var.yres,
  277. info->var.bits_per_pixel, info->fix.line_length);
  278. return 0;
  279. }
  280. static struct fb_ops zz9000fb_ops = {
  281. .owner = THIS_MODULE,
  282. .fb_blank = zz9000fb_blank,
  283. .fb_check_var = zz9000fb_check_var,
  284. .fb_setcolreg = zz9000fb_setcolreg,
  285. .fb_set_par = zz9000fb_set_par,
  286. .fb_fillrect = zz9000fb_fillrect,
  287. .fb_copyarea = zz9000fb_copyarea,
  288. .fb_imageblit = zz9000fb_imageblit,
  289. };
  290. static int __init zz9000fb_setup(char *options)
  291. {
  292. char *this_opt;
  293. if (!options || !*options)
  294. return 0;
  295. while ((this_opt = strsep(&options, ",")) != NULL) {
  296. if (!*this_opt)
  297. continue;
  298. /* Not much here yet */
  299. if (!strcmp(this_opt, "noaccel")) {
  300. zz9000_accel = 0;
  301. } else
  302. mode = this_opt;
  303. }
  304. return 0;
  305. }
  306. static int __init zz9000_graphics_init(struct zz9000_platform_data *data)
  307. {
  308. int ret;
  309. struct fb_info *info;
  310. struct zz9000fb_par *par;
  311. char *option = NULL;
  312. uint32_t board = data->zdev->resource.start;
  313. zz9000_data = data;
  314. if (fb_get_options("zz9000fb", &option))
  315. return -ENODEV;
  316. zz9000fb_setup(option);
  317. info = framebuffer_alloc(sizeof(struct zz9000fb_par), &data->zdev->dev);
  318. if (!info)
  319. return -ENOMEM;
  320. data->fb_info = info;
  321. par = info->par;
  322. info->fix = zz9000fb_fix;
  323. info->fix.smem_start = board + 0x10000;
  324. info->fix.smem_len = is_zorro3(data->zdev) ? 0x500000 : 0x3f0000;
  325. info->fix.mmio_start = board;
  326. info->fix.mmio_len = 0x2000;
  327. info->var = zz9000fb_var;
  328. info->apertures = alloc_apertures(1);
  329. if (!info->apertures) {
  330. ret = -ENOMEM;
  331. goto error_fb_release;
  332. }
  333. info->apertures->ranges[0].base = info->fix.smem_start;
  334. info->apertures->ranges[0].size = info->fix.smem_len;
  335. info->fbops = &zz9000fb_ops;
  336. info->flags = FBINFO_DEFAULT;
  337. info->screen_base = data->fb_mem;
  338. info->pseudo_palette = par->palette;
  339. if (!fb_find_mode(&info->var, info, mode, zz9000fb_modedb,
  340. NUM_TOTAL_MODES, &zz9000fb_modedb[defmode], DEFAULT_BPP))
  341. return -EINVAL;
  342. fb_videomode_to_modelist(zz9000fb_modedb, NUM_TOTAL_MODES,
  343. &info->modelist);
  344. ret = register_framebuffer(info);
  345. if (ret < 0) {
  346. dev_err(&data->zdev->dev, "Unable to register zz9000fb: %d\n",
  347. ret);
  348. goto error_fb_release;
  349. }
  350. dev_info(&data->zdev->dev, "fb%d: zz9000fb registered!\n", info->node);
  351. return 0;
  352. error_fb_release:
  353. framebuffer_release(info);
  354. return ret;
  355. }
  356. int zz9000_graphics_remove(struct zz9000_platform_data *data)
  357. {
  358. zz9000_capture_mode(MNTZZ_VMODE_720x576);
  359. unregister_framebuffer(data->fb_info);
  360. framebuffer_release(data->fb_info);
  361. data->fb_info = NULL;
  362. return 0;
  363. }
  364. static int __init zz9000_graphics_module_init(void)
  365. {
  366. struct zz9000_platform_data *data;
  367. data = get_zz9000_data();
  368. return zz9000_graphics_init(data);
  369. }
  370. module_init(zz9000_graphics_module_init);
  371. static void __exit zz9000_graphics_module_exit(void)
  372. {
  373. struct zz9000_platform_data *data;
  374. data = get_zz9000_data();
  375. zz9000_graphics_remove(data);
  376. }
  377. module_exit(zz9000_graphics_module_exit);
  378. module_param(mode, charp, 0);
  379. MODULE_PARM_DESC(mode,
  380. "\nSelects the desired default display mode in the format XxYxDepth,\n"
  381. "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
  382. "XxY-Depth@Rate. (default: 1280x720-60@16)\n");
  383. MODULE_DESCRIPTION("MNT ZZ9000 graphics driver");
  384. MODULE_AUTHOR("Stefan Reinauer <stefan.reinauer@coreboot.org>");
  385. MODULE_LICENSE("GPL");