1/* $FreeBSD$ */
2/*	$NecBSD: busiosubr.c,v 1.30.4.4 1999/08/28 02:25:35 honda Exp $	*/
3/*	$NetBSD$	*/
4
5/*-
6 * [NetBSD for NEC PC-98 series]
7 *  Copyright (c) 1996, 1997, 1998
8 *	NetBSD/pc98 porting staff. All rights reserved.
9 *
10 * [Ported for FreeBSD]
11 *  Copyright (c) 2001
12 *	TAKAHASHI Yoshihiro. All rights reserved.
13 *
14 *  Redistribution and use in source and binary forms, with or without
15 *  modification, are permitted provided that the following conditions
16 *  are met:
17 *  1. Redistributions of source code must retain the above copyright
18 *     notice, this list of conditions and the following disclaimer.
19 *  2. Redistributions in binary form must reproduce the above copyright
20 *     notice, this list of conditions and the following disclaimer in the
21 *     documentation and/or other materials provided with the distribution.
22 *  3. The name of the author may not be used to endorse or promote products
23 *     derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * Copyright (c) 1997, 1998
40 *	Naofumi HONDA.  All rights reserved.
41 */
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#include <machine/bus.h>
48
49static MALLOC_DEFINE(M_BUSSPACEHANDLE, "busspacehandle", "Bus space handle");
50
51_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int8_t,1)
52_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int16_t,2)
53_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_io,u_int32_t,4)
54_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int8_t,1)
55_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int16_t,2)
56_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_DA_mem,u_int32_t,4)
57
58_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int8_t,1)
59_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int16_t,2)
60_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_io,u_int32_t,4)
61_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int8_t,1)
62_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int16_t,2)
63_BUS_SPACE_CALL_FUNCS_PROTO(SBUS_RA_mem,u_int32_t,4)
64
65struct bus_space_tag SBUS_io_space_tag = {
66	BUS_SPACE_TAG_IO,
67
68	/* direct bus access methods */
69	{
70		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int8_t,1),
71		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int16_t,2),
72		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int32_t,4),
73	},
74
75	/* relocate bus access methods */
76	{
77		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int8_t,1),
78		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int16_t,2),
79		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int32_t,4),
80	}
81};
82
83struct bus_space_tag SBUS_mem_space_tag = {
84	BUS_SPACE_TAG_MEM,
85
86	/* direct bus access methods */
87	{
88		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int8_t,1),
89		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int16_t,2),
90		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int32_t,4),
91	},
92
93	/* relocate bus access methods */
94	{
95		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int8_t,1),
96		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int16_t,2),
97		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int32_t,4),
98	}
99};
100
101
102#include "opt_mecia.h"
103#ifdef DEV_MECIA
104
105_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_DA_io,u_int16_t,2)
106_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_DA_io,u_int32_t,4)
107
108_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_RA_io,u_int16_t,2)
109_BUS_SPACE_CALL_FUNCS_PROTO(NEPC_RA_io,u_int32_t,4)
110
111struct bus_space_tag NEPC_io_space_tag = {
112	BUS_SPACE_TAG_IO,
113
114	/* direct bus access methods */
115	{
116		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_io,u_int8_t,1),
117		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_DA_io,u_int16_t,2),
118		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_DA_io,u_int32_t,4),
119	},
120
121	/* relocate bus access methods */
122	{
123		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_io,u_int8_t,1),
124		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_RA_io,u_int16_t,2),
125		_BUS_SPACE_CALL_FUNCS_TAB(NEPC_RA_io,u_int32_t,4),
126	}
127};
128
129struct bus_space_tag NEPC_mem_space_tag = {
130	BUS_SPACE_TAG_MEM,
131
132	/* direct bus access methods */
133	{
134		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int8_t,1),
135		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int16_t,2),
136		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_DA_mem,u_int32_t,4),
137	},
138
139	/* relocate bus access methods */
140	{
141		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int8_t,1),
142		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int16_t,2),
143		_BUS_SPACE_CALL_FUNCS_TAB(SBUS_RA_mem,u_int32_t,4),
144	}
145};
146
147#endif /* DEV_MECIA */
148
149/*************************************************************************
150 * map init
151 *************************************************************************/
152static __inline void
153bus_space_iat_init(bus_space_handle_t bsh)
154{
155	int i;
156
157	for (i = 0; i < bsh->bsh_maxiatsz; i++)
158		bsh->bsh_iat[i] = bsh->bsh_base + i;
159}
160
161/*************************************************************************
162 * handle allocation
163 *************************************************************************/
164int
165i386_bus_space_handle_alloc(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
166			    bus_space_handle_t *bshp)
167{
168	bus_space_handle_t bsh;
169
170	bsh = (bus_space_handle_t) malloc(sizeof (*bsh), M_BUSSPACEHANDLE,
171					  M_NOWAIT | M_ZERO);
172	if (bsh == NULL)
173		return ENOMEM;
174
175	bsh->bsh_maxiatsz = BUS_SPACE_IAT_MAXSIZE;
176	bsh->bsh_iatsz = 0;
177	bsh->bsh_base = bpa;
178	bsh->bsh_sz = size;
179	bsh->bsh_res = NULL;
180	bsh->bsh_ressz = 0;
181	bus_space_iat_init(bsh);
182
183	bsh->bsh_bam = t->bs_da;		/* default: direct access */
184
185	*bshp = bsh;
186	return 0;
187}
188
189void
190i386_bus_space_handle_free(bus_space_tag_t t, bus_space_handle_t bsh,
191			   size_t size)
192{
193
194	free(bsh, M_BUSSPACEHANDLE);
195}
196
197/*************************************************************************
198 * map
199 *************************************************************************/
200int
201i386_memio_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, int flags,
202	       bus_space_handle_t *bshp)
203{
204
205	return i386_bus_space_handle_alloc(t, bpa, size, bshp);
206}
207
208void
209i386_memio_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
210{
211
212	i386_bus_space_handle_free(t, bsh, bsh->bsh_sz);
213}
214
215void
216i386_memio_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
217{
218
219	/* i386_memio_unmap() does all that we need to do. */
220	i386_memio_unmap(t, bsh, bsh->bsh_sz);
221}
222
223int
224i386_memio_map_load(bus_space_tag_t t, bus_space_handle_t bsh,
225		    bus_size_t size, bus_space_iat_t iat, u_int flags __unused)
226{
227	int i;
228
229	if (size > bsh->bsh_maxiatsz) {
230		printf("i386_memio_map_load: map size too large\n");
231		return EINVAL;
232	}
233
234	for (i = 0; i < bsh->bsh_maxiatsz; i++) {
235		if (i < size)
236			bsh->bsh_iat[i] = iat[i];
237		else
238			bsh->bsh_iat[i] = 0;
239		bsh->bsh_iat[i] += bsh->bsh_base;
240	}
241
242	bsh->bsh_iatsz = size;
243	bsh->bsh_bam = t->bs_ra;	/* relocate access */
244
245	return 0;
246}
247
248int
249i386_memio_subregion(bus_space_tag_t t, bus_space_handle_t pbsh,
250		     bus_size_t offset, bus_size_t size,
251		     bus_space_handle_t *tbshp)
252{
253	int i, error = 0;
254	bus_space_handle_t bsh;
255	bus_addr_t pbase;
256
257	pbase = pbsh->bsh_base + offset;
258	switch (t->bs_tag) {
259	case BUS_SPACE_TAG_IO:
260		if (pbsh->bsh_iatsz > 0) {
261			if (offset >= pbsh->bsh_iatsz ||
262			    offset + size > pbsh->bsh_iatsz)
263				return EINVAL;
264			pbase = pbsh->bsh_base;
265		}
266		break;
267
268	case BUS_SPACE_TAG_MEM:
269		if (pbsh->bsh_iatsz > 0)
270			return EINVAL;
271		if (offset > pbsh->bsh_sz || offset + size > pbsh->bsh_sz)
272			return EINVAL;
273		break;
274
275	default:
276		panic("i386_memio_subregion: bad bus space tag");
277		break;
278	}
279
280	error = i386_bus_space_handle_alloc(t, pbase, size, &bsh);
281	if (error != 0)
282		return error;
283
284	switch (t->bs_tag) {
285	case BUS_SPACE_TAG_IO:
286		if (pbsh->bsh_iatsz > 0) {
287			for (i = 0; i < size; i ++)
288				bsh->bsh_iat[i] = pbsh->bsh_iat[i + offset];
289			bsh->bsh_iatsz = size;
290		} else if (pbsh->bsh_base > bsh->bsh_base ||
291		         pbsh->bsh_base + pbsh->bsh_sz <
292		         bsh->bsh_base + bsh->bsh_sz) {
293			i386_bus_space_handle_free(t, bsh, size);
294			return EINVAL;
295		}
296		break;
297
298	case BUS_SPACE_TAG_MEM:
299		break;
300	}
301
302	if (pbsh->bsh_iatsz > 0)
303		bsh->bsh_bam = t->bs_ra;	/* relocate access */
304	*tbshp = bsh;
305	return error;
306}
307
308int
309i386_memio_compare(bus_space_tag_t t1, bus_space_handle_t bsh1,
310		   bus_space_tag_t t2, bus_space_handle_t bsh2)
311{
312	int i;
313
314	if (t1->bs_tag != t2->bs_tag)
315		return (1);
316	if (bsh1->bsh_base != bsh2->bsh_base)
317		return (1);
318	if (bsh1->bsh_sz != bsh2->bsh_sz)
319		return (1);
320	if (bsh1->bsh_bam.bs_read_1 != bsh2->bsh_bam.bs_read_1)	/* XXX */
321		return (1);
322
323	if (bsh1->bsh_iatsz != bsh2->bsh_iatsz)
324		return (1);
325	for (i = 0; i < bsh1->bsh_iatsz; i++) {
326		if (bsh1->bsh_iat[i] != bsh2->bsh_iat[i])
327			return (1);
328	}
329
330	return (0);
331}
332