xref: /openbsd-src/sys/arch/macppc/pci/ht.c (revision 89ed722c33692ad18452b9d394c650f8adc43407)
1*89ed722cSmpi /*	$OpenBSD: ht.c,v 1.19 2022/03/13 12:33:01 mpi Exp $	*/
2f80b69abSkettenis 
3f80b69abSkettenis /*
4f80b69abSkettenis  * Copyright (c) 2005 Mark Kettenis
5f80b69abSkettenis  *
6f80b69abSkettenis  * Permission to use, copy, modify, and distribute this software for any
7f80b69abSkettenis  * purpose with or without fee is hereby granted, provided that the above
8f80b69abSkettenis  * copyright notice and this permission notice appear in all copies.
9f80b69abSkettenis  *
10f80b69abSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f80b69abSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f80b69abSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f80b69abSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f80b69abSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15f80b69abSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16f80b69abSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f80b69abSkettenis  */
18f80b69abSkettenis 
19f80b69abSkettenis #include <sys/param.h>
20f80b69abSkettenis #include <sys/systm.h>
21f80b69abSkettenis #include <sys/device.h>
22f80b69abSkettenis 
23f80b69abSkettenis #include <machine/autoconf.h>
24f80b69abSkettenis #include <machine/bus.h>
25f80b69abSkettenis 
26f80b69abSkettenis #include <dev/pci/pcireg.h>
27f80b69abSkettenis #include <dev/pci/pcivar.h>
28f80b69abSkettenis #include <dev/pci/pcidevs.h>
29f80b69abSkettenis 
30f80b69abSkettenis #include <dev/ofw/openfirm.h>
31f80b69abSkettenis 
32f80b69abSkettenis int	 ht_match(struct device *, void *, void *);
33f80b69abSkettenis void	 ht_attach(struct device *, struct device *, void *);
34f80b69abSkettenis 
35f80b69abSkettenis pcireg_t ht_conf_read(void *, pcitag_t, int);
36f80b69abSkettenis void	 ht_conf_write(void *, pcitag_t, int, pcireg_t);
37f80b69abSkettenis 
38f80b69abSkettenis int	 ht_print(void *, const char *);
39f80b69abSkettenis 
40f80b69abSkettenis struct ht_softc {
41f80b69abSkettenis 	struct device	sc_dev;
42e1ac7eb5Skettenis 	int		sc_maxdevs;
43f80b69abSkettenis 	struct ppc_bus_space sc_mem_bus_space;
44f80b69abSkettenis 	struct ppc_bus_space sc_io_bus_space;
45f80b69abSkettenis 	struct ppc_pci_chipset sc_pc;
46f80b69abSkettenis 	bus_space_tag_t sc_memt;
47f80b69abSkettenis 	bus_space_handle_t sc_config0_memh;
48f80b69abSkettenis 	bus_space_handle_t sc_config1_memh;
49f80b69abSkettenis 	bus_space_tag_t sc_iot;
50f80b69abSkettenis 	bus_space_handle_t sc_config0_ioh;
51f80b69abSkettenis };
52f80b69abSkettenis 
53*89ed722cSmpi const struct cfattach ht_ca = {
54f80b69abSkettenis 	sizeof(struct ht_softc), ht_match, ht_attach
55f80b69abSkettenis };
56f80b69abSkettenis 
57f80b69abSkettenis struct cfdriver ht_cd = {
58f80b69abSkettenis 	NULL, "ht", DV_DULL,
59f80b69abSkettenis };
60f80b69abSkettenis 
61f80b69abSkettenis int
ht_match(struct device * parent,void * cf,void * aux)62f80b69abSkettenis ht_match(struct device *parent, void *cf, void *aux)
63f80b69abSkettenis {
64f80b69abSkettenis 	struct confargs *ca = aux;
65f80b69abSkettenis 
66f80b69abSkettenis 	if (strcmp(ca->ca_name, "ht") == 0)
67f80b69abSkettenis 		return (1);
68f80b69abSkettenis 	return (0);
69f80b69abSkettenis }
70f80b69abSkettenis 
71f80b69abSkettenis void
ht_attach(struct device * parent,struct device * self,void * aux)72f80b69abSkettenis ht_attach(struct device *parent, struct device *self, void *aux)
73f80b69abSkettenis {
74f80b69abSkettenis 	struct ht_softc *sc = (struct ht_softc *)self;
75f80b69abSkettenis 	struct confargs *ca = aux;
76f80b69abSkettenis 	struct pcibus_attach_args pba;
77f80b69abSkettenis 	u_int32_t regs[6];
78f80b69abSkettenis 	char compat[32];
792d3c312aSmpi 	int node, len;
80f80b69abSkettenis 
81f80b69abSkettenis 	if (ca->ca_node == 0) {
82e6dadaadSderaadt 		printf(": invalid node on ht config\n");
83f80b69abSkettenis 		return;
84f80b69abSkettenis 	}
85f80b69abSkettenis 
86f80b69abSkettenis 	len = OF_getprop(ca->ca_node, "reg", regs, sizeof(regs));
87c16de979Smiod 	if (len < 0 || len < sizeof(regs)) {
88f80b69abSkettenis 		printf(": regs lookup failed, node %x\n", ca->ca_node);
89f80b69abSkettenis 		return;
90f80b69abSkettenis 	}
91f80b69abSkettenis 
92f80b69abSkettenis 	sc->sc_mem_bus_space.bus_base = 0x80000000;
93f80b69abSkettenis 	sc->sc_mem_bus_space.bus_size = 0;
94f80b69abSkettenis 	sc->sc_mem_bus_space.bus_io = 0;
95f80b69abSkettenis 	sc->sc_memt = &sc->sc_mem_bus_space;
96f80b69abSkettenis 
97f80b69abSkettenis 	sc->sc_io_bus_space.bus_base = 0x80000000;
98f80b69abSkettenis 	sc->sc_io_bus_space.bus_size = 0;
99f80b69abSkettenis 	sc->sc_io_bus_space.bus_io = 1;
100f80b69abSkettenis 	sc->sc_iot = &sc->sc_io_bus_space;
101f80b69abSkettenis 
1020a7c5b4dSdrahn 	sc->sc_maxdevs = 1;
1030a7c5b4dSdrahn 	for (node = OF_child(ca->ca_node); node; node = OF_peer(node))
1040a7c5b4dSdrahn 		sc->sc_maxdevs++;
1050a7c5b4dSdrahn 
1060a7c5b4dSdrahn 	if (bus_space_map(sc->sc_memt, regs[1],
1072d3c312aSmpi 	    (1 << 11)*sc->sc_maxdevs, 0, &sc->sc_config0_memh)) {
108f80b69abSkettenis 		printf(": can't map PCI config0 memory\n");
109f80b69abSkettenis 		return;
110f80b69abSkettenis 	}
111f80b69abSkettenis 
112ded3bfd1Smpi 	if (bus_space_map(sc->sc_memt, regs[1] + 0x01000000,
113ded3bfd1Smpi 	    regs[2] - 0x01000000, 0, &sc->sc_config1_memh)) {
114f80b69abSkettenis 		printf(": can't map PCI config1 memory\n");
115f80b69abSkettenis 		return;
116f80b69abSkettenis 	}
117f80b69abSkettenis 
118f80b69abSkettenis 	if (bus_space_map(sc->sc_iot, regs[4], 0x1000, 0,
119f80b69abSkettenis 	    &sc->sc_config0_ioh)) {
120f80b69abSkettenis 		printf(": can't map PCI config0 io\n");
121f80b69abSkettenis 		return;
122f80b69abSkettenis 	}
123f80b69abSkettenis 
124f80b69abSkettenis 	len = OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
125f80b69abSkettenis 	if (len <= 0)
126e1ac7eb5Skettenis 		printf(": unknown");
127f80b69abSkettenis 	else
128e1ac7eb5Skettenis 		printf(": %s", compat);
129f80b69abSkettenis 
130f80b69abSkettenis 	sc->sc_pc.pc_conf_v = sc;
1312d3c312aSmpi 	sc->sc_pc.pc_node = ca->ca_node;
132f80b69abSkettenis 	sc->sc_pc.pc_conf_read = ht_conf_read;
133f80b69abSkettenis 	sc->sc_pc.pc_conf_write = ht_conf_write;
134f80b69abSkettenis 
1354eb8f200Skettenis 	bzero(&pba, sizeof(pba));
136f80b69abSkettenis 	pba.pba_busname = "pci";
137f80b69abSkettenis 	pba.pba_iot = sc->sc_iot;
138f80b69abSkettenis 	pba.pba_memt = sc->sc_memt;
139f80b69abSkettenis 	pba.pba_dmat = &pci_bus_dma_tag;
140f80b69abSkettenis 	pba.pba_pc = &sc->sc_pc;
141d307f358Skettenis 	pba.pba_domain = pci_ndomains++;
142f80b69abSkettenis 	pba.pba_bus = 0;
143f80b69abSkettenis 
144e6dadaadSderaadt 	printf(", %d devices\n", sc->sc_maxdevs);
145e1ac7eb5Skettenis 
146f80b69abSkettenis 	config_found(self, &pba, ht_print);
147f80b69abSkettenis }
148f80b69abSkettenis 
149f80b69abSkettenis pcireg_t
ht_conf_read(void * cpv,pcitag_t tag,int offset)150f80b69abSkettenis ht_conf_read(void *cpv, pcitag_t tag, int offset)
151f80b69abSkettenis {
152f80b69abSkettenis 	struct ht_softc *sc = cpv;
153f80b69abSkettenis 	int bus, dev, fcn;
154f80b69abSkettenis 	pcireg_t reg;
1552d3c312aSmpi 	uint32_t val;
156f80b69abSkettenis 
1572d3c312aSmpi 	val = PCITAG_OFFSET(tag);
158f80b69abSkettenis #ifdef DEBUG
1592d3c312aSmpi 	printf("ht_conf_read: tag=%x, offset=%x\n", val, offset);
160f80b69abSkettenis #endif
1612d3c312aSmpi 	pci_decompose_tag(NULL, tag, &bus, &dev, &fcn);
162f80b69abSkettenis 	if (bus == 0 && dev == 0) {
1632d3c312aSmpi 		val |= (offset << 2);
1642d3c312aSmpi 		reg = bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val);
165f80b69abSkettenis 		reg = letoh32(reg);
166f80b69abSkettenis 	} else if (bus == 0) {
167a4203404Skettenis 		/* XXX Why can we only access function 0? */
168a4203404Skettenis 		if (fcn > 0)
169f80b69abSkettenis 			return ~0;
1702d3c312aSmpi 		val |= offset;
1712d3c312aSmpi 		reg = bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val);
172f80b69abSkettenis 	} else {
1732d3c312aSmpi 		val |= offset;
1742d3c312aSmpi 		reg = bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val);
175f80b69abSkettenis 	}
176f80b69abSkettenis #ifdef DEBUG
177f80b69abSkettenis 	printf("ht_conf_read: reg=%x\n", reg);
178f80b69abSkettenis #endif
179f80b69abSkettenis 	return reg;
180f80b69abSkettenis }
181f80b69abSkettenis 
182f80b69abSkettenis void
ht_conf_write(void * cpv,pcitag_t tag,int offset,pcireg_t data)183f80b69abSkettenis ht_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
184f80b69abSkettenis {
185f80b69abSkettenis 	struct ht_softc *sc = cpv;
186a4203404Skettenis 	int bus, dev, fcn;
1872d3c312aSmpi 	uint32_t val;
188f80b69abSkettenis 
1892d3c312aSmpi 	val = PCITAG_OFFSET(tag);
190f80b69abSkettenis #ifdef DEBUG
191f80b69abSkettenis 	printf("ht_conf_write: tag=%x, offset=%x, data = %x\n",
1922d3c312aSmpi 	       val, offset, data);
193f80b69abSkettenis #endif
1942d3c312aSmpi 	pci_decompose_tag(NULL, tag, &bus, &dev, &fcn);
195f80b69abSkettenis 	if (bus == 0 && dev == 0) {
1962d3c312aSmpi 		val |= (offset << 2);
197f80b69abSkettenis 		data = htole32(data);
1982d3c312aSmpi 		bus_space_write_4(sc->sc_iot, sc->sc_config0_ioh, val, data);
1992d3c312aSmpi 		bus_space_read_4(sc->sc_iot, sc->sc_config0_ioh, val);
200f80b69abSkettenis 	} else if (bus == 0) {
201a4203404Skettenis 		/* XXX Why can we only access function 0? */
202a4203404Skettenis 		if (fcn > 0)
203a4203404Skettenis 			return;
2042d3c312aSmpi 		val |= offset;
2052d3c312aSmpi 		bus_space_write_4(sc->sc_memt, sc->sc_config0_memh, val, data);
2062d3c312aSmpi 		bus_space_read_4(sc->sc_memt, sc->sc_config0_memh, val);
207f80b69abSkettenis 	} else {
2082d3c312aSmpi 		val |= offset;
2092d3c312aSmpi 		bus_space_write_4(sc->sc_memt, sc->sc_config1_memh, val, data);
2102d3c312aSmpi 		bus_space_read_4(sc->sc_memt, sc->sc_config1_memh, val);
211f80b69abSkettenis 	}
212f80b69abSkettenis }
213f80b69abSkettenis 
214f80b69abSkettenis int
ht_print(void * aux,const char * pnp)215f80b69abSkettenis ht_print(void *aux, const char *pnp)
216f80b69abSkettenis {
217f80b69abSkettenis 	struct pcibus_attach_args *pba = aux;
218f80b69abSkettenis 
219f80b69abSkettenis 	if (pnp)
220f80b69abSkettenis 		printf("%s at %s", pba->pba_busname, pnp);
221f80b69abSkettenis 	printf(" bus %d", pba->pba_bus);
222f80b69abSkettenis 	return (UNCONF);
223f80b69abSkettenis }
224