]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/powerpc/powermac/smu.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / powerpc / powermac / smu.c
1 /*-
2  * Copyright (c) 2009 Nathan Whitehorn
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/systm.h>
34 #include <sys/module.h>
35 #include <sys/conf.h>
36 #include <sys/cpu.h>
37 #include <sys/clock.h>
38 #include <sys/ctype.h>
39 #include <sys/kernel.h>
40 #include <sys/kthread.h>
41 #include <sys/reboot.h>
42 #include <sys/rman.h>
43 #include <sys/sysctl.h>
44 #include <sys/unistd.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr_machdep.h>
48 #include <machine/md_var.h>
49
50 #include <dev/iicbus/iicbus.h>
51 #include <dev/iicbus/iiconf.h>
52 #include <dev/led/led.h>
53 #include <dev/ofw/openfirm.h>
54 #include <dev/ofw/ofw_bus.h>
55 #include <dev/ofw/ofw_bus_subr.h>
56 #include <powerpc/powermac/macgpiovar.h>
57 #include <powerpc/powermac/powermac_thermal.h>
58
59 #include "clock_if.h"
60 #include "iicbus_if.h"
61
62 struct smu_cmd {
63         volatile uint8_t cmd;
64         uint8_t         len;
65         uint8_t         data[254];
66
67         STAILQ_ENTRY(smu_cmd) cmd_q;
68 };
69
70 STAILQ_HEAD(smu_cmdq, smu_cmd);
71
72 struct smu_fan {
73         struct pmac_fan fan;
74         device_t dev;
75         cell_t  reg;
76
77         enum {
78                 SMU_FAN_RPM,
79                 SMU_FAN_PWM
80         } type;
81         int     setpoint;
82         int     old_style;
83         int     rpm;
84 };
85
86 /* We can read the PWM and the RPM from a PWM controlled fan.
87  * Offer both values via sysctl.
88  */
89 enum {
90         SMU_PWM_SYSCTL_PWM   = 1 << 8,
91         SMU_PWM_SYSCTL_RPM   = 2 << 8
92 };
93
94 struct smu_sensor {
95         struct pmac_therm therm;
96         device_t dev;
97
98         cell_t  reg;
99         enum {
100                 SMU_CURRENT_SENSOR,
101                 SMU_VOLTAGE_SENSOR,
102                 SMU_POWER_SENSOR,
103                 SMU_TEMP_SENSOR
104         } type;
105 };
106
107 struct smu_softc {
108         device_t        sc_dev;
109         struct mtx      sc_mtx;
110
111         struct resource *sc_memr;
112         int             sc_memrid;
113         int             sc_u3;
114
115         bus_dma_tag_t   sc_dmatag;
116         bus_space_tag_t sc_bt;
117         bus_space_handle_t sc_mailbox;
118
119         struct smu_cmd  *sc_cmd, *sc_cur_cmd;
120         bus_addr_t      sc_cmd_phys;
121         bus_dmamap_t    sc_cmd_dmamap;
122         struct smu_cmdq sc_cmdq;
123
124         struct smu_fan  *sc_fans;
125         int             sc_nfans;
126         int             old_style_fans;
127         struct smu_sensor *sc_sensors;
128         int             sc_nsensors;
129
130         int             sc_doorbellirqid;
131         struct resource *sc_doorbellirq;
132         void            *sc_doorbellirqcookie;
133
134         struct proc     *sc_fanmgt_proc;
135         time_t          sc_lastuserchange;
136
137         /* Calibration data */
138         uint16_t        sc_cpu_diode_scale;
139         int16_t         sc_cpu_diode_offset;
140
141         uint16_t        sc_cpu_volt_scale;
142         int16_t         sc_cpu_volt_offset;
143         uint16_t        sc_cpu_curr_scale;
144         int16_t         sc_cpu_curr_offset;
145
146         uint16_t        sc_slots_pow_scale;
147         int16_t         sc_slots_pow_offset;
148
149         struct cdev     *sc_leddev;
150 };
151
152 /* regular bus attachment functions */
153
154 static int      smu_probe(device_t);
155 static int      smu_attach(device_t);
156 static const struct ofw_bus_devinfo *
157     smu_get_devinfo(device_t bus, device_t dev);
158
159 /* cpufreq notification hooks */
160
161 static void     smu_cpufreq_pre_change(device_t, const struct cf_level *level);
162 static void     smu_cpufreq_post_change(device_t, const struct cf_level *level);
163
164 /* clock interface */
165 static int      smu_gettime(device_t dev, struct timespec *ts);
166 static int      smu_settime(device_t dev, struct timespec *ts);
167
168 /* utility functions */
169 static int      smu_run_cmd(device_t dev, struct smu_cmd *cmd, int wait);
170 static int      smu_get_datablock(device_t dev, int8_t id, uint8_t *buf,
171                     size_t len);
172 static void     smu_attach_i2c(device_t dev, phandle_t i2croot);
173 static void     smu_attach_fans(device_t dev, phandle_t fanroot);
174 static void     smu_attach_sensors(device_t dev, phandle_t sensroot);
175 static void     smu_set_sleepled(void *xdev, int onoff);
176 static int      smu_server_mode(SYSCTL_HANDLER_ARGS);
177 static void     smu_doorbell_intr(void *xdev);
178 static void     smu_shutdown(void *xdev, int howto);
179
180 /* where to find the doorbell GPIO */
181
182 static device_t smu_doorbell = NULL;
183
184 static device_method_t  smu_methods[] = {
185         /* Device interface */
186         DEVMETHOD(device_probe,         smu_probe),
187         DEVMETHOD(device_attach,        smu_attach),
188
189         /* Clock interface */
190         DEVMETHOD(clock_gettime,        smu_gettime),
191         DEVMETHOD(clock_settime,        smu_settime),
192
193         /* ofw_bus interface */
194         DEVMETHOD(bus_child_pnpinfo_str,ofw_bus_gen_child_pnpinfo_str),
195         DEVMETHOD(ofw_bus_get_devinfo,  smu_get_devinfo),
196         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
197         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
198         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
199         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
200         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
201
202         { 0, 0 },
203 };
204
205 static driver_t smu_driver = {
206         "smu",
207         smu_methods,
208         sizeof(struct smu_softc)
209 };
210
211 static devclass_t smu_devclass;
212
213 DRIVER_MODULE(smu, nexus, smu_driver, smu_devclass, 0, 0);
214 static MALLOC_DEFINE(M_SMU, "smu", "SMU Sensor Information");
215
216 #define SMU_MAILBOX             0x8000860c
217 #define SMU_FANMGT_INTERVAL     1000 /* ms */
218
219 /* Command types */
220 #define SMU_ADC                 0xd8
221 #define SMU_FAN                 0x4a
222 #define SMU_RPM_STATUS          0x01
223 #define SMU_RPM_SETPOINT        0x02
224 #define SMU_PWM_STATUS          0x11
225 #define SMU_PWM_SETPOINT        0x12
226 #define SMU_I2C                 0x9a
227 #define  SMU_I2C_SIMPLE         0x00
228 #define  SMU_I2C_NORMAL         0x01
229 #define  SMU_I2C_COMBINED       0x02
230 #define SMU_MISC                0xee
231 #define  SMU_MISC_GET_DATA      0x02
232 #define  SMU_MISC_LED_CTRL      0x04
233 #define SMU_POWER               0xaa
234 #define SMU_POWER_EVENTS        0x8f
235 #define  SMU_PWR_GET_POWERUP    0x00
236 #define  SMU_PWR_SET_POWERUP    0x01
237 #define  SMU_PWR_CLR_POWERUP    0x02
238 #define SMU_RTC                 0x8e
239 #define  SMU_RTC_GET            0x81
240 #define  SMU_RTC_SET            0x80
241
242 /* Power event types */
243 #define SMU_WAKEUP_KEYPRESS     0x01
244 #define SMU_WAKEUP_AC_INSERT    0x02
245 #define SMU_WAKEUP_AC_CHANGE    0x04
246 #define SMU_WAKEUP_RING         0x10
247
248 /* Data blocks */
249 #define SMU_CPUTEMP_CAL         0x18
250 #define SMU_CPUVOLT_CAL         0x21
251 #define SMU_SLOTPW_CAL          0x78
252
253 /* Partitions */
254 #define SMU_PARTITION           0x3e
255 #define SMU_PARTITION_LATEST    0x01
256 #define SMU_PARTITION_BASE      0x02
257 #define SMU_PARTITION_UPDATE    0x03
258
259 static int
260 smu_probe(device_t dev)
261 {
262         const char *name = ofw_bus_get_name(dev);
263
264         if (strcmp(name, "smu") != 0)
265                 return (ENXIO);
266
267         device_set_desc(dev, "Apple System Management Unit");
268         return (0);
269 }
270
271 static void
272 smu_phys_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
273 {
274         struct smu_softc *sc = xsc;
275
276         sc->sc_cmd_phys = segs[0].ds_addr;
277 }
278
279 static int
280 smu_attach(device_t dev)
281 {
282         struct smu_softc *sc;
283         phandle_t       node, child;
284         uint8_t         data[12];
285
286         sc = device_get_softc(dev);
287
288         mtx_init(&sc->sc_mtx, "smu", NULL, MTX_DEF);
289         sc->sc_cur_cmd = NULL;
290         sc->sc_doorbellirqid = -1;
291
292         sc->sc_u3 = 0;
293         if (OF_finddevice("/u3") != -1)
294                 sc->sc_u3 = 1;
295
296         /*
297          * Map the mailbox area. This should be determined from firmware,
298          * but I have not found a simple way to do that.
299          */
300         bus_dma_tag_create(NULL, 16, 0, BUS_SPACE_MAXADDR_32BIT,
301             BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 1, PAGE_SIZE, 0, NULL,
302             NULL, &(sc->sc_dmatag));
303         sc->sc_bt = &bs_le_tag;
304         bus_space_map(sc->sc_bt, SMU_MAILBOX, 4, 0, &sc->sc_mailbox);
305
306         /*
307          * Allocate the command buffer. This can be anywhere in the low 4 GB
308          * of memory.
309          */
310         bus_dmamem_alloc(sc->sc_dmatag, (void **)&sc->sc_cmd, BUS_DMA_WAITOK | 
311             BUS_DMA_ZERO, &sc->sc_cmd_dmamap);
312         bus_dmamap_load(sc->sc_dmatag, sc->sc_cmd_dmamap,
313             sc->sc_cmd, PAGE_SIZE, smu_phys_callback, sc, 0);
314         STAILQ_INIT(&sc->sc_cmdq);
315
316         /*
317          * Set up handlers to change CPU voltage when CPU frequency is changed.
318          */
319         EVENTHANDLER_REGISTER(cpufreq_pre_change, smu_cpufreq_pre_change, dev,
320             EVENTHANDLER_PRI_ANY);
321         EVENTHANDLER_REGISTER(cpufreq_post_change, smu_cpufreq_post_change, dev,
322             EVENTHANDLER_PRI_ANY);
323
324         node = ofw_bus_get_node(dev);
325
326         /* Some SMUs have RPM and PWM controlled fans which do not sit
327          * under the same node. So we have to attach them separately.
328          */
329         smu_attach_fans(dev, node);
330
331         /*
332          * Now detect and attach the other child devices.
333          */
334         for (child = OF_child(node); child != 0; child = OF_peer(child)) {
335                 char name[32];
336                 memset(name, 0, sizeof(name));
337                 OF_getprop(child, "name", name, sizeof(name));
338
339                 if (strncmp(name, "sensors", 8) == 0)
340                         smu_attach_sensors(dev, child);
341
342                 if (strncmp(name, "smu-i2c-control", 15) == 0)
343                         smu_attach_i2c(dev, child);
344         }
345
346         /* Some SMUs have the I2C children directly under the bus. */
347         smu_attach_i2c(dev, node);
348
349         /*
350          * Collect calibration constants.
351          */
352         smu_get_datablock(dev, SMU_CPUTEMP_CAL, data, sizeof(data));
353         sc->sc_cpu_diode_scale = (data[4] << 8) + data[5];
354         sc->sc_cpu_diode_offset = (data[6] << 8) + data[7];
355
356         smu_get_datablock(dev, SMU_CPUVOLT_CAL, data, sizeof(data));
357         sc->sc_cpu_volt_scale = (data[4] << 8) + data[5];
358         sc->sc_cpu_volt_offset = (data[6] << 8) + data[7];
359         sc->sc_cpu_curr_scale = (data[8] << 8) + data[9];
360         sc->sc_cpu_curr_offset = (data[10] << 8) + data[11];
361
362         smu_get_datablock(dev, SMU_SLOTPW_CAL, data, sizeof(data));
363         sc->sc_slots_pow_scale = (data[4] << 8) + data[5];
364         sc->sc_slots_pow_offset = (data[6] << 8) + data[7];
365
366         /*
367          * Set up LED interface
368          */
369         sc->sc_leddev = led_create(smu_set_sleepled, dev, "sleepled");
370
371         /*
372          * Reset on power loss behavior
373          */
374
375         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
376             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
377             "server_mode", CTLTYPE_INT | CTLFLAG_RW, dev, 0,
378             smu_server_mode, "I", "Enable reboot after power failure");
379
380         /*
381          * Set up doorbell interrupt.
382          */
383         sc->sc_doorbellirqid = 0;
384         sc->sc_doorbellirq = bus_alloc_resource_any(smu_doorbell, SYS_RES_IRQ,
385             &sc->sc_doorbellirqid, RF_ACTIVE);
386         bus_setup_intr(smu_doorbell, sc->sc_doorbellirq,
387             INTR_TYPE_MISC | INTR_MPSAFE, NULL, smu_doorbell_intr, dev,
388             &sc->sc_doorbellirqcookie);
389         powerpc_config_intr(rman_get_start(sc->sc_doorbellirq),
390             INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
391
392         /*
393          * Connect RTC interface.
394          */
395         clock_register(dev, 1000);
396
397         /*
398          * Learn about shutdown events
399          */
400         EVENTHANDLER_REGISTER(shutdown_final, smu_shutdown, dev,
401             SHUTDOWN_PRI_LAST);
402
403         return (bus_generic_attach(dev));
404 }
405
406 static const struct ofw_bus_devinfo *
407 smu_get_devinfo(device_t bus, device_t dev)
408 {
409
410         return (device_get_ivars(dev));
411 }
412
413 static void
414 smu_send_cmd(device_t dev, struct smu_cmd *cmd)
415 {
416         struct smu_softc *sc;
417
418         sc = device_get_softc(dev);
419
420         mtx_assert(&sc->sc_mtx, MA_OWNED);
421
422         if (sc->sc_u3)
423                 powerpc_pow_enabled = 0; /* SMU cannot work if we go to NAP */
424
425         sc->sc_cur_cmd = cmd;
426
427         /* Copy the command to the mailbox */
428         sc->sc_cmd->cmd = cmd->cmd;
429         sc->sc_cmd->len = cmd->len;
430         memcpy(sc->sc_cmd->data, cmd->data, sizeof(cmd->data));
431         bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_PREWRITE);
432         bus_space_write_4(sc->sc_bt, sc->sc_mailbox, 0, sc->sc_cmd_phys);
433
434         /* Flush the cacheline it is in -- SMU bypasses the cache */
435         __asm __volatile("sync; dcbf 0,%0; sync" :: "r"(sc->sc_cmd): "memory");
436
437         /* Ring SMU doorbell */
438         macgpio_write(smu_doorbell, GPIO_DDR_OUTPUT);
439 }
440
441 static void
442 smu_doorbell_intr(void *xdev)
443 {
444         device_t smu;
445         struct smu_softc *sc;
446         int doorbell_ack;
447
448         smu = xdev;
449         doorbell_ack = macgpio_read(smu_doorbell);
450         sc = device_get_softc(smu);
451
452         if (doorbell_ack != (GPIO_DDR_OUTPUT | GPIO_LEVEL_RO | GPIO_DATA)) 
453                 return;
454
455         mtx_lock(&sc->sc_mtx);
456
457         if (sc->sc_cur_cmd == NULL)     /* spurious */
458                 goto done;
459
460         /* Check result. First invalidate the cache again... */
461         __asm __volatile("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
462         
463         bus_dmamap_sync(sc->sc_dmatag, sc->sc_cmd_dmamap, BUS_DMASYNC_POSTREAD);
464
465         sc->sc_cur_cmd->cmd = sc->sc_cmd->cmd;
466         sc->sc_cur_cmd->len = sc->sc_cmd->len;
467         memcpy(sc->sc_cur_cmd->data, sc->sc_cmd->data,
468             sizeof(sc->sc_cmd->data));
469         wakeup(sc->sc_cur_cmd);
470         sc->sc_cur_cmd = NULL;
471         if (sc->sc_u3)
472                 powerpc_pow_enabled = 1;
473
474     done:
475         /* Queue next command if one is pending */
476         if (STAILQ_FIRST(&sc->sc_cmdq) != NULL) {
477                 sc->sc_cur_cmd = STAILQ_FIRST(&sc->sc_cmdq);
478                 STAILQ_REMOVE_HEAD(&sc->sc_cmdq, cmd_q);
479                 smu_send_cmd(smu, sc->sc_cur_cmd);
480         }
481
482         mtx_unlock(&sc->sc_mtx);
483 }
484
485 static int
486 smu_run_cmd(device_t dev, struct smu_cmd *cmd, int wait)
487 {
488         struct smu_softc *sc;
489         uint8_t cmd_code;
490         int error;
491
492         sc = device_get_softc(dev);
493         cmd_code = cmd->cmd;
494
495         mtx_lock(&sc->sc_mtx);
496         if (sc->sc_cur_cmd != NULL) {
497                 STAILQ_INSERT_TAIL(&sc->sc_cmdq, cmd, cmd_q);
498         } else
499                 smu_send_cmd(dev, cmd);
500         mtx_unlock(&sc->sc_mtx);
501
502         if (!wait)
503                 return (0);
504
505         if (sc->sc_doorbellirqid < 0) {
506                 /* Poll if the IRQ has not been set up yet */
507                 do {
508                         DELAY(50);
509                         smu_doorbell_intr(dev);
510                 } while (sc->sc_cur_cmd != NULL);
511         } else {
512                 /* smu_doorbell_intr will wake us when the command is ACK'ed */
513                 error = tsleep(cmd, 0, "smu", 800 * hz / 1000);
514                 if (error != 0)
515                         smu_doorbell_intr(dev); /* One last chance */
516                 
517                 if (error != 0) {
518                     mtx_lock(&sc->sc_mtx);
519                     if (cmd->cmd == cmd_code) { /* Never processed */
520                         /* Abort this command if we timed out */
521                         if (sc->sc_cur_cmd == cmd)
522                                 sc->sc_cur_cmd = NULL;
523                         else
524                                 STAILQ_REMOVE(&sc->sc_cmdq, cmd, smu_cmd,
525                                     cmd_q);
526                         mtx_unlock(&sc->sc_mtx);
527                         return (error);
528                     }
529                     error = 0;
530                     mtx_unlock(&sc->sc_mtx);
531                 }
532         }
533
534         /* SMU acks the command by inverting the command bits */
535         if (cmd->cmd == ((~cmd_code) & 0xff))
536                 error = 0;
537         else
538                 error = EIO;
539
540         return (error);
541 }
542
543 static int
544 smu_get_datablock(device_t dev, int8_t id, uint8_t *buf, size_t len)
545 {
546         struct smu_cmd cmd;
547         uint8_t addr[4];
548
549         cmd.cmd = SMU_PARTITION;
550         cmd.len = 2;
551         cmd.data[0] = SMU_PARTITION_LATEST;
552         cmd.data[1] = id; 
553
554         smu_run_cmd(dev, &cmd, 1);
555
556         addr[0] = addr[1] = 0;
557         addr[2] = cmd.data[0];
558         addr[3] = cmd.data[1];
559
560         cmd.cmd = SMU_MISC;
561         cmd.len = 7;
562         cmd.data[0] = SMU_MISC_GET_DATA;
563         cmd.data[1] = sizeof(addr);
564         memcpy(&cmd.data[2], addr, sizeof(addr));
565         cmd.data[6] = len;
566
567         smu_run_cmd(dev, &cmd, 1);
568         memcpy(buf, cmd.data, len);
569         return (0);
570 }
571
572 static void
573 smu_slew_cpu_voltage(device_t dev, int to)
574 {
575         struct smu_cmd cmd;
576
577         cmd.cmd = SMU_POWER;
578         cmd.len = 8;
579         cmd.data[0] = 'V';
580         cmd.data[1] = 'S'; 
581         cmd.data[2] = 'L'; 
582         cmd.data[3] = 'E'; 
583         cmd.data[4] = 'W'; 
584         cmd.data[5] = 0xff;
585         cmd.data[6] = 1;
586         cmd.data[7] = to;
587
588         smu_run_cmd(dev, &cmd, 1);
589 }
590
591 static void
592 smu_cpufreq_pre_change(device_t dev, const struct cf_level *level)
593 {
594         /*
595          * Make sure the CPU voltage is raised before we raise
596          * the clock.
597          */
598                 
599         if (level->rel_set[0].freq == 10000 /* max */)
600                 smu_slew_cpu_voltage(dev, 0);
601 }
602
603 static void
604 smu_cpufreq_post_change(device_t dev, const struct cf_level *level)
605 {
606         /* We are safe to reduce CPU voltage after a downward transition */
607
608         if (level->rel_set[0].freq < 10000 /* max */)
609                 smu_slew_cpu_voltage(dev, 1); /* XXX: 1/4 voltage for 970MP? */
610 }
611
612 /* Routines for probing the SMU doorbell GPIO */
613 static int doorbell_probe(device_t dev);
614 static int doorbell_attach(device_t dev);
615
616 static device_method_t  doorbell_methods[] = {
617         /* Device interface */
618         DEVMETHOD(device_probe,         doorbell_probe),
619         DEVMETHOD(device_attach,        doorbell_attach),
620         { 0, 0 },
621 };
622
623 static driver_t doorbell_driver = {
624         "smudoorbell",
625         doorbell_methods,
626         0
627 };
628
629 static devclass_t doorbell_devclass;
630
631 DRIVER_MODULE(smudoorbell, macgpio, doorbell_driver, doorbell_devclass, 0, 0);
632
633 static int
634 doorbell_probe(device_t dev)
635 {
636         const char *name = ofw_bus_get_name(dev);
637
638         if (strcmp(name, "smu-doorbell") != 0)
639                 return (ENXIO);
640
641         device_set_desc(dev, "SMU Doorbell GPIO");
642         device_quiet(dev);
643         return (0);
644 }
645
646 static int
647 doorbell_attach(device_t dev)
648 {
649         smu_doorbell = dev;
650         return (0);
651 }
652
653 /*
654  * Sensor and fan management
655  */
656
657 static int
658 smu_fan_check_old_style(struct smu_fan *fan)
659 {
660         device_t smu = fan->dev;
661         struct smu_softc *sc = device_get_softc(smu);
662         struct smu_cmd cmd;
663         int error;
664
665         if (sc->old_style_fans != -1)
666                 return (sc->old_style_fans);
667
668         /*
669          * Apple has two fan control mechanisms. We can't distinguish
670          * them except by seeing if the new one fails. If the new one
671          * fails, use the old one.
672          */
673         
674         cmd.cmd = SMU_FAN;
675         cmd.len = 2;
676         cmd.data[0] = 0x31;
677         cmd.data[1] = fan->reg;
678
679         do {
680                 error = smu_run_cmd(smu, &cmd, 1);
681         } while (error == EWOULDBLOCK);
682
683         sc->old_style_fans = (error != 0);
684
685         return (sc->old_style_fans);
686 }
687
688 static int
689 smu_fan_set_rpm(struct smu_fan *fan, int rpm)
690 {
691         device_t smu = fan->dev;
692         struct smu_cmd cmd;
693         int error;
694
695         cmd.cmd = SMU_FAN;
696         error = EIO;
697
698         /* Clamp to allowed range */
699         rpm = max(fan->fan.min_rpm, rpm);
700         rpm = min(fan->fan.max_rpm, rpm);
701
702         smu_fan_check_old_style(fan);
703
704         if (!fan->old_style) {
705                 cmd.len = 4;
706                 cmd.data[0] = 0x30;
707                 cmd.data[1] = fan->reg;
708                 cmd.data[2] = (rpm >> 8) & 0xff;
709                 cmd.data[3] = rpm & 0xff;
710
711                 error = smu_run_cmd(smu, &cmd, 1);
712                 if (error && error != EWOULDBLOCK)
713                         fan->old_style = 1;
714         } else {
715                 cmd.len = 14;
716                 cmd.data[0] = 0x00; /* RPM fan. */
717                 cmd.data[1] = 1 << fan->reg;
718                 cmd.data[2 + 2*fan->reg] = (rpm >> 8) & 0xff;
719                 cmd.data[3 + 2*fan->reg] = rpm & 0xff;
720                 error = smu_run_cmd(smu, &cmd, 1);
721         }
722
723         if (error == 0)
724                 fan->setpoint = rpm;
725
726         return (error);
727 }
728
729 static int
730 smu_fan_read_rpm(struct smu_fan *fan)
731 {
732         device_t smu = fan->dev;
733         struct smu_cmd cmd;
734         int rpm, error;
735
736         smu_fan_check_old_style(fan);
737
738         if (!fan->old_style) {
739                 cmd.cmd = SMU_FAN;
740                 cmd.len = 2;
741                 cmd.data[0] = 0x31;
742                 cmd.data[1] = fan->reg;
743
744                 error = smu_run_cmd(smu, &cmd, 1);
745                 if (error && error != EWOULDBLOCK)
746                         fan->old_style = 1;
747
748                 rpm = (cmd.data[0] << 8) | cmd.data[1];
749         }
750
751         if (fan->old_style) {
752                 cmd.cmd = SMU_FAN;
753                 cmd.len = 1;
754                 cmd.data[0] = SMU_RPM_STATUS;
755
756                 error = smu_run_cmd(smu, &cmd, 1);
757                 if (error)
758                         return (error);
759
760                 rpm = (cmd.data[fan->reg*2+1] << 8) | cmd.data[fan->reg*2+2];
761         }
762
763         return (rpm);
764 }
765 static int
766 smu_fan_set_pwm(struct smu_fan *fan, int pwm)
767 {
768         device_t smu = fan->dev;
769         struct smu_cmd cmd;
770         int error;
771
772         cmd.cmd = SMU_FAN;
773         error = EIO;
774
775         /* Clamp to allowed range */
776         pwm = max(fan->fan.min_rpm, pwm);
777         pwm = min(fan->fan.max_rpm, pwm);
778
779         /*
780          * Apple has two fan control mechanisms. We can't distinguish
781          * them except by seeing if the new one fails. If the new one
782          * fails, use the old one.
783          */
784         
785         if (!fan->old_style) {
786                 cmd.len = 4;
787                 cmd.data[0] = 0x30;
788                 cmd.data[1] = fan->reg;
789                 cmd.data[2] = (pwm >> 8) & 0xff;
790                 cmd.data[3] = pwm & 0xff;
791         
792                 error = smu_run_cmd(smu, &cmd, 1);
793                 if (error && error != EWOULDBLOCK)
794                         fan->old_style = 1;
795         }
796
797         if (fan->old_style) {
798                 cmd.len = 14;
799                 cmd.data[0] = 0x10; /* PWM fan. */
800                 cmd.data[1] = 1 << fan->reg;
801                 cmd.data[2 + 2*fan->reg] = (pwm >> 8) & 0xff;
802                 cmd.data[3 + 2*fan->reg] = pwm & 0xff;
803                 error = smu_run_cmd(smu, &cmd, 1);
804         }
805
806         if (error == 0)
807                 fan->setpoint = pwm;
808
809         return (error);
810 }
811
812 static int
813 smu_fan_read_pwm(struct smu_fan *fan, int *pwm, int *rpm)
814 {
815         device_t smu = fan->dev;
816         struct smu_cmd cmd;
817         int error;
818
819         if (!fan->old_style) {
820                 cmd.cmd = SMU_FAN;
821                 cmd.len = 2;
822                 cmd.data[0] = 0x31;
823                 cmd.data[1] = fan->reg;
824
825                 error = smu_run_cmd(smu, &cmd, 1);
826                 if (error && error != EWOULDBLOCK)
827                         fan->old_style = 1;
828
829                 *rpm = (cmd.data[0] << 8) | cmd.data[1];
830         }
831
832         if (fan->old_style) {
833                 cmd.cmd = SMU_FAN;
834                 cmd.len = 1;
835                 cmd.data[0] = SMU_PWM_STATUS;
836
837                 error = smu_run_cmd(smu, &cmd, 1);
838                 if (error)
839                         return (error);
840
841                 *rpm = (cmd.data[fan->reg*2+1] << 8) | cmd.data[fan->reg*2+2];
842         }
843         if (fan->old_style) {
844                 cmd.cmd = SMU_FAN;
845                 cmd.len = 14;
846                 cmd.data[0] = SMU_PWM_SETPOINT;
847                 cmd.data[1] = 1 << fan->reg;
848
849                 error = smu_run_cmd(smu, &cmd, 1);
850                 if (error)
851                         return (error);
852
853                 *pwm = cmd.data[fan->reg*2+2];
854         }
855         return (0);
856 }
857
858 static int
859 smu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
860 {
861         device_t smu;
862         struct smu_softc *sc;
863         struct smu_fan *fan;
864         int pwm = 0, rpm, error = 0;
865
866         smu = arg1;
867         sc = device_get_softc(smu);
868         fan = &sc->sc_fans[arg2 & 0xff];
869
870         if (fan->type == SMU_FAN_RPM) {
871                 rpm = smu_fan_read_rpm(fan);
872                 if (rpm < 0)
873                         return (rpm);
874
875                 error = sysctl_handle_int(oidp, &rpm, 0, req);
876         } else {
877                 error = smu_fan_read_pwm(fan, &pwm, &rpm);
878                 if (error < 0)
879                         return (EIO);
880
881                 switch (arg2 & 0xff00) {
882                 case SMU_PWM_SYSCTL_PWM:
883                         error = sysctl_handle_int(oidp, &pwm, 0, req);
884                         break;
885                 case SMU_PWM_SYSCTL_RPM:
886                         error = sysctl_handle_int(oidp, &rpm, 0, req);
887                         break;
888                 default:
889                         /* This should never happen */
890                         return (EINVAL);
891                 };
892         }
893         /* We can only read the RPM from a PWM controlled fan, so return. */
894         if ((arg2 & 0xff00) == SMU_PWM_SYSCTL_RPM)
895                 return (0);
896
897         if (error || !req->newptr)
898                 return (error);
899
900         sc->sc_lastuserchange = time_uptime;
901
902         if (fan->type == SMU_FAN_RPM)
903                 return (smu_fan_set_rpm(fan, rpm));
904         else
905                 return (smu_fan_set_pwm(fan, pwm));
906 }
907
908 static void
909 smu_fill_fan_prop(device_t dev, phandle_t child, int id)
910 {
911         struct smu_fan *fan;
912         struct smu_softc *sc;
913         char type[32];
914
915         sc = device_get_softc(dev);
916         fan = &sc->sc_fans[id];
917
918         OF_getprop(child, "device_type", type, sizeof(type));
919         /* We have either RPM or PWM controlled fans. */
920         if (strcmp(type, "fan-rpm-control") == 0)
921                 fan->type = SMU_FAN_RPM;
922         else
923                 fan->type = SMU_FAN_PWM;
924
925         fan->dev = dev;
926         fan->old_style = 0;
927         OF_getprop(child, "reg", &fan->reg,
928                    sizeof(cell_t));
929         OF_getprop(child, "min-value", &fan->fan.min_rpm,
930                    sizeof(int));
931         OF_getprop(child, "max-value", &fan->fan.max_rpm,
932                    sizeof(int));
933         OF_getprop(child, "zone", &fan->fan.zone,
934                    sizeof(int));
935
936         if (OF_getprop(child, "unmanaged-value",
937                        &fan->fan.default_rpm,
938                        sizeof(int)) != sizeof(int))
939                 fan->fan.default_rpm = fan->fan.max_rpm;
940
941         OF_getprop(child, "location", fan->fan.name,
942                    sizeof(fan->fan.name));
943
944         if (fan->type == SMU_FAN_RPM)
945                 fan->setpoint = smu_fan_read_rpm(fan);
946         else
947                 smu_fan_read_pwm(fan, &fan->setpoint, &fan->rpm);
948 }
949
950 /* On the first call count the number of fans. In the second call,
951  * after allocating the fan struct, fill the properties of the fans.
952  */
953 static int
954 smu_count_fans(device_t dev)
955 {
956         struct smu_softc *sc;
957         phandle_t child, node, root;
958         int nfans = 0;
959
960         node = ofw_bus_get_node(dev);
961         sc = device_get_softc(dev);
962
963         /* First find the fanroots and count the number of fans. */
964         for (root = OF_child(node); root != 0; root = OF_peer(root)) {
965                 char name[32];
966                 memset(name, 0, sizeof(name));
967                 OF_getprop(root, "name", name, sizeof(name));
968                 if (strncmp(name, "rpm-fans", 9) == 0 ||
969                     strncmp(name, "pwm-fans", 9) == 0 ||
970                     strncmp(name, "fans", 5) == 0)
971                         for (child = OF_child(root); child != 0;
972                              child = OF_peer(child)) {
973                                 nfans++;
974                                 /* When allocated, fill the fan properties. */
975                                 if (sc->sc_fans != NULL) {
976                                         smu_fill_fan_prop(dev, child,
977                                                           nfans - 1);
978                                 }
979                         }
980         }
981         if (nfans == 0) {
982                 device_printf(dev, "WARNING: No fans detected!\n");
983                 return (0);
984         }
985         return (nfans);
986 }
987
988 static void
989 smu_attach_fans(device_t dev, phandle_t fanroot)
990 {
991         struct smu_fan *fan;
992         struct smu_softc *sc;
993         struct sysctl_oid *oid, *fanroot_oid;
994         struct sysctl_ctx_list *ctx;
995         char sysctl_name[32];
996         int i, j;
997
998         sc = device_get_softc(dev);
999
1000         /* Get the number of fans. */
1001         sc->sc_nfans = smu_count_fans(dev);
1002         if (sc->sc_nfans == 0)
1003                 return;
1004
1005         /* Now we're able to allocate memory for the fans struct. */
1006         sc->sc_fans = malloc(sc->sc_nfans * sizeof(struct smu_fan), M_SMU,
1007             M_WAITOK | M_ZERO);
1008
1009         /* Now fill in the properties. */
1010         smu_count_fans(dev);
1011         
1012         /* Register fans with pmac_thermal */
1013         for (i = 0; i < sc->sc_nfans; i++)
1014                 pmac_thermal_fan_register(&sc->sc_fans[i].fan);
1015
1016         ctx = device_get_sysctl_ctx(dev);
1017         fanroot_oid = SYSCTL_ADD_NODE(ctx,
1018             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans",
1019             CTLFLAG_RD, 0, "SMU Fan Information");
1020
1021         /* Add sysctls */
1022         for (i = 0; i < sc->sc_nfans; i++) {
1023                 fan = &sc->sc_fans[i];
1024                 for (j = 0; j < strlen(fan->fan.name); j++) {
1025                         sysctl_name[j] = tolower(fan->fan.name[j]);
1026                         if (isspace(sysctl_name[j]))
1027                                 sysctl_name[j] = '_';
1028                 }
1029                 sysctl_name[j] = 0;
1030                 if (fan->type == SMU_FAN_RPM) {
1031                         oid = SYSCTL_ADD_NODE(ctx,
1032                                               SYSCTL_CHILDREN(fanroot_oid),
1033                                               OID_AUTO, sysctl_name,
1034                                               CTLFLAG_RD, 0, "Fan Information");
1035                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
1036                                        "minrpm", CTLTYPE_INT | CTLFLAG_RD,
1037                                        &fan->fan.min_rpm, sizeof(int),
1038                                        "Minimum allowed RPM");
1039                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
1040                                        "maxrpm", CTLTYPE_INT | CTLFLAG_RD,
1041                                        &fan->fan.max_rpm, sizeof(int),
1042                                        "Maximum allowed RPM");
1043                         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
1044                                         "rpm",CTLTYPE_INT | CTLFLAG_RW |
1045                                         CTLFLAG_MPSAFE, dev, i,
1046                                         smu_fanrpm_sysctl, "I", "Fan RPM");
1047
1048                         fan->fan.read = (int (*)(struct pmac_fan *))smu_fan_read_rpm;
1049                         fan->fan.set = (int (*)(struct pmac_fan *, int))smu_fan_set_rpm;
1050
1051                 } else {
1052                         oid = SYSCTL_ADD_NODE(ctx,
1053                                               SYSCTL_CHILDREN(fanroot_oid),
1054                                               OID_AUTO, sysctl_name,
1055                                               CTLFLAG_RD, 0, "Fan Information");
1056                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
1057                                        "minpwm", CTLTYPE_INT | CTLFLAG_RD,
1058                                        &fan->fan.min_rpm, sizeof(int),
1059                                        "Minimum allowed PWM in %");
1060                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
1061                                        "maxpwm", CTLTYPE_INT | CTLFLAG_RD,
1062                                        &fan->fan.max_rpm, sizeof(int),
1063                                        "Maximum allowed PWM in %");
1064                         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
1065                                         "pwm",CTLTYPE_INT | CTLFLAG_RW |
1066                                         CTLFLAG_MPSAFE, dev,
1067                                         SMU_PWM_SYSCTL_PWM | i,
1068                                         smu_fanrpm_sysctl, "I", "Fan PWM in %");
1069                         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
1070                                         "rpm",CTLTYPE_INT | CTLFLAG_RD |
1071                                         CTLFLAG_MPSAFE, dev,
1072                                         SMU_PWM_SYSCTL_RPM | i,
1073                                         smu_fanrpm_sysctl, "I", "Fan RPM");
1074                         fan->fan.read = NULL;
1075                         fan->fan.set = (int (*)(struct pmac_fan *, int))smu_fan_set_pwm;
1076
1077                 }
1078                 if (bootverbose)
1079                         device_printf(dev, "Fan: %s type: %d\n",
1080                                       fan->fan.name, fan->type);
1081         }
1082 }
1083
1084 static int
1085 smu_sensor_read(struct smu_sensor *sens)
1086 {
1087         device_t smu = sens->dev;
1088         struct smu_cmd cmd;
1089         struct smu_softc *sc;
1090         int64_t value;
1091         int error;
1092
1093         cmd.cmd = SMU_ADC;
1094         cmd.len = 1;
1095         cmd.data[0] = sens->reg;
1096         error = 0;
1097
1098         error = smu_run_cmd(smu, &cmd, 1);
1099         if (error != 0)
1100                 return (-1);
1101         
1102         sc = device_get_softc(smu);
1103         value = (cmd.data[0] << 8) | cmd.data[1];
1104
1105         switch (sens->type) {
1106         case SMU_TEMP_SENSOR:
1107                 value *= sc->sc_cpu_diode_scale;
1108                 value >>= 3;
1109                 value += ((int64_t)sc->sc_cpu_diode_offset) << 9;
1110                 value <<= 1;
1111
1112                 /* Convert from 16.16 fixed point degC into integer 0.1 K. */
1113                 value = 10*(value >> 16) + ((10*(value & 0xffff)) >> 16) + 2732;
1114                 break;
1115         case SMU_VOLTAGE_SENSOR:
1116                 value *= sc->sc_cpu_volt_scale;
1117                 value += sc->sc_cpu_volt_offset;
1118                 value <<= 4;
1119
1120                 /* Convert from 16.16 fixed point V into mV. */
1121                 value *= 15625;
1122                 value /= 1024;
1123                 value /= 1000;
1124                 break;
1125         case SMU_CURRENT_SENSOR:
1126                 value *= sc->sc_cpu_curr_scale;
1127                 value += sc->sc_cpu_curr_offset;
1128                 value <<= 4;
1129
1130                 /* Convert from 16.16 fixed point A into mA. */
1131                 value *= 15625;
1132                 value /= 1024;
1133                 value /= 1000;
1134                 break;
1135         case SMU_POWER_SENSOR:
1136                 value *= sc->sc_slots_pow_scale;
1137                 value += sc->sc_slots_pow_offset;
1138                 value <<= 4;
1139
1140                 /* Convert from 16.16 fixed point W into mW. */
1141                 value *= 15625;
1142                 value /= 1024;
1143                 value /= 1000;
1144                 break;
1145         }
1146
1147         return (value);
1148 }
1149
1150 static int
1151 smu_sensor_sysctl(SYSCTL_HANDLER_ARGS)
1152 {
1153         device_t smu;
1154         struct smu_softc *sc;
1155         struct smu_sensor *sens;
1156         int value, error;
1157
1158         smu = arg1;
1159         sc = device_get_softc(smu);
1160         sens = &sc->sc_sensors[arg2];
1161
1162         value = smu_sensor_read(sens);
1163         if (value < 0)
1164                 return (EBUSY);
1165
1166         error = sysctl_handle_int(oidp, &value, 0, req);
1167
1168         return (error);
1169 }
1170
1171 static void
1172 smu_attach_sensors(device_t dev, phandle_t sensroot)
1173 {
1174         struct smu_sensor *sens;
1175         struct smu_softc *sc;
1176         struct sysctl_oid *sensroot_oid;
1177         struct sysctl_ctx_list *ctx;
1178         phandle_t child;
1179         char type[32];
1180         int i;
1181
1182         sc = device_get_softc(dev);
1183         sc->sc_nsensors = 0;
1184
1185         for (child = OF_child(sensroot); child != 0; child = OF_peer(child))
1186                 sc->sc_nsensors++;
1187
1188         if (sc->sc_nsensors == 0) {
1189                 device_printf(dev, "WARNING: No sensors detected!\n");
1190                 return;
1191         }
1192
1193         sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct smu_sensor),
1194             M_SMU, M_WAITOK | M_ZERO);
1195
1196         sens = sc->sc_sensors;
1197         sc->sc_nsensors = 0;
1198
1199         ctx = device_get_sysctl_ctx(dev);
1200         sensroot_oid = SYSCTL_ADD_NODE(ctx,
1201             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensors",
1202             CTLFLAG_RD, 0, "SMU Sensor Information");
1203
1204         for (child = OF_child(sensroot); child != 0; child = OF_peer(child)) {
1205                 char sysctl_name[40], sysctl_desc[40];
1206                 const char *units;
1207
1208                 sens->dev = dev;
1209                 OF_getprop(child, "device_type", type, sizeof(type));
1210
1211                 if (strcmp(type, "current-sensor") == 0) {
1212                         sens->type = SMU_CURRENT_SENSOR;
1213                         units = "mA";
1214                 } else if (strcmp(type, "temp-sensor") == 0) {
1215                         sens->type = SMU_TEMP_SENSOR;
1216                         units = "C";
1217                 } else if (strcmp(type, "voltage-sensor") == 0) {
1218                         sens->type = SMU_VOLTAGE_SENSOR;
1219                         units = "mV";
1220                 } else if (strcmp(type, "power-sensor") == 0) {
1221                         sens->type = SMU_POWER_SENSOR;
1222                         units = "mW";
1223                 } else {
1224                         continue;
1225                 }
1226
1227                 OF_getprop(child, "reg", &sens->reg, sizeof(cell_t));
1228                 OF_getprop(child, "zone", &sens->therm.zone, sizeof(int));
1229                 OF_getprop(child, "location", sens->therm.name,
1230                     sizeof(sens->therm.name));
1231
1232                 for (i = 0; i < strlen(sens->therm.name); i++) {
1233                         sysctl_name[i] = tolower(sens->therm.name[i]);
1234                         if (isspace(sysctl_name[i]))
1235                                 sysctl_name[i] = '_';
1236                 }
1237                 sysctl_name[i] = 0;
1238
1239                 sprintf(sysctl_desc,"%s (%s)", sens->therm.name, units);
1240
1241                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
1242                     sysctl_name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1243                     dev, sc->sc_nsensors, smu_sensor_sysctl, 
1244                     (sens->type == SMU_TEMP_SENSOR) ? "IK" : "I", sysctl_desc);
1245
1246                 if (sens->type == SMU_TEMP_SENSOR) {
1247                         /* Make up some numbers */
1248                         sens->therm.target_temp = 500 + 2732; /* 50 C */
1249                         sens->therm.max_temp = 900 + 2732; /* 90 C */
1250
1251                         sens->therm.read =
1252                             (int (*)(struct pmac_therm *))smu_sensor_read;
1253                         pmac_thermal_sensor_register(&sens->therm);
1254                 }
1255
1256                 sens++;
1257                 sc->sc_nsensors++;
1258         }
1259 }
1260
1261 static void
1262 smu_set_sleepled(void *xdev, int onoff)
1263 {
1264         static struct smu_cmd cmd;
1265         device_t smu = xdev;
1266
1267         cmd.cmd = SMU_MISC;
1268         cmd.len = 3;
1269         cmd.data[0] = SMU_MISC_LED_CTRL;
1270         cmd.data[1] = 0;
1271         cmd.data[2] = onoff; 
1272
1273         smu_run_cmd(smu, &cmd, 0);
1274 }
1275
1276 static int
1277 smu_server_mode(SYSCTL_HANDLER_ARGS)
1278 {
1279         struct smu_cmd cmd;
1280         u_int server_mode;
1281         device_t smu = arg1;
1282         int error;
1283         
1284         cmd.cmd = SMU_POWER_EVENTS;
1285         cmd.len = 1;
1286         cmd.data[0] = SMU_PWR_GET_POWERUP;
1287
1288         error = smu_run_cmd(smu, &cmd, 1);
1289
1290         if (error)
1291                 return (error);
1292
1293         server_mode = (cmd.data[1] & SMU_WAKEUP_AC_INSERT) ? 1 : 0;
1294
1295         error = sysctl_handle_int(oidp, &server_mode, 0, req);
1296
1297         if (error || !req->newptr)
1298                 return (error);
1299
1300         if (server_mode == 1)
1301                 cmd.data[0] = SMU_PWR_SET_POWERUP;
1302         else if (server_mode == 0)
1303                 cmd.data[0] = SMU_PWR_CLR_POWERUP;
1304         else
1305                 return (EINVAL);
1306
1307         cmd.len = 3;
1308         cmd.data[1] = 0;
1309         cmd.data[2] = SMU_WAKEUP_AC_INSERT;
1310
1311         return (smu_run_cmd(smu, &cmd, 1));
1312 }
1313
1314 static void
1315 smu_shutdown(void *xdev, int howto)
1316 {
1317         device_t smu = xdev;
1318         struct smu_cmd cmd;
1319
1320         cmd.cmd = SMU_POWER;
1321         if (howto & RB_HALT)
1322                 strcpy(cmd.data, "SHUTDOWN");
1323         else
1324                 strcpy(cmd.data, "RESTART");
1325
1326         cmd.len = strlen(cmd.data);
1327
1328         smu_run_cmd(smu, &cmd, 1);
1329
1330         for (;;);
1331 }
1332
1333 static int
1334 smu_gettime(device_t dev, struct timespec *ts)
1335 {
1336         struct smu_cmd cmd;
1337         struct clocktime ct;
1338
1339         cmd.cmd = SMU_RTC;
1340         cmd.len = 1;
1341         cmd.data[0] = SMU_RTC_GET;
1342
1343         if (smu_run_cmd(dev, &cmd, 1) != 0)
1344                 return (ENXIO);
1345
1346         ct.nsec = 0;
1347         ct.sec  = bcd2bin(cmd.data[0]);
1348         ct.min  = bcd2bin(cmd.data[1]);
1349         ct.hour = bcd2bin(cmd.data[2]);
1350         ct.dow  = bcd2bin(cmd.data[3]);
1351         ct.day  = bcd2bin(cmd.data[4]);
1352         ct.mon  = bcd2bin(cmd.data[5]);
1353         ct.year = bcd2bin(cmd.data[6]) + 2000;
1354
1355         return (clock_ct_to_ts(&ct, ts));
1356 }
1357
1358 static int
1359 smu_settime(device_t dev, struct timespec *ts)
1360 {
1361         static struct smu_cmd cmd;
1362         struct clocktime ct;
1363
1364         cmd.cmd = SMU_RTC;
1365         cmd.len = 8;
1366         cmd.data[0] = SMU_RTC_SET;
1367
1368         clock_ts_to_ct(ts, &ct);
1369
1370         cmd.data[1] = bin2bcd(ct.sec);
1371         cmd.data[2] = bin2bcd(ct.min);
1372         cmd.data[3] = bin2bcd(ct.hour);
1373         cmd.data[4] = bin2bcd(ct.dow);
1374         cmd.data[5] = bin2bcd(ct.day);
1375         cmd.data[6] = bin2bcd(ct.mon);
1376         cmd.data[7] = bin2bcd(ct.year - 2000);
1377
1378         return (smu_run_cmd(dev, &cmd, 0));
1379 }
1380
1381 /* SMU I2C Interface */
1382
1383 static int smuiic_probe(device_t dev);
1384 static int smuiic_attach(device_t dev);
1385 static int smuiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs);
1386 static phandle_t smuiic_get_node(device_t bus, device_t dev);
1387
1388 static device_method_t smuiic_methods[] = {
1389         /* device interface */
1390         DEVMETHOD(device_probe,         smuiic_probe),
1391         DEVMETHOD(device_attach,        smuiic_attach),
1392
1393         /* iicbus interface */
1394         DEVMETHOD(iicbus_callback,      iicbus_null_callback),
1395         DEVMETHOD(iicbus_transfer,      smuiic_transfer),
1396
1397         /* ofw_bus interface */
1398         DEVMETHOD(ofw_bus_get_node,     smuiic_get_node),
1399
1400         { 0, 0 }
1401 };
1402
1403 struct smuiic_softc {
1404         struct mtx      sc_mtx;
1405         volatile int    sc_iic_inuse;
1406         int             sc_busno;
1407 };
1408
1409 static driver_t smuiic_driver = {
1410         "iichb",
1411         smuiic_methods,
1412         sizeof(struct smuiic_softc)
1413 };
1414 static devclass_t smuiic_devclass;
1415
1416 DRIVER_MODULE(smuiic, smu, smuiic_driver, smuiic_devclass, 0, 0);
1417
1418 static void
1419 smu_attach_i2c(device_t smu, phandle_t i2croot)
1420 {
1421         phandle_t child;
1422         device_t cdev;
1423         struct ofw_bus_devinfo *dinfo;
1424         char name[32];
1425
1426         for (child = OF_child(i2croot); child != 0; child = OF_peer(child)) {
1427                 if (OF_getprop(child, "name", name, sizeof(name)) <= 0)
1428                         continue;
1429
1430                 if (strcmp(name, "i2c-bus") != 0 && strcmp(name, "i2c") != 0)
1431                         continue;
1432
1433                 dinfo = malloc(sizeof(struct ofw_bus_devinfo), M_SMU,
1434                     M_WAITOK | M_ZERO);
1435                 if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
1436                         free(dinfo, M_SMU);
1437                         continue;
1438                 }
1439
1440                 cdev = device_add_child(smu, NULL, -1);
1441                 if (cdev == NULL) {
1442                         device_printf(smu, "<%s>: device_add_child failed\n",
1443                             dinfo->obd_name);
1444                         ofw_bus_gen_destroy_devinfo(dinfo);
1445                         free(dinfo, M_SMU);
1446                         continue;
1447                 }
1448                 device_set_ivars(cdev, dinfo);
1449         }
1450 }
1451
1452 static int
1453 smuiic_probe(device_t dev)
1454 {
1455         const char *name;
1456
1457         name = ofw_bus_get_name(dev);
1458         if (name == NULL)
1459                 return (ENXIO);
1460
1461         if (strcmp(name, "i2c-bus") == 0 || strcmp(name, "i2c") == 0) {
1462                 device_set_desc(dev, "SMU I2C controller");
1463                 return (0);
1464         }
1465
1466         return (ENXIO);
1467 }
1468
1469 static int
1470 smuiic_attach(device_t dev)
1471 {
1472         struct smuiic_softc *sc = device_get_softc(dev);
1473         mtx_init(&sc->sc_mtx, "smuiic", NULL, MTX_DEF);
1474         sc->sc_iic_inuse = 0;
1475
1476         /* Get our bus number */
1477         OF_getprop(ofw_bus_get_node(dev), "reg", &sc->sc_busno,
1478             sizeof(sc->sc_busno));
1479
1480         /* Add the IIC bus layer */
1481         device_add_child(dev, "iicbus", -1);
1482
1483         return (bus_generic_attach(dev));
1484 }
1485
1486 static int
1487 smuiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
1488 {
1489         struct smuiic_softc *sc = device_get_softc(dev);
1490         struct smu_cmd cmd;
1491         int i, j, error;
1492
1493         mtx_lock(&sc->sc_mtx);
1494         while (sc->sc_iic_inuse)
1495                 mtx_sleep(sc, &sc->sc_mtx, 0, "smuiic", 100);
1496
1497         sc->sc_iic_inuse = 1;
1498         error = 0;
1499
1500         for (i = 0; i < nmsgs; i++) {
1501                 cmd.cmd = SMU_I2C;
1502                 cmd.data[0] = sc->sc_busno;
1503                 if (msgs[i].flags & IIC_M_NOSTOP)
1504                         cmd.data[1] = SMU_I2C_COMBINED;
1505                 else
1506                         cmd.data[1] = SMU_I2C_SIMPLE;
1507
1508                 cmd.data[2] = msgs[i].slave;
1509                 if (msgs[i].flags & IIC_M_RD)
1510                         cmd.data[2] |= 1; 
1511
1512                 if (msgs[i].flags & IIC_M_NOSTOP) {
1513                         KASSERT(msgs[i].len < 4,
1514                             ("oversize I2C combined message"));
1515
1516                         cmd.data[3] = min(msgs[i].len, 3);
1517                         memcpy(&cmd.data[4], msgs[i].buf, min(msgs[i].len, 3));
1518                         i++; /* Advance to next part of message */
1519                 } else {
1520                         cmd.data[3] = 0;
1521                         memset(&cmd.data[4], 0, 3);
1522                 }
1523
1524                 cmd.data[7] = msgs[i].slave;
1525                 if (msgs[i].flags & IIC_M_RD)
1526                         cmd.data[7] |= 1; 
1527
1528                 cmd.data[8] = msgs[i].len;
1529                 if (msgs[i].flags & IIC_M_RD) {
1530                         memset(&cmd.data[9], 0xff, msgs[i].len);
1531                         cmd.len = 9;
1532                 } else {
1533                         memcpy(&cmd.data[9], msgs[i].buf, msgs[i].len);
1534                         cmd.len = 9 + msgs[i].len;
1535                 }
1536
1537                 mtx_unlock(&sc->sc_mtx);
1538                 smu_run_cmd(device_get_parent(dev), &cmd, 1);
1539                 mtx_lock(&sc->sc_mtx);
1540
1541                 for (j = 0; j < 10; j++) {
1542                         cmd.cmd = SMU_I2C;
1543                         cmd.len = 1;
1544                         cmd.data[0] = 0;
1545                         memset(&cmd.data[1], 0xff, msgs[i].len);
1546                         
1547                         mtx_unlock(&sc->sc_mtx);
1548                         smu_run_cmd(device_get_parent(dev), &cmd, 1);
1549                         mtx_lock(&sc->sc_mtx);
1550                         
1551                         if (!(cmd.data[0] & 0x80))
1552                                 break;
1553
1554                         mtx_sleep(sc, &sc->sc_mtx, 0, "smuiic", 10);
1555                 }
1556                 
1557                 if (cmd.data[0] & 0x80) {
1558                         error = EIO;
1559                         msgs[i].len = 0;
1560                         goto exit;
1561                 }
1562                 memcpy(msgs[i].buf, &cmd.data[1], msgs[i].len);
1563                 msgs[i].len = cmd.len - 1;
1564         }
1565
1566     exit:
1567         sc->sc_iic_inuse = 0;
1568         mtx_unlock(&sc->sc_mtx);
1569         wakeup(sc);
1570         return (error);
1571 }
1572
1573 static phandle_t
1574 smuiic_get_node(device_t bus, device_t dev)
1575 {
1576
1577         return (ofw_bus_get_node(bus));
1578 }
1579