#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: apc.c,v 1.3 2025/05/31 15:14:40 jdc Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <machine/autoconf.h>
#include <sparc/dev/apcreg.h>
static int apcmatch(device_t, struct cfdata *, void *);
static void apcattach(device_t, device_t, void *);
static void apc_cpu_sleep(void);
struct apc_softc {
device_t sc_dev;
bus_space_tag_t sc_bt;
bus_space_handle_t sc_bh;
};
struct apc_softc *apc = NULL;
CFATTACH_DECL_NEW(apc, sizeof(struct apc_softc),
apcmatch, apcattach, NULL, NULL);
static int
apcmatch(device_t parent, struct cfdata *cf, void *aux)
{
struct sbus_attach_args *sa = aux;
if (apc != NULL)
return 0;
return strcmp("power-management", sa->sa_name) == 0;
}
static void
apcattach(device_t parent, device_t self, void *aux)
{
struct sbus_attach_args *sa = aux;
struct apc_softc *sc = device_private(self);
#ifdef MULTIPROCESSOR
struct cpu_info *cpi;
CPU_INFO_ITERATOR n;
#endif
sc->sc_bt = sa->sa_bustag;
if (sbus_bus_map(sa->sa_bustag,
sa->sa_slot, sa->sa_offset, APC_REG_SIZE, 0, &sc->sc_bh) != 0) {
aprint_error(": cannot map registers\n");
return;
}
aprint_normal("\n");
apc = sc;
#ifdef MULTIPROCESSOR
for (CPU_INFO_FOREACH(n, cpi)) {
cpi->idlespin = apc_cpu_sleep;
}
#else
curcpu()->idlespin = apc_cpu_sleep;
#endif
}
static void
apc_cpu_sleep(void)
{
uint8_t val;
if (apc == NULL)
return;
val = bus_space_read_1(apc->sc_bt, apc->sc_bh, APC_IDLE_REG);
bus_space_write_1(apc->sc_bt, apc->sc_bh, APC_IDLE_REG,
val | APC_IDLE_REG_IDLE);
}