smiLynxEM.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. /*
  2. * (C) Copyright 1997-2002 ELTEC Elektronik AG
  3. * Frank Gottschling <fgottschling@eltec.de>
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. /*
  24. * smiLynxEM.c
  25. *
  26. * Silicon Motion graphic interface for sm810/sm710/sm712 accelerator
  27. *
  28. * modification history
  29. * --------------------
  30. * 04-18-2002 Rewritten for U-Boot <fgottschling@eltec.de>.
  31. *
  32. * 18-03-2004 - Unify videomodes handling with the ct69000
  33. * - The video output can be set via the variable "videoout"
  34. * in the environment.
  35. * videoout=1 output on LCD
  36. * videoout=2 output on CRT (default value)
  37. * <p.aubert@staubli.com>
  38. */
  39. #include <common.h>
  40. #if defined(CONFIG_VIDEO_SMI_LYNXEM)
  41. #include <pci.h>
  42. #include <video_fb.h>
  43. #include "videomodes.h"
  44. /*
  45. * Export Graphic Device
  46. */
  47. GraphicDevice smi;
  48. /*
  49. * SMI 710/712 have 4MB internal RAM; SMI 810 2MB internal + 2MB external
  50. */
  51. #define VIDEO_MEM_SIZE 0x400000
  52. /*
  53. * ISA mapped regs
  54. */
  55. #define SMI_INDX_C4 (pGD->isaBase + 0x03c4) /* index reg */
  56. #define SMI_DATA_C5 (pGD->isaBase + 0x03c5) /* data reg */
  57. #define SMI_INDX_D4 (pGD->isaBase + 0x03d4) /* index reg */
  58. #define SMI_DATA_D5 (pGD->isaBase + 0x03d5) /* data reg */
  59. #define SMI_ISR1 (pGD->isaBase + 0x03ca)
  60. #define SMI_INDX_CE (pGD->isaBase + 0x03ce) /* index reg */
  61. #define SMI_DATA_CF (pGD->isaBase + 0x03cf) /* data reg */
  62. #define SMI_LOCK_REG (pGD->isaBase + 0x03c3) /* unlock/lock ext crt reg */
  63. #define SMI_MISC_REG (pGD->isaBase + 0x03c2) /* misc reg */
  64. #define SMI_LUT_MASK (pGD->isaBase + 0x03c6) /* lut mask reg */
  65. #define SMI_LUT_START (pGD->isaBase + 0x03c8) /* lut start index */
  66. #define SMI_LUT_RGB (pGD->isaBase + 0x03c9) /* lut colors auto incr.*/
  67. #define SMI_INDX_ATTR (pGD->isaBase + 0x03c0) /* attributes index reg */
  68. /*
  69. * Video processor control
  70. */
  71. typedef struct {
  72. unsigned int control;
  73. unsigned int colorKey;
  74. unsigned int colorKeyMask;
  75. unsigned int start;
  76. unsigned short offset;
  77. unsigned short width;
  78. unsigned int fifoPrio;
  79. unsigned int fifoERL;
  80. unsigned int YUVtoRGB;
  81. } SmiVideoProc;
  82. /*
  83. * Video window control
  84. */
  85. typedef struct {
  86. unsigned short top;
  87. unsigned short left;
  88. unsigned short bottom;
  89. unsigned short right;
  90. unsigned int srcStart;
  91. unsigned short width;
  92. unsigned short offset;
  93. unsigned char hStretch;
  94. unsigned char vStretch;
  95. } SmiVideoWin;
  96. /*
  97. * Capture port control
  98. */
  99. typedef struct {
  100. unsigned int control;
  101. unsigned short topClip;
  102. unsigned short leftClip;
  103. unsigned short srcHeight;
  104. unsigned short srcWidth;
  105. unsigned int srcBufStart1;
  106. unsigned int srcBufStart2;
  107. unsigned short srcOffset;
  108. unsigned short fifoControl;
  109. } SmiCapturePort;
  110. /*
  111. * Register values for common video modes
  112. */
  113. static char SMI_SCR[] = {
  114. /* all modes */
  115. 0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90,
  116. 0x17, 0x20, 0x18, 0xb1, 0x19, 0x00,
  117. };
  118. static char SMI_EXT_CRT[] = {
  119. 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00,
  120. 0x36, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
  121. };
  122. static char SMI_ATTR [] = {
  123. 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05,
  124. 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b,
  125. 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x41, 0x11, 0x00,
  126. 0x12, 0x0f, 0x13, 0x00, 0x14, 0x00,
  127. };
  128. static char SMI_GCR[18] = {
  129. 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x40,
  130. 0x06, 0x05, 0x07, 0x0f, 0x08, 0xff,
  131. };
  132. static char SMI_SEQR[] = {
  133. 0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03,
  134. };
  135. static char SMI_PCR [] = {
  136. 0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00,
  137. };
  138. static char SMI_MCR[] = {
  139. 0x60, 0x01, 0x61, 0x00,
  140. #ifdef CONFIG_HMI1001
  141. 0x62, 0x74, /* Memory type is not configured by pins on HMI1001 */
  142. #endif
  143. };
  144. static char SMI_HCR[] = {
  145. 0x80, 0xff, 0x81, 0x07, 0x82, 0x00, 0x83, 0xff, 0x84, 0xff, 0x88, 0x00,
  146. 0x89, 0x02, 0x8a, 0x80, 0x8b, 0x01, 0x8c, 0xff, 0x8d, 0x00,
  147. };
  148. /*******************************************************************************
  149. *
  150. * Write SMI ISA register
  151. */
  152. static void smiWrite (unsigned short index, char reg, char val)
  153. {
  154. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  155. out8 ((pGD->isaBase + index), reg);
  156. out8 ((pGD->isaBase + index + 1), val);
  157. }
  158. /*******************************************************************************
  159. *
  160. * Write a table of SMI ISA register
  161. */
  162. static void smiLoadRegs (
  163. unsigned int iReg,
  164. unsigned int dReg,
  165. char *regTab,
  166. unsigned int tabSize
  167. )
  168. {
  169. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  170. register int i;
  171. for (i=0; i<tabSize; i+=2) {
  172. if (iReg == SMI_INDX_ATTR) {
  173. /* Reset the Flip Flop */
  174. in8 (SMI_ISR1);
  175. out8 (iReg, regTab[i]);
  176. out8 (iReg, regTab[i+1]);
  177. } else {
  178. out8 (iReg, regTab[i]);
  179. out8 (dReg, regTab[i+1]);
  180. }
  181. }
  182. }
  183. /*******************************************************************************
  184. *
  185. * Init capture port registers
  186. */
  187. static void smiInitCapturePort (void)
  188. {
  189. SmiCapturePort smiCP = { 0x01400600, 0x30, 0x40, 480, 640, 0, 0, 2560, 6 };
  190. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  191. register SmiCapturePort *pCP = (SmiCapturePort *)&smiCP;
  192. out32r ((pGD->cprBase + 0x0004), ((pCP->topClip<<16) | pCP->leftClip));
  193. out32r ((pGD->cprBase + 0x0008), ((pCP->srcHeight<<16) | pCP->srcWidth));
  194. out32r ((pGD->cprBase + 0x000c), pCP->srcBufStart1/8);
  195. out32r ((pGD->cprBase + 0x0010), pCP->srcBufStart2/8);
  196. out32r ((pGD->cprBase + 0x0014), pCP->srcOffset/8);
  197. out32r ((pGD->cprBase + 0x0018), pCP->fifoControl);
  198. out32r ((pGD->cprBase + 0x0000), pCP->control);
  199. }
  200. /*******************************************************************************
  201. *
  202. * Init video processor registers
  203. */
  204. static void smiInitVideoProcessor (void)
  205. {
  206. SmiVideoProc smiVP = { 0x100000, 0, 0, 0, 0, 1600, 0x1200543, 4, 0xededed };
  207. SmiVideoWin smiVW = { 0, 0, 599, 799, 0, 1600, 0, 0, 0 };
  208. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  209. register SmiVideoProc *pVP = (SmiVideoProc *)&smiVP;
  210. register SmiVideoWin *pVWin = (SmiVideoWin *)&smiVW;
  211. pVP->width = pGD->plnSizeX * pGD->gdfBytesPP;
  212. pVP->control |= pGD->gdfIndex << 16;
  213. pVWin->bottom = pGD->winSizeY - 1;
  214. pVWin->right = pGD->winSizeX - 1;
  215. pVWin->width = pVP->width;
  216. /* color key */
  217. out32r ((pGD->vprBase + 0x0004), pVP->colorKey);
  218. /* color key mask */
  219. out32r ((pGD->vprBase + 0x0008), pVP->colorKeyMask);
  220. /* data src start adrs */
  221. out32r ((pGD->vprBase + 0x000c), pVP->start / 8);
  222. /* data width and offset */
  223. out32r ((pGD->vprBase + 0x0010),
  224. ((pVP->offset / 8 * pGD->gdfBytesPP) << 16) |
  225. (pGD->plnSizeX / 8 * pGD->gdfBytesPP));
  226. /* video window 1 */
  227. out32r ((pGD->vprBase + 0x0014),
  228. ((pVWin->top << 16) | pVWin->left));
  229. out32r ((pGD->vprBase + 0x0018),
  230. ((pVWin->bottom << 16) | pVWin->right));
  231. out32r ((pGD->vprBase + 0x001c), pVWin->srcStart / 8);
  232. out32r ((pGD->vprBase + 0x0020),
  233. (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
  234. out32r ((pGD->vprBase + 0x0024),
  235. (((pVWin->hStretch) << 8) | pVWin->vStretch));
  236. /* video window 2 */
  237. out32r ((pGD->vprBase + 0x0028),
  238. ((pVWin->top << 16) | pVWin->left));
  239. out32r ((pGD->vprBase + 0x002c),
  240. ((pVWin->bottom << 16) | pVWin->right));
  241. out32r ((pGD->vprBase + 0x0030),
  242. pVWin->srcStart / 8);
  243. out32r ((pGD->vprBase + 0x0034),
  244. (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
  245. out32r ((pGD->vprBase + 0x0038),
  246. (((pVWin->hStretch) << 8) | pVWin->vStretch));
  247. /* fifo prio control */
  248. out32r ((pGD->vprBase + 0x0054), pVP->fifoPrio);
  249. /* fifo empty request levell */
  250. out32r ((pGD->vprBase + 0x0058), pVP->fifoERL);
  251. /* conversion constant */
  252. out32r ((pGD->vprBase + 0x005c), pVP->YUVtoRGB);
  253. /* vpr control word */
  254. out32r ((pGD->vprBase + 0x0000), pVP->control);
  255. }
  256. /******************************************************************************
  257. *
  258. * Init drawing engine registers
  259. */
  260. static void smiInitDrawingEngine (void)
  261. {
  262. GraphicDevice *pGD = (GraphicDevice *)&smi;
  263. unsigned int val;
  264. /* don't start now */
  265. out32r ((pGD->dprBase + 0x000c), 0x000f0000);
  266. /* set rop2 to copypen */
  267. val = 0xffff3ff0 & in32r ((pGD->dprBase + 0x000c));
  268. out32r ((pGD->dprBase + 0x000c), (val | 0x8000 | 0x0c));
  269. /* set clip rect */
  270. out32r ((pGD->dprBase + 0x002c), 0);
  271. out32r ((pGD->dprBase + 0x0030),
  272. ((pGD->winSizeY<<16) | pGD->winSizeX * pGD->gdfBytesPP ));
  273. /* src row pitch */
  274. val = 0xffff0000 & (in32r ((pGD->dprBase + 0x0010)));
  275. out32r ((pGD->dprBase + 0x0010),
  276. (val | pGD->plnSizeX * pGD->gdfBytesPP));
  277. /* dst row pitch */
  278. val = 0x0000ffff & (in32r ((pGD->dprBase + 0x0010)));
  279. out32r ((pGD->dprBase + 0x0010),
  280. (((pGD->plnSizeX * pGD->gdfBytesPP)<<16) | val));
  281. /* window width src/dst */
  282. out32r ((pGD->dprBase + 0x003c),
  283. (((pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)<<16) |
  284. (pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)));
  285. out16r ((pGD->dprBase + 0x001e), 0x0000);
  286. /* src base adrs */
  287. out32r ((pGD->dprBase + 0x0040),
  288. (((pGD->frameAdrs/8) & 0x000fffff)));
  289. /* dst base adrs */
  290. out32r ((pGD->dprBase + 0x0044),
  291. (((pGD->frameAdrs/8) & 0x000fffff)));
  292. /* foreground color */
  293. out32r ((pGD->dprBase + 0x0014), pGD->fg);
  294. /* background color */
  295. out32r ((pGD->dprBase + 0x0018), pGD->bg);
  296. /* xcolor */
  297. out32r ((pGD->dprBase + 0x0020), 0x00ffffff);
  298. /* xcolor mask */
  299. out32r ((pGD->dprBase + 0x0024), 0x00ffffff);
  300. /* bit mask */
  301. out32r ((pGD->dprBase + 0x0028), 0x00ffffff);
  302. /* load mono pattern */
  303. out32r ((pGD->dprBase + 0x0034), 0);
  304. out32r ((pGD->dprBase + 0x0038), 0);
  305. }
  306. static struct pci_device_id supported[] = {
  307. { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_710 },
  308. { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_712 },
  309. { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_810 },
  310. { }
  311. };
  312. /*****************************************************************************/
  313. static void smiLoadMsr (struct ctfb_res_modes *mode)
  314. {
  315. unsigned char h_synch_high, v_synch_high;
  316. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  317. h_synch_high = (mode->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x40; /* horizontal Synch High active */
  318. v_synch_high = (mode->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x80; /* vertical Synch High active */
  319. out8 (SMI_MISC_REG, (h_synch_high | v_synch_high | 0x29));
  320. /* upper64K==0x20, CLC2select==0x08, RAMenable==0x02!(todo), CGA==0x01
  321. * Selects the upper 64KB page.Bit5=1
  322. * CLK2 (left reserved in standard VGA) Bit3|2=1|0
  323. * Disables CPU access to frame buffer. Bit1=0
  324. * Sets the I/O address decode for ST01, FCR, and all CR registers
  325. * to the 3Dx I/O address range (CGA emulation). Bit0=1
  326. */
  327. }
  328. /*****************************************************************************/
  329. static void smiLoadCrt (struct ctfb_res_modes *var, int bits_per_pixel)
  330. {
  331. unsigned char cr[0x7a];
  332. int i;
  333. unsigned int hd, hs, he, ht, hbs, hbe; /* Horizontal. */
  334. unsigned int vd, vs, ve, vt, vbs, vbe; /* vertical */
  335. unsigned int bpp, wd, dblscan, interlaced;
  336. const int LineCompare = 0x3ff;
  337. unsigned int TextScanLines = 1; /* this is in fact a vertical zoom factor */
  338. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  339. /* Horizontal */
  340. hd = (var->xres) / 8; /* HDisp. */
  341. hs = (var->xres + var->right_margin) / 8; /* HsStrt */
  342. he = (var->xres + var->right_margin + var->hsync_len) / 8; /* HsEnd */
  343. ht = (var->left_margin + var->xres + var->right_margin + var->hsync_len) / 8; /* HTotal */
  344. /* Blank */
  345. hbs = hd;
  346. hbe = 0; /* Blank end at 0 */
  347. /* Vertical */
  348. vd = var->yres; /* VDisplay */
  349. vs = var->yres + var->lower_margin; /* VSyncStart */
  350. ve = var->yres + var->lower_margin + var->vsync_len; /* VSyncEnd */
  351. vt = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; /* VTotal */
  352. vbs = vd;
  353. vbe = 0;
  354. bpp = bits_per_pixel;
  355. dblscan = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0;
  356. interlaced = var->vmode & FB_VMODE_INTERLACED;
  357. if (bpp == 15)
  358. bpp = 16;
  359. wd = var->xres * bpp / 64; /* double words per line */
  360. if (interlaced) { /* we divide all vertical timings, exept vd */
  361. vs >>= 1;
  362. vbs >>= 1;
  363. ve >>= 1;
  364. vt >>= 1;
  365. }
  366. memset (cr, 0, sizeof (cr));
  367. cr[0x00] = ht - 5;
  368. cr[0x01] = hd - 1;
  369. cr[0x02] = hbs - 1;
  370. cr[0x03] = (hbe & 0x1F);
  371. cr[0x04] = hs;
  372. cr[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
  373. cr[0x06] = (vt - 2) & 0xFF;
  374. cr[0x07] = (((vt - 2) & 0x100) >> 8)
  375. | (((vd - 1) & 0x100) >> 7)
  376. | ((vs & 0x100) >> 6)
  377. | (((vbs - 1) & 0x100) >> 5)
  378. | ((LineCompare & 0x100) >> 4)
  379. | (((vt - 2) & 0x200) >> 4)
  380. | (((vd - 1) & 0x200) >> 3)
  381. | ((vs & 0x200) >> 2);
  382. cr[0x30] = ((vt - 2) & 0x400) >> 7
  383. | (((vd - 1) & 0x400) >> 8)
  384. | (((vbs - 1) & 0x400) >> 9)
  385. | ((vs & 0x400) >> 10)
  386. | (interlaced) ? 0x80 : 0;
  387. cr[0x08] = 0x00;
  388. cr[0x09] = (dblscan << 7)
  389. | ((LineCompare & 0x200) >> 3)
  390. | (((vbs - 1) & 0x200) >> 4)
  391. | (TextScanLines - 1);
  392. cr[0x10] = vs & 0xff; /* VSyncPulseStart */
  393. cr[0x11] = (ve & 0x0f);
  394. cr[0x12] = (vd - 1) & 0xff; /* LineCount */
  395. cr[0x13] = wd & 0xff;
  396. cr[0x14] = 0x40;
  397. cr[0x15] = (vbs - 1) & 0xff;
  398. cr[0x16] = vbe & 0xff;
  399. cr[0x17] = 0xe3; /* but it does not work */
  400. cr[0x18] = 0xff & LineCompare;
  401. cr[0x22] = 0x00; /* todo? */
  402. /* now set the registers */
  403. for (i = 0; i <= 0x18; i++) { /*CR00 .. CR18 */
  404. smiWrite (SMI_INDX_D4, i, cr[i]);
  405. }
  406. i = 0x22; /*CR22 */
  407. smiWrite (SMI_INDX_D4, i, cr[i]);
  408. i = 0x30; /*CR30 */
  409. smiWrite (SMI_INDX_D4, i, cr[i]);
  410. }
  411. /*****************************************************************************/
  412. #define REF_FREQ 14318180
  413. #define PMIN 1
  414. #define PMAX 255
  415. #define QMIN 1
  416. #define QMAX 63
  417. static unsigned int FindPQ (unsigned int freq, unsigned int *pp, unsigned int *pq)
  418. {
  419. unsigned int n = QMIN, m = 0;
  420. long long int L = 0, P = freq, Q = REF_FREQ, H = P >> 1;
  421. long long int D = 0x7ffffffffffffffLL;
  422. for (n = QMIN; n <= QMAX; n++) {
  423. m = PMIN; /* p/q ~ freq/ref -> p*ref-freq*q ~ 0 */
  424. L = P * n - m * Q;
  425. while (L > 0 && m < PMAX) {
  426. L -= REF_FREQ; /* difference is greater as 0 subtract fref */
  427. m++; /* and increment m */
  428. }
  429. /* difference is less or equal than 0 or m > maximum */
  430. if (m > PMAX)
  431. break; /* no solution: if we increase n we get the same situation */
  432. /* L is <= 0 now */
  433. if (-L > H && m > PMIN) { /* if difference > the half fref */
  434. L += REF_FREQ; /* we take the situation before */
  435. m--; /* because its closer to 0 */
  436. }
  437. L = (L < 0) ? -L : +L; /* absolute value */
  438. if (D < L) /* if last difference was better take next n */
  439. continue;
  440. D = L;
  441. *pp = m;
  442. *pq = n; /* keep improved data */
  443. if (D == 0)
  444. break; /* best result we can get */
  445. }
  446. return (unsigned int) (0xffffffff & D);
  447. }
  448. /*****************************************************************************/
  449. static void smiLoadCcr (struct ctfb_res_modes *var, unsigned short device_id)
  450. {
  451. unsigned int p, q;
  452. long long freq;
  453. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  454. smiWrite (SMI_INDX_C4, 0x65, 0);
  455. smiWrite (SMI_INDX_C4, 0x66, 0);
  456. smiWrite (SMI_INDX_C4, 0x68, 0x50);
  457. if (device_id == PCI_DEVICE_ID_SMI_810) {
  458. smiWrite (SMI_INDX_C4, 0x69, 0x3);
  459. } else {
  460. smiWrite (SMI_INDX_C4, 0x69, 0x0);
  461. }
  462. /* Memory clock */
  463. switch (device_id) {
  464. case PCI_DEVICE_ID_SMI_710 :
  465. smiWrite (SMI_INDX_C4, 0x6a, 0x75);
  466. break;
  467. case PCI_DEVICE_ID_SMI_712 :
  468. smiWrite (SMI_INDX_C4, 0x6a, 0x80);
  469. break;
  470. default :
  471. smiWrite (SMI_INDX_C4, 0x6a, 0x53);
  472. break;
  473. }
  474. smiWrite (SMI_INDX_C4, 0x6b, 0x15);
  475. /* VCLK */
  476. freq = 1000000000000LL / var -> pixclock;
  477. FindPQ ((unsigned int)freq, &p, &q);
  478. smiWrite (SMI_INDX_C4, 0x6c, p);
  479. smiWrite (SMI_INDX_C4, 0x6d, q);
  480. }
  481. /*******************************************************************************
  482. *
  483. * Init video chip with common Linux graphic modes (lilo)
  484. */
  485. void *video_hw_init (void)
  486. {
  487. GraphicDevice *pGD = (GraphicDevice *)&smi;
  488. unsigned short device_id;
  489. pci_dev_t devbusfn;
  490. int videomode;
  491. unsigned long t1, hsynch, vsynch;
  492. unsigned int pci_mem_base, *vm;
  493. char *penv;
  494. int tmp, i, bits_per_pixel;
  495. struct ctfb_res_modes *res_mode;
  496. struct ctfb_res_modes var_mode;
  497. unsigned char videoout;
  498. /* Search for video chip */
  499. printf("Video: ");
  500. if ((devbusfn = pci_find_devices(supported, 0)) < 0)
  501. {
  502. printf ("Controller not found !\n");
  503. return (NULL);
  504. }
  505. /* PCI setup */
  506. pci_write_config_dword (devbusfn, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
  507. pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
  508. pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
  509. pci_mem_base = pci_mem_to_phys (devbusfn, pci_mem_base);
  510. tmp = 0;
  511. videomode = CFG_DEFAULT_VIDEO_MODE;
  512. /* get video mode via environment */
  513. if ((penv = getenv ("videomode")) != NULL) {
  514. /* deceide if it is a string */
  515. if (penv[0] <= '9') {
  516. videomode = (int) simple_strtoul (penv, NULL, 16);
  517. tmp = 1;
  518. }
  519. } else {
  520. tmp = 1;
  521. }
  522. if (tmp) {
  523. /* parameter are vesa modes */
  524. /* search params */
  525. for (i = 0; i < VESA_MODES_COUNT; i++) {
  526. if (vesa_modes[i].vesanr == videomode)
  527. break;
  528. }
  529. if (i == VESA_MODES_COUNT) {
  530. printf ("no VESA Mode found, switching to mode 0x%x ", CFG_DEFAULT_VIDEO_MODE);
  531. i = 0;
  532. }
  533. res_mode =
  534. (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
  535. resindex];
  536. bits_per_pixel = vesa_modes[i].bits_per_pixel;
  537. } else {
  538. res_mode = (struct ctfb_res_modes *) &var_mode;
  539. bits_per_pixel = video_get_params (res_mode, penv);
  540. }
  541. /* calculate hsynch and vsynch freq (info only) */
  542. t1 = (res_mode->left_margin + res_mode->xres +
  543. res_mode->right_margin + res_mode->hsync_len) / 8;
  544. t1 *= 8;
  545. t1 *= res_mode->pixclock;
  546. t1 /= 1000;
  547. hsynch = 1000000000L / t1;
  548. t1 *=
  549. (res_mode->upper_margin + res_mode->yres +
  550. res_mode->lower_margin + res_mode->vsync_len);
  551. t1 /= 1000;
  552. vsynch = 1000000000L / t1;
  553. /* fill in Graphic device struct */
  554. sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
  555. res_mode->yres, bits_per_pixel, (hsynch / 1000),
  556. (vsynch / 1000));
  557. printf ("%s\n", pGD->modeIdent);
  558. pGD->winSizeX = res_mode->xres;
  559. pGD->winSizeY = res_mode->yres;
  560. pGD->plnSizeX = res_mode->xres;
  561. pGD->plnSizeY = res_mode->yres;
  562. switch (bits_per_pixel) {
  563. case 8:
  564. pGD->gdfBytesPP = 1;
  565. pGD->gdfIndex = GDF__8BIT_INDEX;
  566. break;
  567. case 15:
  568. pGD->gdfBytesPP = 2;
  569. pGD->gdfIndex = GDF_15BIT_555RGB;
  570. break;
  571. case 16:
  572. pGD->gdfBytesPP = 2;
  573. pGD->gdfIndex = GDF_16BIT_565RGB;
  574. break;
  575. case 24:
  576. pGD->gdfBytesPP = 3;
  577. pGD->gdfIndex = GDF_24BIT_888RGB;
  578. break;
  579. }
  580. pGD->isaBase = CFG_ISA_IO;
  581. pGD->pciBase = pci_mem_base;
  582. pGD->dprBase = (pci_mem_base + 0x400000 + 0x8000);
  583. pGD->vprBase = (pci_mem_base + 0x400000 + 0xc000);
  584. pGD->cprBase = (pci_mem_base + 0x400000 + 0xe000);
  585. pGD->frameAdrs = pci_mem_base;
  586. pGD->memSize = VIDEO_MEM_SIZE;
  587. /* Set up hardware : select color mode,
  588. set Register base to isa 3dx for 3?x regs*/
  589. out8 (SMI_MISC_REG, 0x01);
  590. /* Turn off display */
  591. smiWrite (SMI_INDX_C4, 0x01, 0x20);
  592. /* Unlock ext. crt regs */
  593. out8 (SMI_LOCK_REG, 0x40);
  594. /* Unlock crt regs 0-7 */
  595. smiWrite (SMI_INDX_D4, 0x11, 0x0e);
  596. /* Sytem Control Register */
  597. smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SCR, sizeof(SMI_SCR));
  598. /* extented CRT Register */
  599. smiLoadRegs (SMI_INDX_D4, SMI_DATA_D5, SMI_EXT_CRT, sizeof(SMI_EXT_CRT));
  600. /* Attributes controller registers */
  601. smiLoadRegs (SMI_INDX_ATTR, SMI_INDX_ATTR, SMI_ATTR, sizeof(SMI_ATTR));
  602. /* Graphics Controller Register */
  603. smiLoadRegs (SMI_INDX_CE, SMI_DATA_CF, SMI_GCR, sizeof(SMI_GCR));
  604. /* Sequencer Register */
  605. smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SEQR, sizeof(SMI_SEQR));
  606. /* Power Control Register */
  607. smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_PCR, sizeof(SMI_PCR));
  608. /* Memory Control Register */
  609. /* Register MSR62 is a power on configurable register. We don't */
  610. /* modify it */
  611. smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_MCR, sizeof(SMI_MCR));
  612. /* Set misc output register */
  613. smiLoadMsr (res_mode);
  614. /* Set CRT and Clock control registers */
  615. smiLoadCrt (res_mode, bits_per_pixel);
  616. smiLoadCcr (res_mode, device_id);
  617. /* Hardware Cusor Register */
  618. smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_HCR, sizeof(SMI_HCR));
  619. /* Enable Display */
  620. videoout = 2; /* Default output is CRT */
  621. if ((penv = getenv ("videoout")) != NULL) {
  622. /* deceide if it is a string */
  623. videoout = (int) simple_strtoul (penv, NULL, 16);
  624. }
  625. smiWrite (SMI_INDX_C4, 0x31, videoout);
  626. /* Video processor default setup */
  627. smiInitVideoProcessor ();
  628. /* Capture port default setup */
  629. smiInitCapturePort ();
  630. /* Drawing engine default setup */
  631. smiInitDrawingEngine ();
  632. /* Turn on display */
  633. smiWrite (0x3c4, 0x01, 0x01);
  634. /* Clear video memory */
  635. i = pGD->memSize/4;
  636. vm = (unsigned int *)pGD->pciBase;
  637. while(i--)
  638. *vm++ = 0;
  639. return ((void*)&smi);
  640. }
  641. /*******************************************************************************
  642. *
  643. * Drawing engine fill on screen region
  644. */
  645. void video_hw_rectfill (
  646. unsigned int bpp, /* bytes per pixel */
  647. unsigned int dst_x, /* dest pos x */
  648. unsigned int dst_y, /* dest pos y */
  649. unsigned int dim_x, /* frame width */
  650. unsigned int dim_y, /* frame height */
  651. unsigned int color /* fill color */
  652. )
  653. {
  654. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  655. register unsigned int control;
  656. dim_x *= bpp;
  657. out32r ((pGD->dprBase + 0x0014), color);
  658. out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
  659. out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
  660. control = 0x0000ffff & in32r ((pGD->dprBase + 0x000c));
  661. control |= 0x80010000;
  662. out32r ((pGD->dprBase + 0x000c), control);
  663. /* Wait for drawing processor */
  664. do
  665. {
  666. out8 ((pGD->isaBase + 0x3c4), 0x16);
  667. } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
  668. }
  669. /*******************************************************************************
  670. *
  671. * Drawing engine bitblt with screen region
  672. */
  673. void video_hw_bitblt (
  674. unsigned int bpp, /* bytes per pixel */
  675. unsigned int src_x, /* source pos x */
  676. unsigned int src_y, /* source pos y */
  677. unsigned int dst_x, /* dest pos x */
  678. unsigned int dst_y, /* dest pos y */
  679. unsigned int dim_x, /* frame width */
  680. unsigned int dim_y /* frame height */
  681. )
  682. {
  683. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  684. register unsigned int control;
  685. dim_x *= bpp;
  686. if ((src_y<dst_y) || ((src_y==dst_y) && (src_x<dst_x)))
  687. {
  688. out32r ((pGD->dprBase + 0x0000), (((src_x+dim_x-1)<<16) | (src_y+dim_y-1)));
  689. out32r ((pGD->dprBase + 0x0004), (((dst_x+dim_x-1)<<16) | (dst_y+dim_y-1)));
  690. control = 0x88000000;
  691. } else {
  692. out32r ((pGD->dprBase + 0x0000), ((src_x<<16) | src_y));
  693. out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
  694. control = 0x80000000;
  695. }
  696. out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
  697. control |= (0x0000ffff & in32r ((pGD->dprBase + 0x000c)));
  698. out32r ((pGD->dprBase + 0x000c), control);
  699. /* Wait for drawing processor */
  700. do
  701. {
  702. out8 ((pGD->isaBase + 0x3c4), 0x16);
  703. } while (in8 (pGD->isaBase + 0x3c5) & 0x08);
  704. }
  705. /*******************************************************************************
  706. *
  707. * Set a RGB color in the LUT (8 bit index)
  708. */
  709. void video_set_lut (
  710. unsigned int index, /* color number */
  711. unsigned char r, /* red */
  712. unsigned char g, /* green */
  713. unsigned char b /* blue */
  714. )
  715. {
  716. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  717. out8 (SMI_LUT_MASK, 0xff);
  718. out8 (SMI_LUT_START, (char)index);
  719. out8 (SMI_LUT_RGB, r>>2); /* red */
  720. udelay (10);
  721. out8 (SMI_LUT_RGB, g>>2); /* green */
  722. udelay (10);
  723. out8 (SMI_LUT_RGB, b>>2); /* blue */
  724. udelay (10);
  725. }
  726. #endif /* CONFIG_VIDEO_SMI_LYNXEM */