mpc85xx.c revision 291008
1/*-
2 * Copyright (C) 2008 Semihalf, Rafal Jaworowski
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/mpc85xx.c 291008 2015-11-18 01:54:19Z jhibbits $");
29
30#include "opt_platform.h"
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/lock.h>
34#include <sys/mutex.h>
35#include <sys/rman.h>
36
37#include <vm/vm.h>
38#include <vm/vm_param.h>
39
40#include <machine/cpu.h>
41#include <machine/cpufunc.h>
42#include <machine/pio.h>
43#include <machine/spr.h>
44
45#include <dev/fdt/fdt_common.h>
46
47#include <powerpc/mpc85xx/mpc85xx.h>
48
49
50/*
51 * MPC85xx system specific routines
52 */
53
54uint32_t
55ccsr_read4(uintptr_t addr)
56{
57	volatile uint32_t *ptr = (void *)addr;
58
59	return (*ptr);
60}
61
62void
63ccsr_write4(uintptr_t addr, uint32_t val)
64{
65	volatile uint32_t *ptr = (void *)addr;
66
67	*ptr = val;
68	powerpc_iomb();
69}
70
71int
72law_getmax(void)
73{
74	uint32_t ver;
75	int law_max;
76
77	ver = SVR_VER(mfspr(SPR_SVR));
78	switch (ver) {
79	case SVR_MPC8555:
80	case SVR_MPC8555E:
81		law_max = 8;
82		break;
83	case SVR_MPC8533:
84	case SVR_MPC8533E:
85	case SVR_MPC8548:
86	case SVR_MPC8548E:
87		law_max = 10;
88		break;
89	case SVR_P5020:
90	case SVR_P5020E:
91		law_max = 32;
92		break;
93	default:
94		law_max = 8;
95	}
96
97	return (law_max);
98}
99
100static inline void
101law_write(uint32_t n, uint64_t bar, uint32_t sr)
102{
103#if defined(QORIQ_DPAA)
104	ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32);
105	ccsr_write4(OCP85XX_LAWBARL(n), bar);
106#else
107	ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12);
108#endif
109	ccsr_write4(OCP85XX_LAWSR(n), sr);
110
111	/*
112	 * The last write to LAWAR should be followed by a read
113	 * of LAWAR before any device try to use any of windows.
114	 * What more the read of LAWAR should be followed by isync
115	 * instruction.
116	 */
117
118	ccsr_read4(OCP85XX_LAWSR(n));
119	isync();
120}
121
122static inline void
123law_read(uint32_t n, uint64_t *bar, uint32_t *sr)
124{
125#if defined(QORIQ_DPAA)
126	*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 |
127	    ccsr_read4(OCP85XX_LAWBARL(n));
128#else
129	*bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12;
130#endif
131	*sr = ccsr_read4(OCP85XX_LAWSR(n));
132}
133
134static int
135law_find_free(void)
136{
137	uint32_t i,sr;
138	uint64_t bar;
139	int law_max;
140
141	law_max = law_getmax();
142	/* Find free LAW */
143	for (i = 0; i < law_max; i++) {
144		law_read(i, &bar, &sr);
145		if ((sr & 0x80000000) == 0)
146			break;
147	}
148
149	return (i);
150}
151
152#define	_LAW_SR(trgt,size)	(0x80000000 | (trgt << 20) | (ffsl(size) - 2))
153
154int
155law_enable(int trgt, uint64_t bar, uint32_t size)
156{
157	uint64_t bar_tmp;
158	uint32_t sr, sr_tmp;
159	int i, law_max;
160
161	if (size == 0)
162		return (0);
163
164	law_max = law_getmax();
165	sr = _LAW_SR(trgt, size);
166
167	/* Bail if already programmed. */
168	for (i = 0; i < law_max; i++) {
169		law_read(i, &bar_tmp, &sr_tmp);
170		if (sr == sr_tmp && bar == bar_tmp)
171			return (0);
172	}
173
174	/* Find an unused access window. */
175	i = law_find_free();
176
177	if (i == law_max)
178		return (ENOSPC);
179
180	law_write(i, bar, sr);
181	return (0);
182}
183
184int
185law_disable(int trgt, uint64_t bar, uint32_t size)
186{
187	uint64_t bar_tmp;
188	uint32_t sr, sr_tmp;
189	int i, law_max;
190
191	law_max = law_getmax();
192	sr = _LAW_SR(trgt, size);
193
194	/* Find and disable requested LAW. */
195	for (i = 0; i < law_max; i++) {
196		law_read(i, &bar_tmp, &sr_tmp);
197		if (sr == sr_tmp && bar == bar_tmp) {
198			law_write(i, 0, 0);
199			return (0);
200		}
201	}
202
203	return (ENOENT);
204}
205
206int
207law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
208{
209	u_long start;
210	uint32_t ver;
211	int trgt, rv;
212
213	ver = SVR_VER(mfspr(SPR_SVR));
214
215	start = rman_get_start(res) & 0xf000;
216
217	rv = 0;
218	trgt = -1;
219	switch (start) {
220	case 0x0000:
221	case 0x8000:
222		trgt = 0;
223		break;
224	case 0x1000:
225	case 0x9000:
226		trgt = 1;
227		break;
228	case 0x2000:
229	case 0xa000:
230		if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
231			trgt = 3;
232		else
233			trgt = 2;
234		break;
235	case 0x3000:
236	case 0xb000:
237		if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
238			rv = EINVAL;
239		else
240			trgt = 3;
241		break;
242	default:
243		rv = ENXIO;
244	}
245	if (rv == 0) {
246		*trgt_mem = trgt;
247		*trgt_io = trgt;
248	}
249	return (rv);
250}
251
252