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