1 /* $NetBSD: haud.c,v 1.1 2026/06/11 01:03:58 rumble Exp $ */ 2 3 /* 4 * Copyright (c) 2025 Stephen M. Rumble <rumble (at) ephemeral.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/cdefs.h> 20 __KERNEL_RCSID(0, "$NetBSD: haud.c,v 1.1 2026/06/11 01:03:58 rumble Exp $"); 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/device.h> 25 #include <sys/audioio.h> 26 #include <sys/kmem.h> 27 #include <sys/bus.h> 28 #include <sys/malloc.h> 29 #include <sys/intr.h> 30 #include <machine/sysconf.h> 31 32 #include <dev/audio/audio_if.h> 33 #include <dev/firmload.h> 34 35 #include <sgimips/hpc/hpcvar.h> 36 #include <sgimips/hpc/hpcreg.h> 37 38 #include <sgimips/hpc/haudreg.h> 39 #include <sgimips/hpc/haudvar.h> 40 41 #ifdef AUDIO_DEBUG 42 #define DPRINTF(x) printf x 43 #else 44 #define DPRINTF(x) 45 #endif 46 47 static int haud_open(void *, int); 48 static int haud_query_format(void *, audio_format_query_t *); 49 static int haud_set_format(void *, int, 50 const audio_params_t *, const audio_params_t *, 51 audio_filter_reg_t *, audio_filter_reg_t *); 52 static int haud_round_blocksize(void *, int, 53 int, const audio_params_t *); 54 static int haud_start_output(void *, void *, int, void (*)(void *), 55 void *); 56 static int haud_halt_output(void *); 57 static int haud_getdev(void *, struct audio_device *); 58 static int haud_set_port(void *, mixer_ctrl_t *); 59 static int haud_get_port(void *, mixer_ctrl_t *); 60 static int haud_query_devinfo(void *, mixer_devinfo_t *); 61 static int haud_get_props(void *); 62 static void haud_get_locks(void *, kmutex_t **, kmutex_t **); 63 64 static const struct audio_hw_if haud_hw_if = { 65 .open = haud_open, 66 .query_format = haud_query_format, 67 .set_format = haud_set_format, 68 .start_output = haud_start_output, 69 .halt_output = haud_halt_output, 70 .getdev = haud_getdev, 71 .set_port = haud_set_port, 72 .get_port = haud_get_port, 73 .query_devinfo = haud_query_devinfo, 74 .get_props = haud_get_props, 75 .get_locks = haud_get_locks, 76 .round_blocksize = haud_round_blocksize, 77 }; 78 79 static const struct audio_device haud_device = { 80 "HAUD", 81 "", 82 "haud" 83 }; 84 85 static const struct audio_format haud_formats = { 86 .mode = AUMODE_PLAY, 87 .encoding = AUDIO_ENCODING_SLINEAR_BE, 88 .validbits = 16, 89 .precision = 16, 90 .channels = 2, 91 .channel_mask = AUFMT_STEREO, 92 .frequency_type = 1, 93 .frequency = { 44100 }, 94 }; 95 #define HAUD_NFORMATS __arraycount(haud_formats) 96 97 #define HAUD_MASTER_VOL 0 98 #define HAUD_OUTPUT_CLASS 1 99 100 static int haud_match(device_t, cfdata_t, void *); 101 static void haud_attach(device_t, device_t, void *); 102 static void haud_softintr(void *); 103 static int haud_intr(void *); 104 105 CFATTACH_DECL_NEW(haud, sizeof(struct haud_softc), 106 haud_match, haud_attach, NULL, NULL); 107 108 #define haud_write_sram_word(sc,idx,val) \ 109 bus_space_write_4(sc->sc_st, sc->sc_sram_sh, idx*4, val) 110 111 #define haud_write_reg(sc,off,val) \ 112 bus_space_write_4(sc->sc_st, sc->sc_regs_sh, off, val) 113 114 #define haud_read_reg(sc,off) \ 115 bus_space_read_4(sc->sc_st, sc->sc_regs_sh, off) 116 117 /* 118 * XXX We only allocate one sample buffer right now, which the DSP assigns 119 * this ID to. It happens to be the same as the kernel ID we send in the 120 * registration request. 121 * 122 * If we dynamically allocate buffers in the future, we will need to track the 123 * DSP IDs returned after registering. 124 */ 125 #define HAUD_SINGLETON_OUTPUT_BUFFER_ID 2 126 127 // Hardware assumes 4K pages. 128 CTASSERT(PAGE_SIZE == 4096); 129 130 #define WORDS_PER_PAGE (PAGE_SIZE / sizeof(u_int32_t)) 131 #define HEADER_WORDS (sizeof(haud_dsp_buffer_header_t) / sizeof(u_int32_t)) 132 133 static haud_dsp_buffer_header_t * 134 haud_buffer_header(haud_buffer_t *buf) { 135 KASSERT(MIPS_KSEG1_P(buf->pages[0].kaddr)); 136 return (haud_dsp_buffer_header_t *)buf->pages[0].kaddr; 137 } 138 139 static int 140 haud_buffer_word_capacity(haud_buffer_t *buf) 141 { 142 return (buf->npages * PAGE_SIZE - sizeof(haud_dsp_buffer_header_t)) / 143 sizeof(u_int32_t); 144 } 145 146 static int 147 haud_buffer_page_number(int buf_idx) 148 { 149 return (buf_idx + HEADER_WORDS) / WORDS_PER_PAGE; 150 } 151 152 static int 153 haud_buffer_page_offset(int buf_idx) 154 { 155 const int first_page_words = WORDS_PER_PAGE - HEADER_WORDS; 156 if (buf_idx < first_page_words) { 157 return buf_idx + HEADER_WORDS; 158 } else { 159 return (buf_idx - first_page_words) % WORDS_PER_PAGE; 160 } 161 } 162 163 static bus_addr_t 164 haud_buffer_page_dma_addr(haud_buffer_t *buf, int page) 165 { 166 KASSERT(buf->pages[page].dma_map->dm_nsegs == 1); 167 return buf->pages[page].dma_map->dm_segs[0].ds_addr; 168 } 169 170 static int 171 haud_buffer_occupied_words(haud_buffer_t *buf) 172 { 173 haud_dsp_buffer_header_t *hdr = haud_buffer_header(buf); 174 int head = hdr->head; 175 int tail = hdr->tail; 176 int capacity = haud_buffer_word_capacity(buf); 177 return tail >= head ? tail - head : capacity - (head - tail); 178 } 179 180 static int 181 haud_buffer_free_words(haud_buffer_t *buf) 182 { 183 return haud_buffer_word_capacity(buf) - haud_buffer_occupied_words(buf); 184 } 185 186 static bool 187 haud_alloc_buffer_page(struct haud_softc *sc, 188 haud_buffer_t *buf, 189 int page, 190 bool no_wait) 191 { 192 // HPC can only address 28 bits for SCSI and Ethernet. Does this 193 // device have the same limitation? Only a potential issue on IP20. 194 const bus_size_t boundary = 1 << 28; 195 196 const int flags = no_wait ? BUS_DMA_NOWAIT : 0; 197 198 int rsegs; 199 if (bus_dmamem_alloc(sc->sc_dma_tag, PAGE_SIZE, PAGE_SIZE, boundary, 200 &buf->pages[page].dma_seg, 1, &rsegs, flags)) { 201 goto fail_dmamem_alloc; 202 } 203 204 // We rely on BUS_DMA_COHERENT mapping accesses to KSEG1 (uncached) for 205 // the first page. This avoids potential clobbering of the header, and 206 // buffer contents following it, that could be in the same cache line. 207 // 208 // The problem is that CPU and DSP accesses to the circular buffer are 209 // apparently only loosely coordinated. If, for example, the CPU is 210 // reading from an input buffer, it must update the head index after 211 // consuming the DSP's data. However, the DSP may write new data to the 212 // buffer and update the tail index at any point (so long as the buffer 213 // isn't full). This means that we cannot keep the CPU cache coherent 214 // with the buffer. If the CPU were to update the head index with a 215 // cached write, we would risk writing back stale words in the same 216 // cacheline. 217 // 218 // This isn't a concern on IP12 since the R3000's D-cache is 4 bytes 219 // wide, but IP20's L1 and L2 caches are 32B and 128B, respectively. 220 // 221 // We could separate the header and buffer to limit uncached accesses 222 // to just the header. Cached reads/writes to audio data in the first 223 // page would be roughly 10x faster, but the benefit of speeding up 224 // access to 1/n'th of the buffer isn't really worth it. 225 const int coherent = page == 0 ? BUS_DMA_COHERENT : 0; 226 if (bus_dmamem_map(sc->sc_dma_tag, &buf->pages[page].dma_seg, 1, 227 PAGE_SIZE, (void **)&buf->pages[page].kaddr, flags | coherent)) { 228 goto fail_dmamem_map; 229 } 230 KASSERT((page != 0) ^ MIPS_KSEG1_P(buf->pages[page].kaddr)); 231 232 if (bus_dmamap_create(sc->sc_dma_tag, PAGE_SIZE, 1, PAGE_SIZE, boundary, 233 flags, &buf->pages[page].dma_map)) { 234 goto fail_dmamap_create; 235 } 236 237 if (bus_dmamap_load(sc->sc_dma_tag, buf->pages[page].dma_map, 238 buf->pages[page].kaddr, PAGE_SIZE, NULL, flags)) { 239 goto fail_dmamap_load; 240 } 241 242 memset(buf->pages[page].kaddr, 0, PAGE_SIZE); 243 244 return buf; 245 246 fail_dmamap_load: 247 bus_dmamap_destroy(sc->sc_dma_tag, buf->pages[page].dma_map); 248 fail_dmamap_create: 249 fail_dmamem_map: 250 bus_dmamem_free(sc->sc_dma_tag, &buf->pages[page].dma_seg, 1); 251 fail_dmamem_alloc: 252 return NULL; 253 } 254 255 static void 256 haud_free_buffer_page(struct haud_softc *sc, 257 haud_buffer_t *buf, 258 int page) 259 { 260 bus_dmamap_destroy(sc->sc_dma_tag, buf->pages[page].dma_map); 261 bus_dmamem_free(sc->sc_dma_tag, &buf->pages[page].dma_seg, 1); 262 } 263 264 static haud_buffer_t * 265 haud_create_buffer(struct haud_softc *sc, bool is_command_buffer) 266 { 267 int flags = (is_command_buffer ? M_NOWAIT : 0) | M_ZERO; 268 haud_buffer_t *buf = malloc(sizeof(haud_buffer_t), M_DEVBUF, flags); 269 if (buf == NULL) { 270 return NULL; 271 } 272 273 /* 274 * XXX Consider splitting the header and buffer and allocating the 275 * latter in virtually contiguous memory. That would simplify the 276 * buffer read/write routines for sample buffers. Though the command 277 * buffers can't be split and the asymmetry would add some complexity 278 * back. 279 */ 280 buf->npages = is_command_buffer ? 1 : __arraycount(buf->pages); 281 for (int i = 0; i < buf->npages; i++) { 282 const bool no_wait = is_command_buffer; 283 if (!haud_alloc_buffer_page(sc, buf, i, no_wait)) { 284 for (int j = 0; j < i; j++) { 285 haud_free_buffer_page(sc, buf, j); 286 } 287 return NULL; 288 } 289 } 290 291 cv_init(&buf->cv, "haudintr"); 292 293 return buf; 294 } 295 296 static void 297 haud_copy_audio_to_buffer(u_int32_t *dst, 298 const u_int16_t *src, 299 int copy_words) 300 { 301 // A simple copy loop is 7 instrs/word. Naive unrolling approaches 4, 302 // but GCC leaves load hazard slots unused (nop-filled). Manual 303 // pipelining fills those slots and approaches optimal 3 instrs/word. 304 // Too bad the samples aren't half-word aligned... 305 const u_int16_t *end = src + copy_words; 306 while (src + 16 <= end) { 307 u_int16_t a, b; 308 #define _pipelined_copy(_x, _y) \ 309 a = src[_x]; \ 310 b = src[_y]; \ 311 dst[_x] = ((u_int32_t)a) << 8; \ 312 dst[_y] = ((u_int32_t)b) << 8 313 _pipelined_copy(0, 1); 314 _pipelined_copy(2, 3); 315 _pipelined_copy(4, 5); 316 _pipelined_copy(6, 7); 317 _pipelined_copy(8, 9); 318 _pipelined_copy(10, 11); 319 _pipelined_copy(12, 13); 320 _pipelined_copy(14, 15); 321 #undef _pipelined_copy 322 src += 16, dst += 16; 323 } 324 while (src < end) { 325 *dst++ = ((u_int32_t)*src++) << 8; 326 } 327 } 328 329 static void 330 haud_copy_audio_from_buffer(u_int16_t *dst, const u_int32_t *src, int copy_words) { 331 const u_int32_t *end = src + copy_words; 332 while (src + 16 <= end) { 333 u_int32_t a, b; 334 #define _pipelined_copy(_x, _y) \ 335 a = src[_x]; \ 336 b = src[_y]; \ 337 dst[_x] = (a >> 8) & 0xffff; \ 338 dst[_y] = (b >> 8) & 0xffff 339 _pipelined_copy(0, 1); 340 _pipelined_copy(2, 3); 341 _pipelined_copy(4, 5); 342 _pipelined_copy(6, 7); 343 _pipelined_copy(8, 9); 344 _pipelined_copy(10, 11); 345 _pipelined_copy(12, 13); 346 _pipelined_copy(14, 15); 347 #undef _pipelined_copy 348 src += 16, dst += 16; 349 } 350 while (src < end) { 351 *dst++ = (*src++ >> 8) & 0xffff; 352 } 353 } 354 355 /* 356 * Adapter for callers that write / read commands (32-bit) or audio (16-bit) 357 * to / from the 32-bit circular DSP buffer using haud_{write,read}_buffer. 358 */ 359 typedef struct haud_buffer_io { 360 enum haud_buffer_io_type { 361 IO_TYPE_COMMAND, 362 IO_TYPE_AUDIO, 363 } type; 364 union { 365 u_int32_t *command; 366 u_int16_t *audio; 367 } data; 368 int length; 369 } haud_buffer_io_t; 370 371 static bool 372 haud_wait_for_write(struct haud_softc *sc, haud_buffer_t *buf, int words) 373 { 374 KASSERT(mutex_owned(&sc->sc_intr_lock)); 375 for (int i = 0; haud_buffer_free_words(buf) < words; i++) { 376 if (i == 10) { 377 printf("%s: wait_for_write stuck; bailing\n", 378 device_xname(sc->sc_dev)); 379 return false; 380 } 381 haud_dsp_buffer_header_t *hdr = haud_buffer_header(buf); 382 hdr->watr = haud_buffer_word_capacity(buf) - words; 383 hdr->intr = 1; 384 cv_timedwait(&buf->cv, &sc->sc_intr_lock, mstohz(100)); 385 } 386 return true; 387 } 388 389 static bool 390 haud_write_buffer(struct haud_softc *sc, 391 haud_buffer_t *buf, 392 const haud_buffer_io_t *input) 393 { 394 KASSERT(mutex_owned(&sc->sc_intr_lock)); 395 396 haud_dsp_buffer_header_t *hdr = haud_buffer_header(buf); 397 398 KASSERT(buf->is_write_buffer); 399 const int cap = haud_buffer_word_capacity(buf); 400 KASSERT(input->length <= cap); 401 402 if (!haud_wait_for_write(sc, buf, input->length)) { 403 printf("%s: write_buffer timed out waiting for free space; " 404 "dropping samples", device_xname(sc->sc_dev)); 405 return false; 406 } 407 408 int tail = hdr->tail; 409 int words_left = input->length; 410 while (words_left > 0) { 411 const int page = haud_buffer_page_number(tail); 412 const int page_offset = haud_buffer_page_offset(tail); 413 const int src_start = input->length - words_left; 414 const int words = MIN(words_left, WORDS_PER_PAGE - page_offset); 415 u_int32_t *dst = buf->pages[page].kaddr + page_offset; 416 417 if (input->type == IO_TYPE_AUDIO) { 418 const u_int16_t *src = input->data.audio + src_start; 419 haud_copy_audio_to_buffer(dst, src, words); 420 } else { 421 const u_int32_t *src = input->data.command + src_start; 422 for (int i = 0; i < words; i++) { 423 dst[i] = *src++; 424 } 425 } 426 427 tail += words; 428 if (tail == haud_buffer_word_capacity(buf)) { 429 tail = 0; 430 } 431 words_left -= words; 432 433 bus_dmamap_sync(sc->sc_dma_tag, buf->pages[page].dma_map, 434 page_offset * sizeof(u_int32_t), words * sizeof(u_int32_t), 435 BUS_DMASYNC_PREWRITE); 436 } 437 hdr->tail = tail; 438 439 return true; 440 } 441 442 static bool 443 haud_wait_for_read(struct haud_softc *sc, haud_buffer_t *buf, int words) 444 { 445 KASSERT(mutex_owned(&sc->sc_intr_lock)); 446 for (int i = 0; haud_buffer_occupied_words(buf) < words; i++) { 447 if (i == 10) { 448 printf("%s: wait_for_read stuck; bailing\n", 449 device_xname(sc->sc_dev)); 450 return false; 451 } 452 haud_dsp_buffer_header_t *hdr = haud_buffer_header(buf); 453 hdr->watr = haud_buffer_word_capacity(buf) - words; 454 hdr->intr = 1; 455 cv_timedwait(&buf->cv, &sc->sc_intr_lock, mstohz(100)); 456 } 457 return true; 458 } 459 460 static bool 461 haud_read_buffer(struct haud_softc *sc, 462 haud_buffer_t *buf, 463 const haud_buffer_io_t *output) 464 { 465 KASSERT(mutex_owned(&sc->sc_intr_lock)); 466 467 haud_dsp_buffer_header_t *hdr = haud_buffer_header(buf); 468 469 KASSERT(!buf->is_write_buffer); 470 const int cap = haud_buffer_word_capacity(buf); 471 KASSERT(output->length <= cap); 472 473 // XXX- Handle the case of audio with stopped sampling, resulting in 474 // a short read. 475 if (!haud_wait_for_read(sc, buf, output->length)) { 476 printf("%s: read_buffer timed out waiting for data; " 477 "dropping samples", device_xname(sc->sc_dev)); 478 return false; 479 } 480 481 int head = hdr->head; 482 int words_left = output->length; 483 while (words_left > 0) { 484 const int page = haud_buffer_page_number(head); 485 const int page_offset = haud_buffer_page_offset(head); 486 const int dst_start = output->length - words_left; 487 const int words = MIN(words_left, WORDS_PER_PAGE - page_offset); 488 u_int32_t *src = buf->pages[page].kaddr + page_offset; 489 490 bus_dmamap_sync(sc->sc_dma_tag, buf->pages[page].dma_map, 491 page_offset * sizeof(u_int32_t), words * sizeof(u_int32_t), 492 BUS_DMASYNC_PREREAD); 493 494 if (output->type == IO_TYPE_AUDIO) { 495 u_int16_t *dst = output->data.audio + dst_start; 496 haud_copy_audio_from_buffer(dst, src, words); 497 } else { 498 u_int32_t *dst = output->data.command + dst_start; 499 for (int i = 0; i < words; i++) { 500 *dst++ = src[i]; 501 } 502 } 503 504 head += words; 505 if (head == haud_buffer_word_capacity(buf)) { 506 head = 0; 507 } 508 words_left -= words; 509 } 510 hdr->head = head; 511 512 return true; 513 } 514 515 static void 516 haud_dsp_request(struct haud_softc *sc, 517 u_int32_t *request, 518 u_int32_t request_byte_length, 519 u_int32_t *response, 520 u_int32_t response_byte_length) 521 { 522 KASSERT(mutex_owned(&sc->sc_intr_lock)); 523 524 // Requests/responses are always in word lengths (byte parameters 525 // are for caller convenience of using sizeof). 526 KASSERT(request_byte_length % 4 == 0); 527 KASSERT(response_byte_length % 4 == 0); 528 const int request_words = request_byte_length / 4; 529 const int response_words = response_byte_length / 4; 530 531 // Set the len field. 532 request[0] = request_words; 533 534 DPRINTF(("haud: Sending request to DSP:\n")); 535 for (int i = 0; i < request_words; i++) { 536 DPRINTF((" 0x%x\n", request[i])); 537 } 538 539 haud_buffer_io_t input = { 540 .type = IO_TYPE_COMMAND, 541 .data.command = request, 542 .length = request_words 543 }; 544 haud_write_buffer(sc, sc->sc_cmd_req, &input); 545 546 // The DSP responds almost immediately to some commands, but changing 547 // audio parameters can take hundreds of milliseconds. 548 if (!haud_wait_for_read(sc, sc->sc_cmd_resp, response_words)) { 549 printf("%s: DSP did not respond to request id %d\n", 550 device_xname(sc->sc_dev), request[1]); 551 return; 552 } 553 554 haud_buffer_io_t output = { 555 .type = IO_TYPE_COMMAND, 556 .data.command = response, 557 .length = response_words 558 }; 559 haud_read_buffer(sc, sc->sc_cmd_resp, &output); 560 561 DPRINTF(("haud: Received response from DSP:\n")); 562 for (int i = 0; i < response_words; i++) { 563 DPRINTF((" 0x%x\n", response[i])); 564 } 565 } 566 567 static haud_buffer_t * 568 haud_alloc_sample_buffer(struct haud_softc *sc, 569 u_int32_t kern_id, 570 bool is_write_buffer) 571 { 572 haud_buffer_t *buf = haud_create_buffer(sc, false); 573 if (buf == NULL) { 574 return buf; 575 } 576 577 buf->kern_id = kern_id; 578 buf->is_write_buffer = is_write_buffer; 579 580 // Register the buffer with the DSP. 581 struct haud_dsp_cmd_register_buffer_req req; 582 req.op = HAUD_DSP_CMD_REGISTER_BUFFER_OPCODE; 583 req.kern_id = kern_id; 584 req.cap = haud_buffer_word_capacity(buf); 585 req.out = is_write_buffer ? 1 : 0; 586 req.hdr_hi = haud_buffer_page_dma_addr(buf, 0) >> 16; 587 req.hdr_lo = haud_buffer_page_dma_addr(buf, 0) & 0xffff; 588 req.buf_off = sizeof(*haud_buffer_header(buf)); 589 for (int i = 0; i < __arraycount(req.page_nums); i++) { 590 req.page_nums[i] = haud_buffer_page_dma_addr(buf, i) >> 12; 591 } 592 CTASSERT(__arraycount(buf->pages) == __arraycount(req.page_nums)); 593 594 struct haud_dsp_cmd_register_buffer_resp resp; 595 haud_dsp_request(sc, (u_int32_t *)&req, sizeof(req), 596 (u_int32_t *)&resp, sizeof(resp)); 597 598 buf->dsp_id = resp.dsp_id; 599 600 return buf; 601 } 602 603 static void 604 haud_set_audio_params(struct haud_softc *sc) 605 { 606 KASSERT(mutex_owned(&sc->sc_intr_lock)); 607 608 struct haud_dsp_cmd_set_audio_params_req req; 609 req.op = HAUD_DSP_CMD_SET_AUDIO_PARAMS; 610 req.unknown = 0; 611 #define _setparam(_i, _p, _v) \ 612 req.params[_i].param = _p; \ 613 req.params[_i].value = _v 614 _setparam(0, HAUD_AUDIO_PARAMS_INPUT_SRC, 0); 615 _setparam(1, HAUD_AUDIO_PARAMS_INPUT_ATTN_L, 0); 616 _setparam(2, HAUD_AUDIO_PARAMS_INPUT_ATTN_R, 0); 617 _setparam(3, HAUD_AUDIO_PARAMS_INPUT_RATE, HAUD_RATE_44100); 618 _setparam(4, HAUD_AUDIO_PARAMS_OUTPUT_RATE, HAUD_RATE_44100); 619 _setparam(5, HAUD_AUDIO_PARAMS_SPKR_GAIN_L, sc->sc_speaker_l_gain); 620 _setparam(6, HAUD_AUDIO_PARAMS_SPKR_GAIN_R, sc->sc_speaker_r_gain); 621 #undef _setparam 622 623 struct haud_dsp_cmd_set_audio_params_resp resp; 624 haud_dsp_request(sc, (u_int32_t *)&req, sizeof(req), 625 (u_int32_t *)&resp, sizeof(resp)); 626 627 } 628 629 static bool 630 haud_load_firmware(struct haud_softc *sc) 631 { 632 const int firmware_size = 128 * 1024; 633 firmware_handle_t fhp; 634 uint32_t *fw = NULL; 635 int error; 636 637 if ((error = firmware_open("haud", "hdsp.bin", &fhp))) { 638 printf("%s: error %d opening firmware file, see haud(9)\n", 639 device_xname(sc->sc_dev), error); 640 return false; 641 } 642 643 if (firmware_get_size(fhp) != firmware_size) { 644 printf("%s: invalid firmware file size (must be %dKiB)\n", 645 device_xname(sc->sc_dev), firmware_size / 1024); 646 firmware_close(fhp); 647 return false; 648 } 649 650 fw = malloc(firmware_size, M_DEVBUF, M_NOWAIT | M_ZERO); 651 if (fw == NULL) { 652 firmware_close(fhp); 653 return false; 654 } 655 656 if ((error = firmware_read(fhp, 0, fw, firmware_size))) { 657 printf("%s: firmware file read failedu: %d\n", 658 device_xname(sc->sc_dev), error); 659 firmware_close(fhp); 660 free(fw, M_DEVBUF); 661 return false; 662 } 663 664 for (int i = 0; i < firmware_size / 4; i++) { 665 haud_write_sram_word(sc, i, fw[i]); 666 } 667 668 firmware_close(fhp); 669 free(fw, M_DEVBUF); 670 671 return true; 672 } 673 674 static bool 675 haud_boot_dsp(struct haud_softc *sc) 676 { 677 KASSERT(mutex_owned(&sc->sc_intr_lock)); 678 679 if (sc->sc_dsp_booted) { 680 return true; 681 } 682 683 haud_write_reg(sc, HAUD_MISC_CSR, 684 HAUD_MISC_CSR_RESET | HAUD_MISC_CSR_32K_SRAM); 685 delay(100); 686 687 mutex_spin_exit(&sc->sc_intr_lock); 688 bool loaded = haud_load_firmware(sc); 689 mutex_spin_enter(&sc->sc_intr_lock); 690 691 if (!loaded) { 692 return false; 693 } 694 695 // Set up command request buffer and point the DSP at it. 696 haud_buffer_header(sc->sc_cmd_req)->head = 0; 697 haud_buffer_header(sc->sc_cmd_req)->tail = 0; 698 haud_buffer_header(sc->sc_cmd_req)->intr = 0; 699 haud_buffer_header(sc->sc_cmd_req)->watr = 0; 700 haud_write_sram_word(sc, 0, 701 haud_buffer_page_dma_addr(sc->sc_cmd_req, 0) & 0xffff); 702 haud_write_sram_word(sc, 1, 703 haud_buffer_page_dma_addr(sc->sc_cmd_req, 0) >> 16); 704 haud_write_sram_word(sc, 2, haud_buffer_word_capacity(sc->sc_cmd_req)); 705 706 // Set up command response buffer and point the DSP at it. 707 haud_buffer_header(sc->sc_cmd_resp)->head = 0; 708 haud_buffer_header(sc->sc_cmd_resp)->tail = 0; 709 haud_buffer_header(sc->sc_cmd_resp)->intr = 0; 710 haud_buffer_header(sc->sc_cmd_resp)->watr = 0; 711 haud_write_sram_word(sc, 3, 712 haud_buffer_page_dma_addr(sc->sc_cmd_resp, 0) & 0xffff); 713 haud_write_sram_word(sc, 4, 714 haud_buffer_page_dma_addr(sc->sc_cmd_resp, 0) >> 16); 715 haud_write_sram_word(sc, 5, haud_buffer_word_capacity(sc->sc_cmd_resp)); 716 717 // Enable TX and RX handshake interrupts. Don't interrupt on DMA, as 718 // that happens far too frequently. 719 haud_write_reg(sc, HAUD_CPU_INTR_STAT, 0); 720 haud_write_reg(sc, HAUD_CPU_INTR_MASK, 721 HAUD_CPU_INTR_MASK_TX_ENBL | HAUD_CPU_INTR_MASK_RX_ENBL); 722 723 // Fire up the DSP. 724 haud_write_reg(sc, HAUD_MISC_CSR, HAUD_MISC_CSR_32K_SRAM); 725 726 // Wait for the firmware to interrupt. This should happen within tens 727 // of microseconds. 728 cv_timedwait(&sc->sc_cmd_req->cv, &sc->sc_intr_lock, mstohz(10)); 729 730 if (!sc->sc_dsp_booted) { 731 printf("%s: DSP failed to boot within 1000 usec\n", 732 device_xname(sc->sc_dev)); 733 return false; 734 } 735 736 printf("%s: DSP firmware booted\n", device_xname(sc->sc_dev)); 737 738 // Set up initial audio parameters. 739 sc->sc_speaker_l_gain = sc->sc_speaker_r_gain = 16; 740 haud_set_audio_params(sc); 741 742 // Allocate and register our single output buffer. 743 sc->sc_output = haud_alloc_sample_buffer( 744 sc, HAUD_SINGLETON_OUTPUT_BUFFER_ID, true); 745 if (sc->sc_output == NULL) { 746 // Bummer. Well, just reset the chip and we can try to reinit 747 // again later. 748 haud_write_reg(sc, HAUD_MISC_CSR, 749 HAUD_MISC_CSR_RESET | HAUD_MISC_CSR_32K_SRAM); 750 sc->sc_dsp_booted = false; 751 return false; 752 } 753 754 return true; 755 } 756 757 /* 758 * Hollywood Audio should be present on most, if not all, IP12 Indigos and IP20 759 * Indigos, though perhaps rare "Hollywood Light" or VME-based Indigos lack it. 760 * 761 * On IP12 Personal Irises the same Hollywood Audio hardware was implemented 762 * as an option card called "Magnum Audio" (partially, anyway -- the DSP and 763 * some other components are always on the mainboard). 764 */ 765 static int 766 haud_match(device_t parent, cfdata_t cf, void *aux) 767 { 768 struct hpc_attach_args *haa = aux; 769 770 if (strcmp(haa->ha_name, cf->cf_name)) { 771 return 0; 772 } 773 774 // See if we can read the CSR register. 775 if (platform.badaddr((void *)(vaddr_t)(haa->ha_sh + haa->ha_devoff + 776 HAUD_MISC_CSR), sizeof(uint32_t))) { 777 aprint_normal(": not installed (CSR unreadable)"); 778 return 0; 779 } 780 781 // See if we can read the first word in the DSP's SRAM. 782 if (platform.badaddr((void *)(vaddr_t)(haa->ha_sh + haa->ha_dmaoff), 783 sizeof(uint32_t))) { 784 aprint_normal(": not installed (SRAM unreadable)"); 785 return 0; 786 } 787 788 // Try resetting the DSP, writing to DSP SRAM, and reading back. 789 *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(haa->ha_sh + haa->ha_devoff + 790 HAUD_MISC_CSR) = HAUD_MISC_CSR_RESET | HAUD_MISC_CSR_32K_SRAM; 791 delay(100); 792 const uint32_t random_24b = 0x00448de3; 793 *(volatile uint32_t *) 794 MIPS_PHYS_TO_KSEG1(haa->ha_sh + haa->ha_dmaoff) = random_24b; 795 if (*(volatile uint32_t *) 796 MIPS_PHYS_TO_KSEG1(haa->ha_sh + haa->ha_dmaoff) != random_24b) { 797 aprint_normal(": not installed (SRAM unwritable)"); 798 return 0; 799 } 800 801 return 1; 802 } 803 804 static void 805 haud_attach(device_t parent, device_t self, void *aux) 806 { 807 struct haud_softc *sc = device_private(self); 808 struct hpc_attach_args *haa = aux; 809 810 sc->sc_dev = self; 811 sc->sc_st = haa->ha_st; 812 sc->sc_dma_tag = haa->ha_dmat; 813 814 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 815 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 816 817 if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff, 818 HPC1_DSP_DEVREGS_SIZE, &sc->sc_regs_sh)) { 819 aprint_error(": unable to map HPC registers\n"); 820 return; 821 } 822 823 if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_dmaoff, 824 HPC1_DSP_SRAM_SIZE, &sc->sc_sram_sh)) { 825 aprint_error(": unable to map SRAM\n"); 826 return; 827 } 828 829 sc->sc_output_softint_cookie = softint_establish(SOFTINT_SERIAL, 830 haud_softintr, sc); 831 if (sc->sc_output_softint_cookie == NULL) { 832 aprint_error(": unable to establish soft interrupt\n"); 833 return; 834 } 835 836 if (cpu_intr_establish(haa->ha_irq, IPL_AUDIO, haud_intr, sc) == NULL) { 837 aprint_error(": unable to establish hw interrupt\n"); 838 softint_disestablish(sc->sc_output_softint_cookie); 839 return; 840 } 841 842 sc->sc_cmd_req = haud_create_buffer(sc, true); 843 KASSERT(sc->sc_cmd_req != NULL); 844 sc->sc_cmd_req->kern_id = 0; 845 sc->sc_cmd_req->dsp_id = 0; 846 sc->sc_cmd_req->is_write_buffer = true; 847 848 sc->sc_cmd_resp = haud_create_buffer(sc, true); 849 KASSERT(sc->sc_cmd_resp != NULL); 850 sc->sc_cmd_req->kern_id = 1; 851 sc->sc_cmd_req->dsp_id = 1; 852 sc->sc_cmd_resp->is_write_buffer = false; 853 854 aprint_normal(": Hollywood Audio (awaiting firmware, see haud(4))\n"); 855 856 sc->sc_dsp_booted = false; 857 858 audio_attach_mi(&haud_hw_if, sc, self); 859 } 860 861 static void 862 haud_softintr(void *v) 863 { 864 struct haud_softc *sc = v; 865 mutex_spin_enter(&sc->sc_intr_lock); 866 if (sc->sc_output_intr) { 867 sc->sc_output_intr(sc->sc_output_intr_arg); 868 } 869 mutex_spin_exit(&sc->sc_intr_lock); 870 } 871 872 static int 873 haud_intr(void *v) 874 { 875 struct haud_softc *sc = v; 876 bool handled = false; 877 878 mutex_spin_enter(&sc->sc_intr_lock); 879 880 if (!sc->sc_dsp_booted) { 881 sc->sc_dsp_booted = true; 882 } 883 884 const u_int32_t stat = haud_read_reg(sc, HAUD_CPU_INTR_STAT); 885 haud_write_reg(sc, HAUD_CPU_INTR_STAT, 0); 886 887 if (stat & HAUD_CPU_INTR_STAT_DMA) { 888 // Nothing to do (this should be masked out anyway). 889 } 890 891 if (stat & HAUD_CPU_INTR_STAT_TX) { 892 haud_buffer_t *buf = NULL; 893 const u_int32_t buf_id = haud_read_reg(sc, HAUD_TX_HANDSHAKE); 894 switch (buf_id) { 895 case 0: 896 buf = sc->sc_cmd_req; 897 break; 898 case 1: 899 // Why TX interrupts for the cmd response queue? 900 buf = sc->sc_cmd_resp; 901 break; 902 case HAUD_SINGLETON_OUTPUT_BUFFER_ID: 903 buf = sc->sc_output; 904 break; 905 case 0xffff: 906 // Usually this ID is read when the DSP first interrupts 907 // after booting. 908 break; 909 default: 910 printf("%s: unexpected TX intr for buf id 0x%x\n", 911 device_xname(sc->sc_dev), buf_id); 912 break; 913 } 914 915 if (buf != NULL) { 916 // If a thread is waiting in haud_wait_for_write, we 917 // will wake it up below. 918 haud_buffer_header(buf)->intr = 0; 919 cv_signal(&buf->cv); 920 } 921 922 handled = true; 923 } 924 925 if (stat & HAUD_CPU_INTR_STAT_RX) { 926 // Nothing to do until we support recording. 927 } 928 929 mutex_spin_exit(&sc->sc_intr_lock); 930 931 return handled; 932 } 933 934 static int 935 haud_open(void *v, int flags) 936 { 937 struct haud_softc *sc = v; 938 939 if (!haud_boot_dsp(sc)) { 940 return ENXIO; 941 } 942 943 return 0; 944 } 945 946 static int 947 haud_query_format(void *v, audio_format_query_t *afp) 948 { 949 return audio_query_format(&haud_formats, 1, afp); 950 } 951 952 static int 953 haud_set_format(void *v, int setmode, 954 const audio_params_t *play, const audio_params_t *rec, 955 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 956 { 957 /* Nothing to do. We only support one format right now. */ 958 return 0; 959 } 960 961 static int 962 haud_round_blocksize(void *v, int blocksize, 963 int mode, const audio_params_t *param) 964 { 965 KASSERT(blocksize <= PAGE_SIZE * 4); 966 return PAGE_SIZE * 4; 967 } 968 969 static int 970 haud_halt_output(void *v) 971 { 972 /* Nothing special to do. DSP will stop when it hits the tail. */ 973 struct haud_softc *sc = v; 974 sc->sc_output_intr = NULL; 975 return 0; 976 } 977 978 static int 979 haud_getdev(void *v, struct audio_device *dev) 980 { 981 *dev = haud_device; 982 return 0; 983 } 984 985 static int 986 haud_set_port(void *v, mixer_ctrl_t *mc) 987 { 988 struct haud_softc *sc = v; 989 990 KASSERT(!mutex_owned(&sc->sc_intr_lock)); 991 992 if (mc->type != AUDIO_MIXER_VALUE || 993 mc->dev != HAUD_MASTER_VOL || 994 mc->un.value.num_channels != 2) { 995 return EINVAL; 996 } 997 998 const int l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 999 const int r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 1000 if (l < HAUD_MIN_GAIN || r < HAUD_MIN_GAIN || 1001 l > HAUD_MAX_GAIN || r > HAUD_MAX_GAIN) { 1002 return EINVAL; 1003 } 1004 if (l != sc->sc_speaker_l_gain || r != sc->sc_speaker_r_gain) { 1005 mutex_spin_enter(&sc->sc_intr_lock); 1006 sc->sc_speaker_l_gain = l; 1007 sc->sc_speaker_r_gain = r; 1008 if (sc->sc_dsp_booted) { 1009 haud_set_audio_params(sc); 1010 } 1011 mutex_spin_exit(&sc->sc_intr_lock); 1012 } 1013 1014 return 0; 1015 } 1016 1017 static int 1018 haud_get_port(void *v, mixer_ctrl_t *mc) 1019 { 1020 struct haud_softc *sc = v; 1021 1022 KASSERT(!mutex_owned(&sc->sc_intr_lock)); 1023 1024 if (mc->type != AUDIO_MIXER_VALUE || 1025 mc->dev != HAUD_MASTER_VOL || 1026 mc->un.value.num_channels != 2) { 1027 return EINVAL; 1028 } 1029 1030 mutex_spin_enter(&sc->sc_intr_lock); 1031 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_speaker_r_gain; 1032 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_speaker_l_gain; 1033 mutex_spin_exit(&sc->sc_intr_lock); 1034 1035 return 0; 1036 } 1037 1038 static int 1039 haud_query_devinfo(void *v, mixer_devinfo_t *dev) 1040 { 1041 switch (dev->index) { 1042 case HAUD_MASTER_VOL: 1043 dev->type = AUDIO_MIXER_VALUE; 1044 dev->mixer_class = HAUD_OUTPUT_CLASS; 1045 dev->prev = dev->next = AUDIO_MIXER_LAST; 1046 strcpy(dev->label.name, AudioNmaster); 1047 dev->un.v.num_channels = 2; 1048 dev->un.v.delta = 16; 1049 strcpy(dev->un.v.units.name, AudioNvolume); 1050 break; 1051 1052 case HAUD_OUTPUT_CLASS: 1053 dev->type = AUDIO_MIXER_CLASS; 1054 dev->mixer_class = HAUD_OUTPUT_CLASS; 1055 dev->next = dev->prev = AUDIO_MIXER_LAST; 1056 strcpy(dev->label.name, AudioCoutputs); 1057 break; 1058 1059 default: 1060 return EINVAL; 1061 } 1062 1063 return 0; 1064 } 1065 1066 static int 1067 haud_get_props(void *v) 1068 { 1069 return AUDIO_PROP_PLAYBACK; 1070 } 1071 1072 static int 1073 haud_start_output(void *v, void *block, int blksize, 1074 void (*intr)(void *), void *intrarg) 1075 { 1076 struct haud_softc *sc = v; 1077 1078 KASSERT(mutex_owned(&sc->sc_intr_lock)); 1079 1080 sc->sc_output_intr = intr; 1081 sc->sc_output_intr_arg = intrarg; 1082 1083 haud_buffer_io_t input = { 1084 .type = IO_TYPE_AUDIO, 1085 .data.audio = block, 1086 .length = blksize / 2 1087 }; 1088 if (!haud_write_buffer(sc, sc->sc_output, &input)) { 1089 return EBUSY; 1090 } 1091 1092 // Trigger the next block of input. 1093 softint_schedule(sc->sc_output_softint_cookie); 1094 1095 return 0; 1096 } 1097 1098 static void 1099 haud_get_locks(void *v, kmutex_t **intr, kmutex_t **thread) 1100 { 1101 struct haud_softc *sc = v; 1102 *intr = &sc->sc_intr_lock; 1103 *thread = &sc->sc_lock; 1104 } 1105