sm501fb.c 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162
  1. /* linux/drivers/video/sm501fb.c
  2. *
  3. * Copyright (c) 2006 Simtec Electronics
  4. * Vincent Sanders <vince@simtec.co.uk>
  5. * Ben Dooks <ben@simtec.co.uk>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * Framebuffer driver for the Silicon Motion SM501
  12. */
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/errno.h>
  16. #include <linux/string.h>
  17. #include <linux/mm.h>
  18. #include <linux/tty.h>
  19. #include <linux/slab.h>
  20. #include <linux/delay.h>
  21. #include <linux/fb.h>
  22. #include <linux/init.h>
  23. #include <linux/vmalloc.h>
  24. #include <linux/dma-mapping.h>
  25. #include <linux/interrupt.h>
  26. #include <linux/workqueue.h>
  27. #include <linux/wait.h>
  28. #include <linux/platform_device.h>
  29. #include <linux/clk.h>
  30. #include <linux/console.h>
  31. #include <linux/io.h>
  32. #include <asm/uaccess.h>
  33. #include <asm/div64.h>
  34. #ifdef CONFIG_PM
  35. #include <linux/pm.h>
  36. #endif
  37. #include <linux/sm501.h>
  38. #include <linux/sm501-regs.h>
  39. #define NR_PALETTE 256
  40. enum sm501_controller {
  41. HEAD_CRT = 0,
  42. HEAD_PANEL = 1,
  43. };
  44. /* SM501 memory address.
  45. *
  46. * This structure is used to track memory usage within the SM501 framebuffer
  47. * allocation. The sm_addr field is stored as an offset as it is often used
  48. * against both the physical and mapped addresses.
  49. */
  50. struct sm501_mem {
  51. unsigned long size;
  52. unsigned long sm_addr; /* offset from base of sm501 fb. */
  53. void __iomem *k_addr;
  54. };
  55. /* private data that is shared between all frambuffers* */
  56. struct sm501fb_info {
  57. struct device *dev;
  58. struct fb_info *fb[2]; /* fb info for both heads */
  59. struct resource *fbmem_res; /* framebuffer resource */
  60. struct resource *regs_res; /* registers resource */
  61. struct resource *regs2d_res; /* 2d registers resource */
  62. struct sm501_platdata_fb *pdata; /* our platform data */
  63. unsigned long pm_crt_ctrl; /* pm: crt ctrl save */
  64. int irq;
  65. int swap_endian; /* set to swap rgb=>bgr */
  66. void __iomem *regs; /* remapped registers */
  67. void __iomem *regs2d; /* 2d remapped registers */
  68. void __iomem *fbmem; /* remapped framebuffer */
  69. size_t fbmem_len; /* length of remapped region */
  70. };
  71. /* per-framebuffer private data */
  72. struct sm501fb_par {
  73. u32 pseudo_palette[16];
  74. enum sm501_controller head;
  75. struct sm501_mem cursor;
  76. struct sm501_mem screen;
  77. struct fb_ops ops;
  78. void *store_fb;
  79. void *store_cursor;
  80. void __iomem *cursor_regs;
  81. struct sm501fb_info *info;
  82. };
  83. /* Helper functions */
  84. static inline int h_total(struct fb_var_screeninfo *var)
  85. {
  86. return var->xres + var->left_margin +
  87. var->right_margin + var->hsync_len;
  88. }
  89. static inline int v_total(struct fb_var_screeninfo *var)
  90. {
  91. return var->yres + var->upper_margin +
  92. var->lower_margin + var->vsync_len;
  93. }
  94. /* sm501fb_sync_regs()
  95. *
  96. * This call is mainly for PCI bus systems where we need to
  97. * ensure that any writes to the bus are completed before the
  98. * next phase, or after completing a function.
  99. */
  100. static inline void sm501fb_sync_regs(struct sm501fb_info *info)
  101. {
  102. smc501_readl(info->regs);
  103. }
  104. /* sm501_alloc_mem
  105. *
  106. * This is an attempt to lay out memory for the two framebuffers and
  107. * everything else
  108. *
  109. * |fbmem_res->start fbmem_res->end|
  110. * | |
  111. * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
  112. * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
  113. *
  114. * The "spare" space is for the 2d engine data
  115. * the fixed is space for the cursors (2x1Kbyte)
  116. *
  117. * we need to allocate memory for the 2D acceleration engine
  118. * command list and the data for the engine to deal with.
  119. *
  120. * - all allocations must be 128bit aligned
  121. * - cursors are 64x64x2 bits (1Kbyte)
  122. *
  123. */
  124. #define SM501_MEMF_CURSOR (1)
  125. #define SM501_MEMF_PANEL (2)
  126. #define SM501_MEMF_CRT (4)
  127. #define SM501_MEMF_ACCEL (8)
  128. static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
  129. unsigned int why, size_t size, u32 smem_len)
  130. {
  131. struct sm501fb_par *par;
  132. struct fb_info *fbi;
  133. unsigned int ptr;
  134. unsigned int end;
  135. switch (why) {
  136. case SM501_MEMF_CURSOR:
  137. ptr = inf->fbmem_len - size;
  138. inf->fbmem_len = ptr; /* adjust available memory. */
  139. break;
  140. case SM501_MEMF_PANEL:
  141. if (size > inf->fbmem_len)
  142. return -ENOMEM;
  143. ptr = inf->fbmem_len - size;
  144. fbi = inf->fb[HEAD_CRT];
  145. /* round down, some programs such as directfb do not draw
  146. * 0,0 correctly unless the start is aligned to a page start.
  147. */
  148. if (ptr > 0)
  149. ptr &= ~(PAGE_SIZE - 1);
  150. if (fbi && ptr < smem_len)
  151. return -ENOMEM;
  152. break;
  153. case SM501_MEMF_CRT:
  154. ptr = 0;
  155. /* check to see if we have panel memory allocated
  156. * which would put an limit on available memory. */
  157. fbi = inf->fb[HEAD_PANEL];
  158. if (fbi) {
  159. par = fbi->par;
  160. end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
  161. } else
  162. end = inf->fbmem_len;
  163. if ((ptr + size) > end)
  164. return -ENOMEM;
  165. break;
  166. case SM501_MEMF_ACCEL:
  167. fbi = inf->fb[HEAD_CRT];
  168. ptr = fbi ? smem_len : 0;
  169. fbi = inf->fb[HEAD_PANEL];
  170. if (fbi) {
  171. par = fbi->par;
  172. end = par->screen.sm_addr;
  173. } else
  174. end = inf->fbmem_len;
  175. if ((ptr + size) > end)
  176. return -ENOMEM;
  177. break;
  178. default:
  179. return -EINVAL;
  180. }
  181. mem->size = size;
  182. mem->sm_addr = ptr;
  183. mem->k_addr = inf->fbmem + ptr;
  184. dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n",
  185. __func__, mem->sm_addr, mem->k_addr, why, size);
  186. return 0;
  187. }
  188. /* sm501fb_ps_to_hz
  189. *
  190. * Converts a period in picoseconds to Hz.
  191. *
  192. * Note, we try to keep this in Hz to minimise rounding with
  193. * the limited PLL settings on the SM501.
  194. */
  195. static unsigned long sm501fb_ps_to_hz(unsigned long psvalue)
  196. {
  197. unsigned long long numerator=1000000000000ULL;
  198. /* 10^12 / picosecond period gives frequency in Hz */
  199. do_div(numerator, psvalue);
  200. return (unsigned long)numerator;
  201. }
  202. /* sm501fb_hz_to_ps is identical to the oposite transform */
  203. #define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
  204. /* sm501fb_setup_gamma
  205. *
  206. * Programs a linear 1.0 gamma ramp in case the gamma
  207. * correction is enabled without programming anything else.
  208. */
  209. static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
  210. unsigned long palette)
  211. {
  212. unsigned long value = 0;
  213. int offset;
  214. /* set gamma values */
  215. for (offset = 0; offset < 256 * 4; offset += 4) {
  216. smc501_writel(value, fbi->regs + palette + offset);
  217. value += 0x010101; /* Advance RGB by 1,1,1.*/
  218. }
  219. }
  220. /* sm501fb_check_var
  221. *
  222. * check common variables for both panel and crt
  223. */
  224. static int sm501fb_check_var(struct fb_var_screeninfo *var,
  225. struct fb_info *info)
  226. {
  227. struct sm501fb_par *par = info->par;
  228. struct sm501fb_info *sm = par->info;
  229. unsigned long tmp;
  230. /* check we can fit these values into the registers */
  231. if (var->hsync_len > 255 || var->vsync_len > 63)
  232. return -EINVAL;
  233. /* hdisplay end and hsync start */
  234. if ((var->xres + var->right_margin) > 4096)
  235. return -EINVAL;
  236. /* vdisplay end and vsync start */
  237. if ((var->yres + var->lower_margin) > 2048)
  238. return -EINVAL;
  239. /* hard limits of device */
  240. if (h_total(var) > 4096 || v_total(var) > 2048)
  241. return -EINVAL;
  242. /* check our line length is going to be 128 bit aligned */
  243. tmp = (var->xres * var->bits_per_pixel) / 8;
  244. if ((tmp & 15) != 0)
  245. return -EINVAL;
  246. /* check the virtual size */
  247. if (var->xres_virtual > 4096 || var->yres_virtual > 2048)
  248. return -EINVAL;
  249. /* can cope with 8,16 or 32bpp */
  250. if (var->bits_per_pixel <= 8)
  251. var->bits_per_pixel = 8;
  252. else if (var->bits_per_pixel <= 16)
  253. var->bits_per_pixel = 16;
  254. else if (var->bits_per_pixel == 24)
  255. var->bits_per_pixel = 32;
  256. /* set r/g/b positions and validate bpp */
  257. switch(var->bits_per_pixel) {
  258. case 8:
  259. var->red.length = var->bits_per_pixel;
  260. var->red.offset = 0;
  261. var->green.length = var->bits_per_pixel;
  262. var->green.offset = 0;
  263. var->blue.length = var->bits_per_pixel;
  264. var->blue.offset = 0;
  265. var->transp.length = 0;
  266. var->transp.offset = 0;
  267. break;
  268. case 16:
  269. if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
  270. var->blue.offset = 11;
  271. var->green.offset = 5;
  272. var->red.offset = 0;
  273. } else {
  274. var->red.offset = 11;
  275. var->green.offset = 5;
  276. var->blue.offset = 0;
  277. }
  278. var->transp.offset = 0;
  279. var->red.length = 5;
  280. var->green.length = 6;
  281. var->blue.length = 5;
  282. var->transp.length = 0;
  283. break;
  284. case 32:
  285. if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
  286. var->transp.offset = 0;
  287. var->red.offset = 8;
  288. var->green.offset = 16;
  289. var->blue.offset = 24;
  290. } else {
  291. var->transp.offset = 24;
  292. var->red.offset = 16;
  293. var->green.offset = 8;
  294. var->blue.offset = 0;
  295. }
  296. var->red.length = 8;
  297. var->green.length = 8;
  298. var->blue.length = 8;
  299. var->transp.length = 0;
  300. break;
  301. default:
  302. return -EINVAL;
  303. }
  304. return 0;
  305. }
  306. /*
  307. * sm501fb_check_var_crt():
  308. *
  309. * check the parameters for the CRT head, and either bring them
  310. * back into range, or return -EINVAL.
  311. */
  312. static int sm501fb_check_var_crt(struct fb_var_screeninfo *var,
  313. struct fb_info *info)
  314. {
  315. return sm501fb_check_var(var, info);
  316. }
  317. /* sm501fb_check_var_pnl():
  318. *
  319. * check the parameters for the CRT head, and either bring them
  320. * back into range, or return -EINVAL.
  321. */
  322. static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var,
  323. struct fb_info *info)
  324. {
  325. return sm501fb_check_var(var, info);
  326. }
  327. /* sm501fb_set_par_common
  328. *
  329. * set common registers for framebuffers
  330. */
  331. static int sm501fb_set_par_common(struct fb_info *info,
  332. struct fb_var_screeninfo *var)
  333. {
  334. struct sm501fb_par *par = info->par;
  335. struct sm501fb_info *fbi = par->info;
  336. unsigned long pixclock; /* pixelclock in Hz */
  337. unsigned long sm501pixclock; /* pixelclock the 501 can achieve in Hz */
  338. unsigned int mem_type;
  339. unsigned int clock_type;
  340. unsigned int head_addr;
  341. unsigned int smem_len;
  342. dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
  343. __func__, var->xres, var->yres, var->bits_per_pixel,
  344. var->xres_virtual, var->yres_virtual);
  345. switch (par->head) {
  346. case HEAD_CRT:
  347. mem_type = SM501_MEMF_CRT;
  348. clock_type = SM501_CLOCK_V2XCLK;
  349. head_addr = SM501_DC_CRT_FB_ADDR;
  350. break;
  351. case HEAD_PANEL:
  352. mem_type = SM501_MEMF_PANEL;
  353. clock_type = SM501_CLOCK_P2XCLK;
  354. head_addr = SM501_DC_PANEL_FB_ADDR;
  355. break;
  356. default:
  357. mem_type = 0; /* stop compiler warnings */
  358. head_addr = 0;
  359. clock_type = 0;
  360. }
  361. switch (var->bits_per_pixel) {
  362. case 8:
  363. info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  364. break;
  365. case 16:
  366. info->fix.visual = FB_VISUAL_TRUECOLOR;
  367. break;
  368. case 32:
  369. info->fix.visual = FB_VISUAL_TRUECOLOR;
  370. break;
  371. }
  372. /* allocate fb memory within 501 */
  373. info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
  374. smem_len = info->fix.line_length * var->yres_virtual;
  375. dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
  376. info->fix.line_length);
  377. if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) {
  378. dev_err(fbi->dev, "no memory available\n");
  379. return -ENOMEM;
  380. }
  381. mutex_lock(&info->mm_lock);
  382. info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
  383. info->fix.smem_len = smem_len;
  384. mutex_unlock(&info->mm_lock);
  385. info->screen_base = fbi->fbmem + par->screen.sm_addr;
  386. info->screen_size = info->fix.smem_len;
  387. /* set start of framebuffer to the screen */
  388. smc501_writel(par->screen.sm_addr | SM501_ADDR_FLIP,
  389. fbi->regs + head_addr);
  390. /* program CRT clock */
  391. pixclock = sm501fb_ps_to_hz(var->pixclock);
  392. sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type,
  393. pixclock);
  394. /* update fb layer with actual clock used */
  395. var->pixclock = sm501fb_hz_to_ps(sm501pixclock);
  396. dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz) = %lu, "
  397. "sm501pixclock = %lu, error = %ld%%\n",
  398. __func__, var->pixclock, pixclock, sm501pixclock,
  399. ((pixclock - sm501pixclock)*100)/pixclock);
  400. return 0;
  401. }
  402. /* sm501fb_set_par_geometry
  403. *
  404. * set the geometry registers for specified framebuffer.
  405. */
  406. static void sm501fb_set_par_geometry(struct fb_info *info,
  407. struct fb_var_screeninfo *var)
  408. {
  409. struct sm501fb_par *par = info->par;
  410. struct sm501fb_info *fbi = par->info;
  411. void __iomem *base = fbi->regs;
  412. unsigned long reg;
  413. if (par->head == HEAD_CRT)
  414. base += SM501_DC_CRT_H_TOT;
  415. else
  416. base += SM501_DC_PANEL_H_TOT;
  417. /* set framebuffer width and display width */
  418. reg = info->fix.line_length;
  419. reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
  420. smc501_writel(reg, fbi->regs + (par->head == HEAD_CRT ?
  421. SM501_DC_CRT_FB_OFFSET : SM501_DC_PANEL_FB_OFFSET));
  422. /* program horizontal total */
  423. reg = (h_total(var) - 1) << 16;
  424. reg |= (var->xres - 1);
  425. smc501_writel(reg, base + SM501_OFF_DC_H_TOT);
  426. /* program horizontal sync */
  427. reg = var->hsync_len << 16;
  428. reg |= var->xres + var->right_margin - 1;
  429. smc501_writel(reg, base + SM501_OFF_DC_H_SYNC);
  430. /* program vertical total */
  431. reg = (v_total(var) - 1) << 16;
  432. reg |= (var->yres - 1);
  433. smc501_writel(reg, base + SM501_OFF_DC_V_TOT);
  434. /* program vertical sync */
  435. reg = var->vsync_len << 16;
  436. reg |= var->yres + var->lower_margin - 1;
  437. smc501_writel(reg, base + SM501_OFF_DC_V_SYNC);
  438. }
  439. /* sm501fb_pan_crt
  440. *
  441. * pan the CRT display output within an virtual framebuffer
  442. */
  443. static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
  444. struct fb_info *info)
  445. {
  446. struct sm501fb_par *par = info->par;
  447. struct sm501fb_info *fbi = par->info;
  448. unsigned int bytes_pixel = var->bits_per_pixel / 8;
  449. unsigned long reg;
  450. unsigned long xoffs;
  451. xoffs = var->xoffset * bytes_pixel;
  452. reg = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
  453. reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
  454. reg |= ((xoffs & 15) / bytes_pixel) << 4;
  455. smc501_writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
  456. reg = (par->screen.sm_addr + xoffs +
  457. var->yoffset * info->fix.line_length);
  458. smc501_writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
  459. sm501fb_sync_regs(fbi);
  460. return 0;
  461. }
  462. /* sm501fb_pan_pnl
  463. *
  464. * pan the panel display output within an virtual framebuffer
  465. */
  466. static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
  467. struct fb_info *info)
  468. {
  469. struct sm501fb_par *par = info->par;
  470. struct sm501fb_info *fbi = par->info;
  471. unsigned long reg;
  472. reg = var->xoffset | (var->xres_virtual << 16);
  473. smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
  474. reg = var->yoffset | (var->yres_virtual << 16);
  475. smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
  476. sm501fb_sync_regs(fbi);
  477. return 0;
  478. }
  479. /* sm501fb_set_par_crt
  480. *
  481. * Set the CRT video mode from the fb_info structure
  482. */
  483. static int sm501fb_set_par_crt(struct fb_info *info)
  484. {
  485. struct sm501fb_par *par = info->par;
  486. struct sm501fb_info *fbi = par->info;
  487. struct fb_var_screeninfo *var = &info->var;
  488. unsigned long control; /* control register */
  489. int ret;
  490. /* activate new configuration */
  491. dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
  492. /* enable CRT DAC - note 0 is on!*/
  493. sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
  494. control = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
  495. control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
  496. SM501_DC_CRT_CONTROL_GAMMA |
  497. SM501_DC_CRT_CONTROL_BLANK |
  498. SM501_DC_CRT_CONTROL_SEL |
  499. SM501_DC_CRT_CONTROL_CP |
  500. SM501_DC_CRT_CONTROL_TVP);
  501. /* set the sync polarities before we check data source */
  502. if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
  503. control |= SM501_DC_CRT_CONTROL_HSP;
  504. if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
  505. control |= SM501_DC_CRT_CONTROL_VSP;
  506. if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
  507. /* the head is displaying panel data... */
  508. sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0,
  509. info->fix.smem_len);
  510. goto out_update;
  511. }
  512. ret = sm501fb_set_par_common(info, var);
  513. if (ret) {
  514. dev_err(fbi->dev, "failed to set common parameters\n");
  515. return ret;
  516. }
  517. sm501fb_pan_crt(var, info);
  518. sm501fb_set_par_geometry(info, var);
  519. control |= SM501_FIFO_3; /* fill if >3 free slots */
  520. switch(var->bits_per_pixel) {
  521. case 8:
  522. control |= SM501_DC_CRT_CONTROL_8BPP;
  523. break;
  524. case 16:
  525. control |= SM501_DC_CRT_CONTROL_16BPP;
  526. sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
  527. break;
  528. case 32:
  529. control |= SM501_DC_CRT_CONTROL_32BPP;
  530. sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
  531. break;
  532. default:
  533. BUG();
  534. }
  535. control |= SM501_DC_CRT_CONTROL_SEL; /* CRT displays CRT data */
  536. control |= SM501_DC_CRT_CONTROL_TE; /* enable CRT timing */
  537. control |= SM501_DC_CRT_CONTROL_ENABLE; /* enable CRT plane */
  538. out_update:
  539. dev_dbg(fbi->dev, "new control is %08lx\n", control);
  540. smc501_writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
  541. sm501fb_sync_regs(fbi);
  542. return 0;
  543. }
  544. static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
  545. {
  546. unsigned long control;
  547. void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
  548. struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
  549. control = smc501_readl(ctrl_reg);
  550. if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
  551. /* enable panel power */
  552. control |= SM501_DC_PANEL_CONTROL_VDD; /* FPVDDEN */
  553. smc501_writel(control, ctrl_reg);
  554. sm501fb_sync_regs(fbi);
  555. mdelay(10);
  556. control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */
  557. smc501_writel(control, ctrl_reg);
  558. sm501fb_sync_regs(fbi);
  559. mdelay(10);
  560. /* VBIASEN */
  561. if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
  562. if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
  563. control &= ~SM501_DC_PANEL_CONTROL_BIAS;
  564. else
  565. control |= SM501_DC_PANEL_CONTROL_BIAS;
  566. smc501_writel(control, ctrl_reg);
  567. sm501fb_sync_regs(fbi);
  568. mdelay(10);
  569. }
  570. if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
  571. if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
  572. control &= ~SM501_DC_PANEL_CONTROL_FPEN;
  573. else
  574. control |= SM501_DC_PANEL_CONTROL_FPEN;
  575. smc501_writel(control, ctrl_reg);
  576. sm501fb_sync_regs(fbi);
  577. mdelay(10);
  578. }
  579. } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
  580. /* disable panel power */
  581. if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
  582. if (pd->flags & SM501FB_FLAG_PANEL_INV_FPEN)
  583. control |= SM501_DC_PANEL_CONTROL_FPEN;
  584. else
  585. control &= ~SM501_DC_PANEL_CONTROL_FPEN;
  586. smc501_writel(control, ctrl_reg);
  587. sm501fb_sync_regs(fbi);
  588. mdelay(10);
  589. }
  590. if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
  591. if (pd->flags & SM501FB_FLAG_PANEL_INV_VBIASEN)
  592. control |= SM501_DC_PANEL_CONTROL_BIAS;
  593. else
  594. control &= ~SM501_DC_PANEL_CONTROL_BIAS;
  595. smc501_writel(control, ctrl_reg);
  596. sm501fb_sync_regs(fbi);
  597. mdelay(10);
  598. }
  599. control &= ~SM501_DC_PANEL_CONTROL_DATA;
  600. smc501_writel(control, ctrl_reg);
  601. sm501fb_sync_regs(fbi);
  602. mdelay(10);
  603. control &= ~SM501_DC_PANEL_CONTROL_VDD;
  604. smc501_writel(control, ctrl_reg);
  605. sm501fb_sync_regs(fbi);
  606. mdelay(10);
  607. }
  608. sm501fb_sync_regs(fbi);
  609. }
  610. /* sm501fb_set_par_pnl
  611. *
  612. * Set the panel video mode from the fb_info structure
  613. */
  614. static int sm501fb_set_par_pnl(struct fb_info *info)
  615. {
  616. struct sm501fb_par *par = info->par;
  617. struct sm501fb_info *fbi = par->info;
  618. struct fb_var_screeninfo *var = &info->var;
  619. unsigned long control;
  620. unsigned long reg;
  621. int ret;
  622. dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
  623. /* activate this new configuration */
  624. ret = sm501fb_set_par_common(info, var);
  625. if (ret)
  626. return ret;
  627. sm501fb_pan_pnl(var, info);
  628. sm501fb_set_par_geometry(info, var);
  629. /* update control register */
  630. control = smc501_readl(fbi->regs + SM501_DC_PANEL_CONTROL);
  631. control &= (SM501_DC_PANEL_CONTROL_GAMMA |
  632. SM501_DC_PANEL_CONTROL_VDD |
  633. SM501_DC_PANEL_CONTROL_DATA |
  634. SM501_DC_PANEL_CONTROL_BIAS |
  635. SM501_DC_PANEL_CONTROL_FPEN |
  636. SM501_DC_PANEL_CONTROL_CP |
  637. SM501_DC_PANEL_CONTROL_CK |
  638. SM501_DC_PANEL_CONTROL_HP |
  639. SM501_DC_PANEL_CONTROL_VP |
  640. SM501_DC_PANEL_CONTROL_HPD |
  641. SM501_DC_PANEL_CONTROL_VPD);
  642. control |= SM501_FIFO_3; /* fill if >3 free slots */
  643. switch(var->bits_per_pixel) {
  644. case 8:
  645. control |= SM501_DC_PANEL_CONTROL_8BPP;
  646. break;
  647. case 16:
  648. control |= SM501_DC_PANEL_CONTROL_16BPP;
  649. sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
  650. break;
  651. case 32:
  652. control |= SM501_DC_PANEL_CONTROL_32BPP;
  653. sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
  654. break;
  655. default:
  656. BUG();
  657. }
  658. smc501_writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
  659. /* panel plane top left and bottom right location */
  660. smc501_writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
  661. reg = var->xres - 1;
  662. reg |= (var->yres - 1) << 16;
  663. smc501_writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
  664. /* program panel control register */
  665. control |= SM501_DC_PANEL_CONTROL_TE; /* enable PANEL timing */
  666. control |= SM501_DC_PANEL_CONTROL_EN; /* enable PANEL gfx plane */
  667. if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
  668. control |= SM501_DC_PANEL_CONTROL_HSP;
  669. if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
  670. control |= SM501_DC_PANEL_CONTROL_VSP;
  671. smc501_writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
  672. sm501fb_sync_regs(fbi);
  673. /* ensure the panel interface is not tristated at this point */
  674. sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL,
  675. 0, SM501_SYSCTRL_PANEL_TRISTATE);
  676. /* power the panel up */
  677. sm501fb_panel_power(fbi, 1);
  678. return 0;
  679. }
  680. /* chan_to_field
  681. *
  682. * convert a colour value into a field position
  683. *
  684. * from pxafb.c
  685. */
  686. static inline unsigned int chan_to_field(unsigned int chan,
  687. struct fb_bitfield *bf)
  688. {
  689. chan &= 0xffff;
  690. chan >>= 16 - bf->length;
  691. return chan << bf->offset;
  692. }
  693. /* sm501fb_setcolreg
  694. *
  695. * set the colour mapping for modes that support palettised data
  696. */
  697. static int sm501fb_setcolreg(unsigned regno,
  698. unsigned red, unsigned green, unsigned blue,
  699. unsigned transp, struct fb_info *info)
  700. {
  701. struct sm501fb_par *par = info->par;
  702. struct sm501fb_info *fbi = par->info;
  703. void __iomem *base = fbi->regs;
  704. unsigned int val;
  705. if (par->head == HEAD_CRT)
  706. base += SM501_DC_CRT_PALETTE;
  707. else
  708. base += SM501_DC_PANEL_PALETTE;
  709. switch (info->fix.visual) {
  710. case FB_VISUAL_TRUECOLOR:
  711. /* true-colour, use pseuo-palette */
  712. if (regno < 16) {
  713. u32 *pal = par->pseudo_palette;
  714. val = chan_to_field(red, &info->var.red);
  715. val |= chan_to_field(green, &info->var.green);
  716. val |= chan_to_field(blue, &info->var.blue);
  717. pal[regno] = val;
  718. }
  719. break;
  720. case FB_VISUAL_PSEUDOCOLOR:
  721. if (regno < 256) {
  722. val = (red >> 8) << 16;
  723. val |= (green >> 8) << 8;
  724. val |= blue >> 8;
  725. smc501_writel(val, base + (regno * 4));
  726. }
  727. break;
  728. default:
  729. return 1; /* unknown type */
  730. }
  731. return 0;
  732. }
  733. /* sm501fb_blank_pnl
  734. *
  735. * Blank or un-blank the panel interface
  736. */
  737. static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info)
  738. {
  739. struct sm501fb_par *par = info->par;
  740. struct sm501fb_info *fbi = par->info;
  741. dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
  742. switch (blank_mode) {
  743. case FB_BLANK_POWERDOWN:
  744. sm501fb_panel_power(fbi, 0);
  745. break;
  746. case FB_BLANK_UNBLANK:
  747. sm501fb_panel_power(fbi, 1);
  748. break;
  749. case FB_BLANK_NORMAL:
  750. case FB_BLANK_VSYNC_SUSPEND:
  751. case FB_BLANK_HSYNC_SUSPEND:
  752. default:
  753. return 1;
  754. }
  755. return 0;
  756. }
  757. /* sm501fb_blank_crt
  758. *
  759. * Blank or un-blank the crt interface
  760. */
  761. static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
  762. {
  763. struct sm501fb_par *par = info->par;
  764. struct sm501fb_info *fbi = par->info;
  765. unsigned long ctrl;
  766. dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
  767. ctrl = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
  768. switch (blank_mode) {
  769. case FB_BLANK_POWERDOWN:
  770. ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
  771. sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
  772. case FB_BLANK_NORMAL:
  773. ctrl |= SM501_DC_CRT_CONTROL_BLANK;
  774. break;
  775. case FB_BLANK_UNBLANK:
  776. ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;
  777. ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
  778. sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
  779. break;
  780. case FB_BLANK_VSYNC_SUSPEND:
  781. case FB_BLANK_HSYNC_SUSPEND:
  782. default:
  783. return 1;
  784. }
  785. smc501_writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
  786. sm501fb_sync_regs(fbi);
  787. return 0;
  788. }
  789. /* sm501fb_cursor
  790. *
  791. * set or change the hardware cursor parameters
  792. */
  793. static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
  794. {
  795. struct sm501fb_par *par = info->par;
  796. struct sm501fb_info *fbi = par->info;
  797. void __iomem *base = fbi->regs;
  798. unsigned long hwc_addr;
  799. unsigned long fg, bg;
  800. dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);
  801. if (par->head == HEAD_CRT)
  802. base += SM501_DC_CRT_HWC_BASE;
  803. else
  804. base += SM501_DC_PANEL_HWC_BASE;
  805. /* check not being asked to exceed capabilities */
  806. if (cursor->image.width > 64)
  807. return -EINVAL;
  808. if (cursor->image.height > 64)
  809. return -EINVAL;
  810. if (cursor->image.depth > 1)
  811. return -EINVAL;
  812. hwc_addr = smc501_readl(base + SM501_OFF_HWC_ADDR);
  813. if (cursor->enable)
  814. smc501_writel(hwc_addr | SM501_HWC_EN,
  815. base + SM501_OFF_HWC_ADDR);
  816. else
  817. smc501_writel(hwc_addr & ~SM501_HWC_EN,
  818. base + SM501_OFF_HWC_ADDR);
  819. /* set data */
  820. if (cursor->set & FB_CUR_SETPOS) {
  821. unsigned int x = cursor->image.dx;
  822. unsigned int y = cursor->image.dy;
  823. if (x >= 2048 || y >= 2048 )
  824. return -EINVAL;
  825. dev_dbg(fbi->dev, "set position %d,%d\n", x, y);
  826. //y += cursor->image.height;
  827. smc501_writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
  828. }
  829. if (cursor->set & FB_CUR_SETCMAP) {
  830. unsigned int bg_col = cursor->image.bg_color;
  831. unsigned int fg_col = cursor->image.fg_color;
  832. dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",
  833. __func__, bg_col, fg_col);
  834. bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |
  835. ((info->cmap.green[bg_col] & 0xFC) << 3) |
  836. ((info->cmap.blue[bg_col] & 0xF8) >> 3);
  837. fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |
  838. ((info->cmap.green[fg_col] & 0xFC) << 3) |
  839. ((info->cmap.blue[fg_col] & 0xF8) >> 3);
  840. dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
  841. smc501_writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
  842. smc501_writel(fg, base + SM501_OFF_HWC_COLOR_3);
  843. }
  844. if (cursor->set & FB_CUR_SETSIZE ||
  845. cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
  846. /* SM501 cursor is a two bpp 64x64 bitmap this routine
  847. * clears it to transparent then combines the cursor
  848. * shape plane with the colour plane to set the
  849. * cursor */
  850. int x, y;
  851. const unsigned char *pcol = cursor->image.data;
  852. const unsigned char *pmsk = cursor->mask;
  853. void __iomem *dst = par->cursor.k_addr;
  854. unsigned char dcol = 0;
  855. unsigned char dmsk = 0;
  856. unsigned int op;
  857. dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",
  858. __func__, cursor->image.width, cursor->image.height);
  859. for (op = 0; op < (64*64*2)/8; op+=4)
  860. smc501_writel(0x0, dst + op);
  861. for (y = 0; y < cursor->image.height; y++) {
  862. for (x = 0; x < cursor->image.width; x++) {
  863. if ((x % 8) == 0) {
  864. dcol = *pcol++;
  865. dmsk = *pmsk++;
  866. } else {
  867. dcol >>= 1;
  868. dmsk >>= 1;
  869. }
  870. if (dmsk & 1) {
  871. op = (dcol & 1) ? 1 : 3;
  872. op <<= ((x % 4) * 2);
  873. op |= readb(dst + (x / 4));
  874. writeb(op, dst + (x / 4));
  875. }
  876. }
  877. dst += (64*2)/8;
  878. }
  879. }
  880. sm501fb_sync_regs(fbi); /* ensure cursor data flushed */
  881. return 0;
  882. }
  883. /* sm501fb_crtsrc_show
  884. *
  885. * device attribute code to show where the crt output is sourced from
  886. */
  887. static ssize_t sm501fb_crtsrc_show(struct device *dev,
  888. struct device_attribute *attr, char *buf)
  889. {
  890. struct sm501fb_info *info = dev_get_drvdata(dev);
  891. unsigned long ctrl;
  892. ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
  893. ctrl &= SM501_DC_CRT_CONTROL_SEL;
  894. return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
  895. }
  896. /* sm501fb_crtsrc_show
  897. *
  898. * device attribute code to set where the crt output is sourced from
  899. */
  900. static ssize_t sm501fb_crtsrc_store(struct device *dev,
  901. struct device_attribute *attr,
  902. const char *buf, size_t len)
  903. {
  904. struct sm501fb_info *info = dev_get_drvdata(dev);
  905. enum sm501_controller head;
  906. unsigned long ctrl;
  907. if (len < 1)
  908. return -EINVAL;
  909. if (strnicmp(buf, "crt", 3) == 0)
  910. head = HEAD_CRT;
  911. else if (strnicmp(buf, "panel", 5) == 0)
  912. head = HEAD_PANEL;
  913. else
  914. return -EINVAL;
  915. dev_info(dev, "setting crt source to head %d\n", head);
  916. ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
  917. if (head == HEAD_CRT) {
  918. ctrl |= SM501_DC_CRT_CONTROL_SEL;
  919. ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
  920. ctrl |= SM501_DC_CRT_CONTROL_TE;
  921. } else {
  922. ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
  923. ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
  924. ctrl &= ~SM501_DC_CRT_CONTROL_TE;
  925. }
  926. smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
  927. sm501fb_sync_regs(info);
  928. return len;
  929. }
  930. /* Prepare the device_attr for registration with sysfs later */
  931. static DEVICE_ATTR(crt_src, 0666, sm501fb_crtsrc_show, sm501fb_crtsrc_store);
  932. /* sm501fb_show_regs
  933. *
  934. * show the primary sm501 registers
  935. */
  936. static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
  937. unsigned int start, unsigned int len)
  938. {
  939. void __iomem *mem = info->regs;
  940. char *buf = ptr;
  941. unsigned int reg;
  942. for (reg = start; reg < (len + start); reg += 4)
  943. ptr += sprintf(ptr, "%08x = %08x\n", reg,
  944. smc501_readl(mem + reg));
  945. return ptr - buf;
  946. }
  947. /* sm501fb_debug_show_crt
  948. *
  949. * show the crt control and cursor registers
  950. */
  951. static ssize_t sm501fb_debug_show_crt(struct device *dev,
  952. struct device_attribute *attr, char *buf)
  953. {
  954. struct sm501fb_info *info = dev_get_drvdata(dev);
  955. char *ptr = buf;
  956. ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);
  957. ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);
  958. return ptr - buf;
  959. }
  960. static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);
  961. /* sm501fb_debug_show_pnl
  962. *
  963. * show the panel control and cursor registers
  964. */
  965. static ssize_t sm501fb_debug_show_pnl(struct device *dev,
  966. struct device_attribute *attr, char *buf)
  967. {
  968. struct sm501fb_info *info = dev_get_drvdata(dev);
  969. char *ptr = buf;
  970. ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);
  971. ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);
  972. return ptr - buf;
  973. }
  974. static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
  975. /* acceleration operations */
  976. static int sm501fb_sync(struct fb_info *info)
  977. {
  978. int count = 1000000;
  979. struct sm501fb_par *par = info->par;
  980. struct sm501fb_info *fbi = par->info;
  981. /* wait for the 2d engine to be ready */
  982. while ((count > 0) &&
  983. (smc501_readl(fbi->regs + SM501_SYSTEM_CONTROL) &
  984. SM501_SYSCTRL_2D_ENGINE_STATUS) != 0)
  985. count--;
  986. if (count <= 0) {
  987. dev_err(info->dev, "Timeout waiting for 2d engine sync\n");
  988. return 1;
  989. }
  990. return 0;
  991. }
  992. static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
  993. {
  994. struct sm501fb_par *par = info->par;
  995. struct sm501fb_info *fbi = par->info;
  996. int width = area->width;
  997. int height = area->height;
  998. int sx = area->sx;
  999. int sy = area->sy;
  1000. int dx = area->dx;
  1001. int dy = area->dy;
  1002. unsigned long rtl = 0;
  1003. /* source clip */
  1004. if ((sx >= info->var.xres_virtual) ||
  1005. (sy >= info->var.yres_virtual))
  1006. /* source Area not within virtual screen, skipping */
  1007. return;
  1008. if ((sx + width) >= info->var.xres_virtual)
  1009. width = info->var.xres_virtual - sx - 1;
  1010. if ((sy + height) >= info->var.yres_virtual)
  1011. height = info->var.yres_virtual - sy - 1;
  1012. /* dest clip */
  1013. if ((dx >= info->var.xres_virtual) ||
  1014. (dy >= info->var.yres_virtual))
  1015. /* Destination Area not within virtual screen, skipping */
  1016. return;
  1017. if ((dx + width) >= info->var.xres_virtual)
  1018. width = info->var.xres_virtual - dx - 1;
  1019. if ((dy + height) >= info->var.yres_virtual)
  1020. height = info->var.yres_virtual - dy - 1;
  1021. if ((sx < dx) || (sy < dy)) {
  1022. rtl = 1 << 27;
  1023. sx += width - 1;
  1024. dx += width - 1;
  1025. sy += height - 1;
  1026. dy += height - 1;
  1027. }
  1028. if (sm501fb_sync(info))
  1029. return;
  1030. /* set the base addresses */
  1031. smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
  1032. smc501_writel(par->screen.sm_addr,
  1033. fbi->regs2d + SM501_2D_DESTINATION_BASE);
  1034. /* set the window width */
  1035. smc501_writel((info->var.xres << 16) | info->var.xres,
  1036. fbi->regs2d + SM501_2D_WINDOW_WIDTH);
  1037. /* set window stride */
  1038. smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
  1039. fbi->regs2d + SM501_2D_PITCH);
  1040. /* set data format */
  1041. switch (info->var.bits_per_pixel) {
  1042. case 8:
  1043. smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
  1044. break;
  1045. case 16:
  1046. smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
  1047. break;
  1048. case 32:
  1049. smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
  1050. break;
  1051. }
  1052. /* 2d compare mask */
  1053. smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
  1054. /* 2d mask */
  1055. smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
  1056. /* source and destination x y */
  1057. smc501_writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
  1058. smc501_writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
  1059. /* w/h */
  1060. smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
  1061. /* do area move */
  1062. smc501_writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
  1063. }
  1064. static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  1065. {
  1066. struct sm501fb_par *par = info->par;
  1067. struct sm501fb_info *fbi = par->info;
  1068. int width = rect->width, height = rect->height;
  1069. if ((rect->dx >= info->var.xres_virtual) ||
  1070. (rect->dy >= info->var.yres_virtual))
  1071. /* Rectangle not within virtual screen, skipping */
  1072. return;
  1073. if ((rect->dx + width) >= info->var.xres_virtual)
  1074. width = info->var.xres_virtual - rect->dx - 1;
  1075. if ((rect->dy + height) >= info->var.yres_virtual)
  1076. height = info->var.yres_virtual - rect->dy - 1;
  1077. if (sm501fb_sync(info))
  1078. return;
  1079. /* set the base addresses */
  1080. smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
  1081. smc501_writel(par->screen.sm_addr,
  1082. fbi->regs2d + SM501_2D_DESTINATION_BASE);
  1083. /* set the window width */
  1084. smc501_writel((info->var.xres << 16) | info->var.xres,
  1085. fbi->regs2d + SM501_2D_WINDOW_WIDTH);
  1086. /* set window stride */
  1087. smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
  1088. fbi->regs2d + SM501_2D_PITCH);
  1089. /* set data format */
  1090. switch (info->var.bits_per_pixel) {
  1091. case 8:
  1092. smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
  1093. break;
  1094. case 16:
  1095. smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
  1096. break;
  1097. case 32:
  1098. smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
  1099. break;
  1100. }
  1101. /* 2d compare mask */
  1102. smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
  1103. /* 2d mask */
  1104. smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
  1105. /* colour */
  1106. smc501_writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
  1107. /* x y */
  1108. smc501_writel((rect->dx << 16) | rect->dy,
  1109. fbi->regs2d + SM501_2D_DESTINATION);
  1110. /* w/h */
  1111. smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
  1112. /* do rectangle fill */
  1113. smc501_writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
  1114. }
  1115. static struct fb_ops sm501fb_ops_crt = {
  1116. .owner = THIS_MODULE,
  1117. .fb_check_var = sm501fb_check_var_crt,
  1118. .fb_set_par = sm501fb_set_par_crt,
  1119. .fb_blank = sm501fb_blank_crt,
  1120. .fb_setcolreg = sm501fb_setcolreg,
  1121. .fb_pan_display = sm501fb_pan_crt,
  1122. .fb_cursor = sm501fb_cursor,
  1123. .fb_fillrect = sm501fb_fillrect,
  1124. .fb_copyarea = sm501fb_copyarea,
  1125. .fb_imageblit = cfb_imageblit,
  1126. .fb_sync = sm501fb_sync,
  1127. };
  1128. static struct fb_ops sm501fb_ops_pnl = {
  1129. .owner = THIS_MODULE,
  1130. .fb_check_var = sm501fb_check_var_pnl,
  1131. .fb_set_par = sm501fb_set_par_pnl,
  1132. .fb_pan_display = sm501fb_pan_pnl,
  1133. .fb_blank = sm501fb_blank_pnl,
  1134. .fb_setcolreg = sm501fb_setcolreg,
  1135. .fb_cursor = sm501fb_cursor,
  1136. .fb_fillrect = sm501fb_fillrect,
  1137. .fb_copyarea = sm501fb_copyarea,
  1138. .fb_imageblit = cfb_imageblit,
  1139. .fb_sync = sm501fb_sync,
  1140. };
  1141. /* sm501_init_cursor
  1142. *
  1143. * initialise hw cursor parameters
  1144. */
  1145. static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
  1146. {
  1147. struct sm501fb_par *par;
  1148. struct sm501fb_info *info;
  1149. int ret;
  1150. if (fbi == NULL)
  1151. return 0;
  1152. par = fbi->par;
  1153. info = par->info;
  1154. par->cursor_regs = info->regs + reg_base;
  1155. ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024,
  1156. fbi->fix.smem_len);
  1157. if (ret < 0)
  1158. return ret;
  1159. /* initialise the colour registers */
  1160. smc501_writel(par->cursor.sm_addr,
  1161. par->cursor_regs + SM501_OFF_HWC_ADDR);
  1162. smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
  1163. smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
  1164. smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
  1165. sm501fb_sync_regs(info);
  1166. return 0;
  1167. }
  1168. /* sm501fb_info_start
  1169. *
  1170. * fills the par structure claiming resources and remapping etc.
  1171. */
  1172. static int sm501fb_start(struct sm501fb_info *info,
  1173. struct platform_device *pdev)
  1174. {
  1175. struct resource *res;
  1176. struct device *dev = &pdev->dev;
  1177. int k;
  1178. int ret;
  1179. info->irq = ret = platform_get_irq(pdev, 0);
  1180. if (ret < 0) {
  1181. /* we currently do not use the IRQ */
  1182. dev_warn(dev, "no irq for device\n");
  1183. }
  1184. /* allocate, reserve and remap resources for display
  1185. * controller registers */
  1186. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  1187. if (res == NULL) {
  1188. dev_err(dev, "no resource definition for registers\n");
  1189. ret = -ENOENT;
  1190. goto err_release;
  1191. }
  1192. info->regs_res = request_mem_region(res->start,
  1193. resource_size(res),
  1194. pdev->name);
  1195. if (info->regs_res == NULL) {
  1196. dev_err(dev, "cannot claim registers\n");
  1197. ret = -ENXIO;
  1198. goto err_release;
  1199. }
  1200. info->regs = ioremap(res->start, resource_size(res));
  1201. if (info->regs == NULL) {
  1202. dev_err(dev, "cannot remap registers\n");
  1203. ret = -ENXIO;
  1204. goto err_regs_res;
  1205. }
  1206. /* allocate, reserve and remap resources for 2d
  1207. * controller registers */
  1208. res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  1209. if (res == NULL) {
  1210. dev_err(dev, "no resource definition for 2d registers\n");
  1211. ret = -ENOENT;
  1212. goto err_regs_map;
  1213. }
  1214. info->regs2d_res = request_mem_region(res->start,
  1215. resource_size(res),
  1216. pdev->name);
  1217. if (info->regs2d_res == NULL) {
  1218. dev_err(dev, "cannot claim registers\n");
  1219. ret = -ENXIO;
  1220. goto err_regs_map;
  1221. }
  1222. info->regs2d = ioremap(res->start, resource_size(res));
  1223. if (info->regs2d == NULL) {
  1224. dev_err(dev, "cannot remap registers\n");
  1225. ret = -ENXIO;
  1226. goto err_regs2d_res;
  1227. }
  1228. /* allocate, reserve resources for framebuffer */
  1229. res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
  1230. if (res == NULL) {
  1231. dev_err(dev, "no memory resource defined\n");
  1232. ret = -ENXIO;
  1233. goto err_regs2d_map;
  1234. }
  1235. info->fbmem_res = request_mem_region(res->start,
  1236. resource_size(res),
  1237. pdev->name);
  1238. if (info->fbmem_res == NULL) {
  1239. dev_err(dev, "cannot claim framebuffer\n");
  1240. ret = -ENXIO;
  1241. goto err_regs2d_map;
  1242. }
  1243. info->fbmem = ioremap(res->start, resource_size(res));
  1244. if (info->fbmem == NULL) {
  1245. dev_err(dev, "cannot remap framebuffer\n");
  1246. goto err_mem_res;
  1247. }
  1248. info->fbmem_len = resource_size(res);
  1249. /* clear framebuffer memory - avoids garbage data on unused fb */
  1250. memset(info->fbmem, 0, info->fbmem_len);
  1251. /* clear palette ram - undefined at power on */
  1252. for (k = 0; k < (256 * 3); k++)
  1253. smc501_writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
  1254. /* enable display controller */
  1255. sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
  1256. /* enable 2d controller */
  1257. sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1);
  1258. /* setup cursors */
  1259. sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
  1260. sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
  1261. return 0; /* everything is setup */
  1262. err_mem_res:
  1263. release_resource(info->fbmem_res);
  1264. kfree(info->fbmem_res);
  1265. err_regs2d_map:
  1266. iounmap(info->regs2d);
  1267. err_regs2d_res:
  1268. release_resource(info->regs2d_res);
  1269. kfree(info->regs2d_res);
  1270. err_regs_map:
  1271. iounmap(info->regs);
  1272. err_regs_res:
  1273. release_resource(info->regs_res);
  1274. kfree(info->regs_res);
  1275. err_release:
  1276. return ret;
  1277. }
  1278. static void sm501fb_stop(struct sm501fb_info *info)
  1279. {
  1280. /* disable display controller */
  1281. sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
  1282. iounmap(info->fbmem);
  1283. release_resource(info->fbmem_res);
  1284. kfree(info->fbmem_res);
  1285. iounmap(info->regs2d);
  1286. release_resource(info->regs2d_res);
  1287. kfree(info->regs2d_res);
  1288. iounmap(info->regs);
  1289. release_resource(info->regs_res);
  1290. kfree(info->regs_res);
  1291. }
  1292. static int sm501fb_init_fb(struct fb_info *fb,
  1293. enum sm501_controller head,
  1294. const char *fbname)
  1295. {
  1296. struct sm501_platdata_fbsub *pd;
  1297. struct sm501fb_par *par = fb->par;
  1298. struct sm501fb_info *info = par->info;
  1299. unsigned long ctrl;
  1300. unsigned int enable;
  1301. int ret;
  1302. switch (head) {
  1303. case HEAD_CRT:
  1304. pd = info->pdata->fb_crt;
  1305. ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
  1306. enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
  1307. /* ensure we set the correct source register */
  1308. if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
  1309. ctrl |= SM501_DC_CRT_CONTROL_SEL;
  1310. smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
  1311. }
  1312. break;
  1313. case HEAD_PANEL:
  1314. pd = info->pdata->fb_pnl;
  1315. ctrl = smc501_readl(info->regs + SM501_DC_PANEL_CONTROL);
  1316. enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
  1317. break;
  1318. default:
  1319. pd = NULL; /* stop compiler warnings */
  1320. ctrl = 0;
  1321. enable = 0;
  1322. BUG();
  1323. }
  1324. dev_info(info->dev, "fb %s %sabled at start\n",
  1325. fbname, enable ? "en" : "dis");
  1326. /* check to see if our routing allows this */
  1327. if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
  1328. ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
  1329. smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
  1330. enable = 0;
  1331. }
  1332. strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));
  1333. memcpy(&par->ops,
  1334. (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
  1335. sizeof(struct fb_ops));
  1336. /* update ops dependant on what we've been passed */
  1337. if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)
  1338. par->ops.fb_cursor = NULL;
  1339. fb->fbops = &par->ops;
  1340. fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST |
  1341. FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
  1342. FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
  1343. /* fixed data */
  1344. fb->fix.type = FB_TYPE_PACKED_PIXELS;
  1345. fb->fix.type_aux = 0;
  1346. fb->fix.xpanstep = 1;
  1347. fb->fix.ypanstep = 1;
  1348. fb->fix.ywrapstep = 0;
  1349. fb->fix.accel = FB_ACCEL_NONE;
  1350. /* screenmode */
  1351. fb->var.nonstd = 0;
  1352. fb->var.activate = FB_ACTIVATE_NOW;
  1353. fb->var.accel_flags = 0;
  1354. fb->var.vmode = FB_VMODE_NONINTERLACED;
  1355. fb->var.bits_per_pixel = 16;
  1356. if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
  1357. /* TODO read the mode from the current display */
  1358. } else {
  1359. if (pd->def_mode) {
  1360. dev_info(info->dev, "using supplied mode\n");
  1361. fb_videomode_to_var(&fb->var, pd->def_mode);
  1362. fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;
  1363. fb->var.xres_virtual = fb->var.xres;
  1364. fb->var.yres_virtual = fb->var.yres;
  1365. } else {
  1366. ret = fb_find_mode(&fb->var, fb,
  1367. NULL, NULL, 0, NULL, 8);
  1368. if (ret == 0 || ret == 4) {
  1369. dev_err(info->dev,
  1370. "failed to get initial mode\n");
  1371. return -EINVAL;
  1372. }
  1373. }
  1374. }
  1375. /* initialise and set the palette */
  1376. if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) {
  1377. dev_err(info->dev, "failed to allocate cmap memory\n");
  1378. return -ENOMEM;
  1379. }
  1380. fb_set_cmap(&fb->cmap, fb);
  1381. ret = (fb->fbops->fb_check_var)(&fb->var, fb);
  1382. if (ret)
  1383. dev_err(info->dev, "check_var() failed on initial setup?\n");
  1384. return 0;
  1385. }
  1386. /* default platform data if none is supplied (ie, PCI device) */
  1387. static struct sm501_platdata_fbsub sm501fb_pdata_crt = {
  1388. .flags = (SM501FB_FLAG_USE_INIT_MODE |
  1389. SM501FB_FLAG_USE_HWCURSOR |
  1390. SM501FB_FLAG_USE_HWACCEL |
  1391. SM501FB_FLAG_DISABLE_AT_EXIT),
  1392. };
  1393. static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {
  1394. .flags = (SM501FB_FLAG_USE_INIT_MODE |
  1395. SM501FB_FLAG_USE_HWCURSOR |
  1396. SM501FB_FLAG_USE_HWACCEL |
  1397. SM501FB_FLAG_DISABLE_AT_EXIT),
  1398. };
  1399. static struct sm501_platdata_fb sm501fb_def_pdata = {
  1400. .fb_route = SM501_FB_OWN,
  1401. .fb_crt = &sm501fb_pdata_crt,
  1402. .fb_pnl = &sm501fb_pdata_pnl,
  1403. };
  1404. static char driver_name_crt[] = "sm501fb-crt";
  1405. static char driver_name_pnl[] = "sm501fb-panel";
  1406. static int __devinit sm501fb_probe_one(struct sm501fb_info *info,
  1407. enum sm501_controller head)
  1408. {
  1409. unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel";
  1410. struct sm501_platdata_fbsub *pd;
  1411. struct sm501fb_par *par;
  1412. struct fb_info *fbi;
  1413. pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl;
  1414. /* Do not initialise if we've not been given any platform data */
  1415. if (pd == NULL) {
  1416. dev_info(info->dev, "no data for fb %s (disabled)\n", name);
  1417. return 0;
  1418. }
  1419. fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev);
  1420. if (fbi == NULL) {
  1421. dev_err(info->dev, "cannot allocate %s framebuffer\n", name);
  1422. return -ENOMEM;
  1423. }
  1424. par = fbi->par;
  1425. par->info = info;
  1426. par->head = head;
  1427. fbi->pseudo_palette = &par->pseudo_palette;
  1428. info->fb[head] = fbi;
  1429. return 0;
  1430. }
  1431. /* Free up anything allocated by sm501fb_init_fb */
  1432. static void sm501_free_init_fb(struct sm501fb_info *info,
  1433. enum sm501_controller head)
  1434. {
  1435. struct fb_info *fbi = info->fb[head];
  1436. fb_dealloc_cmap(&fbi->cmap);
  1437. }
  1438. static int __devinit sm501fb_start_one(struct sm501fb_info *info,
  1439. enum sm501_controller head,
  1440. const char *drvname)
  1441. {
  1442. struct fb_info *fbi = info->fb[head];
  1443. int ret;
  1444. if (!fbi)
  1445. return 0;
  1446. mutex_init(&info->fb[head]->mm_lock);
  1447. ret = sm501fb_init_fb(info->fb[head], head, drvname);
  1448. if (ret) {
  1449. dev_err(info->dev, "cannot initialise fb %s\n", drvname);
  1450. return ret;
  1451. }
  1452. ret = register_framebuffer(info->fb[head]);
  1453. if (ret) {
  1454. dev_err(info->dev, "failed to register fb %s\n", drvname);
  1455. sm501_free_init_fb(info, head);
  1456. return ret;
  1457. }
  1458. dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);
  1459. return 0;
  1460. }
  1461. static int __devinit sm501fb_probe(struct platform_device *pdev)
  1462. {
  1463. struct sm501fb_info *info;
  1464. struct device *dev = &pdev->dev;
  1465. int ret;
  1466. /* allocate our framebuffers */
  1467. info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
  1468. if (!info) {
  1469. dev_err(dev, "failed to allocate state\n");
  1470. return -ENOMEM;
  1471. }
  1472. info->dev = dev = &pdev->dev;
  1473. platform_set_drvdata(pdev, info);
  1474. if (dev->parent->platform_data) {
  1475. struct sm501_platdata *pd = dev->parent->platform_data;
  1476. info->pdata = pd->fb;
  1477. }
  1478. if (info->pdata == NULL) {
  1479. dev_info(dev, "using default configuration data\n");
  1480. info->pdata = &sm501fb_def_pdata;
  1481. }
  1482. /* probe for the presence of each panel */
  1483. ret = sm501fb_probe_one(info, HEAD_CRT);
  1484. if (ret < 0) {
  1485. dev_err(dev, "failed to probe CRT\n");
  1486. goto err_alloc;
  1487. }
  1488. ret = sm501fb_probe_one(info, HEAD_PANEL);
  1489. if (ret < 0) {
  1490. dev_err(dev, "failed to probe PANEL\n");
  1491. goto err_probed_crt;
  1492. }
  1493. if (info->fb[HEAD_PANEL] == NULL &&
  1494. info->fb[HEAD_CRT] == NULL) {
  1495. dev_err(dev, "no framebuffers found\n");
  1496. goto err_alloc;
  1497. }
  1498. /* get the resources for both of the framebuffers */
  1499. ret = sm501fb_start(info, pdev);
  1500. if (ret) {
  1501. dev_err(dev, "cannot initialise SM501\n");
  1502. goto err_probed_panel;
  1503. }
  1504. ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);
  1505. if (ret) {
  1506. dev_err(dev, "failed to start CRT\n");
  1507. goto err_started;
  1508. }
  1509. ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);
  1510. if (ret) {
  1511. dev_err(dev, "failed to start Panel\n");
  1512. goto err_started_crt;
  1513. }
  1514. /* create device files */
  1515. ret = device_create_file(dev, &dev_attr_crt_src);
  1516. if (ret)
  1517. goto err_started_panel;
  1518. ret = device_create_file(dev, &dev_attr_fbregs_pnl);
  1519. if (ret)
  1520. goto err_attached_crtsrc_file;
  1521. ret = device_create_file(dev, &dev_attr_fbregs_crt);
  1522. if (ret)
  1523. goto err_attached_pnlregs_file;
  1524. /* we registered, return ok */
  1525. return 0;
  1526. err_attached_pnlregs_file:
  1527. device_remove_file(dev, &dev_attr_fbregs_pnl);
  1528. err_attached_crtsrc_file:
  1529. device_remove_file(dev, &dev_attr_crt_src);
  1530. err_started_panel:
  1531. unregister_framebuffer(info->fb[HEAD_PANEL]);
  1532. sm501_free_init_fb(info, HEAD_PANEL);
  1533. err_started_crt:
  1534. unregister_framebuffer(info->fb[HEAD_CRT]);
  1535. sm501_free_init_fb(info, HEAD_CRT);
  1536. err_started:
  1537. sm501fb_stop(info);
  1538. err_probed_panel:
  1539. framebuffer_release(info->fb[HEAD_PANEL]);
  1540. err_probed_crt:
  1541. framebuffer_release(info->fb[HEAD_CRT]);
  1542. err_alloc:
  1543. kfree(info);
  1544. return ret;
  1545. }
  1546. /*
  1547. * Cleanup
  1548. */
  1549. static int sm501fb_remove(struct platform_device *pdev)
  1550. {
  1551. struct sm501fb_info *info = platform_get_drvdata(pdev);
  1552. struct fb_info *fbinfo_crt = info->fb[0];
  1553. struct fb_info *fbinfo_pnl = info->fb[1];
  1554. device_remove_file(&pdev->dev, &dev_attr_fbregs_crt);
  1555. device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);
  1556. device_remove_file(&pdev->dev, &dev_attr_crt_src);
  1557. sm501_free_init_fb(info, HEAD_CRT);
  1558. sm501_free_init_fb(info, HEAD_PANEL);
  1559. unregister_framebuffer(fbinfo_crt);
  1560. unregister_framebuffer(fbinfo_pnl);
  1561. sm501fb_stop(info);
  1562. kfree(info);
  1563. framebuffer_release(fbinfo_pnl);
  1564. framebuffer_release(fbinfo_crt);
  1565. return 0;
  1566. }
  1567. #ifdef CONFIG_PM
  1568. static int sm501fb_suspend_fb(struct sm501fb_info *info,
  1569. enum sm501_controller head)
  1570. {
  1571. struct fb_info *fbi = info->fb[head];
  1572. struct sm501fb_par *par = fbi->par;
  1573. if (par->screen.size == 0)
  1574. return 0;
  1575. /* blank the relevant interface to ensure unit power minimised */
  1576. (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
  1577. /* tell console/fb driver we are suspending */
  1578. console_lock();
  1579. fb_set_suspend(fbi, 1);
  1580. console_unlock();
  1581. /* backup copies in case chip is powered down over suspend */
  1582. par->store_fb = vmalloc(par->screen.size);
  1583. if (par->store_fb == NULL) {
  1584. dev_err(info->dev, "no memory to store screen\n");
  1585. return -ENOMEM;
  1586. }
  1587. par->store_cursor = vmalloc(par->cursor.size);
  1588. if (par->store_cursor == NULL) {
  1589. dev_err(info->dev, "no memory to store cursor\n");
  1590. goto err_nocursor;
  1591. }
  1592. dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb);
  1593. dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor);
  1594. memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
  1595. memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
  1596. return 0;
  1597. err_nocursor:
  1598. vfree(par->store_fb);
  1599. par->store_fb = NULL;
  1600. return -ENOMEM;
  1601. }
  1602. static void sm501fb_resume_fb(struct sm501fb_info *info,
  1603. enum sm501_controller head)
  1604. {
  1605. struct fb_info *fbi = info->fb[head];
  1606. struct sm501fb_par *par = fbi->par;
  1607. if (par->screen.size == 0)
  1608. return;
  1609. /* re-activate the configuration */
  1610. (par->ops.fb_set_par)(fbi);
  1611. /* restore the data */
  1612. dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb);
  1613. dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor);
  1614. if (par->store_fb)
  1615. memcpy_toio(par->screen.k_addr, par->store_fb,
  1616. par->screen.size);
  1617. if (par->store_cursor)
  1618. memcpy_toio(par->cursor.k_addr, par->store_cursor,
  1619. par->cursor.size);
  1620. console_lock();
  1621. fb_set_suspend(fbi, 0);
  1622. console_unlock();
  1623. vfree(par->store_fb);
  1624. vfree(par->store_cursor);
  1625. }
  1626. /* suspend and resume support */
  1627. static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
  1628. {
  1629. struct sm501fb_info *info = platform_get_drvdata(pdev);
  1630. /* store crt control to resume with */
  1631. info->pm_crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
  1632. sm501fb_suspend_fb(info, HEAD_CRT);
  1633. sm501fb_suspend_fb(info, HEAD_PANEL);
  1634. /* turn off the clocks, in case the device is not powered down */
  1635. sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
  1636. return 0;
  1637. }
  1638. #define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \
  1639. SM501_DC_CRT_CONTROL_SEL)
  1640. static int sm501fb_resume(struct platform_device *pdev)
  1641. {
  1642. struct sm501fb_info *info = platform_get_drvdata(pdev);
  1643. unsigned long crt_ctrl;
  1644. sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
  1645. /* restore the items we want to be saved for crt control */
  1646. crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
  1647. crt_ctrl &= ~SM501_CRT_CTRL_SAVE;
  1648. crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE;
  1649. smc501_writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
  1650. sm501fb_resume_fb(info, HEAD_CRT);
  1651. sm501fb_resume_fb(info, HEAD_PANEL);
  1652. return 0;
  1653. }
  1654. #else
  1655. #define sm501fb_suspend NULL
  1656. #define sm501fb_resume NULL
  1657. #endif
  1658. static struct platform_driver sm501fb_driver = {
  1659. .probe = sm501fb_probe,
  1660. .remove = sm501fb_remove,
  1661. .suspend = sm501fb_suspend,
  1662. .resume = sm501fb_resume,
  1663. .driver = {
  1664. .name = "sm501-fb",
  1665. .owner = THIS_MODULE,
  1666. },
  1667. };
  1668. static int __devinit sm501fb_init(void)
  1669. {
  1670. return platform_driver_register(&sm501fb_driver);
  1671. }
  1672. static void __exit sm501fb_cleanup(void)
  1673. {
  1674. platform_driver_unregister(&sm501fb_driver);
  1675. }
  1676. module_init(sm501fb_init);
  1677. module_exit(sm501fb_cleanup);
  1678. MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
  1679. MODULE_DESCRIPTION("SM501 Framebuffer driver");
  1680. MODULE_LICENSE("GPL v2");