1/* $OpenBSD: mcpcia.c,v 1.7 2022/03/13 08:04:13 mpi Exp $ */
2/* $NetBSD: mcpcia.c,v 1.20 2007/03/04 05:59:11 christos Exp $ */
3
4/*-
5 * Copyright (c) 1999 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * Copyright (c) 1998 by Matthew Jacob
36 * NASA AMES Research Center.
37 * All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 *    notice immediately at the beginning of the file, without modification,
44 *    this list of conditions, and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 *    notice, this list of conditions and the following disclaimer in the
47 *    documentation and/or other materials provided with the distribution.
48 * 3. The name of the author may not be used to endorse or promote products
49 *    derived from this software without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
55 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 */
63
64/*
65 * MCPCIA mcbus to PCI bus adapter
66 * found on AlphaServer 4100 systems.
67 */
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/device.h>
72#include <sys/malloc.h>
73
74#include <machine/autoconf.h>
75#include <machine/rpb.h>
76#include <machine/sysarch.h>
77
78#include <alpha/mcbus/mcbusreg.h>
79#include <alpha/mcbus/mcbusvar.h>
80#include <alpha/pci/mcpciareg.h>
81#include <alpha/pci/mcpciavar.h>
82#include <alpha/pci/pci_kn300.h>
83
84#define KV(_addr)	((caddr_t)ALPHA_PHYS_TO_K0SEG((_addr)))
85#define	MCPCIA_SYSBASE(mc)	\
86	((((unsigned long) (mc)->cc_gid) << MCBUS_GID_SHIFT) | \
87	 (((unsigned long) (mc)->cc_mid) << MCBUS_MID_SHIFT) | \
88	 (MCBUS_IOSPACE))
89
90#define	MCPCIA_PROBE(mid, gid)	\
91	badaddr((void *)KV(((((unsigned long) gid) << MCBUS_GID_SHIFT) | \
92	 (((unsigned long) mid) << MCBUS_MID_SHIFT) | \
93	 (MCBUS_IOSPACE) | MCPCIA_PCI_BRIDGE | _MCPCIA_PCI_REV)), \
94	sizeof(u_int32_t))
95
96int	mcpciamatch (struct device *, void *, void *);
97void	mcpciaattach (struct device *, struct device *, void *);
98void	mcpcia_config_cleanup (void);
99
100int	mcpciaprint (void *, const char *);
101
102const struct cfattach mcpcia_ca = {
103	sizeof(struct mcpcia_softc), mcpciamatch, mcpciaattach
104};
105
106struct cfdriver mcpcia_cd = {
107        NULL, "mcpcia", DV_DULL,
108};
109
110/*
111 * We have one statically-allocated mcpcia_config structure; this is
112 * the one used for the console (which, coincidentally, is the only
113 * MCPCIA with an EISA adapter attached to it).
114 */
115struct mcpcia_config mcpcia_console_configuration;
116
117int
118mcpciaprint(aux, pnp)
119       void *aux;
120       const char *pnp;
121{
122       register struct pcibus_attach_args *pba = aux;
123       /* only PCIs can attach to MCPCIA for now */
124       if (pnp)
125               printf("%s at %s", pba->pba_busname, pnp);
126       printf(" bus %d", pba->pba_bus);
127       return (UNCONF);
128}
129
130int
131mcpciamatch(parent, cf, aux)
132	struct device *parent;
133	void *cf;
134	void *aux;
135{
136	struct mcbus_dev_attach_args *ma = aux;
137
138	if (ma->ma_type == MCBUS_TYPE_PCI)
139		return (1);
140
141	return (0);
142}
143
144void
145mcpciaattach(parent, self, aux)
146	struct device *parent;
147	struct device *self;
148	void *aux;
149{
150	static int first = 1;
151	struct mcbus_dev_attach_args *ma = aux;
152	struct mcpcia_softc *mcp = (struct mcpcia_softc *)self;
153	struct mcpcia_config *ccp;
154	struct pcibus_attach_args pba;
155	u_int32_t ctl;
156
157	/*
158	 * Make sure this MCPCIA exists...
159	 */
160	if (MCPCIA_PROBE(ma->ma_mid, ma->ma_gid)) {
161		mcp->mcpcia_cc = NULL;
162		printf(" (not present)\n");
163		return;
164	}
165	printf("\n");
166
167	/*
168	 * Determine if we're the console's MCPCIA.
169	 */
170	if (ma->ma_mid == mcpcia_console_configuration.cc_mid &&
171	    ma->ma_gid == mcpcia_console_configuration.cc_gid)
172		ccp = &mcpcia_console_configuration;
173	else {
174		ccp = malloc(sizeof(*ccp), M_DEVBUF, M_WAITOK | M_ZERO);
175
176		ccp->cc_mid = ma->ma_mid;
177		ccp->cc_gid = ma->ma_gid;
178	}
179	mcp->mcpcia_cc = ccp;
180	ccp->cc_sc = mcp;
181
182	/* This initializes cc_sysbase so we can do register access. */
183	mcpcia_init0(ccp, 1);
184
185	ctl = REGVAL(MCPCIA_PCI_REV(ccp));
186	printf("%s: Horse rev %d, %s handed Saddle rev %d, CAP rev %d\n",
187	    mcp->mcpcia_dev.dv_xname, HORSE_REV(ctl),
188	    (SADDLE_TYPE(ctl) & 1) ? "right" : "left", SADDLE_REV(ctl),
189	    CAP_REV(ctl));
190
191	mcpcia_dma_init(ccp);
192
193	/*
194	 * Set up interrupts
195	 */
196	pci_kn300_pickintr(ccp, first);
197	first = 0;
198
199	/*
200	 * Attach PCI bus
201	 */
202	bzero(&pba, sizeof(pba));
203	pba.pba_busname = "pci";
204	pba.pba_iot = &ccp->cc_iot;
205	pba.pba_memt = &ccp->cc_memt;
206	pba.pba_dmat =
207	    alphabus_dma_get_tag(&ccp->cc_dmat_direct, ALPHA_BUS_PCI);
208	pba.pba_pc = &ccp->cc_pc;
209	pba.pba_domain = pci_ndomains++;
210	pba.pba_bus = 0;
211
212	config_found(self, &pba, mcpciaprint);
213
214	/*
215	 * Clear any errors that may have occurred during the probe
216	 * sequence.
217	 */
218	REGVAL(MCPCIA_CAP_ERR(ccp)) = 0xFFFFFFFF;
219	alpha_mb();
220}
221
222void
223mcpcia_init()
224{
225	struct mcpcia_config *ccp = &mcpcia_console_configuration;
226	int i;
227
228	/*
229	 * Look for all of the MCPCIAs on the system.  One of them
230	 * will have an EISA attached to it.  This MCPCIA is the
231	 * only one that can be used for the console.  Once we find
232	 * that one, initialize it.
233	 */
234	for (i = 0; i < MCPCIA_PER_MCBUS; i++) {
235		ccp->cc_mid = mcbus_mcpcia_probe_order[i];
236		/*
237		 * XXX If we ever support more than one MCBUS, we'll
238		 * XXX have to probe for them, and map them to unit
239		 * XXX numbers.
240		 */
241		ccp->cc_gid = MCBUS_GID_FROM_INSTANCE(0);
242		ccp->cc_sysbase = MCPCIA_SYSBASE(ccp);
243
244		if (badaddr((void *)ALPHA_PHYS_TO_K0SEG(MCPCIA_PCI_REV(ccp)),
245		    sizeof(u_int32_t)))
246			continue;
247
248		if (EISA_PRESENT(REGVAL(MCPCIA_PCI_REV(ccp)))) {
249			mcpcia_init0(ccp, 0);
250			return;
251		}
252	}
253
254	panic("mcpcia_init: unable to find EISA bus");
255}
256
257void
258mcpcia_init0(ccp, mallocsafe)
259	struct mcpcia_config *ccp;
260	int mallocsafe;
261{
262	u_int32_t ctl;
263
264	snprintf(ccp->pc_io_ex_name, sizeof ccp->pc_io_ex_name,
265	    "mcpcia%d_bus_io", ccp->cc_mid);
266	snprintf(ccp->pc_mem_dex_name, sizeof ccp->pc_mem_dex_name,
267	    "mcpciad%d_bus_mem", ccp->cc_mid);
268	snprintf(ccp->pc_mem_dex_name, sizeof ccp->pc_mem_sex_name,
269	    "mcpcias%d_bus_mem", ccp->cc_mid);
270
271	if (!ccp->cc_initted) {
272		/* don't do these twice since they set up extents */
273		mcpcia_bus_io_init(&ccp->cc_iot, ccp);
274		mcpcia_bus_mem_init(&ccp->cc_memt, ccp);
275	}
276	ccp->cc_mallocsafe = mallocsafe;
277
278	mcpcia_pci_init(&ccp->cc_pc, ccp);
279
280        /*
281         * Establish a precalculated base for convenience's sake.
282         */
283        ccp->cc_sysbase = MCPCIA_SYSBASE(ccp);
284
285        /*
286         * Disable interrupts and clear errors prior to probing
287         */
288        REGVAL(MCPCIA_INT_MASK0(ccp)) = 0;
289        REGVAL(MCPCIA_INT_MASK1(ccp)) = 0;
290        REGVAL(MCPCIA_CAP_ERR(ccp)) = 0xFFFFFFFF;
291        alpha_mb();
292
293        if (ccp == &mcpcia_console_configuration) {
294                /*
295                 * Use this opportunity to also find out the MID and CPU
296                 * type of the currently running CPU (that's us, billybob....)
297                 */
298                ctl = REGVAL(MCPCIA_WHOAMI(ccp));
299                mcbus_primary.mcbus_cpu_mid = MCBUS_CPU_MID(ctl);
300                if ((MCBUS_CPU_INFO(ctl) & CPU_Fill_Err) == 0 &&
301                    mcbus_primary.mcbus_valid == 0) {
302                        mcbus_primary.mcbus_bcache =
303                            MCBUS_CPU_INFO(ctl) & CPU_BCacheMask;
304                        mcbus_primary.mcbus_valid = 1;
305                }
306                alpha_mb();
307        }
308
309	alpha_pci_chipset = &ccp->cc_pc;
310	alpha_pci_chipset->pc_name = "mcpcia";
311	alpha_pci_chipset->pc_hae_mask = 0;
312	alpha_pci_chipset->pc_dense = MCPCIA_PCI_DENSE;
313
314        ccp->cc_initted = 1;
315}
316
317void
318mcpcia_config_cleanup()
319{
320	volatile u_int32_t ctl;
321	struct mcpcia_softc *mcp;
322	struct mcpcia_config *ccp;
323	int i;
324	extern struct cfdriver mcpcia_cd;
325
326	/*
327	 * Turn on Hard, Soft error interrupts. Maybe i2c too.
328	 */
329	for (i = 0; i < mcpcia_cd.cd_ndevs; i++) {
330		if ((mcp = mcpcia_cd.cd_devs[i]) == NULL)
331			continue;
332
333		ccp = mcp->mcpcia_cc;
334		if (ccp == NULL)
335			continue;
336
337		ctl = REGVAL(MCPCIA_INT_MASK0(ccp));
338		ctl |= MCPCIA_GEN_IENABL;
339		REGVAL(MCPCIA_INT_MASK0(ccp)) = ctl;
340		alpha_mb();
341
342		/* force stall while write completes */
343		ctl = REGVAL(MCPCIA_INT_MASK0(ccp));
344	}
345}
346