1/*	$NetBSD: bus_space.c,v 1.4 2008/04/28 20:23:18 martin Exp $	*/
2
3/*-
4 * Copyright (c) 2001, 2004, 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.4 2008/04/28 20:23:18 martin Exp $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/malloc.h>
35#include <sys/extent.h>
36
37#define	_EWS4800MIPS_BUS_SPACE_PRIVATE
38#include <machine/bus.h>
39#include <machine/sbdvar.h>
40
41#ifdef BUS_SPACE_DEBUG
42int	bus_space_debug = 0;
43#define	DPRINTF(fmt, args...)						\
44	if (bus_space_debug)						\
45		printf("%s: " fmt, __func__ , ##args)
46#define	DPRINTFN(n, arg)						\
47	if (bus_space_debug > (n))					\
48		printf("%s: " fmt, __func__ , ##args)
49#else
50#define	DPRINTF(arg...)		((void)0)
51#define	DPRINTFN(n, arg...)	((void)0)
52#endif
53
54#define	VADDR(h, o)	(h + o)
55_BUS_SPACE_READ(_default, 1, 8)
56_BUS_SPACE_READ(_default, 2, 16)
57_BUS_SPACE_READ(_default, 4, 32)
58_BUS_SPACE_READ(_default, 8, 64)
59_BUS_SPACE_READ_MULTI(_default, 1, 8)
60_BUS_SPACE_READ_MULTI(_default, 2, 16)
61_BUS_SPACE_READ_MULTI(_default, 4, 32)
62_BUS_SPACE_READ_MULTI(_default, 8, 64)
63_BUS_SPACE_READ_REGION(_default, 1, 8)
64_BUS_SPACE_READ_REGION(_default, 2, 16)
65_BUS_SPACE_READ_REGION(_default, 4, 32)
66_BUS_SPACE_READ_REGION(_default, 8, 64)
67_BUS_SPACE_WRITE(_default, 1, 8)
68_BUS_SPACE_WRITE(_default, 2, 16)
69_BUS_SPACE_WRITE(_default, 4, 32)
70_BUS_SPACE_WRITE(_default, 8, 64)
71_BUS_SPACE_WRITE_MULTI(_default, 1, 8)
72_BUS_SPACE_WRITE_MULTI(_default, 2, 16)
73_BUS_SPACE_WRITE_MULTI(_default, 4, 32)
74_BUS_SPACE_WRITE_MULTI(_default, 8, 64)
75_BUS_SPACE_WRITE_REGION(_default, 1, 8)
76_BUS_SPACE_WRITE_REGION(_default, 2, 16)
77_BUS_SPACE_WRITE_REGION(_default, 4, 32)
78_BUS_SPACE_WRITE_REGION(_default, 8, 64)
79_BUS_SPACE_SET_MULTI(_default, 1, 8)
80_BUS_SPACE_SET_MULTI(_default, 2, 16)
81_BUS_SPACE_SET_MULTI(_default, 4, 32)
82_BUS_SPACE_SET_MULTI(_default, 8, 64)
83_BUS_SPACE_SET_REGION(_default, 1, 8)
84_BUS_SPACE_SET_REGION(_default, 2, 16)
85_BUS_SPACE_SET_REGION(_default, 4, 32)
86_BUS_SPACE_SET_REGION(_default, 8, 64)
87_BUS_SPACE_COPY_REGION(_default, 1, 8)
88_BUS_SPACE_COPY_REGION(_default, 2, 16)
89_BUS_SPACE_COPY_REGION(_default, 4, 32)
90_BUS_SPACE_COPY_REGION(_default, 8, 64)
91#undef VADDR
92
93static int _default_map(void *, bus_addr_t, bus_size_t, int,
94    bus_space_handle_t *);
95static void _default_unmap(void *, bus_space_handle_t, bus_size_t);
96static int _default_subregion(void *, bus_space_handle_t, bus_size_t,
97    bus_size_t, bus_space_handle_t *);
98static int _default_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t,
99    bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *);
100static void _default_free(void *, bus_space_handle_t, bus_size_t);
101static void *_default_vaddr(void *, bus_space_handle_t);
102
103static const struct ews4800mips_bus_space _default_bus_space = {
104	.ebs_map	= _default_map,
105	.ebs_unmap	= _default_unmap,
106	.ebs_subregion	= _default_subregion,
107	.ebs_alloc	= _default_alloc,
108	.ebs_free	= _default_free,
109	.ebs_vaddr	= _default_vaddr,
110	.ebs_r_1	= _default_read_1,
111	.ebs_r_2	= _default_read_2,
112	.ebs_r_4	= _default_read_4,
113	.ebs_r_8	= _default_read_8,
114	.ebs_rm_1	= _default_read_multi_1,
115	.ebs_rm_2	= _default_read_multi_2,
116	.ebs_rm_4	= _default_read_multi_4,
117	.ebs_rm_8	= _default_read_multi_8,
118	.ebs_rr_1	= _default_read_region_1,
119	.ebs_rr_2	= _default_read_region_2,
120	.ebs_rr_4	= _default_read_region_4,
121	.ebs_rr_8	= _default_read_region_8,
122	.ebs_w_1	= _default_write_1,
123	.ebs_w_2	= _default_write_2,
124	.ebs_w_4	= _default_write_4,
125	.ebs_w_8	= _default_write_8,
126	.ebs_wm_1	= _default_write_multi_1,
127	.ebs_wm_2	= _default_write_multi_2,
128	.ebs_wm_4	= _default_write_multi_4,
129	.ebs_wm_8	= _default_write_multi_8,
130	.ebs_wr_1	= _default_write_region_1,
131	.ebs_wr_2	= _default_write_region_2,
132	.ebs_wr_4	= _default_write_region_4,
133	.ebs_wr_8	= _default_write_region_8,
134	.ebs_sm_1	= _default_set_multi_1,
135	.ebs_sm_2	= _default_set_multi_2,
136	.ebs_sm_4	= _default_set_multi_4,
137	.ebs_sm_8	= _default_set_multi_8,
138	.ebs_sr_1	= _default_set_region_1,
139	.ebs_sr_2	= _default_set_region_2,
140	.ebs_sr_4	= _default_set_region_4,
141	.ebs_sr_8	= _default_set_region_8,
142	.ebs_c_1	= _default_copy_region_1,
143	.ebs_c_2	= _default_copy_region_2,
144	.ebs_c_4	= _default_copy_region_4,
145	.ebs_c_8	= _default_copy_region_8
146};
147
148/* create default bus_space_tag */
149int
150bus_space_create(bus_space_tag_t t, const char *name,
151    bus_addr_t addr, bus_size_t size)
152{
153	struct ews4800mips_bus_space *ebs = t;
154
155	if (ebs == NULL)
156		return EFAULT;
157
158	/* set default method */
159	*ebs = _default_bus_space;	/* structure assignment */
160	ebs->ebs_cookie = ebs;
161
162	/* set access region */
163	if (size == 0) {
164		/* no extent */
165		ebs->ebs_base_addr = addr;
166		ebs->ebs_size = size;
167	} else {
168		ebs->ebs_extent = extent_create(name, addr, addr + size - 1,
169		    0, 0, EX_NOWAIT);
170		if (ebs->ebs_extent == NULL) {
171			panic("%s:: unable to create bus_space for "
172			    "0x%08lx-%#lx", __func__, addr, size);
173		}
174	}
175
176	return 0;
177}
178
179void
180bus_space_destroy(bus_space_tag_t t)
181{
182	struct ews4800mips_bus_space *ebs = t;
183	struct extent *ex = ebs->ebs_extent;
184
185	if (ex != NULL)
186		extent_destroy(ex);
187}
188
189void
190_bus_space_invalid_access(void)
191{
192
193	panic("invalid bus space access.");
194}
195
196/* default bus_space tag */
197static int
198_default_map(void *t, bus_addr_t bpa, bus_size_t size, int flags,
199    bus_space_handle_t *bshp)
200{
201	struct ews4800mips_bus_space *ebs = t;
202	struct extent *ex = ebs->ebs_extent;
203	int error;
204
205	if (ex == NULL) {
206		if (bpa + size > ebs->ebs_size)
207			return EFAULT;
208		*bshp = (bus_space_handle_t)(ebs->ebs_base_addr + bpa);
209		return 0;
210	}
211
212	bpa += ex->ex_start;
213	error = extent_alloc_region(ex, bpa, size, EX_NOWAIT | EX_MALLOCOK);
214
215	if (error) {
216		DPRINTF("failed.\n");
217		return error;
218	}
219
220	*bshp = (bus_space_handle_t)bpa;
221
222	DPRINTF("success.\n");
223
224	return 0;
225}
226
227static int
228_default_subregion(void *t, bus_space_handle_t bsh,
229    bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
230{
231
232	*nbshp = bsh + offset;
233
234	return 0;
235}
236
237static int
238_default_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
239    bus_size_t size, bus_size_t alignment, bus_size_t boundary,
240    int flags, bus_addr_t *bpap, bus_space_handle_t *bshp)
241{
242	struct ews4800mips_bus_space *ebs = t;
243	struct extent *ex = ebs->ebs_extent;
244	u_long bpa, base;
245	int error;
246
247	if (ex == NULL) {
248		if (rend > ebs->ebs_size)
249			return EFAULT;
250		*bshp = *bpap = rstart + ebs->ebs_base_addr;
251		return 0;
252	}
253
254	base = ex->ex_start;
255
256	error = extent_alloc_subregion(ex, rstart + base, rend + base, size,
257	    alignment, boundary,
258	    EX_FAST | EX_NOWAIT | EX_MALLOCOK,
259	    &bpa);
260
261	if (error) {
262		DPRINTF("failed.\n");
263		return error;
264	}
265
266	*bshp = (bus_space_handle_t)bpa;
267
268	if (bpap)
269		*bpap = bpa;
270
271	DPRINTF("success.\n");
272
273	return 0;
274}
275
276static void
277_default_free(void *t, bus_space_handle_t bsh, bus_size_t size)
278{
279	struct ews4800mips_bus_space *ebs = t;
280	struct extent *ex = ebs->ebs_extent;
281
282	if (ex != NULL)
283		_default_unmap(t, bsh, size);
284}
285
286static void
287_default_unmap(void *t, bus_space_handle_t bsh, bus_size_t size)
288{
289	struct ews4800mips_bus_space *ebs = t;
290	struct extent *ex = ebs->ebs_extent;
291	int error;
292
293	if (ex == NULL)
294		return;
295
296	error = extent_free(ex, bsh, size, EX_NOWAIT);
297
298	if (error) {
299		DPRINTF("%#lx-%#lx of %s space lost\n", bsh, bsh + size,
300		    ex->ex_name);
301	}
302}
303
304void *
305_default_vaddr(void *t, bus_space_handle_t h)
306{
307
308	return (void *)h;
309}
310