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