home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Examples / DriverKit / ATI / ATI_reloc.tproj / ATI.m < prev    next >
Text File  |  1993-08-30  |  20KB  |  705 lines

  1. /* Copyright (c) 1992, 1993 NeXT Computer, Inc.  All rights reserved. 
  2.  *
  3.  * ATI.m - ATI display driver.
  4.  *
  5.  * HISTORY
  6.  * 07 Oct 92    Joe Pasqua
  7.  *      Created. 
  8.  * 01 June 93    Mike Paquette
  9.  *    Rewrite: Convert from Corsair device driver to general MACH32 chipset
  10.  *         driver. Add support for multiple DACs and CRT setups.
  11.  *        Add 8 bit monochrome support.  Add support for non-Cosair
  12.  *        implementations.
  13.  *  7 July 1993    Derek B Clegg
  14.  *    Cleaned up for external release.
  15.  */
  16.  
  17. #import <driverkit/generalFuncs.h>
  18. #import <driverkit/i386/ioPorts.h>
  19. #import <driverkit/i386/directDevice.h>
  20. #import <driverkit/i386/IOEISADeviceDescription.h>
  21. #import "ATI.h"
  22.  
  23. #define    ONE_MEG    (1024 * 1024)
  24.  
  25. @implementation ATI
  26.  
  27. static void
  28. UnlockShadowSet(int set)
  29. {
  30.     outb(SHADOW_SET, 2);
  31.     outb(SHADOW_CNTL, 0);
  32.     outb(SHADOW_SET, 1);
  33.     outb(SHADOW_CNTL, 0);
  34.     outb(SHADOW_SET, set);
  35. }
  36.  
  37. static void
  38. LockShadowSet(void)
  39. {
  40.     outb(SHADOW_SET, 1);
  41.     outb(SHADOW_CNTL, 0x3F);
  42.     outb(SHADOW_SET, 2);
  43.     outb(SHADOW_CNTL, 0x3F);
  44.     outb(SHADOW_SET, 0);
  45. }
  46.  
  47. static void
  48. ProgramShadowSet(int set, const ATI_CRTCSetup *setup)
  49. {
  50.     UnlockShadowSet(set);
  51.     
  52.     outb(DISP_CNTL, 0x53);        /* Reset, blanking display. */
  53.     outb(H_TOTAL, setup->h_total);
  54.     outb(H_DISP, setup->h_disp);
  55.     outb(H_SYNC_START, setup->h_sync_start);
  56.     outb(H_SYNC_WIDTH, setup->h_sync_wid);
  57.     outw(V_TOTAL, setup->v_total);
  58.     outw(V_DISP, setup->v_disp);
  59.     outw(V_SYNC_START, setup->v_sync_start);
  60.     outb(V_SYNC_WID, setup->v_sync_wid);
  61.     outb(DISP_CNTL, setup->disp_cntl);
  62.     outw(CLOCK_SELECT, setup->clock_select);
  63.  
  64.     /* Zero overscan registers to avoid weird borders. */
  65.     outw(HORIZONTAL_OVERSCAN, 0);
  66.     outw(VERTICAL_OVERSCAN, 0);
  67.     outb(OVERSCAN_COLOR_BLUE, 0);
  68.     outb(OVERSCAN_COLOR_GREEN, 0);
  69.     outb(OVERSCAN_COLOR_RED, 0);
  70.  
  71.     LockShadowSet();
  72. }
  73.  
  74. static void
  75. SelectShadowSet(int set)
  76. {
  77.     unsigned char v;
  78.  
  79.     switch (set) {
  80.     case 0:
  81.     v = 2;
  82.     break;
  83.     case 1:
  84.     v = 3;
  85.     break;
  86.     case 2:
  87.     v = 7;
  88.     break;
  89.     default:
  90.     return;
  91.     }
  92.     outb(ADVFUNC_CNTL, v);
  93. }
  94.  
  95. static void
  96. SetMemOffset(void)
  97. {
  98.     unsigned int vga_boundary;
  99.     
  100.     /* Get the video memory boundary, in 256K pages.  The 8514 controller
  101.      * cannot access memory below this, and the VGA controller cannot
  102.      * access memory above this. */
  103.     vga_boundary = inb(MEM_BNDRY) & 0x0f;
  104.     
  105.     /* Set the start of the CRT buffer to match the start of the
  106.      * 8514 controller VRAM address.  We also set up the graphics engine... */
  107.     outb(GE_OFFSET_HI, vga_boundary);
  108.     outb(CRT_OFFSET_HI, vga_boundary);
  109.     outb(GE_OFFSET_LO, 0);
  110.     outb(CRT_OFFSET_LO, 0);
  111. }
  112.  
  113. /*
  114.  * Returns the physical base address of the memory aperature.  The method
  115.  * used to decode this varies based on the BIOS and Mach32 chip type.
  116.  */
  117. static unsigned int
  118. MemoryAperatureBaseAddress(void)
  119. {
  120.     unsigned char *ip;
  121.     unsigned int location;    /* Base address in Mbytes */
  122.     
  123.     /*
  124.      * The PC BIOS is broken into 2 Kb slices. On startup, the ATI BIOS
  125.      * stashes away which 2 Kb slice it live in in scratch reg 0.
  126.      */
  127.     ip = (unsigned char *)
  128.         (((inb(ROM_SCRATCH_PAD_0) & 0x7F) * 0x800) + ATI_BIOS_BASEADDR);
  129.  
  130.     /* Look up the BIOS flag to see if it uses extended or simple format */
  131.     if ( (ip[0x62] & 1) != 0 )    /* Corsair/Nova style BIOS */
  132.     {
  133.         /*
  134.          * MEM_CFG+1 specifies an address from 0-127 Mb
  135.          * (MSB is always 0), and the scratch register specifies
  136.          * what the external hardware decodes, up to 4 Gb.
  137.          */
  138.         location =   ((inb(ROM_SCRATCH_PAD_0 + 1) & 0x1F) << 7)
  139.                | (inb(MEM_CFG + 1));
  140.     }
  141.     else    /* No external address decode.  Just use MEM_CFG register */
  142.     {
  143.         if ((inb(CONFIG_STATUS_2 + 1) & MEM_APERATURE_4GB_RANGE) != 0)
  144.             location = inw( MEM_CFG ) >> 4;
  145.         else
  146.             location = inb( MEM_CFG + 1 );
  147.     }
  148. #if DEBUG
  149.     IOLog("MemoryAperatureBaseAddress() == 0x%x\n", location * ONE_MEG);
  150. #endif
  151.     return (location * ONE_MEG); /* Return phys address in bytes, not Mb */
  152. }
  153.  
  154. /*
  155.  * Returns the physical base address of the memory aperature.  The method
  156.  * used to decode this varies based on the BIOS and Mach32 chip type.
  157.  */
  158. static BOOL
  159. SetMemoryAperatureBaseAddress(unsigned int newLocation)
  160. {
  161.     unsigned char *ip;
  162.     unsigned int location;
  163. #if DEBUG
  164.     IOLog("SetMemoryAperatureBaseAddress(0x%x)\n", newLocation );
  165. #endif
  166.     /* Convert location to Mbytes. Make sure it's on a 1 Mb boundry */
  167.     if ( (newLocation & (ONE_MEG - 1)) != 0 )
  168.         return NO;
  169.     location = newLocation / ONE_MEG;
  170.     
  171.     /*
  172.      * The PC BIOS is broken into 2 Kb slices. On startup, the ATI BIOS
  173.      * stashes away which 2 Kb slice it live in in scratch reg 0.
  174.      */
  175.     ip = (unsigned char *)
  176.         (((inb(ROM_SCRATCH_PAD_0) & 0x7F) * 0x800) + ATI_BIOS_BASEADDR);
  177.  
  178.     /* Look up the BIOS flag to see if it uses extended or simple format */
  179.     if ( (ip[0x62] & 1) != 0 )    /* Corsair/Nova style BIOS */
  180.     {
  181.         /*
  182.          * It's never safe to reprogram these, as we don't know
  183.          * how to set the off-chip decoding logic.
  184.          */
  185.          return NO;
  186.     }
  187.     else    /* No external address decode.  Just use MEM_CFG register */
  188.     {
  189.         if ((inb(CONFIG_STATUS_2 + 1) & MEM_APERATURE_4GB_RANGE) != 0)
  190.         {
  191.             outw(MEM_CFG, (location << 4)|(inw( MEM_CFG ) & 0xF));
  192.         }
  193.         else
  194.         {
  195.             if ( newLocation > ATI_LOCALBUS_VRAM_ADDRESS )
  196.                 return NO; /* Invalid addr for this config */
  197.             outb( MEM_CFG + 1, location );
  198.         }
  199.     }
  200. #if DEBUG
  201.     IOLog("SetMemoryAperatureBaseAddress(0x%x) succeeds\n", newLocation );
  202. #endif
  203.     return YES;
  204. }
  205.  
  206. /* Undo our munging of the DAC.  Put DAC back in a state usable by VGA mode.
  207.  */
  208. static void
  209. reset_DAC(void)
  210. {
  211.     ATI_DAC dac_type;
  212.  
  213.     /* Disable VGA passthrough mode so the DAC may be programmed. */
  214.     outw(CLOCK_SELECT, inw(CLOCK_SELECT) | 1);
  215.  
  216.     dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
  217.     switch(dac_type) {
  218.     case ATI_DAC_ATT20C491:        /* ATT 20C491 */
  219.     case ATI_DAC_Bt481:            /* Brooktree Bt481, Bt482 */
  220.     /* TO DO: Not tested yet */
  221.     outw(EXT_GE_CONFIG, 0x101A);    /* DAC reg 1. */
  222.     outb(DAC_MASK, 0);        /* VGA mode. */
  223.     break;
  224.  
  225.     case ATI_DAC_68875:            /* ATI or TI 34075. */
  226.     outw(EXT_GE_CONFIG, 0x201A);    /* DAC reg 1. */
  227.     outb(INPUT_CLK_SEL, 0);        /* clock 0. */
  228.     outb(OUTPUT_CLK_SEL, 0);    /* SCLK & VCLK 1. */
  229.     outb(MUX_CNTL, 0x2D);        /* MUX CNTL to 8/16. */
  230.  
  231.     /* Set default 8 BPP delay and blank adjust. */
  232.     outw(LOCAL_CNTL, (inw(LOCAL_CNTL) | 0x8));
  233.     /* Set PIXEL DELAY = 3, BLANK ADJ = 0    (0xC). */
  234.     outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xF0) | 0xC);
  235.     /* Set horizontal skew. */
  236.     outw(HORIZONTAL_OVERSCAN, 1);
  237.     break;
  238.  
  239.     case ATI_DAC_68830:            /* ATI 68830*/
  240.     default:
  241.     /* Set PIXEL DELAY = 0, BLANK ADJ = 0. */
  242.     outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xF0) | 0);
  243.     /* Set horizontal skew. */
  244.     outw(HORIZONTAL_OVERSCAN, 0);
  245.     break;
  246.     }
  247.  
  248.     /* Put DAC in 6 bit mode, engine in 8 bit mode. */
  249.     outw(EXT_GE_CONFIG, 0x001A);    /* reset EXT_DAC_ADDR */
  250.     /* Enable VGA passthrough mode. */
  251.     outw(CLOCK_SELECT, inw(CLOCK_SELECT) & ~1);
  252. }
  253.  
  254. static void
  255. program_TI34075(const ATI_DACSetup *parm, const IODisplayInfo *displayMode)
  256. {
  257.     ATI_CRTCSetup *setup;
  258.  
  259.     /* DAC RS 3 active, 8 bit pixel width. */
  260.     outw(EXT_GE_CONFIG, 0x201A);
  261.     outb(OUTPUT_CLK_SEL, parm->out_clk);
  262.     outb(MUX_CNTL, parm->mux);
  263.     outb(INPUT_CLK_SEL, parm->in_clk);
  264.     outw(EXT_GE_CONFIG, parm->GE_config);
  265.     outb(DAC_MASK, parm->mask);
  266.  
  267.     /* Set blank adjust and pixel delay values per parm->delay_timing. */
  268.     outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xf0) | parm->delay_timing);
  269.  
  270.     setup = (ATI_CRTCSetup *)displayMode->parameters;
  271.     if (setup->mux_flag == 0)
  272.     return;
  273.  
  274.     /* Set PIXEL DELAY = 0, BLANK ADJ = 1. */
  275.     outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xF0) | 1);
  276.  
  277.     UnlockShadowSet(2);
  278.     outw(CLOCK_SELECT, setup->clock_select);
  279.     LockShadowSet();
  280.     SelectShadowSet(2);
  281. }
  282.  
  283. static void
  284. program_ATI68830(const ATI_DACSetup *parm, const IODisplayInfo *displayMode)
  285. {
  286.     /* Set pixel depth, packing, aliased monitor ID of 2. */
  287.     outw(EXT_GE_CONFIG, parm->GE_config & 0x0fff);
  288. }
  289.  
  290. /* Brooktree Bt481, Bt482 or ATT 20C491 RAMDAC setup code.
  291.  * On entry, the CRT controller is programmed, and VGA passthru is disabled.
  292.  * TO DO:  Test with ATT 20C491.
  293.  */
  294. static void
  295. program_Bt481(const ATI_DACSetup *parm, const IODisplayInfo *displayMode)
  296. {
  297.     /* The clock should already be set appropriately for a 'slow', or
  298.      * double-clocked DAC on entry. */
  299.  
  300.     /* Activate the TrueColor mode in the DAC. */
  301.  
  302.     /* DAC RS 2 active, 8 bit pixel width. */
  303.     outw(EXT_GE_CONFIG, 0x101A);
  304.  
  305.     /* Set reg 6 to correct mode. */
  306.     outb(DAC_MASK, parm->mode);
  307.     
  308.     /* Set blank adjust and pixel delay values. */
  309.     outb(MISC_CNTL + 1, (inb(R_MISC_CNTL + 1) & 0xf0) | parm->delay_timing);
  310.  
  311.     /* Set pixel depth, packing, aliased monitor ID of 2. */
  312.     outw(EXT_GE_CONFIG, parm->GE_config & 0x0fff);
  313.  
  314.     /* Set the appropriate DAC pixel mask. */
  315.     outb(DAC_MASK, parm->mask);
  316. }
  317.  
  318. /* Set up a simple gamma corrected grayscale. We rely on the Window Server
  319.  * invoking this function once via IO_SET_TRANSFER_TABLE during startup.
  320.  */
  321. static void
  322. ATISetTransferTable(const unsigned int *table)
  323. {
  324.     ATI_DAC dac_type;
  325.     int g, val;
  326.     unsigned int scale;
  327.  
  328.     dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
  329.  
  330.     switch (dac_type) {
  331.     case ATI_DAC_68875:        /* ATI or TI 34075 */
  332.     case ATI_DAC_68830:        /* ATI 68830*/
  333.     case ATI_DAC_Bt476:
  334.     scale = 0;
  335.     break;
  336.     case ATI_DAC_ATT20C491:    /* ATT 20C491 */
  337.     case ATI_DAC_Bt481:        /* Brooktree Bt481, Bt482 */
  338.     default:
  339.     scale = 2;
  340.     break;
  341.     }
  342.  
  343.     outb(DAC_W_INDEX, 0);
  344.  
  345.     for (g = 0; g < IO_8BPP_TRANSFER_TABLE_SIZE; g++) {
  346.     val = (table[g] & 0x000000FF);
  347.     if (scale)
  348.         val >>= scale;
  349.     outb(DAC_DATA, val);
  350.     outb(DAC_DATA, val);
  351.     outb(DAC_DATA, val);
  352.     }
  353. }
  354.  
  355. - (void)setupHardware
  356. {
  357.     ATI_DAC dac_type;
  358.     const ATI_DACSetup *parm;
  359.  
  360.     SetMemOffset();    /* Set VGA VRAM memory offset. */
  361.  
  362.     dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
  363.  
  364.     /* Load a register shadow set with our desired setup. */
  365.  
  366.     /* Load CRT regs, and enable controller in appropriate mode, unblanking
  367.      * the display in the process. */
  368.     ProgramShadowSet(2, CRTControllerSetup);
  369.  
  370.     /* Select our setup, re-enabling the CRT controller. */
  371.     SelectShadowSet(2);
  372.  
  373.     /* At this point, the CRT timing is set, VGA passthrough is disabled,
  374.      * and the pixel clock is set.  We need to place the DAC in the correct
  375.      * mode of operation. */
  376.  
  377.     if (displayMode->bitsPerPixel == IO_15BitsPerPixel) 
  378.     parm = &ATI_DAC_Setup_15BPP;
  379.     else
  380.     parm = &ATI_DAC_Setup_8BPP;
  381.  
  382.     switch (dac_type) {
  383.     case ATI_DAC_68830:        /* ATI 68830*/
  384.     program_ATI68830(parm, displayMode);
  385.     outw(HORZ_OVERSCAN, 1);
  386.     break;
  387.  
  388.     case ATI_DAC_ATT20C491:    /* ATT 20C491 */
  389.     case ATI_DAC_Bt481:        /* Brooktree Bt481, Bt482 */
  390.     program_Bt481(parm, displayMode);
  391.     break;
  392.  
  393.     case ATI_DAC_68875:        /* ATI or TI 34075 */
  394.     program_TI34075(parm, displayMode);
  395.     break;
  396.  
  397.     default:
  398.     /* Bt476 or some other unusable part. */
  399.     IOLog("%s: Unknown DAC on ATI board - ID:%d\n", [self name], dac_type);
  400.     break;
  401.     }
  402.  
  403.     /* Set the CRT pitch, in units of (pixels_per_line/8).
  404.      * CAUTION: Writing ADVFUNC_CNTL or MEM_CNTL (0xbee8) resets
  405.      * this to 1024 pixels/line. */
  406.     outb(CRT_LINE_PITCH, CRTControllerSetup->xres >> 3);
  407.  
  408.     /* Also set the graphics engine... */
  409.     outb(GE_PITCH, CRTControllerSetup->xres >> 3);
  410. }
  411.  
  412. - (vm_offset_t)prepareMemoryAperture
  413. {
  414.     unsigned int physLoc;
  415.     vm_offset_t virtLoc;
  416.     vm_size_t length, needed_length;
  417.     ATI_DAC dac_type;
  418.     int mode, k;
  419.     BOOL valid[ATIModeCount];
  420.     BOOL slowDAC = NO;
  421.     IORange *range;
  422.     const IODisplayInfo *displayTable;
  423.     int    numTableEntries;
  424.     const IODisplayInfo *displayDefault;
  425.     
  426.     /* Set memory boundary to share. */
  427.     outb(MEM_BNDRY, 0);                                      
  428.     /* Enable memory aperture with a 4 Mb width, page sel for page 0. */
  429.     outb(MEM_CFG, (inb(MEM_CFG) & 0xf0) | 0x02);
  430.  
  431.     /* Get memory aperture location (units in Mbyte).  This is hardware
  432.      * and version dependent.  The high 8 bits of MEM_CFG specify the
  433.      * memory aperature location between 0 and 127Mb, in 1 Mb units.
  434.      */
  435.     range = [[self deviceDescription] memoryRangeList];
  436.     if (range == NULL) {
  437.     IOLog("%s: No memory range set.\n", [self name]);
  438.     return 0;
  439.     }
  440.  
  441.     physLoc = 0;    /* Default to Configure app settings. */
  442.  
  443.     /* Use the Misc Options register (36EE) bits 2&3 to determine
  444.      * the amount of installed memory. 0 = 512, 1 = 1M, 2 = 2M, 3 = 4M.
  445.      * Select a timing setup based on available memory and DACs.
  446.      * We do this here instead of in goLinear so we can report the
  447.      * potential frame buffer size early in the startup sequence.
  448.      */
  449.     dac_type = (inb(CONFIG_STATUS_1 + 1) >> 1) & 7;
  450.  
  451.     switch (dac_type) {
  452.     case ATI_DAC_68830:        /* ATI 68830*/
  453.     case ATI_DAC_68875:        /* ATI or TI 34075 */
  454.     slowDAC = NO;
  455.     break;
  456.     case ATI_DAC_ATT20C491:    /* ATT 20C491 */
  457.     case ATI_DAC_Bt476:        /* Brooktree Bt476, Bt478 */
  458.     case ATI_DAC_Bt481:        /* Brooktree Bt481, Bt482 */
  459.     default:
  460.     /* These DACs can't handle the clock rates at 1024x768. */
  461.     slowDAC = YES;
  462.     break;
  463.     }
  464.  
  465.     switch ((inb(MISC_OPTIONS) & 0x0c) >> 2) {
  466.     default:
  467.     case 0:                /* 512 Kb VRAM. */
  468.     return (vm_offset_t)0;
  469.     case 1:                /* 1 Mb VRAM. */
  470.     length = ONE_MEG;
  471.     break;
  472.     case 2:                /* 2 Mb VRAM. */
  473.     case 3:                /* 4 Mb VRAM. */
  474.     length = 2 * ONE_MEG;        /* The most we currently need. */
  475.     break;
  476.     }
  477.     
  478.     switch (ati_flavor) {
  479.     case ATI_EISA_Card:        /* Definitely programmable address. */
  480.     case ATILocalBusCard:    /* Usually a programmable address. */
  481.     /* Read out the full address using the mechanism endorsed by
  482.      * ATI.  This mechanism is supported by ATI in their Windows
  483.      * driver, and every vendor we've tested follows it rather than
  484.      * rolling their own drivers.
  485.      */
  486.     physLoc = MemoryAperatureBaseAddress();
  487.  
  488.     /* If the address is in a range supported by the Mach32
  489.      * chipset (below 128 Mb), try to program it. Otherwise,
  490.      * we'll assume the address is hardwired, and pick it up
  491.      * using the ATI endorsed addressing mechanism. */
  492.     if ( physLoc != range->start )
  493.         SetMemoryAperatureBaseAddress( range->start );
  494.     /* FALL THRU */
  495.  
  496.     default:            /* Unknown device. */
  497.     case ATI_NovaCard:        /* Not programmable in prototypes tested. */
  498.     case ATICorsair:        /* Not programmable. */
  499.     /* Read out the full address using the mechanism endorsed by
  500.      * ATI.  This mechanism is supported by ATI in their Windows
  501.      * driver, and every vendor we've tested follows it rather than
  502.      * rolling their own drivers.
  503.      */
  504.     physLoc = MemoryAperatureBaseAddress();
  505.  
  506.     /* If the address doesn't match the one set in Configure, complain.
  507.      * We then override the Configure address with the address reported
  508.      * by the hardware.  This gives the driver a fighting chance of
  509.      * working correctly, and works around a bug in 3.1 Configure and
  510.      * DriverKit which prevents setting addresses in the high 2 Gb of
  511.      * address space.
  512.      */
  513.     if (range->start != physLoc || range->size < length) {
  514.         IOLog("%s: FB addr decodes as 0x%x, overriding configured "
  515.           "addr 0x%x.\n", [self name], physLoc, range->start);
  516.  
  517.         /* Force the range to match the hardware config,
  518.          * so the Window Server will work correctly. */
  519.         range->start = physLoc;
  520.         range->size = length;
  521.         /* Reprogram the device description with usable values. */
  522.         [[self deviceDescription] setMemoryRangeList:range
  523.          num:[[self deviceDescription] numMemoryRanges]];
  524.     }
  525.     break;
  526.     }
  527.      
  528.     /* Enable kernel access with the appropriate mapping. */
  529.  
  530.     virtLoc = [self mapFrameBufferAtPhysicalAddress:physLoc length:length];
  531.     if (virtLoc == 0)
  532.         return virtLoc;
  533.  
  534.     /* If the DAC is a slow double-clocked part (ATT20C491, Bt481) use
  535.      * the special setup for the part. */
  536.  
  537.     if (slowDAC == YES) {
  538.         displayTable = ATISlowDACMode;
  539.     numTableEntries = ATISlowDACModeCount;
  540.     displayDefault = &ATISlowDACMode[ATI_DEFAULT_SlowDAC_MODE];
  541.     } else {
  542.         displayTable = ATIMode;
  543.     numTableEntries = ATIModeCount;
  544.     displayDefault = (length > ONE_MEG) ? &ATIMode[ATI_DEFAULT_2MEG_MODE]
  545.                         : &ATIMode[ATI_DEFAULT_1MEG_MODE];
  546.     }
  547.  
  548.     /* Determine which entries are valid for the amount of memory in the
  549.      * system. */
  550.  
  551.     for (k = 0; k < numTableEntries; k++) {
  552.         needed_length = displayTable[k].width * displayTable[k].height;
  553.     if (displayTable[k].bitsPerPixel != IO_8BitsPerPixel)
  554.         needed_length *= sizeof(short);
  555.     valid[k] = (needed_length <= length);
  556.     /* The 68830 DAC can't handle higher res than 1024x768. */
  557.     if ( dac_type == ATI_DAC_68830 && displayTable[k].width > 1024 )
  558.         valid[k] = NO;
  559.     }
  560.  
  561.     /* Look up the correct entry to use. */
  562.     mode = [self selectMode:displayTable count:numTableEntries valid:valid];
  563.     if (mode < 0)
  564.     displayMode = displayDefault;
  565.     else
  566.     displayMode = &displayTable[mode];
  567.     CRTControllerSetup = (ATI_CRTCSetup *)displayMode->parameters;  
  568.     return virtLoc;
  569. }
  570.  
  571. - (void)establishLinearFB
  572.     /* Local Bus timing magic */
  573.     if ( inw( MACH32_STEP6_ID_REG ) != MACH32_STEP6_ID_VALUE )
  574.     {
  575.     asm volatile(
  576.              "pushl    %eax;        \n"
  577.              "pushl    %edx;        \n"
  578.              ";                \n"
  579.              "movl    0x01CE, %edx;    \n"
  580.              "movl    0xAE,    %eax;    \n"
  581.              "outb    %al,    %dx;    \n"
  582.              "incl    %edx;        \n"
  583.              "inb    %dx,    %al;    \n"
  584.              "andb    $ ~0x10, %al;    \n"
  585.              "movb    %al,    %ah;    \n"
  586.              "movb    $0xAE,    %al;    \n"
  587.              "decl    %edx;        \n"
  588.              "outw    %ax,    %dx;    \n"
  589.              ";                \n"
  590.              "movl    $0x2185,%eax;    \n"
  591.              "outw    %ax,%dx;    \n"
  592.              ";                \n"
  593.              "movl    $0x01CE, %edx;    \n"
  594.              "movl    $0xAE,    %eax;    \n"
  595.              "outb    %al,    %dx;    \n"
  596.              "incl    %edx;        \n"
  597.              "inb    %dx,    %al;    \n"
  598.              "orb    $ 0x10, %al;    \n"
  599.              "movb    %al,    %ah;    \n"
  600.              "movl    $0xAE,  %al;    \n"
  601.              "decl    %edx;        \n"
  602.              "outw    %ax,    %dx;    \n"
  603.              ";                \n"
  604.              "popl    %edx;        \n"
  605.              "popl    %eax;        \n");
  606.     };
  607.  
  608.     /* Program controller to 16bpp or 8bpp mode. */
  609.     [self setupHardware];
  610. }
  611.  
  612. /* Determine whether there is an ATi chipset present.
  613.  *   1) Check for an EISA card.  If found, we're done.
  614.  *   2) Check for EISA CPU board ID.  If it's a Corsair, we're done.
  615.  *   3) Fallback: assume a localbus+ISA card. (No ID mechanism!)
  616.  */
  617. - (boolean_t)ATIPresent
  618. {
  619.     int slot;
  620.     unsigned int product_id;
  621.     
  622.     /* First, scan for a board in an EISA slot. */
  623.     if ([self isEISAPresent] == TRUE) {
  624.     for (slot = 1; slot < 16; slot++) {
  625.         if ([self getEISAId:&product_id forSlot:slot] == TRUE) {
  626.             switch (product_id & ~0x0f) {
  627.         case ATI_EISA_ID:
  628.             ati_flavor = ATI_EISA_Card;
  629.             return TRUE;
  630.         case ATI_NOVA_PBUS_EISA_ID:
  631.             ati_flavor = ATI_NovaCard;
  632.             return TRUE;
  633.         }
  634.         }
  635.     }
  636.  
  637.     /* Examine the EISA ID for the motherboard, found in 'slot 0'.
  638.      * Do this AFTER the slot scan, so we preferentially use boards
  639.      * in the EISA slots.
  640.      */
  641.     if ([self getEISAId:&product_id forSlot:0] == TRUE 
  642.         && (product_id & ~0x0f) == INTEL_CORSAIR_ID) {
  643.         ati_flavor = ATICorsair;
  644.         return TRUE;
  645.     }
  646.     }
  647.  
  648.     IOLog("%s: Assuming a local bus ATI card.\n", [self name]);
  649.     ati_flavor = ATILocalBusCard;
  650.     return TRUE;
  651. }
  652.  
  653. - (void)enterLinearMode
  654. {
  655.     [self establishLinearFB];
  656. }
  657.  
  658. - initFromDeviceDescription:deviceDescription
  659. {
  660.     void *frameBuffer;
  661.     IODisplayInfo *display;
  662.     
  663.     if ([super initFromDeviceDescription:deviceDescription] == nil)
  664.     return [super free];
  665.  
  666.     if (![self ATIPresent])
  667.     return [super free];
  668.  
  669.     display = [self displayInfo];
  670.     frameBuffer = (void *)[self prepareMemoryAperture];
  671.     if (frameBuffer == 0)
  672.         return nil;
  673.     *display = *displayMode;
  674.     display->frameBuffer = frameBuffer;
  675.     display->flags = IO_DISPLAY_CACHE_WRITETHROUGH;
  676.     if (displayMode->bitsPerPixel == IO_15BitsPerPixel) {
  677.     display->flags |=  IO_DISPLAY_NEEDS_SOFTWARE_GAMMA_CORRECTION;
  678.     } else if (displayMode->bitsPerPixel == IO_8BitsPerPixel) {
  679.         display->flags |= IO_DISPLAY_HAS_TRANSFER_TABLE;
  680.     }
  681.     return self;
  682. }
  683.  
  684. - free
  685. {
  686.     return [super free];
  687. }
  688.  
  689. - (void)revertToVGAMode
  690. {
  691.     /* Select VGA setup, re-enabling the VGA CRT controller. */
  692.     SelectShadowSet(0);        /* Select VGA CRT configuration. */
  693.     reset_DAC();        /* Restore DAC for VGA operation. */
  694.     [super revertToVGAMode];    /* Let superclass do generic VGA stuff. */
  695. }
  696.  
  697. - setTransferTable:(const unsigned int *)table count:(int)count
  698. {
  699.     if (displayMode->bitsPerPixel == IO_8BitsPerPixel)
  700.     ATISetTransferTable(table);
  701.     return self;
  702. }
  703. @end
  704.