Annotation of sys/dev/pci/sti_pci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sti_pci.c,v 1.6 2007/06/17 12:07:10 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2006, 2007 Miodrag Vallat.
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice, this permission notice, and the disclaimer below
9: * appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: #include <sys/param.h>
21: #include <sys/systm.h>
22: #include <sys/device.h>
23:
24: #include <dev/pci/pcireg.h>
25: #include <dev/pci/pcivar.h>
26: #include <dev/pci/pcidevs.h>
27:
28: #include <dev/wscons/wsdisplayvar.h>
29:
30: #include <dev/ic/stireg.h>
31: #include <dev/ic/stivar.h>
32:
33: int sti_pci_match(struct device *, void *, void *);
34: void sti_pci_attach(struct device *, struct device *, void *);
35:
36: struct sti_pci_softc {
37: struct sti_softc sc_base;
38:
39: pci_chipset_tag_t sc_pc;
40: pcitag_t sc_tag;
41: };
42:
43: struct cfattach sti_pci_ca = {
44: sizeof(struct sti_pci_softc), sti_pci_match, sti_pci_attach
45: };
46:
47: const struct pci_matchid sti_pci_devices[] = {
48: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_EG },
49: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX2 },
50: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX4 },
51: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX6 },
52: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FXE },
53: };
54:
55: int sti_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int);
56: int sti_check_rom(struct sti_pci_softc *, struct pci_attach_args *);
57: void sti_pci_enable_rom(struct sti_softc *);
58: void sti_pci_disable_rom(struct sti_softc *);
59:
60: int sti_pci_is_console(struct pci_attach_args *, bus_addr_t *);
61:
62: int
63: sti_pci_match(struct device *parent, void *cf, void *aux)
64: {
65: struct pci_attach_args *paa = aux;
66:
67: return (pci_matchbyid(paa, sti_pci_devices,
68: sizeof(sti_pci_devices) / sizeof(sti_pci_devices[0])));
69: }
70:
71: void
72: sti_pci_attach(struct device *parent, struct device *self, void *aux)
73: {
74: struct sti_pci_softc *spc = (void *)self;
75: struct pci_attach_args *paa = aux;
76:
77: spc->sc_pc = paa->pa_pc;
78: spc->sc_tag = paa->pa_tag;
79: spc->sc_base.sc_enable_rom = sti_pci_enable_rom;
80: spc->sc_base.sc_disable_rom = sti_pci_disable_rom;
81:
82: printf("\n");
83:
84: if (sti_check_rom(spc, paa) != 0)
85: return;
86:
87: printf("%s", self->dv_xname);
88: if (sti_attach_common(&spc->sc_base, STI_CODEBASE_MAIN) == 0) {
89: if (sti_pci_is_console(paa, spc->sc_base.bases) != 0)
90: spc->sc_base.sc_flags |= STI_CONSOLE;
91: startuphook_establish(sti_end_attach, spc);
92: }
93: }
94:
95: /*
96: * Grovel the STI ROM image.
97: */
98: int
99: sti_check_rom(struct sti_pci_softc *spc, struct pci_attach_args *pa)
100: {
101: struct sti_softc *sc = &spc->sc_base;
102: pcireg_t address, mask;
103: bus_space_handle_t romh;
104: bus_size_t romsize, subsize, stiromsize;
105: bus_addr_t selected, offs, suboffs;
106: u_int32_t tmp;
107: int i;
108: int rc;
109:
110: /* sort of inline sti_pci_enable_rom(sc) */
111: address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
112: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE);
113: mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
114: address |= PCI_ROM_ENABLE;
115: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
116: sc->sc_flags |= STI_ROM_ENABLED;
117:
118: /*
119: * Map the complete ROM for now.
120: */
121:
122: romsize = PCI_ROM_SIZE(mask);
123: rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address), romsize,
124: 0, &romh);
125: sti_pci_disable_rom(sc);
126: if (rc != 0) {
127: printf("%s: can't map PCI ROM (%d)\n",
128: sc->sc_dev.dv_xname, rc);
129: goto fail2;
130: }
131:
132: /*
133: * Iterate over the ROM images, pick the best candidate.
134: */
135:
136: selected = (bus_addr_t)-1;
137: for (offs = 0; offs < romsize; offs += subsize) {
138: sti_pci_enable_rom(sc);
139: /*
140: * Check for a valid ROM header.
141: */
142: tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0);
143: tmp = letoh32(tmp);
144: if (tmp != 0x55aa0000) {
145: sti_pci_disable_rom(sc);
146: if (offs == 0) {
147: printf("%s: invalid PCI ROM header signature"
148: " (%08x)\n",
149: sc->sc_dev.dv_xname, tmp);
150: rc = EINVAL;
151: }
152: break;
153: }
154:
155: /*
156: * Check ROM type.
157: */
158: tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4);
159: tmp = letoh32(tmp);
160: if (tmp != 0x00000001) { /* 1 == STI ROM */
161: sti_pci_disable_rom(sc);
162: if (offs == 0) {
163: printf("%s: invalid PCI ROM type (%08x)\n",
164: sc->sc_dev.dv_xname, tmp);
165: rc = EINVAL;
166: }
167: break;
168: }
169:
170: subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
171: offs + 0x0c);
172: subsize <<= 9;
173:
174: #ifdef STIDEBUG
175: sti_pci_disable_rom(sc);
176: printf("ROM offset %08x size %08x type %08x",
177: offs, subsize, tmp);
178: sti_pci_enable_rom(sc);
179: #endif
180:
181: /*
182: * Check for a valid ROM data structure.
183: * We do not need it except to know what architecture the ROM
184: * code is for.
185: */
186:
187: suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
188: offs + 0x18);
189: tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0);
190: tmp = letoh32(tmp);
191: if (tmp != 0x50434952) { /* PCIR */
192: sti_pci_disable_rom(sc);
193: if (offs == 0) {
194: printf("%s: invalid PCI data signature"
195: " (%08x)\n",
196: sc->sc_dev.dv_xname, tmp);
197: rc = EINVAL;
198: } else {
199: #ifdef STIDEBUG
200: printf(" invalid PCI data signature %08x\n",
201: tmp);
202: #endif
203: continue;
204: }
205: }
206:
207: tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14);
208: sti_pci_disable_rom(sc);
209: #ifdef STIDEBUG
210: printf(" code %02x", tmp);
211: #endif
212:
213: switch (tmp) {
214: #ifdef __hppa__
215: case 0x10:
216: if (selected == (bus_addr_t)-1)
217: selected = offs;
218: break;
219: #endif
220: #ifdef __i386__
221: case 0x00:
222: if (selected == (bus_addr_t)-1)
223: selected = offs;
224: break;
225: #endif
226: default:
227: #ifdef STIDEBUG
228: printf(" (wrong architecture)");
229: #endif
230: break;
231: }
232:
233: #ifdef STIDEBUG
234: if (selected == offs)
235: printf(" -> SELECTED");
236: printf("\n");
237: #endif
238: }
239:
240: if (selected == (bus_addr_t)-1) {
241: if (rc == 0) {
242: printf("%s: found no ROM with correct microcode"
243: " architecture\n", sc->sc_dev.dv_xname);
244: rc = ENOEXEC;
245: }
246: goto fail;
247: }
248:
249: /*
250: * Read the STI region BAR assignments.
251: */
252:
253: sti_pci_enable_rom(sc);
254: offs = selected +
255: (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e);
256: for (i = 0; i < STI_REGION_MAX; i++) {
257: rc = sti_readbar(sc, pa, i,
258: bus_space_read_1(pa->pa_memt, romh, offs + i));
259: if (rc != 0)
260: goto fail;
261: }
262:
263: /*
264: * Find out where the STI ROM itself lies, and its size.
265: */
266:
267: offs = selected +
268: (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08);
269: stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh,
270: offs + 0x18);
271: stiromsize = letoh32(stiromsize);
272: sti_pci_disable_rom(sc);
273:
274: /*
275: * Replace our mapping with a smaller mapping of only the area
276: * we are interested in.
277: */
278:
279: bus_space_unmap(pa->pa_memt, romh, romsize);
280: rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address) + offs,
281: stiromsize, 0, &sc->romh);
282: if (rc != 0) {
283: printf("%s: can't map STI ROM (%d)\n",
284: sc->sc_dev.dv_xname, rc);
285: goto fail2;
286: }
287: sc->memt = pa->pa_memt;
288:
289: return (0);
290:
291: fail:
292: bus_space_unmap(pa->pa_memt, romh, romsize);
293: fail2:
294: sti_pci_disable_rom(sc);
295:
296: return (rc);
297: }
298:
299: /*
300: * Decode a BAR register.
301: */
302: int
303: sti_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region,
304: int bar)
305: {
306: bus_addr_t addr;
307: bus_size_t size;
308: u_int32_t cf;
309: int rc;
310:
311: if (bar == 0) {
312: sc->bases[region] = 0;
313: return (0);
314: }
315:
316: #ifdef DIAGNOSTIC
317: if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) {
318: sti_pci_disable_rom(sc);
319: printf("%s: unexpected bar %02x for region %d\n",
320: sc->sc_dev.dv_xname, bar, region);
321: sti_pci_enable_rom(sc);
322: }
323: #endif
324:
325: cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
326:
327: if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
328: rc = pci_io_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size);
329: else
330: rc = pci_mem_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size,
331: NULL);
332:
333: if (rc != 0) {
334: sti_pci_disable_rom(sc);
335: printf("%s: invalid bar %02x for region %d\n",
336: sc->sc_dev.dv_xname, bar, region);
337: sti_pci_enable_rom(sc);
338: return (rc);
339: }
340:
341: sc->bases[region] = addr;
342: return (0);
343: }
344:
345: /*
346: * Enable PCI ROM.
347: */
348: void
349: sti_pci_enable_rom(struct sti_softc *sc)
350: {
351: struct sti_pci_softc *spc = (struct sti_pci_softc *)sc;
352: pcireg_t address;
353:
354: if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
355: address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG);
356: address |= PCI_ROM_ENABLE;
357: pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address);
358: SET(sc->sc_flags, STI_ROM_ENABLED);
359: }
360: }
361:
362: /*
363: * Disable PCI ROM.
364: */
365: void
366: sti_pci_disable_rom(struct sti_softc *sc)
367: {
368: struct sti_pci_softc *spc = (struct sti_pci_softc *)sc;
369: pcireg_t address;
370:
371: if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
372: address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG);
373: address &= ~PCI_ROM_ENABLE;
374: pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address);
375:
376: CLR(sc->sc_flags, STI_ROM_ENABLED);
377: }
378: }
CVSweb