i386/67760: [PATCH] Getting AGP/DRM working for VIA KT600 (MSI 7021) motherboard + ATI Radeon 9200 SE video card

Martin Birgmeier martin at gandalf.xyzzy
Wed Jun 9 17:50:41 GMT 2004


>Number:         67760
>Category:       i386
>Synopsis:       [PATCH] Getting AGP/DRM working for VIA KT600 (MSI 7021) motherboard + ATI Radeon 9200 SE video card
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-i386
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jun 09 17:50:18 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Martin Birgmeier
>Release:        RELENG_4_10_0_RELEASE (4.10)
>Organization:
MBi at home
>Environment:
n.a.
>Description:
This patch gets AGP working for the VIA KT600 chipset as used on the MSI 7021 motherboard. Together with XFree86 4.4.0, this enables the use of DRM (hardware accelerated video) on a combination of this motherboard plus an ATI Radeon 9200 SE el cheapo graphics card.

The patch is mostly just a merge from HEAD, plus the addition of the 0x31891106 PCI identifier in agp_via.c.

Note: Linux seems to have a more generic solution here: They are looking at some bit in some PCI conf. register to determine which set of register offsets to use for AGP control.

Note 2: FreeBSD's code in agp_via.c is not very pretty - in relies on correct ordering of #defines together with array initializations. The proper way to do this would be to define something like

struct regs {
    int reg_gartctrl, reg_apsize, reg_attbase;
};

and use this instead.

Regards,

Martin

>How-To-Repeat:

>Fix:
*** sys/pci/agp_via.c.ORIG      Sun Aug 24 08:16:53 2003
--- sys/pci/agp_via.c   Wed Jun  9 18:59:38 2004
***************
*** 45,56 ****
--- 45,66 ----
  #include <vm/vm_object.h>
  #include <vm/pmap.h>
  
+ #define       REG_GARTCTRL    0
+ #define       REG_APSIZE      1
+ #define       REG_ATTBASE     2
+ 
  struct agp_via_softc {
        struct agp_softc agp;
        u_int32_t       initial_aperture; /* aperture size at startup */
        struct agp_gatt *gatt;
+       int             *regs;
  };
  
+ static int via_v2_regs[] = { AGP_VIA_GARTCTRL, AGP_VIA_APSIZE,
+     AGP_VIA_ATTBASE };
+ static int via_v3_regs[] = { AGP3_VIA_GARTCTRL, AGP3_VIA_APSIZE,
+     AGP3_VIA_ATTBASE };
+ 
  static const char*
  agp_via_match(device_t dev)
  {
***************
*** 74,79 ****
--- 84,93 ----
                return ("VIA 82C694X (Apollo Pro 133A) host to PCI bridge");
        case 0x06911106:
                return ("VIA 82C691 (Apollo Pro) host to PCI bridge");
+       case 0x31881106:
+               return ("VIA 8385 host to PCI bridge");
+       case 0x31891106:
+               return ("VT8377 [KT400/KT600 AGP] Host Bridge");
        };
  
        if (pci_get_vendor(dev) == 0x1106)
***************
*** 104,109 ****
--- 118,133 ----
        struct agp_gatt *gatt;
        int error;
  
+       switch (pci_get_devid(dev)) {
+       case 0x31881106:
+       case 0x31891106:
+               sc->regs = via_v3_regs;
+               break;
+       default:
+               sc->regs = via_v2_regs;
+               break;
+       }
+ 
        error = agp_generic_attach(dev);
        if (error)
                return error;
***************
*** 127,136 ****
        sc->gatt = gatt;
  
        /* Install the gatt. */
!       pci_write_config(dev, AGP_VIA_ATTBASE, gatt->ag_physical | 3, 4);
  
        /* Enable the aperture. */
!       pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
  
        return 0;
  }
--- 151,160 ----
        sc->gatt = gatt;
  
        /* Install the gatt. */
!       pci_write_config(dev, sc->regs[REG_ATTBASE], gatt->ag_physical | 3, 4);
  
        /* Enable the aperture. */
!       pci_write_config(dev, sc->regs[REG_GARTCTRL], 0x0f, 4);
  
        return 0;
  }
***************
*** 145,152 ****
        if (error)
                return error;
  
!       pci_write_config(dev, AGP_VIA_GARTCTRL, 0, 4);
!       pci_write_config(dev, AGP_VIA_ATTBASE, 0, 4);
        AGP_SET_APERTURE(dev, sc->initial_aperture);
        agp_free_gatt(sc->gatt);
  
--- 169,176 ----
        if (error)
                return error;
  
!       pci_write_config(dev, sc->regs[REG_GARTCTRL], 0, 4);
!       pci_write_config(dev, sc->regs[REG_ATTBASE], 0, 4);
        AGP_SET_APERTURE(dev, sc->initial_aperture);
        agp_free_gatt(sc->gatt);
  
***************
*** 156,164 ****
  static u_int32_t
  agp_via_get_aperture(device_t dev)
  {
        u_int32_t apsize;
  
!       apsize = pci_read_config(dev, AGP_VIA_APSIZE, 1) & 0x1f;
  
        /*
         * The size is determined by the number of low bits of
--- 180,189 ----
  static u_int32_t
  agp_via_get_aperture(device_t dev)
  {
+       struct agp_via_softc *sc = device_get_softc(dev);
        u_int32_t apsize;
  
!       apsize = pci_read_config(dev, sc->regs[REG_APSIZE], 1) & 0x1f;
  
        /*
         * The size is determined by the number of low bits of
***************
*** 173,178 ****
--- 198,204 ----
  static int
  agp_via_set_aperture(device_t dev, u_int32_t aperture)
  {
+       struct agp_via_softc *sc = device_get_softc(dev);
        u_int32_t apsize;
  
        /*
***************
*** 186,192 ****
        if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
                return EINVAL;
  
!       pci_write_config(dev, AGP_VIA_APSIZE, apsize, 1);
  
        return 0;
  }
--- 212,218 ----
        if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
                return EINVAL;
  
!       pci_write_config(dev, sc->regs[REG_APSIZE], apsize, 1);
  
        return 0;
  }
***************
*** 218,225 ****
  static void
  agp_via_flush_tlb(device_t dev)
  {
!       pci_write_config(dev, AGP_VIA_GARTCTRL, 0x8f, 4);
!       pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
  }
  
  static device_method_t agp_via_methods[] = {
--- 244,253 ----
  static void
  agp_via_flush_tlb(device_t dev)
  {
!       struct agp_via_softc *sc = device_get_softc(dev);
! 
!       pci_write_config(dev, sc->regs[REG_GARTCTRL], 0x8f, 4);
!       pci_write_config(dev, sc->regs[REG_GARTCTRL], 0x0f, 4);
  }
  
  static device_method_t agp_via_methods[] = {
*** sys/pci/agp.c.ORIG  Sun Aug 11 21:58:12 2002
--- sys/pci/agp.c       Wed Jun  9 18:34:56 2004
***************
*** 174,179 ****
--- 174,184 ----
                              "allocating GATT for aperture of size %dM\n",
                              apsize / (1024*1024));
  
+       if (entries == 0) {
+               device_printf(dev, "bad aperture size\n");
+               return NULL;
+       }
+ 
        gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
        if (!gatt)
                return 0;
***************
*** 276,293 ****
        return 0;
  }
  
! int
! agp_generic_enable(device_t dev, u_int32_t mode)
  {
-       device_t mdev = agp_find_display();
        u_int32_t tstatus, mstatus;
        u_int32_t command;
!       int rq, sba, fw, rate;;
  
!       if (!mdev) {
!               AGP_DPF("can't find display\n");
!               return ENXIO;
!       }
  
        tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
        mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
--- 281,363 ----
        return 0;
  }
  
! /*
!  * This does the enable logic for v3, with the same topology
!  * restrictions as in place for v2 -- one bus, one device on the bus.
!  */
! static int
! agp_v3_enable(device_t dev, device_t mdev, u_int32_t mode)
  {
        u_int32_t tstatus, mstatus;
        u_int32_t command;
!       int rq, sba, fw, rate, arqsz, cal;
  
!       tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
!       mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
! 
!       /* Set RQ to the min of mode, tstatus and mstatus */
!       rq = AGP_MODE_GET_RQ(mode);
!       if (AGP_MODE_GET_RQ(tstatus) < rq)
!               rq = AGP_MODE_GET_RQ(tstatus);
!       if (AGP_MODE_GET_RQ(mstatus) < rq)
!               rq = AGP_MODE_GET_RQ(mstatus);
! 
!       /*
!        * ARQSZ - Set the value to the maximum one.
!        * Don't allow the mode register to override values.
!        */
!       arqsz = AGP_MODE_GET_ARQSZ(mode);
!       if (AGP_MODE_GET_ARQSZ(tstatus) > rq)
!               rq = AGP_MODE_GET_ARQSZ(tstatus);
!       if (AGP_MODE_GET_ARQSZ(mstatus) > rq)
!               rq = AGP_MODE_GET_ARQSZ(mstatus);
! 
!       /* Calibration cycle - don't allow override by mode register */
!       cal = AGP_MODE_GET_CAL(tstatus);
!       if (AGP_MODE_GET_CAL(mstatus) < cal)
!               cal = AGP_MODE_GET_CAL(mstatus);
! 
!       /* SBA must be supported for AGP v3. */
!       sba = 1;
! 
!       /* Set FW if all three support it. */
!       fw = (AGP_MODE_GET_FW(tstatus)
!              & AGP_MODE_GET_FW(mstatus)
!              & AGP_MODE_GET_FW(mode));
! 
!       /* Figure out the max rate */
!       rate = (AGP_MODE_GET_RATE(tstatus)
!               & AGP_MODE_GET_RATE(mstatus)
!               & AGP_MODE_GET_RATE(mode));
!       if (rate & AGP_MODE_V3_RATE_8x)
!               rate = AGP_MODE_V3_RATE_8x;
!       else
!               rate = AGP_MODE_V3_RATE_4x;
!       if (bootverbose)
!               device_printf(dev, "Setting AGP v3 mode %d\n", rate * 4);
! 
!       pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, 0, 4);
! 
!       /* Construct the new mode word and tell the hardware */
!       command = AGP_MODE_SET_RQ(0, rq);
!       command = AGP_MODE_SET_ARQSZ(command, arqsz);
!       command = AGP_MODE_SET_CAL(command, cal);
!       command = AGP_MODE_SET_SBA(command, sba);
!       command = AGP_MODE_SET_FW(command, fw);
!       command = AGP_MODE_SET_RATE(command, rate);
!       command = AGP_MODE_SET_AGP(command, 1);
!       pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
!       pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
! 
!       return 0;
! }
! 
! static int
! agp_v2_enable(device_t dev, device_t mdev, u_int32_t mode)
! {
!       u_int32_t tstatus, mstatus;
!       u_int32_t command;
!       int rq, sba, fw, rate;
  
        tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
        mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
***************
*** 313,324 ****
        rate = (AGP_MODE_GET_RATE(tstatus)
                & AGP_MODE_GET_RATE(mstatus)
                & AGP_MODE_GET_RATE(mode));
!       if (rate & AGP_MODE_RATE_4x)
!               rate = AGP_MODE_RATE_4x;
!       else if (rate & AGP_MODE_RATE_2x)
!               rate = AGP_MODE_RATE_2x;
        else
!               rate = AGP_MODE_RATE_1x;
  
        /* Construct the new mode word and tell the hardware */
        command = AGP_MODE_SET_RQ(0, rq);
--- 383,396 ----
        rate = (AGP_MODE_GET_RATE(tstatus)
                & AGP_MODE_GET_RATE(mstatus)
                & AGP_MODE_GET_RATE(mode));
!       if (rate & AGP_MODE_V2_RATE_4x)
!               rate = AGP_MODE_V2_RATE_4x;
!       else if (rate & AGP_MODE_V2_RATE_2x)
!               rate = AGP_MODE_V2_RATE_2x;
        else
!               rate = AGP_MODE_V2_RATE_1x;
!       if (bootverbose)
!               device_printf(dev, "Setting AGP v2 mode %d\n", rate);
  
        /* Construct the new mode word and tell the hardware */
        command = AGP_MODE_SET_RQ(0, rq);
***************
*** 330,335 ****
--- 402,435 ----
        pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
  
        return 0;
+ }
+ 
+ int
+ agp_generic_enable(device_t dev, u_int32_t mode)
+ {
+       device_t mdev = agp_find_display();
+       u_int32_t tstatus, mstatus;
+ 
+       if (!mdev) {
+               AGP_DPF("can't find display\n");
+               return ENXIO;
+       }
+ 
+       tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
+       mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
+ 
+       /*
+        * Check display and bridge for AGP v3 support.  AGP v3 allows
+        * more variety in topology than v2, e.g. multiple AGP devices
+        * attached to one bridge, or multiple AGP bridges in one
+        * system.  This doesn't attempt to address those situations,
+        * but should work fine for a classic single AGP slot system
+        * with AGP v3.
+        */
+       if (AGP_MODE_GET_MODE_3(tstatus) && AGP_MODE_GET_MODE_3(mstatus))
+               return (agp_v3_enable(dev, mdev, mode));
+       else
+               return (agp_v2_enable(dev, mdev, mode));            
  }
  
  struct agp_memory *
*** sys/pci/agp_ali.c.ORIG      Wed Jul 19 11:48:04 2000
--- sys/pci/agp_ali.c   Wed Jun  9 18:34:56 2004
***************
*** 99,104 ****
--- 99,108 ----
                return error;
  
        sc->initial_aperture = AGP_GET_APERTURE(dev);
+       if (sc->initial_aperture == 0) {
+               device_printf(dev, "bad initial aperture size, disabling\n");
+               return ENXIO;
+       }
  
        for (;;) {
                gatt = agp_alloc_gatt(dev);
*** sys/pci/agpreg.h.ORIG       Thu Jun 19 15:59:27 2003
--- sys/pci/agpreg.h    Wed Jun  9 18:34:56 2004
***************
*** 46,51 ****
--- 46,73 ----
  
  #define AGP_STATUS            0x4
  #define AGP_COMMAND           0x8
+ #define AGP_STATUS_AGP3               0x0008
+ #define AGP_STATUS_RQ_MASK    0xff000000
+ #define AGP_COMMAND_RQ_MASK   0xff000000
+ #define AGP_STATUS_ARQSZ_MASK 0xe000
+ #define AGP_COMMAND_ARQSZ_MASK        0xe000
+ #define AGP_STATUS_CAL_MASK   0x1c00
+ #define AGP_COMMAND_CAL_MASK  0x1c00
+ #define AGP_STATUS_ISOCH      0x10000
+ #define AGP_STATUS_SBA                0x0200
+ #define AGP_STATUS_ITA_COH    0x0100
+ #define AGP_STATUS_GART64     0x0080
+ #define AGP_STATUS_HTRANS     0x0040
+ #define AGP_STATUS_64BIT      0x0020
+ #define AGP_STATUS_FW         0x0010
+ #define AGP_COMMAND_RQ_MASK   0xff000000
+ #define AGP_COMMAND_ARQSZ_MASK        0xe000
+ #define AGP_COMMAND_CAL_MASK  0x1c00
+ #define AGP_COMMAND_SBA               0x0200
+ #define AGP_COMMAND_AGP               0x0100
+ #define AGP_COMMAND_GART64    0x0080
+ #define AGP_COMMAND_64BIT     0x0020
+ #define AGP_COMMAND_FW                0x0010
  
  /*
   * Config offsets for Intel AGP chipsets.
***************
*** 65,75 ****
  #define AGP_INTEL_I8XX_ERRSTS 0xc8
  
  /*
!  * Config offsets for VIA AGP chipsets.
   */
  #define AGP_VIA_GARTCTRL      0x80
  #define AGP_VIA_APSIZE                0x84
  #define AGP_VIA_ATTBASE               0x88
  
  /*
   * Config offsets for SiS AGP chipsets.
--- 87,104 ----
  #define AGP_INTEL_I8XX_ERRSTS 0xc8
  
  /*
!  * Config offsets for VIA AGP 2.x chipsets.
   */
  #define AGP_VIA_GARTCTRL      0x80
  #define AGP_VIA_APSIZE                0x84
  #define AGP_VIA_ATTBASE               0x88
+ 
+ /*
+  * Config offsets for VIA AGP 3.0 chipsets.
+  */
+ #define AGP3_VIA_GARTCTRL        0x90
+ #define AGP3_VIA_APSIZE          0x94
+ #define AGP3_VIA_ATTBASE         0x98
  
  /*
   * Config offsets for SiS AGP chipsets.
*** sys/sys/agpio.h.ORIG        Thu Dec 20 11:36:57 2001
--- sys/sys/agpio.h     Wed Jun  9 18:35:43 2004
***************
*** 39,58 ****
   * Macros to manipulate AGP mode words.
   */
  #define AGP_MODE_GET_RQ(x)            (((x) & 0xff000000U) >> 24)
  #define AGP_MODE_GET_SBA(x)           (((x) & 0x00000200U) >> 9)
  #define AGP_MODE_GET_AGP(x)           (((x) & 0x00000100U) >> 8)
! #define AGP_MODE_GET_4G(x)            (((x) & 0x00000020U) >> 5)
  #define AGP_MODE_GET_FW(x)            (((x) & 0x00000010U) >> 4)
  #define AGP_MODE_GET_RATE(x)          ((x) & 0x00000007U)
  #define AGP_MODE_SET_RQ(x,v)          (((x) & ~0xff000000U) | ((v) << 24))
  #define AGP_MODE_SET_SBA(x,v)         (((x) & ~0x00000200U) | ((v) << 9))
  #define AGP_MODE_SET_AGP(x,v)         (((x) & ~0x00000100U) | ((v) << 8))
! #define AGP_MODE_SET_4G(x,v)          (((x) & ~0x00000020U) | ((v) << 5))
  #define AGP_MODE_SET_FW(x,v)          (((x) & ~0x00000010U) | ((v) << 4))
  #define AGP_MODE_SET_RATE(x,v)                (((x) & ~0x00000007U) | (v))
! #define AGP_MODE_RATE_1x              0x00000001
! #define AGP_MODE_RATE_2x              0x00000002
! #define AGP_MODE_RATE_4x              0x00000004
  
  #define AGPIOC_BASE       'A'
  #define AGPIOC_INFO       _IOR (AGPIOC_BASE, 0, agp_info)
--- 39,76 ----
   * Macros to manipulate AGP mode words.
   */
  #define AGP_MODE_GET_RQ(x)            (((x) & 0xff000000U) >> 24)
+ #define AGP_MODE_GET_ARQSZ(x)         (((x) & 0x0000e000U) >> 13)
+ #define AGP_MODE_GET_CAL(x)           (((x) & 0x00001c00U) >> 10)
  #define AGP_MODE_GET_SBA(x)           (((x) & 0x00000200U) >> 9)
  #define AGP_MODE_GET_AGP(x)           (((x) & 0x00000100U) >> 8)
! #define AGP_MODE_GET_GART_64(x)               (((x) & 0x00000080U) >> 7)
! #define AGP_MODE_GET_OVER_4G(x)               (((x) & 0x00000020U) >> 5)
  #define AGP_MODE_GET_FW(x)            (((x) & 0x00000010U) >> 4)
+ #define AGP_MODE_GET_MODE_3(x)                (((x) & 0x00000008U) >> 3)
  #define AGP_MODE_GET_RATE(x)          ((x) & 0x00000007U)
  #define AGP_MODE_SET_RQ(x,v)          (((x) & ~0xff000000U) | ((v) << 24))
+ #define AGP_MODE_SET_ARQSZ(x,v)               (((x) & ~0x0000e000U) | ((v) << 13))
+ #define AGP_MODE_SET_CAL(x,v)         (((x) & ~0x00001c00U) | ((v) << 10))
  #define AGP_MODE_SET_SBA(x,v)         (((x) & ~0x00000200U) | ((v) << 9))
  #define AGP_MODE_SET_AGP(x,v)         (((x) & ~0x00000100U) | ((v) << 8))
! #define AGP_MODE_SET_GART_64(x,v)     (((x) & ~0x00000080U) | ((v) << 7))
! #define AGP_MODE_SET_OVER_4G(x,v)     (((x) & ~0x00000020U) | ((v) << 5))
  #define AGP_MODE_SET_FW(x,v)          (((x) & ~0x00000010U) | ((v) << 4))
+ #define AGP_MODE_SET_MODE_3(x,v)      (((x) & ~0x00000008U) | ((v) << 3))
  #define AGP_MODE_SET_RATE(x,v)                (((x) & ~0x00000007U) | (v))
! #define AGP_MODE_V2_RATE_1x           0x00000001
! #define AGP_MODE_V2_RATE_2x           0x00000002
! #define AGP_MODE_V2_RATE_4x           0x00000004
! #define AGP_MODE_V3_RATE_4x           0x00000001
! #define AGP_MODE_V3_RATE_8x           0x00000002
! #define AGP_MODE_V3_RATE_RSVD         0x00000004
! 
! /* XXX: Compat */
! #define AGP_MODE_GET_4G(x)            AGP_MODE_GET_OVER_4G(x)
! #define AGP_MODE_SET_4G(x)            AGP_MODE_SET_OVER_4G(x)
! #define AGP_MODE_RATE_1x              AGP_MODE_V2_RATE_1x
! #define AGP_MODE_RATE_2x              AGP_MODE_V2_RATE_2x
! #define AGP_MODE_RATE_4x              AGP_MODE_V2_RATE_4x
  
  #define AGPIOC_BASE       'A'
  #define AGPIOC_INFO       _IOR (AGPIOC_BASE, 0, agp_info)

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-i386 mailing list