1 /*
2  * Device driver for the via-pmu on Apple Powermacs.
3  *
4  * The VIA (versatile interface adapter) interfaces to the PMU,
5  * a 6805 microprocessor core whose primary function is to control
6  * battery charging and system power on the PowerBook 3400 and 2400.
7  * The PMU also controls the ADB (Apple Desktop Bus) which connects
8  * to the keyboard and mouse, as well as the non-volatile RAM
9  * and the RTC (real time clock) chip.
10  *
11  * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
12  * Copyright (C) 2001-2002 Benjamin Herrenschmidt
13  * Copyright (C) 2006-2007 Johannes Berg
14  *
15  */
16 
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "drivers/drivers.h"
20 #include "libc/byteorder.h"
21 #include "libc/vsprintf.h"
22 
23 #include "macio.h"
24 #include "pmu.h"
25 
26 #undef DEBUG_PMU
27 #ifdef DEBUG_PMU
28 #define PMU_DPRINTF(fmt, args...) \
29 	do { printk("PMU - %s: " fmt, __func__ , ##args); } while (0)
30 #else
31 #define PMU_DPRINTF(fmt, args...) do { } while (0)
32 #endif
33 
34 #define IO_PMU_OFFSET	0x00016000
35 #define IO_PMU_SIZE	0x00002000
36 
37 /* VIA registers - spaced 0x200 bytes apart */
38 #define RS              0x200           /* skip between registers */
39 #define B               0               /* B-side data */
40 #define A               RS              /* A-side data */
41 #define DIRB            (2*RS)          /* B-side direction (1=output) */
42 #define DIRA            (3*RS)          /* A-side direction (1=output) */
43 #define T1CL            (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
44 #define T1CH            (5*RS)          /* Timer 1 counter (high 8 bits) */
45 #define T1LL            (6*RS)          /* Timer 1 latch (low 8 bits) */
46 #define T1LH            (7*RS)          /* Timer 1 latch (high 8 bits) */
47 #define T2CL            (8*RS)          /* Timer 2 ctr/latch (low 8 bits) */
48 #define T2CH            (9*RS)          /* Timer 2 counter (high 8 bits) */
49 #define SR              (10*RS)         /* Shift register */
50 #define ACR             (11*RS)         /* Auxiliary control register */
51 #define PCR             (12*RS)         /* Peripheral control register */
52 #define IFR             (13*RS)         /* Interrupt flag register */
53 #define IER             (14*RS)         /* Interrupt enable register */
54 #define ANH             (15*RS)         /* A-side data, no handshake */
55 
56 /* Bits in B data register: all active low */
57 #define TACK		0x08		/* Transfer request (input) */
58 #define TREQ		0x10		/* Transfer acknowledge (output) */
59 
60 /* Bits in ACR */
61 #define SR_CTRL         0x1c            /* Shift register control bits */
62 #define SR_EXT          0x0c            /* Shift on external clock */
63 #define SR_OUT          0x10            /* Shift out if 1 */
64 
65 /* Bits in IFR and IER */
66 #define IER_SET         0x80            /* set bits in IER */
67 #define IER_CLR         0               /* clear bits in IER */
68 #define SR_INT          0x04            /* Shift register full/empty */
69 
70 /*
71  * This table indicates for each PMU opcode:
72  * - the number of data bytes to be sent with the command, or -1
73  *   if a length byte should be sent,
74  * - the number of response bytes which the PMU will return, or
75  *   -1 if it will send a length byte.
76  */
77 static const int8_t pmu_data_len[256][2] = {
78 /*	   0	   1	   2	   3	   4	   5	   6	   7  */
79 /*00*/  {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
80 /*08*/  {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
81 /*10*/  { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
82 /*18*/  { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
83 /*20*/  {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
84 /*28*/  { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
85 /*30*/  { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
86 /*38*/  { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
87 /*40*/  { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
88 /*48*/  { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
89 /*50*/  { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
90 /*58*/  { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
91 /*60*/  { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
92 /*68*/  { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
93 /*70*/  { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
94 /*78*/  { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
95 /*80*/  { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
96 /*88*/  { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
97 /*90*/  { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
98 /*98*/  { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
99 /*a0*/  { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
100 /*a8*/  { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
101 /*b0*/  {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
102 /*b8*/  {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
103 /*c0*/  {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
104 /*c8*/  {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
105 /*d0*/  { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
106 /*d8*/  { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
107 /*e0*/  {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
108 /*e8*/  { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
109 /*f0*/  {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
110 /*f8*/  {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
111 };
112 
113 /*
114  * PMU commands
115  */
116 #define PMU_POWER_CTRL0            0x10  /* control power of some devices */
117 #define PMU_POWER_CTRL             0x11  /* control power of some devices */
118 #define PMU_ADB_CMD                0x20  /* send ADB packet */
119 #define PMU_ADB_POLL_OFF           0x21  /* disable ADB auto-poll */
120 #define PMU_WRITE_NVRAM            0x33  /* write non-volatile RAM */
121 #define PMU_READ_NVRAM             0x3b  /* read non-volatile RAM */
122 #define PMU_SET_RTC                0x30  /* set real-time clock */
123 #define PMU_READ_RTC               0x38  /* read real-time clock */
124 #define PMU_SET_VOLBUTTON          0x40  /* set volume up/down position */
125 #define PMU_BACKLIGHT_BRIGHT       0x41  /* set backlight brightness */
126 #define PMU_GET_VOLBUTTON          0x48  /* get volume up/down position */
127 #define PMU_PCEJECT                0x4c  /* eject PC-card from slot */
128 #define PMU_BATTERY_STATE          0x6b  /* report battery state etc. */
129 #define PMU_SMART_BATTERY_STATE    0x6f  /* report battery state (new way) */
130 #define PMU_SET_INTR_MASK          0x70  /* set PMU interrupt mask */
131 #define PMU_INT_ACK                0x78  /* read interrupt bits */
132 #define PMU_SHUTDOWN               0x7e  /* turn power off */
133 #define PMU_CPU_SPEED              0x7d  /* control CPU speed on some models */
134 #define PMU_SLEEP                  0x7f  /* put CPU to sleep */
135 #define PMU_POWER_EVENTS           0x8f  /* Send power-event commands to PMU */
136 #define PMU_I2C_CMD                0x9a  /* I2C operations */
137 #define PMU_RESET                  0xd0  /* reset CPU */
138 #define PMU_GET_BRIGHTBUTTON       0xd9  /* report brightness up/down pos */
139 #define PMU_GET_COVER              0xdc  /* report cover open/closed */
140 #define PMU_SYSTEM_READY           0xdf  /* tell PMU we are awake */
141 #define PMU_GET_VERSION            0xea  /* read the PMU version */
142 
143 /* Bits to use with the PMU_POWER_CTRL0 command */
144 #define PMU_POW0_ON                0x80  /* OR this to power ON the device */
145 #define PMU_POW0_OFF               0x00  /* leave bit 7 to 0 to power it OFF */
146 #define PMU_POW0_HARD_DRIVE        0x04  /* Hard drive power (on wallstreet/lombard ?) */
147 
148 /* Bits to use with the PMU_POWER_CTRL command */
149 #define PMU_POW_ON                 0x80  /* OR this to power ON the device */
150 #define PMU_POW_OFF                0x00  /* leave bit 7 to 0 to power it OFF */
151 #define PMU_POW_BACKLIGHT          0x01  /* backlight power */
152 #define PMU_POW_CHARGER            0x02  /* battery charger power */
153 #define PMU_POW_IRLED              0x04  /* IR led power (on wallstreet) */
154 #define PMU_POW_MEDIABAY           0x08  /* media bay power (wallstreet/lombard ?) */
155 
156 /* Bits in PMU interrupt and interrupt mask bytes */
157 #define PMU_INT_PCEJECT            0x04  /* PC-card eject buttons */
158 #define PMU_INT_SNDBRT             0x08  /* sound/brightness up/down buttons */
159 #define PMU_INT_ADB                0x10  /* ADB autopoll or reply data */
160 #define PMU_INT_BATTERY            0x20  /* Battery state change */
161 #define PMU_INT_ENVIRONMENT        0x40  /* Environment interrupts */
162 #define PMU_INT_TICK               0x80  /* 1-second tick interrupt */
163 
164 /* Other bits in PMU interrupt valid when PMU_INT_ADB is set */
165 #define PMU_INT_ADB_AUTO           0x04  /* ADB autopoll, when PMU_INT_ADB */
166 #define PMU_INT_WAITING_CHARGER    0x01  /* ??? */
167 #define PMU_INT_AUTO_SRQ_POLL      0x02  /* ??? */
168 
169 /* Bits in the environement message (either obtained via PMU_GET_COVER,
170  * or via PMU_INT_ENVIRONMENT on core99 */
171 #define PMU_ENV_LID_CLOSED         0x01  /* The lid is closed */
172 
173 /* I2C related definitions */
174 #define PMU_I2C_MODE_SIMPLE    0
175 #define PMU_I2C_MODE_STDSUB    1
176 #define PMU_I2C_MODE_COMBINED  2
177 
178 #define PMU_I2C_BUS_STATUS     0
179 #define PMU_I2C_BUS_SYSCLK     1
180 #define PMU_I2C_BUS_POWER      2
181 
182 #define PMU_I2C_STATUS_OK          0
183 #define PMU_I2C_STATUS_DATAREAD    1
184 #define PMU_I2C_STATUS_BUSY        0xfe
185 
186 /* PMU PMU_POWER_EVENTS commands */
187 enum {
188     PMU_PWR_GET_POWERUP_EVENTS = 0x00,
189     PMU_PWR_SET_POWERUP_EVENTS = 0x01,
190     PMU_PWR_CLR_POWERUP_EVENTS = 0x02,
191     PMU_PWR_GET_WAKEUP_EVENTS  = 0x03,
192     PMU_PWR_SET_WAKEUP_EVENTS  = 0x04,
193     PMU_PWR_CLR_WAKEUP_EVENTS  = 0x05,
194 };
195 
196 /* Power events wakeup bits */
197 enum {
198     PMU_PWR_WAKEUP_KEY       = 0x01,  /* Wake on key press */
199     PMU_PWR_WAKEUP_AC_INSERT = 0x02,  /* Wake on AC adapter plug */
200     PMU_PWR_WAKEUP_AC_CHANGE = 0x04,
201     PMU_PWR_WAKEUP_LID_OPEN  = 0x08,
202     PMU_PWR_WAKEUP_RING      = 0x10,
203 };
204 
pmu_readb(pmu_t * dev,int reg)205 static uint8_t pmu_readb(pmu_t *dev, int reg)
206 {
207     return *(volatile uint8_t *)(dev->base + reg);
208     asm volatile("eieio" : : : "memory");
209 }
210 
pmu_writeb(pmu_t * dev,int reg,uint8_t val)211 static void pmu_writeb(pmu_t *dev, int reg, uint8_t val)
212 {
213     *(volatile uint8_t *)(dev->base + reg) = val;
214     asm volatile("eieio" : : : "memory");
215 }
216 
pmu_handshake(pmu_t * dev)217 static void pmu_handshake(pmu_t *dev)
218 {
219     pmu_writeb(dev, B, pmu_readb(dev, B) & ~TREQ);
220     while ((pmu_readb(dev, B) & TACK) != 0);
221 
222     pmu_writeb(dev, B, pmu_readb(dev, B) | TREQ);
223     while ((pmu_readb(dev, B) & TACK) == 0);
224 }
225 
pmu_send_byte(pmu_t * dev,uint8_t val)226 static void pmu_send_byte(pmu_t *dev, uint8_t val)
227 {
228     pmu_writeb(dev, ACR, pmu_readb(dev, ACR) | SR_OUT | SR_EXT);
229     pmu_writeb(dev, SR, val);
230     pmu_handshake(dev);
231 }
232 
pmu_recv_byte(pmu_t * dev)233 static uint8_t pmu_recv_byte(pmu_t *dev)
234 {
235     pmu_writeb(dev, ACR, (pmu_readb(dev, ACR) & ~SR_OUT) | SR_EXT);
236     pmu_readb(dev, SR);
237     pmu_handshake(dev);
238 
239     return pmu_readb(dev, SR);
240 }
241 
pmu_request(pmu_t * dev,uint8_t cmd,uint8_t in_len,uint8_t * in_data,uint8_t * out_len,uint8_t * out_data)242 int pmu_request(pmu_t *dev, uint8_t cmd,
243                 uint8_t in_len, uint8_t *in_data,
244                 uint8_t *out_len, uint8_t *out_data)
245 {
246     int i, l, out_sz;
247     uint8_t d;
248 
249     /* Check command data size */
250     l = pmu_data_len[cmd][0];
251     if (l >= 0 && in_len != l) {
252         printk("PMU: Error, request %02x wants %d args, got %d\n",
253                cmd, l, in_len);
254         return -1;
255     }
256 
257     /* Make sure PMU is idle */
258     while ((pmu_readb(dev, B) & TACK) == 0);
259 
260     /* Send command */
261     pmu_send_byte(dev, cmd);
262 
263     /* Optionally send data length */
264     if (l < 0) {
265         pmu_send_byte(dev, in_len);
266         /* Send data */
267     }
268 
269     for (i = 0; i < in_len; i++) {
270         pmu_send_byte(dev, in_data[i]);
271     }
272 
273     /* Check response size */
274     l = pmu_data_len[cmd][1];
275     if (l < 0) {
276         l = pmu_recv_byte(dev);
277     }
278 
279     if (out_len) {
280         out_sz = *out_len;
281         *out_len = 0;
282     } else {
283         out_sz = 0;
284     }
285 
286     if (l > out_sz) {
287         printk("PMU: Error, request %02x returns %d bytes"
288                ", room for %d\n", cmd, l, out_sz);
289     }
290 
291     for (i = 0; i < l; i++) {
292         d = pmu_recv_byte(dev);
293         if (i < out_sz) {
294             out_data[i] = d;
295             (*out_len)++;
296         }
297     }
298 
299     return 0;
300 }
301 
302 #define MAX_REQ_SIZE     128
303 
304 #ifdef CONFIG_DRIVER_ADB
pmu_adb_req(void * host,const uint8_t * snd_buf,int len,uint8_t * rcv_buf)305 static int pmu_adb_req(void *host, const uint8_t *snd_buf, int len,
306                        uint8_t *rcv_buf)
307 {
308     uint8_t buffer[MAX_REQ_SIZE], *pos, olen;
309     int rc;
310 
311     PMU_DPRINTF("pmu_adb_req: len=%d: %02x %02x %02x...\n",
312                 len, snd_buf[0], snd_buf[1], snd_buf[2]);
313 
314     if (len >= (MAX_REQ_SIZE - 1)) {
315         printk("pmu_adb_req: too big ! (%d)\n", len);
316         return -1;
317     }
318 
319     buffer[0] = snd_buf[0];
320     buffer[1] = 0; /* We don't do autopoll */
321     buffer[2] = len - 1;
322 
323     if (len > 1) {
324         memcpy(&buffer[3], &snd_buf[1], len - 1);
325     }
326     rc = pmu_request(host, PMU_ADB_CMD, len + 2, buffer, NULL, NULL);
327     if (rc) {
328         printk("PMU adb request failure %d\n", rc);
329         return 0;
330     }
331     olen = MAX_REQ_SIZE;
332     rc = pmu_request(host, PMU_INT_ACK, 0, NULL, &olen, buffer);
333     if (rc) {
334         printk("PMU intack request failure %d\n", rc);
335         return 0;
336     }
337     PMU_DPRINTF("pmu_resp=%d int=0x%02x\n", olen, buffer[0]);
338     if (olen <= 2) {
339         return 0;
340     } else {
341         pos = &buffer[3];
342         olen -= 3;
343         PMU_DPRINTF("ADB resp: 0x%02x 0x%02x\n", buffer[3], buffer[4]);
344     }
345     memcpy(rcv_buf, pos, olen);
346 
347     return olen;
348 }
349 #endif
350 
351 DECLARE_UNNAMED_NODE(ob_pmu, INSTALL_OPEN, sizeof(int));
352 
353 static pmu_t *main_pmu;
354 
pmu_reset_all(void)355 static void pmu_reset_all(void)
356 {
357     pmu_request(main_pmu, PMU_RESET, 0, NULL, NULL, NULL);
358 }
359 
pmu_poweroff(void)360 static void pmu_poweroff(void)
361 {
362     uint8_t params[] = "MATT";
363 
364     pmu_request(main_pmu, PMU_SHUTDOWN, 4, params, NULL, NULL);
365 }
366 
ob_pmu_initialize(int * idx)367 static void ob_pmu_initialize (int *idx)
368 {
369     phandle_t ph=get_cur_dev();
370     int props[2];
371 
372     push_str("via-pmu");
373     fword("device-type");
374 
375     set_int_property(ph, "#address-cells", 1);
376     set_int_property(ph, "#size-cells", 0);
377     set_property(ph, "compatible", "pmu", 4);
378 
379     props[0] = __cpu_to_be32(IO_PMU_OFFSET);
380     props[1] = __cpu_to_be32(IO_PMU_SIZE);
381     set_property(ph, "reg", (char *)&props, sizeof(props));
382 
383     /* On newworld machines the PMU is on interrupt 0x19 */
384     props[0] = 0x19;
385     props[1] = 1;
386     set_property(ph, "interrupts", (char *)props, sizeof(props));
387     set_int_property(ph, "pmu-version", 0xd0330c);
388 
389     bind_func("pmu-reset-all", pmu_reset_all);
390     feval("['] pmu-reset-all to reset-all");
391 }
392 
ob_pmu_open(int * idx)393 static void ob_pmu_open(int *idx)
394 {
395     RET(-1);
396 }
397 
ob_pmu_close(int * idx)398 static void ob_pmu_close(int *idx)
399 {
400 }
401 
402 NODE_METHODS(ob_pmu) = {
403     { NULL,        ob_pmu_initialize },
404     { "open",      ob_pmu_open },
405     { "close",     ob_pmu_close },
406 };
407 
408 DECLARE_UNNAMED_NODE(rtc, INSTALL_OPEN, sizeof(int));
409 
rtc_open(int * idx)410 static void rtc_open(int *idx)
411 {
412     RET(-1);
413 }
414 
415 /*
416  * get-time ( -- second minute hour day month year )
417  *
418  */
419 
420 static const int days_month[12] =
421     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
422 static const int days_month_leap[12] =
423     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
424 
is_leap(int year)425 static inline int is_leap(int year)
426 {
427     return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
428 }
429 
rtc_get_time(int * idx)430 static void rtc_get_time(int *idx)
431 {
432     uint8_t obuf[4], olen;
433     ucell second, minute, hour, day, month, year;
434     uint32_t now;
435     int current;
436     const int *days;
437 
438     olen = 4;
439     pmu_request(main_pmu, PMU_READ_RTC, 0, NULL, &olen, obuf);
440 
441     /* seconds since 01/01/1904 */
442     now = (obuf[0] << 24) + (obuf[1] << 16) + (obuf[2] << 8) + obuf[3];
443 
444     second =  now % 60;
445     now /= 60;
446 
447     minute = now % 60;
448     now /= 60;
449 
450     hour = now % 24;
451     now /= 24;
452 
453     year = now * 100 / 36525;
454     now -= year * 36525 / 100;
455     year += 1904;
456 
457     days = is_leap(year) ?  days_month_leap : days_month;
458 
459     current = 0;
460     month = 0;
461     while (month < 12) {
462         if (now <= current + days[month]) {
463             break;
464         }
465 
466         current += days[month];
467         month++;
468     }
469     month++;
470 
471     day = now - current;
472 
473     PUSH(second);
474     PUSH(minute);
475     PUSH(hour);
476     PUSH(day);
477     PUSH(month);
478     PUSH(year);
479 }
480 
481 /*
482  * set-time ( second minute hour day month year -- )
483  *
484  */
485 
rtc_set_time(int * idx)486 static  void rtc_set_time(int *idx)
487 {
488     uint8_t ibuf[4];
489     ucell second, minute, hour, day, month, year;
490     const int *days;
491     uint32_t now;
492     unsigned int nb_days;
493     int i;
494 
495     year = POP();
496     month = POP();
497     day = POP();
498     hour = POP();
499     minute = POP();
500     second = POP();
501 
502     days = is_leap(year) ?  days_month_leap : days_month;
503     nb_days = (year - 1904) * 36525 / 100 + day;
504     for (i = 0; i < month - 1; i++) {
505         nb_days += days[i];
506     }
507 
508     now = (((nb_days * 24) + hour) * 60 + minute) * 60 + second;
509 
510     ibuf[0] = now >> 24;
511     ibuf[1] = now >> 16;
512     ibuf[2] = now >> 8;
513     ibuf[3] = now;
514     pmu_request(main_pmu, PMU_SET_RTC, 4, ibuf, NULL, NULL);
515 }
516 
517 NODE_METHODS(rtc) = {
518     { "open",      rtc_open },
519     { "get-time",  rtc_get_time },
520     { "set-time",  rtc_set_time },
521 };
522 
rtc_init(char * path)523 static void rtc_init(char *path)
524 {
525     phandle_t ph, aliases;
526     char buf[64];
527 
528     snprintf(buf, sizeof(buf), "%s/rtc", path);
529     REGISTER_NAMED_NODE(rtc, buf);
530 
531     ph = find_dev(buf);
532     set_property(ph, "device_type", "rtc", 4);
533     set_property(ph, "compatible", "rtc,via-pmu", 12);
534 
535     aliases = find_dev("/aliases");
536     set_property(aliases, "rtc", buf, strlen(buf) + 1);
537     device_end();
538 }
539 
powermgt_init(char * path)540 static void powermgt_init(char *path)
541 {
542     phandle_t ph;
543     char buf[64];
544 
545     /* This is a bunch of magic "Feature" bits for which we only have
546      * partial definitions from Darwin. These are taken from a
547      * PowerMac3,1 device-tree. They are also identical in a
548      * PowerMac5,1 "Cube". Note that more recent machines such as
549      * the MacMini (PowerMac10,1) do not have this property, however
550      * MacOS 9 seems to require it (it hangs during boot otherwise).
551      */
552     const char prim[] = { 0x00, 0x00, 0x00, 0xff,
553                           0x00, 0x00, 0x00, 0x2c,
554                           0x00, 0x03, 0x0d, 0x40,
555                           /* Public PM features */
556                           /* 0x00000001 : Wake timer supported */
557                           /* 0x00000004 : Processor cycling supported */
558                           /* 0x00000100 : Can wake on modem ring */
559                           /* 0x00000200 : Has monitor dimming support */
560                           /* 0x00000400 : Can program startup timer */
561                           /* 0x00002000 : Supports wake on LAN */
562                           /* 0x00004000 : Can wake on LID/case open */
563                           /* 0x00008000 : Can power off PCI on sleep */
564                           /* 0x00010000 : Supports deep sleep */
565                           0x00, 0x01, 0xe7, 0x05,
566                           /* Private PM features */
567                           /* 0x00000400 : Supports ICT control */
568                           /* 0x00001000 : Supports Idle2 in hardware */
569                           /* 0x00002000 : Open case prevents sleep */
570                           0x00, 0x00, 0x34, 0x00,
571                           0x00, 0x00, 0x00, 0x00,
572                           0x00, 0x00, /* # of batteries supported */
573                           0x26, 0x0d,
574                           0x46, 0x00, 0x02, 0x78,
575                           0x78, 0x3c, 0x00 };
576 
577     snprintf(buf, sizeof(buf), "%s/power-mgt", path);
578     REGISTER_NAMED_NODE(rtc, buf); // XXX ?
579 
580     ph = find_dev(buf);
581     set_property(ph, "device_type", "power-mgt", 10);
582     set_property(ph, "compatible", "via-pmu-99", 11);
583     set_property(ph, "registry-name", "extint-gpio1", 13);
584     set_property(ph, "prim-info", prim, sizeof(prim));
585     device_end();
586 }
587 
pmu_init(const char * path,phys_addr_t base)588 pmu_t *pmu_init(const char *path, phys_addr_t base)
589 {
590     pmu_t *pmu;
591     char buf[64];
592     phandle_t aliases;
593 
594     base += IO_PMU_OFFSET;
595     PMU_DPRINTF(" base=" FMT_plx "\n", base);
596 
597     pmu = malloc(sizeof(pmu_t));
598     if (pmu == NULL) {
599         return NULL;
600     }
601 
602     snprintf(buf, sizeof(buf), "%s/via-pmu", path);
603     REGISTER_NAMED_NODE(ob_pmu, buf);
604 
605     aliases = find_dev("/aliases");
606     set_property(aliases, "via-pmu", buf, strlen(buf) + 1);
607     pmu->base = base;
608 
609 #ifdef CONFIG_DRIVER_ADB
610     if (has_adb()) {
611        pmu->adb_bus = adb_bus_new(pmu, &pmu_adb_req);
612        adb_bus_init(buf, pmu->adb_bus);
613     }
614 #endif
615 
616     rtc_init(buf);
617     powermgt_init(buf);
618 
619     main_pmu = pmu;
620 
621     device_end();
622     bind_func("poweroff", pmu_poweroff);
623 
624     return pmu;
625 }
626