1 1.46 isaki /* $NetBSD: bba.c,v 1.46 2020/09/12 05:19:16 isaki Exp $ */ 2 1.1 augustss 3 1.1 augustss /* 4 1.1 augustss * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 1.1 augustss * All rights reserved. 6 1.1 augustss * 7 1.1 augustss * Redistribution and use in source and binary forms, with or without 8 1.1 augustss * modification, are permitted provided that the following conditions 9 1.1 augustss * are met: 10 1.1 augustss * 1. Redistributions of source code must retain the above copyright 11 1.1 augustss * notice, this list of conditions and the following disclaimer. 12 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 augustss * notice, this list of conditions and the following disclaimer in the 14 1.1 augustss * documentation and/or other materials provided with the distribution. 15 1.1 augustss * 16 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 27 1.1 augustss */ 28 1.1 augustss 29 1.1 augustss /* maxine/alpha baseboard audio (bba) */ 30 1.15 lukem 31 1.15 lukem #include <sys/cdefs.h> 32 1.46 isaki __KERNEL_RCSID(0, "$NetBSD: bba.c,v 1.46 2020/09/12 05:19:16 isaki Exp $"); 33 1.1 augustss 34 1.1 augustss #include <sys/param.h> 35 1.1 augustss #include <sys/systm.h> 36 1.1 augustss #include <sys/kernel.h> 37 1.1 augustss #include <sys/device.h> 38 1.39 jmcneill #include <sys/kmem.h> 39 1.1 augustss 40 1.32 ad #include <sys/bus.h> 41 1.1 augustss #include <machine/autoconf.h> 42 1.32 ad #include <sys/cpu.h> 43 1.1 augustss 44 1.1 augustss #include <sys/audioio.h> 45 1.43 isaki #include <dev/audio/audio_if.h> 46 1.1 augustss 47 1.1 augustss #include <dev/ic/am7930reg.h> 48 1.1 augustss #include <dev/ic/am7930var.h> 49 1.1 augustss 50 1.1 augustss #include <dev/tc/tcvar.h> 51 1.1 augustss #include <dev/tc/ioasicreg.h> 52 1.1 augustss #include <dev/tc/ioasicvar.h> 53 1.1 augustss 54 1.43 isaki /* include mulaw.c (not .h file) here to expand mulaw32 */ 55 1.43 isaki void audio_mulaw32_to_internal(audio_filter_arg_t *); 56 1.43 isaki void audio_internal_to_mulaw32(audio_filter_arg_t *); 57 1.43 isaki #define MULAW32 58 1.43 isaki #include <dev/audio/mulaw.c> 59 1.43 isaki 60 1.1 augustss #ifdef AUDIO_DEBUG 61 1.1 augustss #define DPRINTF(x) if (am7930debug) printf x 62 1.1 augustss #else 63 1.1 augustss #define DPRINTF(x) 64 1.1 augustss #endif /* AUDIO_DEBUG */ 65 1.1 augustss 66 1.1 augustss #define BBA_MAX_DMA_SEGMENTS 16 67 1.9 thorpej #define BBA_DMABUF_SIZE (BBA_MAX_DMA_SEGMENTS*IOASIC_DMA_BLOCKSIZE) 68 1.9 thorpej #define BBA_DMABUF_ALIGN IOASIC_DMA_BLOCKSIZE 69 1.6 gmcgarry #define BBA_DMABUF_BOUNDARY 0 70 1.1 augustss 71 1.1 augustss struct bba_mem { 72 1.24 kent struct bba_mem *next; 73 1.1 augustss bus_addr_t addr; 74 1.1 augustss bus_size_t size; 75 1.31 christos void *kva; 76 1.1 augustss }; 77 1.1 augustss 78 1.1 augustss struct bba_dma_state { 79 1.20 wiz bus_dmamap_t dmam; /* DMA map */ 80 1.1 augustss int active; 81 1.20 wiz int curseg; /* current segment in DMA buffer */ 82 1.24 kent void (*intr)(void *); /* higher-level audio handler */ 83 1.1 augustss void *intr_arg; 84 1.1 augustss }; 85 1.1 augustss 86 1.1 augustss struct bba_softc { 87 1.1 augustss struct am7930_softc sc_am7930; /* glue to MI code */ 88 1.1 augustss 89 1.1 augustss bus_space_tag_t sc_bst; /* IOASIC bus tag/handle */ 90 1.1 augustss bus_space_handle_t sc_bsh; 91 1.1 augustss bus_dma_tag_t sc_dmat; 92 1.1 augustss bus_space_handle_t sc_codec_bsh; /* codec bus space handle */ 93 1.1 augustss 94 1.1 augustss struct bba_mem *sc_mem_head; /* list of buffers */ 95 1.1 augustss 96 1.1 augustss struct bba_dma_state sc_tx_dma_state; 97 1.1 augustss struct bba_dma_state sc_rx_dma_state; 98 1.1 augustss }; 99 1.1 augustss 100 1.36 cegger static int bba_match(device_t, cfdata_t, void *); 101 1.36 cegger static void bba_attach(device_t, device_t, void *); 102 1.1 augustss 103 1.38 tsutsui CFATTACH_DECL_NEW(bba, sizeof(struct bba_softc), 104 1.18 thorpej bba_match, bba_attach, NULL, NULL); 105 1.1 augustss 106 1.1 augustss /* 107 1.1 augustss * Define our interface into the am7930 MI driver. 108 1.1 augustss */ 109 1.1 augustss 110 1.46 isaki static uint8_t bba_codec_dread(struct am7930_softc *, int); 111 1.46 isaki static void bba_codec_dwrite(struct am7930_softc *, int, uint8_t); 112 1.28 thorpej 113 1.1 augustss struct am7930_glue bba_glue = { 114 1.46 isaki bba_codec_dread, 115 1.46 isaki bba_codec_dwrite, 116 1.1 augustss }; 117 1.1 augustss 118 1.1 augustss /* 119 1.1 augustss * Define our interface to the higher level audio driver. 120 1.1 augustss */ 121 1.1 augustss 122 1.43 isaki static int bba_query_format(void *, audio_format_query_t *); 123 1.43 isaki static int bba_set_format(void *, int, 124 1.43 isaki const audio_params_t *, const audio_params_t *, 125 1.43 isaki audio_filter_reg_t *, audio_filter_reg_t *); 126 1.28 thorpej static int bba_round_blocksize(void *, int, int, const audio_params_t *); 127 1.28 thorpej static int bba_halt_output(void *); 128 1.28 thorpej static int bba_halt_input(void *); 129 1.28 thorpej static int bba_getdev(void *, struct audio_device *); 130 1.39 jmcneill static void *bba_allocm(void *, int, size_t); 131 1.39 jmcneill static void bba_freem(void *, void *, size_t); 132 1.28 thorpej static size_t bba_round_buffersize(void *, int, size_t); 133 1.28 thorpej static int bba_trigger_output(void *, void *, void *, int, 134 1.28 thorpej void (*)(void *), void *, 135 1.28 thorpej const audio_params_t *); 136 1.28 thorpej static int bba_trigger_input(void *, void *, void *, int, 137 1.28 thorpej void (*)(void *), void *, 138 1.28 thorpej const audio_params_t *); 139 1.1 augustss 140 1.28 thorpej static const struct audio_hw_if sa_hw_if = { 141 1.43 isaki .query_format = bba_query_format, 142 1.43 isaki .set_format = bba_set_format, 143 1.42 isaki .round_blocksize = bba_round_blocksize, /* md */ 144 1.42 isaki .commit_settings = am7930_commit_settings, 145 1.42 isaki .halt_output = bba_halt_output, /* md */ 146 1.42 isaki .halt_input = bba_halt_input, /* md */ 147 1.42 isaki .getdev = bba_getdev, 148 1.42 isaki .set_port = am7930_set_port, 149 1.42 isaki .get_port = am7930_get_port, 150 1.42 isaki .query_devinfo = am7930_query_devinfo, 151 1.42 isaki .allocm = bba_allocm, /* md */ 152 1.42 isaki .freem = bba_freem, /* md */ 153 1.42 isaki .round_buffersize = bba_round_buffersize, /* md */ 154 1.44 isaki .get_props = am7930_get_props, 155 1.42 isaki .trigger_output = bba_trigger_output, /* md */ 156 1.42 isaki .trigger_input = bba_trigger_input, /* md */ 157 1.46 isaki .get_locks = am7930_get_locks, 158 1.1 augustss }; 159 1.1 augustss 160 1.28 thorpej static struct audio_device bba_device = { 161 1.1 augustss "am7930", 162 1.1 augustss "x", 163 1.1 augustss "bba" 164 1.1 augustss }; 165 1.1 augustss 166 1.43 isaki static const struct audio_format bba_format = { 167 1.43 isaki .mode = AUMODE_PLAY | AUMODE_RECORD, 168 1.43 isaki .encoding = AUDIO_ENCODING_ULAW, /* XXX */ 169 1.43 isaki .validbits = 32, 170 1.43 isaki .precision = 32, 171 1.43 isaki .channels = 1, 172 1.43 isaki .channel_mask = AUFMT_MONAURAL, 173 1.43 isaki .frequency_type = 1, 174 1.43 isaki .frequency = { 8000 }, 175 1.43 isaki }; 176 1.43 isaki 177 1.28 thorpej static int bba_intr(void *); 178 1.28 thorpej static void bba_reset(struct bba_softc *, int); 179 1.24 kent 180 1.28 thorpej static int 181 1.36 cegger bba_match(device_t parent, cfdata_t cf, void *aux) 182 1.1 augustss { 183 1.24 kent struct ioasicdev_attach_args *ia; 184 1.1 augustss 185 1.24 kent ia = aux; 186 1.6 gmcgarry if (strcmp(ia->iada_modname, "isdn") != 0 && 187 1.6 gmcgarry strcmp(ia->iada_modname, "AMD79c30") != 0) 188 1.6 gmcgarry return 0; 189 1.1 augustss 190 1.1 augustss return 1; 191 1.1 augustss } 192 1.1 augustss 193 1.1 augustss 194 1.28 thorpej static void 195 1.36 cegger bba_attach(device_t parent, device_t self, void *aux) 196 1.24 kent { 197 1.24 kent struct ioasicdev_attach_args *ia; 198 1.24 kent struct bba_softc *sc; 199 1.46 isaki struct am7930_softc *amsc; 200 1.29 thorpej struct ioasic_softc *iosc = device_private(parent); 201 1.1 augustss 202 1.24 kent ia = aux; 203 1.27 thorpej sc = device_private(self); 204 1.46 isaki amsc = &sc->sc_am7930; 205 1.46 isaki amsc->sc_dev = self; 206 1.29 thorpej sc->sc_bst = iosc->sc_bst; 207 1.29 thorpej sc->sc_bsh = iosc->sc_bsh; 208 1.29 thorpej sc->sc_dmat = iosc->sc_dmat; 209 1.1 augustss 210 1.1 augustss /* get the bus space handle for codec */ 211 1.1 augustss if (bus_space_subregion(sc->sc_bst, sc->sc_bsh, 212 1.6 gmcgarry ia->iada_offset, 0, &sc->sc_codec_bsh)) { 213 1.38 tsutsui aprint_error_dev(self, "unable to map device\n"); 214 1.1 augustss return; 215 1.1 augustss } 216 1.1 augustss 217 1.1 augustss printf("\n"); 218 1.1 augustss 219 1.45 isaki bba_reset(sc, 1); 220 1.1 augustss 221 1.1 augustss /* 222 1.1 augustss * Set up glue for MI code early; we use some of it here. 223 1.1 augustss */ 224 1.46 isaki amsc->sc_glue = &bba_glue; 225 1.1 augustss 226 1.1 augustss /* 227 1.1 augustss * MI initialisation. We will be doing DMA. 228 1.1 augustss */ 229 1.46 isaki am7930_init(amsc, AUDIOAMD_DMA_MODE); 230 1.1 augustss 231 1.1 augustss ioasic_intr_establish(parent, ia->iada_cookie, TC_IPL_NONE, 232 1.6 gmcgarry bba_intr, sc); 233 1.1 augustss 234 1.46 isaki audio_attach_mi(&sa_hw_if, sc, self); 235 1.1 augustss } 236 1.1 augustss 237 1.1 augustss 238 1.28 thorpej static void 239 1.24 kent bba_reset(struct bba_softc *sc, int reset) 240 1.1 augustss { 241 1.24 kent uint32_t ssr; 242 1.1 augustss 243 1.1 augustss /* disable any DMA and reset the codec */ 244 1.1 augustss ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 245 1.1 augustss ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R); 246 1.1 augustss if (reset) 247 1.1 augustss ssr &= ~IOASIC_CSR_ISDN_ENABLE; 248 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 249 1.1 augustss DELAY(10); /* 400ns required for codec to reset */ 250 1.1 augustss 251 1.1 augustss /* initialise DMA pointers */ 252 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1); 253 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1); 254 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1); 255 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1); 256 1.1 augustss 257 1.1 augustss /* take out of reset state */ 258 1.1 augustss if (reset) { 259 1.1 augustss ssr |= IOASIC_CSR_ISDN_ENABLE; 260 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 261 1.1 augustss } 262 1.1 augustss } 263 1.1 augustss 264 1.1 augustss 265 1.28 thorpej static void * 266 1.39 jmcneill bba_allocm(void *addr, int direction, size_t size) 267 1.1 augustss { 268 1.46 isaki struct am7930_softc *amsc; 269 1.24 kent struct bba_softc *sc; 270 1.1 augustss bus_dma_segment_t seg; 271 1.1 augustss int rseg; 272 1.31 christos void *kva; 273 1.1 augustss struct bba_mem *m; 274 1.24 kent int state; 275 1.1 augustss 276 1.26 kleink DPRINTF(("bba_allocm: size = %zu\n", size)); 277 1.24 kent sc = addr; 278 1.46 isaki amsc = addr; 279 1.24 kent state = 0; 280 1.6 gmcgarry 281 1.6 gmcgarry if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN, 282 1.39 jmcneill BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, BUS_DMA_WAITOK)) { 283 1.46 isaki aprint_error_dev(amsc->sc_dev, "can't allocate DMA buffer\n"); 284 1.1 augustss goto bad; 285 1.1 augustss } 286 1.1 augustss state |= 1; 287 1.1 augustss 288 1.1 augustss if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 289 1.39 jmcneill &kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) { 290 1.46 isaki aprint_error_dev(amsc->sc_dev, "can't map DMA buffer\n"); 291 1.1 augustss goto bad; 292 1.1 augustss } 293 1.1 augustss state |= 2; 294 1.1 augustss 295 1.39 jmcneill m = kmem_alloc(sizeof(struct bba_mem), KM_SLEEP); 296 1.1 augustss m->addr = seg.ds_addr; 297 1.1 augustss m->size = seg.ds_len; 298 1.24 kent m->kva = kva; 299 1.24 kent m->next = sc->sc_mem_head; 300 1.24 kent sc->sc_mem_head = m; 301 1.1 augustss 302 1.24 kent return (void *)kva; 303 1.1 augustss 304 1.1 augustss bad: 305 1.1 augustss if (state & 2) 306 1.1 augustss bus_dmamem_unmap(sc->sc_dmat, kva, size); 307 1.1 augustss if (state & 1) 308 1.1 augustss bus_dmamem_free(sc->sc_dmat, &seg, 1); 309 1.1 augustss return NULL; 310 1.1 augustss } 311 1.1 augustss 312 1.1 augustss 313 1.28 thorpej static void 314 1.39 jmcneill bba_freem(void *addr, void *ptr, size_t size) 315 1.1 augustss { 316 1.24 kent struct bba_softc *sc; 317 1.24 kent struct bba_mem **mp, *m; 318 1.1 augustss bus_dma_segment_t seg; 319 1.31 christos void *kva; 320 1.1 augustss 321 1.24 kent sc = addr; 322 1.31 christos kva = (void *)addr; 323 1.1 augustss for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva; 324 1.6 gmcgarry mp = &(*mp)->next) 325 1.24 kent continue; 326 1.1 augustss m = *mp; 327 1.6 gmcgarry if (m == NULL) { 328 1.6 gmcgarry printf("bba_freem: freeing unallocated memory\n"); 329 1.1 augustss return; 330 1.1 augustss } 331 1.1 augustss *mp = m->next; 332 1.1 augustss bus_dmamem_unmap(sc->sc_dmat, kva, m->size); 333 1.1 augustss 334 1.24 kent seg.ds_addr = m->addr; 335 1.24 kent seg.ds_len = m->size; 336 1.1 augustss bus_dmamem_free(sc->sc_dmat, &seg, 1); 337 1.39 jmcneill kmem_free(m, sizeof(struct bba_mem)); 338 1.1 augustss } 339 1.1 augustss 340 1.1 augustss 341 1.28 thorpej static size_t 342 1.24 kent bba_round_buffersize(void *addr, int direction, size_t size) 343 1.1 augustss { 344 1.24 kent 345 1.26 kleink DPRINTF(("bba_round_buffersize: size=%zu\n", size)); 346 1.24 kent return size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE : 347 1.24 kent roundup(size, IOASIC_DMA_BLOCKSIZE); 348 1.1 augustss } 349 1.1 augustss 350 1.1 augustss 351 1.28 thorpej static int 352 1.24 kent bba_halt_output(void *addr) 353 1.1 augustss { 354 1.24 kent struct bba_softc *sc; 355 1.24 kent struct bba_dma_state *d; 356 1.24 kent uint32_t ssr; 357 1.1 augustss 358 1.24 kent sc = addr; 359 1.24 kent d = &sc->sc_tx_dma_state; 360 1.1 augustss /* disable any DMA */ 361 1.1 augustss ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 362 1.1 augustss ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 363 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 364 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1); 365 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1); 366 1.1 augustss 367 1.1 augustss if (d->active) { 368 1.1 augustss bus_dmamap_unload(sc->sc_dmat, d->dmam); 369 1.1 augustss bus_dmamap_destroy(sc->sc_dmat, d->dmam); 370 1.1 augustss d->active = 0; 371 1.1 augustss } 372 1.1 augustss 373 1.1 augustss return 0; 374 1.1 augustss } 375 1.1 augustss 376 1.1 augustss 377 1.28 thorpej static int 378 1.24 kent bba_halt_input(void *addr) 379 1.1 augustss { 380 1.24 kent struct bba_softc *sc; 381 1.24 kent struct bba_dma_state *d; 382 1.24 kent uint32_t ssr; 383 1.1 augustss 384 1.24 kent sc = addr; 385 1.24 kent d = &sc->sc_rx_dma_state; 386 1.1 augustss /* disable any DMA */ 387 1.1 augustss ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 388 1.1 augustss ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 389 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 390 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1); 391 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1); 392 1.1 augustss 393 1.1 augustss if (d->active) { 394 1.1 augustss bus_dmamap_unload(sc->sc_dmat, d->dmam); 395 1.1 augustss bus_dmamap_destroy(sc->sc_dmat, d->dmam); 396 1.1 augustss d->active = 0; 397 1.1 augustss } 398 1.1 augustss 399 1.1 augustss return 0; 400 1.1 augustss } 401 1.1 augustss 402 1.1 augustss 403 1.28 thorpej static int 404 1.24 kent bba_getdev(void *addr, struct audio_device *retp) 405 1.1 augustss { 406 1.24 kent 407 1.1 augustss *retp = bba_device; 408 1.1 augustss return 0; 409 1.1 augustss } 410 1.1 augustss 411 1.1 augustss 412 1.28 thorpej static int 413 1.24 kent bba_trigger_output(void *addr, void *start, void *end, int blksize, 414 1.24 kent void (*intr)(void *), void *arg, 415 1.24 kent const audio_params_t *param) 416 1.1 augustss { 417 1.24 kent struct bba_softc *sc; 418 1.24 kent struct bba_dma_state *d; 419 1.24 kent uint32_t ssr; 420 1.23 kent tc_addr_t phys, nphys; 421 1.24 kent int state; 422 1.1 augustss 423 1.1 augustss DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 424 1.6 gmcgarry addr, start, end, blksize, intr, arg)); 425 1.24 kent sc = addr; 426 1.24 kent d = &sc->sc_tx_dma_state; 427 1.24 kent state = 0; 428 1.6 gmcgarry 429 1.6 gmcgarry /* disable any DMA */ 430 1.6 gmcgarry ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 431 1.6 gmcgarry ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 432 1.6 gmcgarry bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 433 1.1 augustss 434 1.1 augustss if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start, 435 1.9 thorpej BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 436 1.9 thorpej BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 437 1.1 augustss printf("bba_trigger_output: can't create DMA map\n"); 438 1.1 augustss goto bad; 439 1.1 augustss } 440 1.1 augustss state |= 1; 441 1.1 augustss 442 1.1 augustss if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, 443 1.13 thorpej (char *)end - (char *)start, NULL, BUS_DMA_WRITE|BUS_DMA_NOWAIT)) { 444 1.45 isaki printf("bba_trigger_output: can't load DMA map\n"); 445 1.1 augustss goto bad; 446 1.1 augustss } 447 1.1 augustss state |= 2; 448 1.1 augustss 449 1.1 augustss d->intr = intr; 450 1.1 augustss d->intr_arg = arg; 451 1.1 augustss d->curseg = 1; 452 1.1 augustss 453 1.1 augustss /* get physical address of buffer start */ 454 1.2 gmcgarry phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 455 1.2 gmcgarry nphys = (tc_addr_t)d->dmam->dm_segs[1].ds_addr; 456 1.1 augustss 457 1.1 augustss /* setup DMA pointer */ 458 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 459 1.6 gmcgarry IOASIC_DMA_ADDR(phys)); 460 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 461 1.6 gmcgarry IOASIC_DMA_ADDR(nphys)); 462 1.1 augustss 463 1.1 augustss /* kick off DMA */ 464 1.1 augustss ssr |= IOASIC_CSR_DMAEN_ISDN_T; 465 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 466 1.1 augustss 467 1.1 augustss d->active = 1; 468 1.1 augustss 469 1.1 augustss return 0; 470 1.1 augustss 471 1.1 augustss bad: 472 1.1 augustss if (state & 2) 473 1.1 augustss bus_dmamap_unload(sc->sc_dmat, d->dmam); 474 1.1 augustss if (state & 1) 475 1.1 augustss bus_dmamap_destroy(sc->sc_dmat, d->dmam); 476 1.1 augustss return 1; 477 1.1 augustss } 478 1.1 augustss 479 1.1 augustss 480 1.28 thorpej static int 481 1.24 kent bba_trigger_input(void *addr, void *start, void *end, int blksize, 482 1.24 kent void (*intr)(void *), void *arg, const audio_params_t *param) 483 1.1 augustss { 484 1.24 kent struct bba_softc *sc; 485 1.24 kent struct bba_dma_state *d; 486 1.23 kent tc_addr_t phys, nphys; 487 1.37 tsutsui uint32_t ssr; 488 1.1 augustss int state = 0; 489 1.1 augustss 490 1.1 augustss DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 491 1.6 gmcgarry addr, start, end, blksize, intr, arg)); 492 1.38 tsutsui sc = addr; 493 1.24 kent d = &sc->sc_rx_dma_state; 494 1.24 kent state = 0; 495 1.6 gmcgarry 496 1.6 gmcgarry /* disable any DMA */ 497 1.6 gmcgarry ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 498 1.6 gmcgarry ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 499 1.6 gmcgarry bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 500 1.1 augustss 501 1.1 augustss if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start, 502 1.9 thorpej BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 503 1.9 thorpej BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 504 1.1 augustss printf("bba_trigger_input: can't create DMA map\n"); 505 1.1 augustss goto bad; 506 1.1 augustss } 507 1.1 augustss state |= 1; 508 1.1 augustss 509 1.1 augustss if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, 510 1.13 thorpej (char *)end - (char *)start, NULL, BUS_DMA_READ|BUS_DMA_NOWAIT)) { 511 1.1 augustss printf("bba_trigger_input: can't load DMA map\n"); 512 1.1 augustss goto bad; 513 1.1 augustss } 514 1.1 augustss state |= 2; 515 1.1 augustss 516 1.1 augustss d->intr = intr; 517 1.1 augustss d->intr_arg = arg; 518 1.1 augustss d->curseg = 1; 519 1.1 augustss 520 1.1 augustss /* get physical address of buffer start */ 521 1.2 gmcgarry phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 522 1.2 gmcgarry nphys = (tc_addr_t)d->dmam->dm_segs[1].ds_addr; 523 1.1 augustss 524 1.1 augustss /* setup DMA pointer */ 525 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 526 1.6 gmcgarry IOASIC_DMA_ADDR(phys)); 527 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 528 1.6 gmcgarry IOASIC_DMA_ADDR(nphys)); 529 1.1 augustss 530 1.1 augustss /* kick off DMA */ 531 1.1 augustss ssr |= IOASIC_CSR_DMAEN_ISDN_R; 532 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 533 1.1 augustss 534 1.1 augustss d->active = 1; 535 1.1 augustss 536 1.1 augustss return 0; 537 1.1 augustss 538 1.1 augustss bad: 539 1.1 augustss if (state & 2) 540 1.1 augustss bus_dmamap_unload(sc->sc_dmat, d->dmam); 541 1.1 augustss if (state & 1) 542 1.1 augustss bus_dmamap_destroy(sc->sc_dmat, d->dmam); 543 1.1 augustss return 1; 544 1.1 augustss } 545 1.1 augustss 546 1.28 thorpej static int 547 1.24 kent bba_intr(void *addr) 548 1.1 augustss { 549 1.24 kent struct bba_softc *sc; 550 1.1 augustss struct bba_dma_state *d; 551 1.1 augustss tc_addr_t nphys; 552 1.39 jmcneill int mask; 553 1.1 augustss 554 1.24 kent sc = addr; 555 1.39 jmcneill mutex_enter(&sc->sc_am7930.sc_intr_lock); 556 1.1 augustss 557 1.1 augustss mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 558 1.1 augustss 559 1.1 augustss if (mask & IOASIC_INTR_ISDN_TXLOAD) { 560 1.1 augustss d = &sc->sc_tx_dma_state; 561 1.1 augustss d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 562 1.1 augustss nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 563 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, 564 1.6 gmcgarry IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 565 1.1 augustss if (d->intr != NULL) 566 1.1 augustss (*d->intr)(d->intr_arg); 567 1.1 augustss } 568 1.1 augustss if (mask & IOASIC_INTR_ISDN_RXLOAD) { 569 1.1 augustss d = &sc->sc_rx_dma_state; 570 1.1 augustss d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 571 1.1 augustss nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 572 1.1 augustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, 573 1.6 gmcgarry IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 574 1.1 augustss if (d->intr != NULL) 575 1.1 augustss (*d->intr)(d->intr_arg); 576 1.1 augustss } 577 1.1 augustss 578 1.39 jmcneill mutex_exit(&sc->sc_am7930.sc_intr_lock); 579 1.1 augustss 580 1.1 augustss return 0; 581 1.6 gmcgarry } 582 1.6 gmcgarry 583 1.28 thorpej static int 584 1.43 isaki bba_query_format(void *addr, audio_format_query_t *afp) 585 1.6 gmcgarry { 586 1.6 gmcgarry 587 1.43 isaki return audio_query_format(&bba_format, 1, afp); 588 1.23 kent } 589 1.23 kent 590 1.23 kent static int 591 1.43 isaki bba_set_format(void *addr, int setmode, 592 1.43 isaki const audio_params_t *play, const audio_params_t *rec, 593 1.43 isaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 594 1.23 kent { 595 1.23 kent 596 1.43 isaki if ((setmode & AUMODE_PLAY) != 0) { 597 1.43 isaki pfil->codec = audio_internal_to_mulaw32; 598 1.43 isaki } 599 1.43 isaki if ((setmode & AUMODE_RECORD) != 0) { 600 1.43 isaki rfil->codec = audio_mulaw32_to_internal; 601 1.43 isaki } 602 1.23 kent 603 1.23 kent return 0; 604 1.1 augustss } 605 1.1 augustss 606 1.28 thorpej static int 607 1.24 kent bba_round_blocksize(void *addr, int blk, int mode, const audio_params_t *param) 608 1.1 augustss { 609 1.24 kent 610 1.24 kent return IOASIC_DMA_BLOCKSIZE; 611 1.1 augustss } 612 1.1 augustss 613 1.1 augustss 614 1.1 augustss /* direct write */ 615 1.28 thorpej static void 616 1.46 isaki bba_codec_dwrite(struct am7930_softc *amsc, int reg, uint8_t val) 617 1.1 augustss { 618 1.24 kent struct bba_softc *sc; 619 1.1 augustss 620 1.46 isaki sc = (struct bba_softc *)amsc; 621 1.24 kent DPRINTF(("bba_codec_dwrite(): sc=%p, reg=%d, val=%d\n", sc, reg, val)); 622 1.1 augustss 623 1.9 thorpej #if defined(__alpha__) 624 1.5 gmcgarry bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, 625 1.9 thorpej reg << 2, val << 8); 626 1.9 thorpej #else 627 1.9 thorpej bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, 628 1.9 thorpej reg << 6, val); 629 1.9 thorpej #endif 630 1.1 augustss } 631 1.1 augustss 632 1.1 augustss /* direct read */ 633 1.28 thorpej static uint8_t 634 1.46 isaki bba_codec_dread(struct am7930_softc *amsc, int reg) 635 1.1 augustss { 636 1.24 kent struct bba_softc *sc; 637 1.1 augustss 638 1.46 isaki sc = (struct bba_softc *)amsc; 639 1.24 kent DPRINTF(("bba_codec_dread(): sc=%p, reg=%d\n", sc, reg)); 640 1.1 augustss 641 1.9 thorpej #if defined(__alpha__) 642 1.9 thorpej return ((bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, 643 1.9 thorpej reg << 2) >> 8) & 0xff); 644 1.9 thorpej #else 645 1.9 thorpej return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, 646 1.9 thorpej reg << 6) & 0xff); 647 1.9 thorpej #endif 648 1.1 augustss } 649