1 /* $NetBSD: adm5120_cfio.c,v 1.2 2011/07/01 18:38:48 dyoung Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 David Young. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or 7 * without modification, are permitted provided that the following 8 * conditions 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 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 3. The name of the author may not be used to endorse or promote 16 * products derived from this software without specific prior 17 * written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 26 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 * OF SUCH DAMAGE. 31 */ 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: adm5120_cfio.c,v 1.2 2011/07/01 18:38:48 dyoung Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 39 #include <sys/bus.h> 40 41 #include <mips/cache.h> 42 #include <mips/cpuregs.h> 43 44 #include <mips/adm5120/include/adm5120reg.h> 45 #include <mips/adm5120/include/adm5120var.h> 46 #include <mips/adm5120/include/adm5120_mainbusvar.h> 47 #include <mips/adm5120/include/adm5120_extiovar.h> 48 49 #ifdef CFIO_DEBUG 50 int cfio_debug = 1; 51 #define CFIO_DPRINTF(__fmt, ...) \ 52 do { \ 53 if (cfio_debug) \ 54 printf((__fmt), __VA_ARGS__); \ 55 } while (/*CONSTCOND*/0) 56 #else /* !CFIO_DEBUG */ 57 #define CFIO_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0) 58 #endif /* CFIO_DEBUG */ 59 60 static struct { 61 bus_space_handle_t ch_handle[2]; 62 int ch_inuse; 63 int ch_parent; 64 } cf_handles[16]; 65 66 static int cf_handle_alloc(int); 67 static void cf_handle_free(int); 68 static void cf_bs_unmap(void *, bus_space_handle_t, bus_size_t, int); 69 static int cf_bs_map(void *, bus_addr_t, bus_size_t, int, 70 bus_space_handle_t *, int); 71 static int cf_bs_subregion(void *, bus_space_handle_t, bus_size_t, 72 bus_size_t, bus_space_handle_t *); 73 static int cf_bs_translate(void *, bus_addr_t, bus_size_t, int, 74 struct mips_bus_space_translation *); 75 static int cf_bs_get_window(void *, int, struct mips_bus_space_translation *); 76 static int cf_bs_translate(void *, bus_addr_t, bus_size_t, int, 77 struct mips_bus_space_translation *); 78 static int cf_bs_get_window(void *, int, struct mips_bus_space_translation *); 79 static int cf_bs_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t, bus_size_t, 80 bus_size_t, int, bus_addr_t *, bus_space_handle_t *); 81 static void cf_bs_free(void *, bus_space_handle_t, bus_size_t size); 82 static void *cf_bs_vaddr(void *, bus_space_handle_t); 83 static paddr_t cf_bs_mmap(void *, bus_addr_t, off_t off, int prot, int); 84 static void cf_bs_barrier(void *, bus_space_handle_t, bus_size_t, 85 bus_size_t length, int); 86 static uint8_t cf_bs_r_1(void *, bus_space_handle_t, bus_size_t offset); 87 static void cf_bs_rm_1(void *, bus_space_handle_t, bus_size_t, 88 uint8_t *, bus_size_t); 89 static void cf_bs_w_1(void *, bus_space_handle_t, bus_size_t, uint8_t val); 90 static void cf_bs_wm_1(void *, bus_space_handle_t, bus_size_t, 91 const uint8_t *, bus_size_t); 92 static uint8_t cf_bs_rs_1(void *, bus_space_handle_t, bus_size_t offset); 93 static void cf_bs_rms_1(void *, bus_space_handle_t, bus_size_t, 94 uint8_t *, bus_size_t); 95 static void cf_bs_ws_1(void *, bus_space_handle_t, bus_size_t, uint8_t val); 96 static void cf_bs_wms_1(void *, bus_space_handle_t, bus_size_t, const uint8_t *, 97 bus_size_t); 98 static void cf_bs_sm_1(void *, bus_space_handle_t, bus_size_t, uint8_t, 99 bus_size_t); 100 101 static const struct mips_bus_space cfio_space = { 102 /* cookie */ 103 .bs_cookie = NULL, 104 105 /* mapping/unmapping */ 106 .bs_map = cf_bs_map, 107 .bs_unmap = cf_bs_unmap, 108 .bs_subregion = cf_bs_subregion, 109 110 .bs_translate = cf_bs_translate, 111 .bs_get_window = cf_bs_get_window, 112 .bs_alloc = cf_bs_alloc, 113 .bs_free = cf_bs_free, 114 .bs_vaddr = cf_bs_vaddr, 115 .bs_mmap = cf_bs_mmap, 116 .bs_barrier = cf_bs_barrier, 117 .bs_r_1 = cf_bs_r_1, 118 .bs_r_2 = NULL, 119 .bs_r_4 = NULL, 120 .bs_r_8 = NULL, 121 .bs_rm_1 = cf_bs_rm_1, 122 .bs_rm_2 = NULL, 123 .bs_rm_4 = NULL, 124 .bs_rm_8 = NULL, 125 .bs_rr_1 = NULL, 126 .bs_rr_2 = NULL, 127 .bs_rr_4 = NULL, 128 .bs_rr_8 = NULL, 129 .bs_w_1 = cf_bs_w_1, 130 .bs_w_2 = NULL, 131 .bs_w_4 = NULL, 132 .bs_w_8 = NULL, 133 134 .bs_wm_1 = cf_bs_wm_1, 135 .bs_wm_2 = NULL, 136 .bs_wm_4 = NULL, 137 .bs_wm_8 = NULL, 138 139 .bs_wr_1 = NULL, 140 .bs_wr_2 = NULL, 141 .bs_wr_4 = NULL, 142 .bs_wr_8 = NULL, 143 144 /* read (single) stream */ 145 .bs_rs_1 = cf_bs_rs_1, 146 .bs_rs_2 = NULL, 147 .bs_rs_4 = NULL, 148 .bs_rs_8 = NULL, 149 150 /* read multiple stream */ 151 .bs_rms_1 = cf_bs_rms_1, 152 .bs_rms_2 = NULL, 153 .bs_rms_4 = NULL, 154 .bs_rms_8 = NULL, 155 156 /* read region stream */ 157 .bs_rrs_1 = NULL, 158 .bs_rrs_2 = NULL, 159 .bs_rrs_4 = NULL, 160 .bs_rrs_8 = NULL, 161 162 /* write (single) stream */ 163 .bs_ws_1 = cf_bs_ws_1, 164 .bs_ws_2 = NULL, 165 .bs_ws_4 = NULL, 166 .bs_ws_8 = NULL, 167 168 /* write multiple stream */ 169 .bs_wms_1 = cf_bs_wms_1, 170 .bs_wms_2 = NULL, 171 .bs_wms_4 = NULL, 172 .bs_wms_8 = NULL, 173 174 /* write region stream */ 175 .bs_wrs_1 = NULL, 176 .bs_wrs_2 = NULL, 177 .bs_wrs_4 = NULL, 178 .bs_wrs_8 = NULL, 179 180 /* set multiple */ 181 .bs_sm_1 = cf_bs_sm_1, 182 .bs_sm_2 = NULL, 183 .bs_sm_4 = NULL, 184 .bs_sm_8 = NULL, 185 186 /* set region */ 187 .bs_sr_1 = NULL, 188 .bs_sr_2 = NULL, 189 .bs_sr_4 = NULL, 190 .bs_sr_8 = NULL, 191 192 /* copy */ 193 .bs_c_1 = NULL, 194 .bs_c_2 = NULL, 195 .bs_c_4 = NULL, 196 .bs_c_8 = NULL, 197 }; 198 199 void 200 cfio_bus_mem_init(bus_space_tag_t cfio, bus_space_tag_t extio) 201 { 202 *cfio = cfio_space; 203 cfio->bs_cookie = (void *)extio; 204 } 205 206 static void 207 cf_bs_unmap(void *cookie, bus_space_handle_t bh, bus_size_t size, int acct) 208 { 209 KASSERT(acct == 1); 210 bus_space_unmap((bus_space_tag_t)cookie, 211 cf_handles[bh].ch_handle[1], size); 212 bus_space_unmap((bus_space_tag_t)cookie, 213 cf_handles[bh].ch_handle[0], size); 214 cf_handle_free(bh); 215 } 216 217 static void 218 cf_handle_free(int which) 219 { 220 int i, parent; 221 222 KASSERT(cf_handles[which].ch_inuse); 223 for (i = 0; i < __arraycount(cf_handles); i++) { 224 for (parent = cf_handles[i].ch_parent; parent != -1; 225 parent = cf_handles[parent].ch_parent) { 226 if (parent == which) { 227 CFIO_DPRINTF("%s: free %d (ancestor %d)\n", 228 __func__, i, which); 229 cf_handles[i].ch_inuse = 0; 230 break; 231 } 232 } 233 } 234 cf_handles[which].ch_inuse = 0; 235 for (i = 0; i < __arraycount(cf_handles); i++) { 236 if (!cf_handles[i].ch_inuse) 237 cf_handles[i].ch_parent = -1; 238 } 239 } 240 241 static int 242 cf_handle_alloc(int parent) 243 { 244 int i; 245 246 for (i = 0; i < __arraycount(cf_handles) && cf_handles[i].ch_inuse; i++) 247 ; 248 if (i >= __arraycount(cf_handles)) 249 return -1; 250 cf_handles[i].ch_inuse = 1; 251 cf_handles[i].ch_parent = parent; 252 return i; 253 } 254 255 static int 256 cf_bs_map(void *cookie, bus_addr_t addr, bus_size_t size, int flags, 257 bus_space_handle_t *bhp, int acct) 258 { 259 int bh, rc; 260 261 KASSERT(acct == 1); 262 263 if ((bh = cf_handle_alloc(-1)) == -1) 264 return EBUSY; 265 266 rc = bus_space_map((bus_space_tag_t)cookie, 267 addr + ADM5120_BASE_EXTIO1 - ADM5120_BASE_EXTIO0, size, flags, 268 &cf_handles[bh].ch_handle[1]); 269 if (rc != 0) 270 return rc; 271 272 rc = bus_space_map((bus_space_tag_t)cookie, addr, size, flags, 273 &cf_handles[bh].ch_handle[0]); 274 if (rc != 0) { 275 bus_space_unmap((bus_space_tag_t)cookie, 276 cf_handles[bh].ch_handle[1], size); 277 cf_handle_free(bh); 278 } else 279 *bhp = bh; 280 281 return rc; 282 } 283 284 static int 285 cf_bs_subregion(void *cookie, bus_space_handle_t h, bus_size_t offset, 286 bus_size_t size, bus_space_handle_t *bhp) 287 { 288 int bh, rc; 289 290 if ((bh = cf_handle_alloc(h)) == -1) 291 return EBUSY; 292 293 rc = bus_space_subregion((bus_space_tag_t)cookie, 294 cf_handles[h].ch_handle[1], offset, size, 295 &cf_handles[bh].ch_handle[1]); 296 if (rc != 0) 297 return rc; 298 299 rc = bus_space_subregion((bus_space_tag_t)cookie, 300 cf_handles[h].ch_handle[0], offset, size, 301 &cf_handles[bh].ch_handle[0]); 302 if (rc != 0) 303 cf_handle_free(bh); 304 else 305 *bhp = bh; 306 307 return rc; 308 } 309 310 static int 311 cf_bs_translate(void *cookie, bus_addr_t addr, bus_size_t len, int flags, 312 struct mips_bus_space_translation *mbst) 313 { 314 panic("%s: not implemented\n", __func__); 315 } 316 317 static int 318 cf_bs_get_window(void *cookie, int window, 319 struct mips_bus_space_translation *mbst) 320 { 321 panic("%s: not implemented\n", __func__); 322 } 323 324 static int 325 cf_bs_alloc(void *cookie, bus_addr_t reg_start, 326 bus_addr_t reg_end, bus_size_t size, bus_size_t alignment, 327 bus_size_t boundary, int flags, bus_addr_t *addrp, 328 bus_space_handle_t *bhp) 329 { 330 bus_addr_t tmp; 331 int bh, rc; 332 333 if ((bh = cf_handle_alloc(-1)) == -1) 334 return EBUSY; 335 336 rc = bus_space_alloc((bus_space_tag_t)cookie, 337 reg_start + ADM5120_BASE_EXTIO1 - ADM5120_BASE_EXTIO0, 338 reg_end + ADM5120_BASE_EXTIO1 - ADM5120_BASE_EXTIO0, 339 size, alignment, boundary, flags, &tmp, 340 &cf_handles[bh].ch_handle[1]); 341 if (rc != 0) 342 return rc; 343 344 rc = bus_space_alloc((bus_space_tag_t)cookie, reg_start, reg_end, size, 345 alignment, boundary, flags, addrp, &cf_handles[bh].ch_handle[0]); 346 if (rc != 0) { 347 bus_space_free((bus_space_tag_t)cookie, 348 cf_handles[bh].ch_handle[1], size); 349 cf_handle_free(bh); 350 } else 351 *bhp = bh; 352 353 return rc; 354 } 355 356 static void 357 cf_bs_free(void *cookie, bus_space_handle_t bh, bus_size_t size) 358 { 359 bus_space_free((bus_space_tag_t)cookie, cf_handles[bh].ch_handle[0], 360 size); 361 bus_space_free((bus_space_tag_t)cookie, cf_handles[bh].ch_handle[1], 362 size); 363 cf_handle_free(bh); 364 } 365 366 static void * 367 cf_bs_vaddr(void *cookie, bus_space_handle_t bh) 368 { 369 panic("%s: not implemented", __func__); 370 } 371 372 static paddr_t 373 cf_bs_mmap(void *cookie, bus_addr_t addr, off_t off, int prot, int flags) 374 { 375 panic("%s: not implemented", __func__); 376 } 377 378 static void 379 cf_bs_barrier(void *cookie, bus_space_handle_t bh, bus_size_t offset, 380 bus_size_t length, int flags) 381 { 382 bus_space_barrier((bus_space_tag_t)cookie, cf_handles[bh].ch_handle[0], 383 offset, length, flags); 384 bus_space_barrier((bus_space_tag_t)cookie, cf_handles[bh].ch_handle[1], 385 offset, length, flags); 386 } 387 388 /* read (single) */ 389 static uint8_t 390 cf_bs_r_1(void *cookie, bus_space_handle_t bh, bus_size_t offset) 391 { 392 (void)bus_space_read_1((bus_space_tag_t)cookie, 393 cf_handles[bh].ch_handle[0], offset); 394 return bus_space_read_1((bus_space_tag_t)cookie, 395 cf_handles[bh].ch_handle[1], offset); 396 } 397 398 /* read multiple */ 399 static void 400 cf_bs_rm_1(void *cookie, bus_space_handle_t bh, bus_size_t offset, 401 uint8_t *datap, bus_size_t count) 402 { 403 while (count-- > 0) 404 *datap++ = cf_bs_r_1(cookie, bh, offset); 405 } 406 407 /* write (single) */ 408 static void 409 cf_bs_w_1(void *cookie, bus_space_handle_t bh, bus_size_t offset, uint8_t val) 410 { 411 bus_space_write_1((bus_space_tag_t)cookie, cf_handles[bh].ch_handle[0], 412 offset, val); 413 bus_space_write_1((bus_space_tag_t)cookie, cf_handles[bh].ch_handle[1], 414 offset, val); 415 } 416 417 /* write multiple */ 418 static void 419 cf_bs_wm_1(void *cookie, bus_space_handle_t bh, bus_size_t offset, 420 const uint8_t *datap, bus_size_t count) 421 { 422 while (count-- > 0) 423 cf_bs_w_1(cookie, bh, offset, *datap++); 424 } 425 426 /* read (single) stream */ 427 static uint8_t 428 cf_bs_rs_1(void *cookie, bus_space_handle_t bh, bus_size_t offset) 429 { 430 (void)bus_space_read_stream_1((bus_space_tag_t)cookie, 431 cf_handles[bh].ch_handle[0], offset); 432 return bus_space_read_stream_1((bus_space_tag_t)cookie, 433 cf_handles[bh].ch_handle[1], offset); 434 } 435 436 /* read multiple stream */ 437 static void 438 cf_bs_rms_1(void *cookie, bus_space_handle_t bh, bus_size_t offset, 439 uint8_t *datap, bus_size_t count) 440 { 441 while (count-- > 0) 442 *datap++ = cf_bs_rs_1(cookie, bh, offset); 443 } 444 445 /* write (single) stream */ 446 static void 447 cf_bs_ws_1(void *cookie, bus_space_handle_t bh, bus_size_t offset, uint8_t val) 448 { 449 bus_space_write_stream_1((bus_space_tag_t)cookie, 450 cf_handles[bh].ch_handle[0], offset, val); 451 bus_space_write_stream_1((bus_space_tag_t)cookie, 452 cf_handles[bh].ch_handle[1], offset, val); 453 } 454 455 /* write multiple stream */ 456 static void 457 cf_bs_wms_1(void *cookie, bus_space_handle_t bh, bus_size_t offset, 458 const uint8_t *datap, bus_size_t count) 459 { 460 while (count-- > 0) 461 cf_bs_ws_1(cookie, bh, offset, *datap++); 462 } 463 464 /* set multiple */ 465 static void 466 cf_bs_sm_1(void *cookie, bus_space_handle_t bh, bus_size_t offset, 467 uint8_t value, bus_size_t count) 468 { 469 while (count-- > 0) 470 cf_bs_w_1(cookie, bh, offset, value); 471 } 472