xref: /openbsd-src/sys/arch/sparc64/sparc64/rbus_machdep.c (revision a5c223f85f4ca7080a9af0c743e3a439eb27bde4)
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