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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/drivers/video/epson1355fb.c
  3.  * -- Support for the Epson SED1355 LCD/CRT controller
  4.  *
  5.  * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
  6.  *
  7.  * based on linux/drivers/video/skeletonfb.c, which was
  8.  *  Created 28 Dec 1997 by Geert Uytterhoeven
  9.  *
  10.  * This file is subject to the terms and conditions of the GNU General Public
  11.  * License.  See the file COPYING in the main directory of this archive
  12.  * for more details.
  13.  */
  14. /* TODO (roughly in order of priority):
  15.  * 16 bpp support
  16.  * crt support
  17.  * hw cursor support
  18.  * SwivelView
  19.  */
  20. #include <asm/io.h>
  21. #include <linux/config.h>
  22. #include <linux/delay.h>
  23. #include <linux/errno.h>
  24. #include <linux/fb.h>
  25. #include <linux/init.h>
  26. #include <linux/kernel.h>
  27. #include <linux/slab.h>
  28. #include <linux/mm.h>
  29. #include <linux/module.h>
  30. #include <linux/sched.h>
  31. #include <linux/string.h>
  32. #include <linux/tty.h>
  33. #include <video/fbcon-cfb8.h>
  34. #include <video/fbcon-mfb.h>
  35. #include <video/fbcon.h>
  36. /* Register defines.  The docs don't seem to provide nice mnemonic names
  37.  * so I made them up myself ... */
  38. #define E1355_PANEL 0x02
  39. #define E1355_DISPLAY 0x0D
  40. #define E1355_MISC 0x1B
  41. #define E1355_GPIO 0x20
  42. #define E1355_LUT_INDEX 0x24
  43. #define E1355_LUT_DATA 0x26
  44. #ifdef CONFIG_SUPERH
  45. #define E1355_REG_BASE CONFIG_E1355_REG_BASE
  46. #define E1355_FB_BASE CONFIG_E1355_FB_BASE
  47. static inline u8 e1355_read_reg(int index)
  48. {
  49. return ctrl_inb(E1355_REG_BASE + index);
  50. }
  51. static inline void e1355_write_reg(u8 data, int index)
  52. {
  53. ctrl_outb(data, E1355_REG_BASE + index);
  54. }
  55. static inline u16 e1355_read_reg16(int index)
  56. {
  57. return e1355_read_reg(index) + (e1355_read_reg(index+1) << 8);
  58. }
  59. static inline void e1355_write_reg16(u16 data, int index)
  60. {
  61. e1355_write_reg((data&0xff), index);
  62. e1355_write_reg(((data>>8)&0xff), index + 1);
  63. }
  64. #else
  65. #error unknown architecture
  66. #endif
  67. struct e1355fb_info {
  68. struct fb_info_gen gen;
  69. };
  70. static int current_par_valid = 0;
  71. static struct display disp;
  72. static struct fb_var_screeninfo default_var;
  73. int e1355fb_init(void);
  74. int e1355fb_setup(char*);
  75. static int e1355_encode_var(struct fb_var_screeninfo *var, const void *par,
  76.     struct fb_info_gen *info);
  77. /* ------------------- chipset specific functions -------------------------- */
  78. static void disable_hw_cursor(void)
  79. {
  80. u8 curs;
  81. curs = e1355_read_reg(0x27);
  82. curs &= ~0xc0;
  83. e1355_write_reg(curs, 0x27);
  84. }
  85. static void e1355_detect(void)
  86. {
  87. u8 rev;
  88. e1355_write_reg(0x00, E1355_MISC);
  89. rev = e1355_read_reg(0x00);
  90. if ((rev & 0xfc) != 0x0c) {
  91. printk(KERN_WARNING "Epson 1355 not detectedn");
  92. }
  93. /* XXX */
  94. disable_hw_cursor();
  95. e1355_encode_var(&default_var, NULL, NULL);
  96. }
  97. struct e1355_par {
  98. u32 xres;
  99. u32 yres;
  100. int bpp;
  101. int mem_bpp;
  102. u32 panel_xres;
  103. u32 panel_yres;
  104. int panel_width;
  105. int panel_ymul;
  106. };
  107. static int e1355_encode_fix(struct fb_fix_screeninfo *fix,
  108.     const void *raw_par,
  109.     struct fb_info_gen *info)
  110. {
  111. const struct e1355_par *par = raw_par;
  112. memset(fix, 0, sizeof *fix);
  113. fix->type= FB_TYPE_PACKED_PIXELS;
  114. if (!par)
  115. BUG();
  116. if (par->bpp == 1) {
  117. fix->visual = FB_VISUAL_MONO10;
  118. } else if (par->bpp <= 8) {
  119. fix->visual = FB_VISUAL_PSEUDOCOLOR;
  120. } else {
  121. fix->visual = FB_VISUAL_TRUECOLOR;
  122. }
  123. return 0;
  124. }
  125. static int e1355_set_bpp(struct e1355_par *par, int bpp)
  126. {
  127. int code;
  128. u8 disp;
  129. u16 bytes_per_line;
  130. switch(bpp) {
  131. case 1:
  132. code = 0; break;
  133. case 2:
  134. code = 1; break;
  135. case 4:
  136. code = 2; break;
  137. case 8:
  138. code = 3; break;
  139. case 16:
  140. code = 5; break;
  141. default:
  142. return -EINVAL; break;
  143. }
  144. disp = e1355_read_reg(E1355_DISPLAY);
  145. disp &= ~0x1c;
  146. disp |= code << 2;
  147. e1355_write_reg(disp, E1355_DISPLAY);
  148. bytes_per_line = (par->xres * bpp) >> 3;
  149. e1355_write_reg16(bytes_per_line, 0x16);
  150. par->bpp = bpp;
  151. return 0;
  152. }
  153. static int e1355_decode_var(const struct fb_var_screeninfo *var,
  154.     void *raw_par,
  155.     struct fb_info_gen *info)
  156. {
  157. struct e1355_par *par = raw_par;
  158. int ret;
  159. if (!par)
  160. BUG();
  161. /*
  162.  * Don't allow setting any of these yet: xres and yres don't
  163.  * make sense for LCD panels; xres_virtual and yres_virtual
  164.  * should be supported fine by our hardware though.
  165.  */
  166. if (var->xres != par->xres ||
  167.     var->yres != par->yres ||
  168.     var->xres != var->xres_virtual ||
  169.     var->yres != var->yres_virtual ||
  170.     var->xoffset != 0 ||
  171.     var->yoffset != 0)
  172. return -EINVAL;
  173. if(var->bits_per_pixel != par->bpp) {
  174. ret = e1355_set_bpp(par, var->bits_per_pixel);
  175. if (ret)
  176. goto out_err;
  177. }
  178. return 0;
  179.  out_err:
  180. return ret;
  181. }
  182. static void dump_panel_data(void)
  183. {
  184. u8 panel = e1355_read_reg(E1355_PANEL);
  185. int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
  186. printk("%s %s %s panel, width %d bitsn",
  187.        panel & 2 ? "dual" : "single",
  188.        panel & 4 ? "color" : "mono",
  189.        panel & 1 ? "TFT" : "passive",
  190.        width[panel&1][(panel>>4)&3]);
  191. printk("resolution %d x %dn",
  192.        (e1355_read_reg(0x04) + 1) * 8,
  193.        ((e1355_read_reg16(0x08) + 1) * (1 + ((panel & 3) == 2))));
  194. }
  195. static int e1355_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
  196. {
  197. switch(bpp) {
  198. case 1:
  199. case 2:
  200. case 4:
  201. case 8:
  202. var->bits_per_pixel = bpp;
  203. var->red.offset = var->green.offset = var->blue.offset = 0;
  204. var->red.length = var->green.length = var->blue.length = bpp;
  205. break;
  206. case 16:
  207. var->bits_per_pixel = 16;
  208. var->red.offset = 11;
  209. var->red.length = 5;
  210. var->green.offset = 5;
  211. var->green.length = 6;
  212. var->blue.offset = 0;
  213. var->blue.length = 5;
  214. break;
  215. }
  216. return 0;
  217. }
  218. static int e1355_encode_var(struct fb_var_screeninfo *var, const void *raw_par,
  219.     struct fb_info_gen *info)
  220. {
  221. u8 panel, display;
  222. u32 xres, xres_virtual, yres;
  223. static int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
  224. static int bpp_tab[8] = { 1, 2, 4, 8, 15, 16 };
  225. int bpp, hw_bpp;
  226. int is_color, is_dual, is_tft;
  227. int lcd_enabled, crt_enabled;
  228. panel = e1355_read_reg(E1355_PANEL);
  229. display = e1355_read_reg(E1355_DISPLAY);
  230. is_color = (panel & 0x04) != 0;
  231. is_dual  = (panel & 0x02) != 0;
  232. is_tft   = (panel & 0x01) != 0;
  233. bpp = bpp_tab[(display>>2)&7]; 
  234. e1355_bpp_to_var(bpp, var);
  235. crt_enabled = (display & 0x02) != 0;
  236. lcd_enabled = (display & 0x02) != 0;
  237. hw_bpp = width[is_tft][(panel>>4)&3];
  238. xres = e1355_read_reg(0x04) + 1;
  239. yres = e1355_read_reg16(0x08) + 1;
  240. xres *= 8;
  241. /* talk about weird hardware .. */
  242. yres *= (is_dual && !crt_enabled) ? 2 : 1;
  243. xres_virtual = e1355_read_reg16(0x16);
  244. /* it's in 2-byte words initially */
  245. xres_virtual *= 16;
  246. xres_virtual /= var->bits_per_pixel;
  247. var->xres = xres;
  248. var->yres = yres;
  249. var->xres_virtual = xres_virtual;
  250. var->yres_virtual = yres;
  251. var->xoffset = var->yoffset = 0;
  252. var->grayscale = !is_color;
  253. return 0;
  254. }
  255. #define is_dual(panel) (((panel)&3)==2)
  256. static void get_panel_data(struct e1355_par *par)
  257. {
  258. u8 panel;
  259. int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
  260. panel = e1355_read_reg(E1355_PANEL);
  261. par->panel_width = width[panel&1][(panel>>4)&3];
  262. par->panel_xres = (e1355_read_reg(0x04) + 1) * 8;
  263. par->panel_ymul = is_dual(panel) ? 2 : 1;
  264. par->panel_yres = ((e1355_read_reg16(0x08) + 1)
  265.    * par->panel_ymul);
  266. }
  267. static void e1355_get_par(void *raw_par, struct fb_info_gen *info)
  268. {
  269. struct e1355_par *par = raw_par;
  270. get_panel_data(par);
  271. }
  272. static void e1355_set_par(const void *par, struct fb_info_gen *info)
  273. {
  274. }
  275. static int e1355_getcolreg(unsigned regno, unsigned *red, unsigned *green,
  276.    unsigned *blue, unsigned *transp,
  277.    struct fb_info *info)
  278. {
  279. u8 r, g, b;
  280. e1355_write_reg(regno, E1355_LUT_INDEX);
  281. r = e1355_read_reg(E1355_LUT_DATA);
  282. g = e1355_read_reg(E1355_LUT_DATA);
  283. b = e1355_read_reg(E1355_LUT_DATA);
  284. *red = r << 8;
  285. *green = g << 8;
  286. *blue = b << 8;
  287. return 0;
  288. }
  289. static int e1355_setcolreg(unsigned regno, unsigned red, unsigned green,
  290.    unsigned blue, unsigned transp,
  291.    struct fb_info *info)
  292. {
  293. u8 r = (red >> 8) & 0xf0;
  294. u8 g = (green>>8) & 0xf0;
  295. u8 b = (blue>> 8) & 0xf0;
  296. e1355_write_reg(regno, E1355_LUT_INDEX);
  297. e1355_write_reg(r, E1355_LUT_DATA);
  298. e1355_write_reg(g, E1355_LUT_DATA);
  299. e1355_write_reg(b, E1355_LUT_DATA);
  300. return 0;
  301. }
  302. static int e1355_pan_display(const struct fb_var_screeninfo *var,
  303.      struct fb_info_gen *info)
  304. {
  305. BUG();
  306. return -EINVAL;
  307. }
  308. /*
  309.  * The AERO_HACKS parts disable/enable the backlight on the Compaq Aero 8000.
  310.  * I'm not sure they aren't dangerous to the hardware, so be warned.
  311.  */
  312. #undef AERO_HACKS
  313. static int e1355_blank(int blank_mode, struct fb_info_gen *info)
  314. {
  315. u8 disp;
  316. switch (blank_mode) {
  317. case VESA_NO_BLANKING:
  318. disp = e1355_read_reg(E1355_DISPLAY);
  319. disp |= 1;
  320. e1355_write_reg(disp, E1355_DISPLAY);
  321.  
  322. #ifdef AERO_HACKS
  323. e1355_write_reg(0x6, 0x20);
  324. #endif
  325. break;
  326. case VESA_VSYNC_SUSPEND:
  327. case VESA_HSYNC_SUSPEND:
  328. case VESA_POWERDOWN:
  329. disp = e1355_read_reg(E1355_DISPLAY);
  330. disp &= ~1;
  331. e1355_write_reg(disp, E1355_DISPLAY);
  332. #ifdef AERO_HACKS
  333. e1355_write_reg(0x0, 0x20);
  334. #endif
  335. break;
  336. default:
  337. return -EINVAL;
  338. }
  339. return 0;
  340. }
  341. static struct display_switch e1355_dispsw;
  342. static void e1355_set_disp(const void *unused, struct display *disp,
  343.    struct fb_info_gen *info)
  344. {
  345. struct display_switch *d;
  346. disp->screen_base = (void *)E1355_FB_BASE;
  347. disp->dispsw = &e1355_dispsw;
  348. switch(disp->var.bits_per_pixel) {
  349. #ifdef FBCON_HAS_MFB
  350. case 1:
  351. d = &fbcon_mfb; break;
  352. #endif        
  353. #ifdef FBCON_HAS_CFB8
  354. case 8:
  355. d = &fbcon_cfb8; break;
  356. #endif
  357. default:
  358. BUG(); break;
  359. }
  360. memcpy(&e1355_dispsw, d, sizeof *d);
  361. /* reading is terribly slow for us */
  362. #if 0 /* XXX: need to work out why this doesn't work */
  363. e1355_dispsw.bmove = fbcon_redraw_bmove;
  364. #endif
  365. }
  366. /* ------------ Interfaces to hardware functions ------------ */
  367. struct fbgen_hwswitch e1355_switch = {
  368. detect: e1355_detect,
  369. encode_fix: e1355_encode_fix,
  370. decode_var: e1355_decode_var,
  371. encode_var: e1355_encode_var,
  372. get_par: e1355_get_par,
  373. set_par: e1355_set_par,
  374. getcolreg: e1355_getcolreg,
  375. setcolreg: e1355_setcolreg,
  376. pan_display: e1355_pan_display,
  377. blank: e1355_blank,
  378. set_disp: e1355_set_disp,
  379. };
  380. /* ------------ Hardware Independent Functions ------------ */
  381. static struct fb_ops e1355fb_ops = {
  382. owner: THIS_MODULE,
  383. fb_get_fix: fbgen_get_fix,
  384. fb_get_var: fbgen_get_var,
  385. fb_set_var: fbgen_set_var,
  386. fb_get_cmap: fbgen_get_cmap,
  387. fb_set_cmap: fbgen_set_cmap,
  388. fb_pan_display: fbgen_pan_display,
  389. };
  390. static struct e1355fb_info fb_info;
  391. int __init e1355fb_setup(char *str)
  392. {
  393. return 0;
  394. }
  395. int __init e1355fb_init(void)
  396. {
  397. fb_info.gen.fbhw = &e1355_switch;
  398. fb_info.gen.fbhw->detect();
  399. strcpy(fb_info.gen.info.modename, "SED1355");
  400. fb_info.gen.info.changevar = NULL;
  401. fb_info.gen.info.node = -1;
  402. fb_info.gen.info.fbops = &e1355fb_ops;
  403. fb_info.gen.info.disp = &disp;
  404. fb_info.gen.parsize = sizeof(struct e1355_par);
  405. fb_info.gen.info.switch_con = &fbgen_switch;
  406. fb_info.gen.info.updatevar = &fbgen_update_var;
  407. fb_info.gen.info.blank = &fbgen_blank;
  408. fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
  409. /* This should give a reasonable default video mode */
  410. fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
  411. fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
  412. fbgen_set_disp(-1, &fb_info.gen);
  413. if (disp.var.bits_per_pixel > 1) 
  414. fbgen_install_cmap(0, &fb_info.gen);
  415. if (register_framebuffer(&fb_info.gen.info) < 0)
  416. return -EINVAL;
  417. printk(KERN_INFO "fb%d: %s frame buffer devicen", GET_FB_IDX(fb_info.gen.info.node),
  418.        fb_info.gen.info.modename);
  419. return 0;
  420. }
  421.     /*
  422.      *  Cleanup
  423.      */
  424. void e1355fb_cleanup(struct fb_info *info)
  425. {
  426. /*
  427.  *  If your driver supports multiple boards, you should unregister and
  428.  *  clean up all instances.
  429.  */
  430. unregister_framebuffer(info);
  431. /* ... */
  432. }
  433. MODULE_LICENSE("GPL");