vfd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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. /* MAGIC */
  49. #define FRAME_BUF_SIZE ((256*4*56)/8)
  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. /*
  67. * clear frame buffer (logical clear => set to "black")
  68. */
  69. memset ((void *)(gd->fb_base),
  70. gd->vfd_inv_data ? 0xFF : 0,
  71. FRAME_BUF_SIZE);
  72. switch (gd->vfd_type) {
  73. case VFD_TYPE_T119C:
  74. for (display=0; display<4; display++) {
  75. for(grid_cycle=0; grid_cycle<56; grid_cycle++) {
  76. bit = grid_cycle * 256 * 4 +
  77. (grid_cycle + 200) * 4 +
  78. frame_buf_offs + display;
  79. /* wrap arround if offset (see manual S3C2400) */
  80. if (bit>=FRAME_BUF_SIZE*8)
  81. bit = bit - (FRAME_BUF_SIZE * 8);
  82. adr = gd->fb_base + (bit/32) * 4 + (3 - (bit%32) / 8);
  83. bit_nr = bit % 8;
  84. bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4;
  85. temp=(*(volatile unsigned char*)(adr));
  86. if (gd->vfd_inv_data)
  87. temp &= ~(1<<bit_nr);
  88. else
  89. temp |= (1<<bit_nr);
  90. (*(volatile unsigned char*)(adr))=temp;
  91. if(grid_cycle<55)
  92. bit = grid_cycle*256*4+(grid_cycle+201)*4+frame_buf_offs+display;
  93. else
  94. bit = grid_cycle*256*4+200*4+frame_buf_offs+display-4; /* grid nr. 0 */
  95. /* wrap arround if offset (see manual S3C2400) */
  96. if (bit>=FRAME_BUF_SIZE*8)
  97. bit = bit-(FRAME_BUF_SIZE*8);
  98. adr = gd->fb_base+(bit/32)*4+(3-(bit%32)/8);
  99. bit_nr = bit%8;
  100. bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
  101. temp=(*(volatile unsigned char*)(adr));
  102. if (gd->vfd_inv_data)
  103. temp &= ~(1<<bit_nr);
  104. else
  105. temp |= (1<<bit_nr);
  106. (*(volatile unsigned char*)(adr))=temp;
  107. }
  108. }
  109. break;
  110. case VFD_TYPE_MN11236:
  111. for (display=0; display<4; display++) {
  112. for (grid_cycle=0; grid_cycle<38; grid_cycle++) {
  113. bit = grid_cycle * 256 * 4 +
  114. (253 - grid_cycle) * 4 +
  115. frame_buf_offs + display;
  116. /* wrap arround if offset (see manual S3C2400) */
  117. if (bit>=FRAME_BUF_SIZE*8)
  118. bit = bit - (FRAME_BUF_SIZE * 8);
  119. adr = gd->fb_base + (bit/32) * 4 + (3 - (bit%32) / 8);
  120. bit_nr = bit % 8;
  121. bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4;
  122. temp=(*(volatile unsigned char*)(adr));
  123. if (gd->vfd_inv_data)
  124. temp &= ~(1<<bit_nr);
  125. else
  126. temp |= (1<<bit_nr);
  127. (*(volatile unsigned char*)(adr))=temp;
  128. if(grid_cycle<37)
  129. bit = grid_cycle*256*4+(252-grid_cycle)*4+frame_buf_offs+display;
  130. /* wrap arround if offset (see manual S3C2400) */
  131. if (bit>=FRAME_BUF_SIZE*8)
  132. bit = bit-(FRAME_BUF_SIZE*8);
  133. adr = gd->fb_base+(bit/32)*4+(3-(bit%32)/8);
  134. bit_nr = bit%8;
  135. bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
  136. temp=(*(volatile unsigned char*)(adr));
  137. if (gd->vfd_inv_data)
  138. temp &= ~(1<<bit_nr);
  139. else
  140. temp |= (1<<bit_nr);
  141. (*(volatile unsigned char*)(adr))=temp;
  142. }
  143. }
  144. break;
  145. default:
  146. printf ("Warning: unknown display type\n");
  147. break;
  148. }
  149. }
  150. /*
  151. *create translation table for getting easy the right position in the
  152. *physical framebuffer for some x/y-coordinates of the VFDs
  153. */
  154. void create_vfd_table(void)
  155. {
  156. DECLARE_GLOBAL_DATA_PTR;
  157. unsigned long vfd_table[112][18][2][4][2];
  158. unsigned int x, y, color, display, entry, pixel;
  159. unsigned int x_abcdef = 0;
  160. switch (gd->vfd_type) {
  161. case VFD_TYPE_T119C:
  162. for(y=0; y<=17; y++) { /* Line */
  163. for(x=0; x<=111; x++) { /* Column */
  164. for(display=0; display <=3; display++) {
  165. /* Display 0 blue pixels */
  166. vfd_table[x][y][0][display][0] =
  167. (x==0) ? y*16+display
  168. : (x%4)*4+y*16+((x-1)/2)*1024+display;
  169. /* Display 0 red pixels */
  170. vfd_table[x][y][1][display][0] =
  171. (x==0) ? y*16+512+display
  172. : (x%4)*4+y*16+((x-1)/2)*1024+512+display;
  173. }
  174. }
  175. }
  176. break;
  177. case VFD_TYPE_MN11236:
  178. for(y=0; y<=17; y++) { /* Line */
  179. for(x=0; x<=111; x++) { /* Column */
  180. for(display=0; display <=3; display++) {
  181. vfd_table[x][y][0][display][0]=0;
  182. vfd_table[x][y][0][display][1]=0;
  183. vfd_table[x][y][1][display][0]=0;
  184. vfd_table[x][y][1][display][1]=0;
  185. switch (x%6) {
  186. case 0: x_abcdef=0; break; /* a -> a */
  187. case 1: x_abcdef=2; break; /* b -> c */
  188. case 2: x_abcdef=4; break; /* c -> e */
  189. case 3: x_abcdef=5; break; /* d -> f */
  190. case 4: x_abcdef=3; break; /* e -> d */
  191. case 5: x_abcdef=1; break; /* f -> b */
  192. }
  193. /* blue pixels */
  194. vfd_table[x][y][0][display][0] =
  195. (x>1) ? x_abcdef*4+((x-1)/3)*1024+y*48+display
  196. : x_abcdef*4+ 0+y*48+display;
  197. /* blue pixels */
  198. if (x>1 && (x-1)%3)
  199. vfd_table[x][y][0][display][1] = x_abcdef*4+((x-1)/3+1)*1024+y*48+display;
  200. /* red pixels */
  201. vfd_table[x][y][1][display][0] =
  202. (x>1) ? x_abcdef*4+24+((x-1)/3)*1024+y*48+display
  203. : x_abcdef*4+24+ 0+y*48+display;
  204. /* red pixels */
  205. if (x>1 && (x-1)%3)
  206. vfd_table[x][y][1][display][1] = x_abcdef*4+24+((x-1)/3+1)*1024+y*48+display;
  207. }
  208. }
  209. }
  210. break;
  211. default:
  212. /* do nothing */
  213. return;
  214. }
  215. /*
  216. * Create table with entries for physical byte adresses and
  217. * bit-number within the byte
  218. * from table with bit-numbers within the total framebuffer
  219. */
  220. for(y=0;y<18;y++) {
  221. for(x=0;x<112;x++) {
  222. for(color=0;color<2;color++) {
  223. for(display=0;display<4;display++) {
  224. for(entry=0;entry<2;entry++) {
  225. unsigned long adr = gd->fb_base;
  226. unsigned int bit_nr = 0;
  227. if (vfd_table[x][y][color][display][entry]) {
  228. pixel = vfd_table[x][y][color][display][entry] + frame_buf_offs;
  229. /*
  230. * wrap arround if offset
  231. * (see manual S3C2400)
  232. */
  233. if (pixel>=FRAME_BUF_SIZE*8)
  234. pixel = pixel-(FRAME_BUF_SIZE*8);
  235. adr = gd->fb_base+(pixel/32)*4+(3-(pixel%32)/8);
  236. bit_nr = pixel%8;
  237. bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
  238. }
  239. adr_vfd_table[x][y][color][display][entry] = adr;
  240. bit_vfd_table[x][y][color][display][entry] = bit_nr;
  241. }
  242. }
  243. }
  244. }
  245. }
  246. }
  247. /*
  248. * Set/clear pixel of the VFDs
  249. */
  250. void set_vfd_pixel(unsigned char x, unsigned char y,
  251. unsigned char color, unsigned char display,
  252. unsigned char value)
  253. {
  254. DECLARE_GLOBAL_DATA_PTR;
  255. ulong adr;
  256. unsigned char bit_nr, temp;
  257. if (! gd->vfd_type) {
  258. /* Unknown type. */
  259. return;
  260. }
  261. /* Pixel-Eintrag Nr. 1 */
  262. adr = adr_vfd_table[x][y][color][display][0];
  263. /* Pixel-Eintrag Nr. 1 */
  264. bit_nr = bit_vfd_table[x][y][color][display][0];
  265. temp=(*(volatile unsigned char*)(adr));
  266. if (gd->vfd_inv_data) {
  267. if (value)
  268. temp &= ~(1<<bit_nr);
  269. else
  270. temp |= (1<<bit_nr);
  271. } else {
  272. if (value)
  273. temp |= (1<<bit_nr);
  274. else
  275. temp &= ~(1<<bit_nr);
  276. }
  277. (*(volatile unsigned char*)(adr))=temp;
  278. }
  279. /*
  280. * transfer image from BMP-File
  281. */
  282. void transfer_pic(int display, unsigned char *adr, int height, int width)
  283. {
  284. int x, y;
  285. unsigned char temp;
  286. for (; height > 0; height -= 18)
  287. {
  288. if (height > 18)
  289. y = 18;
  290. else
  291. y = height;
  292. for (; y > 0; y--)
  293. {
  294. for (x = 0; x < width; x += 2)
  295. {
  296. temp = *adr++;
  297. set_vfd_pixel(x, y-1, 0, display, 0);
  298. set_vfd_pixel(x, y-1, 1, display, 0);
  299. if ((temp >> 4) == BLAU)
  300. set_vfd_pixel(x, y-1, 0, display, 1);
  301. else if ((temp >> 4) == ROT)
  302. set_vfd_pixel(x, y-1, 1, display, 1);
  303. else if ((temp >> 4) == VIOLETT)
  304. {
  305. set_vfd_pixel(x, y-1, 0, display, 1);
  306. set_vfd_pixel(x, y-1, 1, display, 1);
  307. }
  308. set_vfd_pixel(x+1, y-1, 0, display, 0);
  309. set_vfd_pixel(x+1, y-1, 1, display, 0);
  310. if ((temp & 0x0F) == BLAU)
  311. set_vfd_pixel(x+1, y-1, 0, display, 1);
  312. else if ((temp & 0x0F) == ROT)
  313. set_vfd_pixel(x+1, y-1, 1, display, 1);
  314. else if ((temp & 0x0F) == VIOLETT)
  315. {
  316. set_vfd_pixel(x+1, y-1, 0, display, 1);
  317. set_vfd_pixel(x+1, y-1, 1, display, 1);
  318. }
  319. }
  320. }
  321. display++;
  322. if (display > 3)
  323. display = 0;
  324. }
  325. }
  326. /*
  327. * This function initializes VFD clock that is needed for the CPLD that
  328. * manages the keyboard.
  329. */
  330. int vfd_init_clocks(void)
  331. {
  332. /* Port-Pins als LCD-Ausgang */
  333. rPCCON = (rPCCON & 0xFFFFFF00)| 0x000000AA;
  334. /* Port-Pins als LCD-Ausgang */
  335. rPDCON = (rPDCON & 0xFFFFFF03)| 0x000000A8;
  336. #ifdef CFG_WITH_VFRAME
  337. /* mit VFRAME zum Messen */
  338. rPDCON = (rPDCON & 0xFFFFFF00)| 0x000000AA;
  339. #endif
  340. rLCDCON2 = 0x000DC000;
  341. rLCDCON3 = 0x0051000A;
  342. rLCDCON4 = 0x00000001;
  343. rLCDCON5 = 0x00000440;
  344. rLCDCON1 = 0x00000B75;
  345. return 0;
  346. }
  347. /*
  348. * initialize LCD-Controller of the S3C2400 for using VFDs
  349. *
  350. * VFD detection depends on the board revision:
  351. * starting from Rev. 200 a type code can be read from the data pins,
  352. * driven by some pull-up resistors; all earlier systems must be
  353. * manually configured. The type is set in the "vfd_type" environment
  354. * variable.
  355. */
  356. int drv_vfd_init(void)
  357. {
  358. char *tmp;
  359. ulong palette;
  360. static int vfd_init_done = 0;
  361. int vfd_id;
  362. DECLARE_GLOBAL_DATA_PTR;
  363. if (vfd_init_done != 0)
  364. return (0);
  365. vfd_init_done = 1;
  366. /* try to determine display type from the value
  367. * defined by pull-ups
  368. */
  369. rPCUP = (rPCUP & 0xFFF0); /* activate GPC0...GPC3 pullups */
  370. rPCCON = (rPCCON & 0xFFFFFF00); /* configure GPC0...GPC3 as inputs */
  371. udelay(10); /* allow signals to settle */
  372. vfd_id = (~rPCDAT) & 0x000F; /* read GPC0...GPC3 port pins */
  373. debug("Detecting Revison of WA4-VFD: ID=0x%X\n", vfd_id);
  374. switch (vfd_id) {
  375. case 0: /* board revision < Rev.200 */
  376. if ((tmp = getenv ("vfd_type")) == NULL) {
  377. break;
  378. }
  379. if (strcmp(tmp, "T119C") == 0) {
  380. gd->vfd_type = VFD_TYPE_T119C;
  381. } else if (strcmp(tmp, "MN11236") == 0) {
  382. gd->vfd_type = VFD_TYPE_MN11236;
  383. } else {
  384. /* cannot use printf for a warning here */
  385. gd->vfd_type = 0; /* unknown */
  386. }
  387. gd->vfd_inv_data = 0;
  388. break;
  389. default: /* default to MN11236, data inverted */
  390. gd->vfd_type = VFD_TYPE_MN11236;
  391. gd->vfd_inv_data = 1;
  392. setenv ("vfd_type", "MN11236");
  393. }
  394. debug ("VFD type: %s%s\n",
  395. (gd->vfd_type == VFD_TYPE_T119C) ? "T119C" :
  396. (gd->vfd_type == VFD_TYPE_MN11236) ? "MN11236" :
  397. "unknown",
  398. gd->vfd_inv_data ? ", inverted data" : "");
  399. gd->fb_base = gd->fb_base;
  400. create_vfd_table();
  401. init_grid_ctrl();
  402. for (palette=0; palette < 16; palette++)
  403. (*(volatile unsigned int*)(PALETTE+(palette*4)))=palette;
  404. for (palette=16; palette < 256; palette++)
  405. (*(volatile unsigned int*)(PALETTE+(palette*4)))=0x00;
  406. /*
  407. * Hinweis: Der Framebuffer ist um genau ein Nibble verschoben
  408. * Das erste angezeigte Pixel wird aus dem zweiten Nibble geholt
  409. * das letzte angezeigte Pixel wird aus dem ersten Nibble geholt
  410. * (wrap around)
  411. * see manual S3C2400
  412. */
  413. /* frame buffer startadr */
  414. rLCDSADDR1 = gd->fb_base >> 1;
  415. /* frame buffer endadr */
  416. rLCDSADDR2 = (gd->fb_base + FRAME_BUF_SIZE) >> 1;
  417. rLCDSADDR3 = ((256/4));
  418. debug ("LCDSADDR1: %lX\n", rLCDSADDR1);
  419. debug ("LCDSADDR2: %lX\n", rLCDSADDR2);
  420. debug ("LCDSADDR3: %lX\n", rLCDSADDR3);
  421. return 0;
  422. }
  423. /************************************************************************/
  424. /* ** ROM capable initialization part - needed to reserve FB memory */
  425. /************************************************************************/
  426. /*
  427. * This is called early in the system initialization to grab memory
  428. * for the VFD controller.
  429. *
  430. * Note that this is running from ROM, so no write access to global data.
  431. */
  432. ulong vfd_setmem (ulong addr)
  433. {
  434. ulong size;
  435. /* Round up to nearest full page */
  436. size = (FRAME_BUF_SIZE + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
  437. debug ("Reserving %ldk for VFD Framebuffer at: %08lx\n", size>>10, addr);
  438. return (size);
  439. }
  440. #endif /* CONFIG_VFD */