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 <jmcne...@invisible.ca>
@@ -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 <jmcne...@invisible.ca>
+ * 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 <jmcne...@invisible.ca>
+ * 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 <jmcne...@invisible.ca>
+ * 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);

Reply via email to