1 /* $NetBSD: sti_pci_machdep.c,v 1.3 2025/10/20 09:50:10 macallan Exp $ */ 2 3 /* $OpenBSD: sti_pci_machdep.c,v 1.2 2009/04/10 17:11:27 miod Exp $ */ 4 5 /* 6 * Copyright (c) 2007, 2009 Miodrag Vallat. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice, this permission notice, and the disclaimer below 11 * appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/device.h> 25 26 #include <machine/iomod.h> 27 #include <machine/autoconf.h> 28 29 #include <dev/pci/pcivar.h> 30 31 #include <dev/wscons/wsdisplayvar.h> 32 #include <hppa/hppa/machdep.h> 33 #include <dev/ic/stireg.h> 34 #include <dev/ic/stivar.h> 35 #include <hppa/dev/sti_pci_var.h> 36 37 #define PCI_ROM_SIZE(mr) \ 38 (PCI_MAPREG_ROM_ADDR(mr) & -PCI_MAPREG_ROM_ADDR(mr)) 39 40 #include "opt_sti_pci.h" 41 42 #ifdef STI_PCI_DEBUG 43 #define DPRINTF printf 44 #else 45 #define DPRINTF while (0) printf /* */ 46 #endif 47 48 int 49 sti_pci_is_console(struct pci_attach_args *paa, bus_addr_t *bases) 50 { 51 hppa_hpa_t consaddr; 52 uint32_t cf; 53 int pagezero_cookie; 54 int bar; 55 int rc; 56 57 KASSERT(paa != NULL); 58 59 pagezero_cookie = hppa_pagezero_map(); 60 consaddr = (hppa_hpa_t)PAGE0->mem_cons.pz_hpa; 61 hppa_pagezero_unmap(pagezero_cookie); 62 /* 63 * PAGE0 console information will point to one of our BARs, 64 * but depending on the particular sti model, this might not 65 * be the BAR mapping the rom (region #0). 66 * 67 * For example, on Visualize FXe, regions #0, #2 and #3 are 68 * mapped by BAR 0x18, while region #1 is mapped by BAR 0x10, 69 * which matches PAGE0 console address. 70 * 71 * Rather than trying to be smart, reread the region->BAR array 72 * again, and compare the BAR mapping region #1 against PAGE0 73 * values, we simply try all the valid BARs; if any of them 74 * matches what PAGE0 says, then we are the console, and it 75 * doesn't matter which BAR matched. 76 */ 77 for (bar = PCI_MAPREG_START; bar <= PCI_MAPREG_PPB_END; ) { 78 bus_addr_t addr; 79 bus_size_t size; 80 81 cf = pci_conf_read(paa->pa_pc, paa->pa_tag, bar); 82 83 rc = pci_mapreg_info(paa->pa_pc, paa->pa_tag, bar, 84 PCI_MAPREG_TYPE(cf), &addr, &size, NULL); 85 86 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) { 87 bar += 4; 88 } else { 89 if (PCI_MAPREG_MEM_TYPE(cf) == 90 PCI_MAPREG_MEM_TYPE_64BIT) 91 bar += 8; 92 else 93 bar += 4; 94 } 95 96 if (rc == 0 && (hppa_hpa_t)addr == consaddr) 97 return 1; 98 } 99 100 return 0; 101 } 102 103 /* 104 * Decode a BAR register. 105 */ 106 static int 107 sti_pci_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region, 108 int bar) 109 { 110 bus_addr_t addr; 111 bus_size_t size; 112 uint32_t cf; 113 int rc; 114 115 if (bar == 0) { 116 sc->bases[region] = 0; 117 return (0); 118 } 119 120 #ifdef DIAGNOSTIC 121 if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) { 122 sc->sc_disable_rom(sc); 123 printf("%s: unexpected bar %02x for region %d\n", 124 device_xname(sc->sc_dev), bar, region); 125 sc->sc_enable_rom(sc); 126 } 127 #endif 128 129 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar); 130 131 rc = pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar, PCI_MAPREG_TYPE(cf), 132 &addr, &size, NULL); 133 134 if (rc != 0) { 135 sc->sc_disable_rom(sc); 136 aprint_error_dev(sc->sc_dev, "invalid bar %02x for region %d\n", 137 bar, region); 138 sc->sc_enable_rom(sc); 139 return (rc); 140 } 141 142 sc->bases[region] = addr; 143 return (0); 144 } 145 146 /* 147 * Grovel the STI ROM image. 148 */ 149 int 150 sti_pci_check_rom(struct sti_softc *sc, struct pci_attach_args *pa, 151 bus_space_handle_t *rom_handle) 152 { 153 pcireg_t address, mask; 154 bus_space_handle_t romh; 155 bus_size_t romsize, subsize, stiromsize; 156 bus_addr_t selected, offs, suboffs; 157 uint32_t tmp; 158 int i; 159 int rc; 160 161 /* sort of inline sti_pci_enable_rom(sc) */ 162 address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM); 163 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, 164 ~PCI_MAPREG_ROM_ENABLE); 165 mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM); 166 address |= PCI_MAPREG_ROM_ENABLE; 167 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_MAPREG_ROM, address); 168 sc->sc_flags |= STI_ROM_ENABLED; 169 /* 170 * Map the complete ROM for now. 171 */ 172 173 romsize = PCI_ROM_SIZE(mask); 174 DPRINTF("%s: mapping rom @ %lx for %lx\n", __func__, 175 (long)PCI_MAPREG_ROM_ADDR(address), (long)romsize); 176 177 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address), romsize, 178 0, &romh); 179 if (rc != 0) { 180 aprint_error_dev(sc->sc_dev, "can't map PCI ROM (%d)\n", rc); 181 goto fail2; 182 } 183 184 sc->sc_disable_rom(sc); 185 /* 186 * Iterate over the ROM images, pick the best candidate. 187 */ 188 189 selected = (bus_addr_t)-1; 190 for (offs = 0; offs < romsize; offs += subsize) { 191 sc->sc_enable_rom(sc); 192 /* 193 * Check for a valid ROM header. 194 */ 195 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0); 196 tmp = le32toh(tmp); 197 if (tmp != 0x55aa0000) { 198 sc->sc_disable_rom(sc); 199 if (offs == 0) { 200 aprint_error_dev(sc->sc_dev, 201 "invalid PCI ROM header signature (%08x)\n", 202 tmp); 203 rc = EINVAL; 204 } 205 break; 206 } 207 208 /* 209 * Check ROM type. 210 */ 211 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4); 212 tmp = le32toh(tmp); 213 if (tmp != 0x00000001) { /* 1 == STI ROM */ 214 sc->sc_disable_rom(sc); 215 if (offs == 0) { 216 aprint_error_dev(sc->sc_dev, 217 "invalid PCI ROM type (%08x)\n", tmp); 218 rc = EINVAL; 219 } 220 break; 221 } 222 223 subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, 224 offs + 0x0c); 225 subsize <<= 9; 226 227 #ifdef STI_PCI_DEBUG 228 sc->sc_disable_rom(sc); 229 DPRINTF("ROM offset %08x size %08x type %08x", 230 (u_int)offs, (u_int)subsize, tmp); 231 sc->sc_enable_rom(sc); 232 #endif 233 234 /* 235 * Check for a valid ROM data structure. 236 * We do not need it except to know what architecture the ROM 237 * code is for. 238 */ 239 240 suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh, 241 offs + 0x18); 242 tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0); 243 tmp = le32toh(tmp); 244 if (tmp != 0x50434952) { /* PCIR */ 245 sc->sc_disable_rom(sc); 246 if (offs == 0) { 247 aprint_error_dev(sc->sc_dev, "invalid PCI data" 248 " signature (%08x)\n", tmp); 249 rc = EINVAL; 250 } else { 251 DPRINTF(" invalid PCI data signature %08x\n", 252 tmp); 253 continue; 254 } 255 } 256 257 tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14); 258 sc->sc_disable_rom(sc); 259 DPRINTF(" code %02x", tmp); 260 261 switch (tmp) { 262 #ifdef __hppa__ 263 case 0x10: 264 if (selected == (bus_addr_t)-1) 265 selected = offs; 266 break; 267 #endif 268 #ifdef __i386__ 269 case 0x00: 270 if (selected == (bus_addr_t)-1) 271 selected = offs; 272 break; 273 #endif 274 default: 275 DPRINTF(" (wrong architecture)"); 276 break; 277 } 278 DPRINTF("%s\n", selected == offs ? " -> SELECTED" : ""); 279 } 280 281 if (selected == (bus_addr_t)-1) { 282 if (rc == 0) { 283 aprint_error_dev(sc->sc_dev, "found no ROM with " 284 "correct microcode architecture\n"); 285 rc = ENOEXEC; 286 } 287 goto fail; 288 } 289 290 /* 291 * Read the STI region BAR assignments. 292 */ 293 294 sc->sc_enable_rom(sc); 295 offs = selected + 296 (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e); 297 for (i = 0; i < STI_REGION_MAX; i++) { 298 rc = sti_pci_readbar(sc, pa, i, 299 bus_space_read_1(pa->pa_memt, romh, offs + i)); 300 if (rc != 0) 301 goto fail; 302 } 303 304 /* 305 * Find out where the STI ROM itself lies, and its size. 306 */ 307 308 offs = selected + 309 (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08); 310 stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, 311 offs + 0x18); 312 stiromsize = le32toh(stiromsize); 313 sc->sc_disable_rom(sc); 314 315 /* 316 * Replace our mapping with a smaller mapping of only the area 317 * we are interested in. 318 */ 319 320 DPRINTF("remapping rom @ %lx for %lx\n", 321 (long)(PCI_MAPREG_ROM_ADDR(address) + offs), (long)stiromsize); 322 bus_space_unmap(pa->pa_memt, romh, romsize); 323 rc = bus_space_map(pa->pa_memt, PCI_MAPREG_ROM_ADDR(address) + offs, 324 stiromsize, 0, rom_handle); 325 if (rc != 0) { 326 aprint_error_dev(sc->sc_dev, "can't map STI ROM (%d)\n", 327 rc); 328 goto fail2; 329 } 330 sc->sc_disable_rom(sc); 331 sc->sc_flags &= ~STI_ROM_ENABLED; 332 333 return 0; 334 335 fail: 336 bus_space_unmap(pa->pa_memt, romh, romsize); 337 fail2: 338 sc->sc_disable_rom(sc); 339 340 return rc; 341 } 342 343 344