1/*	$OpenBSD: arm64_bus_space.c,v 1.8 2021/02/16 12:33:22 kettenis Exp $ */
2
3/*
4 * Copyright (c) 2001-2003 Opsycon AB  (www.opsycon.se / www.opsycon.com)
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
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29/*
30 * Simple generic bus access primitives.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35
36#include <machine/bus.h>
37#include <uvm/uvm_extern.h>
38
39bus_space_t arm64_bs_tag = {
40	.bus_base = 0ULL, // XXX
41	.bus_private = NULL,
42	._space_read_1 =	generic_space_read_1,
43	._space_write_1 =	generic_space_write_1,
44	._space_read_2 =	generic_space_read_2,
45	._space_write_2 =	generic_space_write_2,
46	._space_read_4 =	generic_space_read_4,
47	._space_write_4 =	generic_space_write_4,
48	._space_read_8 =	generic_space_read_8,
49	._space_write_8 =	generic_space_write_8,
50	._space_read_raw_2 =	generic_space_read_raw_2,
51	._space_write_raw_2 =	generic_space_write_raw_2,
52	._space_read_raw_4 =	generic_space_read_raw_4,
53	._space_write_raw_4 =	generic_space_write_raw_4,
54	._space_read_raw_8 =	generic_space_read_raw_8,
55	._space_write_raw_8 =	generic_space_write_raw_8,
56	._space_map =		generic_space_map,
57	._space_unmap =		generic_space_unmap,
58	._space_subregion =	generic_space_region,
59	._space_vaddr =		generic_space_vaddr,
60	._space_mmap =		generic_space_mmap
61};
62bus_space_t *fdt_cons_bs_tag = &arm64_bs_tag;
63
64uint8_t
65generic_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
66{
67	return *(volatile uint8_t *)(h + o);
68}
69
70uint16_t
71generic_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
72{
73	return *(volatile uint16_t *)(h + o);
74}
75
76uint32_t
77generic_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
78{
79	return *(volatile uint32_t *)(h + o);
80}
81
82uint64_t
83generic_space_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
84{
85	return *(volatile uint64_t *)(h + o);
86}
87
88void
89generic_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
90    uint8_t v)
91{
92	*(volatile uint8_t *)(h + o) = v;
93}
94
95void
96generic_space_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
97    uint16_t v)
98{
99	*(volatile uint16_t *)(h + o) = v;
100}
101
102void
103generic_space_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
104    uint32_t v)
105{
106	*(volatile uint32_t *)(h + o) = v;
107}
108
109void
110generic_space_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
111    uint64_t v)
112{
113	*(volatile uint64_t *)(h + o) = v;
114}
115
116void
117generic_space_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
118    uint8_t *buf, bus_size_t len)
119{
120	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
121	len >>= 1;
122	while (len-- != 0) {
123		*(uint16_t *)buf = *addr;
124		buf += 2;
125	}
126}
127
128void
129generic_space_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
130    const uint8_t *buf, bus_size_t len)
131{
132	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
133	len >>= 1;
134	while (len-- != 0) {
135		*addr = *(uint16_t *)buf;
136		buf += 2;
137	}
138}
139
140void
141generic_space_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
142    uint8_t *buf, bus_size_t len)
143{
144	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
145	len >>= 2;
146	while (len-- != 0) {
147		*(uint32_t *)buf = *addr;
148		buf += 4;
149	}
150}
151
152void
153generic_space_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
154    const uint8_t *buf, bus_size_t len)
155{
156	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
157	len >>= 2;
158	while (len-- != 0) {
159		*addr = *(uint32_t *)buf;
160		buf += 4;
161	}
162}
163
164void
165generic_space_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
166    uint8_t *buf, bus_size_t len)
167{
168	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
169	len >>= 3;
170	while (len-- != 0) {
171		*(uint64_t *)buf = *addr;
172		buf += 8;
173	}
174}
175
176void
177generic_space_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
178    const uint8_t *buf, bus_size_t len)
179{
180	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
181	len >>= 3;
182	while (len-- != 0) {
183		*addr = *(uint64_t *)buf;
184		buf += 8;
185	}
186}
187
188int
189generic_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
190    int flags, bus_space_handle_t *bshp)
191{
192	u_long startpa, endpa, pa;
193	vaddr_t va;
194	int cache = PMAP_CACHE_DEV_NGNRNE;
195
196	if (flags & BUS_SPACE_MAP_CACHEABLE)
197		cache = PMAP_CACHE_WB;
198	if (flags & BUS_SPACE_MAP_POSTED)
199		cache = PMAP_CACHE_DEV_NGNRE;
200
201	startpa = trunc_page(offs);
202	endpa = round_page(offs + size);
203
204	va = (vaddr_t)km_alloc(endpa - startpa, &kv_any, &kp_none, &kd_nowait);
205	if (! va)
206		return(ENOMEM);
207
208	*bshp = (bus_space_handle_t)(va + (offs - startpa));
209
210	for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
211		pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, cache);
212	}
213	pmap_update(pmap_kernel());
214
215	return(0);
216}
217
218void
219generic_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
220{
221	vaddr_t	va, endva;
222
223	va = trunc_page((vaddr_t)bsh);
224	endva = round_page((vaddr_t)bsh + size);
225
226	pmap_kremove(va, endva - va);
227	pmap_update(pmap_kernel());
228	km_free((void *)va, endva - va, &kv_any, &kp_none);
229}
230
231int
232generic_space_region(bus_space_tag_t t, bus_space_handle_t bsh,
233    bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
234{
235	*nbshp = bsh + offset;
236	return 0;
237}
238
239void *
240generic_space_vaddr(bus_space_tag_t t, bus_space_handle_t h)
241{
242	return (void *)h;
243}
244
245paddr_t
246generic_space_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off,
247    int prot, int flags)
248{
249	return (addr + off);
250}
251