smtcfb.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  1. /*
  2. * Silicon Motion SM7XX frame buffer device
  3. *
  4. * Copyright (C) 2006 Silicon Motion Technology Corp.
  5. * Authors: Ge Wang, gewang@siliconmotion.com
  6. * Boyod boyod.yang@siliconmotion.com.cn
  7. *
  8. * Copyright (C) 2009 Lemote, Inc.
  9. * Author: Wu Zhangjin, wuzhangjin@gmail.com
  10. *
  11. * Copyright (C) 2011 Igalia, S.L.
  12. * Author: Javier M. Mellid <jmunhoz@igalia.com>
  13. *
  14. * This file is subject to the terms and conditions of the GNU General Public
  15. * License. See the file COPYING in the main directory of this archive for
  16. * more details.
  17. *
  18. * Version 0.10.26192.21.01
  19. * - Add PowerPC/Big endian support
  20. * - Verified on 2.6.19.2
  21. * Boyod.yang <boyod.yang@siliconmotion.com.cn>
  22. *
  23. * Version 0.09.2621.00.01
  24. * - Only support Linux Kernel's version 2.6.21
  25. * Boyod.yang <boyod.yang@siliconmotion.com.cn>
  26. *
  27. * Version 0.09
  28. * - Only support Linux Kernel's version 2.6.12
  29. * Boyod.yang <boyod.yang@siliconmotion.com.cn>
  30. */
  31. #include <linux/io.h>
  32. #include <linux/fb.h>
  33. #include <linux/pci.h>
  34. #include <linux/init.h>
  35. #include <linux/slab.h>
  36. #include <linux/uaccess.h>
  37. #include <linux/console.h>
  38. #include <linux/screen_info.h>
  39. #ifdef CONFIG_PM
  40. #include <linux/pm.h>
  41. #endif
  42. #include "smtcfb.h"
  43. #ifdef DEBUG
  44. #define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
  45. #else
  46. #define smdbg(format, arg...)
  47. #endif
  48. struct screen_info smtc_screen_info;
  49. /*
  50. * Private structure
  51. */
  52. struct smtcfb_info {
  53. /*
  54. * The following is a pointer to be passed into the
  55. * functions below. The modules outside the main
  56. * voyager.c driver have no knowledge as to what
  57. * is within this structure.
  58. */
  59. struct fb_info fb;
  60. struct display_switch *dispsw;
  61. struct pci_dev *dev;
  62. signed int currcon;
  63. struct {
  64. u8 red, green, blue;
  65. } palette[NR_RGB];
  66. u_int palette_size;
  67. };
  68. struct par_info {
  69. /*
  70. * Hardware
  71. */
  72. u16 chipID;
  73. unsigned char __iomem *m_pMMIO;
  74. char __iomem *m_pLFB;
  75. char *m_pDPR;
  76. char *m_pVPR;
  77. char *m_pCPR;
  78. u_int width;
  79. u_int height;
  80. u_int hz;
  81. u_long BaseAddressInVRAM;
  82. u8 chipRevID;
  83. };
  84. struct vesa_mode_table {
  85. char mode_index[6];
  86. u16 lfb_width;
  87. u16 lfb_height;
  88. u16 lfb_depth;
  89. };
  90. static struct vesa_mode_table vesa_mode[] = {
  91. {"0x301", 640, 480, 8},
  92. {"0x303", 800, 600, 8},
  93. {"0x305", 1024, 768, 8},
  94. {"0x307", 1280, 1024, 8},
  95. {"0x311", 640, 480, 16},
  96. {"0x314", 800, 600, 16},
  97. {"0x317", 1024, 768, 16},
  98. {"0x31A", 1280, 1024, 16},
  99. {"0x312", 640, 480, 24},
  100. {"0x315", 800, 600, 24},
  101. {"0x318", 1024, 768, 24},
  102. {"0x31B", 1280, 1024, 24},
  103. };
  104. char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */
  105. char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */
  106. static u32 colreg[17];
  107. static struct par_info hw; /* hardware information */
  108. u16 smtc_ChipIDs[] = {
  109. 0x710,
  110. 0x712,
  111. 0x720
  112. };
  113. #define numSMTCchipIDs ARRAY_SIZE(smtc_ChipIDs)
  114. static struct fb_var_screeninfo smtcfb_var = {
  115. .xres = 1024,
  116. .yres = 600,
  117. .xres_virtual = 1024,
  118. .yres_virtual = 600,
  119. .bits_per_pixel = 16,
  120. .red = {16, 8, 0},
  121. .green = {8, 8, 0},
  122. .blue = {0, 8, 0},
  123. .activate = FB_ACTIVATE_NOW,
  124. .height = -1,
  125. .width = -1,
  126. .vmode = FB_VMODE_NONINTERLACED,
  127. };
  128. static struct fb_fix_screeninfo smtcfb_fix = {
  129. .id = "sm712fb",
  130. .type = FB_TYPE_PACKED_PIXELS,
  131. .visual = FB_VISUAL_TRUECOLOR,
  132. .line_length = 800 * 3,
  133. .accel = FB_ACCEL_SMI_LYNX,
  134. };
  135. static void sm712_set_timing(struct smtcfb_info *sfb,
  136. struct par_info *ppar_info)
  137. {
  138. int i = 0, j = 0;
  139. u32 m_nScreenStride;
  140. smdbg("\nppar_info->width = %d ppar_info->height = %d"
  141. "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
  142. ppar_info->width, ppar_info->height,
  143. sfb->fb.var.bits_per_pixel, ppar_info->hz);
  144. for (j = 0; j < numVGAModes; j++) {
  145. if (VGAMode[j].mmSizeX == ppar_info->width &&
  146. VGAMode[j].mmSizeY == ppar_info->height &&
  147. VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
  148. VGAMode[j].hz == ppar_info->hz) {
  149. smdbg("\nVGAMode[j].mmSizeX = %d VGAMode[j].mmSizeY ="
  150. "%d VGAMode[j].bpp = %d"
  151. "VGAMode[j].hz=%d\n",
  152. VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
  153. VGAMode[j].bpp, VGAMode[j].hz);
  154. smdbg("VGAMode index=%d\n", j);
  155. smtc_mmiowb(0x0, 0x3c6);
  156. smtc_seqw(0, 0x1);
  157. smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
  158. /* init SEQ register SR00 - SR04 */
  159. for (i = 0; i < SIZE_SR00_SR04; i++)
  160. smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
  161. /* init SEQ register SR10 - SR24 */
  162. for (i = 0; i < SIZE_SR10_SR24; i++)
  163. smtc_seqw(i + 0x10,
  164. VGAMode[j].Init_SR10_SR24[i]);
  165. /* init SEQ register SR30 - SR75 */
  166. for (i = 0; i < SIZE_SR30_SR75; i++)
  167. if (((i + 0x30) != 0x62) \
  168. && ((i + 0x30) != 0x6a) \
  169. && ((i + 0x30) != 0x6b))
  170. smtc_seqw(i + 0x30,
  171. VGAMode[j].Init_SR30_SR75[i]);
  172. /* init SEQ register SR80 - SR93 */
  173. for (i = 0; i < SIZE_SR80_SR93; i++)
  174. smtc_seqw(i + 0x80,
  175. VGAMode[j].Init_SR80_SR93[i]);
  176. /* init SEQ register SRA0 - SRAF */
  177. for (i = 0; i < SIZE_SRA0_SRAF; i++)
  178. smtc_seqw(i + 0xa0,
  179. VGAMode[j].Init_SRA0_SRAF[i]);
  180. /* init Graphic register GR00 - GR08 */
  181. for (i = 0; i < SIZE_GR00_GR08; i++)
  182. smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
  183. /* init Attribute register AR00 - AR14 */
  184. for (i = 0; i < SIZE_AR00_AR14; i++)
  185. smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
  186. /* init CRTC register CR00 - CR18 */
  187. for (i = 0; i < SIZE_CR00_CR18; i++)
  188. smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
  189. /* init CRTC register CR30 - CR4D */
  190. for (i = 0; i < SIZE_CR30_CR4D; i++)
  191. smtc_crtcw(i + 0x30,
  192. VGAMode[j].Init_CR30_CR4D[i]);
  193. /* init CRTC register CR90 - CRA7 */
  194. for (i = 0; i < SIZE_CR90_CRA7; i++)
  195. smtc_crtcw(i + 0x90,
  196. VGAMode[j].Init_CR90_CRA7[i]);
  197. }
  198. }
  199. smtc_mmiowb(0x67, 0x3c2);
  200. /* set VPR registers */
  201. writel(0x0, ppar_info->m_pVPR + 0x0C);
  202. writel(0x0, ppar_info->m_pVPR + 0x40);
  203. /* set data width */
  204. m_nScreenStride =
  205. (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
  206. switch (sfb->fb.var.bits_per_pixel) {
  207. case 8:
  208. writel(0x0, ppar_info->m_pVPR + 0x0);
  209. break;
  210. case 16:
  211. writel(0x00020000, ppar_info->m_pVPR + 0x0);
  212. break;
  213. case 24:
  214. writel(0x00040000, ppar_info->m_pVPR + 0x0);
  215. break;
  216. case 32:
  217. writel(0x00030000, ppar_info->m_pVPR + 0x0);
  218. break;
  219. }
  220. writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
  221. ppar_info->m_pVPR + 0x10);
  222. }
  223. static void sm712_setpalette(int regno, unsigned red, unsigned green,
  224. unsigned blue, struct fb_info *info)
  225. {
  226. struct par_info *cur_par = (struct par_info *)info->par;
  227. if (cur_par->BaseAddressInVRAM)
  228. /*
  229. * second display palette for dual head. Enable CRT RAM, 6-bit
  230. * RAM
  231. */
  232. smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20);
  233. else
  234. /* primary display palette. Enable LCD RAM only, 6-bit RAM */
  235. smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
  236. smtc_mmiowb(regno, dac_reg);
  237. smtc_mmiowb(red >> 10, dac_val);
  238. smtc_mmiowb(green >> 10, dac_val);
  239. smtc_mmiowb(blue >> 10, dac_val);
  240. }
  241. static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
  242. *ppar_info)
  243. {
  244. switch (ppar_info->chipID) {
  245. case 0x710:
  246. case 0x712:
  247. case 0x720:
  248. sm712_set_timing(sfb, ppar_info);
  249. break;
  250. }
  251. }
  252. /* chan_to_field
  253. *
  254. * convert a colour value into a field position
  255. *
  256. * from pxafb.c
  257. */
  258. static inline unsigned int chan_to_field(unsigned int chan,
  259. struct fb_bitfield *bf)
  260. {
  261. chan &= 0xffff;
  262. chan >>= 16 - bf->length;
  263. return chan << bf->offset;
  264. }
  265. static int cfb_blank(int blank_mode, struct fb_info *info)
  266. {
  267. /* clear DPMS setting */
  268. switch (blank_mode) {
  269. case FB_BLANK_UNBLANK:
  270. /* Screen On: HSync: On, VSync : On */
  271. smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
  272. smtc_seqw(0x6a, 0x16);
  273. smtc_seqw(0x6b, 0x02);
  274. smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
  275. smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
  276. smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
  277. smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
  278. smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
  279. break;
  280. case FB_BLANK_NORMAL:
  281. /* Screen Off: HSync: On, VSync : On Soft blank */
  282. smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
  283. smtc_seqw(0x6a, 0x16);
  284. smtc_seqw(0x6b, 0x02);
  285. smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
  286. smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
  287. smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
  288. smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
  289. break;
  290. case FB_BLANK_VSYNC_SUSPEND:
  291. /* Screen On: HSync: On, VSync : Off */
  292. smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
  293. smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
  294. smtc_seqw(0x6a, 0x0c);
  295. smtc_seqw(0x6b, 0x02);
  296. smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
  297. smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
  298. smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
  299. smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
  300. smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
  301. smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
  302. break;
  303. case FB_BLANK_HSYNC_SUSPEND:
  304. /* Screen On: HSync: Off, VSync : On */
  305. smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
  306. smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
  307. smtc_seqw(0x6a, 0x0c);
  308. smtc_seqw(0x6b, 0x02);
  309. smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
  310. smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
  311. smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
  312. smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
  313. smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
  314. smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
  315. break;
  316. case FB_BLANK_POWERDOWN:
  317. /* Screen On: HSync: Off, VSync : Off */
  318. smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
  319. smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
  320. smtc_seqw(0x6a, 0x0c);
  321. smtc_seqw(0x6b, 0x02);
  322. smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
  323. smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
  324. smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
  325. smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
  326. smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
  327. smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
  328. break;
  329. default:
  330. return -EINVAL;
  331. }
  332. return 0;
  333. }
  334. static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
  335. unsigned blue, unsigned trans, struct fb_info *info)
  336. {
  337. struct smtcfb_info *sfb = (struct smtcfb_info *)info;
  338. u32 val;
  339. if (regno > 255)
  340. return 1;
  341. switch (sfb->fb.fix.visual) {
  342. case FB_VISUAL_DIRECTCOLOR:
  343. case FB_VISUAL_TRUECOLOR:
  344. /*
  345. * 16/32 bit true-colour, use pseuo-palette for 16 base color
  346. */
  347. if (regno < 16) {
  348. if (sfb->fb.var.bits_per_pixel == 16) {
  349. u32 *pal = sfb->fb.pseudo_palette;
  350. val = chan_to_field(red, &sfb->fb.var.red);
  351. val |= chan_to_field(green, \
  352. &sfb->fb.var.green);
  353. val |= chan_to_field(blue, &sfb->fb.var.blue);
  354. #ifdef __BIG_ENDIAN
  355. pal[regno] =
  356. ((red & 0xf800) >> 8) |
  357. ((green & 0xe000) >> 13) |
  358. ((green & 0x1c00) << 3) |
  359. ((blue & 0xf800) >> 3);
  360. #else
  361. pal[regno] = val;
  362. #endif
  363. } else {
  364. u32 *pal = sfb->fb.pseudo_palette;
  365. val = chan_to_field(red, &sfb->fb.var.red);
  366. val |= chan_to_field(green, \
  367. &sfb->fb.var.green);
  368. val |= chan_to_field(blue, &sfb->fb.var.blue);
  369. #ifdef __BIG_ENDIAN
  370. val =
  371. (val & 0xff00ff00 >> 8) |
  372. (val & 0x00ff00ff << 8);
  373. #endif
  374. pal[regno] = val;
  375. }
  376. }
  377. break;
  378. case FB_VISUAL_PSEUDOCOLOR:
  379. /* color depth 8 bit */
  380. sm712_setpalette(regno, red, green, blue, info);
  381. break;
  382. default:
  383. return 1; /* unknown type */
  384. }
  385. return 0;
  386. }
  387. #ifdef __BIG_ENDIAN
  388. static ssize_t smtcfb_read(struct fb_info *info, char __user * buf, size_t
  389. count, loff_t *ppos)
  390. {
  391. unsigned long p = *ppos;
  392. u32 *buffer, *dst;
  393. u32 __iomem *src;
  394. int c, i, cnt = 0, err = 0;
  395. unsigned long total_size;
  396. if (!info || !info->screen_base)
  397. return -ENODEV;
  398. if (info->state != FBINFO_STATE_RUNNING)
  399. return -EPERM;
  400. total_size = info->screen_size;
  401. if (total_size == 0)
  402. total_size = info->fix.smem_len;
  403. if (p >= total_size)
  404. return 0;
  405. if (count >= total_size)
  406. count = total_size;
  407. if (count + p > total_size)
  408. count = total_size - p;
  409. buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
  410. if (!buffer)
  411. return -ENOMEM;
  412. src = (u32 __iomem *) (info->screen_base + p);
  413. if (info->fbops->fb_sync)
  414. info->fbops->fb_sync(info);
  415. while (count) {
  416. c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  417. dst = buffer;
  418. for (i = c >> 2; i--;) {
  419. *dst = fb_readl(src++);
  420. *dst =
  421. (*dst & 0xff00ff00 >> 8) |
  422. (*dst & 0x00ff00ff << 8);
  423. dst++;
  424. }
  425. if (c & 3) {
  426. u8 *dst8 = (u8 *) dst;
  427. u8 __iomem *src8 = (u8 __iomem *) src;
  428. for (i = c & 3; i--;) {
  429. if (i & 1) {
  430. *dst8++ = fb_readb(++src8);
  431. } else {
  432. *dst8++ = fb_readb(--src8);
  433. src8 += 2;
  434. }
  435. }
  436. src = (u32 __iomem *) src8;
  437. }
  438. if (copy_to_user(buf, buffer, c)) {
  439. err = -EFAULT;
  440. break;
  441. }
  442. *ppos += c;
  443. buf += c;
  444. cnt += c;
  445. count -= c;
  446. }
  447. kfree(buffer);
  448. return (err) ? err : cnt;
  449. }
  450. static ssize_t
  451. smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
  452. loff_t *ppos)
  453. {
  454. unsigned long p = *ppos;
  455. u32 *buffer, *src;
  456. u32 __iomem *dst;
  457. int c, i, cnt = 0, err = 0;
  458. unsigned long total_size;
  459. if (!info || !info->screen_base)
  460. return -ENODEV;
  461. if (info->state != FBINFO_STATE_RUNNING)
  462. return -EPERM;
  463. total_size = info->screen_size;
  464. if (total_size == 0)
  465. total_size = info->fix.smem_len;
  466. if (p > total_size)
  467. return -EFBIG;
  468. if (count > total_size) {
  469. err = -EFBIG;
  470. count = total_size;
  471. }
  472. if (count + p > total_size) {
  473. if (!err)
  474. err = -ENOSPC;
  475. count = total_size - p;
  476. }
  477. buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
  478. if (!buffer)
  479. return -ENOMEM;
  480. dst = (u32 __iomem *) (info->screen_base + p);
  481. if (info->fbops->fb_sync)
  482. info->fbops->fb_sync(info);
  483. while (count) {
  484. c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  485. src = buffer;
  486. if (copy_from_user(src, buf, c)) {
  487. err = -EFAULT;
  488. break;
  489. }
  490. for (i = c >> 2; i--;) {
  491. fb_writel((*src & 0xff00ff00 >> 8) |
  492. (*src & 0x00ff00ff << 8), dst++);
  493. src++;
  494. }
  495. if (c & 3) {
  496. u8 *src8 = (u8 *) src;
  497. u8 __iomem *dst8 = (u8 __iomem *) dst;
  498. for (i = c & 3; i--;) {
  499. if (i & 1) {
  500. fb_writeb(*src8++, ++dst8);
  501. } else {
  502. fb_writeb(*src8++, --dst8);
  503. dst8 += 2;
  504. }
  505. }
  506. dst = (u32 __iomem *) dst8;
  507. }
  508. *ppos += c;
  509. buf += c;
  510. cnt += c;
  511. count -= c;
  512. }
  513. kfree(buffer);
  514. return (cnt) ? cnt : err;
  515. }
  516. #endif /* ! __BIG_ENDIAN */
  517. void smtcfb_setmode(struct smtcfb_info *sfb)
  518. {
  519. switch (sfb->fb.var.bits_per_pixel) {
  520. case 32:
  521. sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  522. sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
  523. sfb->fb.var.red.length = 8;
  524. sfb->fb.var.green.length = 8;
  525. sfb->fb.var.blue.length = 8;
  526. sfb->fb.var.red.offset = 16;
  527. sfb->fb.var.green.offset = 8;
  528. sfb->fb.var.blue.offset = 0;
  529. break;
  530. case 8:
  531. sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
  532. sfb->fb.fix.line_length = sfb->fb.var.xres;
  533. sfb->fb.var.red.offset = 5;
  534. sfb->fb.var.red.length = 3;
  535. sfb->fb.var.green.offset = 2;
  536. sfb->fb.var.green.length = 3;
  537. sfb->fb.var.blue.offset = 0;
  538. sfb->fb.var.blue.length = 2;
  539. break;
  540. case 24:
  541. sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  542. sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
  543. sfb->fb.var.red.length = 8;
  544. sfb->fb.var.green.length = 8;
  545. sfb->fb.var.blue.length = 8;
  546. sfb->fb.var.red.offset = 16;
  547. sfb->fb.var.green.offset = 8;
  548. sfb->fb.var.blue.offset = 0;
  549. break;
  550. case 16:
  551. default:
  552. sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  553. sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
  554. sfb->fb.var.red.length = 5;
  555. sfb->fb.var.green.length = 6;
  556. sfb->fb.var.blue.length = 5;
  557. sfb->fb.var.red.offset = 11;
  558. sfb->fb.var.green.offset = 5;
  559. sfb->fb.var.blue.offset = 0;
  560. break;
  561. }
  562. hw.width = sfb->fb.var.xres;
  563. hw.height = sfb->fb.var.yres;
  564. hw.hz = 60;
  565. smtc_set_timing(sfb, &hw);
  566. }
  567. static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  568. {
  569. /* sanity checks */
  570. if (var->xres_virtual < var->xres)
  571. var->xres_virtual = var->xres;
  572. if (var->yres_virtual < var->yres)
  573. var->yres_virtual = var->yres;
  574. /* set valid default bpp */
  575. if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) &&
  576. (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
  577. var->bits_per_pixel = 16;
  578. return 0;
  579. }
  580. static int smtc_set_par(struct fb_info *info)
  581. {
  582. struct smtcfb_info *sfb = (struct smtcfb_info *)info;
  583. smtcfb_setmode(sfb);
  584. return 0;
  585. }
  586. static struct fb_ops smtcfb_ops = {
  587. .owner = THIS_MODULE,
  588. .fb_check_var = smtc_check_var,
  589. .fb_set_par = smtc_set_par,
  590. .fb_setcolreg = smtc_setcolreg,
  591. .fb_blank = cfb_blank,
  592. .fb_fillrect = cfb_fillrect,
  593. .fb_imageblit = cfb_imageblit,
  594. .fb_copyarea = cfb_copyarea,
  595. #ifdef __BIG_ENDIAN
  596. .fb_read = smtcfb_read,
  597. .fb_write = smtcfb_write,
  598. #endif
  599. };
  600. /*
  601. * Alloc struct smtcfb_info and assign the default value
  602. */
  603. static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
  604. char *name)
  605. {
  606. struct smtcfb_info *sfb;
  607. sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
  608. if (!sfb)
  609. return NULL;
  610. sfb->currcon = -1;
  611. sfb->dev = dev;
  612. /*** Init sfb->fb with default value ***/
  613. sfb->fb.flags = FBINFO_FLAG_DEFAULT;
  614. sfb->fb.fbops = &smtcfb_ops;
  615. sfb->fb.var = smtcfb_var;
  616. sfb->fb.fix = smtcfb_fix;
  617. strcpy(sfb->fb.fix.id, name);
  618. sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
  619. sfb->fb.fix.type_aux = 0;
  620. sfb->fb.fix.xpanstep = 0;
  621. sfb->fb.fix.ypanstep = 0;
  622. sfb->fb.fix.ywrapstep = 0;
  623. sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX;
  624. sfb->fb.var.nonstd = 0;
  625. sfb->fb.var.activate = FB_ACTIVATE_NOW;
  626. sfb->fb.var.height = -1;
  627. sfb->fb.var.width = -1;
  628. /* text mode acceleration */
  629. sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
  630. sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
  631. sfb->fb.par = &hw;
  632. sfb->fb.pseudo_palette = colreg;
  633. return sfb;
  634. }
  635. /*
  636. * Unmap in the memory mapped IO registers
  637. */
  638. static void smtc_unmap_mmio(struct smtcfb_info *sfb)
  639. {
  640. if (sfb && smtc_RegBaseAddress)
  641. smtc_RegBaseAddress = NULL;
  642. }
  643. /*
  644. * Map in the screen memory
  645. */
  646. static int smtc_map_smem(struct smtcfb_info *sfb,
  647. struct pci_dev *dev, u_long smem_len)
  648. {
  649. if (sfb->fb.var.bits_per_pixel == 32) {
  650. #ifdef __BIG_ENDIAN
  651. sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
  652. + 0x800000;
  653. #else
  654. sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
  655. #endif
  656. } else {
  657. sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
  658. }
  659. sfb->fb.fix.smem_len = smem_len;
  660. sfb->fb.screen_base = smtc_VRAMBaseAddress;
  661. if (!sfb->fb.screen_base) {
  662. printk(KERN_ERR "%s: unable to map screen memory\n",
  663. sfb->fb.fix.id);
  664. return -ENOMEM;
  665. }
  666. return 0;
  667. }
  668. /*
  669. * Unmap in the screen memory
  670. *
  671. */
  672. static void smtc_unmap_smem(struct smtcfb_info *sfb)
  673. {
  674. if (sfb && sfb->fb.screen_base) {
  675. iounmap(sfb->fb.screen_base);
  676. sfb->fb.screen_base = NULL;
  677. }
  678. }
  679. /*
  680. * We need to wake up the LynxEM+, and make sure its in linear memory mode.
  681. */
  682. static inline void sm7xx_init_hw(void)
  683. {
  684. outb_p(0x18, 0x3c4);
  685. outb_p(0x11, 0x3c5);
  686. }
  687. static void smtc_free_fb_info(struct smtcfb_info *sfb)
  688. {
  689. if (sfb) {
  690. fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
  691. kfree(sfb);
  692. }
  693. }
  694. /*
  695. * sm712vga_setup - process command line options, get vga parameter
  696. * @options: string of options
  697. * Returns zero.
  698. *
  699. */
  700. static int __init sm712vga_setup(char *options)
  701. {
  702. int index;
  703. if (!options || !*options) {
  704. smdbg("\n No vga parameter\n");
  705. return -EINVAL;
  706. }
  707. smtc_screen_info.lfb_width = 0;
  708. smtc_screen_info.lfb_height = 0;
  709. smtc_screen_info.lfb_depth = 0;
  710. smdbg("\nsm712vga_setup = %s\n", options);
  711. for (index = 0;
  712. index < ARRAY_SIZE(vesa_mode);
  713. index++) {
  714. if (strstr(options, vesa_mode[index].mode_index)) {
  715. smtc_screen_info.lfb_width = vesa_mode[index].lfb_width;
  716. smtc_screen_info.lfb_height =
  717. vesa_mode[index].lfb_height;
  718. smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth;
  719. return 0;
  720. }
  721. }
  722. return -1;
  723. }
  724. __setup("vga=", sm712vga_setup);
  725. /* Jason (08/13/2009)
  726. * Original init function changed to probe method to be used by pci_drv
  727. * process used to detect chips replaced with kernel process in pci_drv
  728. */
  729. static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
  730. const struct pci_device_id *ent)
  731. {
  732. struct smtcfb_info *sfb;
  733. u_long smem_size = 0x00800000; /* default 8MB */
  734. char name[16];
  735. int err;
  736. unsigned long pFramebufferPhysical;
  737. printk(KERN_INFO
  738. "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
  739. err = pci_enable_device(pdev); /* enable SMTC chip */
  740. if (err)
  741. return err;
  742. hw.chipID = ent->device;
  743. sprintf(name, "sm%Xfb", hw.chipID);
  744. sfb = smtc_alloc_fb_info(pdev, name);
  745. if (!sfb)
  746. goto failed_free;
  747. /* Jason (08/13/2009)
  748. * Store fb_info to be further used when suspending and resuming
  749. */
  750. pci_set_drvdata(pdev, sfb);
  751. sm7xx_init_hw();
  752. /*get mode parameter from smtc_screen_info */
  753. if (smtc_screen_info.lfb_width != 0) {
  754. sfb->fb.var.xres = smtc_screen_info.lfb_width;
  755. sfb->fb.var.yres = smtc_screen_info.lfb_height;
  756. sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth;
  757. } else {
  758. /* default resolution 1024x600 16bit mode */
  759. sfb->fb.var.xres = SCREEN_X_RES;
  760. sfb->fb.var.yres = SCREEN_Y_RES;
  761. sfb->fb.var.bits_per_pixel = SCREEN_BPP;
  762. }
  763. #ifdef __BIG_ENDIAN
  764. if (sfb->fb.var.bits_per_pixel == 24)
  765. sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32);
  766. #endif
  767. /* Map address and memory detection */
  768. pFramebufferPhysical = pci_resource_start(pdev, 0);
  769. pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
  770. switch (hw.chipID) {
  771. case 0x710:
  772. case 0x712:
  773. sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
  774. sfb->fb.fix.mmio_len = 0x00400000;
  775. smem_size = SM712_VIDEOMEMORYSIZE;
  776. #ifdef __BIG_ENDIAN
  777. hw.m_pLFB = (smtc_VRAMBaseAddress =
  778. ioremap(pFramebufferPhysical, 0x00c00000));
  779. #else
  780. hw.m_pLFB = (smtc_VRAMBaseAddress =
  781. ioremap(pFramebufferPhysical, 0x00800000));
  782. #endif
  783. hw.m_pMMIO = (smtc_RegBaseAddress =
  784. smtc_VRAMBaseAddress + 0x00700000);
  785. hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
  786. hw.m_pVPR = hw.m_pLFB + 0x0040c000;
  787. #ifdef __BIG_ENDIAN
  788. if (sfb->fb.var.bits_per_pixel == 32) {
  789. smtc_VRAMBaseAddress += 0x800000;
  790. hw.m_pLFB += 0x800000;
  791. printk(KERN_INFO
  792. "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
  793. smtc_VRAMBaseAddress, hw.m_pLFB);
  794. }
  795. #endif
  796. if (!smtc_RegBaseAddress) {
  797. printk(KERN_ERR
  798. "%s: unable to map memory mapped IO\n",
  799. sfb->fb.fix.id);
  800. err = -ENOMEM;
  801. goto failed_fb;
  802. }
  803. /* set MCLK = 14.31818 * (0x16 / 0x2) */
  804. smtc_seqw(0x6a, 0x16);
  805. smtc_seqw(0x6b, 0x02);
  806. smtc_seqw(0x62, 0x3e);
  807. /* enable PCI burst */
  808. smtc_seqw(0x17, 0x20);
  809. /* enable word swap */
  810. #ifdef __BIG_ENDIAN
  811. if (sfb->fb.var.bits_per_pixel == 32)
  812. smtc_seqw(0x17, 0x30);
  813. #endif
  814. break;
  815. case 0x720:
  816. sfb->fb.fix.mmio_start = pFramebufferPhysical;
  817. sfb->fb.fix.mmio_len = 0x00200000;
  818. smem_size = SM722_VIDEOMEMORYSIZE;
  819. hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
  820. hw.m_pLFB = (smtc_VRAMBaseAddress =
  821. hw.m_pDPR + 0x00200000);
  822. hw.m_pMMIO = (smtc_RegBaseAddress =
  823. hw.m_pDPR + 0x000c0000);
  824. hw.m_pVPR = hw.m_pDPR + 0x800;
  825. smtc_seqw(0x62, 0xff);
  826. smtc_seqw(0x6a, 0x0d);
  827. smtc_seqw(0x6b, 0x02);
  828. break;
  829. default:
  830. printk(KERN_ERR
  831. "No valid Silicon Motion display chip was detected!\n");
  832. goto failed_fb;
  833. }
  834. /* can support 32 bpp */
  835. if (15 == sfb->fb.var.bits_per_pixel)
  836. sfb->fb.var.bits_per_pixel = 16;
  837. sfb->fb.var.xres_virtual = sfb->fb.var.xres;
  838. sfb->fb.var.yres_virtual = sfb->fb.var.yres;
  839. err = smtc_map_smem(sfb, pdev, smem_size);
  840. if (err)
  841. goto failed;
  842. smtcfb_setmode(sfb);
  843. /* Primary display starting from 0 position */
  844. hw.BaseAddressInVRAM = 0;
  845. sfb->fb.par = &hw;
  846. err = register_framebuffer(&sfb->fb);
  847. if (err < 0)
  848. goto failed;
  849. printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
  850. "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
  851. sfb->fb.var.xres, sfb->fb.var.yres,
  852. sfb->fb.var.bits_per_pixel);
  853. return 0;
  854. failed:
  855. printk(KERN_ERR "Silicon Motion, Inc. primary display init fail\n");
  856. smtc_unmap_smem(sfb);
  857. smtc_unmap_mmio(sfb);
  858. failed_fb:
  859. smtc_free_fb_info(sfb);
  860. failed_free:
  861. pci_disable_device(pdev);
  862. return err;
  863. }
  864. /* Jason (08/11/2009) PCI_DRV wrapper essential structs */
  865. static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
  866. {0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  867. {0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  868. {0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  869. {0,}
  870. };
  871. /* Jason (08/14/2009)
  872. * do some clean up when the driver module is removed
  873. */
  874. static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
  875. {
  876. struct smtcfb_info *sfb;
  877. sfb = pci_get_drvdata(pdev);
  878. pci_set_drvdata(pdev, NULL);
  879. smtc_unmap_smem(sfb);
  880. smtc_unmap_mmio(sfb);
  881. unregister_framebuffer(&sfb->fb);
  882. smtc_free_fb_info(sfb);
  883. }
  884. #ifdef CONFIG_PM
  885. static int smtcfb_pci_suspend(struct device *device)
  886. {
  887. struct pci_dev *pdev = to_pci_dev(device);
  888. struct smtcfb_info *sfb;
  889. sfb = pci_get_drvdata(pdev);
  890. /* set the hw in sleep mode use externel clock and self memory refresh
  891. * so that we can turn off internal PLLs later on
  892. */
  893. smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
  894. smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
  895. console_lock();
  896. fb_set_suspend(&sfb->fb, 1);
  897. console_unlock();
  898. /* additionally turn off all function blocks including internal PLLs */
  899. smtc_seqw(0x21, 0xff);
  900. return 0;
  901. }
  902. static int smtcfb_pci_resume(struct device *device)
  903. {
  904. struct pci_dev *pdev = to_pci_dev(device);
  905. struct smtcfb_info *sfb;
  906. sfb = pci_get_drvdata(pdev);
  907. /* reinit hardware */
  908. sm7xx_init_hw();
  909. switch (hw.chipID) {
  910. case 0x710:
  911. case 0x712:
  912. /* set MCLK = 14.31818 * (0x16 / 0x2) */
  913. smtc_seqw(0x6a, 0x16);
  914. smtc_seqw(0x6b, 0x02);
  915. smtc_seqw(0x62, 0x3e);
  916. /* enable PCI burst */
  917. smtc_seqw(0x17, 0x20);
  918. #ifdef __BIG_ENDIAN
  919. if (sfb->fb.var.bits_per_pixel == 32)
  920. smtc_seqw(0x17, 0x30);
  921. #endif
  922. break;
  923. case 0x720:
  924. smtc_seqw(0x62, 0xff);
  925. smtc_seqw(0x6a, 0x0d);
  926. smtc_seqw(0x6b, 0x02);
  927. break;
  928. }
  929. smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
  930. smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
  931. smtcfb_setmode(sfb);
  932. console_lock();
  933. fb_set_suspend(&sfb->fb, 0);
  934. console_unlock();
  935. return 0;
  936. }
  937. static const struct dev_pm_ops sm7xx_pm_ops = {
  938. .suspend = smtcfb_pci_suspend,
  939. .resume = smtcfb_pci_resume,
  940. .freeze = smtcfb_pci_suspend,
  941. .thaw = smtcfb_pci_resume,
  942. .poweroff = smtcfb_pci_suspend,
  943. .restore = smtcfb_pci_resume,
  944. };
  945. #define SM7XX_PM_OPS (&sm7xx_pm_ops)
  946. #else /* !CONFIG_PM */
  947. #define SM7XX_PM_OPS NULL
  948. #endif /* !CONFIG_PM */
  949. static struct pci_driver smtcfb_driver = {
  950. .name = "smtcfb",
  951. .id_table = smtcfb_pci_table,
  952. .probe = smtcfb_pci_probe,
  953. .remove = __devexit_p(smtcfb_pci_remove),
  954. .driver.pm = SM7XX_PM_OPS,
  955. };
  956. static int __init smtcfb_init(void)
  957. {
  958. return pci_register_driver(&smtcfb_driver);
  959. }
  960. static void __exit smtcfb_exit(void)
  961. {
  962. pci_unregister_driver(&smtcfb_driver);
  963. }
  964. module_init(smtcfb_init);
  965. module_exit(smtcfb_exit);
  966. MODULE_AUTHOR("Siliconmotion ");
  967. MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
  968. MODULE_LICENSE("GPL");