Home | History | Annotate | Line # | Download | only in dev
      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