|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "Resolving AGP Initialization Lockups on the Intel 440LX" |
| 4 | +date: 2025-08-04 15:00:00 +0200 |
| 5 | +toc: true |
| 6 | +toc_label: "440LX AGP Issues" |
| 7 | +excerpt: "A deep dive into the chipset errata and register-level pitfalls that cause system hangs when enabling AGP in coreboot on the 440LX, and a robust software solution." |
| 8 | +header: |
| 9 | + teaser: |
| 10 | +categories: |
| 11 | + - Firmware |
| 12 | + - Hardware |
| 13 | + - Retro Computing |
| 14 | +tags: |
| 15 | + - coreboot |
| 16 | + - firmware |
| 17 | + - retro |
| 18 | + - i440lx |
| 19 | + - agp |
| 20 | + - bugfix |
| 21 | +--- |
| 22 | + |
| 23 | +## 440LX, Intel's First Go at AGP |
| 24 | + |
| 25 | +There's a special kind of satisfaction in bringing modern, open-source firmware to a piece of vintage hardware. After getting coreboot running smoothly on the [MSI MS-6117](https://theretroweb.com/motherboards/s/msi-ms-6117-lx6) motherboard, I was feeling pretty good. |
| 26 | + |
| 27 | +The final boss was in sight: enabling the Accelerated Graphics Port (AGP). I flipped the config switch, rebuilt, and... nothing. A hard lockup during the PCI scan. |
| 28 | + |
| 29 | +The most baffling part? It hung even with no AGP card in the slot. This wasn't a fussy graphics card. This was the chipset itself throwing a tantrum. |
| 30 | + |
| 31 | +This is the story of taming the Intel [440LX](https://theretroweb.com/chipsets/282)-Intel's first stab at AGP, and a masterclass in quirky hardware design. |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## The First Clue: A Chipset with a Split Personality |
| 36 | + |
| 37 | +My first assumption was a simple bug in my code, but the “no card” hang pointed to something deeper. It turns out the 440LX isn't a single northbridge in the way you'd expect. Instead, Intel designed it as two logical devices on the PCI bus: |
| 38 | + |
| 39 | +- **Device 0 (ID 7180h):** Host Bridge - manages DRAM controller and AGP registers. |
| 40 | +- **Device 1 (ID 7181h):** Virtual PCI-to-PCI Bridge - exposes AGP as a secondary PCI bus. |
| 41 | + |
| 42 | +This meant that the AGP engine on Device 0 wouldn’t function correctly unless Device 1 was properly initialized. My code was talking to the AGP registers before their parent bus existed. |
| 43 | + |
| 44 | +--- |
| 45 | + |
| 46 | +## Datasheet Archaeology: Unearthing Ancient Bugs |
| 47 | + |
| 48 | +The next stop was Intel’s specification updates. Buried within: |
| 49 | + |
| 50 | +> **VGA Hang Erratum**: If a PCI device tries to access the legacy VGA memory range (0xA0000–0xBFFFF) while the VGA card is on AGP, the chipset locks up *completely*. |
| 51 | +> There is no hardware fix-only a strict software sequence can avoid it. |
| 52 | +
|
| 53 | +That explained the lockup with *no card inserted*. The firmware was forwarding VGA cycles to an empty AGP bus, resulting in deadlock. |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +## The Rules of Engagement |
| 58 | + |
| 59 | +Key takeaways from the errata and datasheets: |
| 60 | + |
| 61 | +- **Order matters**: Write `APSIZE` before `APBASE`. Get it wrong, and `APBASE` is undefined. |
| 62 | +- **Don’t enable the AGP aperture in firmware**: Let the OS driver handle that. |
| 63 | +- **Don’t confuse 440LX with 440BX**: 440LX architecturely is more akin to Intel's 430TX chipset with AGP and a new host bus slapped on. |
| 64 | + |
| 65 | +--- |
| 66 | + |
| 67 | +## The Fix: A Two-Part Incantation |
| 68 | + |
| 69 | +### Phase 1: Before PCI Enumeration |
| 70 | + |
| 71 | +Set up the aperture carefully while leaving it disabled. This prevents undefined states and the VGA hang. |
| 72 | + |
| 73 | +```c |
| 74 | +/** |
| 75 | + * @brief Initialize the AGP aperture early in ramstage. |
| 76 | + */ |
| 77 | +void i440lx_agp_aperture_init(struct device *dev) |
| 78 | +{ |
| 79 | + uint32_t tolm, aperture_base; |
| 80 | + uint16_t paccfg; |
| 81 | + const uint32_t aperture_size = 64 * 1024 * 1024; /* 64 MB */ |
| 82 | + |
| 83 | + printk(BIOS_INFO, "440LX: Initializing AGP Aperture...\n"); |
| 84 | + |
| 85 | + /* Set a sane aperture size */ |
| 86 | + pci_write_config8(dev, APSIZE, 0x30); /* 64MB */ |
| 87 | + |
| 88 | + /* Set base address above system RAM */ |
| 89 | + tolm = find_pci_tolm(dev->bus); |
| 90 | + aperture_base = (tolm + (aperture_size - 1)) & ~(aperture_size - 1); |
| 91 | + pci_write_config32(dev, APBASE, aperture_base); |
| 92 | + |
| 93 | + /* Configure PACCFG for VGA hang workaround */ |
| 94 | + paccfg = pci_read_config16(dev, PACCFG); |
| 95 | + paccfg |= PACCFG_PCI_APER_DIS; |
| 96 | + paccfg &= ~PACCFG_GBL_APER_EN; |
| 97 | + paccfg &= ~PACCFG_MDA_PRESENT; |
| 98 | + pci_write_config16(dev, PACCFG, paccfg); |
| 99 | +} |
| 100 | +```` |
| 101 | +
|
| 102 | +--- |
| 103 | +
|
| 104 | +### Phase 2: After PCI Scan |
| 105 | +
|
| 106 | +Enable AGP protocol only if a VGA card is actually detected. |
| 107 | +
|
| 108 | +```c |
| 109 | +/** |
| 110 | + * @brief Finalize AGP configuration after PCI enumeration. |
| 111 | + */ |
| 112 | +void i440lx_agp_enable_devices(void) |
| 113 | +{ |
| 114 | + struct device *host_bridge, *agp_bridge, *agp_dev; |
| 115 | + uint16_t bctrl; |
| 116 | + uint32_t agpcmd; |
| 117 | +
|
| 118 | + host_bridge = dev_find_slot(0, PCI_DEVFN(0, 0)); |
| 119 | + agp_bridge = dev_find_slot(0, PCI_DEVFN(0, 1)); |
| 120 | + agp_dev = dev_find_slot(1, PCI_DEVFN(0, 0)); |
| 121 | +
|
| 122 | + if (!agp_dev || !agp_dev->enabled) { |
| 123 | + printk(BIOS_INFO, "440LX: No AGP device found. Keeping AGP disabled.\n"); |
| 124 | + bctrl = pci_read_config16(agp_bridge, BCTRL); |
| 125 | + bctrl &= ~BCTRL_VGA_EN; |
| 126 | + pci_write_config16(agp_bridge, BCTRL, bctrl); |
| 127 | + return; |
| 128 | + } |
| 129 | +
|
| 130 | + /* Enable VGA forwarding if needed */ |
| 131 | + if (pci_read_class(agp_dev) == PCI_CLASS_DISPLAY_VGA) { |
| 132 | + printk(BIOS_INFO, "440LX: Enabling VGA forwarding for AGP device.\n"); |
| 133 | + bctrl = pci_read_config16(agp_bridge, BCTRL); |
| 134 | + bctrl |= BCTRL_VGA_EN; |
| 135 | + pci_write_config16(agp_bridge, BCTRL, bctrl); |
| 136 | + } |
| 137 | +
|
| 138 | + /* Enable AGP 2x mode */ |
| 139 | + agpcmd = AGPCMD_AGP_EN | AGPCMD_RATE_2X; |
| 140 | + printk(BIOS_INFO, "440LX: Enabling AGP 2x mode.\n"); |
| 141 | +
|
| 142 | + pci_write_config32(host_bridge, AGPCMD, agpcmd); |
| 143 | + pci_write_config32(agp_dev, agp_dev->cap_ptr + 4, agpcmd); |
| 144 | +} |
| 145 | +``` |
| 146 | +--- |
0 commit comments