1 /* $NetBSD: haudvar.h,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 21 #ifndef _ARCH_SGIMIPS_HPC_HAUDVAR_H_ 22 #define _ARCH_SGIMIPS_HPC_HAUDVAR_H_ 23 24 /* 25 * Hollywood Audio is based around a Motorola 56001 DSP and supporting hardware 26 * such as DACs, SRAMs, the HPC, and either the AUD1 ASIC or an equivalent FPGA. 27 * 28 * This driver leverages IRIX's hdsp.lod 56K code, which takes care of the audio 29 * hardware behind the DSP and interfaces with the kernel primarily via circular 30 * buffers in host physical memory. 31 * 32 * The DSP has a 32768 24-bit word memory provided by three 32Kbyte SRAMs. This 33 * is used for the DSP's firmware code and data. The HPC maps the SRAMs into 34 * the CPU's physical address space so that the kernel can load the DSP's 35 * firmware and initialise circular command buffers. The SRAM is mapped via 36 * 32768 contiguous 32-bit words at offset HPC1_DSP_SRAM. The HPC also provides 37 * DMA for the DSP so that it can read from or write to the circular buffers in 38 * host memory. 39 * 40 * IRIX's hdsp.lod firmware has two command buffers, one for sending command 41 * requests to the DSP and one for receiving responses back. Command examples 42 * include setting up new circular buffers for playback or recording ('sample 43 * buffers'), tearing down unused circular buffers, and changing various audio 44 * parameters such as output volumes, input attentuation, etc. 45 * 46 * The command request and response buffers are bootstrapped by writing to 47 * special locations low in the SRAM space (after writing the firmware, but 48 * before taking the DSP chip out of reset). After bootstrap, all subsequent 49 * interaction happens via host memory (buffers), registers in the HPC, and 50 * interrupts. The command request and response buffers are contiguous in host 51 * physical memory, though due to their small size they can easily fit within a 52 * page. 53 * 54 * All playback and recording uses 16-bit big endian PCM samples. Each sample 55 * occupies a full 32-bit word in the circular buffer and is shifted 8 bits left 56 * (i.e., it occupies the middle two bytes). 57 * 58 * Sample buffers for playback and recording do not need to be physically 59 * contiguous in memory. Constituent pages are registered with the DSP as part 60 * of setting up a new buffer (via the command buffer). 61 * 62 * Both command and sample buffers are controlled by a 16-byte header. The 63 * command buffers' headers are followed immediately by their circular buffer. 64 * Sample buffers' headers and circular buffers can be split apart, but this 65 * driver maintains the same layout for both types. 66 * 67 * The header's format is shared with the DSP and consists of four 32-bit fields 68 * (see haud_dsp_buffer_header_t below for details). Each circular buffer is 69 * either used to send audio data to the DSP for playback (TX) or receive audio 70 * data from the DSP for recording (RX). 71 * 72 * Each sample buffer has two unique identifiers: one assigned by the kernel and 73 * registered with the DSP (kern_id), and one assigned by the DSP in response to 74 * the registration (dsp_id). The DSP-returned ID is presumably dense and refers 75 * to a fixed table of buffers under management. The DSP writes dsp_id to the TX 76 * handshake register to indicate which buffer the current interrupt applies to. 77 * It's not really clear what use kern_id has on the DSP side. 78 * 79 * The special command request and response queues apparently go by IDs 0 and 1, 80 * respectively, and the first sample buffer registered gets ID 2. 81 * 82 * The DSP appears to only support one output stream and one input stream, as 83 * sample buffers aren't registered against a particular port and sample rates 84 * are configured globally for all outputs and all inputs. That said, the DSP 85 * will supposedly mix multiple active output buffers automatically (per IRIX's 86 * audio(1) manpage). 87 * 88 * Audio is played to all output ports simultaneously. On systems with an 89 * internal speaker (Indigo), plugging into the headphone jack cuts off the 90 * speaker output. 91 * 92 * A single input source can be selected at time. TODO: What happens if multiple 93 * input sample buffers are allocated? Presumably the DSP would return an error 94 * for such a request. 95 */ 96 97 /* 98 * Number of 4KB pages we will allocate for each sample buffer. 99 */ 100 #define HAUD_SAMPLE_BUFFER_PAGES 64 101 102 /* 103 * Circular buffer in the format understood by the DSP. Used for both command 104 * request/response buffers and audio sample buffers. 105 */ 106 typedef struct haud_dsp_buffer_header { 107 u_int32_t head; // Start of data (index in words units) 108 u_int32_t tail; // End of data (index in word units) 109 u_int32_t intr; // Set to 1 to trigger interrupt by DSP. 110 u_int32_t watr; // A low watermark for interrupt triggering? 111 } haud_dsp_buffer_header_t; 112 CTASSERT(sizeof(haud_dsp_buffer_header_t) == 4 * 4); 113 114 /* 115 * Represents a circular buffer registered with the DSP along with kernel state. 116 * 117 * Buffers are logically contiguous, but cobbled together from individual pages. 118 * The first 16 bytes of the first page contains the header. We follow that 119 * immediately with up to 1020 words of data. Pages after the first contain only 120 * data. 121 * 122 * We could split the header and data, but there's not much point. 123 */ 124 typedef struct haud_buffer { 125 u_int32_t kern_id; // ID assigned by kernel, registered with DSP. 126 u_int32_t dsp_id; // ID assigned by DSP. 127 bool is_write_buffer; // True: CPU->DSP, false: DSP->CPU (ex. record). 128 kcondvar_t cv; // For blocking on DSP I/O (with sc_intr_lock). 129 130 // One or more pages for the header and circular buffer. Command request 131 // and response buffers are one page, sample buffers are multiple. 132 struct { 133 bus_dmamap_t dma_map; 134 bus_dma_segment_t dma_seg; 135 uint32_t *kaddr; 136 } pages[HAUD_SAMPLE_BUFFER_PAGES]; 137 int npages; 138 } haud_buffer_t; 139 140 /* 141 * DSP Commands: Requests sent to the DSP via the command request buffer to 142 * configure new sample buffers and change input/output parameters. Each request 143 * is responded to via the response queue. 144 * 145 * The first word of each request and response is the full length of the message 146 * in 32-bit words. The second word is the command opcode. Responses use the 147 * same opcode as the request. 148 */ 149 150 #define HAUD_DSP_CMD_REGISTER_BUFFER_OPCODE 4 151 struct haud_dsp_cmd_register_buffer_req { 152 u_int32_t len; // 8. 153 u_int32_t op; // 4. 154 u_int32_t kern_id; // Kernel-assigned identifier. 155 u_int32_t cap; // Number of 32-bit words in the buffer. 156 u_int32_t out; // 1: Output (CPU->DSP), 0: Input (DSP->CPU). 157 u_int32_t hdr_hi; // haud_dsp_buffer phys. address (high 16 bits). 158 u_int32_t hdr_lo; // haud_dsp_buffer phys. address (low 16 bits). 159 u_int32_t buf_off; // Buffer start offset in first page (bytes). 160 161 /* 162 * The following contains the physical page number (i.e., phys_addr / 163 * 4096) of each page in the buffer. The first page needs to be included 164 * even though it's already referenced above. 165 * 166 * This is a variable-length message, but we always allocate sample 167 * buffers of the same static size. 168 * 169 * TODO: What is the DSP's upper bound for pages per buffer? 170 */ 171 u_int32_t page_nums[HAUD_SAMPLE_BUFFER_PAGES]; 172 }; 173 CTASSERT(sizeof(struct haud_dsp_cmd_register_buffer_req) == 174 (8 + HAUD_SAMPLE_BUFFER_PAGES) * 4); 175 176 struct haud_dsp_cmd_register_buffer_resp { 177 u_int32_t len; // 5. 178 u_int32_t op; // 4. 179 u_int32_t kern_id; // Echo of the ID given in the request. 180 u_int32_t error; // 0 iff request succeeded. 181 u_int32_t dsp_id; // ID allocated by the DSP. 182 }; 183 CTASSERT(sizeof(struct haud_dsp_cmd_register_buffer_resp) == 5 * 4); 184 185 #define HAUD_DSP_CMD_DEREGISTER_BUFFER_OPCODE 5 186 struct haud_dsp_cmd_deregister_buffer_req { 187 u_int32_t len; // 4. 188 u_int32_t op; // 5. 189 u_int32_t unknown; // Always 0? 190 u_int32_t dsp_id; // ID of the buffer to dereg (XXX DSP ID?). 191 }; 192 CTASSERT(sizeof(struct haud_dsp_cmd_deregister_buffer_req) == 4 * 4); 193 194 struct haud_dsp_cmd_deregister_buffer_resp { 195 u_int32_t len; // 4. 196 u_int32_t op; // 5. 197 u_int32_t unknown; // Always 0? 198 u_int32_t error; // 0 iff request succeeded. 199 }; 200 CTASSERT(sizeof(struct haud_dsp_cmd_deregister_buffer_resp) == 4 * 4); 201 202 #define HAUD_DSP_CMD_SET_AUDIO_PARAMS 7 203 struct haud_dsp_cmd_set_audio_params_req { 204 u_int32_t len; // Variable: 3 + 2 * num_params. 205 u_int32_t op; // 7. 206 u_int32_t unknown; // Always 0? 207 208 /* 209 * This is a variable-length message, but we always send the same full 210 * set of parameters. 211 */ 212 struct { 213 u_int32_t param; 214 u_int32_t value; 215 } params[7]; // One or more <param, value> pairs. 216 }; 217 CTASSERT(sizeof(struct haud_dsp_cmd_set_audio_params_req) == (3 + 7 * 2) * 4); 218 219 struct haud_dsp_cmd_set_audio_params_resp { 220 u_int32_t len; // 4. 221 u_int32_t op; // 7. 222 u_int32_t unknown; // Always 0? 223 u_int32_t unknown2; // error? 224 }; 225 CTASSERT(sizeof(struct haud_dsp_cmd_set_audio_params_resp) == 4 * 4); 226 227 #define HAUD_AUDIO_PARAMS_INPUT_SRC 0 // 0:line 1:mic 2: digtl 228 #define HAUD_AUDIO_PARAMS_INPUT_ATTN_L 1 // Left attenuation 229 #define HAUD_AUDIO_PARAMS_INPUT_ATTN_R 2 // Right attenuation 230 #define HAUD_AUDIO_PARAMS_INPUT_RATE 3 // See values below 231 #define HAUD_AUDIO_PARAMS_OUTPUT_RATE 4 // See values below 232 #define HAUD_AUDIO_PARAMS_SPKR_GAIN_L 5 // Left gain 233 #define HAUD_AUDIO_PARAMS_SPKR_GAIN_R 6 // Right gain 234 235 /* 236 * Minimum and maximum values for input/output gain/attenuation parameters. 237 */ 238 #define HAUD_MIN_GAIN 0 239 #define HAUD_MAX_GAIN 255 240 #define HAUD_MIN_ATTN 0 241 #define HAUD_MAX_ATTN 255 242 243 /* 244 * Values for HAUD_AUDIO_PARAMS_INPUT_RATE and _OUTPUT_RATE parameters. 245 * Many others are supported, too, but aren't terribly important. 246 */ 247 #define HAUD_RATE_48000 0x00 248 #define HAUD_RATE_44100 0x04 249 #define HAUD_RATE_22050 0x14 250 #define HAUD_RATE_11025 0x34 251 252 struct haud_softc { 253 device_t sc_dev; 254 kmutex_t sc_lock; 255 kmutex_t sc_intr_lock; 256 257 bus_space_tag_t sc_st; 258 bus_space_handle_t sc_regs_sh; 259 bus_space_handle_t sc_sram_sh; 260 bus_dma_tag_t sc_dma_tag; 261 262 haud_buffer_t *sc_cmd_req; 263 haud_buffer_t *sc_cmd_resp; 264 haud_buffer_t *sc_output; 265 266 // Protected by sc_intr_lock. 267 bool sc_dsp_booted; 268 269 // Provided by the audio(9) layer in its call to haud_start_output. 270 void (*sc_output_intr)(void *); 271 void *sc_output_intr_arg; 272 273 // Used to trigger additional output after haud_start_output. 274 void *sc_output_softint_cookie; 275 276 int sc_speaker_l_gain; 277 int sc_speaker_r_gain; 278 }; 279 280 #endif /* _ARCH_SGIMIPS_HPC_HAUDVAR_H_ */ 281