xref: /netbsd/sys/arch/arm/marvell/pci_machdep.c (revision 6550d01e)
1 /*	$NetBSD: pci_machdep.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $	*/
2 /*
3  * Copyright (c) 2008 KIYOHARA Takashi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $");
30 
31 #include "opt_mvsoc.h"
32 #include "gtpci.h"
33 #include "mvpex.h"
34 #include "pci.h"
35 
36 #include <sys/param.h>
37 #include <sys/device.h>
38 #include <sys/extent.h>
39 
40 #include <dev/pci/pcivar.h>
41 #include <dev/pci/pciconf.h>
42 
43 #include <arm/marvell/mvsocreg.h>
44 #include <arm/marvell/mvsocvar.h>
45 #include <arm/marvell/mvsocgppvar.h>
46 #if NGTPCI > 0
47 #include <dev/marvell/gtpcireg.h>
48 #include <dev/marvell/gtpcivar.h>
49 #endif
50 #if NMVPEX > 0
51 #include <dev/marvell/mvpexreg.h>
52 #include <dev/marvell/mvpexvar.h>
53 #endif
54 
55 #include <machine/pci_machdep.h>
56 
57 #if defined(ORION)
58 #include <arm/marvell/orionreg.h>
59 #endif
60 #if defined(KIRKWOOD)
61 #include <arm/marvell/kirkwoodreg.h>
62 #endif
63 #include <dev/marvell/marvellreg.h>
64 
65 
66 #if NGTPCI > 0
67 #if NGTPCI_MBUS > 0
68 static pcireg_t gtpci_mbus_conf_read(void *, pcitag_t, int);
69 static void gtpci_mbus_conf_write(void *, pcitag_t, int, pcireg_t);
70 #endif
71 static int gtpci_gpp_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
72 static const char *gtpci_gpp_intr_string(void *, pci_intr_handle_t);
73 static const struct evcnt *gtpci_gpp_intr_evcnt(void *, pci_intr_handle_t);
74 static void *gtpci_gpp_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), void *);
75 static void gtpci_gpp_intr_disestablish(void *, void *);
76 
77 struct arm32_pci_chipset arm32_gtpci_chipset = {
78 	NULL,	/* conf_v */
79 	gtpci_attach_hook,
80 	gtpci_bus_maxdevs,
81 	gtpci_make_tag,
82 	gtpci_decompose_tag,
83 #if NGTPCI_MBUS > 0
84 	gtpci_mbus_conf_read,		/* XXXX: always this functions */
85 	gtpci_mbus_conf_write,
86 #else
87 	gtpci_conf_read,
88 	gtpci_conf_write,
89 #endif
90 	NULL,	/* intr_v */
91 	gtpci_gpp_intr_map,
92 	gtpci_gpp_intr_string,
93 	gtpci_gpp_intr_evcnt,
94 	gtpci_gpp_intr_establish,
95 	gtpci_gpp_intr_disestablish,
96 #ifdef __HAVE_PCI_CONF_HOOK
97 	gtpci_conf_hook,
98 #endif
99 };
100 #endif
101 
102 #if NMVPEX > 0
103 #if NMVPEX_MBUS > 0
104 static pcireg_t mvpex_mbus_conf_read(void *, pcitag_t, int);
105 #endif
106 
107 struct arm32_pci_chipset arm32_mvpex0_chipset = {
108 	NULL,	/* conf_v */
109 	mvpex_attach_hook,
110 	mvpex_bus_maxdevs,
111 	mvpex_make_tag,
112 	mvpex_decompose_tag,
113 #if NMVPEX_MBUS > 0
114 	mvpex_mbus_conf_read,		/* XXXX: always this functions */
115 #else
116 	mvpex_conf_read,
117 #endif
118 	mvpex_conf_write,
119 	NULL,	/* intr_v */
120 	mvpex_intr_map,
121 	mvpex_intr_string,
122 	mvpex_intr_evcnt,
123 	mvpex_intr_establish,
124 	mvpex_intr_disestablish,
125 #ifdef __HAVE_PCI_CONF_HOOK
126 	mvpex_conf_hook,
127 #endif
128 };
129 struct arm32_pci_chipset arm32_mvpex1_chipset = {
130 	NULL,	/* conf_v */
131 	mvpex_attach_hook,
132 	mvpex_bus_maxdevs,
133 	mvpex_make_tag,
134 	mvpex_decompose_tag,
135 #if NMVPEX_MBUS > 0
136 	mvpex_mbus_conf_read,		/* XXXX: always this functions */
137 #else
138 	mvpex_conf_read,
139 #endif
140 	mvpex_conf_write,
141 	NULL,	/* intr_v */
142 	mvpex_intr_map,
143 	mvpex_intr_string,
144 	mvpex_intr_evcnt,
145 	mvpex_intr_establish,
146 	mvpex_intr_disestablish,
147 #ifdef __HAVE_PCI_CONF_HOOK
148 	mvpex_conf_hook,
149 #endif
150 };
151 #endif
152 
153 
154 void
155 pci_conf_interrupt(pci_chipset_tag_t v, int bus, int dev, int pin, int swiz,
156 		   int *iline)
157 {
158 
159 	/* nothing */
160 }
161 
162 
163 #if NGTPCI > 0
164 #if NGTPCI_MBUS > 0
165 #define GTPCI_MBUS_CA		0x0c78	/* Configuration Address */
166 #define GTPCI_MBUS_CD		0x0c7c	/* Configuration Data */
167 
168 static pcireg_t
169 gtpci_mbus_conf_read(void *v, pcitag_t tag, int reg)
170 {
171 	struct gtpci_softc *sc = v;
172 	const pcireg_t addr = tag | reg;
173 
174 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA,
175 	    addr | GTPCI_CA_CONFIGEN);
176 	if ((addr | GTPCI_CA_CONFIGEN) !=
177 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA))
178 		return -1;
179 
180 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CD);
181 }
182 
183 static void
184 gtpci_mbus_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
185 {
186 	struct gtpci_softc *sc = v;
187 	pcireg_t addr = tag | (reg & 0xfc);
188 
189 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA,
190 	    addr | GTPCI_CA_CONFIGEN);
191 	if ((addr | GTPCI_CA_CONFIGEN) !=
192 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA))
193 		return;
194 
195 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CD, data);
196 }
197 #endif	/* NGTPCI_MBUS */
198 
199 /*
200  * We assume to use GPP interrupt as PCI interrupts.
201  *   pci_intr_map() shall returns number of GPP between 0 and 31.  However
202  *   returns 0xff, because we do not know the connected pin number for GPP
203  *   of your board.
204  *   pci_intr_string() shall returns string "gpp <num>".
205  *   pci_intr_establish() established interrupt in the pin of all GPP.
206  *   Moreover, the return value will be disregarded.  For instance, the
207  *   setting for interrupt is not done.
208  */
209 
210 /* ARGSUSED */
211 static int
212 gtpci_gpp_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
213 {
214 
215 	*ihp = pa->pa_intrpin;
216 	return 0;
217 }
218 
219 /* ARGSUSED */
220 static const char *
221 gtpci_gpp_intr_string(void *v, pci_intr_handle_t pin)
222 {
223 	struct gtpci_softc *sc = v;
224 	prop_array_t int2gpp;
225 	prop_object_t gpp;
226 	static char intrstr[8];
227 
228 	int2gpp = prop_dictionary_get(device_properties(sc->sc_dev), "int2gpp");
229 	gpp = prop_array_get(int2gpp, pin);
230 	sprintf(intrstr, "gpp %d", (int)prop_number_integer_value(gpp));
231 
232 	return intrstr;
233 }
234 
235 /* ARGSUSED */
236 static const struct evcnt *
237 gtpci_gpp_intr_evcnt(void *v, pci_intr_handle_t pin)
238 {
239 
240 	return NULL;
241 }
242 
243 static void *
244 gtpci_gpp_intr_establish(void *v, pci_intr_handle_t int_pin, int ipl,
245 		         int (*intrhand)(void *), void *intrarg)
246 {
247 	struct gtpci_softc *sc = v;
248 	prop_array_t int2gpp;
249 	prop_object_t gpp;
250 	int gpp_pin;
251 
252 	int2gpp = prop_dictionary_get(device_properties(sc->sc_dev), "int2gpp");
253 	gpp = prop_array_get(int2gpp, int_pin);
254 	gpp_pin = prop_number_integer_value(gpp);
255 	return mvsocgpp_intr_establish(gpp_pin, ipl, 0, intrhand, intrarg);
256 }
257 
258 static void
259 gtpci_gpp_intr_disestablish(void *v, void *ih)
260 {
261 
262 	mvsocgpp_intr_disestablish(ih);
263 }
264 #endif
265 
266 #if NMVPEX_MBUS > 0
267 static pcireg_t
268 mvpex_mbus_conf_read(void *v, pcitag_t tag, int reg)
269 {
270 	struct mvpex_softc *sc = v;
271 	pcireg_t addr, data, pci_cs;
272 	uint32_t stat;
273 	int bus, dev, func, pexbus, pexdev;
274 
275 	mvpex_decompose_tag(v, tag, &bus, &dev, &func);
276 
277 	stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_STAT);
278 	pexbus = MVPEX_STAT_PEXBUSNUM(stat);
279 	pexdev = MVPEX_STAT_PEXDEVNUM(stat);
280 	if (bus != pexbus || dev != pexdev)
281 		if (stat & MVPEX_STAT_DLDOWN)
282 			return -1;
283 
284 	if (bus == pexbus) {
285 		if (pexdev == 0) {
286 			if (dev != 1 && dev != pexdev)
287 				return -1;
288 		} else {
289 			if (dev != 0 && dev != pexdev)
290 				return -1;
291 		}
292 		if (func != 0)
293 			return -1;
294 	}
295 
296 	addr = ((reg & 0xf00) << 24)  | tag | (reg & 0xfc);
297 
298 #if defined(ORION)
299 	/*
300 	 * Guideline (GL# PCI Express-1) Erroneous Read Data on Configuration
301 	 * This guideline is relevant for all devices except of the following
302 	 * devices:
303 	 *     88F5281-BO and above, and 88F5181L-A0 and above
304 	 */
305 	if ((bus != pexbus || dev != pexdev) &&
306 	    !(sc->sc_model == MARVELL_ORION_2_88F5281 && sc->sc_rev == 1) &&
307 	    !(sc->sc_model == MARVELL_ORION_1_88F5181 && sc->sc_rev == 8)) {
308 
309 		/* PCI-Express configuration read work-around */
310 		/*
311 		 * We will use one of the Punit (AHBToMbus) windows to
312 		 * access the xbar and read the data from there
313 		 *
314 		 * Need to configure the 2 free Punit (AHB to MBus bridge)
315 		 * address decoding windows:
316 		 * Configure the flash Window to handle Configuration space
317 		 * requests for PEX0/1:
318 		 *
319 		 * Configuration transactions from the CPU should write/read
320 		 * the data to/from address of the form:
321 		 *	addr[31:28]: 0x5 (for PEX0) or 0x6 (for PEX1)
322 		 *	addr[27:24]: extended register number
323 		 *	addr[23:16]: bus number
324 		 *	addr[15:11]: device number
325 		 *	addr[10: 8]: function number
326 		 *	addr[ 7: 0]: register number
327 		 */
328 
329 		struct mvsoc_softc *soc =
330 		    device_private(device_parent(sc->sc_dev));;
331 		bus_space_handle_t pcicfg_ioh;
332 		uint32_t remapl, remaph, wc, pcicfg_addr, pcicfg_size;
333 		int window, target, attr, base, size, s;
334 		const int pex_pcicfg_tag =
335 		    (sc->sc_model == MARVELL_ORION_1_88F1181) ?
336 		    ORION_TAG_FLASH_CS : ORION_TAG_PEX0_MEM;
337 
338 		window = mvsoc_target(pex_pcicfg_tag,
339 		    &target, &attr, &base, &size);
340 		if (window >= nwindow) {
341 			aprint_error_dev(sc->sc_dev,
342 			    "can't read pcicfg space\n");
343 			return -1;
344 		}
345 
346 		s = splhigh();
347 
348 		remapl = remaph = 0;
349 		if (window == 0 || window == 1) {
350 			remapl = read_mlmbreg(MVSOC_MLMB_WRLR(window));
351 			remaph = read_mlmbreg(MVSOC_MLMB_WRHR(window));
352 		}
353 
354 		wc =
355 		    MVSOC_MLMB_WCR_WINEN			|
356 		    MVSOC_MLMB_WCR_ATTR(ORION_ATTR_PEX_CFG)	|
357 		    MVSOC_MLMB_WCR_TARGET((soc->sc_addr + sc->sc_offset) >> 16);
358 		if (sc->sc_model == MARVELL_ORION_1_88F1181) {
359 			pcicfg_addr = base;
360 			pcicfg_size = size;
361 		} else if (sc->sc_model == MARVELL_ORION_1_88F5182) {
362 #define PEX_PCICFG_RW_WA_BASE		0x50000000
363 #define PEX_PCICFG_RW_WA_5182_BASE	0xf0000000
364 #define PEX_PCICFG_RW_WA_SIZE		(16 * 1024 * 1024)
365 			pcicfg_addr = PEX_PCICFG_RW_WA_5182_BASE;
366 			pcicfg_size = PEX_PCICFG_RW_WA_SIZE;
367 		} else {
368 			pcicfg_addr = PEX_PCICFG_RW_WA_BASE;
369 			pcicfg_size = PEX_PCICFG_RW_WA_SIZE;
370 		}
371 		write_mlmbreg(MVSOC_MLMB_WCR(window),
372 		    wc | MVSOC_MLMB_WCR_SIZE(pcicfg_size));
373 		write_mlmbreg(MVSOC_MLMB_WBR(window), pcicfg_addr);
374 
375 		if (window == 0 || window == 1) {
376 			write_mlmbreg(MVSOC_MLMB_WRLR(window), pcicfg_addr);
377 			write_mlmbreg(MVSOC_MLMB_WRHR(window), 0);
378 		}
379 
380 		if (bus_space_map(sc->sc_iot, pcicfg_addr, pcicfg_size, 0,
381 		    &pcicfg_ioh) == 0) {
382 			data = bus_space_read_4(sc->sc_iot, pcicfg_ioh, addr);
383 			bus_space_unmap(sc->sc_iot, pcicfg_ioh, pcicfg_size);
384 		} else
385 			data = -1;
386 
387 		write_mlmbreg(MVSOC_MLMB_WCR(window),
388 		    MVSOC_MLMB_WCR_WINEN		|
389 		    MVSOC_MLMB_WCR_ATTR(attr)		|
390 		    MVSOC_MLMB_WCR_TARGET(target)	|
391 		    MVSOC_MLMB_WCR_SIZE(size));
392 		write_mlmbreg(MVSOC_MLMB_WBR(window), base);
393 		if (window == 0 || window == 1) {
394 			write_mlmbreg(MVSOC_MLMB_WRLR(window), remapl);
395 			write_mlmbreg(MVSOC_MLMB_WRHR(window), remaph);
396 		}
397 
398 		splx(s);
399 #else
400 	if (0) {
401 #endif
402 	} else {
403 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVPEX_CA,
404 		    addr | MVPEX_CA_CONFIGEN);
405 		if ((addr | MVPEX_CA_CONFIGEN) !=
406 		    bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_CA))
407 			return -1;
408 
409 		pci_cs = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
410 		    PCI_COMMAND_STATUS_REG);
411 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
412 		    PCI_COMMAND_STATUS_REG, pci_cs | PCI_STATUS_MASTER_ABORT);
413 
414 		data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_CD);
415 	}
416 
417 	return data;
418 }
419 #endif
420