Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / sandpoint / stand / netboot / pci.c
bloba38940df059375a596f6187a6f053dd3a6beb674
1 /* $NetBSD: pci.c,v 1.11 2009/03/18 10:22:35 cegger Exp $ */
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/param.h>
34 #include <lib/libsa/stand.h>
37 * "Map B" layout
39 * practice direct mode configuration scheme with CONFIG_ADDR
40 * (0xfec0'0000) and CONFIG_DATA (0xfee0'0000).
42 #define PCI_MEMBASE 0x80000000
43 #define PCI_MEMLIMIT 0xfbffffff /* EUMB is next to this */
44 #define PCI_IOBASE 0x00001000 /* reserves room for via 686B */
45 #define PCI_IOLIMIT 0x000fffff
46 #define CONFIG_ADDR 0xfec00000
47 #define CONFIG_DATA 0xfee00000
49 #define MAXNDEVS 32
51 #include "globals.h"
53 static unsigned cfgread(int, int, int, int);
54 static void cfgwrite(int, int, int, int, unsigned);
55 static void _buswalk(int,
56 int (*)(int, int, int, unsigned long), unsigned long);
57 static int _pcilookup(int,
58 int (*)(int, int, int, unsigned long), unsigned long,
59 unsigned [][2], int, int);
60 static int deviceinit(int, int, int, unsigned long);
61 static void memassign(int, int, int);
62 static int devmatch(int, int, int, unsigned long);
63 static int clsmatch(int, int, int, unsigned long);
65 unsigned memstart, memlimit;
66 unsigned iostart, iolimit;
67 unsigned maxbus;
69 void
70 pcisetup(void)
73 memstart = PCI_MEMBASE;
74 memlimit = PCI_MEMLIMIT;
75 iostart = PCI_IOBASE;
76 iolimit = PCI_IOLIMIT;
77 maxbus = 0;
79 (void)_buswalk(0, deviceinit, 0UL);
82 int
83 pcifinddev(unsigned vend, unsigned prod, unsigned *tag)
85 unsigned pciid, target[1][2];
87 pciid = PCI_DEVICE(vend, prod);
88 if (_pcilookup(0, devmatch, pciid, target, 0, 1)) {
89 *tag = target[0][1];
90 return 0;
92 *tag = ~0;
93 return -1;
96 int
97 pcilookup(type, list, max)
98 unsigned type;
99 unsigned list[][2];
100 int max;
103 return _pcilookup(0, clsmatch, type, list, 0, max);
106 unsigned
107 pcimaketag(int b, int d, int f)
110 return (1U << 31) | (b << 16) | (d << 11) | (f << 8);
113 void
114 pcidecomposetag(unsigned tag, int *b, int *d, int *f)
117 if (b != NULL)
118 *b = (tag >> 16) & 0xff;
119 if (d != NULL)
120 *d = (tag >> 11) & 0x1f;
121 if (f != NULL)
122 *f = (tag >> 8) & 0x7;
123 return;
126 unsigned
127 pcicfgread(unsigned tag, int off)
129 unsigned cfg;
131 cfg = tag | (off &~ 03);
132 iohtole32(CONFIG_ADDR, cfg);
133 return iole32toh(CONFIG_DATA);
136 void
137 pcicfgwrite(unsigned tag, int off, unsigned val)
139 unsigned cfg;
141 cfg = tag | (off &~ 03);
142 iohtole32(CONFIG_ADDR, cfg);
143 iohtole32(CONFIG_DATA, val);
146 static unsigned
147 cfgread(int b, int d, int f, int off)
149 unsigned cfg;
151 off &= ~03;
152 cfg = (1U << 31) | (b << 16) | (d << 11) | (f << 8) | off | 0;
153 iohtole32(CONFIG_ADDR, cfg);
154 return iole32toh(CONFIG_DATA);
157 static void
158 cfgwrite(int b, int d, int f, int off, unsigned val)
160 unsigned cfg;
162 off &= ~03;
163 cfg = (1U << 31) | (b << 16) | (d << 11) | (f << 8) | off | 0;
164 iohtole32(CONFIG_ADDR, cfg);
165 iohtole32(CONFIG_DATA, val);
168 static void
169 _buswalk(int bus, int (*proc)(int, int, int, unsigned long), unsigned long data)
171 int device, function, nfunctions;
172 unsigned pciid, bhlcr;
174 for (device = 0; device < MAXNDEVS; device++) {
175 pciid = cfgread(bus, device, 0, PCI_ID_REG);
176 if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
177 continue;
178 if (PCI_VENDOR(pciid) == 0)
179 continue;
180 bhlcr = cfgread(bus, device, 0, PCI_BHLC_REG);
181 nfunctions = (PCI_HDRTYPE_MULTIFN(bhlcr)) ? 8 : 1;
182 for (function = 0; function < nfunctions; function++) {
183 pciid = cfgread(bus, device, function, PCI_ID_REG);
184 if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
185 continue;
186 if (PCI_VENDOR(pciid) == 0)
187 continue;
189 if ((*proc)(bus, device, function, data) != 0)
190 goto out; /* early exit */
193 out:;
196 static int
197 deviceinit(int bus, int dev, int func, unsigned long data)
199 unsigned val;
201 /* 0x00 */
202 printf("%02d:%02d:%02d:", bus, dev, func);
203 val = cfgread(bus, dev, func, 0x00);
204 printf(" chip %04x.%04x", val & 0xffff, val>>16);
205 val = cfgread(bus, dev, func, 0x2c);
206 printf(" card %04x.%04x", val & 0xffff, val>>16);
207 val = cfgread(bus, dev, func, 0x08);
208 printf(" rev %02x class %02x.%02x.%02x",
209 val & 0xff, (val>>24), (val>>16) & 0xff, (val>>8) & 0xff);
210 val = cfgread(bus, dev, func, 0x0c);
211 printf(" hdr %02x\n", (val>>16) & 0xff);
213 /* 0x04 */
214 val = cfgread(bus, dev, func, 0x04);
215 val |= 0xffff0107; /* enable IO,MEM,MASTER,SERR */
216 cfgwrite(bus, dev, func, 0x04, val);
218 /* 0x0c */
219 val = 0x80 << 8 | 0x08 /* 32B cache line */;
220 cfgwrite(bus, dev, func, 0x0c, val);
222 #if 1
223 /* skip IDE controller BAR assignment */
224 val = cfgread(bus, dev, func, PCI_CLASS_REG);
225 if ((val >> 16) == PCI_CLASS_IDE)
226 return 0;
227 #endif
228 memassign(bus, dev, func);
230 /* descending toward PCI-PCI bridge */
231 if ((cfgread(bus, dev, func, 0x08) >> 16) == PCI_CLASS_PPB) {
232 unsigned new;
234 /* 0x18 */
235 new = (maxbus += 1);
236 val = (0xff << 16) | (new << 8) | bus;
237 cfgwrite(bus, dev, func, 0x18, val);
239 /* 0x1c and 0x30 */
240 val = (iostart + (0xfff)) & ~0xfff; /* 4KB boundary */
241 iostart = val;
242 val = 0xffff0000 | (iolimit & 0xf000) | (val & 0xf000) >> 8;
243 cfgwrite(bus, dev, func, 0x1c, val);
244 val = (iolimit & 0xffff0000) | (val & 0xffff0000) >> 16;
245 cfgwrite(bus, dev, func, 0x30, val);
247 /* 0x20 */
248 val = (memstart + 0xfffff) &~ 0xfffff; /* 1MB boundary */
249 memstart = val;
250 val = (memlimit & 0xffff0000) | (val & 0xffff0000) >> 16;
251 cfgwrite(bus, dev, func, 0x20, val);
253 /* redo 0x04 */
254 val = cfgread(bus, dev, func, 0x04);
255 val |= 0xffff0107;
256 cfgwrite(bus, dev, func, 0x04, val);
258 _buswalk(new, deviceinit, data);
260 /* adjust 0x18 */
261 val = cfgread(bus, dev, func, 0x18);
262 val = (maxbus << 16) | (val & 0xffff);
263 cfgwrite(bus, dev, func, 0x18, val);
265 return 0;
268 static void
269 memassign(int bus, int dev, int func)
271 unsigned val, maxbar, mapr, req, mapbase, size;
273 val = cfgread(bus, dev, func, 0x0c);
274 switch (PCI_HDRTYPE_TYPE(val)) {
275 case 0:
276 maxbar = 0x10 + 6 * 4; break;
277 case 1:
278 maxbar = 0x10 + 2 * 4; break;
279 default:
280 maxbar = 0x10 + 1 * 4; break;
282 for (mapr = 0x10; mapr < maxbar; mapr += 4) {
283 cfgwrite(bus, dev, func, mapr, 0xffffffff);
284 val = cfgread(bus, dev, func, mapr);
285 if (val & 01) {
286 /* PCI IO space */
287 req = ~(val & 0xfffffffc) + 1;
288 if (req & (req - 1)) /* power of 2 */
289 continue;
290 if (req == 0) /* ever exists */
291 continue;
292 size = (req > 0x10) ? req : 0x10;
293 mapbase = (iostart + size - 1) & ~(size - 1);
294 if (mapbase + size > iolimit)
295 continue;
297 iostart = mapbase + size;
298 /* establish IO space */
299 cfgwrite(bus, dev, func, mapr, mapbase | 01);
301 else {
302 /* PCI memory space */
303 req = ~(val & 0xfffffff0) + 1;
304 if (req & (req - 1)) /* power of 2 */
305 continue;
306 if (req == 0) /* ever exists */
307 continue;
308 val &= 0x6;
309 if (val == 2 || val == 6)
310 continue;
311 size = (req > 0x1000) ? req : 0x1000;
312 mapbase = (memstart + size - 1) & ~(size - 1);
313 if (mapbase + size > memlimit)
314 continue;
316 memstart = mapbase + size;
317 /* establish memory space */
318 cfgwrite(bus, dev, func, mapr, mapbase);
319 if (val == 4) {
320 mapr += 4;
321 cfgwrite(bus, dev, func, mapr, 0);
324 printf("%s base %x size %x\n", (val & 01) ? "i/o" : "mem", mapbase, size);
328 static int
329 devmatch(int bus, int dev, int func, unsigned long data)
331 unsigned pciid;
333 pciid = cfgread(bus, dev, func, PCI_ID_REG);
334 return (pciid == (unsigned)data);
337 static int
338 clsmatch(int bus, int dev, int func, unsigned long data)
340 unsigned class;
342 class = cfgread(bus, dev, func, PCI_CLASS_REG);
343 return ((class >> 16) == (unsigned)data);
346 static int
347 _pcilookup(int bus, int (*match)(int, int, int, unsigned long), unsigned long data, unsigned list[][2], int index, int limit)
349 int device, function, nfuncs;
350 unsigned pciid, bhlcr, class;
352 for (device = 0; device < MAXNDEVS; device++) {
353 pciid = cfgread(bus, device, 0, PCI_ID_REG);
354 if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
355 continue;
356 if (PCI_VENDOR(pciid) == 0)
357 continue;
358 class = cfgread(bus, device, 0, PCI_CLASS_REG);
359 if ((class >> 16) == PCI_CLASS_PPB) {
360 /* exploring bus beyond PCI-PCI bridge */
361 index = _pcilookup(bus + 1,
362 match, data, list, index, limit);
363 if (index >= limit)
364 goto out;
365 continue;
367 bhlcr = cfgread(bus, device, 0, PCI_BHLC_REG);
368 nfuncs = (PCI_HDRTYPE_MULTIFN(bhlcr)) ? 8 : 1;
369 for (function = 0; function < nfuncs; function++) {
370 pciid = cfgread(bus, device, function, PCI_ID_REG);
371 if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID)
372 continue;
373 if (PCI_VENDOR(pciid) == 0)
374 continue;
375 if ((*match)(bus, device, function, data)) {
376 list[index][0] = pciid;
377 list[index][1] =
378 pcimaketag(bus, device, function);
379 index += 1;
380 if (index >= limit)
381 goto out;
385 out:
386 return index;