Module Name: src
Committed By: jmcneill
Date: Mon Jan 22 21:28:15 UTC 2024
Modified Files:
src/sys/arch/evbppc/conf: WII files.wii
src/sys/arch/evbppc/include: wii.h
src/sys/arch/evbppc/wii: machdep.c mainbus.c
Added Files:
src/sys/arch/evbppc/wii/dev: bwai.c bwai.h bwdsp.c
Log Message:
wii: Add drivers for Broadway DSP and Audio interface.
0: [*] audio0 @ bwdsp0: Broadway DSP
playback: 16, 2ch, 48000Hz
record: unavailable
(P-) slinear_be 16/16, 2ch, { 48000 }
To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/evbppc/conf/WII \
src/sys/arch/evbppc/conf/files.wii
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/evbppc/include/wii.h
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/evbppc/wii/machdep.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/evbppc/wii/mainbus.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/evbppc/wii/dev/bwai.c \
src/sys/arch/evbppc/wii/dev/bwai.h src/sys/arch/evbppc/wii/dev/bwdsp.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/evbppc/conf/WII
diff -u src/sys/arch/evbppc/conf/WII:1.1 src/sys/arch/evbppc/conf/WII:1.2
--- src/sys/arch/evbppc/conf/WII:1.1 Sat Jan 20 21:35:59 2024
+++ src/sys/arch/evbppc/conf/WII Mon Jan 22 21:28:15 2024
@@ -1,4 +1,4 @@
-# $NetBSD: WII,v 1.1 2024/01/20 21:35:59 jmcneill Exp $
+# $NetBSD: WII,v 1.2 2024/01/22 21:28:15 jmcneill Exp $
#
# Nintendo Wii
#
@@ -128,6 +128,8 @@ options WSDISPLAY_DEFAULTSCREENS=4
options WSDISPLAY_SCROLLSUPPORT
hollywood0 at mainbus0 irq 14
+bwai0 at mainbus0 addr 0x0d006c00 irq 5 # Audio interface
+bwdsp0 at mainbus0 addr 0x0c005000 irq 6 # DSP
#iosipc0 at hollywood0 addr 0x0d000000 irq 30 # IOS IPC
resetbtn0 at hollywood0 irq 17 # Reset button
Index: src/sys/arch/evbppc/conf/files.wii
diff -u src/sys/arch/evbppc/conf/files.wii:1.1 src/sys/arch/evbppc/conf/files.wii:1.2
--- src/sys/arch/evbppc/conf/files.wii:1.1 Sat Jan 20 21:35:59 2024
+++ src/sys/arch/evbppc/conf/files.wii Mon Jan 22 21:28:15 2024
@@ -1,4 +1,4 @@
-# $NetBSD: files.wii,v 1.1 2024/01/20 21:35:59 jmcneill Exp $
+# $NetBSD: files.wii,v 1.2 2024/01/22 21:28:15 jmcneill Exp $
#
#
maxpartitions 16
@@ -39,6 +39,14 @@ file arch/evbppc/wii/mainbus.c mainbus
attach genfb at mainbus with wiifb
file arch/evbppc/wii/dev/wiifb.c wiifb
+device bwai
+attach bwai at mainbus
+file arch/evbppc/wii/dev/bwai.c bwai
+
+device bwdsp: audiobus
+attach bwdsp at mainbus
+file arch/evbppc/wii/dev/bwdsp.c bwdsp
+
define hollywood { [addr=-1], [irq=-1] }
device hollywood: hollywood
attach hollywood at mainbus
Index: src/sys/arch/evbppc/include/wii.h
diff -u src/sys/arch/evbppc/include/wii.h:1.2 src/sys/arch/evbppc/include/wii.h:1.3
--- src/sys/arch/evbppc/include/wii.h:1.2 Sun Jan 21 01:41:54 2024
+++ src/sys/arch/evbppc/include/wii.h Mon Jan 22 21:28:15 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: wii.h,v 1.2 2024/01/21 01:41:54 jmcneill Exp $ */
+/* $NetBSD: wii.h,v 1.3 2024/01/22 21:28:15 jmcneill Exp $ */
/*-
* Copyright (c) 2024 Jared McNeill <[email protected]>
@@ -42,18 +42,24 @@
#define WII_IOMEM_BASE 0x0c000000
-#define GLOBAL_BASE 0x00000000
+#define GLOBAL_BASE 0x00000000
#define GLOBAL_SIZE 0x00003400
#define BROADWAY_BASE 0x0c000000
#define BROADWAY_SIZE 0x00000004
-#define VI_BASE 0x0c002000
-#define VI_SIZE 0x00000100
+#define VI_BASE 0x0c002000
+#define VI_SIZE 0x00000100
#define PI_BASE 0x0c003000
#define PI_SIZE 0x00000100
+#define DSP_BASE 0x0c005000
+#define DSP_SIZE 0x00000200
+
+#define AI_BASE 0x0d006c00
+#define AI_SIZE 0x00000020
+
#define HOLLYWOOD_BASE 0x0d000000
#define HOLLYWOOD_PRIV_BASE 0x0d800000
#define HOLLYWOOD_SIZE 0x00008000
@@ -61,8 +67,8 @@
#define XFB_START 0x01698000
#define XFB_SIZE 0x00168000
-#define DSP_START 0x10000000
-#define DSP_SIZE 0x00004000
+#define DSP_MEM_START 0x10000000
+#define DSP_MEM_SIZE 0x00004000
#define IPC_START 0x133e0000
#define IPC_SIZE 0x00020000
@@ -90,12 +96,14 @@
#define PI_INTMR (PI_BASE + 0x04)
/* Processor IRQs */
-#define PI_IRQ_HOLLYWOOD 14
+#define PI_IRQ_AI 5
+#define PI_IRQ_DSP 6
+#define PI_IRQ_HOLLYWOOD 14
/* Hollywood registers */
#define HW_PPCIRQFLAGS (HOLLYWOOD_BASE + 0x030)
#define HW_PPCIRQMASK (HOLLYWOOD_BASE + 0x034)
-#define HW_ARMIRQFLAGS (HOLLYWOOD_PRIV_BASE + 0x038)
+#define HW_ARMIRQFLAGS (HOLLYWOOD_PRIV_BASE + 0x038)
#define HW_ARMIRQMASK (HOLLYWOOD_PRIV_BASE + 0x03c)
#define HW_AHBPROT (HOLLYWOOD_PRIV_BASE + 0x064)
#define HW_GPIOB_OUT (HOLLYWOOD_BASE + 0x0c0)
Index: src/sys/arch/evbppc/wii/machdep.c
diff -u src/sys/arch/evbppc/wii/machdep.c:1.2 src/sys/arch/evbppc/wii/machdep.c:1.3
--- src/sys/arch/evbppc/wii/machdep.c:1.2 Sun Jan 21 01:41:54 2024
+++ src/sys/arch/evbppc/wii/machdep.c Mon Jan 22 21:28:15 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.2 2024/01/21 01:41:54 jmcneill Exp $ */
+/* $NetBSD: machdep.c,v 1.3 2024/01/22 21:28:15 jmcneill Exp $ */
/*
* Copyright (c) 2002, 2024 The NetBSD Foundation, Inc.
@@ -63,7 +63,7 @@
#define _POWERPC_BUS_DMA_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.2 2024/01/21 01:41:54 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.3 2024/01/22 21:28:15 jmcneill Exp $");
#include "opt_compat_netbsd.h"
#include "opt_ddb.h"
@@ -254,8 +254,8 @@ initppc(u_int startkernel, u_int endkern
availmemr[1].size = physmemr[1].size;
if (mem2_size != 0) {
/* DSP uses 16KB at the start of MEM2 */
- availmemr[1].start += DSP_SIZE;
- availmemr[1].size -= DSP_SIZE;
+ availmemr[1].start += DSP_MEM_SIZE;
+ availmemr[1].size -= DSP_MEM_SIZE;
/* IPC and Starlet use memory at the end of MEM2 */
availmemr[1].size -= IPC_SIZE;
availmemr[1].size -= ARM_SIZE;
Index: src/sys/arch/evbppc/wii/mainbus.c
diff -u src/sys/arch/evbppc/wii/mainbus.c:1.1 src/sys/arch/evbppc/wii/mainbus.c:1.2
--- src/sys/arch/evbppc/wii/mainbus.c:1.1 Sat Jan 20 21:36:00 2024
+++ src/sys/arch/evbppc/wii/mainbus.c Mon Jan 22 21:28:15 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: mainbus.c,v 1.1 2024/01/20 21:36:00 jmcneill Exp $ */
+/* $NetBSD: mainbus.c,v 1.2 2024/01/22 21:28:15 jmcneill Exp $ */
/*
* Copyright (c) 2002, 2024 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.1 2024/01/20 21:36:00 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.2 2024/01/22 21:28:15 jmcneill Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -106,6 +106,16 @@ mainbus_attach(device_t parent, device_t
maa.maa_addr = MAINBUSCF_ADDR_DEFAULT;
maa.maa_irq = PI_IRQ_HOLLYWOOD;
config_found(self, &maa, mainbus_print, CFARGS_NONE);
+
+ maa.maa_name = "bwai";
+ maa.maa_addr = AI_BASE;
+ maa.maa_irq = PI_IRQ_AI;
+ config_found(self, &maa, mainbus_print, CFARGS_NONE);
+
+ maa.maa_name = "bwdsp";
+ maa.maa_addr = DSP_BASE;
+ maa.maa_irq = PI_IRQ_DSP;
+ config_found(self, &maa, mainbus_print, CFARGS_NONE);
}
static int cpu_match(device_t, cfdata_t, void *);
Added files:
Index: src/sys/arch/evbppc/wii/dev/bwai.c
diff -u /dev/null src/sys/arch/evbppc/wii/dev/bwai.c:1.1
--- /dev/null Mon Jan 22 21:28:15 2024
+++ src/sys/arch/evbppc/wii/dev/bwai.c Mon Jan 22 21:28:15 2024
@@ -0,0 +1,315 @@
+/* $NetBSD: bwai.c,v 1.1 2024/01/22 21:28:15 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2024 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: bwai.c,v 1.1 2024/01/22 21:28:15 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/bitops.h>
+
+#include <dev/audio/audio_dai.h>
+
+#include <machine/wii.h>
+
+#include "mainbus.h"
+#include "bwai.h"
+
+#define AI_CONTROL 0x00
+#define AI_CONTROL_RATE __BIT(6)
+#define AI_CONTROL_SCRESET __BIT(5)
+#define AI_CONTROL_AIINTVLD __BIT(4)
+#define AI_CONTROL_AIINT __BIT(3)
+#define AI_CONTROL_AIINTMSK __BIT(2)
+#define AI_CONTROL_AFR __BIT(1)
+#define AI_CONTROL_PSTAT __BIT(0)
+#define AI_AIIT 0x0c
+
+struct bwai_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ int sc_irq;
+
+ struct audio_dai_device sc_dai;
+
+ uint8_t sc_swvol;
+ void (*sc_intr)(void *);
+ void *sc_intrarg;
+
+ kmutex_t *sc_intr_lock;
+};
+
+enum bwai_mixer_ctrl {
+ BWAI_OUTPUT_CLASS,
+ BWAI_INPUT_CLASS,
+
+ BWAI_OUTPUT_MASTER_VOLUME,
+ BWAI_INPUT_DAC_VOLUME,
+
+ BWAI_MIXER_CTRL_LAST
+};
+
+#define RD4(sc, reg) \
+ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define WR4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int
+bwai_intr(void *priv)
+{
+ struct bwai_softc * const sc = priv;
+ uint32_t val;
+
+ val = RD4(sc, AI_CONTROL);
+ if ((val & AI_CONTROL_AIINT) != 0) {
+ WR4(sc, AI_CONTROL, val | AI_CONTROL_SCRESET);
+
+ mutex_enter(sc->sc_intr_lock);
+ if (sc->sc_intr) {
+ sc->sc_intr(sc->sc_intrarg);
+ }
+ mutex_exit(sc->sc_intr_lock);
+ }
+
+ return 1;
+}
+
+audio_dai_tag_t
+bwai_dsp_init(kmutex_t *intr_lock)
+{
+ struct bwai_softc *sc;
+ device_t dev;
+
+ dev = device_find_by_driver_unit("bwai", 0);
+ if (dev == NULL) {
+ return NULL;
+ }
+ sc = device_private(dev);
+
+ sc->sc_intr_lock = intr_lock;
+
+ intr_establish(sc->sc_irq, IST_LEVEL, IPL_AUDIO, bwai_intr, sc);
+
+ return &sc->sc_dai;
+}
+
+static void
+bwai_swvol_codec(audio_filter_arg_t *arg)
+{
+ struct bwai_softc * const sc = arg->context;
+ const aint_t *src;
+ int16_t *dst;
+ u_int sample_count;
+ u_int i;
+
+ src = arg->src;
+ dst = arg->dst;
+ sample_count = arg->count * arg->srcfmt->channels;
+ for (i = 0; i < sample_count; i++) {
+ aint2_t v = (aint2_t)(*src++);
+ v = v * sc->sc_swvol / 255;
+ *dst++ = (aint_t)v;
+ }
+}
+
+static int
+bwai_set_port(void *priv, mixer_ctrl_t *mc)
+{
+ struct bwai_softc * const sc = priv;
+
+ if (mc->dev != BWAI_OUTPUT_MASTER_VOLUME &&
+ mc->dev != BWAI_INPUT_DAC_VOLUME) {
+ return ENXIO;
+ }
+
+ sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
+
+ return 0;
+}
+
+static int
+bwai_get_port(void *priv, mixer_ctrl_t *mc)
+{
+ struct bwai_softc * const sc = priv;
+
+ if (mc->dev != BWAI_OUTPUT_MASTER_VOLUME &&
+ mc->dev != BWAI_INPUT_DAC_VOLUME) {
+ return ENXIO;
+ }
+
+ mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_swvol;
+ mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_swvol;
+
+ return 0;
+}
+
+static int
+bwai_query_devinfo(void *priv, mixer_devinfo_t *di)
+{
+ switch (di->index) {
+ case BWAI_OUTPUT_CLASS:
+ di->mixer_class = di->index;
+ strcpy(di->label.name, AudioCoutputs);
+ di->type = AUDIO_MIXER_CLASS;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ return 0;
+
+ case BWAI_INPUT_CLASS:
+ di->mixer_class = di->index;
+ strcpy(di->label.name, AudioCinputs);
+ di->type = AUDIO_MIXER_CLASS;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ return 0;
+
+ case BWAI_OUTPUT_MASTER_VOLUME:
+ di->mixer_class = BWAI_OUTPUT_CLASS;
+ strcpy(di->label.name, AudioNmaster);
+ di->un.v.delta = 1;
+ di->type = AUDIO_MIXER_VALUE;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ di->un.v.num_channels = 2;
+ strcpy(di->un.v.units.name, AudioNvolume);
+ return 0;
+
+ case BWAI_INPUT_DAC_VOLUME:
+ di->mixer_class = BWAI_INPUT_CLASS;
+ strcpy(di->label.name, AudioNdac);
+ di->un.v.delta = 1;
+ di->type = AUDIO_MIXER_VALUE;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ di->un.v.num_channels = 2;
+ strcpy(di->un.v.units.name, AudioNvolume);
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+static int
+bwai_set_format(void *priv, int setmode,
+ const audio_params_t *play, const audio_params_t *rec,
+ audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
+{
+ struct bwai_softc * const sc = priv;
+
+ pfil->codec = bwai_swvol_codec;
+ pfil->context = sc;
+
+ return 0;
+}
+
+static int
+bwai_trigger_output(void *priv, void *start, void *end, int blksize,
+ void (*intr)(void *), void *intrarg, const audio_params_t *params)
+{
+ struct bwai_softc * const sc = priv;
+ uint32_t val;
+
+ sc->sc_intr = intr;
+ sc->sc_intrarg = intrarg;
+
+ val = RD4(sc, AI_CONTROL);
+ if ((val & AI_CONTROL_PSTAT) != 0) {
+ WR4(sc, AI_CONTROL, 0);
+ }
+
+ WR4(sc, AI_AIIT, blksize / 4);
+
+ val = AI_CONTROL_SCRESET |
+ AI_CONTROL_AIINT |
+ AI_CONTROL_AIINTMSK |
+ AI_CONTROL_AFR;
+ WR4(sc, AI_CONTROL, val);
+
+ val |= AI_CONTROL_PSTAT;
+ WR4(sc, AI_CONTROL, val);
+
+ return 0;
+}
+
+static int
+bwai_halt_output(void *priv)
+{
+ struct bwai_softc * const sc = priv;
+
+ WR4(sc, AI_CONTROL, 0);
+
+ sc->sc_intr = NULL;
+ sc->sc_intrarg = NULL;
+
+ return 0;
+}
+
+static const struct audio_hw_if bwai_hw_if = {
+ .set_port = bwai_set_port,
+ .get_port = bwai_get_port,
+ .query_devinfo = bwai_query_devinfo,
+ .set_format = bwai_set_format,
+ .trigger_output = bwai_trigger_output,
+ .halt_output = bwai_halt_output,
+};
+
+static int
+bwai_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct mainbus_attach_args * const maa = aux;
+
+ return strcmp(maa->maa_name, "bwai") == 0;
+}
+
+static void
+bwai_attach(device_t parent, device_t self, void *aux)
+{
+ struct bwai_softc * const sc = device_private(self);
+ struct mainbus_attach_args * const maa = aux;
+
+ sc->sc_dev = self;
+ sc->sc_bst = maa->maa_bst;
+ if (bus_space_map(sc->sc_bst, maa->maa_addr, AI_SIZE, 0,
+ &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+ sc->sc_irq = maa->maa_irq;
+
+ aprint_naive("\n");
+ aprint_normal(": Audio Interface\n");
+
+ sc->sc_dai.dai_hw_if = &bwai_hw_if;
+ sc->sc_dai.dai_dev = self;
+ sc->sc_dai.dai_priv = sc;
+ sc->sc_swvol = 255;
+}
+
+CFATTACH_DECL_NEW(bwai, sizeof(struct bwai_softc),
+ bwai_match, bwai_attach, NULL, NULL);
Index: src/sys/arch/evbppc/wii/dev/bwai.h
diff -u /dev/null src/sys/arch/evbppc/wii/dev/bwai.h:1.1
--- /dev/null Mon Jan 22 21:28:15 2024
+++ src/sys/arch/evbppc/wii/dev/bwai.h Mon Jan 22 21:28:15 2024
@@ -0,0 +1,34 @@
+/* $NetBSD: bwai.h,v 1.1 2024/01/22 21:28:15 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2024 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _WII_DEV_BWAI_H_
+#define _WII_DEV_BWAI_H_
+
+audio_dai_tag_t bwai_dsp_init(kmutex_t *);
+
+#endif /* _WII_DEV_BWAI_H_ */
Index: src/sys/arch/evbppc/wii/dev/bwdsp.c
diff -u /dev/null src/sys/arch/evbppc/wii/dev/bwdsp.c:1.1
--- /dev/null Mon Jan 22 21:28:15 2024
+++ src/sys/arch/evbppc/wii/dev/bwdsp.c Mon Jan 22 21:28:15 2024
@@ -0,0 +1,425 @@
+/* $NetBSD: bwdsp.c,v 1.1 2024/01/22 21:28:15 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2024 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: bwdsp.c,v 1.1 2024/01/22 21:28:15 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+
+#include <sys/audioio.h>
+#include <dev/audio/audio_if.h>
+#include <dev/audio/audio_dai.h>
+
+#include "mainbus.h"
+#include "bwai.h"
+
+#define BWDSP_MAP_FLAGS BUS_DMA_NOCACHE
+
+#define DSP_CONTROL_STATUS 0x0a
+#define DSP_CONTROL_STATUS_DSPINT __BIT(7)
+#define DSP_CONTROL_STATUS_ARINT __BIT(5)
+#define DSP_CONTROL_STATUS_AIDINTMASK __BIT(4)
+#define DSP_CONTROL_STATUS_AIDINT __BIT(3)
+#define DSP_CONTROL_STATUS_HALT __BIT(2)
+#define DSP_CONTROL_STATUS_PIINT __BIT(1)
+#define DSP_DMA_START_ADDR_H 0x30
+#define DSP_DMA_START_ADDR_L 0x32
+#define DSP_DMA_CONTROL_LENGTH 0x36
+#define DSP_DMA_CONTROL_LENGTH_CTRL __BIT(15)
+#define DSP_DMA_CONTROL_LENGTH_NUM_CLS __BITS(14,0)
+
+#define DSP_DMA_ALIGN 32
+#define DSP_DMA_MAX_BUFSIZE (DSP_DMA_CONTROL_LENGTH_NUM_CLS * 32)
+
+struct bwdsp_dma {
+ LIST_ENTRY(bwdsp_dma) dma_list;
+ bus_dmamap_t dma_map;
+ void *dma_addr;
+ size_t dma_size;
+ bus_dma_segment_t dma_segs[1];
+ int dma_nsegs;
+};
+
+struct bwdsp_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ bus_dma_tag_t sc_dmat;
+
+ LIST_HEAD(, bwdsp_dma) sc_dmalist;
+
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
+
+ struct audio_format sc_format;
+
+ audio_dai_tag_t sc_dai;
+};
+
+#define RD2(sc, reg) \
+ bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define WR2(sc, reg, val) \
+ bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int
+bwdsp_allocdma(struct bwdsp_softc *sc, size_t size,
+ size_t align, struct bwdsp_dma *dma)
+{
+ int error;
+
+ dma->dma_size = size;
+ error = bus_dmamem_alloc(sc->sc_dmat, dma->dma_size, align, 0,
+ dma->dma_segs, 1, &dma->dma_nsegs, BUS_DMA_WAITOK);
+ if (error)
+ return error;
+
+ error = bus_dmamem_map(sc->sc_dmat, dma->dma_segs, dma->dma_nsegs,
+ dma->dma_size, &dma->dma_addr, BUS_DMA_WAITOK | BWDSP_MAP_FLAGS);
+ if (error)
+ goto free;
+
+ error = bus_dmamap_create(sc->sc_dmat, dma->dma_size, dma->dma_nsegs,
+ dma->dma_size, 0, BUS_DMA_WAITOK, &dma->dma_map);
+ if (error)
+ goto unmap;
+
+ error = bus_dmamap_load(sc->sc_dmat, dma->dma_map, dma->dma_addr,
+ dma->dma_size, NULL, BUS_DMA_WAITOK);
+ if (error)
+ goto destroy;
+
+ return 0;
+
+destroy:
+ bus_dmamap_destroy(sc->sc_dmat, dma->dma_map);
+unmap:
+ bus_dmamem_unmap(sc->sc_dmat, dma->dma_addr, dma->dma_size);
+free:
+ bus_dmamem_free(sc->sc_dmat, dma->dma_segs, dma->dma_nsegs);
+
+ return error;
+}
+
+static void
+bwdsp_freedma(struct bwdsp_softc *sc, struct bwdsp_dma *dma)
+{
+ bus_dmamap_unload(sc->sc_dmat, dma->dma_map);
+ bus_dmamap_destroy(sc->sc_dmat, dma->dma_map);
+ bus_dmamem_unmap(sc->sc_dmat, dma->dma_addr, dma->dma_size);
+ bus_dmamem_free(sc->sc_dmat, dma->dma_segs, dma->dma_nsegs);
+}
+
+static int
+bwdsp_query_format(void *priv, audio_format_query_t *afp)
+{
+ struct bwdsp_softc * const sc = priv;
+
+ return audio_query_format(&sc->sc_format, 1, afp);
+}
+
+static int
+bwdsp_set_format(void *priv, int setmode,
+ const audio_params_t *play, const audio_params_t *rec,
+ audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
+{
+ struct bwdsp_softc * const sc = priv;
+
+ return audio_dai_mi_set_format(sc->sc_dai, setmode, play, rec,
+ pfil, rfil);
+}
+
+static int
+bwdsp_set_port(void *priv, mixer_ctrl_t *mc)
+{
+ struct bwdsp_softc * const sc = priv;
+
+ return audio_dai_set_port(sc->sc_dai, mc);
+}
+
+static int
+bwdsp_get_port(void *priv, mixer_ctrl_t *mc)
+{
+ struct bwdsp_softc * const sc = priv;
+
+ return audio_dai_get_port(sc->sc_dai, mc);
+}
+
+static int
+bwdsp_query_devinfo(void *priv, mixer_devinfo_t *di)
+{
+ struct bwdsp_softc * const sc = priv;
+
+ return audio_dai_query_devinfo(sc->sc_dai, di);
+}
+
+static void *
+bwdsp_allocm(void *priv, int dir, size_t size)
+{
+ struct bwdsp_softc * const sc = priv;
+ struct bwdsp_dma *dma;
+ int error;
+
+ dma = kmem_alloc(sizeof(*dma), KM_SLEEP);
+
+ error = bwdsp_allocdma(sc, size, DSP_DMA_ALIGN, dma);
+ if (error) {
+ kmem_free(dma, sizeof(*dma));
+ device_printf(sc->sc_dev, "couldn't allocate DMA memory (%d)\n",
+ error);
+ return NULL;
+ }
+
+ LIST_INSERT_HEAD(&sc->sc_dmalist, dma, dma_list);
+
+ return dma->dma_addr;
+}
+
+static void
+bwdsp_freem(void *priv, void *addr, size_t size)
+{
+ struct bwdsp_softc * const sc = priv;
+ struct bwdsp_dma *dma;
+
+ LIST_FOREACH(dma, &sc->sc_dmalist, dma_list)
+ if (dma->dma_addr == addr) {
+ bwdsp_freedma(sc, dma);
+ LIST_REMOVE(dma, dma_list);
+ kmem_free(dma, sizeof(*dma));
+ break;
+ }
+}
+
+static int
+bwdsp_getdev(void *priv, struct audio_device *adev)
+{
+ snprintf(adev->name, sizeof(adev->name), "Broadway DSP");
+ snprintf(adev->version, sizeof(adev->version), "");
+ snprintf(adev->config, sizeof(adev->config), "bwdsp");
+
+ return 0;
+}
+
+static int
+bwdsp_get_props(void *priv)
+{
+ return AUDIO_PROP_PLAYBACK;
+}
+
+static int
+bwdsp_round_blocksize(void *priv, int bs, int mode,
+ const audio_params_t *params)
+{
+ bs = roundup(bs, DSP_DMA_ALIGN);
+ if (bs > DSP_DMA_MAX_BUFSIZE) {
+ bs = DSP_DMA_MAX_BUFSIZE;
+ }
+ return bs;
+}
+
+static size_t
+bwdsp_round_buffersize(void *priv, int dir, size_t bufsize)
+{
+ if (bufsize > DSP_DMA_MAX_BUFSIZE) {
+ bufsize = DSP_DMA_MAX_BUFSIZE;
+ }
+ return bufsize;
+}
+
+static void
+bwdsp_transfer(struct bwdsp_softc *sc, uint32_t phys_addr, size_t bufsize)
+{
+ if (bufsize != 0) {
+ WR2(sc, DSP_DMA_START_ADDR_H, phys_addr >> 16);
+ WR2(sc, DSP_DMA_START_ADDR_L, phys_addr & 0xffff);
+ WR2(sc, DSP_DMA_CONTROL_LENGTH,
+ DSP_DMA_CONTROL_LENGTH_CTRL | (bufsize / 32));
+ } else {
+ WR2(sc, DSP_DMA_CONTROL_LENGTH, 0);
+ }
+}
+
+static int
+bwdsp_trigger_output(void *priv, void *start, void *end, int blksize,
+ void (*intr)(void *), void *intrarg, const audio_params_t *params)
+{
+ struct bwdsp_softc * const sc = priv;
+ struct bwdsp_dma *dma;
+ bus_addr_t pstart;
+ bus_size_t psize;
+ int error;
+
+ pstart = 0;
+ psize = (uintptr_t)end - (uintptr_t)start;
+
+ LIST_FOREACH(dma, &sc->sc_dmalist, dma_list)
+ if (dma->dma_addr == start) {
+ pstart = dma->dma_map->dm_segs[0].ds_addr;
+ break;
+ }
+ if (pstart == 0) {
+ device_printf(sc->sc_dev, "bad addr %p\n", start);
+ return EINVAL;
+ }
+
+ error = audio_dai_trigger(sc->sc_dai, start, end, blksize,
+ intr, intrarg, params, AUMODE_PLAY);
+ if (error != 0) {
+ return error;
+ }
+
+ /* Start DMA transfer */
+ bwdsp_transfer(sc, pstart, psize);
+
+ return 0;
+}
+
+static int
+bwdsp_halt_output(void *priv)
+{
+ struct bwdsp_softc * const sc = priv;
+
+ /* Stop DMA transfer */
+ bwdsp_transfer(sc, 0, 0);
+
+ return audio_dai_halt(sc->sc_dai, AUMODE_PLAY);
+}
+
+static void
+bwdsp_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
+{
+ struct bwdsp_softc * const sc = priv;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
+static const struct audio_hw_if bwdsp_hw_if = {
+ .query_format = bwdsp_query_format,
+ .set_format = bwdsp_set_format,
+ .allocm = bwdsp_allocm,
+ .freem = bwdsp_freem,
+ .getdev = bwdsp_getdev,
+ .set_port = bwdsp_set_port,
+ .get_port = bwdsp_get_port,
+ .query_devinfo = bwdsp_query_devinfo,
+ .get_props = bwdsp_get_props,
+ .round_blocksize = bwdsp_round_blocksize,
+ .round_buffersize = bwdsp_round_buffersize,
+ .trigger_output = bwdsp_trigger_output,
+ .halt_output = bwdsp_halt_output,
+ .get_locks = bwdsp_get_locks,
+};
+
+static int
+bwdsp_intr(void *priv)
+{
+ struct bwdsp_softc * const sc = priv;
+ uint16_t val;
+
+ val = RD2(sc, DSP_CONTROL_STATUS);
+ if ((val & DSP_CONTROL_STATUS_AIDINT) != 0) {
+ /* Acknowledge audio interrupt */
+ val &= ~(DSP_CONTROL_STATUS_DSPINT |
+ DSP_CONTROL_STATUS_ARINT |
+ DSP_CONTROL_STATUS_PIINT);
+ WR2(sc, DSP_CONTROL_STATUS, val);
+ }
+
+ return 1;
+}
+
+static void
+bwdsp_late_attach(device_t dev)
+{
+ struct bwdsp_softc * const sc = device_private(dev);
+
+ sc->sc_dai = bwai_dsp_init(&sc->sc_intr_lock);
+ if (sc->sc_dai == NULL) {
+ aprint_error_dev(dev, "can't find bwai device\n");
+ return;
+ }
+
+ audio_attach_mi(&bwdsp_hw_if, sc, dev);
+}
+
+static int
+bwdsp_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct mainbus_attach_args * const maa = aux;
+
+ return strcmp(maa->maa_name, "bwdsp") == 0;
+}
+
+static void
+bwdsp_attach(device_t parent, device_t self, void *aux)
+{
+ struct bwdsp_softc * const sc = device_private(self);
+ struct mainbus_attach_args * const maa = aux;
+ bus_addr_t addr = maa->maa_addr;
+ bus_size_t size = 0x200;
+ uint16_t val;
+
+ sc->sc_dev = self;
+ sc->sc_bst = maa->maa_bst;
+ if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
+ aprint_error(": couldn't map registers\n");
+ return;
+ }
+ sc->sc_dmat = maa->maa_dmat;
+ LIST_INIT(&sc->sc_dmalist);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+ aprint_naive("\n");
+ aprint_normal(": DSP\n");
+
+ sc->sc_format.mode = AUMODE_PLAY;
+ sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_BE;
+ sc->sc_format.validbits = 16;
+ sc->sc_format.precision = 16;
+ sc->sc_format.channels = 2;
+ sc->sc_format.channel_mask = AUFMT_STEREO;
+ sc->sc_format.frequency_type = 1;
+ sc->sc_format.frequency[0] = 48000;
+
+ val = RD2(sc, DSP_CONTROL_STATUS);
+ val |= DSP_CONTROL_STATUS_AIDINTMASK;
+ val |= DSP_CONTROL_STATUS_PIINT;
+ WR2(sc, DSP_CONTROL_STATUS, val);
+
+ intr_establish(maa->maa_irq, IST_LEVEL, IPL_AUDIO, bwdsp_intr, sc);
+
+ config_defer(self, bwdsp_late_attach);
+}
+
+CFATTACH_DECL_NEW(bwdsp, sizeof(struct bwdsp_softc),
+ bwdsp_match, bwdsp_attach, NULL, NULL);