fsl_diu_fb.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc.
  3. * Authors: York Sun <yorksun@freescale.com>
  4. * Timur Tabi <timur@freescale.com>
  5. *
  6. * FSL DIU Framebuffer driver
  7. *
  8. * See file CREDITS for list of people who contributed to this
  9. * project.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License as
  13. * published by the Free Software Foundation; either version 2 of
  14. * the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24. * MA 02111-1307 USA
  25. */
  26. #include <common.h>
  27. #include <malloc.h>
  28. #include <asm/io.h>
  29. #include "videomodes.h"
  30. #include <video_fb.h>
  31. #include <fsl_diu_fb.h>
  32. struct fb_var_screeninfo {
  33. unsigned int xres; /* visible resolution */
  34. unsigned int yres;
  35. unsigned int bits_per_pixel; /* guess what */
  36. /* Timing: All values in pixclocks, except pixclock (of course) */
  37. unsigned int pixclock; /* pixel clock in ps (pico seconds) */
  38. unsigned int left_margin; /* time from sync to picture */
  39. unsigned int right_margin; /* time from picture to sync */
  40. unsigned int upper_margin; /* time from sync to picture */
  41. unsigned int lower_margin;
  42. unsigned int hsync_len; /* length of horizontal sync */
  43. unsigned int vsync_len; /* length of vertical sync */
  44. unsigned int sync; /* see FB_SYNC_* */
  45. unsigned int vmode; /* see FB_VMODE_* */
  46. unsigned int rotate; /* angle we rotate counter clockwise */
  47. };
  48. struct fb_info {
  49. struct fb_var_screeninfo var; /* Current var */
  50. unsigned int smem_len; /* Length of frame buffer mem */
  51. unsigned int type; /* see FB_TYPE_* */
  52. unsigned int line_length; /* length of a line in bytes */
  53. void *screen_base;
  54. unsigned long screen_size;
  55. };
  56. struct fb_videomode {
  57. const char *name; /* optional */
  58. unsigned int refresh; /* optional */
  59. unsigned int xres;
  60. unsigned int yres;
  61. unsigned int pixclock;
  62. unsigned int left_margin;
  63. unsigned int right_margin;
  64. unsigned int upper_margin;
  65. unsigned int lower_margin;
  66. unsigned int hsync_len;
  67. unsigned int vsync_len;
  68. unsigned int sync;
  69. unsigned int vmode;
  70. unsigned int flag;
  71. };
  72. #define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */
  73. #define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */
  74. #define FB_VMODE_NONINTERLACED 0 /* non interlaced */
  75. /* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */
  76. static struct fb_videomode fsl_diu_mode_800 = {
  77. .name = "800x600-60",
  78. .refresh = 60,
  79. .xres = 800,
  80. .yres = 480,
  81. .pixclock = 31250,
  82. .left_margin = 86,
  83. .right_margin = 42,
  84. .upper_margin = 33,
  85. .lower_margin = 10,
  86. .hsync_len = 128,
  87. .vsync_len = 2,
  88. .sync = 0,
  89. .vmode = FB_VMODE_NONINTERLACED
  90. };
  91. /*
  92. * These parameters give default parameters
  93. * for video output 1024x768,
  94. * FIXME - change timing to proper amounts
  95. * hsync 31.5kHz, vsync 60Hz
  96. */
  97. static struct fb_videomode fsl_diu_mode_1024 = {
  98. .name = "1024x768-60",
  99. .refresh = 60,
  100. .xres = 1024,
  101. .yres = 768,
  102. .pixclock = 15385,
  103. .left_margin = 160,
  104. .right_margin = 24,
  105. .upper_margin = 29,
  106. .lower_margin = 3,
  107. .hsync_len = 136,
  108. .vsync_len = 6,
  109. .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  110. .vmode = FB_VMODE_NONINTERLACED
  111. };
  112. static struct fb_videomode fsl_diu_mode_1280 = {
  113. .name = "1280x1024-60",
  114. .refresh = 60,
  115. .xres = 1280,
  116. .yres = 1024,
  117. .pixclock = 9375,
  118. .left_margin = 38,
  119. .right_margin = 128,
  120. .upper_margin = 2,
  121. .lower_margin = 7,
  122. .hsync_len = 216,
  123. .vsync_len = 37,
  124. .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  125. .vmode = FB_VMODE_NONINTERLACED
  126. };
  127. /*
  128. * These are the fields of area descriptor(in DDR memory) for every plane
  129. */
  130. struct diu_ad {
  131. /* Word 0(32-bit) in DDR memory */
  132. __le32 pix_fmt; /* hard coding pixel format */
  133. /* Word 1(32-bit) in DDR memory */
  134. __le32 addr;
  135. /* Word 2(32-bit) in DDR memory */
  136. __le32 src_size_g_alpha;
  137. /* Word 3(32-bit) in DDR memory */
  138. __le32 aoi_size;
  139. /* Word 4(32-bit) in DDR memory */
  140. __le32 offset_xyi;
  141. /* Word 5(32-bit) in DDR memory */
  142. __le32 offset_xyd;
  143. /* Word 6(32-bit) in DDR memory */
  144. __le32 ckmax_r:8;
  145. __le32 ckmax_g:8;
  146. __le32 ckmax_b:8;
  147. __le32 res9:8;
  148. /* Word 7(32-bit) in DDR memory */
  149. __le32 ckmin_r:8;
  150. __le32 ckmin_g:8;
  151. __le32 ckmin_b:8;
  152. __le32 res10:8;
  153. /* Word 8(32-bit) in DDR memory */
  154. __le32 next_ad;
  155. /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
  156. __le32 res[3];
  157. } __attribute__ ((packed));
  158. /*
  159. * DIU register map
  160. */
  161. struct diu {
  162. __be32 desc[3];
  163. __be32 gamma;
  164. __be32 pallete;
  165. __be32 cursor;
  166. __be32 curs_pos;
  167. __be32 diu_mode;
  168. __be32 bgnd;
  169. __be32 bgnd_wb;
  170. __be32 disp_size;
  171. __be32 wb_size;
  172. __be32 wb_mem_addr;
  173. __be32 hsyn_para;
  174. __be32 vsyn_para;
  175. __be32 syn_pol;
  176. __be32 thresholds;
  177. __be32 int_status;
  178. __be32 int_mask;
  179. __be32 colorbar[8];
  180. __be32 filling;
  181. __be32 plut;
  182. } __attribute__ ((packed));
  183. struct diu_addr {
  184. void *vaddr; /* Virtual address */
  185. u32 paddr; /* 32-bit physical address */
  186. unsigned int offset; /* Alignment offset */
  187. };
  188. static struct fb_info info;
  189. /*
  190. * Align to 64-bit(8-byte), 32-byte, etc.
  191. */
  192. static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
  193. {
  194. u32 offset, ssize;
  195. u32 mask;
  196. ssize = size + bytes_align;
  197. buf->vaddr = malloc(ssize);
  198. if (!buf->vaddr)
  199. return -1;
  200. memset(buf->vaddr, 0, ssize);
  201. mask = bytes_align - 1;
  202. offset = (u32)buf->vaddr & mask;
  203. if (offset) {
  204. buf->offset = bytes_align - offset;
  205. buf->vaddr += offset;
  206. } else
  207. buf->offset = 0;
  208. buf->paddr = virt_to_phys(buf->vaddr);
  209. return 0;
  210. }
  211. /*
  212. * Allocate a framebuffer and an Area Descriptor that points to it. Both
  213. * are created in the same memory block. The Area Descriptor is updated to
  214. * point to the framebuffer memory. Memory is aligned as needed.
  215. */
  216. static struct diu_ad *allocate_fb(unsigned int xres, unsigned int yres,
  217. unsigned int depth, void **fb)
  218. {
  219. unsigned long size = xres * yres * depth;
  220. struct diu_addr addr;
  221. struct diu_ad *ad;
  222. size_t ad_size = roundup(sizeof(struct diu_ad), 32);
  223. /*
  224. * Allocate a memory block that holds the Area Descriptor and the
  225. * frame buffer right behind it. To keep the code simple, everything
  226. * is aligned on a 32-byte address.
  227. */
  228. if (allocate_buf(&addr, ad_size + size, 32) < 0)
  229. return NULL;
  230. ad = addr.vaddr;
  231. ad->addr = cpu_to_le32(addr.paddr + ad_size);
  232. ad->aoi_size = cpu_to_le32((yres << 16) | xres);
  233. ad->src_size_g_alpha = cpu_to_le32((yres << 12) | xres);
  234. ad->offset_xyi = 0;
  235. ad->offset_xyd = 0;
  236. if (fb)
  237. *fb = addr.vaddr + ad_size;
  238. return ad;
  239. }
  240. int fsl_diu_init(int xres, u32 pixel_format, int gamma_fix)
  241. {
  242. struct fb_videomode *fsl_diu_mode_db;
  243. struct diu_ad *ad;
  244. struct diu *hw = (struct diu *)CONFIG_SYS_DIU_ADDR;
  245. u8 *gamma_table_base;
  246. unsigned int i, j;
  247. struct diu_ad *dummy_ad;
  248. struct diu_addr gamma;
  249. struct diu_addr cursor;
  250. switch (xres) {
  251. case 800:
  252. fsl_diu_mode_db = &fsl_diu_mode_800;
  253. break;
  254. case 1280:
  255. fsl_diu_mode_db = &fsl_diu_mode_1280;
  256. break;
  257. default:
  258. fsl_diu_mode_db = &fsl_diu_mode_1024;
  259. }
  260. /* The AD struct for the dummy framebuffer and the FB itself */
  261. dummy_ad = allocate_fb(2, 4, 4, NULL);
  262. if (!dummy_ad) {
  263. printf("DIU: Out of memory\n");
  264. return -1;
  265. }
  266. dummy_ad->pix_fmt = 0x88883316;
  267. /* read mode info */
  268. info.var.xres = fsl_diu_mode_db->xres;
  269. info.var.yres = fsl_diu_mode_db->yres;
  270. info.var.bits_per_pixel = 32;
  271. info.var.pixclock = fsl_diu_mode_db->pixclock;
  272. info.var.left_margin = fsl_diu_mode_db->left_margin;
  273. info.var.right_margin = fsl_diu_mode_db->right_margin;
  274. info.var.upper_margin = fsl_diu_mode_db->upper_margin;
  275. info.var.lower_margin = fsl_diu_mode_db->lower_margin;
  276. info.var.hsync_len = fsl_diu_mode_db->hsync_len;
  277. info.var.vsync_len = fsl_diu_mode_db->vsync_len;
  278. info.var.sync = fsl_diu_mode_db->sync;
  279. info.var.vmode = fsl_diu_mode_db->vmode;
  280. info.line_length = info.var.xres * info.var.bits_per_pixel / 8;
  281. /* Memory allocation for framebuffer */
  282. info.smem_len =
  283. info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
  284. ad = allocate_fb(info.var.xres, info.var.yres,
  285. info.var.bits_per_pixel / 8, &info.screen_base);
  286. if (!ad) {
  287. printf("DIU: Out of memory\n");
  288. return -1;
  289. }
  290. ad->pix_fmt = pixel_format;
  291. /* Disable chroma keying function */
  292. ad->ckmax_r = 0;
  293. ad->ckmax_g = 0;
  294. ad->ckmax_b = 0;
  295. ad->ckmin_r = 255;
  296. ad->ckmin_g = 255;
  297. ad->ckmin_b = 255;
  298. /* Initialize the gamma table */
  299. if (allocate_buf(&gamma, 256 * 3, 32) < 0) {
  300. printf("DIU: Out of memory\n");
  301. return -1;
  302. }
  303. gamma_table_base = gamma.vaddr;
  304. for (i = 0; i <= 2; i++)
  305. for (j = 0; j < 256; j++)
  306. *gamma_table_base++ = j;
  307. if (gamma_fix == 1) { /* fix the gamma */
  308. gamma_table_base = gamma.vaddr;
  309. for (i = 0; i < 256 * 3; i++) {
  310. gamma_table_base[i] = (gamma_table_base[i] << 2)
  311. | ((gamma_table_base[i] >> 6) & 0x03);
  312. }
  313. }
  314. /* Initialize the cursor */
  315. if (allocate_buf(&cursor, 32 * 32 * 2, 32) < 0) {
  316. printf("DIU: Can't alloc cursor data\n");
  317. return -1;
  318. }
  319. /* Program DIU registers */
  320. out_be32(&hw->diu_mode, 0); /* Temporarily disable the DIU */
  321. out_be32(&hw->gamma, gamma.paddr);
  322. out_be32(&hw->cursor, cursor.paddr);
  323. out_be32(&hw->bgnd, 0x007F7F7F);
  324. out_be32(&hw->bgnd_wb, 0);
  325. out_be32(&hw->disp_size, info.var.yres << 16 | info.var.xres);
  326. out_be32(&hw->wb_size, 0);
  327. out_be32(&hw->wb_mem_addr, 0);
  328. out_be32(&hw->hsyn_para, info.var.left_margin << 22 |
  329. info.var.hsync_len << 11 |
  330. info.var.right_margin);
  331. out_be32(&hw->vsyn_para, info.var.upper_margin << 22 |
  332. info.var.vsync_len << 11 |
  333. info.var.lower_margin);
  334. out_be32(&hw->syn_pol, 0);
  335. out_be32(&hw->thresholds, 0x00037800);
  336. out_be32(&hw->int_status, 0);
  337. out_be32(&hw->int_mask, 0);
  338. out_be32(&hw->plut, 0x01F5F666);
  339. /* Pixel Clock configuration */
  340. diu_set_pixel_clock(info.var.pixclock);
  341. /* Set the frame buffers */
  342. out_be32(&hw->desc[0], virt_to_phys(ad));
  343. out_be32(&hw->desc[1], virt_to_phys(dummy_ad));
  344. out_be32(&hw->desc[2], virt_to_phys(dummy_ad));
  345. /* Enable the DIU, set display to all three planes */
  346. out_be32(&hw->diu_mode, 1);
  347. return 0;
  348. }
  349. void *video_hw_init(void)
  350. {
  351. static GraphicDevice ctfb;
  352. const char *options;
  353. unsigned int depth = 0, freq = 0;
  354. if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
  355. &options))
  356. return NULL;
  357. /* Find the monitor port, which is a required option */
  358. if (!options)
  359. return NULL;
  360. if (strncmp(options, "monitor=", 8) != 0)
  361. return NULL;
  362. if (platform_diu_init(ctfb.winSizeX, ctfb.winSizeY, options + 8) < 0)
  363. return NULL;
  364. /* fill in Graphic device struct */
  365. sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz",
  366. ctfb.winSizeX, ctfb.winSizeY, depth, 64, freq);
  367. ctfb.frameAdrs = (unsigned int)info.screen_base;
  368. ctfb.plnSizeX = ctfb.winSizeX;
  369. ctfb.plnSizeY = ctfb.winSizeY;
  370. ctfb.gdfBytesPP = 4;
  371. ctfb.gdfIndex = GDF_32BIT_X888RGB;
  372. ctfb.isaBase = 0;
  373. ctfb.pciBase = 0;
  374. ctfb.memSize = info.screen_size;
  375. /* Cursor Start Address */
  376. ctfb.dprBase = 0;
  377. ctfb.vprBase = 0;
  378. ctfb.cprBase = 0;
  379. return &ctfb;
  380. }