QemuK210/roms/openbios/drivers/pmu.c

682 lines
21 KiB
C

/*
* Device driver for the via-pmu on Apple Powermacs.
*
* The VIA (versatile interface adapter) interfaces to the PMU,
* a 6805 microprocessor core whose primary function is to control
* battery charging and system power on the PowerBook 3400 and 2400.
* The PMU also controls the ADB (Apple Desktop Bus) which connects
* to the keyboard and mouse, as well as the non-volatile RAM
* and the RTC (real time clock) chip.
*
* Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
* Copyright (C) 2001-2002 Benjamin Herrenschmidt
* Copyright (C) 2006-2007 Johannes Berg
*
*/
#include "config.h"
#include "libopenbios/bindings.h"
#include "drivers/drivers.h"
#include "libc/byteorder.h"
#include "libc/vsprintf.h"
#include "macio.h"
#include "pmu.h"
#undef DEBUG_PMU
#ifdef DEBUG_PMU
#define PMU_DPRINTF(fmt, args...) \
do { printk("PMU - %s: " fmt, __func__ , ##args); } while (0)
#else
#define PMU_DPRINTF(fmt, args...) do { } while (0)
#endif
#define IO_PMU_OFFSET 0x00016000
#define IO_PMU_SIZE 0x00002000
/* VIA registers - spaced 0x200 bytes apart */
#define RS 0x200 /* skip between registers */
#define B 0 /* B-side data */
#define A RS /* A-side data */
#define DIRB (2*RS) /* B-side direction (1=output) */
#define DIRA (3*RS) /* A-side direction (1=output) */
#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
#define SR (10*RS) /* Shift register */
#define ACR (11*RS) /* Auxiliary control register */
#define PCR (12*RS) /* Peripheral control register */
#define IFR (13*RS) /* Interrupt flag register */
#define IER (14*RS) /* Interrupt enable register */
#define ANH (15*RS) /* A-side data, no handshake */
/* Bits in B data register: all active low */
#define TACK 0x08 /* Transfer request (input) */
#define TREQ 0x10 /* Transfer acknowledge (output) */
/* Bits in ACR */
#define SR_CTRL 0x1c /* Shift register control bits */
#define SR_EXT 0x0c /* Shift on external clock */
#define SR_OUT 0x10 /* Shift out if 1 */
/* Bits in IFR and IER */
#define IER_SET 0x80 /* set bits in IER */
#define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */
/*
* This table indicates for each PMU opcode:
* - the number of data bytes to be sent with the command, or -1
* if a length byte should be sent,
* - the number of response bytes which the PMU will return, or
* -1 if it will send a length byte.
*/
static const int8_t pmu_data_len[256][2] = {
/* 0 1 2 3 4 5 6 7 */
/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
/*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
/*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
/*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
};
/*
* PMU commands
*/
#define PMU_POWER_CTRL0 0x10 /* control power of some devices */
#define PMU_POWER_CTRL 0x11 /* control power of some devices */
#define PMU_ADB_CMD 0x20 /* send ADB packet */
#define PMU_ADB_POLL_OFF 0x21 /* disable ADB auto-poll */
#define PMU_WRITE_NVRAM 0x33 /* write non-volatile RAM */
#define PMU_READ_NVRAM 0x3b /* read non-volatile RAM */
#define PMU_SET_RTC 0x30 /* set real-time clock */
#define PMU_READ_RTC 0x38 /* read real-time clock */
#define PMU_SET_VOLBUTTON 0x40 /* set volume up/down position */
#define PMU_BACKLIGHT_BRIGHT 0x41 /* set backlight brightness */
#define PMU_GET_VOLBUTTON 0x48 /* get volume up/down position */
#define PMU_PCEJECT 0x4c /* eject PC-card from slot */
#define PMU_BATTERY_STATE 0x6b /* report battery state etc. */
#define PMU_SMART_BATTERY_STATE 0x6f /* report battery state (new way) */
#define PMU_SET_INTR_MASK 0x70 /* set PMU interrupt mask */
#define PMU_INT_ACK 0x78 /* read interrupt bits */
#define PMU_SHUTDOWN 0x7e /* turn power off */
#define PMU_CPU_SPEED 0x7d /* control CPU speed on some models */
#define PMU_SLEEP 0x7f /* put CPU to sleep */
#define PMU_POWER_EVENTS 0x8f /* Send power-event commands to PMU */
#define PMU_I2C_CMD 0x9a /* I2C operations */
#define PMU_RESET 0xd0 /* reset CPU */
#define PMU_GET_BRIGHTBUTTON 0xd9 /* report brightness up/down pos */
#define PMU_GET_COVER 0xdc /* report cover open/closed */
#define PMU_SYSTEM_READY 0xdf /* tell PMU we are awake */
#define PMU_GET_VERSION 0xea /* read the PMU version */
/* Bits to use with the PMU_POWER_CTRL0 command */
#define PMU_POW0_ON 0x80 /* OR this to power ON the device */
#define PMU_POW0_OFF 0x00 /* leave bit 7 to 0 to power it OFF */
#define PMU_POW0_HARD_DRIVE 0x04 /* Hard drive power (on wallstreet/lombard ?) */
/* Bits to use with the PMU_POWER_CTRL command */
#define PMU_POW_ON 0x80 /* OR this to power ON the device */
#define PMU_POW_OFF 0x00 /* leave bit 7 to 0 to power it OFF */
#define PMU_POW_BACKLIGHT 0x01 /* backlight power */
#define PMU_POW_CHARGER 0x02 /* battery charger power */
#define PMU_POW_IRLED 0x04 /* IR led power (on wallstreet) */
#define PMU_POW_MEDIABAY 0x08 /* media bay power (wallstreet/lombard ?) */
/* Bits in PMU interrupt and interrupt mask bytes */
#define PMU_INT_PCEJECT 0x04 /* PC-card eject buttons */
#define PMU_INT_SNDBRT 0x08 /* sound/brightness up/down buttons */
#define PMU_INT_ADB 0x10 /* ADB autopoll or reply data */
#define PMU_INT_BATTERY 0x20 /* Battery state change */
#define PMU_INT_ENVIRONMENT 0x40 /* Environment interrupts */
#define PMU_INT_TICK 0x80 /* 1-second tick interrupt */
/* Other bits in PMU interrupt valid when PMU_INT_ADB is set */
#define PMU_INT_ADB_AUTO 0x04 /* ADB autopoll, when PMU_INT_ADB */
#define PMU_INT_WAITING_CHARGER 0x01 /* ??? */
#define PMU_INT_AUTO_SRQ_POLL 0x02 /* ??? */
/* Bits in the environement message (either obtained via PMU_GET_COVER,
* or via PMU_INT_ENVIRONMENT on core99 */
#define PMU_ENV_LID_CLOSED 0x01 /* The lid is closed */
/* I2C related definitions */
#define PMU_I2C_MODE_SIMPLE 0
#define PMU_I2C_MODE_STDSUB 1
#define PMU_I2C_MODE_COMBINED 2
#define PMU_I2C_BUS_STATUS 0
#define PMU_I2C_BUS_SYSCLK 1
#define PMU_I2C_BUS_POWER 2
#define PMU_I2C_STATUS_OK 0
#define PMU_I2C_STATUS_DATAREAD 1
#define PMU_I2C_STATUS_BUSY 0xfe
/* PMU PMU_POWER_EVENTS commands */
enum {
PMU_PWR_GET_POWERUP_EVENTS = 0x00,
PMU_PWR_SET_POWERUP_EVENTS = 0x01,
PMU_PWR_CLR_POWERUP_EVENTS = 0x02,
PMU_PWR_GET_WAKEUP_EVENTS = 0x03,
PMU_PWR_SET_WAKEUP_EVENTS = 0x04,
PMU_PWR_CLR_WAKEUP_EVENTS = 0x05,
};
/* Power events wakeup bits */
enum {
PMU_PWR_WAKEUP_KEY = 0x01, /* Wake on key press */
PMU_PWR_WAKEUP_AC_INSERT = 0x02, /* Wake on AC adapter plug */
PMU_PWR_WAKEUP_AC_CHANGE = 0x04,
PMU_PWR_WAKEUP_LID_OPEN = 0x08,
PMU_PWR_WAKEUP_RING = 0x10,
};
static uint8_t pmu_readb(pmu_t *dev, int reg)
{
return *(volatile uint8_t *)(dev->base + reg);
asm volatile("eieio" : : : "memory");
}
static void pmu_writeb(pmu_t *dev, int reg, uint8_t val)
{
*(volatile uint8_t *)(dev->base + reg) = val;
asm volatile("eieio" : : : "memory");
}
static void pmu_handshake(pmu_t *dev)
{
pmu_writeb(dev, B, pmu_readb(dev, B) & ~TREQ);
while ((pmu_readb(dev, B) & TACK) != 0);
pmu_writeb(dev, B, pmu_readb(dev, B) | TREQ);
while ((pmu_readb(dev, B) & TACK) == 0);
}
static void pmu_send_byte(pmu_t *dev, uint8_t val)
{
pmu_writeb(dev, ACR, pmu_readb(dev, ACR) | SR_OUT | SR_EXT);
pmu_writeb(dev, SR, val);
pmu_handshake(dev);
}
static uint8_t pmu_recv_byte(pmu_t *dev)
{
pmu_writeb(dev, ACR, (pmu_readb(dev, ACR) & ~SR_OUT) | SR_EXT);
pmu_readb(dev, SR);
pmu_handshake(dev);
return pmu_readb(dev, SR);
}
int pmu_request(pmu_t *dev, uint8_t cmd,
uint8_t in_len, uint8_t *in_data,
uint8_t *out_len, uint8_t *out_data)
{
int i, l, out_sz;
uint8_t d;
/* Check command data size */
l = pmu_data_len[cmd][0];
if (l >= 0 && in_len != l) {
printk("PMU: Error, request %02x wants %d args, got %d\n",
cmd, l, in_len);
return -1;
}
/* Make sure PMU is idle */
while ((pmu_readb(dev, B) & TACK) == 0);
/* Send command */
pmu_send_byte(dev, cmd);
/* Optionally send data length */
if (l < 0) {
pmu_send_byte(dev, in_len);
/* Send data */
}
for (i = 0; i < in_len; i++) {
pmu_send_byte(dev, in_data[i]);
}
/* Check response size */
l = pmu_data_len[cmd][1];
if (l < 0) {
l = pmu_recv_byte(dev);
}
if (out_len) {
out_sz = *out_len;
*out_len = 0;
} else {
out_sz = 0;
}
if (l > out_sz) {
printk("PMU: Error, request %02x returns %d bytes"
", room for %d\n", cmd, l, out_sz);
}
for (i = 0; i < l; i++) {
d = pmu_recv_byte(dev);
if (i < out_sz) {
out_data[i] = d;
(*out_len)++;
}
}
return 0;
}
#define MAX_REQ_SIZE 128
#ifdef CONFIG_DRIVER_ADB
static int pmu_adb_req(void *host, const uint8_t *snd_buf, int len,
uint8_t *rcv_buf)
{
uint8_t buffer[MAX_REQ_SIZE], *pos, olen;
int rc;
PMU_DPRINTF("pmu_adb_req: len=%d: %02x %02x %02x...\n",
len, snd_buf[0], snd_buf[1], snd_buf[2]);
if (len >= (MAX_REQ_SIZE - 1)) {
printk("pmu_adb_req: too big ! (%d)\n", len);
return -1;
}
buffer[0] = snd_buf[0];
buffer[1] = 0; /* We don't do autopoll */
buffer[2] = len - 1;
if (len > 1) {
memcpy(&buffer[3], &snd_buf[1], len - 1);
}
rc = pmu_request(host, PMU_ADB_CMD, len + 2, buffer, NULL, NULL);
if (rc) {
printk("PMU adb request failure %d\n", rc);
return 0;
}
olen = MAX_REQ_SIZE;
rc = pmu_request(host, PMU_INT_ACK, 0, NULL, &olen, buffer);
if (rc) {
printk("PMU intack request failure %d\n", rc);
return 0;
}
PMU_DPRINTF("pmu_resp=%d int=0x%02x\n", olen, buffer[0]);
if (olen <= 2) {
return 0;
} else {
pos = &buffer[3];
olen -= 3;
PMU_DPRINTF("ADB resp: 0x%02x 0x%02x\n", buffer[3], buffer[4]);
}
memcpy(rcv_buf, pos, olen);
return olen;
}
#endif
DECLARE_UNNAMED_NODE(ob_pmu, 0, sizeof(int));
static pmu_t *main_pmu;
static void pmu_reset_all(void)
{
pmu_request(main_pmu, PMU_RESET, 0, NULL, NULL, NULL);
}
static void pmu_poweroff(void)
{
uint8_t params[] = "MATT";
pmu_request(main_pmu, PMU_SHUTDOWN, 4, params, NULL, NULL);
}
static void ob_pmu_open(int *idx)
{
RET(-1);
}
static void ob_pmu_close(int *idx)
{
}
NODE_METHODS(ob_pmu) = {
{ "open", ob_pmu_open },
{ "close", ob_pmu_close },
};
DECLARE_UNNAMED_NODE(rtc, 0, sizeof(int));
static void rtc_open(int *idx)
{
RET(-1);
}
static void rtc_close(int *idx)
{
}
/*
* get-time ( -- second minute hour day month year )
*
*/
static const int days_month[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static const int days_month_leap[12] =
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static inline int is_leap(int year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
static void rtc_get_time(int *idx)
{
uint8_t obuf[4], olen;
ucell second, minute, hour, day, month, year;
uint32_t now;
int current;
const int *days;
olen = 4;
pmu_request(main_pmu, PMU_READ_RTC, 0, NULL, &olen, obuf);
/* seconds since 01/01/1904 */
now = (obuf[0] << 24) + (obuf[1] << 16) + (obuf[2] << 8) + obuf[3];
second = now % 60;
now /= 60;
minute = now % 60;
now /= 60;
hour = now % 24;
now /= 24;
year = now * 100 / 36525;
now -= year * 36525 / 100;
year += 1904;
days = is_leap(year) ? days_month_leap : days_month;
current = 0;
month = 0;
while (month < 12) {
if (now <= current + days[month]) {
break;
}
current += days[month];
month++;
}
month++;
day = now - current;
PUSH(second);
PUSH(minute);
PUSH(hour);
PUSH(day);
PUSH(month);
PUSH(year);
}
/*
* set-time ( second minute hour day month year -- )
*
*/
static void rtc_set_time(int *idx)
{
uint8_t ibuf[4];
ucell second, minute, hour, day, month, year;
const int *days;
uint32_t now;
unsigned int nb_days;
int i;
year = POP();
month = POP();
day = POP();
hour = POP();
minute = POP();
second = POP();
days = is_leap(year) ? days_month_leap : days_month;
nb_days = (year - 1904) * 36525 / 100 + day;
for (i = 0; i < month - 1; i++) {
nb_days += days[i];
}
now = (((nb_days * 24) + hour) * 60 + minute) * 60 + second;
ibuf[0] = now >> 24;
ibuf[1] = now >> 16;
ibuf[2] = now >> 8;
ibuf[3] = now;
pmu_request(main_pmu, PMU_SET_RTC, 4, ibuf, NULL, NULL);
}
NODE_METHODS(rtc) = {
{ "open", rtc_open },
{ "close", rtc_close },
{ "get-time", rtc_get_time },
{ "set-time", rtc_set_time },
};
static void rtc_init(char *path)
{
phandle_t aliases;
char buf[128];
push_str(path);
fword("find-device");
fword("new-device");
push_str("rtc");
fword("device-name");
push_str("rtc");
fword("device-type");
push_str("rtc,via-pmu");
fword("encode-string");
push_str("compatible");
fword("property");
BIND_NODE_METHODS(get_cur_dev(), rtc);
fword("finish-device");
aliases = find_dev("/aliases");
snprintf(buf, sizeof(buf), "%s/rtc", path);
set_property(aliases, "rtc", buf, strlen(buf) + 1);
}
static void powermgt_init(char *path)
{
phandle_t ph;
push_str(path);
fword("find-device");
fword("new-device");
push_str("power-mgt");
fword("device-name");
push_str("power-mgt");
fword("device-type");
push_str("via-pmu-99");
fword("encode-string");
push_str("compatible");
fword("property");
push_str("extint-gpio1");
fword("encode-string");
push_str("registry-name");
fword("property");
/* This is a bunch of magic "Feature" bits for which we only have
* partial definitions from Darwin. These are taken from a
* PowerMac3,1 device-tree. They are also identical in a
* PowerMac5,1 "Cube". Note that more recent machines such as
* the MacMini (PowerMac10,1) do not have this property, however
* MacOS 9 seems to require it (it hangs during boot otherwise).
*/
const char prim[] = { 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x2c,
0x00, 0x03, 0x0d, 0x40,
/* Public PM features */
/* 0x00000001 : Wake timer supported */
/* 0x00000004 : Processor cycling supported */
/* 0x00000100 : Can wake on modem ring */
/* 0x00000200 : Has monitor dimming support */
/* 0x00000400 : Can program startup timer */
/* 0x00002000 : Supports wake on LAN */
/* 0x00004000 : Can wake on LID/case open */
/* 0x00008000 : Can power off PCI on sleep */
/* 0x00010000 : Supports deep sleep */
0x00, 0x01, 0xe7, 0x05,
/* Private PM features */
/* 0x00000400 : Supports ICT control */
/* 0x00001000 : Supports Idle2 in hardware */
/* 0x00002000 : Open case prevents sleep */
0x00, 0x00, 0x34, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, /* # of batteries supported */
0x26, 0x0d,
0x46, 0x00, 0x02, 0x78,
0x78, 0x3c, 0x00 };
ph = get_cur_dev();
BIND_NODE_METHODS(ph, rtc);
set_property(ph, "prim-info", prim, sizeof(prim));
fword("finish-device");
}
pmu_t *pmu_init(const char *path, phys_addr_t base)
{
pmu_t *pmu;
char buf[64];
phandle_t aliases;
base += IO_PMU_OFFSET;
PMU_DPRINTF(" base=" FMT_plx "\n", base);
pmu = malloc(sizeof(pmu_t));
if (pmu == NULL) {
return NULL;
}
fword("new-device");
push_str("via-pmu");
fword("device-name");
push_str("via-pmu");
fword("device-type");
push_str("pmu");
fword("encode-string");
push_str("compatible");
fword("property");
PUSH(1);
fword("encode-int");
push_str("#address-cells");
fword("property");
PUSH(0);
fword("encode-int");
push_str("#size-cells");
fword("property");
PUSH(IO_PMU_OFFSET);
fword("encode-int");
PUSH(IO_PMU_SIZE);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
/* On newworld machines the PMU is on interrupt 0x19 */
PUSH(0x19);
fword("encode-int");
PUSH(1);
fword("encode-int");
fword("encode+");
push_str("interrupts");
fword("property");
PUSH(0xd0330c);
fword("encode-int");
push_str("pmu-version");
fword("property");
BIND_NODE_METHODS(get_cur_dev(), ob_pmu);
aliases = find_dev("/aliases");
snprintf(buf, sizeof(buf), "%s/via-pmu", path);
set_property(aliases, "via-pmu", buf, strlen(buf) + 1);
pmu->base = base;
#ifdef CONFIG_DRIVER_ADB
if (has_adb()) {
pmu->adb_bus = adb_bus_new(pmu, &pmu_adb_req);
adb_bus_init(buf, pmu->adb_bus);
}
#endif
rtc_init(buf);
powermgt_init(buf);
main_pmu = pmu;
fword("finish-device");
bind_func("pmu-power-off", pmu_poweroff);
feval("['] pmu-power-off to power-off");
bind_func("pmu-reset-all", pmu_reset_all);
feval("['] pmu-reset-all to reset-all");
return pmu;
}