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