Home | History | Annotate | Line # | Download | only in hpc
      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