vfd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  2. * (C) Copyright 2001
  3. * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. /************************************************************************/
  24. /* ** DEBUG SETTINGS */
  25. /************************************************************************/
  26. /* #define DEBUG */
  27. /************************************************************************/
  28. /* ** HEADER FILES */
  29. /************************************************************************/
  30. #include <config.h>
  31. #include <common.h>
  32. #include <version.h>
  33. #include <stdarg.h>
  34. #include <linux/types.h>
  35. #include <devices.h>
  36. #include <s3c2400.h>
  37. #ifdef CONFIG_VFD
  38. /************************************************************************/
  39. /* ** CONFIG STUFF -- should be moved to board config file */
  40. /************************************************************************/
  41. /************************************************************************/
  42. #ifndef PAGE_SIZE
  43. #define PAGE_SIZE 4096
  44. #endif
  45. #define ROT 0x09
  46. #define BLAU 0x0C
  47. #define VIOLETT 0X0D
  48. ulong vfdbase;
  49. ulong frame_buf_size;
  50. #define frame_buf_offs 4
  51. /* Supported VFD Types */
  52. #define VFD_TYPE_T119C 1 /* Noritake T119C VFD */
  53. #define VFD_TYPE_MN11236 2
  54. /* taken from armboot/common/vfd.c */
  55. unsigned long adr_vfd_table[112][18][2][4][2];
  56. unsigned char bit_vfd_table[112][18][2][4][2];
  57. /*
  58. * initialize the values for the VFD-grid-control in the framebuffer
  59. */
  60. void init_grid_ctrl(void)
  61. {
  62. DECLARE_GLOBAL_DATA_PTR;
  63. ulong adr, grid_cycle;
  64. unsigned int bit, display;
  65. unsigned char temp, bit_nr;
  66. ulong val;
  67. /*
  68. * clear frame buffer (logical clear => set to "black")
  69. */
  70. if (gd->vfd_inv_data == 0)
  71. val = 0;
  72. else
  73. val = ~0;
  74. for (adr = vfdbase; adr <= (vfdbase+7168); adr += 4) {
  75. (*(volatile ulong*)(adr)) = val;
  76. }
  77. switch (gd->vfd_type) {
  78. case VFD_TYPE_T119C:
  79. for (display=0; display<4; display++) {
  80. for(grid_cycle=0; grid_cycle<56; grid_cycle++) {
  81. bit = grid_cycle * 256 * 4 +
  82. (grid_cycle + 200) * 4 +
  83. frame_buf_offs + display;
  84. /* wrap arround if offset (see manual S3C2400) */
  85. if (bit>=frame_buf_size*8)
  86. bit = bit - (frame_buf_size * 8);
  87. adr = vfdbase + (bit/32) * 4 + (3 - (bit%32) / 8);
  88. bit_nr = bit % 8;
  89. bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4;
  90. temp=(*(volatile unsigned char*)(adr));
  91. if (gd->vfd_inv_data)
  92. temp &= ~(1<<bit_nr);
  93. else
  94. temp |= (1<<bit_nr);
  95. (*(volatile unsigned char*)(adr))=temp;
  96. if(grid_cycle<55)
  97. bit = grid_cycle*256*4+(grid_cycle+201)*4+frame_buf_offs+display;
  98. else
  99. bit = grid_cycle*256*4+200*4+frame_buf_offs+display-4; /* grid nr. 0 */
  100. /* wrap arround if offset (see manual S3C2400) */
  101. if (bit>=frame_buf_size*8)
  102. bit = bit-(frame_buf_size*8);
  103. adr = vfdbase+(bit/32)*4+(3-(bit%32)/8);
  104. bit_nr = bit%8;
  105. bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
  106. temp=(*(volatile unsigned char*)(adr));
  107. if (gd->vfd_inv_data)
  108. temp &= ~(1<<bit_nr);
  109. else
  110. temp |= (1<<bit_nr);
  111. (*(volatile unsigned char*)(adr))=temp;
  112. }
  113. }
  114. break;
  115. case VFD_TYPE_MN11236:
  116. for (display=0; display<4; display++) {
  117. for (grid_cycle=0; grid_cycle<38; grid_cycle++) {
  118. bit = grid_cycle * 256 * 4 +
  119. (253 - grid_cycle) * 4 +
  120. frame_buf_offs + display;
  121. /* wrap arround if offset (see manual S3C2400) */
  122. if (bit>=frame_buf_size*8)
  123. bit = bit - (frame_buf_size * 8);
  124. adr = vfdbase + (bit/32) * 4 + (3 - (bit%32) / 8);
  125. bit_nr = bit % 8;
  126. bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4;
  127. temp=(*(volatile unsigned char*)(adr));
  128. if (gd->vfd_inv_data)
  129. temp &= ~(1<<bit_nr);
  130. else
  131. temp |= (1<<bit_nr);
  132. (*(volatile unsigned char*)(adr))=temp;
  133. if(grid_cycle<37)
  134. bit = grid_cycle*256*4+(252-grid_cycle)*4+frame_buf_offs+display;
  135. /* wrap arround if offset (see manual S3C2400) */
  136. if (bit>=frame_buf_size*8)
  137. bit = bit-(frame_buf_size*8);
  138. adr = vfdbase+(bit/32)*4+(3-(bit%32)/8);
  139. bit_nr = bit%8;
  140. bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
  141. temp=(*(volatile unsigned char*)(adr));
  142. if (gd->vfd_inv_data)
  143. temp &= ~(1<<bit_nr);
  144. else
  145. temp |= (1<<bit_nr);
  146. (*(volatile unsigned char*)(adr))=temp;
  147. }
  148. }
  149. break;
  150. default:
  151. printf ("Warning: unknown display type\n");
  152. break;
  153. }
  154. }
  155. /*
  156. *create translation table for getting easy the right position in the
  157. *physical framebuffer for some x/y-coordinates of the VFDs
  158. */
  159. void create_vfd_table(void)
  160. {
  161. DECLARE_GLOBAL_DATA_PTR;
  162. unsigned long vfd_table[112][18][2][4][2];
  163. unsigned int x, y, color, display, entry, pixel;
  164. unsigned int x_abcdef = 0;
  165. switch (gd->vfd_type) {
  166. case VFD_TYPE_T119C:
  167. for(y=0; y<=17; y++) { /* Line */
  168. for(x=0; x<=111; x++) { /* Column */
  169. for(display=0; display <=3; display++) {
  170. /* Display 0 blue pixels */
  171. vfd_table[x][y][0][display][0] =
  172. (x==0) ? y*16+display
  173. : (x%4)*4+y*16+((x-1)/2)*1024+display;
  174. /* Display 0 red pixels */
  175. vfd_table[x][y][1][display][0] =
  176. (x==0) ? y*16+512+display
  177. : (x%4)*4+y*16+((x-1)/2)*1024+512+display;
  178. }
  179. }
  180. }
  181. break;
  182. case VFD_TYPE_MN11236:
  183. for(y=0; y<=17; y++) { /* Line */
  184. for(x=0; x<=111; x++) { /* Column */
  185. for(display=0; display <=3; display++) {
  186. vfd_table[x][y][0][display][0]=0;
  187. vfd_table[x][y][0][display][1]=0;
  188. vfd_table[x][y][1][display][0]=0;
  189. vfd_table[x][y][1][display][1]=0;
  190. switch (x%6) {
  191. case 0: x_abcdef=0; break; /* a -> a */
  192. case 1: x_abcdef=2; break; /* b -> c */
  193. case 2: x_abcdef=4; break; /* c -> e */
  194. case 3: x_abcdef=5; break; /* d -> f */
  195. case 4: x_abcdef=3; break; /* e -> d */
  196. case 5: x_abcdef=1; break; /* f -> b */
  197. }
  198. /* blue pixels */
  199. vfd_table[x][y][0][display][0] =
  200. (x>1) ? x_abcdef*4+((x-1)/3)*1024+y*48+display
  201. : x_abcdef*4+ 0+y*48+display;
  202. /* blue pixels */
  203. if (x>1 && (x-1)%3)
  204. vfd_table[x][y][0][display][1] = x_abcdef*4+((x-1)/3+1)*1024+y*48+display;
  205. /* red pixels */
  206. vfd_table[x][y][1][display][0] =
  207. (x>1) ? x_abcdef*4+24+((x-1)/3)*1024+y*48+display
  208. : x_abcdef*4+24+ 0+y*48+display;
  209. /* red pixels */
  210. if (x>1 && (x-1)%3)
  211. vfd_table[x][y][1][display][1] = x_abcdef*4+24+((x-1)/3+1)*1024+y*48+display;
  212. }
  213. }
  214. }
  215. break;
  216. default:
  217. /* do nothing */
  218. return;
  219. }
  220. /*
  221. * Create table with entries for physical byte adresses and
  222. * bit-number within the byte
  223. * from table with bit-numbers within the total framebuffer
  224. */
  225. for(y=0;y<18;y++) {
  226. for(x=0;x<112;x++) {
  227. for(color=0;color<2;color++) {
  228. for(display=0;display<4;display++) {
  229. for(entry=0;entry<2;entry++) {
  230. unsigned long adr = vfdbase;
  231. unsigned int bit_nr = 0;
  232. if (vfd_table[x][y][color][display][entry]) {
  233. pixel = vfd_table[x][y][color][display][entry] + frame_buf_offs;
  234. /*
  235. * wrap arround if offset
  236. * (see manual S3C2400)
  237. */
  238. if (pixel>=frame_buf_size*8)
  239. pixel = pixel-(frame_buf_size*8);
  240. adr = vfdbase+(pixel/32)*4+(3-(pixel%32)/8);
  241. bit_nr = pixel%8;
  242. bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
  243. }
  244. adr_vfd_table[x][y][color][display][entry] = adr;
  245. bit_vfd_table[x][y][color][display][entry] = bit_nr;
  246. }
  247. }
  248. }
  249. }
  250. }
  251. }
  252. /*
  253. * Set/clear pixel of the VFDs
  254. */
  255. void set_vfd_pixel(unsigned char x, unsigned char y,
  256. unsigned char color, unsigned char display,
  257. unsigned char value)
  258. {
  259. DECLARE_GLOBAL_DATA_PTR;
  260. ulong adr;
  261. unsigned char bit_nr, temp;
  262. if (! gd->vfd_type) {
  263. /* Unknown type. */
  264. return;
  265. }
  266. /* Pixel-Eintrag Nr. 1 */
  267. adr = adr_vfd_table[x][y][color][display][0];
  268. /* Pixel-Eintrag Nr. 1 */
  269. bit_nr = bit_vfd_table[x][y][color][display][0];
  270. temp=(*(volatile unsigned char*)(adr));
  271. if (gd->vfd_inv_data) {
  272. if (value)
  273. temp &= ~(1<<bit_nr);
  274. else
  275. temp |= (1<<bit_nr);
  276. } else {
  277. if (value)
  278. temp |= (1<<bit_nr);
  279. else
  280. temp &= ~(1<<bit_nr);
  281. }
  282. (*(volatile unsigned char*)(adr))=temp;
  283. }
  284. /*
  285. * transfer image from BMP-File
  286. */
  287. void transfer_pic(int display, unsigned char *adr, int height, int width)
  288. {
  289. int x, y;
  290. unsigned char temp;
  291. for (; height > 0; height -= 18)
  292. {
  293. if (height > 18)
  294. y = 18;
  295. else
  296. y = height;
  297. for (; y > 0; y--)
  298. {
  299. for (x = 0; x < width; x += 2)
  300. {
  301. temp = *adr++;
  302. set_vfd_pixel(x, y-1, 0, display, 0);
  303. set_vfd_pixel(x, y-1, 1, display, 0);
  304. if ((temp >> 4) == BLAU)
  305. set_vfd_pixel(x, y-1, 0, display, 1);
  306. else if ((temp >> 4) == ROT)
  307. set_vfd_pixel(x, y-1, 1, display, 1);
  308. else if ((temp >> 4) == VIOLETT)
  309. {
  310. set_vfd_pixel(x, y-1, 0, display, 1);
  311. set_vfd_pixel(x, y-1, 1, display, 1);
  312. }
  313. set_vfd_pixel(x+1, y-1, 0, display, 0);
  314. set_vfd_pixel(x+1, y-1, 1, display, 0);
  315. if ((temp & 0x0F) == BLAU)
  316. set_vfd_pixel(x+1, y-1, 0, display, 1);
  317. else if ((temp & 0x0F) == ROT)
  318. set_vfd_pixel(x+1, y-1, 1, display, 1);
  319. else if ((temp & 0x0F) == VIOLETT)
  320. {
  321. set_vfd_pixel(x+1, y-1, 0, display, 1);
  322. set_vfd_pixel(x+1, y-1, 1, display, 1);
  323. }
  324. }
  325. }
  326. display++;
  327. if (display > 3)
  328. display = 0;
  329. }
  330. }
  331. /*
  332. * This function initializes VFD clock that is needed for the CPLD that
  333. * manages the keyboard.
  334. */
  335. int vfd_init_clocks(void)
  336. {
  337. /* Port-Pins als LCD-Ausgang */
  338. rPCCON = (rPCCON & 0xFFFFFF00)| 0x000000AA;
  339. /* Port-Pins als LCD-Ausgang */
  340. rPDCON = (rPDCON & 0xFFFFFF03)| 0x000000A8;
  341. #ifdef WITH_VFRAME
  342. /* mit VFRAME zum Messen */
  343. rPDCON = (rPDCON & 0xFFFFFF00)| 0x000000AA;
  344. #endif
  345. rLCDCON2 = 0x000DC000;
  346. rLCDCON3 = 0x0051000A;
  347. rLCDCON4 = 0x00000001;
  348. rLCDCON5 = 0x00000440;
  349. rLCDCON1 = 0x00000B75;
  350. }
  351. /*
  352. * initialize LCD-Controller of the S3C2400 for using VFDs
  353. */
  354. int drv_vfd_init(void)
  355. {
  356. char *tmp;
  357. ulong palette;
  358. static int vfd_init_done = 0;
  359. int vfd_id;
  360. DECLARE_GLOBAL_DATA_PTR;
  361. if (vfd_init_done != 0)
  362. return (0);
  363. vfd_init_done = 1;
  364. /* try to determine display type from the value
  365. * defined by pull-ups
  366. */
  367. rPCUP = (rPCUP | 0x000F); /* activate GPC0...GPC3 pullups */
  368. rPCCON = (rPCCON & 0xFFFFFF00); /* configure GPC0...GPC3 as inputs */
  369. vfd_id = (~rPCDAT) & 0x000F; /* read GPC0...GPC3 port pins */
  370. debug("Detecting Revison of WA4-VFD: ID=0x%X\n", vfd_id);
  371. switch (vfd_id) {
  372. case 0: /* board revision <= Rev.100 */
  373. /*-----*/
  374. gd->vfd_inv_data = 0;
  375. if (0)
  376. gd->vfd_type = VFD_TYPE_MN11236;
  377. else
  378. gd->vfd_type = VFD_TYPE_T119C;
  379. /*-----*/
  380. if ((tmp = getenv ("vfd_type")) == NULL) {
  381. break;
  382. }
  383. if (strcmp(tmp, "T119C") == 0) {
  384. gd->vfd_type = VFD_TYPE_T119C;
  385. } else if (strcmp(tmp, "MN11236") == 0) {
  386. gd->vfd_type = VFD_TYPE_MN11236;
  387. } else {
  388. /* cannot use printf for a warning here */
  389. gd->vfd_type = 0; /* unknown */
  390. }
  391. gd->vfd_inv_data = 0;
  392. break;
  393. default: /* default to MN11236, data inverted */
  394. gd->vfd_type = VFD_TYPE_MN11236;
  395. gd->vfd_inv_data = 1;
  396. setenv ("vfd_type", "MN11236");
  397. }
  398. debug ("VFD type: %s%s\n",
  399. (gd->vfd_type == VFD_TYPE_T119C) ? "T119C" :
  400. (gd->vfd_type == VFD_TYPE_MN11236) ? "MN11236" :
  401. "unknown",
  402. gd->vfd_inv_data ? ", inverted data" : "");
  403. vfdbase = gd->fb_base;
  404. create_vfd_table();
  405. init_grid_ctrl();
  406. for (palette=0; palette < 16; palette++)
  407. (*(volatile unsigned int*)(PALETTE+(palette*4)))=palette;
  408. for (palette=16; palette < 256; palette++)
  409. (*(volatile unsigned int*)(PALETTE+(palette*4)))=0x00;
  410. /*
  411. * Hinweis: Der Framebuffer ist um genau ein Nibble verschoben
  412. * Das erste angezeigte Pixel wird aus dem zweiten Nibble geholt
  413. * das letzte angezeigte Pixel wird aus dem ersten Nibble geholt
  414. * (wrap around)
  415. * see manual S3C2400
  416. */
  417. /* frame buffer startadr */
  418. rLCDSADDR1 = vfdbase >> 1;
  419. /* frame buffer endadr */
  420. rLCDSADDR2 = (vfdbase + frame_buf_size) >> 1;
  421. rLCDSADDR3 = ((256/4));
  422. debug ("LCDSADDR1: %lX\n", rLCDSADDR1);
  423. debug ("LCDSADDR2: %lX\n", rLCDSADDR2);
  424. debug ("LCDSADDR3: %lX\n", rLCDSADDR3);
  425. return 0;
  426. }
  427. /************************************************************************/
  428. /* ** ROM capable initialization part - needed to reserve FB memory */
  429. /************************************************************************/
  430. /*
  431. * This is called early in the system initialization to grab memory
  432. * for the VFD controller.
  433. *
  434. * Note that this is running from ROM, so no write access to global data.
  435. */
  436. ulong vfd_setmem (ulong addr)
  437. {
  438. ulong size;
  439. /* MAGIC */
  440. frame_buf_size = (256*4*56)/8;
  441. /* Round up to nearest full page */
  442. size = (frame_buf_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
  443. debug ("Reserving %ldk for VFD Framebuffer at: %08lx\n", size>>10, addr);
  444. return (size);
  445. }
  446. #endif /* CONFIG_VFD */