smiLynxEM.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  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. #include <pci.h>
  41. #include <video_fb.h>
  42. #include "videomodes.h"
  43. /*
  44. * Export Graphic Device
  45. */
  46. GraphicDevice smi;
  47. /*
  48. * SMI 710/712 have 4MB internal RAM; SMI 810 2MB internal + 2MB external
  49. */
  50. #define VIDEO_MEM_SIZE 0x400000
  51. /*
  52. * ISA mapped regs
  53. */
  54. #define SMI_INDX_C4 (pGD->isaBase + 0x03c4) /* index reg */
  55. #define SMI_DATA_C5 (pGD->isaBase + 0x03c5) /* data reg */
  56. #define SMI_INDX_D4 (pGD->isaBase + 0x03d4) /* index reg */
  57. #define SMI_DATA_D5 (pGD->isaBase + 0x03d5) /* data reg */
  58. #define SMI_ISR1 (pGD->isaBase + 0x03ca)
  59. #define SMI_INDX_CE (pGD->isaBase + 0x03ce) /* index reg */
  60. #define SMI_DATA_CF (pGD->isaBase + 0x03cf) /* data reg */
  61. #define SMI_LOCK_REG (pGD->isaBase + 0x03c3) /* unlock/lock ext crt reg */
  62. #define SMI_MISC_REG (pGD->isaBase + 0x03c2) /* misc reg */
  63. #define SMI_LUT_MASK (pGD->isaBase + 0x03c6) /* lut mask reg */
  64. #define SMI_LUT_START (pGD->isaBase + 0x03c8) /* lut start index */
  65. #define SMI_LUT_RGB (pGD->isaBase + 0x03c9) /* lut colors auto incr.*/
  66. #define SMI_INDX_ATTR (pGD->isaBase + 0x03c0) /* attributes index reg */
  67. /*
  68. * Video processor control
  69. */
  70. typedef struct {
  71. unsigned int control;
  72. unsigned int colorKey;
  73. unsigned int colorKeyMask;
  74. unsigned int start;
  75. unsigned short offset;
  76. unsigned short width;
  77. unsigned int fifoPrio;
  78. unsigned int fifoERL;
  79. unsigned int YUVtoRGB;
  80. } SmiVideoProc;
  81. /*
  82. * Video window control
  83. */
  84. typedef struct {
  85. unsigned short top;
  86. unsigned short left;
  87. unsigned short bottom;
  88. unsigned short right;
  89. unsigned int srcStart;
  90. unsigned short width;
  91. unsigned short offset;
  92. unsigned char hStretch;
  93. unsigned char vStretch;
  94. } SmiVideoWin;
  95. /*
  96. * Capture port control
  97. */
  98. typedef struct {
  99. unsigned int control;
  100. unsigned short topClip;
  101. unsigned short leftClip;
  102. unsigned short srcHeight;
  103. unsigned short srcWidth;
  104. unsigned int srcBufStart1;
  105. unsigned int srcBufStart2;
  106. unsigned short srcOffset;
  107. unsigned short fifoControl;
  108. } SmiCapturePort;
  109. /*
  110. * Register values for common video modes
  111. */
  112. static char SMI_SCR[] = {
  113. /* all modes */
  114. 0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90,
  115. 0x17, 0x20, 0x18, 0xb1, 0x19, 0x00,
  116. };
  117. static char SMI_EXT_CRT[] = {
  118. 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00,
  119. 0x36, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
  120. };
  121. static char SMI_ATTR [] = {
  122. 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05,
  123. 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b,
  124. 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x41, 0x11, 0x00,
  125. 0x12, 0x0f, 0x13, 0x00, 0x14, 0x00,
  126. };
  127. static char SMI_GCR[18] = {
  128. 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x40,
  129. 0x06, 0x05, 0x07, 0x0f, 0x08, 0xff,
  130. };
  131. static char SMI_SEQR[] = {
  132. 0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03,
  133. };
  134. static char SMI_PCR [] = {
  135. 0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00,
  136. };
  137. static char SMI_MCR[] = {
  138. 0x60, 0x01, 0x61, 0x00,
  139. #ifdef CONFIG_HMI1001
  140. 0x62, 0x74, /* Memory type is not configured by pins on HMI1001 */
  141. #endif
  142. };
  143. static char SMI_HCR[] = {
  144. 0x80, 0xff, 0x81, 0x07, 0x82, 0x00, 0x83, 0xff, 0x84, 0xff, 0x88, 0x00,
  145. 0x89, 0x02, 0x8a, 0x80, 0x8b, 0x01, 0x8c, 0xff, 0x8d, 0x00,
  146. };
  147. /*******************************************************************************
  148. *
  149. * Write SMI ISA register
  150. */
  151. static void smiWrite (unsigned short index, char reg, char val)
  152. {
  153. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  154. out8 ((pGD->isaBase + index), reg);
  155. out8 ((pGD->isaBase + index + 1), val);
  156. }
  157. /*******************************************************************************
  158. *
  159. * Write a table of SMI ISA register
  160. */
  161. static void smiLoadRegs (
  162. unsigned int iReg,
  163. unsigned int dReg,
  164. char *regTab,
  165. unsigned int tabSize
  166. )
  167. {
  168. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  169. register int i;
  170. for (i=0; i<tabSize; i+=2) {
  171. if (iReg == SMI_INDX_ATTR) {
  172. /* Reset the Flip Flop */
  173. in8 (SMI_ISR1);
  174. out8 (iReg, regTab[i]);
  175. out8 (iReg, regTab[i+1]);
  176. } else {
  177. out8 (iReg, regTab[i]);
  178. out8 (dReg, regTab[i+1]);
  179. }
  180. }
  181. }
  182. /*******************************************************************************
  183. *
  184. * Init capture port registers
  185. */
  186. static void smiInitCapturePort (void)
  187. {
  188. SmiCapturePort smiCP = { 0x01400600, 0x30, 0x40, 480, 640, 0, 0, 2560, 6 };
  189. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  190. register SmiCapturePort *pCP = (SmiCapturePort *)&smiCP;
  191. out32r ((pGD->cprBase + 0x0004), ((pCP->topClip<<16) | pCP->leftClip));
  192. out32r ((pGD->cprBase + 0x0008), ((pCP->srcHeight<<16) | pCP->srcWidth));
  193. out32r ((pGD->cprBase + 0x000c), pCP->srcBufStart1/8);
  194. out32r ((pGD->cprBase + 0x0010), pCP->srcBufStart2/8);
  195. out32r ((pGD->cprBase + 0x0014), pCP->srcOffset/8);
  196. out32r ((pGD->cprBase + 0x0018), pCP->fifoControl);
  197. out32r ((pGD->cprBase + 0x0000), pCP->control);
  198. }
  199. /*******************************************************************************
  200. *
  201. * Init video processor registers
  202. */
  203. static void smiInitVideoProcessor (void)
  204. {
  205. SmiVideoProc smiVP = { 0x100000, 0, 0, 0, 0, 1600, 0x1200543, 4, 0xededed };
  206. SmiVideoWin smiVW = { 0, 0, 599, 799, 0, 1600, 0, 0, 0 };
  207. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  208. register SmiVideoProc *pVP = (SmiVideoProc *)&smiVP;
  209. register SmiVideoWin *pVWin = (SmiVideoWin *)&smiVW;
  210. pVP->width = pGD->plnSizeX * pGD->gdfBytesPP;
  211. pVP->control |= pGD->gdfIndex << 16;
  212. pVWin->bottom = pGD->winSizeY - 1;
  213. pVWin->right = pGD->winSizeX - 1;
  214. pVWin->width = pVP->width;
  215. /* color key */
  216. out32r ((pGD->vprBase + 0x0004), pVP->colorKey);
  217. /* color key mask */
  218. out32r ((pGD->vprBase + 0x0008), pVP->colorKeyMask);
  219. /* data src start adrs */
  220. out32r ((pGD->vprBase + 0x000c), pVP->start / 8);
  221. /* data width and offset */
  222. out32r ((pGD->vprBase + 0x0010),
  223. ((pVP->offset / 8 * pGD->gdfBytesPP) << 16) |
  224. (pGD->plnSizeX / 8 * pGD->gdfBytesPP));
  225. /* video window 1 */
  226. out32r ((pGD->vprBase + 0x0014),
  227. ((pVWin->top << 16) | pVWin->left));
  228. out32r ((pGD->vprBase + 0x0018),
  229. ((pVWin->bottom << 16) | pVWin->right));
  230. out32r ((pGD->vprBase + 0x001c), pVWin->srcStart / 8);
  231. out32r ((pGD->vprBase + 0x0020),
  232. (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
  233. out32r ((pGD->vprBase + 0x0024),
  234. (((pVWin->hStretch) << 8) | pVWin->vStretch));
  235. /* video window 2 */
  236. out32r ((pGD->vprBase + 0x0028),
  237. ((pVWin->top << 16) | pVWin->left));
  238. out32r ((pGD->vprBase + 0x002c),
  239. ((pVWin->bottom << 16) | pVWin->right));
  240. out32r ((pGD->vprBase + 0x0030),
  241. pVWin->srcStart / 8);
  242. out32r ((pGD->vprBase + 0x0034),
  243. (((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
  244. out32r ((pGD->vprBase + 0x0038),
  245. (((pVWin->hStretch) << 8) | pVWin->vStretch));
  246. /* fifo prio control */
  247. out32r ((pGD->vprBase + 0x0054), pVP->fifoPrio);
  248. /* fifo empty request levell */
  249. out32r ((pGD->vprBase + 0x0058), pVP->fifoERL);
  250. /* conversion constant */
  251. out32r ((pGD->vprBase + 0x005c), pVP->YUVtoRGB);
  252. /* vpr control word */
  253. out32r ((pGD->vprBase + 0x0000), pVP->control);
  254. }
  255. /******************************************************************************
  256. *
  257. * Init drawing engine registers
  258. */
  259. static void smiInitDrawingEngine (void)
  260. {
  261. GraphicDevice *pGD = (GraphicDevice *)&smi;
  262. unsigned int val;
  263. /* don't start now */
  264. out32r ((pGD->dprBase + 0x000c), 0x000f0000);
  265. /* set rop2 to copypen */
  266. val = 0xffff3ff0 & in32r ((pGD->dprBase + 0x000c));
  267. out32r ((pGD->dprBase + 0x000c), (val | 0x8000 | 0x0c));
  268. /* set clip rect */
  269. out32r ((pGD->dprBase + 0x002c), 0);
  270. out32r ((pGD->dprBase + 0x0030),
  271. ((pGD->winSizeY<<16) | pGD->winSizeX * pGD->gdfBytesPP ));
  272. /* src row pitch */
  273. val = 0xffff0000 & (in32r ((pGD->dprBase + 0x0010)));
  274. out32r ((pGD->dprBase + 0x0010),
  275. (val | pGD->plnSizeX * pGD->gdfBytesPP));
  276. /* dst row pitch */
  277. val = 0x0000ffff & (in32r ((pGD->dprBase + 0x0010)));
  278. out32r ((pGD->dprBase + 0x0010),
  279. (((pGD->plnSizeX * pGD->gdfBytesPP)<<16) | val));
  280. /* window width src/dst */
  281. out32r ((pGD->dprBase + 0x003c),
  282. (((pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)<<16) |
  283. (pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)));
  284. out16r ((pGD->dprBase + 0x001e), 0x0000);
  285. /* src base adrs */
  286. out32r ((pGD->dprBase + 0x0040),
  287. (((pGD->frameAdrs/8) & 0x000fffff)));
  288. /* dst base adrs */
  289. out32r ((pGD->dprBase + 0x0044),
  290. (((pGD->frameAdrs/8) & 0x000fffff)));
  291. /* foreground color */
  292. out32r ((pGD->dprBase + 0x0014), pGD->fg);
  293. /* background color */
  294. out32r ((pGD->dprBase + 0x0018), pGD->bg);
  295. /* xcolor */
  296. out32r ((pGD->dprBase + 0x0020), 0x00ffffff);
  297. /* xcolor mask */
  298. out32r ((pGD->dprBase + 0x0024), 0x00ffffff);
  299. /* bit mask */
  300. out32r ((pGD->dprBase + 0x0028), 0x00ffffff);
  301. /* load mono pattern */
  302. out32r ((pGD->dprBase + 0x0034), 0);
  303. out32r ((pGD->dprBase + 0x0038), 0);
  304. }
  305. static struct pci_device_id supported[] = {
  306. { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_710 },
  307. { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_712 },
  308. { PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_810 },
  309. { }
  310. };
  311. /*****************************************************************************/
  312. static void smiLoadMsr (struct ctfb_res_modes *mode)
  313. {
  314. unsigned char h_synch_high, v_synch_high;
  315. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  316. h_synch_high = (mode->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x40; /* horizontal Synch High active */
  317. v_synch_high = (mode->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x80; /* vertical Synch High active */
  318. out8 (SMI_MISC_REG, (h_synch_high | v_synch_high | 0x29));
  319. /* upper64K==0x20, CLC2select==0x08, RAMenable==0x02!(todo), CGA==0x01
  320. * Selects the upper 64KB page.Bit5=1
  321. * CLK2 (left reserved in standard VGA) Bit3|2=1|0
  322. * Disables CPU access to frame buffer. Bit1=0
  323. * Sets the I/O address decode for ST01, FCR, and all CR registers
  324. * to the 3Dx I/O address range (CGA emulation). Bit0=1
  325. */
  326. }
  327. /*****************************************************************************/
  328. static void smiLoadCrt (struct ctfb_res_modes *var, int bits_per_pixel)
  329. {
  330. unsigned char cr[0x7a];
  331. int i;
  332. unsigned int hd, hs, he, ht, hbs, hbe; /* Horizontal. */
  333. unsigned int vd, vs, ve, vt, vbs, vbe; /* vertical */
  334. unsigned int bpp, wd, dblscan, interlaced;
  335. const int LineCompare = 0x3ff;
  336. unsigned int TextScanLines = 1; /* this is in fact a vertical zoom factor */
  337. register GraphicDevice *pGD = (GraphicDevice *)&smi;
  338. /* Horizontal */
  339. hd = (var->xres) / 8; /* HDisp. */
  340. hs = (var->xres + var->right_margin) / 8; /* HsStrt */
  341. he = (var->xres + var->right_margin + var->hsync_len) / 8; /* HsEnd */
  342. ht = (var->left_margin + var->xres + var->right_margin + var->hsync_len) / 8; /* HTotal */
  343. /* Blank */
  344. hbs = hd;
  345. hbe = 0; /* Blank end at 0 */
  346. /* Vertical */
  347. vd = var->yres; /* VDisplay */
  348. vs = var->yres + var->lower_margin; /* VSyncStart */
  349. ve = var->yres + var->lower_margin + var->vsync_len; /* VSyncEnd */
  350. vt = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; /* VTotal */
  351. vbs = vd;
  352. vbe = 0;
  353. bpp = bits_per_pixel;
  354. dblscan = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0;
  355. interlaced = var->vmode & FB_VMODE_INTERLACED;
  356. if (bpp == 15)
  357. bpp = 16;
  358. wd = var->xres * bpp / 64; /* double words per line */
  359. if (interlaced) { /* we divide all vertical timings, exept vd */
  360. vs >>= 1;
  361. vbs >>= 1;
  362. ve >>= 1;
  363. vt >>= 1;
  364. }
  365. memset (cr, 0, sizeof (cr));
  366. cr[0x00] = ht - 5;
  367. cr[0x01] = hd - 1;
  368. cr[0x02] = hbs - 1;
  369. cr[0x03] = (hbe & 0x1F);
  370. cr[0x04] = hs;
  371. cr[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
  372. cr[0x06] = (vt - 2) & 0xFF;
  373. cr[0x07] = (((vt - 2) & 0x100) >> 8)
  374. | (((vd - 1) & 0x100) >> 7)
  375. | ((vs & 0x100) >> 6)
  376. | (((vbs - 1) & 0x100) >> 5)
  377. | ((LineCompare & 0x100) >> 4)
  378. | (((vt - 2) & 0x200) >> 4)
  379. | (((vd - 1) & 0x200) >> 3)
  380. | ((vs & 0x200) >> 2);
  381. cr[0x30] = ((vt - 2) & 0x400) >> 7
  382. | (((vd - 1) & 0x400) >> 8)
  383. | (((vbs - 1) & 0x400) >> 9)
  384. | ((vs & 0x400) >> 10)
  385. | (interlaced) ? 0x80 : 0;
  386. cr[0x08] = 0x00;
  387. cr[0x09] = (dblscan << 7)
  388. | ((LineCompare & 0x200) >> 3)
  389. | (((vbs - 1) & 0x200) >> 4)
  390. | (TextScanLines - 1);
  391. cr[0x10] = vs & 0xff; /* VSyncPulseStart */
  392. cr[0x11] = (ve & 0x0f);
  393. cr[0x12] = (vd - 1) & 0xff; /* LineCount */
  394. cr[0x13] = wd & 0xff;
  395. cr[0x14] = 0x40;
  396. cr[0x15] = (vbs - 1) & 0xff;
  397. cr[0x16] = vbe & 0xff;
  398. cr[0x17] = 0xe3; /* but it does not work */
  399. cr[0x18] = 0xff & LineCompare;
  400. cr[0x22] = 0x00; /* todo? */
  401. /* now set the registers */
  402. for (i = 0; i <= 0x18; i++) { /*CR00 .. CR18 */
  403. smiWrite (SMI_INDX_D4, i, cr[i]);
  404. }
  405. i = 0x22; /*CR22 */
  406. smiWrite (SMI_INDX_D4, i, cr[i]);
  407. i = 0x30; /*CR30 */
  408. smiWrite (SMI_INDX_D4, i, cr[i]);
  409. }
  410. /*****************************************************************************/
  411. #define REF_FREQ 14318180
  412. #define PMIN 1
  413. #define PMAX 255
  414. #define QMIN 1
  415. #define QMAX 63
  416. static unsigned int FindPQ (unsigned int freq, unsigned int *pp, unsigned int *pq)
  417. {
  418. unsigned int n = QMIN, m = 0;
  419. long long int L = 0, P = freq, Q = REF_FREQ, H = P >> 1;
  420. long long int D = 0x7ffffffffffffffLL;
  421. for (n = QMIN; n <= QMAX; n++) {
  422. m = PMIN; /* p/q ~ freq/ref -> p*ref-freq*q ~ 0 */
  423. L = P * n - m * Q;
  424. while (L > 0 && m < PMAX) {
  425. L -= REF_FREQ; /* difference is greater as 0 subtract fref */
  426. m++; /* and increment m */
  427. }
  428. /* difference is less or equal than 0 or m > maximum */
  429. if (m > PMAX)
  430. break; /* no solution: if we increase n we get the same situation */
  431. /* L is <= 0 now */
  432. if (-L > H && m > PMIN) { /* if difference > the half fref */
  433. L += REF_FREQ; /* we take the situation before */
  434. m--; /* because its closer to 0 */
  435. }
  436. L = (L < 0) ? -L : +L; /* absolute value */
  437. if (D < L) /* if last difference was better take next n */
  438. continue;
  439. D = L;
  440. *pp = m;
  441. *pq = n; /* keep improved data */
  442. if (D == 0)
  443. break; /* best result we can get */
  444. }
  445. return (unsigned int) (0xffffffff & D);
  446. }
  447. /*****************************************************************************/
  448. static void smiLoadCcr (struct ctfb_res_modes *var, unsigned short device_id)
  449. {
  450. unsigned int p = 0;
  451. unsigned int q = 0;
  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 = CONFIG_SYS_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 ", CONFIG_SYS_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 = CONFIG_SYS_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. }