1 1.43 thorpej /* $NetBSD: dio.c,v 1.43 2024/01/16 07:06:59 thorpej Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.11 thorpej * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe. 9 1.1 thorpej * 10 1.1 thorpej * Redistribution and use in source and binary forms, with or without 11 1.1 thorpej * modification, are permitted provided that the following conditions 12 1.1 thorpej * are met: 13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer. 15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.1 thorpej * documentation and/or other materials provided with the distribution. 18 1.1 thorpej * 19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.10 jtc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.10 jtc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.1 thorpej */ 31 1.1 thorpej 32 1.1 thorpej /* 33 1.1 thorpej * Autoconfiguration and mapping support for the DIO bus. 34 1.1 thorpej */ 35 1.16 gmcgarry 36 1.16 gmcgarry #include <sys/cdefs.h> 37 1.43 thorpej __KERNEL_RCSID(0, "$NetBSD: dio.c,v 1.43 2024/01/16 07:06:59 thorpej Exp $"); 38 1.1 thorpej 39 1.42 thorpej #define _M68K_INTR_PRIVATE 40 1.7 thorpej 41 1.1 thorpej #include <sys/param.h> 42 1.1 thorpej #include <sys/systm.h> 43 1.1 thorpej #include <sys/kernel.h> 44 1.1 thorpej #include <sys/device.h> 45 1.1 thorpej 46 1.23 gmcgarry #include <machine/bus.h> 47 1.23 gmcgarry 48 1.22 thorpej #include <uvm/uvm_extern.h> 49 1.22 thorpej 50 1.1 thorpej #include <machine/autoconf.h> 51 1.1 thorpej #include <machine/cpu.h> 52 1.6 thorpej #include <machine/hp300spu.h> 53 1.1 thorpej 54 1.7 thorpej #include <hp300/dev/dmavar.h> 55 1.7 thorpej 56 1.1 thorpej #include <hp300/dev/dioreg.h> 57 1.1 thorpej #include <hp300/dev/diovar.h> 58 1.1 thorpej 59 1.1 thorpej #include <hp300/dev/diodevs.h> 60 1.1 thorpej #include <hp300/dev/diodevs_data.h> 61 1.1 thorpej 62 1.23 gmcgarry #include "locators.h" 63 1.23 gmcgarry #define diocf_scode cf_loc[DIOCF_SCODE] 64 1.23 gmcgarry 65 1.24 tsutsui struct dio_softc { 66 1.36 tsutsui device_t sc_dev; 67 1.24 tsutsui struct bus_space_tag sc_tag; 68 1.24 tsutsui }; 69 1.1 thorpej 70 1.27 thorpej static int dio_scodesize(struct dio_attach_args *); 71 1.27 thorpej static const char *dio_devinfo(struct dio_attach_args *, char *, size_t); 72 1.1 thorpej 73 1.36 tsutsui static int diomatch(device_t, cfdata_t, void *); 74 1.36 tsutsui static void dioattach(device_t, device_t, void *); 75 1.27 thorpej static int dioprint(void *, const char *); 76 1.36 tsutsui static int diosubmatch(device_t, cfdata_t, const int *, void *); 77 1.1 thorpej 78 1.36 tsutsui CFATTACH_DECL_NEW(dio, sizeof(struct dio_softc), 79 1.19 thorpej diomatch, dioattach, NULL, NULL); 80 1.1 thorpej 81 1.43 thorpej static LIST_HEAD(, hp300_intrhand) dio_dma_users = 82 1.43 thorpej LIST_HEAD_INITIALIZER(dio_dma_users); 83 1.43 thorpej 84 1.27 thorpej static int 85 1.36 tsutsui diomatch(device_t parent, cfdata_t cf, void *aux) 86 1.1 thorpej { 87 1.1 thorpej static int dio_matched = 0; 88 1.1 thorpej 89 1.1 thorpej /* Allow only one instance. */ 90 1.1 thorpej if (dio_matched) 91 1.33 tsutsui return 0; 92 1.1 thorpej 93 1.1 thorpej dio_matched = 1; 94 1.33 tsutsui return 1; 95 1.1 thorpej } 96 1.1 thorpej 97 1.27 thorpej static void 98 1.36 tsutsui dioattach(device_t parent, device_t self, void *aux) 99 1.1 thorpej { 100 1.36 tsutsui struct dio_softc *sc = device_private(self); 101 1.1 thorpej struct dio_attach_args da; 102 1.34 tsutsui bus_addr_t pa; 103 1.35 christos void *va; 104 1.24 tsutsui bus_space_tag_t bst = &sc->sc_tag; 105 1.34 tsutsui bus_space_handle_t bsh; 106 1.23 gmcgarry int scode, scmax, scodesize; 107 1.1 thorpej 108 1.36 tsutsui sc->sc_dev = self; 109 1.36 tsutsui aprint_normal("\n"); 110 1.20 gmcgarry 111 1.24 tsutsui memset(bst, 0, sizeof(struct bus_space_tag)); 112 1.24 tsutsui bst->bustype = HP300_BUS_SPACE_DIO; 113 1.24 tsutsui 114 1.1 thorpej scmax = DIO_SCMAX(machineid); 115 1.1 thorpej 116 1.1 thorpej for (scode = 0; scode < scmax; ) { 117 1.1 thorpej if (DIO_INHOLE(scode)) { 118 1.1 thorpej scode++; 119 1.1 thorpej continue; 120 1.1 thorpej } 121 1.1 thorpej 122 1.1 thorpej /* 123 1.1 thorpej * Temporarily map the space corresponding to 124 1.1 thorpej * the current select code unless: 125 1.1 thorpej */ 126 1.34 tsutsui pa = (bus_addr_t)dio_scodetopa(scode); 127 1.34 tsutsui if (bus_space_map(bst, pa, PAGE_SIZE, 0, &bsh)) { 128 1.36 tsutsui aprint_error_dev(self, "can't map scode %d\n", scode); 129 1.26 tsutsui scode++; 130 1.26 tsutsui continue; 131 1.1 thorpej } 132 1.34 tsutsui va = bus_space_vaddr(bst, bsh); 133 1.1 thorpej 134 1.1 thorpej /* Check for hardware. */ 135 1.1 thorpej if (badaddr(va)) { 136 1.34 tsutsui bus_space_unmap(bst, bsh, PAGE_SIZE); 137 1.1 thorpej scode++; 138 1.1 thorpej continue; 139 1.1 thorpej } 140 1.1 thorpej 141 1.1 thorpej /* Fill out attach args. */ 142 1.14 gmcgarry memset(&da, 0, sizeof(da)); 143 1.24 tsutsui da.da_bst = bst; 144 1.1 thorpej da.da_scode = scode; 145 1.1 thorpej 146 1.23 gmcgarry da.da_id = DIO_ID(va); 147 1.1 thorpej if (DIO_ISFRAMEBUFFER(da.da_id)) 148 1.1 thorpej da.da_secid = DIO_SECID(va); 149 1.34 tsutsui da.da_addr = pa; 150 1.1 thorpej da.da_size = DIO_SIZE(scode, va); 151 1.1 thorpej scodesize = dio_scodesize(&da); 152 1.1 thorpej if (DIO_ISDIO(scode)) 153 1.1 thorpej da.da_size *= scodesize; 154 1.23 gmcgarry da.da_ipl = DIO_IPL(va); 155 1.1 thorpej 156 1.1 thorpej /* No longer need the device to be mapped. */ 157 1.34 tsutsui bus_space_unmap(bst, bsh, PAGE_SIZE); 158 1.1 thorpej 159 1.1 thorpej /* Attach matching device. */ 160 1.40 thorpej config_found(self, &da, dioprint, 161 1.41 thorpej CFARGS(.submatch = diosubmatch)); 162 1.1 thorpej scode += scodesize; 163 1.1 thorpej } 164 1.1 thorpej } 165 1.1 thorpej 166 1.27 thorpej static int 167 1.36 tsutsui diosubmatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 168 1.1 thorpej { 169 1.1 thorpej struct dio_attach_args *da = aux; 170 1.1 thorpej 171 1.8 jtk if (cf->diocf_scode != DIOCF_SCODE_DEFAULT && 172 1.1 thorpej cf->diocf_scode != da->da_scode) 173 1.33 tsutsui return 0; 174 1.1 thorpej 175 1.33 tsutsui return config_match(parent, cf, aux); 176 1.1 thorpej } 177 1.1 thorpej 178 1.27 thorpej static int 179 1.27 thorpej dioprint(void *aux, const char *pnp) 180 1.1 thorpej { 181 1.1 thorpej struct dio_attach_args *da = aux; 182 1.1 thorpej char buf[128]; 183 1.1 thorpej 184 1.1 thorpej if (pnp) 185 1.21 thorpej aprint_normal("%s at %s", 186 1.21 thorpej dio_devinfo(da, buf, sizeof(buf)), pnp); 187 1.23 gmcgarry aprint_normal(" scode %d ipl %d", da->da_scode, da->da_ipl); 188 1.33 tsutsui return UNCONF; 189 1.1 thorpej } 190 1.1 thorpej 191 1.1 thorpej /* 192 1.1 thorpej * Convert a select code to a system physical address. 193 1.1 thorpej */ 194 1.1 thorpej void * 195 1.27 thorpej dio_scodetopa(int scode) 196 1.1 thorpej { 197 1.1 thorpej u_long rval; 198 1.1 thorpej 199 1.23 gmcgarry if (DIO_ISDIO(scode)) 200 1.1 thorpej rval = DIO_BASE + (scode * DIO_DEVSIZE); 201 1.1 thorpej else if (DIO_ISDIOII(scode)) 202 1.2 thorpej rval = DIOII_BASE + ((scode - DIOII_SCBASE) * DIOII_DEVSIZE); 203 1.1 thorpej else 204 1.1 thorpej rval = 0; 205 1.1 thorpej 206 1.33 tsutsui return (void *)rval; 207 1.1 thorpej } 208 1.1 thorpej 209 1.1 thorpej /* 210 1.1 thorpej * Return the select code size for this device, defaulting to 1 211 1.1 thorpej * if we don't know what kind of device we have. 212 1.1 thorpej */ 213 1.23 gmcgarry static int 214 1.27 thorpej dio_scodesize(struct dio_attach_args *da) 215 1.1 thorpej { 216 1.1 thorpej int i; 217 1.1 thorpej 218 1.1 thorpej /* 219 1.1 thorpej * Find the dio_devdata matchind the primary id. 220 1.1 thorpej * If we're a framebuffer, we also check the secondary id. 221 1.1 thorpej */ 222 1.1 thorpej for (i = 0; i < DIO_NDEVICES; i++) { 223 1.1 thorpej if (da->da_id == dio_devdatas[i].dd_id) { 224 1.1 thorpej if (DIO_ISFRAMEBUFFER(da->da_id)) { 225 1.1 thorpej if (da->da_secid == dio_devdatas[i].dd_secid) { 226 1.1 thorpej goto foundit; 227 1.1 thorpej } 228 1.1 thorpej } else { 229 1.36 tsutsui foundit: 230 1.33 tsutsui return dio_devdatas[i].dd_nscode; 231 1.1 thorpej } 232 1.1 thorpej } 233 1.1 thorpej } 234 1.1 thorpej 235 1.1 thorpej /* 236 1.1 thorpej * Device is unknown. Print a warning and assume a default. 237 1.1 thorpej */ 238 1.36 tsutsui aprint_error("WARNING: select code size unknown " 239 1.36 tsutsui "for id = 0x%x secid = 0x%x\n", 240 1.1 thorpej da->da_id, da->da_secid); 241 1.33 tsutsui return 1; 242 1.1 thorpej } 243 1.1 thorpej 244 1.1 thorpej /* 245 1.1 thorpej * Return a reasonable description of a DIO device. 246 1.1 thorpej */ 247 1.27 thorpej static const char * 248 1.27 thorpej dio_devinfo(struct dio_attach_args *da, char *buf, size_t buflen) 249 1.1 thorpej { 250 1.5 thorpej #ifdef DIOVERBOSE 251 1.1 thorpej int i; 252 1.5 thorpej #endif 253 1.1 thorpej 254 1.14 gmcgarry memset(buf, 0, buflen); 255 1.1 thorpej 256 1.1 thorpej #ifdef DIOVERBOSE 257 1.1 thorpej /* 258 1.1 thorpej * Find the description matching our primary id. 259 1.1 thorpej * If we're a framebuffer, we also check the secondary id. 260 1.1 thorpej */ 261 1.1 thorpej for (i = 0; i < DIO_NDEVICES; i++) { 262 1.1 thorpej if (da->da_id == dio_devdescs[i].dd_id) { 263 1.1 thorpej if (DIO_ISFRAMEBUFFER(da->da_id)) { 264 1.1 thorpej if (da->da_secid == dio_devdescs[i].dd_secid) { 265 1.1 thorpej goto foundit; 266 1.1 thorpej } 267 1.1 thorpej } else { 268 1.1 thorpej foundit: 269 1.39 christos snprintf(buf, buflen, "%s", 270 1.39 christos dio_devdescs[i].dd_desc); 271 1.33 tsutsui return buf; 272 1.1 thorpej } 273 1.1 thorpej } 274 1.1 thorpej } 275 1.1 thorpej #endif /* DIOVERBOSE */ 276 1.1 thorpej 277 1.1 thorpej /* 278 1.1 thorpej * Device is unknown. Construct something reasonable. 279 1.1 thorpej */ 280 1.39 christos snprintf(buf, buflen, "device id = 0x%x secid = 0x%x", 281 1.1 thorpej da->da_id, da->da_secid); 282 1.33 tsutsui return buf; 283 1.7 thorpej } 284 1.7 thorpej 285 1.7 thorpej /* 286 1.43 thorpej * Enumerate the list of DMA controller users (the HPIB and SCSI 287 1.43 thorpej * controllers, essentially), and calculate what the highest 288 1.43 thorpej * auto-vector level used by those devices is. Then tell the DMA 289 1.43 thorpej * controller to interrupt at that level. 290 1.43 thorpej */ 291 1.43 thorpej static void 292 1.43 thorpej dio_dma_users_changed(void) 293 1.43 thorpej { 294 1.43 thorpej struct hp300_intrhand *ih; 295 1.43 thorpej int ipl = 0; 296 1.43 thorpej 297 1.43 thorpej LIST_FOREACH(ih, &dio_dma_users, ih_dio_link) { 298 1.43 thorpej KASSERT(ih->ih_super.ih_isrpri == ISRPRI_BIO); 299 1.43 thorpej if (ih->ih_super.ih_ipl > ipl) { 300 1.43 thorpej ipl = ih->ih_super.ih_ipl; 301 1.43 thorpej } 302 1.43 thorpej } 303 1.43 thorpej dmaupdateipl(ipl); 304 1.43 thorpej } 305 1.43 thorpej 306 1.43 thorpej /* 307 1.7 thorpej * Establish an interrupt handler for a DIO device. 308 1.7 thorpej */ 309 1.7 thorpej void * 310 1.42 thorpej dio_intr_establish(int (*func)(void *), void *arg, int ipl, int isrpri) 311 1.7 thorpej { 312 1.43 thorpej struct hp300_intrhand *ih; 313 1.7 thorpej 314 1.42 thorpej ih = intr_establish(func, arg, ipl, isrpri); 315 1.7 thorpej 316 1.43 thorpej if (ih != NULL && isrpri == ISRPRI_BIO) { 317 1.43 thorpej LIST_INSERT_HEAD(&dio_dma_users, ih, ih_dio_link); 318 1.43 thorpej dio_dma_users_changed(); 319 1.43 thorpej } 320 1.7 thorpej 321 1.33 tsutsui return ih; 322 1.7 thorpej } 323 1.7 thorpej 324 1.7 thorpej /* 325 1.7 thorpej * Remove an interrupt handler for a DIO device. 326 1.7 thorpej */ 327 1.7 thorpej void 328 1.27 thorpej dio_intr_disestablish(void *arg) 329 1.7 thorpej { 330 1.43 thorpej struct hp300_intrhand *ih = arg; 331 1.43 thorpej int isrpri = ih->ih_super.ih_isrpri; 332 1.43 thorpej 333 1.43 thorpej if (isrpri == ISRPRI_BIO) { 334 1.43 thorpej LIST_REMOVE(ih, ih_dio_link); 335 1.43 thorpej } 336 1.7 thorpej 337 1.7 thorpej intr_disestablish(arg); 338 1.7 thorpej 339 1.43 thorpej if (isrpri == ISRPRI_BIO) { 340 1.43 thorpej dio_dma_users_changed(); 341 1.43 thorpej } 342 1.25 tsutsui } 343 1.25 tsutsui 344 1.25 tsutsui /* 345 1.25 tsutsui * DIO specific bus_space(9) support functions. 346 1.25 tsutsui */ 347 1.28 tsutsui static uint8_t dio_bus_space_read_oddbyte_1(bus_space_tag_t, 348 1.27 thorpej bus_space_handle_t, bus_size_t); 349 1.27 thorpej static void dio_bus_space_write_oddbyte_1(bus_space_tag_t, 350 1.28 tsutsui bus_space_handle_t, bus_size_t, uint8_t); 351 1.27 thorpej 352 1.27 thorpej static void dio_bus_space_read_multi_oddbyte_1(bus_space_tag_t, 353 1.28 tsutsui bus_space_handle_t, bus_size_t, uint8_t *, bus_size_t); 354 1.27 thorpej static void dio_bus_space_write_multi_oddbyte_1(bus_space_tag_t, 355 1.28 tsutsui bus_space_handle_t, bus_size_t, const uint8_t *, bus_size_t); 356 1.27 thorpej 357 1.27 thorpej static void dio_bus_space_read_region_oddbyte_1(bus_space_tag_t, 358 1.28 tsutsui bus_space_handle_t, bus_size_t, uint8_t *, bus_size_t); 359 1.27 thorpej static void dio_bus_space_write_region_oddbyte_1(bus_space_tag_t, 360 1.28 tsutsui bus_space_handle_t, bus_size_t, const uint8_t *, bus_size_t); 361 1.25 tsutsui 362 1.27 thorpej static void dio_bus_space_set_multi_oddbyte_1(bus_space_tag_t, 363 1.28 tsutsui bus_space_handle_t, bus_size_t, uint8_t, bus_size_t); 364 1.25 tsutsui 365 1.27 thorpej static void dio_bus_space_set_region_oddbyte_1(bus_space_tag_t, 366 1.28 tsutsui bus_space_handle_t, bus_size_t, uint8_t, bus_size_t); 367 1.25 tsutsui 368 1.25 tsutsui /* 369 1.25 tsutsui * dio_set_bus_space_oddbyte(): 370 1.25 tsutsui * Override bus_space functions in bus_space_tag_t 371 1.25 tsutsui * for devices which have odd byte address space. 372 1.25 tsutsui */ 373 1.25 tsutsui void 374 1.27 thorpej dio_set_bus_space_oddbyte(bus_space_tag_t bst) 375 1.25 tsutsui { 376 1.25 tsutsui 377 1.25 tsutsui /* XXX only 1-byte functions for now */ 378 1.25 tsutsui bst->bsr1 = dio_bus_space_read_oddbyte_1; 379 1.25 tsutsui bst->bsw1 = dio_bus_space_write_oddbyte_1; 380 1.25 tsutsui 381 1.25 tsutsui bst->bsrm1 = dio_bus_space_read_multi_oddbyte_1; 382 1.25 tsutsui bst->bswm1 = dio_bus_space_write_multi_oddbyte_1; 383 1.25 tsutsui 384 1.25 tsutsui bst->bsrr1 = dio_bus_space_read_region_oddbyte_1; 385 1.25 tsutsui bst->bswr1 = dio_bus_space_write_region_oddbyte_1; 386 1.25 tsutsui 387 1.25 tsutsui bst->bssm1 = dio_bus_space_set_multi_oddbyte_1; 388 1.25 tsutsui 389 1.25 tsutsui bst->bssr1 = dio_bus_space_set_region_oddbyte_1; 390 1.25 tsutsui } 391 1.25 tsutsui 392 1.28 tsutsui static uint8_t 393 1.27 thorpej dio_bus_space_read_oddbyte_1(bus_space_tag_t bst, bus_space_handle_t bsh, 394 1.27 thorpej bus_size_t offset) 395 1.25 tsutsui { 396 1.25 tsutsui 397 1.28 tsutsui return *(volatile uint8_t *)(bsh + (offset << 1) + 1); 398 1.25 tsutsui } 399 1.25 tsutsui 400 1.38 tsutsui static void 401 1.27 thorpej dio_bus_space_write_oddbyte_1(bus_space_tag_t bst, bus_space_handle_t bsh, 402 1.28 tsutsui bus_size_t offset, uint8_t val) 403 1.25 tsutsui { 404 1.25 tsutsui 405 1.28 tsutsui *(volatile uint8_t *)(bsh + (offset << 1) + 1) = val; 406 1.25 tsutsui } 407 1.25 tsutsui 408 1.25 tsutsui static void 409 1.27 thorpej dio_bus_space_read_multi_oddbyte_1(bus_space_tag_t bst, bus_space_handle_t bsh, 410 1.28 tsutsui bus_size_t offset, uint8_t *addr, bus_size_t len) 411 1.25 tsutsui { 412 1.25 tsutsui 413 1.32 perry __asm volatile ( 414 1.25 tsutsui " movl %0,%%a0 ;\n" 415 1.25 tsutsui " movl %1,%%a1 ;\n" 416 1.25 tsutsui " movl %2,%%d0 ;\n" 417 1.25 tsutsui "1: movb %%a0@,%%a1@+ ;\n" 418 1.25 tsutsui " subql #1,%%d0 ;\n" 419 1.25 tsutsui " jne 1b" 420 1.25 tsutsui : 421 1.25 tsutsui : "r" (bsh + (offset << 1) + 1), "g" (addr), "g" (len) 422 1.25 tsutsui : "%a0","%a1","%d0"); 423 1.25 tsutsui } 424 1.25 tsutsui 425 1.25 tsutsui static void 426 1.27 thorpej dio_bus_space_write_multi_oddbyte_1(bus_space_tag_t bst, bus_space_handle_t bsh, 427 1.28 tsutsui bus_size_t offset, const uint8_t *addr, bus_size_t len) 428 1.25 tsutsui { 429 1.25 tsutsui 430 1.32 perry __asm volatile ( 431 1.25 tsutsui " movl %0,%%a0 ;\n" 432 1.25 tsutsui " movl %1,%%a1 ;\n" 433 1.25 tsutsui " movl %2,%%d0 ;\n" 434 1.25 tsutsui "1: movb %%a1@+,%%a0@ ;\n" 435 1.25 tsutsui " subql #1,%%d0 ;\n" 436 1.25 tsutsui " jne 1b" 437 1.25 tsutsui : 438 1.25 tsutsui : "r" (bsh + (offset << 1) + 1), "g" (addr), "g" (len) 439 1.25 tsutsui : "%a0","%a1","%d0"); 440 1.25 tsutsui } 441 1.25 tsutsui 442 1.25 tsutsui static void 443 1.27 thorpej dio_bus_space_read_region_oddbyte_1(bus_space_tag_t bst, bus_space_handle_t bsh, 444 1.28 tsutsui bus_size_t offset, uint8_t *addr, bus_size_t len) 445 1.25 tsutsui { 446 1.32 perry __asm volatile ( 447 1.25 tsutsui " movl %0,%%a0 ;\n" 448 1.25 tsutsui " movl %1,%%a1 ;\n" 449 1.25 tsutsui " movl %2,%%d0 ;\n" 450 1.25 tsutsui "1: movb %%a0@,%%a1@+ ;\n" 451 1.25 tsutsui " addql #2,%%a0 ;\n" 452 1.25 tsutsui " subql #1,%%d0 ;\n" 453 1.25 tsutsui " jne 1b" 454 1.25 tsutsui : 455 1.25 tsutsui : "r" (bsh + (offset << 1) + 1), "g" (addr), "g" (len) 456 1.25 tsutsui : "%a0","%a1","%d0"); 457 1.25 tsutsui } 458 1.25 tsutsui 459 1.25 tsutsui static void 460 1.27 thorpej dio_bus_space_write_region_oddbyte_1(bus_space_tag_t bst, 461 1.28 tsutsui bus_space_handle_t bsh, bus_size_t offset, const uint8_t *addr, 462 1.27 thorpej bus_size_t len) 463 1.25 tsutsui { 464 1.25 tsutsui 465 1.32 perry __asm volatile ( 466 1.25 tsutsui " movl %0,%%a0 ;\n" 467 1.25 tsutsui " movl %1,%%a1 ;\n" 468 1.25 tsutsui " movl %2,%%d0 ;\n" 469 1.25 tsutsui "1: movb %%a1@+,%%a0@ ;\n" 470 1.25 tsutsui " addql #2,%%a0 ;\n" 471 1.25 tsutsui " subql #1,%%d0 ;\n" 472 1.25 tsutsui " jne 1b" 473 1.25 tsutsui : 474 1.25 tsutsui : "r" (bsh + (offset << 1) + 1), "g" (addr), "g" (len) 475 1.25 tsutsui : "%a0","%a1","%d0"); 476 1.25 tsutsui } 477 1.25 tsutsui 478 1.25 tsutsui static void 479 1.27 thorpej dio_bus_space_set_multi_oddbyte_1(bus_space_tag_t bst, bus_space_handle_t bsh, 480 1.28 tsutsui bus_size_t offset, uint8_t val, bus_size_t count) 481 1.25 tsutsui { 482 1.32 perry __asm volatile ( 483 1.25 tsutsui " movl %0,%%a0 ;\n" 484 1.25 tsutsui " movl %1,%%d1 ;\n" 485 1.25 tsutsui " movl %2,%%d0 ;\n" 486 1.25 tsutsui "1: movb %%d1,%%a0@ ;\n" 487 1.25 tsutsui " subql #1,%%d0 ;\n" 488 1.25 tsutsui " jne 1b" 489 1.25 tsutsui : 490 1.25 tsutsui : "r" (bsh + (offset << 1) + 1), "g" (val), "g" (count) 491 1.25 tsutsui : "%a0","%d0","%d1"); 492 1.25 tsutsui } 493 1.25 tsutsui 494 1.25 tsutsui static void 495 1.27 thorpej dio_bus_space_set_region_oddbyte_1(bus_space_tag_t bst, bus_space_handle_t bsh, 496 1.28 tsutsui bus_size_t offset, uint8_t val, bus_size_t count) 497 1.25 tsutsui { 498 1.25 tsutsui 499 1.32 perry __asm volatile ( 500 1.25 tsutsui " movl %0,%%a0 ;\n" 501 1.25 tsutsui " movl %1,%%d1 ;\n" 502 1.25 tsutsui " movl %2,%%d0 ;\n" 503 1.25 tsutsui "1: movb %%d1,%%a0@ ;\n" 504 1.25 tsutsui " addql #2,%%a0 ;\n" 505 1.25 tsutsui " subql #1,%%d0 ;\n" 506 1.25 tsutsui " jne 1b" 507 1.25 tsutsui : 508 1.25 tsutsui : "r" (bsh + (offset << 1) + 1), "g" (val), "g" (count) 509 1.25 tsutsui : "%a0","%d0","%d1"); 510 1.1 thorpej } 511