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