xref: /openbsd/sys/arch/riscv64/riscv64/bus_space.c (revision a3fd9ccd)
1 /*	$OpenBSD: bus_space.c,v 1.3 2024/03/27 23:10:18 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 
39 bus_space_t riscv64_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 };
62 bus_space_t *fdt_cons_bs_tag = &riscv64_bs_tag;
63 
64 uint8_t
generic_space_read_1(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)65 generic_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
66 {
67 	uint8_t val = *(volatile uint8_t *)(h + o);
68 	__asm volatile ("fence i,ir" ::: "memory");
69 	return val;
70 }
71 
72 uint16_t
generic_space_read_2(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)73 generic_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
74 {
75 	uint16_t val = *(volatile uint16_t *)(h + o);
76 	__asm volatile ("fence i,ir" ::: "memory");
77 	return val;
78 }
79 
80 uint32_t
generic_space_read_4(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)81 generic_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
82 {
83 	uint32_t val = *(volatile uint32_t *)(h + o);
84 	__asm volatile ("fence i,ir" ::: "memory");
85 	return val;
86 }
87 
88 uint64_t
generic_space_read_8(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o)89 generic_space_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
90 {
91 	uint64_t val = *(volatile uint64_t *)(h + o);
92 	__asm volatile ("fence i,ir" ::: "memory");
93 	return val;
94 }
95 
96 void
generic_space_write_1(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,uint8_t v)97 generic_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
98     uint8_t v)
99 {
100 	__asm volatile ("fence w,o" ::: "memory");
101 	*(volatile uint8_t *)(h + o) = v;
102 	__asm volatile ("fence o,w" ::: "memory");
103 }
104 
105 void
generic_space_write_2(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,uint16_t v)106 generic_space_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
107     uint16_t v)
108 {
109 	__asm volatile ("fence w,o" ::: "memory");
110 	*(volatile uint16_t *)(h + o) = v;
111 	__asm volatile ("fence o,w" ::: "memory");
112 }
113 
114 void
generic_space_write_4(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,uint32_t v)115 generic_space_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
116     uint32_t v)
117 {
118 	__asm volatile ("fence w,o" ::: "memory");
119 	*(volatile uint32_t *)(h + o) = v;
120 	__asm volatile ("fence o,w" ::: "memory");
121 }
122 
123 void
generic_space_write_8(bus_space_tag_t t,bus_space_handle_t h,bus_size_t o,uint64_t v)124 generic_space_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
125     uint64_t v)
126 {
127 	__asm volatile ("fence w,o" ::: "memory");
128 	*(volatile uint64_t *)(h + o) = v;
129 	__asm volatile ("fence o,w" ::: "memory");
130 }
131 
132 void
generic_space_read_raw_2(bus_space_tag_t t,bus_space_handle_t h,bus_addr_t o,uint8_t * buf,bus_size_t len)133 generic_space_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
134     uint8_t *buf, bus_size_t len)
135 {
136 	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
137 	len >>= 1;
138 	while (len-- != 0) {
139 		*(uint16_t *)buf = *addr;
140 		buf += 2;
141 	}
142 	__asm volatile ("fence i,ir" ::: "memory");
143 }
144 
145 void
generic_space_write_raw_2(bus_space_tag_t t,bus_space_handle_t h,bus_addr_t o,const uint8_t * buf,bus_size_t len)146 generic_space_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
147     const uint8_t *buf, bus_size_t len)
148 {
149 	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
150 	__asm volatile ("fence w,o" ::: "memory");
151 	len >>= 1;
152 	while (len-- != 0) {
153 		*addr = *(uint16_t *)buf;
154 		buf += 2;
155 	}
156 	__asm volatile ("fence o,w" ::: "memory");
157 }
158 
159 void
generic_space_read_raw_4(bus_space_tag_t t,bus_space_handle_t h,bus_addr_t o,uint8_t * buf,bus_size_t len)160 generic_space_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
161     uint8_t *buf, bus_size_t len)
162 {
163 	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
164 	len >>= 2;
165 	while (len-- != 0) {
166 		*(uint32_t *)buf = *addr;
167 		buf += 4;
168 	}
169 	__asm volatile ("fence i,ir" ::: "memory");
170 }
171 
172 void
generic_space_write_raw_4(bus_space_tag_t t,bus_space_handle_t h,bus_addr_t o,const uint8_t * buf,bus_size_t len)173 generic_space_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
174     const uint8_t *buf, bus_size_t len)
175 {
176 	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
177 	__asm volatile ("fence w,o" ::: "memory");
178 	len >>= 2;
179 	while (len-- != 0) {
180 		*addr = *(uint32_t *)buf;
181 		buf += 4;
182 	}
183 	__asm volatile ("fence o,w" ::: "memory");
184 }
185 
186 void
generic_space_read_raw_8(bus_space_tag_t t,bus_space_handle_t h,bus_addr_t o,uint8_t * buf,bus_size_t len)187 generic_space_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
188     uint8_t *buf, bus_size_t len)
189 {
190 	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
191 	len >>= 3;
192 	while (len-- != 0) {
193 		*(uint64_t *)buf = *addr;
194 		buf += 8;
195 	}
196 	__asm volatile ("fence i,ir" ::: "memory");
197 }
198 
199 void
generic_space_write_raw_8(bus_space_tag_t t,bus_space_handle_t h,bus_addr_t o,const uint8_t * buf,bus_size_t len)200 generic_space_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
201     const uint8_t *buf, bus_size_t len)
202 {
203 	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
204 	__asm volatile ("fence w,o" ::: "memory");
205 	len >>= 3;
206 	while (len-- != 0) {
207 		*addr = *(uint64_t *)buf;
208 		buf += 8;
209 	}
210 	__asm volatile ("fence o,w" ::: "memory");
211 }
212 
213 int
generic_space_map(bus_space_tag_t t,bus_addr_t offs,bus_size_t size,int flags,bus_space_handle_t * bshp)214 generic_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
215     int flags, bus_space_handle_t *bshp)
216 {
217 	u_long startpa, endpa, pa;
218 	vaddr_t va;
219 	int cache = flags & BUS_SPACE_MAP_CACHEABLE ?
220 	    PMAP_CACHE_WB : PMAP_CACHE_DEV;
221 
222 	startpa = trunc_page(offs);
223 	endpa = round_page(offs + size);
224 
225 	va = (vaddr_t)km_alloc(endpa - startpa, &kv_any, &kp_none, &kd_nowait);
226 	if (! va)
227 		return(ENOMEM);
228 
229 	*bshp = (bus_space_handle_t)(va + (offs - startpa));
230 
231 	for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
232 		pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, cache);
233 	}
234 	pmap_update(pmap_kernel());
235 
236 	return(0);
237 }
238 
239 void
generic_space_unmap(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t size)240 generic_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
241 {
242 	vaddr_t	va, endva;
243 
244 	va = trunc_page((vaddr_t)bsh);
245 	endva = round_page((vaddr_t)bsh + size);
246 
247 	pmap_kremove(va, endva - va);
248 	pmap_update(pmap_kernel());
249 	km_free((void *)va, endva - va, &kv_any, &kp_none);
250 }
251 
252 int
generic_space_region(bus_space_tag_t t,bus_space_handle_t bsh,bus_size_t offset,bus_size_t size,bus_space_handle_t * nbshp)253 generic_space_region(bus_space_tag_t t, bus_space_handle_t bsh,
254     bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
255 {
256 	*nbshp = bsh + offset;
257 	return 0;
258 }
259 
260 void *
generic_space_vaddr(bus_space_tag_t t,bus_space_handle_t h)261 generic_space_vaddr(bus_space_tag_t t, bus_space_handle_t h)
262 {
263 	return (void *)h;
264 }
265 
266 paddr_t
generic_space_mmap(bus_space_tag_t t,bus_addr_t addr,off_t off,int prot,int flags)267 generic_space_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off,
268     int prot, int flags)
269 {
270 	return (addr + off);
271 }
272