1/*	$NetBSD: txcsbus.c,v 1.20 2005/12/11 12:17:34 christos Exp $ */
2
3/*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: txcsbus.c,v 1.20 2005/12/11 12:17:34 christos Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/device.h>
38
39#include <machine/intr.h>
40#include <machine/bus.h>
41#include <machine/bus_space_hpcmips.h>
42
43#include <machine/platid.h>
44#include <machine/platid_mask.h>
45
46#include <hpcmips/tx/tx39var.h>
47#include <hpcmips/tx/txcsbusvar.h>
48#include <hpcmips/tx/tx39biuvar.h>
49#include <hpcmips/tx/tx39biureg.h>
50
51#include "locators.h"
52
53/* TX39 CS mapping. (nonconfigurationable) */
54const struct csmap {
55	const char *cs_name;
56	paddr_t	cs_addr;
57	psize_t	cs_size;
58} __csmap[] = {
59	[TX39_CS0]	= {"CS0(ROM)"	, TX39_SYSADDR_CS0	,
60			   TX39_SYSADDR_CS_SIZE},
61	[TX39_CS1]	= {"CS1"	, TX39_SYSADDR_CS1	,
62			   TX39_SYSADDR_CS_SIZE},
63	[TX39_CS2]	= {"CS2"	, TX39_SYSADDR_CS2	,
64			   TX39_SYSADDR_CS_SIZE},
65	[TX39_CS3]	= {"CS3"	, TX39_SYSADDR_CS3	,
66			   TX39_SYSADDR_CS_SIZE},
67	[TX39_MCS0]	= {"MCS0"	, TX39_SYSADDR_MCS0	,
68			   TX39_SYSADDR_MCS_SIZE},
69	[TX39_MCS1]	= {"MCS1"	, TX39_SYSADDR_MCS1	,
70			   TX39_SYSADDR_MCS_SIZE},
71#ifdef TX391X
72	[TX39_MCS2]	= {"MCS2"	, TX39_SYSADDR_MCS2	,
73			   TX39_SYSADDR_MCS_SIZE},
74	[TX39_MCS3]	= {"MCS3"	, TX39_SYSADDR_MCS3	,
75			   TX39_SYSADDR_MCS_SIZE},
76#endif /* TX391X */
77	[TX39_CARD1]	= {"CARD1(io/attr)", TX39_SYSADDR_CARD1	,
78			   TX39_SYSADDR_CARD_SIZE},
79	[TX39_CARD2]	= {"CARD2(io/attr)", TX39_SYSADDR_CARD2	,
80			   TX39_SYSADDR_CARD_SIZE},
81	[TX39_CARD1MEM]	= {"CARD1(mem)"	, TX39_SYSADDR_CARD1MEM	,
82			   TX39_SYSADDR_CARD_SIZE},
83	[TX39_CARD2MEM]	= {"CARD2(mem)"	, TX39_SYSADDR_CARD2MEM	,
84			   TX39_SYSADDR_CARD_SIZE},
85	[TX39_KUCS0]	= {"KUCS0"	, TX39_SYSADDR_KUSEG_CS0,
86			   TX39_SYSADDR_KUCS_SIZE},
87	[TX39_KUCS1]	= {"KUCS1"	, TX39_SYSADDR_KUSEG_CS1,
88			   TX39_SYSADDR_KUCS_SIZE},
89	[TX39_KUCS2]	= {"KUCS2"	, TX39_SYSADDR_KUSEG_CS2,
90			   TX39_SYSADDR_KUCS_SIZE},
91	[TX39_KUCS3]	= {"KUCS3"	, TX39_SYSADDR_KUSEG_CS3,
92			   TX39_SYSADDR_KUCS_SIZE},
93};
94
95int	txcsbus_match(struct device *, struct cfdata *, void *);
96void	txcsbus_attach(struct device *, struct device *, void *);
97int	txcsbus_print(void *, const char *);
98int	txcsbus_search(struct device *, struct cfdata *,
99		       const int *, void *);
100
101struct txcsbus_softc {
102	struct	device sc_dev;
103	tx_chipset_tag_t sc_tc;
104	/* chip select space tag */
105	struct bus_space_tag_hpcmips *sc_cst[TX39_MAXCS];
106	int sc_pri;
107};
108
109CFATTACH_DECL(txcsbus, sizeof(struct txcsbus_softc),
110    txcsbus_match, txcsbus_attach, NULL, NULL);
111
112static bus_space_tag_t __txcsbus_alloc_cstag(struct txcsbus_softc *,
113    struct cs_handle *);
114
115int
116txcsbus_match(struct device *parent, struct cfdata *cf, void *aux)
117{
118	struct csbus_attach_args *cba = aux;
119	platid_mask_t mask;
120
121	if (strcmp(cba->cba_busname, cf->cf_name))
122		return (0);
123
124	if (cf->cf_loc[TXCSBUSIFCF_PLATFORM] == TXCSBUSIFCF_PLATFORM_DEFAULT)
125		return (1);
126
127	mask = PLATID_DEREF(cf->cf_loc[TXCSBUSIFCF_PLATFORM]);
128	if (platid_match(&platid, &mask))
129		return (2);
130
131	return (0);
132}
133
134void
135txcsbus_attach(struct device *parent, struct device *self, void *aux)
136{
137	struct csbus_attach_args *cba = aux;
138	struct txcsbus_softc *sc = (void*)self;
139
140	sc->sc_tc = cba->cba_tc;
141	printf("\n");
142
143	/*
144	 *	Attach external chip.
145	 */
146	/* higher priority devices attach first */
147	sc->sc_pri = 2;
148	config_search_ia(txcsbus_search, self, "txcsbus", txcsbus_print);
149	/* then, normal priority devices */
150	sc->sc_pri = 1;
151	config_search_ia(txcsbus_search, self, "txcsbus", txcsbus_print);
152}
153
154int
155txcsbus_print(void *aux, const char *pnp)
156{
157#define PRINTIRQ(i) i, (i) / 32, (i) % 32
158	struct cs_attach_args *ca = aux;
159
160	if (ca->ca_csreg.cs != TXCSBUSCF_REGCS_DEFAULT) {
161		aprint_normal(" regcs %s %dbit %#x+%#x",
162		    __csmap[ca->ca_csreg.cs].cs_name,
163		    ca->ca_csreg.cswidth,
164		    ca->ca_csreg.csbase,
165		    ca->ca_csreg.cssize);
166	}
167
168	if (ca->ca_csio.cs != TXCSBUSCF_IOCS_DEFAULT) {
169		aprint_normal(" iocs %s %dbit %#x+%#x",
170		    __csmap[ca->ca_csio.cs].cs_name,
171		    ca->ca_csio.cswidth,
172		    ca->ca_csio.csbase,
173		    ca->ca_csio.cssize);
174	}
175
176	if (ca->ca_csmem.cs != TXCSBUSCF_MEMCS_DEFAULT) {
177		aprint_normal(" memcs %s %dbit %#x+%#x",
178		    __csmap[ca->ca_csmem.cs].cs_name,
179		    ca->ca_csmem.cswidth,
180		    ca->ca_csmem.csbase,
181		    ca->ca_csmem.cssize);
182	}
183
184	if (ca->ca_irq1 != TXCSBUSCF_IRQ1_DEFAULT) {
185		aprint_normal(" irq1 %d(%d:%d)", PRINTIRQ(ca->ca_irq1));
186	}
187
188	if (ca->ca_irq2 != TXCSBUSCF_IRQ2_DEFAULT) {
189		aprint_normal(" irq2 %d(%d:%d)", PRINTIRQ(ca->ca_irq2));
190	}
191
192	if (ca->ca_irq3 != TXCSBUSCF_IRQ3_DEFAULT) {
193		aprint_normal(" irq3 %d(%d:%d)", PRINTIRQ(ca->ca_irq3));
194	}
195
196	return (UNCONF);
197}
198
199int
200txcsbus_search(struct device *parent, struct cfdata *cf,
201	       const int *ldesc, void *aux)
202{
203	struct txcsbus_softc *sc = (void*)parent;
204	struct cs_attach_args ca;
205
206	ca.ca_tc		= sc->sc_tc;
207
208	ca.ca_csreg.cs		= cf->cf_loc[TXCSBUSCF_REGCS];
209	ca.ca_csreg.csbase	= cf->cf_loc[TXCSBUSCF_REGCSBASE];
210	ca.ca_csreg.cssize	= cf->cf_loc[TXCSBUSCF_REGCSSIZE];
211	ca.ca_csreg.cswidth	= cf->cf_loc[TXCSBUSCF_REGCSWIDTH];
212
213	if (ca.ca_csreg.cs != TXCSBUSCF_REGCS_DEFAULT) {
214		ca.ca_csreg.cstag = __txcsbus_alloc_cstag(sc, &ca.ca_csreg);
215	}
216
217	ca.ca_csio.cs		= cf->cf_loc[TXCSBUSCF_IOCS];
218	ca.ca_csio.csbase	= cf->cf_loc[TXCSBUSCF_IOCSBASE];
219	ca.ca_csio.cssize	= cf->cf_loc[TXCSBUSCF_IOCSSIZE];
220	ca.ca_csio.cswidth	= cf->cf_loc[TXCSBUSCF_IOCSWIDTH];
221
222	if (ca.ca_csio.cs != TXCSBUSCF_IOCS_DEFAULT) {
223		ca.ca_csio.cstag = __txcsbus_alloc_cstag(sc, &ca.ca_csio);
224	}
225
226	ca.ca_csmem.cs		= cf->cf_loc[TXCSBUSCF_MEMCS];
227	ca.ca_csmem.csbase	= cf->cf_loc[TXCSBUSCF_MEMCSBASE];
228	ca.ca_csmem.cssize	= cf->cf_loc[TXCSBUSCF_MEMCSSIZE];
229	ca.ca_csmem.cswidth	= cf->cf_loc[TXCSBUSCF_MEMCSWIDTH];
230
231	if (ca.ca_csmem.cs != TXCSBUSCF_MEMCS_DEFAULT) {
232		ca.ca_csmem.cstag = __txcsbus_alloc_cstag(sc, &ca.ca_csmem);
233	}
234
235	ca.ca_irq1		= cf->cf_loc[TXCSBUSCF_IRQ1];
236	ca.ca_irq2		= cf->cf_loc[TXCSBUSCF_IRQ2];
237	ca.ca_irq3		= cf->cf_loc[TXCSBUSCF_IRQ3];
238
239	if (config_match(parent, cf, &ca) == sc->sc_pri) {
240		config_attach(parent, cf, &ca, txcsbus_print);
241	}
242
243	return (0);
244}
245
246bus_space_tag_t
247__txcsbus_alloc_cstag(struct txcsbus_softc *sc, struct cs_handle *csh)
248{
249
250	tx_chipset_tag_t tc = sc->sc_tc;
251	int cs = csh->cs;
252	int width = csh->cswidth;
253	struct bus_space_tag_hpcmips *iot;
254	txreg_t reg;
255
256 	if (!TX39_ISCS(cs) && !TX39_ISMCS(cs) && !TX39_ISCARD(cs) &&
257	    !TX39_ISKUCS(cs)) {
258		panic("txcsbus_alloc_tag: bogus chip select %d", cs);
259	}
260
261	/* Already setuped chip select */
262	if (sc->sc_cst[cs]) {
263		return (&sc->sc_cst[cs]->bst);
264	}
265
266	iot = hpcmips_alloc_bus_space_tag();
267	hpcmips_init_bus_space(iot, hpcmips_system_bus_space_hpcmips(),
268	    __csmap[cs].cs_name, __csmap[cs].cs_addr, __csmap[cs].cs_size);
269	sc->sc_cst[cs] = iot;
270
271	/* CS bus-width (configurationable) */
272	switch (width) {
273	default:
274		panic("txcsbus_alloc_tag: bogus bus width %d", width);
275
276	case 32:
277		if (TX39_ISCS(cs)) {
278			reg = tx_conf_read(tc, TX39_MEMCONFIG0_REG);
279			reg |= (1 << cs);
280			tx_conf_write(tc, TX39_MEMCONFIG0_REG, reg);
281		} else if(TX39_ISMCS(cs)) {
282#ifdef TX391X
283			panic("txcsbus_alloc_tag: MCS is 16bit only");
284#endif /* TX391X */
285#ifdef TX392X
286			reg = tx_conf_read(tc, TX39_MEMCONFIG1_REG);
287			reg |= ((cs == TX39_MCS0) ?
288			    TX39_MEMCONFIG1_MCS0_32 :
289			    TX39_MEMCONFIG1_MCS1_32);
290			tx_conf_write(tc, TX39_MEMCONFIG1_REG, reg);
291#endif /* TX392X */
292		}
293		break;
294
295	case 16:
296		if (TX39_ISCS(cs)) {
297			reg = tx_conf_read(tc, TX39_MEMCONFIG0_REG);
298			reg &= ~(1 << cs);
299			tx_conf_write(tc, TX39_MEMCONFIG0_REG, reg);
300		} else if(TX39_ISMCS(cs)) {
301			/* TX391X always 16bit port */
302#ifdef TX392X
303			reg = tx_conf_read(tc, TX39_MEMCONFIG1_REG);
304			reg &= ~((cs == TX39_MCS0) ?
305			    TX39_MEMCONFIG1_MCS0_32 :
306			    TX39_MEMCONFIG1_MCS1_32);
307			tx_conf_write(tc, TX39_MEMCONFIG1_REG, reg);
308#endif /* TX392X */
309		} else if (TX39_ISCARD(cs)) {
310			/* CARD io/attr or mem */
311			reg = tx_conf_read(tc, TX39_MEMCONFIG3_REG);
312
313			/* enable I/O access */
314			reg |= (cs == TX39_CARD1) ?
315			    TX39_MEMCONFIG3_CARD1IOEN :
316			    TX39_MEMCONFIG3_CARD2IOEN;
317			/* disable 8bit access */
318#ifdef TX392X
319			reg &= ~((cs == TX39_CARD1) ?
320			    TX39_MEMCONFIG3_CARD1_8SEL :
321			    TX39_MEMCONFIG3_CARD2_8SEL);
322#endif /* TX392X */
323#ifdef TX391X
324			reg &= ~TX39_MEMCONFIG3_PORT8SEL;
325#endif /* TX391X */
326			tx_conf_write(tc, TX39_MEMCONFIG3_REG, reg);
327		}
328		break;
329
330	case 8:
331		if (TX39_ISCARD(cs)) {
332			reg = tx_conf_read(tc, TX39_MEMCONFIG3_REG);
333
334			/* enable I/O access */
335			reg |= (cs == TX39_CARD1) ?
336			    TX39_MEMCONFIG3_CARD1IOEN :
337			    TX39_MEMCONFIG3_CARD2IOEN;
338			/* disable 8bit access */
339#ifdef TX392X
340			reg |= (cs == TX39_CARD1) ?
341			    TX39_MEMCONFIG3_CARD1_8SEL :
342			    TX39_MEMCONFIG3_CARD2_8SEL;
343#endif /* TX392X */
344#ifdef TX391X
345			reg |= TX39_MEMCONFIG3_PORT8SEL;
346#endif /* TX391X */
347			tx_conf_write(tc, TX39_MEMCONFIG3_REG, reg);
348
349		} else {
350			panic("__txcsbus_alloc_cstag: CS%d 8bit mode is"
351			    "not allowed", cs);
352		}
353	}
354
355	return (&iot->bst);
356}
357