1/* $NetBSD: adm5120_cfio.c,v 1.1 2007/03/20 08:52:04 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.1 2007/03/20 08:52:04 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 50int cfio_debug = 1; 51#define CFIO_DPRINTF(__fmt, ...) \ 52do { \ 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 60static struct { 61 bus_space_handle_t ch_handle[2]; 62 int ch_inuse; 63 int ch_parent; 64} cf_handles[16]; 65 66static int cf_handle_alloc(int); 67static void cf_handle_free(int); 68static void cf_bs_unmap(void *, bus_space_handle_t, bus_size_t, int); 69static int cf_bs_map(void *, bus_addr_t, bus_size_t, int, 70 bus_space_handle_t *, int); 71static int cf_bs_subregion(void *, bus_space_handle_t, bus_size_t, 72 bus_size_t, bus_space_handle_t *); 73static int cf_bs_translate(void *, bus_addr_t, bus_size_t, int, 74 struct mips_bus_space_translation *); 75static int cf_bs_get_window(void *, int, struct mips_bus_space_translation *); 76static int cf_bs_translate(void *, bus_addr_t, bus_size_t, int, 77 struct mips_bus_space_translation *); 78static int cf_bs_get_window(void *, int, struct mips_bus_space_translation *); 79static 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 *); 81static void cf_bs_free(void *, bus_space_handle_t, bus_size_t size); 82static void *cf_bs_vaddr(void *, bus_space_handle_t); 83static paddr_t cf_bs_mmap(void *, bus_addr_t, off_t off, int prot, int); 84static void cf_bs_barrier(void *, bus_space_handle_t, bus_size_t, 85 bus_size_t length, int); 86static uint8_t cf_bs_r_1(void *, bus_space_handle_t, bus_size_t offset); 87static void cf_bs_rm_1(void *, bus_space_handle_t, bus_size_t, 88 uint8_t *, bus_size_t); 89static void cf_bs_w_1(void *, bus_space_handle_t, bus_size_t, uint8_t val); 90static void cf_bs_wm_1(void *, bus_space_handle_t, bus_size_t, 91 const uint8_t *, bus_size_t); 92static uint8_t cf_bs_rs_1(void *, bus_space_handle_t, bus_size_t offset); 93static void cf_bs_rms_1(void *, bus_space_handle_t, bus_size_t, 94 uint8_t *, bus_size_t); 95static void cf_bs_ws_1(void *, bus_space_handle_t, bus_size_t, uint8_t val); 96static void cf_bs_wms_1(void *, bus_space_handle_t, bus_size_t, const uint8_t *, 97 bus_size_t); 98static void cf_bs_sm_1(void *, bus_space_handle_t, bus_size_t, uint8_t, 99 bus_size_t); 100 101static 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 199void 200cfio_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 206static void 207cf_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 217static void 218cf_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 241static int 242cf_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 255static int 256cf_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 284static int 285cf_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 310static int 311cf_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 317static int 318cf_bs_get_window(void *cookie, int window, 319 struct mips_bus_space_translation *mbst) 320{ 321 panic("%s: not implemented\n", __func__); 322} 323 324static int 325cf_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 356static void 357cf_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 366static void * 367cf_bs_vaddr(void *cookie, bus_space_handle_t bh) 368{ 369 panic("%s: not implemented", __func__); 370} 371 372static paddr_t 373cf_bs_mmap(void *cookie, bus_addr_t addr, off_t off, int prot, int flags) 374{ 375 panic("%s: not implemented", __func__); 376} 377 378static void 379cf_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) */ 389static uint8_t 390cf_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 */ 399static void 400cf_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) */ 408static void 409cf_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 */ 418static void 419cf_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 */ 427static uint8_t 428cf_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 */ 437static void 438cf_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 */ 446static void 447cf_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 */ 456static void 457cf_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 */ 465static void 466cf_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