1 /* $OpenBSD: rbus_machdep.c,v 1.5 2010/09/22 02:28:37 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2007 Mark Kettenis
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 and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/device.h>
21 #include <sys/systm.h>
22
23 #include <machine/bus.h>
24
25 #include <dev/cardbus/rbus.h>
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_pci.h>
28 #include <dev/pci/pcivar.h>
29 #include <dev/pci/pccbbreg.h>
30
31 struct rbustag rbus_null;
32
33 /*
34 * The PROM doesn't really understand PCMCIA/CardBus bridges, and
35 * leaves them mostly alone. However, on the UltraBook machines, it
36 * treats the memory and IO window register as ordinary BARs and
37 * assigns address space to them. We re-use that address space for
38 * rbus. This is a bit of a hack, but it seems to work and saves us
39 * from tracking down available address space globally.
40 */
41
42 rbus_tag_t
rbus_pccbb_parent_mem(struct device * self,struct pci_attach_args * pa)43 rbus_pccbb_parent_mem(struct device *self, struct pci_attach_args *pa)
44 {
45 struct ofw_pci_register addr[5];
46 int naddr, len, i;
47 int space, reg;
48 int node = PCITAG_NODE(pa->pa_tag);
49 char buf[32];
50
51 /* Check for the UltraBook PCMCIA controller. */
52 if (OF_getprop(node, "name", &buf, sizeof(buf)) > 0 &&
53 strcmp(buf, "pcma") == 0) {
54 len = OF_getprop(PCITAG_NODE(pa->pa_tag), "assigned-addresses",
55 &addr, sizeof(addr));
56 naddr = len / sizeof(struct ofw_pci_register);
57
58 for (i = 0; i < naddr; i++) {
59 space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
60 if (space != OFW_PCI_PHYS_HI_SPACE_MEM32)
61 continue;
62 reg = addr[i].phys_hi & OFW_PCI_PHYS_HI_REGISTERMASK;
63 if (reg < PCI_CB_MEMBASE0 || reg > PCI_CB_IOLIMIT1)
64 continue;
65
66 return (rbus_new_root_delegate(pa->pa_memt,
67 addr[i].phys_lo, addr[i].size_lo));
68 }
69 }
70
71 len = OF_getprop(OF_parent(node), "available", &addr, sizeof(addr));
72 naddr = len / sizeof(struct ofw_pci_register);
73
74 for (i = 0; i < naddr; i++) {
75 space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
76 if (space != OFW_PCI_PHYS_HI_SPACE_MEM32)
77 continue;
78 if (addr[i].size_hi == 0 && addr[i].size_lo < 0x10000000)
79 continue;
80
81 return (rbus_new_root_delegate(pa->pa_memt,
82 addr[i].phys_lo, addr[i].size_lo));
83 }
84
85 return &rbus_null;
86 }
87
88 rbus_tag_t
rbus_pccbb_parent_io(struct device * self,struct pci_attach_args * pa)89 rbus_pccbb_parent_io(struct device *self, struct pci_attach_args *pa)
90 {
91 struct ofw_pci_register addr[5];
92 int naddr, len, i;
93 int space, reg;
94 int node = PCITAG_NODE(pa->pa_tag);
95 char buf[32];
96
97 /* Check for the UltraBook PCMCIA controller. */
98 if (OF_getprop(node, "name", &buf, sizeof(buf)) > 0 &&
99 strcmp(buf, "pcma") == 0) {
100 len = OF_getprop(PCITAG_NODE(pa->pa_tag), "assigned-addresses",
101 &addr, sizeof(addr));
102 naddr = len / sizeof(struct ofw_pci_register);
103
104 for (i = 0; i < naddr; i++) {
105 space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
106 if (space != OFW_PCI_PHYS_HI_SPACE_IO)
107 continue;
108 reg = addr[i].phys_hi & OFW_PCI_PHYS_HI_REGISTERMASK;
109 if (reg < PCI_CB_MEMBASE0 || reg > PCI_CB_IOLIMIT1)
110 continue;
111
112 return (rbus_new_root_delegate(pa->pa_iot,
113 addr[i].phys_lo, addr[i].size_lo));
114 }
115 }
116
117 len = OF_getprop(OF_parent(node), "available", &addr, sizeof(addr));
118 naddr = len / sizeof(struct ofw_pci_register);
119
120 for (i = 0; i < naddr; i++) {
121 space = addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK;
122 if (space != OFW_PCI_PHYS_HI_SPACE_IO)
123 continue;
124 if (addr[i].size_hi == 0 && addr[i].size_lo < 0x00001000)
125 continue;
126
127 return (rbus_new_root_delegate(pa->pa_iot,
128 addr[i].phys_lo, addr[i].size_lo));
129 }
130
131 return &rbus_null;
132 }
133
134 void
pccbb_attach_hook(struct device * parent,struct device * self,struct pci_attach_args * pa)135 pccbb_attach_hook(struct device *parent, struct device *self,
136 struct pci_attach_args *pa)
137 {
138 pci_chipset_tag_t pc = pa->pa_pc;
139 int node = PCITAG_NODE(pa->pa_tag);
140 int bus, busrange[2];
141 pcireg_t bir;
142
143 bir = pci_conf_read(pc, pa->pa_tag, PCI_BUSNUM);
144 if (((bir >> 8) & 0xff) != 0)
145 return;
146
147 if (OF_getprop(OF_parent(node), "bus-range", &busrange,
148 sizeof(busrange)) != sizeof(busrange))
149 return;
150
151 bus = busrange[0] + 1;
152 while (bus < 256 && pc->busnode[bus])
153 bus++;
154 if (bus == 256)
155 return;
156 pc->busnode[bus] = node;
157
158 bir &= ~0x0000ff00;
159 bir |= (bus << 8);
160 pci_conf_write(pc, pa->pa_tag, PCI_BUSNUM, bir);
161 }
162