PageRenderTime 63ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/video/w100fb.c

https://bitbucket.org/wisechild/galaxy-nexus
C | 1636 lines | 1207 code | 280 blank | 149 comment | 136 complexity | 4ec282b81b2131985440c631c779b565 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1. /*
  2. * linux/drivers/video/w100fb.c
  3. *
  4. * Frame Buffer Device for ATI Imageon w100 (Wallaby)
  5. *
  6. * Copyright (C) 2002, ATI Corp.
  7. * Copyright (C) 2004-2006 Richard Purdie
  8. * Copyright (c) 2005 Ian Molton
  9. * Copyright (c) 2006 Alberto Mardegan
  10. *
  11. * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
  12. *
  13. * Generic platform support by Ian Molton <spyro@f2s.com>
  14. * and Richard Purdie <rpurdie@rpsys.net>
  15. *
  16. * w32xx support by Ian Molton
  17. *
  18. * Hardware acceleration support by Alberto Mardegan
  19. * <mardy@users.sourceforge.net>
  20. *
  21. * This program is free software; you can redistribute it and/or modify
  22. * it under the terms of the GNU General Public License version 2 as
  23. * published by the Free Software Foundation.
  24. *
  25. */
  26. #include <linux/delay.h>
  27. #include <linux/fb.h>
  28. #include <linux/init.h>
  29. #include <linux/kernel.h>
  30. #include <linux/mm.h>
  31. #include <linux/platform_device.h>
  32. #include <linux/slab.h>
  33. #include <linux/string.h>
  34. #include <linux/vmalloc.h>
  35. #include <asm/io.h>
  36. #include <asm/uaccess.h>
  37. #include <video/w100fb.h>
  38. #include "w100fb.h"
  39. /*
  40. * Prototypes
  41. */
  42. static void w100_suspend(u32 mode);
  43. static void w100_vsync(void);
  44. static void w100_hw_init(struct w100fb_par*);
  45. static void w100_pwm_setup(struct w100fb_par*);
  46. static void w100_init_clocks(struct w100fb_par*);
  47. static void w100_setup_memory(struct w100fb_par*);
  48. static void w100_init_lcd(struct w100fb_par*);
  49. static void w100_set_dispregs(struct w100fb_par*);
  50. static void w100_update_enable(void);
  51. static void w100_update_disable(void);
  52. static void calc_hsync(struct w100fb_par *par);
  53. static void w100_init_graphic_engine(struct w100fb_par *par);
  54. struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit;
  55. /* Pseudo palette size */
  56. #define MAX_PALETTES 16
  57. #define W100_SUSPEND_EXTMEM 0
  58. #define W100_SUSPEND_ALL 1
  59. #define BITS_PER_PIXEL 16
  60. /* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
  61. static void *remapped_base;
  62. static void *remapped_regs;
  63. static void *remapped_fbuf;
  64. #define REMAPPED_FB_LEN 0x15ffff
  65. /* This is the offset in the w100's address space we map the current
  66. framebuffer memory to. We use the position of external memory as
  67. we can remap internal memory to there if external isn't present. */
  68. #define W100_FB_BASE MEM_EXT_BASE_VALUE
  69. /*
  70. * Sysfs functions
  71. */
  72. static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
  73. {
  74. struct fb_info *info = dev_get_drvdata(dev);
  75. struct w100fb_par *par=info->par;
  76. return sprintf(buf, "%d\n",par->flip);
  77. }
  78. static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  79. {
  80. unsigned int flip;
  81. struct fb_info *info = dev_get_drvdata(dev);
  82. struct w100fb_par *par=info->par;
  83. flip = simple_strtoul(buf, NULL, 10);
  84. if (flip > 0)
  85. par->flip = 1;
  86. else
  87. par->flip = 0;
  88. w100_update_disable();
  89. w100_set_dispregs(par);
  90. w100_update_enable();
  91. calc_hsync(par);
  92. return count;
  93. }
  94. static DEVICE_ATTR(flip, 0644, flip_show, flip_store);
  95. static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  96. {
  97. unsigned long regs, param;
  98. regs = simple_strtoul(buf, NULL, 16);
  99. param = readl(remapped_regs + regs);
  100. printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
  101. return count;
  102. }
  103. static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
  104. static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  105. {
  106. unsigned long regs, param;
  107. sscanf(buf, "%lx %lx", &regs, &param);
  108. if (regs <= 0x2000) {
  109. printk("Write Register 0x%08lX: 0x%08lX\n", regs, param);
  110. writel(param, remapped_regs + regs);
  111. }
  112. return count;
  113. }
  114. static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
  115. static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
  116. {
  117. struct fb_info *info = dev_get_drvdata(dev);
  118. struct w100fb_par *par=info->par;
  119. return sprintf(buf, "%d\n",par->fastpll_mode);
  120. }
  121. static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  122. {
  123. struct fb_info *info = dev_get_drvdata(dev);
  124. struct w100fb_par *par=info->par;
  125. if (simple_strtoul(buf, NULL, 10) > 0) {
  126. par->fastpll_mode=1;
  127. printk("w100fb: Using fast system clock (if possible)\n");
  128. } else {
  129. par->fastpll_mode=0;
  130. printk("w100fb: Using normal system clock\n");
  131. }
  132. w100_init_clocks(par);
  133. calc_hsync(par);
  134. return count;
  135. }
  136. static DEVICE_ATTR(fastpllclk, 0644, fastpllclk_show, fastpllclk_store);
  137. /*
  138. * Some touchscreens need hsync information from the video driver to
  139. * function correctly. We export it here.
  140. */
  141. unsigned long w100fb_get_hsynclen(struct device *dev)
  142. {
  143. struct fb_info *info = dev_get_drvdata(dev);
  144. struct w100fb_par *par=info->par;
  145. /* If display is blanked/suspended, hsync isn't active */
  146. if (par->blanked)
  147. return 0;
  148. else
  149. return par->hsync_len;
  150. }
  151. EXPORT_SYMBOL(w100fb_get_hsynclen);
  152. static void w100fb_clear_screen(struct w100fb_par *par)
  153. {
  154. memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
  155. }
  156. /*
  157. * Set a palette value from rgb components
  158. */
  159. static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  160. u_int trans, struct fb_info *info)
  161. {
  162. unsigned int val;
  163. int ret = 1;
  164. /*
  165. * If greyscale is true, then we convert the RGB value
  166. * to greyscale no matter what visual we are using.
  167. */
  168. if (info->var.grayscale)
  169. red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16;
  170. /*
  171. * 16-bit True Colour. We encode the RGB value
  172. * according to the RGB bitfield information.
  173. */
  174. if (regno < MAX_PALETTES) {
  175. u32 *pal = info->pseudo_palette;
  176. val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
  177. pal[regno] = val;
  178. ret = 0;
  179. }
  180. return ret;
  181. }
  182. /*
  183. * Blank the display based on value in blank_mode
  184. */
  185. static int w100fb_blank(int blank_mode, struct fb_info *info)
  186. {
  187. struct w100fb_par *par = info->par;
  188. struct w100_tg_info *tg = par->mach->tg;
  189. switch(blank_mode) {
  190. case FB_BLANK_NORMAL: /* Normal blanking */
  191. case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
  192. case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
  193. case FB_BLANK_POWERDOWN: /* Poweroff */
  194. if (par->blanked == 0) {
  195. if(tg && tg->suspend)
  196. tg->suspend(par);
  197. par->blanked = 1;
  198. }
  199. break;
  200. case FB_BLANK_UNBLANK: /* Unblanking */
  201. if (par->blanked != 0) {
  202. if(tg && tg->resume)
  203. tg->resume(par);
  204. par->blanked = 0;
  205. }
  206. break;
  207. }
  208. return 0;
  209. }
  210. static void w100_fifo_wait(int entries)
  211. {
  212. union rbbm_status_u status;
  213. int i;
  214. for (i = 0; i < 2000000; i++) {
  215. status.val = readl(remapped_regs + mmRBBM_STATUS);
  216. if (status.f.cmdfifo_avail >= entries)
  217. return;
  218. udelay(1);
  219. }
  220. printk(KERN_ERR "w100fb: FIFO Timeout!\n");
  221. }
  222. static int w100fb_sync(struct fb_info *info)
  223. {
  224. union rbbm_status_u status;
  225. int i;
  226. for (i = 0; i < 2000000; i++) {
  227. status.val = readl(remapped_regs + mmRBBM_STATUS);
  228. if (!status.f.gui_active)
  229. return 0;
  230. udelay(1);
  231. }
  232. printk(KERN_ERR "w100fb: Graphic engine timeout!\n");
  233. return -EBUSY;
  234. }
  235. static void w100_init_graphic_engine(struct w100fb_par *par)
  236. {
  237. union dp_gui_master_cntl_u gmc;
  238. union dp_mix_u dp_mix;
  239. union dp_datatype_u dp_datatype;
  240. union dp_cntl_u dp_cntl;
  241. w100_fifo_wait(4);
  242. writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET);
  243. writel(par->xres, remapped_regs + mmDST_PITCH);
  244. writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET);
  245. writel(par->xres, remapped_regs + mmSRC_PITCH);
  246. w100_fifo_wait(3);
  247. writel(0, remapped_regs + mmSC_TOP_LEFT);
  248. writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT);
  249. writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT);
  250. w100_fifo_wait(4);
  251. dp_cntl.val = 0;
  252. dp_cntl.f.dst_x_dir = 1;
  253. dp_cntl.f.dst_y_dir = 1;
  254. dp_cntl.f.src_x_dir = 1;
  255. dp_cntl.f.src_y_dir = 1;
  256. dp_cntl.f.dst_major_x = 1;
  257. dp_cntl.f.src_major_x = 1;
  258. writel(dp_cntl.val, remapped_regs + mmDP_CNTL);
  259. gmc.val = 0;
  260. gmc.f.gmc_src_pitch_offset_cntl = 1;
  261. gmc.f.gmc_dst_pitch_offset_cntl = 1;
  262. gmc.f.gmc_src_clipping = 1;
  263. gmc.f.gmc_dst_clipping = 1;
  264. gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
  265. gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */
  266. gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST;
  267. gmc.f.gmc_byte_pix_order = 1;
  268. gmc.f.gmc_default_sel = 0;
  269. gmc.f.gmc_rop3 = ROP3_SRCCOPY;
  270. gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR;
  271. gmc.f.gmc_clr_cmp_fcn_dis = 1;
  272. gmc.f.gmc_wr_msk_dis = 1;
  273. gmc.f.gmc_dp_op = DP_OP_ROP;
  274. writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
  275. dp_datatype.val = dp_mix.val = 0;
  276. dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype;
  277. dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype;
  278. dp_datatype.f.dp_src2_type = 0;
  279. dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype;
  280. dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype;
  281. dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order;
  282. writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE);
  283. dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source;
  284. dp_mix.f.dp_src2_source = 1;
  285. dp_mix.f.dp_rop3 = gmc.f.gmc_rop3;
  286. dp_mix.f.dp_op = gmc.f.gmc_dp_op;
  287. writel(dp_mix.val, remapped_regs + mmDP_MIX);
  288. }
  289. static void w100fb_fillrect(struct fb_info *info,
  290. const struct fb_fillrect *rect)
  291. {
  292. union dp_gui_master_cntl_u gmc;
  293. if (info->state != FBINFO_STATE_RUNNING)
  294. return;
  295. if (info->flags & FBINFO_HWACCEL_DISABLED) {
  296. cfb_fillrect(info, rect);
  297. return;
  298. }
  299. gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
  300. gmc.f.gmc_rop3 = ROP3_PATCOPY;
  301. gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR;
  302. w100_fifo_wait(2);
  303. writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
  304. writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR);
  305. w100_fifo_wait(2);
  306. writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X);
  307. writel((rect->width << 16) | (rect->height & 0xffff),
  308. remapped_regs + mmDST_WIDTH_HEIGHT);
  309. }
  310. static void w100fb_copyarea(struct fb_info *info,
  311. const struct fb_copyarea *area)
  312. {
  313. u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
  314. u32 h = area->height, w = area->width;
  315. union dp_gui_master_cntl_u gmc;
  316. if (info->state != FBINFO_STATE_RUNNING)
  317. return;
  318. if (info->flags & FBINFO_HWACCEL_DISABLED) {
  319. cfb_copyarea(info, area);
  320. return;
  321. }
  322. gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
  323. gmc.f.gmc_rop3 = ROP3_SRCCOPY;
  324. gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
  325. w100_fifo_wait(1);
  326. writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
  327. w100_fifo_wait(3);
  328. writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X);
  329. writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X);
  330. writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);
  331. }
  332. /*
  333. * Change the resolution by calling the appropriate hardware functions
  334. */
  335. static void w100fb_activate_var(struct w100fb_par *par)
  336. {
  337. struct w100_tg_info *tg = par->mach->tg;
  338. w100_pwm_setup(par);
  339. w100_setup_memory(par);
  340. w100_init_clocks(par);
  341. w100fb_clear_screen(par);
  342. w100_vsync();
  343. w100_update_disable();
  344. w100_init_lcd(par);
  345. w100_set_dispregs(par);
  346. w100_update_enable();
  347. w100_init_graphic_engine(par);
  348. calc_hsync(par);
  349. if (!par->blanked && tg && tg->change)
  350. tg->change(par);
  351. }
  352. /* Select the smallest mode that allows the desired resolution to be
  353. * displayed. If desired, the x and y parameters can be rounded up to
  354. * match the selected mode.
  355. */
  356. static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
  357. {
  358. struct w100_mode *mode = NULL;
  359. struct w100_mode *modelist = par->mach->modelist;
  360. unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
  361. unsigned int i;
  362. for (i = 0 ; i < par->mach->num_modes ; i++) {
  363. if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
  364. modelist[i].xres < best_x && modelist[i].yres < best_y) {
  365. best_x = modelist[i].xres;
  366. best_y = modelist[i].yres;
  367. mode = &modelist[i];
  368. } else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
  369. modelist[i].xres < best_y && modelist[i].yres < best_x) {
  370. best_x = modelist[i].yres;
  371. best_y = modelist[i].xres;
  372. mode = &modelist[i];
  373. }
  374. }
  375. if (mode && saveval) {
  376. *x = best_x;
  377. *y = best_y;
  378. }
  379. return mode;
  380. }
  381. /*
  382. * w100fb_check_var():
  383. * Get the video params out of 'var'. If a value doesn't fit, round it up,
  384. * if it's too big, return -EINVAL.
  385. */
  386. static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  387. {
  388. struct w100fb_par *par=info->par;
  389. if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
  390. return -EINVAL;
  391. if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
  392. return -EINVAL;
  393. if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
  394. return -EINVAL;
  395. var->xres_virtual = max(var->xres_virtual, var->xres);
  396. var->yres_virtual = max(var->yres_virtual, var->yres);
  397. if (var->bits_per_pixel > BITS_PER_PIXEL)
  398. return -EINVAL;
  399. else
  400. var->bits_per_pixel = BITS_PER_PIXEL;
  401. var->red.offset = 11;
  402. var->red.length = 5;
  403. var->green.offset = 5;
  404. var->green.length = 6;
  405. var->blue.offset = 0;
  406. var->blue.length = 5;
  407. var->transp.offset = var->transp.length = 0;
  408. var->nonstd = 0;
  409. var->height = -1;
  410. var->width = -1;
  411. var->vmode = FB_VMODE_NONINTERLACED;
  412. var->sync = 0;
  413. var->pixclock = 0x04; /* 171521; */
  414. return 0;
  415. }
  416. /*
  417. * w100fb_set_par():
  418. * Set the user defined part of the display for the specified console
  419. * by looking at the values in info.var
  420. */
  421. static int w100fb_set_par(struct fb_info *info)
  422. {
  423. struct w100fb_par *par=info->par;
  424. if (par->xres != info->var.xres || par->yres != info->var.yres) {
  425. par->xres = info->var.xres;
  426. par->yres = info->var.yres;
  427. par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
  428. info->fix.visual = FB_VISUAL_TRUECOLOR;
  429. info->fix.ypanstep = 0;
  430. info->fix.ywrapstep = 0;
  431. info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
  432. mutex_lock(&info->mm_lock);
  433. if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
  434. par->extmem_active = 1;
  435. info->fix.smem_len = par->mach->mem->size+1;
  436. } else {
  437. par->extmem_active = 0;
  438. info->fix.smem_len = MEM_INT_SIZE+1;
  439. }
  440. mutex_unlock(&info->mm_lock);
  441. w100fb_activate_var(par);
  442. }
  443. return 0;
  444. }
  445. /*
  446. * Frame buffer operations
  447. */
  448. static struct fb_ops w100fb_ops = {
  449. .owner = THIS_MODULE,
  450. .fb_check_var = w100fb_check_var,
  451. .fb_set_par = w100fb_set_par,
  452. .fb_setcolreg = w100fb_setcolreg,
  453. .fb_blank = w100fb_blank,
  454. .fb_fillrect = w100fb_fillrect,
  455. .fb_copyarea = w100fb_copyarea,
  456. .fb_imageblit = cfb_imageblit,
  457. .fb_sync = w100fb_sync,
  458. };
  459. #ifdef CONFIG_PM
  460. static void w100fb_save_vidmem(struct w100fb_par *par)
  461. {
  462. int memsize;
  463. if (par->extmem_active) {
  464. memsize=par->mach->mem->size;
  465. par->saved_extmem = vmalloc(memsize);
  466. if (par->saved_extmem)
  467. memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
  468. }
  469. memsize=MEM_INT_SIZE;
  470. par->saved_intmem = vmalloc(memsize);
  471. if (par->saved_intmem && par->extmem_active)
  472. memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
  473. else if (par->saved_intmem)
  474. memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
  475. }
  476. static void w100fb_restore_vidmem(struct w100fb_par *par)
  477. {
  478. int memsize;
  479. if (par->extmem_active && par->saved_extmem) {
  480. memsize=par->mach->mem->size;
  481. memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
  482. vfree(par->saved_extmem);
  483. }
  484. if (par->saved_intmem) {
  485. memsize=MEM_INT_SIZE;
  486. if (par->extmem_active)
  487. memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
  488. else
  489. memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
  490. vfree(par->saved_intmem);
  491. }
  492. }
  493. static int w100fb_suspend(struct platform_device *dev, pm_message_t state)
  494. {
  495. struct fb_info *info = platform_get_drvdata(dev);
  496. struct w100fb_par *par=info->par;
  497. struct w100_tg_info *tg = par->mach->tg;
  498. w100fb_save_vidmem(par);
  499. if(tg && tg->suspend)
  500. tg->suspend(par);
  501. w100_suspend(W100_SUSPEND_ALL);
  502. par->blanked = 1;
  503. return 0;
  504. }
  505. static int w100fb_resume(struct platform_device *dev)
  506. {
  507. struct fb_info *info = platform_get_drvdata(dev);
  508. struct w100fb_par *par=info->par;
  509. struct w100_tg_info *tg = par->mach->tg;
  510. w100_hw_init(par);
  511. w100fb_activate_var(par);
  512. w100fb_restore_vidmem(par);
  513. if(tg && tg->resume)
  514. tg->resume(par);
  515. par->blanked = 0;
  516. return 0;
  517. }
  518. #else
  519. #define w100fb_suspend NULL
  520. #define w100fb_resume NULL
  521. #endif
  522. int __devinit w100fb_probe(struct platform_device *pdev)
  523. {
  524. int err = -EIO;
  525. struct w100fb_mach_info *inf;
  526. struct fb_info *info = NULL;
  527. struct w100fb_par *par;
  528. struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  529. unsigned int chip_id;
  530. if (!mem)
  531. return -EINVAL;
  532. /* Remap the chip base address */
  533. remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN);
  534. if (remapped_base == NULL)
  535. goto out;
  536. /* Map the register space */
  537. remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN);
  538. if (remapped_regs == NULL)
  539. goto out;
  540. /* Identify the chip */
  541. printk("Found ");
  542. chip_id = readl(remapped_regs + mmCHIP_ID);
  543. switch(chip_id) {
  544. case CHIP_ID_W100: printk("w100"); break;
  545. case CHIP_ID_W3200: printk("w3200"); break;
  546. case CHIP_ID_W3220: printk("w3220"); break;
  547. default:
  548. printk("Unknown imageon chip ID\n");
  549. err = -ENODEV;
  550. goto out;
  551. }
  552. printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE);
  553. /* Remap the framebuffer */
  554. remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
  555. if (remapped_fbuf == NULL)
  556. goto out;
  557. info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
  558. if (!info) {
  559. err = -ENOMEM;
  560. goto out;
  561. }
  562. par = info->par;
  563. platform_set_drvdata(pdev, info);
  564. inf = pdev->dev.platform_data;
  565. par->chip_id = chip_id;
  566. par->mach = inf;
  567. par->fastpll_mode = 0;
  568. par->blanked = 0;
  569. par->pll_table=w100_get_xtal_table(inf->xtal_freq);
  570. if (!par->pll_table) {
  571. printk(KERN_ERR "No matching Xtal definition found\n");
  572. err = -EINVAL;
  573. goto out;
  574. }
  575. info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL);
  576. if (!info->pseudo_palette) {
  577. err = -ENOMEM;
  578. goto out;
  579. }
  580. info->fbops = &w100fb_ops;
  581. info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
  582. FBINFO_HWACCEL_FILLRECT;
  583. info->node = -1;
  584. info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
  585. info->screen_size = REMAPPED_FB_LEN;
  586. strcpy(info->fix.id, "w100fb");
  587. info->fix.type = FB_TYPE_PACKED_PIXELS;
  588. info->fix.type_aux = 0;
  589. info->fix.accel = FB_ACCEL_NONE;
  590. info->fix.smem_start = mem->start+W100_FB_BASE;
  591. info->fix.mmio_start = mem->start+W100_REG_BASE;
  592. info->fix.mmio_len = W100_REG_LEN;
  593. if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
  594. err = -ENOMEM;
  595. goto out;
  596. }
  597. par->mode = &inf->modelist[0];
  598. if(inf->init_mode & INIT_MODE_ROTATED) {
  599. info->var.xres = par->mode->yres;
  600. info->var.yres = par->mode->xres;
  601. }
  602. else {
  603. info->var.xres = par->mode->xres;
  604. info->var.yres = par->mode->yres;
  605. }
  606. if(inf->init_mode &= INIT_MODE_FLIPPED)
  607. par->flip = 1;
  608. else
  609. par->flip = 0;
  610. info->var.xres_virtual = info->var.xres;
  611. info->var.yres_virtual = info->var.yres;
  612. info->var.pixclock = 0x04; /* 171521; */
  613. info->var.sync = 0;
  614. info->var.grayscale = 0;
  615. info->var.xoffset = info->var.yoffset = 0;
  616. info->var.accel_flags = 0;
  617. info->var.activate = FB_ACTIVATE_NOW;
  618. w100_hw_init(par);
  619. if (w100fb_check_var(&info->var, info) < 0) {
  620. err = -EINVAL;
  621. goto out;
  622. }
  623. if (register_framebuffer(info) < 0) {
  624. err = -EINVAL;
  625. goto out;
  626. }
  627. err = device_create_file(&pdev->dev, &dev_attr_fastpllclk);
  628. err |= device_create_file(&pdev->dev, &dev_attr_reg_read);
  629. err |= device_create_file(&pdev->dev, &dev_attr_reg_write);
  630. err |= device_create_file(&pdev->dev, &dev_attr_flip);
  631. if (err != 0)
  632. printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n",
  633. info->node, err);
  634. printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
  635. return 0;
  636. out:
  637. if (info) {
  638. fb_dealloc_cmap(&info->cmap);
  639. kfree(info->pseudo_palette);
  640. }
  641. if (remapped_fbuf != NULL)
  642. iounmap(remapped_fbuf);
  643. if (remapped_regs != NULL)
  644. iounmap(remapped_regs);
  645. if (remapped_base != NULL)
  646. iounmap(remapped_base);
  647. if (info)
  648. framebuffer_release(info);
  649. return err;
  650. }
  651. static int __devexit w100fb_remove(struct platform_device *pdev)
  652. {
  653. struct fb_info *info = platform_get_drvdata(pdev);
  654. struct w100fb_par *par=info->par;
  655. device_remove_file(&pdev->dev, &dev_attr_fastpllclk);
  656. device_remove_file(&pdev->dev, &dev_attr_reg_read);
  657. device_remove_file(&pdev->dev, &dev_attr_reg_write);
  658. device_remove_file(&pdev->dev, &dev_attr_flip);
  659. unregister_framebuffer(info);
  660. vfree(par->saved_intmem);
  661. vfree(par->saved_extmem);
  662. kfree(info->pseudo_palette);
  663. fb_dealloc_cmap(&info->cmap);
  664. iounmap(remapped_base);
  665. iounmap(remapped_regs);
  666. iounmap(remapped_fbuf);
  667. framebuffer_release(info);
  668. return 0;
  669. }
  670. /* ------------------- chipset specific functions -------------------------- */
  671. static void w100_soft_reset(void)
  672. {
  673. u16 val = readw((u16 *) remapped_base + cfgSTATUS);
  674. writew(val | 0x08, (u16 *) remapped_base + cfgSTATUS);
  675. udelay(100);
  676. writew(0x00, (u16 *) remapped_base + cfgSTATUS);
  677. udelay(100);
  678. }
  679. static void w100_update_disable(void)
  680. {
  681. union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
  682. /* Prevent display updates */
  683. disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
  684. disp_db_buf_wr_cntl.f.update_db_buf = 0;
  685. disp_db_buf_wr_cntl.f.en_db_buf = 0;
  686. writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
  687. }
  688. static void w100_update_enable(void)
  689. {
  690. union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
  691. /* Enable display updates */
  692. disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
  693. disp_db_buf_wr_cntl.f.update_db_buf = 1;
  694. disp_db_buf_wr_cntl.f.en_db_buf = 1;
  695. writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
  696. }
  697. unsigned long w100fb_gpio_read(int port)
  698. {
  699. unsigned long value;
  700. if (port==W100_GPIO_PORT_A)
  701. value = readl(remapped_regs + mmGPIO_DATA);
  702. else
  703. value = readl(remapped_regs + mmGPIO_DATA2);
  704. return value;
  705. }
  706. void w100fb_gpio_write(int port, unsigned long value)
  707. {
  708. if (port==W100_GPIO_PORT_A)
  709. writel(value, remapped_regs + mmGPIO_DATA);
  710. else
  711. writel(value, remapped_regs + mmGPIO_DATA2);
  712. }
  713. EXPORT_SYMBOL(w100fb_gpio_read);
  714. EXPORT_SYMBOL(w100fb_gpio_write);
  715. /*
  716. * Initialization of critical w100 hardware
  717. */
  718. static void w100_hw_init(struct w100fb_par *par)
  719. {
  720. u32 temp32;
  721. union cif_cntl_u cif_cntl;
  722. union intf_cntl_u intf_cntl;
  723. union cfgreg_base_u cfgreg_base;
  724. union wrap_top_dir_u wrap_top_dir;
  725. union cif_read_dbg_u cif_read_dbg;
  726. union cpu_defaults_u cpu_default;
  727. union cif_write_dbg_u cif_write_dbg;
  728. union wrap_start_dir_u wrap_start_dir;
  729. union cif_io_u cif_io;
  730. struct w100_gpio_regs *gpio = par->mach->gpio;
  731. w100_soft_reset();
  732. /* This is what the fpga_init code does on reset. May be wrong
  733. but there is little info available */
  734. writel(0x31, remapped_regs + mmSCRATCH_UMSK);
  735. for (temp32 = 0; temp32 < 10000; temp32++)
  736. readl(remapped_regs + mmSCRATCH_UMSK);
  737. writel(0x30, remapped_regs + mmSCRATCH_UMSK);
  738. /* Set up CIF */
  739. cif_io.val = defCIF_IO;
  740. writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
  741. cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
  742. cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
  743. cif_write_dbg.f.en_dword_split_to_rbbm = 1;
  744. cif_write_dbg.f.dis_timeout_during_rbbm = 1;
  745. writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
  746. cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
  747. cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
  748. writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
  749. cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
  750. cif_cntl.f.dis_system_bits = 1;
  751. cif_cntl.f.dis_mr = 1;
  752. cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
  753. cif_cntl.f.intb_oe = 1;
  754. cif_cntl.f.interrupt_active_high = 1;
  755. writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
  756. /* Setup cfgINTF_CNTL and cfgCPU defaults */
  757. intf_cntl.val = defINTF_CNTL;
  758. intf_cntl.f.ad_inc_a = 1;
  759. intf_cntl.f.ad_inc_b = 1;
  760. intf_cntl.f.rd_data_rdy_a = 0;
  761. intf_cntl.f.rd_data_rdy_b = 0;
  762. writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
  763. cpu_default.val = defCPU_DEFAULTS;
  764. cpu_default.f.access_ind_addr_a = 1;
  765. cpu_default.f.access_ind_addr_b = 1;
  766. cpu_default.f.access_scratch_reg = 1;
  767. cpu_default.f.transition_size = 0;
  768. writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
  769. /* set up the apertures */
  770. writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
  771. cfgreg_base.val = defCFGREG_BASE;
  772. cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
  773. writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
  774. wrap_start_dir.val = defWRAP_START_DIR;
  775. wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
  776. writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
  777. wrap_top_dir.val = defWRAP_TOP_DIR;
  778. wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
  779. writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
  780. writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
  781. /* Set the hardware to 565 colour */
  782. temp32 = readl(remapped_regs + mmDISP_DEBUG2);
  783. temp32 &= 0xff7fffff;
  784. temp32 |= 0x00800000;
  785. writel(temp32, remapped_regs + mmDISP_DEBUG2);
  786. /* Initialise the GPIO lines */
  787. if (gpio) {
  788. writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
  789. writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
  790. writel(gpio->gpio_dir1, remapped_regs + mmGPIO_CNTL1);
  791. writel(gpio->gpio_oe1, remapped_regs + mmGPIO_CNTL2);
  792. writel(gpio->gpio_dir2, remapped_regs + mmGPIO_CNTL3);
  793. writel(gpio->gpio_oe2, remapped_regs + mmGPIO_CNTL4);
  794. }
  795. }
  796. struct power_state {
  797. union clk_pin_cntl_u clk_pin_cntl;
  798. union pll_ref_fb_div_u pll_ref_fb_div;
  799. union pll_cntl_u pll_cntl;
  800. union sclk_cntl_u sclk_cntl;
  801. union pclk_cntl_u pclk_cntl;
  802. union pwrmgt_cntl_u pwrmgt_cntl;
  803. int auto_mode; /* system clock auto changing? */
  804. };
  805. static struct power_state w100_pwr_state;
  806. /* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
  807. /* 12.5MHz Crystal PLL Table */
  808. static struct w100_pll_info xtal_12500000[] = {
  809. /*freq M N_int N_fac tfgoal lock_time */
  810. { 50, 0, 1, 0, 0xe0, 56}, /* 50.00 MHz */
  811. { 75, 0, 5, 0, 0xde, 37}, /* 75.00 MHz */
  812. {100, 0, 7, 0, 0xe0, 28}, /* 100.00 MHz */
  813. {125, 0, 9, 0, 0xe0, 22}, /* 125.00 MHz */
  814. {150, 0, 11, 0, 0xe0, 17}, /* 150.00 MHz */
  815. { 0, 0, 0, 0, 0, 0}, /* Terminator */
  816. };
  817. /* 14.318MHz Crystal PLL Table */
  818. static struct w100_pll_info xtal_14318000[] = {
  819. /*freq M N_int N_fac tfgoal lock_time */
  820. { 40, 4, 13, 0, 0xe0, 80}, /* tfgoal guessed */
  821. { 50, 1, 6, 0, 0xe0, 64}, /* 50.05 MHz */
  822. { 57, 2, 11, 0, 0xe0, 53}, /* tfgoal guessed */
  823. { 75, 0, 4, 3, 0xe0, 43}, /* 75.08 MHz */
  824. {100, 0, 6, 0, 0xe0, 32}, /* 100.10 MHz */
  825. { 0, 0, 0, 0, 0, 0},
  826. };
  827. /* 16MHz Crystal PLL Table */
  828. static struct w100_pll_info xtal_16000000[] = {
  829. /*freq M N_int N_fac tfgoal lock_time */
  830. { 72, 1, 8, 0, 0xe0, 48}, /* tfgoal guessed */
  831. { 80, 1, 9, 0, 0xe0, 13}, /* tfgoal guessed */
  832. { 95, 1, 10, 7, 0xe0, 38}, /* tfgoal guessed */
  833. { 96, 1, 11, 0, 0xe0, 36}, /* tfgoal guessed */
  834. { 0, 0, 0, 0, 0, 0},
  835. };
  836. static struct pll_entries {
  837. int xtal_freq;
  838. struct w100_pll_info *pll_table;
  839. } w100_pll_tables[] = {
  840. { 12500000, &xtal_12500000[0] },
  841. { 14318000, &xtal_14318000[0] },
  842. { 16000000, &xtal_16000000[0] },
  843. { 0 },
  844. };
  845. struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq)
  846. {
  847. struct pll_entries *pll_entry = w100_pll_tables;
  848. do {
  849. if (freq == pll_entry->xtal_freq)
  850. return pll_entry->pll_table;
  851. pll_entry++;
  852. } while (pll_entry->xtal_freq);
  853. return 0;
  854. }
  855. static unsigned int w100_get_testcount(unsigned int testclk_sel)
  856. {
  857. union clk_test_cntl_u clk_test_cntl;
  858. udelay(5);
  859. /* Select the test clock source and reset */
  860. clk_test_cntl.f.start_check_freq = 0x0;
  861. clk_test_cntl.f.testclk_sel = testclk_sel;
  862. clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
  863. writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
  864. clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
  865. writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
  866. /* Run clock test */
  867. clk_test_cntl.f.start_check_freq = 0x1;
  868. writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
  869. /* Give the test time to complete */
  870. udelay(20);
  871. /* Return the result */
  872. clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
  873. clk_test_cntl.f.start_check_freq = 0x0;
  874. writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
  875. return clk_test_cntl.f.test_count;
  876. }
  877. static int w100_pll_adjust(struct w100_pll_info *pll)
  878. {
  879. unsigned int tf80;
  880. unsigned int tf20;
  881. /* Initial Settings */
  882. w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */
  883. w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */
  884. w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */
  885. w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */
  886. w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */
  887. w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */
  888. w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
  889. /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
  890. * therefore, commented out the following lines
  891. * tf80 meant tf100
  892. */
  893. do {
  894. /* set VCO input = 0.8 * VDD */
  895. w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
  896. writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
  897. tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
  898. if (tf80 >= (pll->tfgoal)) {
  899. /* set VCO input = 0.2 * VDD */
  900. w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
  901. writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
  902. tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
  903. if (tf20 <= (pll->tfgoal))
  904. return 1; /* Success */
  905. if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
  906. ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
  907. (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
  908. /* slow VCO config */
  909. w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
  910. w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
  911. w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
  912. continue;
  913. }
  914. }
  915. if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
  916. w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
  917. } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
  918. w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
  919. w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
  920. } else {
  921. return 0; /* Error */
  922. }
  923. } while(1);
  924. }
  925. /*
  926. * w100_pll_calibration
  927. */
  928. static int w100_pll_calibration(struct w100_pll_info *pll)
  929. {
  930. int status;
  931. status = w100_pll_adjust(pll);
  932. /* PLL Reset And Lock */
  933. /* set VCO input = 0.5 * VDD */
  934. w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
  935. writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
  936. udelay(1); /* reset time */
  937. /* enable charge pump */
  938. w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */
  939. writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
  940. /* set VCO input = Hi-Z, disable DAC */
  941. w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
  942. writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
  943. udelay(400); /* lock time */
  944. /* PLL locked */
  945. return status;
  946. }
  947. static int w100_pll_set_clk(struct w100_pll_info *pll)
  948. {
  949. int status;
  950. if (w100_pwr_state.auto_mode == 1) /* auto mode */
  951. {
  952. w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */
  953. w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */
  954. writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
  955. }
  956. /* Set system clock source to XTAL whilst adjusting the PLL! */
  957. w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
  958. writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
  959. w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
  960. w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
  961. w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
  962. w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
  963. writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
  964. w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
  965. writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
  966. status = w100_pll_calibration(pll);
  967. if (w100_pwr_state.auto_mode == 1) /* auto mode */
  968. {
  969. w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */
  970. w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */
  971. writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
  972. }
  973. return status;
  974. }
  975. /* freq = target frequency of the PLL */
  976. static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
  977. {
  978. struct w100_pll_info *pll = par->pll_table;
  979. do {
  980. if (freq == pll->freq) {
  981. return w100_pll_set_clk(pll);
  982. }
  983. pll++;
  984. } while(pll->freq);
  985. return 0;
  986. }
  987. /* Set up an initial state. Some values/fields set
  988. here will be overwritten. */
  989. static void w100_pwm_setup(struct w100fb_par *par)
  990. {
  991. w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
  992. w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
  993. w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
  994. w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
  995. w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
  996. w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
  997. writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
  998. w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
  999. w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */
  1000. w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
  1001. w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
  1002. w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
  1003. w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */
  1004. w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */
  1005. w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */
  1006. w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */
  1007. w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */
  1008. w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */
  1009. w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */
  1010. w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */
  1011. w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */
  1012. w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
  1013. w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
  1014. w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
  1015. w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
  1016. writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
  1017. w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
  1018. w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */
  1019. w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */
  1020. writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
  1021. w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */
  1022. w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */
  1023. w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
  1024. w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
  1025. w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
  1026. writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
  1027. w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
  1028. w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
  1029. w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
  1030. w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */
  1031. w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
  1032. w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
  1033. w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
  1034. w100_pwr_state.pll_cntl.f.pll_pcp = 0x4;
  1035. w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
  1036. w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;
  1037. w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
  1038. w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
  1039. w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
  1040. w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */
  1041. w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
  1042. w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
  1043. w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
  1044. w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
  1045. writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
  1046. w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
  1047. w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */
  1048. w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
  1049. w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
  1050. w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
  1051. w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */
  1052. w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */
  1053. w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
  1054. w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
  1055. writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
  1056. w100_pwr_state.auto_mode = 0; /* manual mode */
  1057. }
  1058. /*
  1059. * Setup the w100 clocks for the specified mode
  1060. */
  1061. static void w100_init_clocks(struct w100fb_par *par)
  1062. {
  1063. struct w100_mode *mode = par->mode;
  1064. if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
  1065. w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
  1066. w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
  1067. w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
  1068. w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
  1069. writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
  1070. }
  1071. static void w100_init_lcd(struct w100fb_par *par)
  1072. {
  1073. u32 temp32;
  1074. struct w100_mode *mode = par->mode;
  1075. struct w100_gen_regs *regs = par->mach->regs;
  1076. union active_h_disp_u active_h_disp;
  1077. union active_v_disp_u active_v_disp;
  1078. union graphic_h_disp_u graphic_h_disp;
  1079. union graphic_v_disp_u graphic_v_disp;
  1080. union crtc_total_u crtc_total;
  1081. /* w3200 doesn't like undefined bits being set so zero register values first */
  1082. active_h_disp.val = 0;
  1083. active_h_disp.f.active_h_start=mode->left_margin;
  1084. active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
  1085. writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
  1086. active_v_disp.val = 0;
  1087. active_v_disp.f.active_v_start=mode->upper_margin;
  1088. active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
  1089. writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
  1090. graphic_h_disp.val = 0;
  1091. graphic_h_disp.f.graphic_h_start=mode->left_margin;
  1092. graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
  1093. writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
  1094. graphic_v_disp.val = 0;
  1095. graphic_v_disp.f.graphic_v_start=mode->upper_margin;
  1096. graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
  1097. writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
  1098. crtc_total.val = 0;
  1099. crtc_total.f.crtc_h_total=mode->left_margin + mode->xres + mode->right_margin;
  1100. crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
  1101. writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
  1102. writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
  1103. writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
  1104. writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
  1105. writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
  1106. writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
  1107. writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
  1108. writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
  1109. writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
  1110. writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
  1111. writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
  1112. writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
  1113. writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
  1114. writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
  1115. writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
  1116. writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
  1117. writel(0x00000000, remapped_regs + mmCRTC_FRAME);
  1118. writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
  1119. writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
  1120. writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
  1121. /* Hack for overlay in ext memory */
  1122. temp32 = readl(remapped_regs + mmDISP_DEBUG2);
  1123. temp32 |= 0xc0000000;
  1124. writel(temp32, remapped_regs + mmDISP_DEBUG2);
  1125. }
  1126. static void w100_setup_memory(struct w100fb_par *par)
  1127. {
  1128. union mc_ext_mem_location_u extmem_location;
  1129. union mc_fb_location_u intmem_location;
  1130. struct w100_mem_info *mem = par->mach->mem;
  1131. struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
  1132. if (!par->extmem_active) {
  1133. w100_suspend(W100_SUSPEND_EXTMEM);
  1134. /* Map Internal Memory at FB Base */
  1135. intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
  1136. intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
  1137. writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
  1138. /* Unmap External Memory - value is *probably* irrelevant but may have meaning
  1139. to acceleration libraries */
  1140. extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
  1141. extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
  1142. writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
  1143. } else {
  1144. /* Map Internal Memory to its default location */
  1145. intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
  1146. intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
  1147. writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
  1148. /* Map External Memory at FB Base */
  1149. extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
  1150. extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
  1151. writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
  1152. writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
  1153. writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
  1154. writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
  1155. udelay(100);
  1156. writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
  1157. udelay(100);
  1158. writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
  1159. udelay(100);
  1160. writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
  1161. writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
  1162. if (bm_mem) {
  1163. writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
  1164. writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
  1165. writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
  1166. writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
  1167. writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
  1168. writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
  1169. writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
  1170. }
  1171. }
  1172. }
  1173. static void w100_set_dispregs(struct w100fb_par *par)
  1174. {
  1175. unsigned long rot=0, divider, offset=0;
  1176. union graphic_ctrl_u graphic_ctrl;
  1177. /* See if the mode has been rotated */
  1178. if (par->xres == par->mode->xres) {
  1179. if (par->flip) {
  1180. rot=3; /* 180 degree */
  1181. offset=(par->xres * par->yres) - 1;
  1182. } /* else 0 degree */
  1183. divider = par->mode->pixclk_divider;
  1184. } else {
  1185. if (par->flip) {
  1186. rot=2; /* 270 degree */
  1187. offset=par->xres - 1;
  1188. } else {
  1189. rot=1; /* 90 degree */
  1190. offset=par->xres * (par->yres - 1);
  1191. }
  1192. divider = par->mode->pixclk_divider_rotated;
  1193. }
  1194. graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
  1195. switch (par->chip_id) {
  1196. case CHIP_ID_W100:
  1197. graphic_ctrl.f_w100.color_depth=6;
  1198. graphic_ctrl.f_w100.en_crtc=1;
  1199. graphic_ctrl.f_w100.en_graphic_req=1;
  1200. graphic_ctrl.f_w100.en_graphic_crtc=1;
  1201. graphic_ctrl.f_w100.lcd_pclk_on=1;
  1202. graphic_ctrl.f_w100.lcd_sclk_on=1;
  1203. graphic_ctrl.f_w100.low_power_on=0;
  1204. graphic_ctrl.f_w100.req_freq=0;
  1205. graphic_ctrl.f_w100.portrait_mode=rot;
  1206. /* Zaurus needs this */
  1207. switch(par->xres) {
  1208. case 240:
  1209. case 320:
  1210. default:
  1211. graphic_ctrl.f_w100.total_req_graphic=0xa0;
  1212. break;
  1213. case 480:
  1214. case 640:
  1215. switch(rot) {
  1216. case 0: /* 0 */
  1217. case 3: /* 180 */
  1218. graphic_ctrl.f_w100.low_power_on=1;
  1219. graphic_ctrl.f_w100.req_freq=5;
  1220. break;
  1221. case 1: /* 90 */
  1222. case 2: /* 270 */
  1223. graphic_ctrl.f_w100.req_freq=4;
  1224. break;
  1225. default:
  1226. break;
  1227. }
  1228. graphic_ctrl.f_w100.total_req_graphic=0xf0;
  1229. break;
  1230. }
  1231. break;
  1232. case CHIP_ID_W3200:
  1233. case CHIP_ID_W3220:
  1234. graphic_ctrl.f_w32xx.color_depth=6;
  1235. graphic_ctrl.f_w32xx.en_crtc=1;
  1236. graphic_ctrl.f_w32xx.en_graphic_req=1;
  1237. graphic_ctrl.f_w32xx.en_graphic_crtc=1;
  1238. graphic_ctrl.f_w32xx.lcd_pclk_on=1;
  1239. graphic_ctrl.f_w32xx.lcd_sclk_on=1;
  1240. graphic_ctrl.f_w32xx.low_power_on=0;
  1241. graphic_ctrl.f_w32xx.req_freq=0;
  1242. graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
  1243. graphic_ctrl.f_w32xx.portrait_mode=rot;
  1244. break;
  1245. }
  1246. /* Set the pixel clock source and divider */
  1247. w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
  1248. w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
  1249. writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
  1250. writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
  1251. writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
  1252. writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
  1253. }
  1254. /*
  1255. * Work out how long the sync pulse lasts
  1256. * Value is 1/(time in seconds)
  1257. */
  1258. static void calc_hsync(struct w100fb_par *par)
  1259. {
  1260. unsigned long hsync;
  1261. struct w100_mode *mode = par->mode;
  1262. union crtc_ss_u crtc_ss;
  1263. if (mode->pixclk_src == CLK_SRC_XTAL)
  1264. hsync=par->mach->xtal_freq;
  1265. else
  1266. hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
  1267. hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
  1268. crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
  1269. if (crtc_ss.val)
  1270. par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
  1271. else
  1272. par->hsync_len = 0;
  1273. }
  1274. static void w100_suspend(u32 mode)
  1275. {
  1276. u32 val;
  1277. writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
  1278. writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
  1279. val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
  1280. val &= ~(0x00100000); /* bit20=0 */
  1281. val |= 0xFF000000; /* bit31:24=0xff */
  1282. writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
  1283. val = readl(remapped_regs + mmMEM_EXT_CNTL);
  1284. val &= ~(0x00040000); /* bit18=0 */
  1285. val |= 0x00080000; /* bit19=1 */
  1286. writel(val, remapped_regs + mmMEM_EXT_CNTL);
  1287. udelay(1); /* wait 1us */
  1288. if (mode == W100_SUSPEND_EXTMEM) {
  1289. /* CKE: Tri-State */
  1290. val = readl(remapped_regs + mmMEM_EXT_CNTL);
  1291. val |= 0x40000000; /* bit30=1 */
  1292. writel(val, remapped_regs + mmMEM_EXT_CNTL);
  1293. /* CLK: Stop */
  1294. val = readl(remapped_regs + mmMEM_EXT_CNTL);
  1295. val &= ~(0x00000001); /* bit0=0 */
  1296. writel(val, remapped_regs + mmMEM_EXT_CNTL);
  1297. } else {
  1298. writel(0x00000000, remapped_regs + mmSCLK_CNTL);
  1299. writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
  1300. writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
  1301. udelay(5);
  1302. val = readl(remapped_regs + mmPLL_CNTL);
  1303. val |= 0x00000004; /* bit2=1 */
  1304. writel(val, remapped_regs + mmPLL_CNTL);
  1305. writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
  1306. }
  1307. }
  1308. static void w100_vsync(void)
  1309. {
  1310. u32 tmp;
  1311. int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
  1312. tmp = readl(remapped_regs + mmACTIVE_V_DISP);
  1313. /* set vline pos */
  1314. writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL);
  1315. /* disable vline irq */
  1316. tmp = readl(remapped_regs + mmGEN_INT_CNTL);
  1317. tmp &= ~0x00000002;
  1318. writel(tmp, remapped_regs + mmGEN_INT_CNTL);
  1319. /* clear vline irq status */
  1320. writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
  1321. /* enable vline irq */
  1322. writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL);
  1323. /* clear vline irq status */
  1324. writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
  1325. while(timeout > 0) {
  1326. if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002)
  1327. break;
  1328. udelay(1);
  1329. timeout--;
  1330. }
  1331. /* disable vline irq */
  1332. writel(tmp, remapped_regs + mmGEN_INT_CNTL);
  1333. /* clear vline irq status */
  1334. writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
  1335. }
  1336. static struct platform_driver w100fb_driver = {
  1337. .probe = w100fb_probe,
  1338. .remove = __devexit_p(w100fb_remove),
  1339. .suspend = w100fb_suspend,
  1340. .resume = w100fb_resume,
  1341. .driver = {
  1342. .name = "w100fb",
  1343. },
  1344. };
  1345. int __init w100fb_init(void)
  1346. {
  1347. return platform_driver_register(&w100fb_driver);
  1348. }
  1349. void __exit w100fb_cleanup(void)
  1350. {
  1351. platform_driver_unregister(&w100fb_driver);
  1352. }
  1353. module_init(w100fb_init);
  1354. module_exit(w100fb_cleanup);
  1355. MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
  1356. MODULE_LICENSE("GPL");