home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer) / NeXT_Developer-3.3.iso / NextDeveloper / Examples / DriverKit / ATI / ATI_reloc.tproj / ATI.m < prev    next >
Encoding:
Text File  |  1994-08-18  |  21.5 KB  |  756 lines

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