summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authormacallan <macallan@NetBSD.org>2006-03-09 20:44:18 +0000
committermacallan <macallan@NetBSD.org>2006-03-09 20:44:18 +0000
commitb4978607ac9ef9727e9b4bc28e6aa8d6e2b41632 (patch)
treeb6fd8efdd99875996a67b5dded4a6320bce6fa40 /sys/dev
parent08f478e5aba8e8e75a64b44f90a21a6a6f1b598b (diff)
keep the chip powered down when not in use on machines that support it
( like SPARCbooks ) - needs testing on other machines tested on my SPARCbook 3GX
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sbus/dbri.c184
-rw-r--r--sys/dev/sbus/dbrireg.h7
-rw-r--r--sys/dev/sbus/dbrivar.h28
-rw-r--r--sys/dev/sbus/files.sbus4
4 files changed, 170 insertions, 53 deletions
diff --git a/sys/dev/sbus/dbri.c b/sys/dev/sbus/dbri.c
index 9af919869a7..d65a6c1962b 100644
--- a/sys/dev/sbus/dbri.c
+++ b/sys/dev/sbus/dbri.c
@@ -1,4 +1,4 @@
-/* $NetBSD: dbri.c,v 1.3 2005/12/11 12:23:44 christos Exp $ */
+/* $NetBSD: dbri.c,v 1.4 2006/03/09 20:44:18 macallan Exp $ */
/*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.3 2005/12/11 12:23:44 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.4 2006/03/09 20:44:18 macallan Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -70,9 +70,15 @@ __KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.3 2005/12/11 12:23:44 christos Exp $");
#include <dev/sbus/dbrireg.h>
#include <dev/sbus/dbrivar.h>
+#include "opt_sbus_dbri.h"
+
#define DBRI_ROM_NAME_PREFIX "SUNW,DBRI"
-#define DBRI_BIG_BUFFER
+#ifdef DBRI_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
static const char *dbri_supported[] = {
"e",
@@ -144,6 +150,8 @@ static int dbri_get_port(void *, mixer_ctrl_t *);
static int dbri_query_devinfo(void *, mixer_devinfo_t *);
static size_t dbri_round_buffersize(void *, int, size_t);
static int dbri_get_props(void *);
+static int dbri_open(void *, int);
+static void dbri_close(void *);
static void
setup_ring(struct dbri_softc *, int, int, int, int, void (*)(void *), void *);
@@ -154,6 +162,9 @@ static int dbri_trigger_output(void *, void *, void *, int,
static void *dbri_malloc(void *, int, size_t, struct malloc_type *, int);
static void dbri_free(void *, void *, struct malloc_type *);
static paddr_t dbri_mappage(void *, void *, off_t, int);
+static void dbri_set_power(struct dbri_softc *, int);
+static void dbri_bring_up(struct dbri_softc *);
+static void dbri_powerhook(int, void *);
/* stupid support routines */
static u_int32_t reverse_bytes(u_int32_t, int);
@@ -165,8 +176,8 @@ struct audio_device dbri_device = {
};
struct audio_hw_if dbri_hw_if = {
- NULL, /*dbri_open,*/
- NULL, /*dbri_close,*/
+ dbri_open,
+ dbri_close,
NULL, /* drain */
dbri_query_encoding,
dbri_set_params,
@@ -245,19 +256,27 @@ dbri_attach_sbus(struct device *parent, struct device *self, void *aux)
sc->sc_iot = sa->sa_bustag;
sc->sc_dmat = sa->sa_dmatag;
+ sc->sc_powerstate = PWR_RESUME;
- pwr=prom_getpropint(sa->sa_node,"pwr-on-auxio",0);
+ pwr = prom_getpropint(sa->sa_node,"pwr-on-auxio",0);
if(pwr) {
- /* we need to power up the device first */
- uint8_t auxregval = 0;
- printf("\n%s: waiting to power up... ",self->dv_xname);
- auxregval = *AUXIO4M_REG;
- *AUXIO4M_REG = auxregval | (AUXIO4M_LED|4);
- DELAY(1000);
- printf("done\n"); /* more delay... */
- } else
+ /*
+ * we can control DBRI power via auxio and we're initially
+ * powered down
+ */
+
+ sc->sc_have_powerctl = 1;
+ sc->sc_powerstate = 0;
+ printf("\n");
+ dbri_set_power(sc, 1);
+ powerhook_establish(dbri_powerhook, sc);
+ } else {
+ /* we can't control power so we're always up */
+ sc->sc_have_powerctl = 0;
+ sc->sc_powerstate = 1;
printf(": rev %s\n", ver);
-
+ }
+
if (sa->sa_npromvaddrs)
ioh = (bus_space_handle_t)sa->sa_promvaddrs[0];
else {
@@ -328,6 +347,61 @@ dbri_attach_sbus(struct device *parent, struct device *self, void *aux)
return;
}
+/*
+ * lowlevel routine to switch power for the DBRI chip
+ */
+static void
+dbri_set_power(struct dbri_softc *sc, int state)
+{
+ int s;
+
+ if (sc->sc_have_powerctl == 0)
+ return;
+ if (sc->sc_powerstate == state)
+ return;
+
+ if (state) {
+ DPRINTF(("%s: waiting to power up... ", sc->sc_dev.dv_xname));
+ s = splhigh();
+ *AUXIO4M_REG |= (AUXIO4M_MMX);
+ splx(s);
+ DELAY(1000);
+ DPRINTF(("done\n")); /* more delay... */
+ } else {
+ DPRINTF(("%s: powering down\n", sc->sc_dev.dv_xname));
+ s = splhigh();
+ *AUXIO4M_REG &= ~AUXIO4M_MMX;
+ splx(s);
+ }
+ sc->sc_powerstate = state;
+}
+
+/*
+ * power up and re-initialize the chip
+ */
+static void
+dbri_bring_up(struct dbri_softc *sc)
+{
+
+ if (sc->sc_have_powerctl == 0)
+ return;
+ if (sc->sc_powerstate == 1)
+ return;
+
+ /* ok, we really need to do something */
+ dbri_set_power(sc, 1);
+
+ /*
+ * re-initialize the chip but skip all the probing, don't overwrite
+ * any other settings either
+ */
+ dbri_init(sc);
+ mmcodec_setgain(sc, 1);
+ mmcodec_pipe_init(sc);
+ mmcodec_init_data(sc);
+ mmcodec_setgain(sc, 0);
+}
+
void
dbri_config_interrupts(struct device *dev)
{
@@ -336,7 +410,9 @@ dbri_config_interrupts(struct device *dev)
mmcodec_init(sc);
/* Attach ourselves to the high level audio interface */
audio_attach_mi(&dbri_hw_if, sc, &sc->sc_dev);
-
+
+ /* power down until open() */
+ dbri_set_power(sc, 0);
return;
}
@@ -559,24 +635,20 @@ dbri_process_interrupt(struct dbri_softc *sc, int32_t i)
break;
}
case DBRI_INTR_FXDT: /* fixed data change */
-#ifdef DBRI_DEBUG
- printf("dbri_intr: Fixed data change (%d: %x)\n",channel,val);
-#endif
+ DPRINTF(("dbri_intr: Fixed data change (%d: %x)\n", channel,
+ val));
+
if (sc->sc_pipe[channel].sdp & DBRI_SDP_MSB)
val = reverse_bytes(val, sc->sc_pipe[channel].length);
if (sc->sc_pipe[channel].prec)
*(sc->sc_pipe[channel].prec) = val;
-#ifdef DBRI_DEBUG
- printf("%s: wakeup %p\n", sc->sc_dev.dv_xname, sc);
-#endif
+ DPRINTF(("%s: wakeup %p\n", sc->sc_dev.dv_xname, sc));
#if 0
wakeup(sc);
#endif
break;
case DBRI_INTR_SBRI:
-#ifdef DBRI_DEBUG
- printf("dbri_intr: SBRI\n");
-#endif
+ DPRINTF(("dbri_intr: SBRI\n"));
break;
case DBRI_INTR_BRDY:
{
@@ -641,9 +713,8 @@ mmcodec_init(struct dbri_softc *sc)
u_int32_t reg2;
reg2 = bus_space_read_4(iot, ioh, DBRI_REG2);
-#ifdef DBRI_DEBUG
- printf("mmcodec_init: PIO reads %x\n",reg2);
-#endif
+ DPRINTF(("mmcodec_init: PIO reads %x\n", reg2));
+
if (reg2 & DBRI_PIO2) {
printf("%s: onboard CS4215 detected\n",
sc->sc_dev.dv_xname);
@@ -807,6 +878,8 @@ mmcodec_setgain(struct dbri_softc *sc, int mute)
sc->sc_mm.data[1] = sc->sc_ratt;
}
+ if (sc->sc_powerstate == 0)
+ return;
pipe_transmit_fixed(sc, 20, *(u_int32_t *)__UNVOLATILE(sc->sc_mm.data));
/* give the chip some time to execure the command */
@@ -969,9 +1042,7 @@ chi_reset(struct dbri_softc *sc, enum ms ms, int bpf)
void
pipe_setup(struct dbri_softc *sc, int pipe, int sdp)
{
-#ifdef DBRI_DEBUG
- printf("pipe setup: %d\n",pipe);
-#endif
+ DPRINTF(("pipe setup: %d\n", pipe));
if (pipe < 0 || pipe >= DBRI_PIPE_MAX) {
printf("%s: illegal pipe number %d\n", sc->sc_dev.dv_xname,
pipe);
@@ -1620,11 +1691,11 @@ dbri_trigger_output(void *hdl, void *start, void *end, int blksize,
count = (unsigned long)(((caddr_t)end - (caddr_t)start));
num = count / blksize;
-#ifdef DBRI_DEBUG
- printf("trigger_output(%lx %lx) : %d %ld %ld\n",
+
+ DPRINTF(("trigger_output(%lx %lx) : %d %ld %ld\n",
(unsigned long)intr,
- (unsigned long)intrarg, blksize, count, num);
-#endif
+ (unsigned long)intrarg, blksize, count, num));
+
sc->sc_params = *param;
mmcodec_setcontrol(sc);
@@ -1687,10 +1758,8 @@ static void
dd->callback = NULL;
dd->dmabase =
dd->dmamap->dm_segs[0].ds_addr;
-#ifdef DBRI_DEBUG
- printf("dbri_malloc: using buffer %d\n",
- sc->sc_desc_used);
-#endif
+ DPRINTF(("dbri_malloc: using buffer %d\n",
+ sc->sc_desc_used));
sc->sc_desc_used++;
return dd->buf;
} else
@@ -1736,4 +1805,39 @@ dbri_mappage(void *v, void *mem, off_t off, int prot)
return -1;
}
-#endif
+static int
+dbri_open(void *cookie, int flags)
+{
+ struct dbri_softc *sc = cookie;
+
+ dbri_bring_up(sc);
+ return 0;
+}
+
+static void
+dbri_close(void *cookie)
+{
+ struct dbri_softc *sc = cookie;
+
+ dbri_set_power(sc, 0);
+}
+
+static void
+dbri_powerhook(int why, void *cookie)
+{
+ struct dbri_softc *sc = cookie;
+
+ switch(why)
+ {
+ case PWR_SUSPEND:
+ case PWR_STANDBY:
+ dbri_set_power(sc, 0);
+ break;
+ case PWR_RESUME:
+ dbri_bring_up(sc);
+ break;
+ }
+}
+
+#endif /* NAUDIO > 0 */
+
diff --git a/sys/dev/sbus/dbrireg.h b/sys/dev/sbus/dbrireg.h
index 81d45df4383..821f41c4d87 100644
--- a/sys/dev/sbus/dbrireg.h
+++ b/sys/dev/sbus/dbrireg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: dbrireg.h,v 1.3 2005/12/11 12:23:44 christos Exp $ */
+/* $NetBSD: dbrireg.h,v 1.4 2006/03/09 20:44:18 macallan Exp $ */
/*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -41,6 +41,9 @@
*
*/
+#ifndef DBRI_REG_H
+#define DBRI_REG_H
+
#define DBRI_REG0 0x00L /* status and control */
#define DBRI_COMMAND_VALID (1<<15)
#define DBRI_BURST_4 (1<<14) /* allow 4-word sbus bursts */
@@ -127,3 +130,5 @@
#define DBRI_TD_FINAL (1<<15) /* final interrupt */
#define DBRI_TD_IDLE (1<<13) /* transmit idle characters */
#define DBRI_TD_TBC (1<<0) /* transmit buffer complete */
+
+#endif /* DBRI_REG_H */
diff --git a/sys/dev/sbus/dbrivar.h b/sys/dev/sbus/dbrivar.h
index 25d335ca3e1..2f5c3cbc289 100644
--- a/sys/dev/sbus/dbrivar.h
+++ b/sys/dev/sbus/dbrivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: dbrivar.h,v 1.3 2005/12/11 12:23:44 christos Exp $ */
+/* $NetBSD: dbrivar.h,v 1.4 2006/03/09 20:44:18 macallan Exp $ */
/*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -41,6 +41,8 @@
*
*/
+#ifndef DBRI_VAR_H
+#define DBRI_VAR_H
#define DBRI_NUM_COMMANDS 64
#define DBRI_NUM_DESCRIPTORS 64
@@ -55,7 +57,7 @@ enum direction {
/* DBRI DMA transmit descriptor */
struct dbri_mem {
- volatile u_int32_t flags;
+ volatile uint32_t flags;
#define TX_EOF 0x80000000 /* End of frame marker */
#define TX_BCNT(x) ((x&0x3fff)<<16)
#define TX_BINT 0x00008000 /* interrupt when EOF */
@@ -63,23 +65,23 @@ struct dbri_mem {
#define TX_IDLE 0x00002000 /* send idles after data */
#define TX_FCNT(x) (x&0x1fff)
- volatile u_int32_t ba; /* tx/rx buffer address */
- volatile u_int32_t nda; /* next descriptor address */
- volatile u_int32_t status;
+ volatile uint32_t ba; /* tx/rx buffer address */
+ volatile uint32_t nda; /* next descriptor address */
+ volatile uint32_t status;
#define TS_OK 0x0001 /* transmission completed */
#define TS_ABORT 0x0004 /* transmission aborted */
#define TS_UNDERRUN 0x0008 /* DMA underrun */
};
struct dbri_pipe {
- u_int32_t sdp; /* SDP command word */
+ uint32_t sdp; /* SDP command word */
enum direction direction;
int next; /* next pipe in linked list */
int prev; /* previous pipe in linked list */
int cycle; /* offset of timeslot (bits) */
int length; /* length of timeslot (bits) */
int desc; /* index of active descriptor */
- volatile u_int32_t *prec; /* pointer to received fixed data */
+ volatile uint32_t *prec; /* pointer to received fixed data */
};
struct dbri_desc {
@@ -95,7 +97,7 @@ struct dbri_desc {
};
struct dbri_dma {
- volatile u_int32_t command[DBRI_NUM_COMMANDS];
+ volatile uint32_t command[DBRI_NUM_COMMANDS];
volatile int32_t intr[DBRI_INT_BLOCKS];
struct dbri_mem desc[DBRI_NUM_DESCRIPTORS];
bus_dmamap_t dmamap;
@@ -110,7 +112,9 @@ struct dbri_softc {
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmamap;
bus_dma_segment_t sc_dmaseg;
-
+
+ int sc_have_powerctl;
+ int sc_powerstate;
int sc_burst; /* DVMA burst size in effect */
bus_addr_t sc_dmabase; /* VA of buffer we provide */
@@ -134,7 +138,7 @@ struct dbri_softc {
int sc_latt, sc_ratt;
int sc_ctl_mode;
- u_int32_t sc_version;
+ uint32_t sc_version;
int sc_chi_pipe_in;
int sc_chi_pipe_out;
int sc_chi_bpf;
@@ -147,7 +151,7 @@ struct dbri_softc {
};
#define dbri_dma_off(member, elem) \
- ((u_int32_t)(unsigned long) \
+ ((uint32_t)(unsigned long) \
(&(((struct dbri_dma *)0)->member[elem])))
#if 1
@@ -163,3 +167,5 @@ struct dbri_softc {
#define DBRI_SDP_MODE(v) ((v) & (7 << 13))
#define DBRI_PIPE(v) ((v) << 0)
+
+#endif /* DBRI_VAR_H */
diff --git a/sys/dev/sbus/files.sbus b/sys/dev/sbus/files.sbus
index a6734004ecc..2487089e9a3 100644
--- a/sys/dev/sbus/files.sbus
+++ b/sys/dev/sbus/files.sbus
@@ -1,4 +1,4 @@
-# $NetBSD: files.sbus,v 1.24 2006/03/09 05:42:35 macallan Exp $
+# $NetBSD: files.sbus,v 1.25 2006/03/09 20:44:18 macallan Exp $
#
# Config file and device description for machine-independent SBUS code.
# Included by ports that need it.
@@ -126,6 +126,8 @@ attach pnozz at sbus
file dev/sbus/p9100.c pnozz needs-flag
# SUNW,DBRI audio
+defflag opt_sbus_dbri.h DBRI_DEBUG
+defflag opt_sbus_dbri.h DBRI_BIG_BUFFER
device dbri { }: audiobus, auconv, mulaw
attach dbri at sbus
file dev/sbus/dbri.c dbri