acornfb.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:44k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/video/acornfb.c
  3.  *
  4.  *  Copyright (C) 1998-2001 Russell King
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License version 2 as
  8.  * published by the Free Software Foundation.
  9.  *
  10.  * Frame buffer code for Acorn platforms
  11.  *
  12.  * NOTE: Most of the modes with X!=640 will disappear shortly.
  13.  * NOTE: Startup setting of HS & VS polarity not supported.
  14.  *       (do we need to support it if we're coming up in 640x480?)
  15.  */
  16. #include <linux/config.h>
  17. #include <linux/module.h>
  18. #include <linux/kernel.h>
  19. #include <linux/sched.h>
  20. #include <linux/errno.h>
  21. #include <linux/string.h>
  22. #include <linux/ctype.h>
  23. #include <linux/mm.h>
  24. #include <linux/tty.h>
  25. #include <linux/slab.h>
  26. #include <linux/init.h>
  27. #include <linux/fb.h>
  28. #include <asm/hardware.h>
  29. #include <asm/io.h>
  30. #include <asm/irq.h>
  31. #include <asm/mach-types.h>
  32. #include <asm/uaccess.h>
  33. #include <video/fbcon.h>
  34. #include <video/fbcon-mfb.h>
  35. #include <video/fbcon-cfb2.h>
  36. #include <video/fbcon-cfb4.h>
  37. #include <video/fbcon-cfb8.h>
  38. #include <video/fbcon-cfb16.h>
  39. #include <video/fbcon-cfb32.h>
  40. #include "acornfb.h"
  41. /*
  42.  * VIDC machines can't do 16 or 32BPP modes.
  43.  */
  44. #ifdef HAS_VIDC
  45. #undef FBCON_HAS_CFB16
  46. #undef FBCON_HAS_CFB32
  47. #endif
  48. /*
  49.  * Default resolution.
  50.  * NOTE that it has to be supported in the table towards
  51.  * the end of this file.
  52.  */
  53. #define DEFAULT_XRES 640
  54. #define DEFAULT_YRES 480
  55. /*
  56.  * The order here defines which BPP we
  57.  * pick depending on which resolutions
  58.  * we have configured.
  59.  */
  60. #if   defined(FBCON_HAS_CFB4)
  61. # define DEFAULT_BPP 4
  62. #elif defined(FBCON_HAS_CFB8)
  63. # define DEFAULT_BPP 8
  64. #elif defined(FBCON_HAS_CFB16)
  65. # define DEFAULT_BPP 16
  66. #elif defined(FBCON_HAS_CFB2)
  67. # define DEFAULT_BPP 2
  68. #elif defined(FBCON_HAS_MFB)
  69. # define DEFAULT_BPP 1
  70. #else
  71. #error No suitable framebuffers configured
  72. #endif
  73. /*
  74.  * define this to debug the video mode selection
  75.  */
  76. #undef DEBUG_MODE_SELECTION
  77. /*
  78.  * Translation from RISC OS monitor types to actual
  79.  * HSYNC and VSYNC frequency ranges.  These are
  80.  * probably not right, but they're the best info I
  81.  * have.  Allow 1% either way on the nominal for TVs.
  82.  */
  83. #define NR_MONTYPES 6
  84. static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {
  85. { 15469, 15781, 49, 51, 0 }, /* TV */
  86. {     0, 99999,  0, 99, 0 }, /* Multi Freq */
  87. { 58608, 58608, 64, 64, 0 }, /* Hi-res mono */
  88. { 30000, 70000, 60, 60, 0 }, /* VGA */
  89. { 30000, 70000, 56, 75, 0 }, /* SVGA */
  90. { 30000, 70000, 60, 60, 0 }
  91. };
  92. static struct display global_disp;
  93. static struct fb_info fb_info;
  94. static struct acornfb_par current_par;
  95. static struct vidc_timing current_vidc;
  96. static struct fb_var_screeninfo __initdata init_var = {};
  97. extern int acornfb_depth; /* set by setup.c */
  98. extern unsigned int vram_size; /* set by setup.c */
  99. #ifdef HAS_VIDC
  100. #define MAX_SIZE 480*1024
  101. /* CTL     VIDC Actual
  102.  * 24.000  0  8.000
  103.  * 25.175  0  8.392
  104.  * 36.000  0 12.000
  105.  * 24.000  1 12.000
  106.  * 25.175  1 12.588
  107.  * 24.000  2 16.000
  108.  * 25.175  2 16.783
  109.  * 36.000  1 18.000
  110.  * 24.000  3 24.000
  111.  * 36.000  2 24.000
  112.  * 25.175  3 25.175
  113.  * 36.000  3 36.000
  114.  */
  115. struct pixclock {
  116. u_long min_clock;
  117. u_long max_clock;
  118. u_int vidc_ctl;
  119. u_int vid_ctl;
  120. };
  121. static struct pixclock arc_clocks[] = {
  122. /* we allow +/-1% on these */
  123. { 123750, 126250, VIDC_CTRL_DIV3,   VID_CTL_24MHz }, /*  8.000MHz */
  124. {  82500,  84167, VIDC_CTRL_DIV2,   VID_CTL_24MHz }, /* 12.000MHz */
  125. {  61875,  63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz }, /* 16.000MHz */
  126. {  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz }, /* 24.000MHz */
  127. };
  128. #ifdef CONFIG_ARCH_A5K
  129. static struct pixclock a5k_clocks[] = {
  130. { 117974, 120357, VIDC_CTRL_DIV3,   VID_CTL_25MHz }, /*  8.392MHz */
  131. {  78649,  80238, VIDC_CTRL_DIV2,   VID_CTL_25MHz }, /* 12.588MHz */
  132. {  58987,  60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz }, /* 16.588MHz */
  133. {  55000,  56111, VIDC_CTRL_DIV2,   VID_CTL_36MHz }, /* 18.000MHz */
  134. {  39325,  40119, VIDC_CTRL_DIV1,   VID_CTL_25MHz }, /* 25.175MHz */
  135. {  27500,  28055, VIDC_CTRL_DIV1,   VID_CTL_36MHz }, /* 36.000MHz */
  136. };
  137. #endif
  138. static struct pixclock *
  139. acornfb_valid_pixrate(u_long pixclock)
  140. {
  141. u_int i;
  142. for (i = 0; i < ARRAY_SIZE(arc_clocks); i++)
  143. if (pixclock > arc_clocks[i].min_clock &&
  144.     pixclock < arc_clocks[i].max_clock)
  145. return arc_clocks + i;
  146. #ifdef CONFIG_ARCH_A5K
  147. if (machine_is_a5k()) {
  148. for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)
  149. if (pixclock > a5k_clocks[i].min_clock &&
  150.     pixclock < a5k_clocks[i].max_clock)
  151. return a5k_clocks + i;
  152. }
  153. #endif
  154. return NULL;
  155. }
  156. /* VIDC Rules:
  157.  * hcr  : must be even (interlace, hcr/2 must be even)
  158.  * hswr : must be even
  159.  * hdsr : must be odd
  160.  * hder : must be odd
  161.  *
  162.  * vcr  : must be odd
  163.  * vswr : >= 1
  164.  * vdsr : >= 1
  165.  * vder : >= vdsr
  166.  * if interlaced, then hcr/2 must be even
  167.  */
  168. static void
  169. acornfb_set_timing(struct fb_var_screeninfo *var)
  170. {
  171. struct pixclock *pclk;
  172. struct vidc_timing vidc;
  173. u_int horiz_correction;
  174. u_int sync_len, display_start, display_end, cycle;
  175. u_int is_interlaced;
  176. u_int vid_ctl, vidc_ctl;
  177. u_int bandwidth;
  178. memset(&vidc, 0, sizeof(vidc));
  179. pclk = acornfb_valid_pixrate(var->pixclock);
  180. vidc_ctl = pclk->vidc_ctl;
  181. vid_ctl  = pclk->vid_ctl;
  182. bandwidth = var->pixclock * 8 / var->bits_per_pixel;
  183. /* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
  184. if (bandwidth > 143500)
  185. vidc_ctl |= VIDC_CTRL_FIFO_3_7;
  186. else if (bandwidth > 71750)
  187. vidc_ctl |= VIDC_CTRL_FIFO_2_6;
  188. else if (bandwidth > 35875)
  189. vidc_ctl |= VIDC_CTRL_FIFO_1_5;
  190. else
  191. vidc_ctl |= VIDC_CTRL_FIFO_0_4;
  192. switch (var->bits_per_pixel) {
  193. case 1:
  194. horiz_correction = 19;
  195. vidc_ctl |= VIDC_CTRL_1BPP;
  196. break;
  197. case 2:
  198. horiz_correction = 11;
  199. vidc_ctl |= VIDC_CTRL_2BPP;
  200. break;
  201. case 4:
  202. horiz_correction = 7;
  203. vidc_ctl |= VIDC_CTRL_4BPP;
  204. break;
  205. default:
  206. case 8:
  207. horiz_correction = 5;
  208. vidc_ctl |= VIDC_CTRL_8BPP;
  209. break;
  210. }
  211. if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
  212. vidc_ctl |= VIDC_CTRL_CSYNC;
  213. else {
  214. if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
  215. vid_ctl |= VID_CTL_HS_NHSYNC;
  216. if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
  217. vid_ctl |= VID_CTL_VS_NVSYNC;
  218. }
  219. sync_len = var->hsync_len;
  220. display_start = sync_len + var->left_margin;
  221. display_end = display_start + var->xres;
  222. cycle = display_end + var->right_margin;
  223. /* if interlaced, then hcr/2 must be even */
  224. is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
  225. if (is_interlaced) {
  226. vidc_ctl |= VIDC_CTRL_INTERLACE;
  227. if (cycle & 2) {
  228. cycle += 2;
  229. var->right_margin += 2;
  230. }
  231. }
  232. vidc.h_cycle = (cycle - 2) / 2;
  233. vidc.h_sync_width = (sync_len - 2) / 2;
  234. vidc.h_border_start = (display_start - 1) / 2;
  235. vidc.h_display_start = (display_start - horiz_correction) / 2;
  236. vidc.h_display_end = (display_end - horiz_correction) / 2;
  237. vidc.h_border_end = (display_end - 1) / 2;
  238. vidc.h_interlace = (vidc.h_cycle + 1) / 2;
  239. sync_len = var->vsync_len;
  240. display_start = sync_len + var->upper_margin;
  241. display_end = display_start + var->yres;
  242. cycle = display_end + var->lower_margin;
  243. if (is_interlaced)
  244. cycle = (cycle - 3) / 2;
  245. else
  246. cycle = cycle - 1;
  247. vidc.v_cycle = cycle;
  248. vidc.v_sync_width = sync_len - 1;
  249. vidc.v_border_start = display_start - 1;
  250. vidc.v_display_start = vidc.v_border_start;
  251. vidc.v_display_end = display_end - 1;
  252. vidc.v_border_end = vidc.v_display_end;
  253. if (machine_is_a5k())
  254. __raw_writeb(vid_ctl, IOEB_VID_CTL);
  255. if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
  256. current_vidc = vidc;
  257. vidc_writel(0xe0000000 | vidc_ctl);
  258. vidc_writel(0x80000000 | (vidc.h_cycle << 14));
  259. vidc_writel(0x84000000 | (vidc.h_sync_width << 14));
  260. vidc_writel(0x88000000 | (vidc.h_border_start << 14));
  261. vidc_writel(0x8c000000 | (vidc.h_display_start << 14));
  262. vidc_writel(0x90000000 | (vidc.h_display_end << 14));
  263. vidc_writel(0x94000000 | (vidc.h_border_end << 14));
  264. vidc_writel(0x98000000);
  265. vidc_writel(0x9c000000 | (vidc.h_interlace << 14));
  266. vidc_writel(0xa0000000 | (vidc.v_cycle << 14));
  267. vidc_writel(0xa4000000 | (vidc.v_sync_width << 14));
  268. vidc_writel(0xa8000000 | (vidc.v_border_start << 14));
  269. vidc_writel(0xac000000 | (vidc.v_display_start << 14));
  270. vidc_writel(0xb0000000 | (vidc.v_display_end << 14));
  271. vidc_writel(0xb4000000 | (vidc.v_border_end << 14));
  272. vidc_writel(0xb8000000);
  273. vidc_writel(0xbc000000);
  274. }
  275. #ifdef DEBUG_MODE_SELECTION
  276. printk(KERN_DEBUG "VIDC registers for %dx%dx%d:n", var->xres,
  277.        var->yres, var->bits_per_pixel);
  278. printk(KERN_DEBUG " H-cycle          : %dn", vidc.h_cycle);
  279. printk(KERN_DEBUG " H-sync-width     : %dn", vidc.h_sync_width);
  280. printk(KERN_DEBUG " H-border-start   : %dn", vidc.h_border_start);
  281. printk(KERN_DEBUG " H-display-start  : %dn", vidc.h_display_start);
  282. printk(KERN_DEBUG " H-display-end    : %dn", vidc.h_display_end);
  283. printk(KERN_DEBUG " H-border-end     : %dn", vidc.h_border_end);
  284. printk(KERN_DEBUG " H-interlace      : %dn", vidc.h_interlace);
  285. printk(KERN_DEBUG " V-cycle          : %dn", vidc.v_cycle);
  286. printk(KERN_DEBUG " V-sync-width     : %dn", vidc.v_sync_width);
  287. printk(KERN_DEBUG " V-border-start   : %dn", vidc.v_border_start);
  288. printk(KERN_DEBUG " V-display-start  : %dn", vidc.v_display_start);
  289. printk(KERN_DEBUG " V-display-end    : %dn", vidc.v_display_end);
  290. printk(KERN_DEBUG " V-border-end     : %dn", vidc.v_border_end);
  291. printk(KERN_DEBUG " VIDC Ctrl (E)    : 0x%08Xn", vidc_ctl);
  292. printk(KERN_DEBUG " IOEB Ctrl        : 0x%08Xn", vid_ctl);
  293. #endif
  294. }
  295. static inline void
  296. acornfb_palette_write(u_int regno, union palette pal)
  297. {
  298. vidc_writel(pal.p);
  299. }
  300. static inline union palette
  301. acornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,
  302.        u_int trans)
  303. {
  304. union palette pal;
  305. pal.p = 0;
  306. pal.vidc.reg   = regno;
  307. pal.vidc.red   = red >> 12;
  308. pal.vidc.green = green >> 12;
  309. pal.vidc.blue  = blue >> 12;
  310. return pal;
  311. }
  312. static void
  313. acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,
  314.        u_int *trans)
  315. {
  316. *red   = EXTEND4(current_par.palette[regno].vidc.red);
  317. *green = EXTEND4(current_par.palette[regno].vidc.green);
  318. *blue  = EXTEND4(current_par.palette[regno].vidc.blue);
  319. *trans = current_par.palette[regno].vidc.trans ? -1 : 0;
  320. }
  321. #endif
  322. #ifdef HAS_VIDC20
  323. #include <asm/arch/acornfb.h>
  324. #define MAX_SIZE 2*1024*1024
  325. /* VIDC20 has a different set of rules from the VIDC:
  326.  *  hcr  : must be multiple of 4
  327.  *  hswr : must be even
  328.  *  hdsr : must be even
  329.  *  hder : must be even
  330.  *  vcr  : >= 2, (interlace, must be odd)
  331.  *  vswr : >= 1
  332.  *  vdsr : >= 1
  333.  *  vder : >= vdsr
  334.  */
  335. static void
  336. acornfb_set_timing(struct fb_var_screeninfo *var)
  337. {
  338. struct vidc_timing vidc;
  339. u_int vcr, fsize;
  340. u_int ext_ctl, dat_ctl;
  341. u_int words_per_line;
  342. memset(&vidc, 0, sizeof(vidc));
  343. vidc.h_sync_width = var->hsync_len - 8;
  344. vidc.h_border_start = vidc.h_sync_width + var->left_margin + 8 - 12;
  345. vidc.h_display_start = vidc.h_border_start + 12 - 18;
  346. vidc.h_display_end = vidc.h_display_start + var->xres;
  347. vidc.h_border_end = vidc.h_display_end + 18 - 12;
  348. vidc.h_cycle = vidc.h_border_end + var->right_margin + 12 - 8;
  349. vidc.h_interlace = vidc.h_cycle / 2;
  350. vidc.v_sync_width = var->vsync_len - 1;
  351. vidc.v_border_start = vidc.v_sync_width + var->upper_margin;
  352. vidc.v_display_start = vidc.v_border_start;
  353. vidc.v_display_end = vidc.v_display_start + var->yres;
  354. vidc.v_border_end = vidc.v_display_end;
  355. vidc.control = acornfb_default_control();
  356. vcr = var->vsync_len + var->upper_margin + var->yres +
  357.       var->lower_margin;
  358. if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
  359. vidc.v_cycle = (vcr - 3) / 2;
  360. vidc.control |= VIDC20_CTRL_INT;
  361. } else
  362. vidc.v_cycle = vcr - 2;
  363. switch (var->bits_per_pixel) {
  364. case  1: vidc.control |= VIDC20_CTRL_1BPP; break;
  365. case  2: vidc.control |= VIDC20_CTRL_2BPP; break;
  366. case  4: vidc.control |= VIDC20_CTRL_4BPP; break;
  367. default:
  368. case  8: vidc.control |= VIDC20_CTRL_8BPP; break;
  369. case 16: vidc.control |= VIDC20_CTRL_16BPP; break;
  370. case 32: vidc.control |= VIDC20_CTRL_32BPP; break;
  371. }
  372. acornfb_vidc20_find_rates(&vidc, var);
  373. fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1;
  374. if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
  375. current_vidc = vidc;
  376. vidc_writel(VIDC20_CTRL| vidc.control);
  377. vidc_writel(0xd0000000 | vidc.pll_ctl);
  378. vidc_writel(0x80000000 | vidc.h_cycle);
  379. vidc_writel(0x81000000 | vidc.h_sync_width);
  380. vidc_writel(0x82000000 | vidc.h_border_start);
  381. vidc_writel(0x83000000 | vidc.h_display_start);
  382. vidc_writel(0x84000000 | vidc.h_display_end);
  383. vidc_writel(0x85000000 | vidc.h_border_end);
  384. vidc_writel(0x86000000);
  385. vidc_writel(0x87000000 | vidc.h_interlace);
  386. vidc_writel(0x90000000 | vidc.v_cycle);
  387. vidc_writel(0x91000000 | vidc.v_sync_width);
  388. vidc_writel(0x92000000 | vidc.v_border_start);
  389. vidc_writel(0x93000000 | vidc.v_display_start);
  390. vidc_writel(0x94000000 | vidc.v_display_end);
  391. vidc_writel(0x95000000 | vidc.v_border_end);
  392. vidc_writel(0x96000000);
  393. vidc_writel(0x97000000);
  394. }
  395. iomd_writel(fsize, IOMD_FSIZE);
  396. ext_ctl = acornfb_default_econtrol();
  397. if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
  398. ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC;
  399. else {
  400. if (var->sync & FB_SYNC_HOR_HIGH_ACT)
  401. ext_ctl |= VIDC20_ECTL_HS_HSYNC;
  402. else
  403. ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
  404. if (var->sync & FB_SYNC_VERT_HIGH_ACT)
  405. ext_ctl |= VIDC20_ECTL_VS_VSYNC;
  406. else
  407. ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
  408. }
  409. vidc_writel(VIDC20_ECTL | ext_ctl);
  410. words_per_line = var->xres * var->bits_per_pixel / 32;
  411. if (current_par.using_vram && current_par.screen_size == 2048*1024)
  412. words_per_line /= 2;
  413. /* RiscPC doesn't use the VIDC's VRAM control. */
  414. dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line;
  415. /* The data bus width is dependent on both the type
  416.  * and amount of video memory.
  417.  *     DRAM 32bit low
  418.  * 1MB VRAM 32bit
  419.  * 2MB VRAM 64bit
  420.  */
  421. if (current_par.using_vram && current_par.vram_half_sam == 2048) {
  422. dat_ctl |= VIDC20_DCTL_BUS_D63_0;
  423. } else 
  424. dat_ctl |= VIDC20_DCTL_BUS_D31_0;
  425. vidc_writel(VIDC20_DCTL | dat_ctl);
  426. #ifdef DEBUG_MODE_SELECTION
  427. printk(KERN_DEBUG "VIDC registers for %dx%dx%d:n", var->xres,
  428.        var->yres, var->bits_per_pixel);
  429. printk(KERN_DEBUG " H-cycle          : %dn", vidc.h_cycle);
  430. printk(KERN_DEBUG " H-sync-width     : %dn", vidc.h_sync_width);
  431. printk(KERN_DEBUG " H-border-start   : %dn", vidc.h_border_start);
  432. printk(KERN_DEBUG " H-display-start  : %dn", vidc.h_display_start);
  433. printk(KERN_DEBUG " H-display-end    : %dn", vidc.h_display_end);
  434. printk(KERN_DEBUG " H-border-end     : %dn", vidc.h_border_end);
  435. printk(KERN_DEBUG " H-interlace      : %dn", vidc.h_interlace);
  436. printk(KERN_DEBUG " V-cycle          : %dn", vidc.v_cycle);
  437. printk(KERN_DEBUG " V-sync-width     : %dn", vidc.v_sync_width);
  438. printk(KERN_DEBUG " V-border-start   : %dn", vidc.v_border_start);
  439. printk(KERN_DEBUG " V-display-start  : %dn", vidc.v_display_start);
  440. printk(KERN_DEBUG " V-display-end    : %dn", vidc.v_display_end);
  441. printk(KERN_DEBUG " V-border-end     : %dn", vidc.v_border_end);
  442. printk(KERN_DEBUG " Ext Ctrl  (C)    : 0x%08Xn", ext_ctl);
  443. printk(KERN_DEBUG " PLL Ctrl  (D)    : 0x%08Xn", vidc.pll_ctl);
  444. printk(KERN_DEBUG " Ctrl      (E)    : 0x%08Xn", vidc.control);
  445. printk(KERN_DEBUG " Data Ctrl (F)    : 0x%08Xn", dat_ctl);
  446. printk(KERN_DEBUG " Fsize            : 0x%08Xn", fsize);
  447. #endif
  448. }
  449. static inline void
  450. acornfb_palette_write(u_int regno, union palette pal)
  451. {
  452. vidc_writel(0x10000000 | regno);
  453. vidc_writel(pal.p);
  454. }
  455. static inline union palette
  456. acornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,
  457.        u_int trans)
  458. {
  459. union palette pal;
  460. pal.p = 0;
  461. pal.vidc20.red   = red >> 8;
  462. pal.vidc20.green = green >> 8;
  463. pal.vidc20.blue  = blue >> 8;
  464. return pal;
  465. }
  466. static void
  467. acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,
  468.        u_int *trans)
  469. {
  470. *red   = EXTEND8(current_par.palette[regno].vidc20.red);
  471. *green = EXTEND8(current_par.palette[regno].vidc20.green);
  472. *blue  = EXTEND8(current_par.palette[regno].vidc20.blue);
  473. *trans = EXTEND4(current_par.palette[regno].vidc20.ext);
  474. }
  475. #endif
  476. /*
  477.  * Before selecting the timing parameters, adjust
  478.  * the resolution to fit the rules.
  479.  */
  480. static int
  481. acornfb_adjust_timing(struct fb_var_screeninfo *var, int con)
  482. {
  483. u_int font_line_len;
  484. u_int fontht;
  485. u_int sam_size, min_size, size;
  486. u_int nr_y;
  487. /* xres must be even */
  488. var->xres = (var->xres + 1) & ~1;
  489. /*
  490.  * We don't allow xres_virtual to differ from xres
  491.  */
  492. var->xres_virtual = var->xres;
  493. var->xoffset = 0;
  494. /*
  495.  * Find the font height
  496.  */
  497. if (con == -1)
  498. fontht = fontheight(&global_disp);
  499. else
  500. fontht = fontheight(fb_display + con);
  501. if (fontht == 0)
  502. fontht = 8;
  503. if (current_par.using_vram)
  504. sam_size = current_par.vram_half_sam * 2;
  505. else
  506. sam_size = 16;
  507. /*
  508.  * Now, find a value for yres_virtual which allows
  509.  * us to do ywrap scrolling.  The value of
  510.  * yres_virtual must be such that the end of the
  511.  * displayable frame buffer must be aligned with
  512.  * the start of a font line.
  513.  */
  514. font_line_len = var->xres * var->bits_per_pixel * fontht / 8;
  515. min_size = var->xres * var->yres * var->bits_per_pixel / 8;
  516. /*
  517.  * If minimum screen size is greater than that we have
  518.  * available, reject it.
  519.  */
  520. if (min_size > current_par.screen_size)
  521. return -EINVAL;
  522. /* Find int 'y', such that y * fll == s * sam < maxsize
  523.  * y = s * sam / fll; s = maxsize / sam
  524.  */
  525. for (size = current_par.screen_size; min_size <= size;
  526.      size -= sam_size) {
  527. nr_y = size / font_line_len;
  528. if (nr_y * font_line_len == size)
  529. break;
  530. }
  531. if (var->accel_flags & FB_ACCELF_TEXT) {
  532. if (min_size > size) {
  533. /*
  534.  * failed, use ypan
  535.  */
  536. size = current_par.screen_size;
  537. var->yres_virtual = size / (font_line_len / fontht);
  538. } else
  539. var->yres_virtual = nr_y * fontht;
  540. }
  541. current_par.screen_end = current_par.screen_base_p + size;
  542. /*
  543.  * Fix yres & yoffset if needed.
  544.  */
  545. if (var->yres > var->yres_virtual)
  546. var->yres = var->yres_virtual;
  547. if (var->vmode & FB_VMODE_YWRAP) {
  548. if (var->yoffset > var->yres_virtual)
  549. var->yoffset = var->yres_virtual;
  550. } else {
  551. if (var->yoffset + var->yres > var->yres_virtual)
  552. var->yoffset = var->yres_virtual - var->yres;
  553. }
  554. /* hsync_len must be even */
  555. var->hsync_len = (var->hsync_len + 1) & ~1;
  556. #ifdef HAS_VIDC
  557. /* left_margin must be odd */
  558. if ((var->left_margin & 1) == 0) {
  559. var->left_margin -= 1;
  560. var->right_margin += 1;
  561. }
  562. /* right_margin must be odd */
  563. var->right_margin |= 1;
  564. #elif defined(HAS_VIDC20)
  565. /* left_margin must be even */
  566. if (var->left_margin & 1) {
  567. var->left_margin += 1;
  568. var->right_margin -= 1;
  569. }
  570. /* right_margin must be even */
  571. if (var->right_margin & 1)
  572. var->right_margin += 1;
  573. #endif
  574. if (var->vsync_len < 1)
  575. var->vsync_len = 1;
  576. return 0;
  577. }
  578. static int
  579. acornfb_validate_timing(struct fb_var_screeninfo *var,
  580. struct fb_monspecs *monspecs)
  581. {
  582. unsigned long hs, vs;
  583. /*
  584.  * hs(Hz) = 10^12 / (pixclock * xtotal)
  585.  * vs(Hz) = hs(Hz) / ytotal
  586.  *
  587.  * No need to do long long divisions or anything
  588.  * like that if you factor it correctly
  589.  */
  590. hs = 1953125000 / var->pixclock;
  591. hs = hs * 512 /
  592.      (var->xres + var->left_margin + var->right_margin + var->hsync_len);
  593. vs = hs /
  594.      (var->yres + var->upper_margin + var->lower_margin + var->vsync_len);
  595. return (vs >= monspecs->vfmin && vs <= monspecs->vfmax &&
  596. hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;
  597. }
  598. static inline void
  599. acornfb_update_dma(struct fb_var_screeninfo *var)
  600. {
  601. int off = (var->yoffset * var->xres_virtual *
  602.    var->bits_per_pixel) >> 3;
  603. #if defined(HAS_MEMC)
  604. memc_write(VDMA_INIT, off >> 2);
  605. #elif defined(HAS_IOMD)
  606. iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT);
  607. #endif
  608. }
  609. static int
  610. acornfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
  611.   u_int *trans, struct fb_info *info)
  612. {
  613. if (regno >= current_par.palette_size)
  614. return 1;
  615. acornfb_palette_decode(regno, red, green, blue, trans);
  616. return 0;
  617. }
  618. /*
  619.  * We have to take note of the VIDC20's 16-bit palette here.
  620.  * The VIDC20 looks up a 16 bit pixel as follows:
  621.  *
  622.  *   bits   111111
  623.  *          5432109876543210
  624.  *   red            ++++++++  (8 bits,  7 to 0)
  625.  *  green       ++++++++      (8 bits, 11 to 4)
  626.  *   blue   ++++++++          (8 bits, 15 to 8)
  627.  *
  628.  * We use a pixel which looks like:
  629.  *
  630.  *   bits   111111
  631.  *          5432109876543210
  632.  *   red               +++++  (5 bits,  4 to  0)
  633.  *  green         +++++       (5 bits,  9 to  5)
  634.  *   blue    +++++            (5 bits, 14 to 10)
  635.  */
  636. static int
  637. acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  638.   u_int trans, struct fb_info *info)
  639. {
  640. union palette pal;
  641. int bpp = fb_display[current_par.currcon].var.bits_per_pixel;
  642. if (regno >= current_par.palette_size)
  643. return 1;
  644. pal = acornfb_palette_encode(regno, red, green, blue, trans);
  645. current_par.palette[regno] = pal;
  646. #ifdef FBCON_HAS_CFB32
  647. if (bpp == 32 && regno < 16) {
  648. current_par.cmap.cfb32[regno] =
  649. regno | regno << 8 | regno << 16;
  650. }
  651. #endif
  652. #ifdef FBCON_HAS_CFB16
  653. if (bpp == 16 && regno < 16) {
  654. int i;
  655. current_par.cmap.cfb16[regno] =
  656. regno | regno << 5 | regno << 10;
  657. pal.p = 0;
  658. vidc_writel(0x10000000);
  659. for (i = 0; i < 256; i += 1) {
  660. pal.vidc20.red   = current_par.palette[ i       & 31].vidc20.red;
  661. pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
  662. pal.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;
  663. vidc_writel(pal.p);
  664. /* Palette register pointer auto-increments */
  665. }
  666. } else
  667. #endif
  668. acornfb_palette_write(regno, pal);
  669. return 0;
  670. }
  671. static int
  672. acornfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  673.  struct fb_info *info)
  674. {
  675. int err = 0;
  676. if (con == current_par.currcon)
  677. err = fb_get_cmap(cmap, kspc, acornfb_getcolreg, info);
  678. else if (fb_display[con].cmap.len)
  679. fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
  680. else
  681. fb_copy_cmap(fb_default_cmap(current_par.palette_size),
  682.      cmap, kspc ? 0 : 2);
  683. return err;
  684. }
  685. static int
  686. acornfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  687.  struct fb_info *info)
  688. {
  689. int err = 0;
  690. if (!fb_display[con].cmap.len)
  691. err = fb_alloc_cmap(&fb_display[con].cmap,
  692.     current_par.palette_size, 0);
  693. if (!err) {
  694. if (con == current_par.currcon)
  695. err = fb_set_cmap(cmap, kspc, acornfb_setcolreg,
  696.   info);
  697. else
  698. fb_copy_cmap(cmap, &fb_display[con].cmap,
  699.      kspc ? 0 : 1);
  700. }
  701. return err;
  702. }
  703. static int
  704. acornfb_decode_var(struct fb_var_screeninfo *var, int con)
  705. {
  706. int err;
  707. #if defined(HAS_VIDC20)
  708. var->red.offset    = 0;
  709. var->red.length    = 8;
  710. var->green         = var->red;
  711. var->blue          = var->red;
  712. var->transp.offset = 0;
  713. var->transp.length = 4;
  714. #elif defined(HAS_VIDC)
  715. var->red.length    = 4;
  716. var->green         = var->red;
  717. var->blue          = var->red;
  718. var->transp.length = 1;
  719. #endif
  720. switch (var->bits_per_pixel) {
  721. #ifdef FBCON_HAS_MFB
  722. case 1:
  723. break;
  724. #endif
  725. #ifdef FBCON_HAS_CFB2
  726. case 2:
  727. break;
  728. #endif
  729. #ifdef FBCON_HAS_CFB4
  730. case 4:
  731. break;
  732. #endif
  733. #ifdef FBCON_HAS_CFB8
  734. case 8:
  735. break;
  736. #endif
  737. #ifdef FBCON_HAS_CFB16
  738. case 16:
  739. var->red.offset    = 0;
  740. var->red.length    = 5;
  741. var->green.offset  = 5;
  742. var->green.length  = 5;
  743. var->blue.offset   = 10;
  744. var->blue.length   = 5;
  745. var->transp.offset = 15;
  746. var->transp.length = 1;
  747. break;
  748. #endif
  749. #ifdef FBCON_HAS_CFB32
  750. case 32:
  751. var->red.offset    = 0;
  752. var->red.length    = 8;
  753. var->green.offset  = 8;
  754. var->green.length  = 8;
  755. var->blue.offset   = 16;
  756. var->blue.length   = 8;
  757. var->transp.offset = 24;
  758. var->transp.length = 4;
  759. break;
  760. #endif
  761. default:
  762. return -EINVAL;
  763. }
  764. /*
  765.  * Check to see if the pixel rate is valid.
  766.  */
  767. if (!var->pixclock || !acornfb_valid_pixrate(var->pixclock))
  768. return -EINVAL;
  769. /*
  770.  * Validate and adjust the resolution to
  771.  * match the video generator hardware.
  772.  */
  773. err = acornfb_adjust_timing(var, con);
  774. if (err)
  775. return err;
  776. /*
  777.  * Validate the timing against the
  778.  * monitor hardware.
  779.  */
  780. return acornfb_validate_timing(var, &fb_info.monspecs);
  781. }
  782. static int
  783. acornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
  784. {
  785. struct display *display;
  786. memset(fix, 0, sizeof(struct fb_fix_screeninfo));
  787. strcpy(fix->id, "Acorn");
  788. if (con >= 0)
  789. display = fb_display + con;
  790. else
  791. display = &global_disp;
  792. fix->smem_start  = current_par.screen_base_p;
  793. fix->smem_len  = current_par.screen_size;
  794. fix->type  = display->type;
  795. fix->type_aux  = display->type_aux;
  796. fix->xpanstep  = 0;
  797. fix->ypanstep  = display->ypanstep;
  798. fix->ywrapstep  = display->ywrapstep;
  799. fix->visual  = display->visual;
  800. fix->line_length = display->line_length;
  801. fix->accel  = FB_ACCEL_NONE;
  802. return 0;
  803. }
  804. static int
  805. acornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
  806. {
  807. if (con == -1) {
  808. *var = global_disp.var;
  809. } else
  810. *var = fb_display[con].var;
  811. return 0;
  812. }
  813. static int
  814. acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
  815. {
  816. struct display *display;
  817. int err, chgvar = 0;
  818. if (con >= 0)
  819. display = fb_display + con;
  820. else
  821. display = &global_disp;
  822. err = acornfb_decode_var(var, con);
  823. if (err)
  824. return err;
  825. switch (var->activate & FB_ACTIVATE_MASK) {
  826. case FB_ACTIVATE_TEST:
  827. return 0;
  828. case FB_ACTIVATE_NXTOPEN:
  829. case FB_ACTIVATE_NOW:
  830. break;
  831. default:
  832. return -EINVAL;
  833. }
  834. if (con >= 0) {
  835. if (display->var.xres != var->xres)
  836. chgvar = 1;
  837. if (display->var.yres != var->yres)
  838. chgvar = 1;
  839. if (display->var.xres_virtual != var->xres_virtual)
  840. chgvar = 1;
  841. if (display->var.yres_virtual != var->yres_virtual)
  842. chgvar = 1;
  843. if (memcmp(&display->var.red, &var->red, sizeof(var->red)))
  844. chgvar = 1;
  845. if (memcmp(&display->var.green, &var->green, sizeof(var->green)))
  846. chgvar = 1;
  847. if (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))
  848. chgvar = 1;
  849. }
  850. display->var = *var;
  851. display->var.activate &= ~FB_ACTIVATE_ALL;
  852. if (var->activate & FB_ACTIVATE_ALL)
  853. global_disp.var = display->var;
  854. switch (display->var.bits_per_pixel) {
  855. #ifdef FBCON_HAS_MFB
  856. case 1:
  857. current_par.palette_size = 2;
  858. display->dispsw = &fbcon_mfb;
  859. display->visual = FB_VISUAL_MONO10;
  860. break;
  861. #endif
  862. #ifdef FBCON_HAS_CFB2
  863. case 2:
  864. current_par.palette_size = 4;
  865. display->dispsw = &fbcon_cfb2;
  866. display->visual = FB_VISUAL_PSEUDOCOLOR;
  867. break;
  868. #endif
  869. #ifdef FBCON_HAS_CFB4
  870. case 4:
  871. current_par.palette_size = 16;
  872. display->dispsw = &fbcon_cfb4;
  873. display->visual = FB_VISUAL_PSEUDOCOLOR;
  874. break;
  875. #endif
  876. #ifdef FBCON_HAS_CFB8
  877. case 8:
  878. current_par.palette_size = VIDC_PALETTE_SIZE;
  879. display->dispsw = &fbcon_cfb8;
  880. #ifdef HAS_VIDC
  881. display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
  882. #else
  883. display->visual = FB_VISUAL_PSEUDOCOLOR;
  884. #endif
  885. break;
  886. #endif
  887. #ifdef FBCON_HAS_CFB16
  888. case 16:
  889. current_par.palette_size = 32;
  890. display->dispsw = &fbcon_cfb16;
  891. display->dispsw_data = current_par.cmap.cfb16;
  892. display->visual = FB_VISUAL_DIRECTCOLOR;
  893. break;
  894. #endif
  895. #ifdef FBCON_HAS_CFB32
  896. case 32:
  897. current_par.palette_size = VIDC_PALETTE_SIZE;
  898. display->dispsw = &fbcon_cfb32;
  899. display->dispsw_data = current_par.cmap.cfb32;
  900. display->visual = FB_VISUAL_TRUECOLOR;
  901. break;
  902. #endif
  903. default:
  904. display->dispsw = &fbcon_dummy;
  905. break;
  906. }
  907. display->screen_base = (char *)current_par.screen_base;
  908. display->type = FB_TYPE_PACKED_PIXELS;
  909. display->type_aux = 0;
  910. display->ypanstep = 1;
  911. display->ywrapstep = 1;
  912. display->line_length =
  913. display->next_line      = (var->xres * var->bits_per_pixel) / 8;
  914. display->can_soft_blank = display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
  915. display->inverse = 0;
  916. if (chgvar && info && info->changevar)
  917. info->changevar(con);
  918. if (con == current_par.currcon) {
  919. struct fb_cmap *cmap;
  920. unsigned long start, size;
  921. int control;
  922. #if defined(HAS_MEMC)
  923. start   = 0;
  924. size    = current_par.screen_size - VDMA_XFERSIZE;
  925. control = 0;
  926. memc_write(VDMA_START, start);
  927. memc_write(VDMA_END, size >> 2);
  928. #elif defined(HAS_IOMD)
  929. start = current_par.screen_base_p;
  930. size  = current_par.screen_end;
  931. if (current_par.using_vram) {
  932. size -= current_par.vram_half_sam;
  933. control = DMA_CR_E | (current_par.vram_half_sam / 256);
  934. } else {
  935. size -= 16;
  936. control = DMA_CR_E | DMA_CR_D | 16;
  937. }
  938. iomd_writel(start,   IOMD_VIDSTART);
  939. iomd_writel(size,    IOMD_VIDEND);
  940. iomd_writel(control, IOMD_VIDCR);
  941. #endif
  942. acornfb_update_dma(var);
  943. acornfb_set_timing(var);
  944. if (display->cmap.len)
  945. cmap = &display->cmap;
  946. else
  947. cmap = fb_default_cmap(current_par.palette_size);
  948. fb_set_cmap(cmap, 1, acornfb_setcolreg, info);
  949. }
  950. return 0;
  951. }
  952. static int
  953. acornfb_pan_display(struct fb_var_screeninfo *var, int con,
  954.     struct fb_info *info)
  955. {
  956. u_int y_bottom;
  957. if (var->xoffset)
  958. return -EINVAL;
  959. y_bottom = var->yoffset;
  960. if (!(var->vmode & FB_VMODE_YWRAP))
  961. y_bottom += var->yres;
  962. if (y_bottom > fb_display[con].var.yres_virtual)
  963. return -EINVAL;
  964. acornfb_update_dma(var);
  965. fb_display[con].var.yoffset = var->yoffset;
  966. if (var->vmode & FB_VMODE_YWRAP)
  967. fb_display[con].var.vmode |= FB_VMODE_YWRAP;
  968. else
  969. fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
  970. return 0;
  971. }
  972. /*
  973.  * Note that we are entered with the kernel locked.
  974.  */
  975. static int
  976. acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
  977. {
  978. unsigned long off, start;
  979. u32 len;
  980. off = vma->vm_pgoff << PAGE_SHIFT;
  981. start = current_par.screen_base_p;
  982. len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size;
  983. start &= PAGE_MASK;
  984. if ((vma->vm_end - vma->vm_start + off) > len)
  985. return -EINVAL;
  986. off += start;
  987. vma->vm_pgoff = off >> PAGE_SHIFT;
  988. /* This is an IO map - tell maydump to skip this VMA */
  989. vma->vm_flags |= VM_IO;
  990. #ifdef CONFIG_CPU_32
  991. pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE;
  992. #endif
  993. /*
  994.  * Don't alter the page protection flags; we want to keep the area
  995.  * cached for better performance.  This does mean that we may miss
  996.  * some updates to the screen occasionally, but process switches
  997.  * should cause the caches and buffers to be flushed often enough.
  998.  */
  999. if (io_remap_page_range(vma->vm_start, off,
  1000. vma->vm_end - vma->vm_start,
  1001. vma->vm_page_prot))
  1002. return -EAGAIN;
  1003. return 0;
  1004. }
  1005. static struct fb_ops acornfb_ops = {
  1006. owner: THIS_MODULE,
  1007. fb_get_fix: acornfb_get_fix,
  1008. fb_get_var: acornfb_get_var,
  1009. fb_set_var: acornfb_set_var,
  1010. fb_get_cmap: acornfb_get_cmap,
  1011. fb_set_cmap: acornfb_set_cmap,
  1012. fb_pan_display: acornfb_pan_display,
  1013. fb_mmap: acornfb_mmap,
  1014. };
  1015. static int
  1016. acornfb_updatevar(int con, struct fb_info *info)
  1017. {
  1018. if (con == current_par.currcon)
  1019. acornfb_update_dma(&fb_display[con].var);
  1020. return 0;
  1021. }
  1022. static int
  1023. acornfb_switch(int con, struct fb_info *info)
  1024. {
  1025. struct fb_cmap *cmap;
  1026. if (current_par.currcon >= 0) {
  1027. cmap = &fb_display[current_par.currcon].cmap;
  1028. if (cmap->len)
  1029. fb_get_cmap(cmap, 1, acornfb_getcolreg, info);
  1030. }
  1031. current_par.currcon = con;
  1032. fb_display[con].var.activate = FB_ACTIVATE_NOW;
  1033. acornfb_set_var(&fb_display[con].var, con, info);
  1034. return 0;
  1035. }
  1036. static void
  1037. acornfb_blank(int blank, struct fb_info *info)
  1038. {
  1039. union palette p;
  1040. int i, bpp = fb_display[current_par.currcon].var.bits_per_pixel;
  1041. #ifdef FBCON_HAS_CFB16
  1042. if (bpp == 16) {
  1043. p.p = 0;
  1044. for (i = 0; i < 256; i++) {
  1045. if (blank)
  1046. p = acornfb_palette_encode(i, 0, 0, 0, 0);
  1047. else {
  1048. p.vidc20.red   = current_par.palette[ i       & 31].vidc20.red;
  1049. p.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
  1050. p.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;
  1051. }
  1052. acornfb_palette_write(i, current_par.palette[i]);
  1053. }
  1054. } else
  1055. #endif
  1056. {
  1057. for (i = 0; i < current_par.palette_size; i++) {
  1058. if (blank)
  1059. p = acornfb_palette_encode(i, 0, 0, 0, 0);
  1060. else
  1061. p = current_par.palette[i];
  1062. acornfb_palette_write(i, p);
  1063. }
  1064. }
  1065. }
  1066. /*
  1067.  * Everything after here is initialisation!!!
  1068.  */
  1069. static struct fb_videomode modedb[] __initdata = {
  1070. { /* 320x256 @ 50Hz */
  1071. NULL, 50,  320,  256, 125000,  92,  62,  35, 19,  38, 2,
  1072. FB_SYNC_COMP_HIGH_ACT,
  1073. FB_VMODE_NONINTERLACED
  1074. }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */
  1075. NULL, 50,  640,  250,  62500, 185, 123,  38, 21,  76, 3,
  1076. 0,
  1077. FB_VMODE_NONINTERLACED
  1078. }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */
  1079. NULL, 50,  640,  256,  62500, 185, 123,  35, 18,  76, 3,
  1080. 0,
  1081. FB_VMODE_NONINTERLACED
  1082. }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */
  1083. NULL, 50,  640,  512,  41667, 113,  87,  18,  1,  56, 3,
  1084. 0,
  1085. FB_VMODE_NONINTERLACED
  1086. }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */
  1087. NULL, 70,  640,  250,  39722,  48,  16, 109, 88,  96, 2,
  1088. 0,
  1089. FB_VMODE_NONINTERLACED
  1090. }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */
  1091. NULL, 70,  640,  256,  39722,  48,  16, 106, 85,  96, 2,
  1092. 0,
  1093. FB_VMODE_NONINTERLACED
  1094. }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */
  1095. NULL, 70,  640,  352,  39722,  48,  16,  58, 37,  96, 2,
  1096. 0,
  1097. FB_VMODE_NONINTERLACED
  1098. }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */
  1099. NULL, 60,  640,  480,  39722,  48,  16,  32, 11,  96, 2,
  1100. 0,
  1101. FB_VMODE_NONINTERLACED
  1102. }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */
  1103. NULL, 56,  800,  600,  27778, 101,  23,  22,  1, 100, 2,
  1104. 0,
  1105. FB_VMODE_NONINTERLACED
  1106. }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */
  1107. NULL, 60,  896,  352,  41667,  59,  27,   9,  0, 118, 3,
  1108. 0,
  1109. FB_VMODE_NONINTERLACED
  1110. }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */
  1111. NULL, 60, 1024,  768,  15385, 160,  24,  29,  3, 136, 6,
  1112. 0,
  1113. FB_VMODE_NONINTERLACED
  1114. }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */
  1115. NULL, 60, 1280, 1024,   9090, 186,  96,  38,  1, 160, 3,
  1116. 0,
  1117. FB_VMODE_NONINTERLACED
  1118. }
  1119. };
  1120. static struct fb_videomode __initdata
  1121. acornfb_default_mode = {
  1122. name: NULL,
  1123. refresh: 60,
  1124. xres: 640,
  1125. yres: 480,
  1126. pixclock: 39722,
  1127. left_margin: 56,
  1128. right_margin: 16,
  1129. upper_margin: 34,
  1130. lower_margin: 9,
  1131. hsync_len: 88,
  1132. vsync_len: 2,
  1133. sync: 0,
  1134. vmode: FB_VMODE_NONINTERLACED
  1135. };
  1136. static void __init
  1137. acornfb_init_fbinfo(void)
  1138. {
  1139. static int first = 1;
  1140. if (!first)
  1141. return;
  1142. first = 0;
  1143. strcpy(fb_info.modename, "Acorn");
  1144. strcpy(fb_info.fontname, "Acorn8x8");
  1145. fb_info.node    = -1;
  1146. fb_info.fbops    = &acornfb_ops;
  1147. fb_info.disp    = &global_disp;
  1148. fb_info.changevar    = NULL;
  1149. fb_info.switch_con    = acornfb_switch;
  1150. fb_info.updatevar    = acornfb_updatevar;
  1151. fb_info.blank    = acornfb_blank;
  1152. fb_info.flags    = FBINFO_FLAG_DEFAULT;
  1153. global_disp.dispsw    = &fbcon_dummy;
  1154. /*
  1155.  * setup initial parameters
  1156.  */
  1157. memset(&init_var, 0, sizeof(init_var));
  1158. #if defined(HAS_VIDC20)
  1159. init_var.red.length    = 8;
  1160. init_var.transp.length    = 4;
  1161. #elif defined(HAS_VIDC)
  1162. init_var.red.length    = 4;
  1163. init_var.transp.length    = 1;
  1164. #endif
  1165. init_var.green    = init_var.red;
  1166. init_var.blue    = init_var.red;
  1167. init_var.nonstd    = 0;
  1168. init_var.activate    = FB_ACTIVATE_NOW;
  1169. init_var.height    = -1;
  1170. init_var.width    = -1;
  1171. init_var.vmode    = FB_VMODE_NONINTERLACED;
  1172. init_var.accel_flags    = FB_ACCELF_TEXT;
  1173. current_par.dram_size    = 0;
  1174. current_par.montype    = -1;
  1175. current_par.dpms    = 0;
  1176. }
  1177. /*
  1178.  * setup acornfb options:
  1179.  *
  1180.  *  font:fontname
  1181.  * Set fontname
  1182.  *
  1183.  *  mon:hmin-hmax:vmin-vmax:dpms:width:height
  1184.  * Set monitor parameters:
  1185.  * hmin   = horizontal minimum frequency (Hz)
  1186.  * hmax   = horizontal maximum frequency (Hz) (optional)
  1187.  * vmin   = vertical minimum frequency (Hz)
  1188.  * vmax   = vertical maximum frequency (Hz) (optional)
  1189.  * dpms   = DPMS supported? (optional)
  1190.  * width  = width of picture in mm. (optional)
  1191.  * height = height of picture in mm. (optional)
  1192.  *
  1193.  * montype:type
  1194.  * Set RISC-OS style monitor type:
  1195.  * 0 (or tv) - TV frequency
  1196.  * 1 (or multi) - Multi frequency
  1197.  * 2 (or hires) - Hi-res monochrome
  1198.  * 3 (or vga) - VGA
  1199.  * 4 (or svga) - SVGA
  1200.  * auto, or option missing
  1201.  * - try hardware detect
  1202.  *
  1203.  * dram:size
  1204.  * Set the amount of DRAM to use for the frame buffer
  1205.  * (even if you have VRAM).
  1206.  * size can optionally be followed by 'M' or 'K' for
  1207.  * MB or KB respectively.
  1208.  */
  1209. static void __init
  1210. acornfb_parse_font(char *opt)
  1211. {
  1212. strcpy(fb_info.fontname, opt);
  1213. }
  1214. static void __init
  1215. acornfb_parse_mon(char *opt)
  1216. {
  1217. char *p = opt;
  1218. current_par.montype = -2;
  1219. fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0);
  1220. if (*p == '-')
  1221. fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0);
  1222. else
  1223. fb_info.monspecs.hfmax = fb_info.monspecs.hfmin;
  1224. if (*p != ':')
  1225. goto bad;
  1226. fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0);
  1227. if (*p == '-')
  1228. fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0);
  1229. else
  1230. fb_info.monspecs.vfmax = fb_info.monspecs.vfmin;
  1231. if (*p != ':')
  1232. goto check_values;
  1233. fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0);
  1234. if (*p != ':')
  1235. goto check_values;
  1236. init_var.width = simple_strtoul(p + 1, &p, 0);
  1237. if (*p != ':')
  1238. goto check_values;
  1239. init_var.height = simple_strtoul(p + 1, NULL, 0);
  1240. check_values:
  1241. if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin ||
  1242.     fb_info.monspecs.vfmax < fb_info.monspecs.vfmin)
  1243. goto bad;
  1244. return;
  1245. bad:
  1246. printk(KERN_ERR "Acornfb: bad monitor settings: %sn", opt);
  1247. current_par.montype = -1;
  1248. }
  1249. static void __init
  1250. acornfb_parse_montype(char *opt)
  1251. {
  1252. current_par.montype = -2;
  1253. if (strncmp(opt, "tv", 2) == 0) {
  1254. opt += 2;
  1255. current_par.montype = 0;
  1256. } else if (strncmp(opt, "multi", 5) == 0) {
  1257. opt += 5;
  1258. current_par.montype = 1;
  1259. } else if (strncmp(opt, "hires", 5) == 0) {
  1260. opt += 5;
  1261. current_par.montype = 2;
  1262. } else if (strncmp(opt, "vga", 3) == 0) {
  1263. opt += 3;
  1264. current_par.montype = 3;
  1265. } else if (strncmp(opt, "svga", 4) == 0) {
  1266. opt += 4;
  1267. current_par.montype = 4;
  1268. } else if (strncmp(opt, "auto", 4) == 0) {
  1269. opt += 4;
  1270. current_par.montype = -1;
  1271. } else if (isdigit(*opt))
  1272. current_par.montype = simple_strtoul(opt, &opt, 0);
  1273. if (current_par.montype == -2 ||
  1274.     current_par.montype > NR_MONTYPES) {
  1275. printk(KERN_ERR "acornfb: unknown monitor type: %sn",
  1276. opt);
  1277. current_par.montype = -1;
  1278. } else
  1279. if (opt && *opt) {
  1280. if (strcmp(opt, ",dpms") == 0)
  1281. current_par.dpms = 1;
  1282. else
  1283. printk(KERN_ERR
  1284.        "acornfb: unknown monitor option: %sn",
  1285.        opt);
  1286. }
  1287. }
  1288. static void __init
  1289. acornfb_parse_dram(char *opt)
  1290. {
  1291. unsigned int size;
  1292. size = simple_strtoul(opt, &opt, 0);
  1293. if (opt) {
  1294. switch (*opt) {
  1295. case 'M':
  1296. case 'm':
  1297. size *= 1024;
  1298. case 'K':
  1299. case 'k':
  1300. size *= 1024;
  1301. default:
  1302. break;
  1303. }
  1304. }
  1305. current_par.dram_size = size;
  1306. }
  1307. static struct options {
  1308. char *name;
  1309. void (*parse)(char *opt);
  1310. } opt_table[] __initdata = {
  1311. { "font",    acornfb_parse_font    },
  1312. { "mon",     acornfb_parse_mon     },
  1313. { "montype", acornfb_parse_montype },
  1314. { "dram",    acornfb_parse_dram    },
  1315. { NULL, NULL }
  1316. };
  1317. int __init
  1318. acornfb_setup(char *options)
  1319. {
  1320. struct options *optp;
  1321. char *opt;
  1322. if (!options || !*options)
  1323. return 0;
  1324. acornfb_init_fbinfo();
  1325. while ((opt = strsep(&options, ",")) != NULL) {
  1326. if (!*opt)
  1327. continue;
  1328. for (optp = opt_table; optp->name; optp++) {
  1329. int optlen;
  1330. optlen = strlen(optp->name);
  1331. if (strncmp(opt, optp->name, optlen) == 0 &&
  1332.     opt[optlen] == ':') {
  1333. optp->parse(opt + optlen + 1);
  1334. break;
  1335. }
  1336. }
  1337. if (!optp->name)
  1338. printk(KERN_ERR "acornfb: unknown parameter: %sn",
  1339.        opt);
  1340. }
  1341. return 0;
  1342. }
  1343. /*
  1344.  * Detect type of monitor connected
  1345.  *  For now, we just assume SVGA
  1346.  */
  1347. static int __init
  1348. acornfb_detect_monitortype(void)
  1349. {
  1350. return 4;
  1351. }
  1352. /*
  1353.  * This enables the unused memory to be freed on older Acorn machines.
  1354.  */
  1355. static inline void
  1356. free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
  1357. {
  1358. int mb_freed = 0;
  1359. /*
  1360.  * Align addresses
  1361.  */
  1362. virtual_start = PAGE_ALIGN(virtual_start);
  1363. virtual_end = PAGE_ALIGN(virtual_end);
  1364. while (virtual_start < virtual_end) {
  1365. struct page *page;
  1366. /*
  1367.  * Clear page reserved bit,
  1368.  * set count to 1, and free
  1369.  * the page.
  1370.  */
  1371. page = virt_to_page(virtual_start);
  1372. ClearPageReserved(page);
  1373. atomic_set(&page->count, 1);
  1374. free_page(virtual_start);
  1375. virtual_start += PAGE_SIZE;
  1376. mb_freed += PAGE_SIZE / 1024;
  1377. }
  1378. printk("acornfb: freed %dK memoryn", mb_freed);
  1379. }
  1380. int __init
  1381. acornfb_init(void)
  1382. {
  1383. unsigned long size;
  1384. u_int h_sync, v_sync;
  1385. int rc, i;
  1386. acornfb_init_fbinfo();
  1387. if (current_par.montype == -1)
  1388. current_par.montype = acornfb_detect_monitortype();
  1389. if (current_par.montype == -1 || current_par.montype > NR_MONTYPES)
  1390. current_par.montype = 4;
  1391. if (current_par.montype >= 0) {
  1392. fb_info.monspecs = monspecs[current_par.montype];
  1393. fb_info.monspecs.dpms = current_par.dpms;
  1394. }
  1395. /*
  1396.  * Try to select a suitable default mode
  1397.  */
  1398. for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) {
  1399. unsigned long hs;
  1400. hs = modedb[i].refresh *
  1401.      (modedb[i].yres + modedb[i].upper_margin +
  1402.       modedb[i].lower_margin + modedb[i].vsync_len);
  1403. if (modedb[i].xres == DEFAULT_XRES &&
  1404.     modedb[i].yres == DEFAULT_YRES &&
  1405.     modedb[i].refresh >= fb_info.monspecs.vfmin &&
  1406.     modedb[i].refresh <= fb_info.monspecs.vfmax &&
  1407.     hs                >= fb_info.monspecs.hfmin &&
  1408.     hs                <= fb_info.monspecs.hfmax) {
  1409. acornfb_default_mode = modedb[i];
  1410. break;
  1411. }
  1412. }
  1413. current_par.currcon    = -1;
  1414. current_par.screen_base    = SCREEN_BASE;
  1415. current_par.screen_base_p  = SCREEN_START;
  1416. current_par.using_vram     = 0;
  1417. /*
  1418.  * If vram_size is set, we are using VRAM in
  1419.  * a Risc PC.  However, if the user has specified
  1420.  * an amount of DRAM then use that instead.
  1421.  */
  1422. if (vram_size && !current_par.dram_size) {
  1423. size = vram_size;
  1424. current_par.vram_half_sam = vram_size / 1024;
  1425. current_par.using_vram = 1;
  1426. } else if (current_par.dram_size)
  1427. size = current_par.dram_size;
  1428. else
  1429. size = MAX_SIZE;
  1430. /*
  1431.  * Limit maximum screen size.
  1432.  */
  1433. if (size > MAX_SIZE)
  1434. size = MAX_SIZE;
  1435. size = PAGE_ALIGN(size);
  1436. #if defined(HAS_VIDC20)
  1437. if (!current_par.using_vram) {
  1438. /*
  1439.  * RiscPC needs to allocate the DRAM memory
  1440.  * for the framebuffer if we are not using
  1441.  * VRAM.  Archimedes/A5000 machines use a
  1442.  * fixed address for their framebuffers.
  1443.  */
  1444. int order = 0;
  1445. unsigned long page, top;
  1446. while (size > (PAGE_SIZE * (1 << order)))
  1447. order++;
  1448. current_par.screen_base = __get_free_pages(GFP_KERNEL, order);
  1449. if (current_par.screen_base == 0) {
  1450. printk(KERN_ERR "acornfb: unable to allocate screen "
  1451.        "memoryn");
  1452. return -ENOMEM;
  1453. }
  1454. top = current_par.screen_base + (PAGE_SIZE * (1 << order));
  1455. /* Mark the framebuffer pages as reserved so mmap will work. */
  1456. for (page = current_par.screen_base; 
  1457.      page < PAGE_ALIGN(current_par.screen_base + size);
  1458.      page += PAGE_SIZE)
  1459. SetPageReserved(virt_to_page(page));
  1460. /* Hand back any excess pages that we allocated. */
  1461. for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE)
  1462. free_page(page);
  1463. current_par.screen_base_p =
  1464. virt_to_phys((void *)current_par.screen_base);
  1465. }
  1466. #endif
  1467. #if defined(HAS_VIDC)
  1468. /*
  1469.  * Free unused pages
  1470.  */
  1471. free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
  1472. #endif
  1473. current_par.screen_size    = size;
  1474. current_par.palette_size   = VIDC_PALETTE_SIZE;
  1475. /*
  1476.  * Lookup the timing for this resolution.  If we can't
  1477.  * find it, then we can't restore it if we change
  1478.  * the resolution, so we disable this feature.
  1479.  */
  1480. do {
  1481. rc = fb_find_mode(&init_var, &fb_info, NULL, modedb,
  1482.  sizeof(modedb) / sizeof(*modedb),
  1483.  &acornfb_default_mode, DEFAULT_BPP);
  1484. /*
  1485.  * If we found an exact match, all ok.
  1486.  */
  1487. if (rc == 1)
  1488. break;
  1489. rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0,
  1490.   &acornfb_default_mode, DEFAULT_BPP);
  1491. /*
  1492.  * If we found an exact match, all ok.
  1493.  */
  1494. if (rc == 1)
  1495. break;
  1496. rc = fb_find_mode(&init_var, &fb_info, NULL, modedb,
  1497.  sizeof(modedb) / sizeof(*modedb),
  1498.  &acornfb_default_mode, DEFAULT_BPP);
  1499. if (rc)
  1500. break;
  1501. rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0,
  1502.   &acornfb_default_mode, DEFAULT_BPP);
  1503. } while (0);
  1504. /*
  1505.  * If we didn't find an exact match, try the
  1506.  * generic database.
  1507.  */
  1508. if (rc == 0) {
  1509. printk("Acornfb: no valid mode foundn");
  1510. return -EINVAL;
  1511. }
  1512. h_sync = 1953125000 / init_var.pixclock;
  1513. h_sync = h_sync * 512 / (init_var.xres + init_var.left_margin +
  1514.  init_var.right_margin + init_var.hsync_len);
  1515. v_sync = h_sync / (init_var.yres + init_var.upper_margin +
  1516.  init_var.lower_margin + init_var.vsync_len);
  1517. printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, "
  1518. "%d.%03dkHz, %dHzn",
  1519. current_par.screen_size / 1024,
  1520. current_par.using_vram ? 'V' : 'D',
  1521. VIDC_NAME, init_var.xres, init_var.yres,
  1522. h_sync / 1000, h_sync % 1000, v_sync);
  1523. printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%sn",
  1524. fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000,
  1525. fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000,
  1526. fb_info.monspecs.vfmin, fb_info.monspecs.vfmax,
  1527. fb_info.monspecs.dpms ? ", DPMS" : "");
  1528. if (acornfb_set_var(&init_var, -1, &fb_info))
  1529. printk(KERN_ERR "Acornfb: unable to set display parametersn");
  1530. if (register_framebuffer(&fb_info) < 0)
  1531. return -EINVAL;
  1532. return 0;
  1533. }
  1534. MODULE_AUTHOR("Russell King");
  1535. MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver");
  1536. MODULE_LICENSE("GPL");
  1537. EXPORT_NO_SYMBOLS;