smu.c revision 1.13 1 /*-
2 * Copyright (c) 2013 Phileas Fogg
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/kernel.h>
30 #include <sys/malloc.h>
31 #include <sys/device.h>
32 #include <sys/proc.h>
33 #include <sys/mutex.h>
34 #include <sys/time.h>
35 #include <sys/reboot.h>
36 #include <sys/sysctl.h>
37 #include <sys/kthread.h>
38
39 #include <machine/autoconf.h>
40
41 #include <dev/ofw/openfirm.h>
42 #include <dev/i2c/i2cvar.h>
43 #include <dev/clock_subr.h>
44 #include <dev/sysmon/sysmonvar.h>
45 #include <dev/sysmon/sysmon_taskq.h>
46
47 #include <macppc/dev/obiovar.h>
48 #include <macppc/dev/smuvar.h>
49
50 #include "opt_smu.h"
51
52 struct smu_softc;
53
54 struct smu_cmd {
55 u_char cmd;
56 u_char len;
57 u_char data[254];
58 };
59
60 struct smu_fan {
61 struct smu_softc* sc;
62
63 char location[32];
64 int reg;
65 int zone;
66 int rpm_ctl;
67 int min_rpm;
68 int max_rpm;
69 int default_rpm;
70 int current_rpm;
71 time_t last_update;
72 };
73
74 struct smu_iicbus {
75 struct smu_softc* sc;
76
77 int reg;
78 struct i2c_controller i2c;
79 };
80
81 #define SMU_MAX_FANS 8
82 #define SMU_MAX_IICBUS 3
83 #define SMU_MAX_SME_SENSORS (SMU_MAX_FANS + 8)
84
85 struct smu_zone {
86 bool (*filter)(const envsys_data_t *);
87 int nfans;
88 int fans[SMU_MAX_FANS];
89 int threshold, step;
90 int duty;
91 };
92
93
94 #define SMU_ZONE_CPUS 0
95 #define SMU_ZONE_DRIVES 1
96 #define SMU_ZONE_SLOTS 2
97 #define SMU_ZONES 3
98
99 #define C_TO_uK(n) (n * 1000000 + 273150000)
100
101 struct smu_softc {
102 device_t sc_dev;
103 int sc_node;
104 struct sysctlnode *sc_sysctl_me;
105
106 kmutex_t sc_cmd_lock;
107 kmutex_t sc_msg_lock;
108 struct smu_cmd *sc_cmd;
109 paddr_t sc_cmd_paddr;
110 int sc_dbell_mbox;
111 int sc_dbell_gpio;
112
113 int sc_num_fans;
114 struct smu_fan sc_fans[SMU_MAX_FANS];
115
116 int sc_num_iicbus;
117 struct smu_iicbus sc_iicbus[SMU_MAX_IICBUS];
118
119 struct todr_chip_handle sc_todr;
120
121 struct sysmon_envsys *sc_sme;
122 envsys_data_t sc_sme_sensors[SMU_MAX_SME_SENSORS];
123 uint32_t cpu_m;
124 int32_t cpu_b;
125
126 struct smu_zone sc_zones[SMU_ZONES];
127 lwp_t *sc_thread;
128 bool sc_dying;
129 };
130
131 #define SMU_CMD_FAN 0x4a
132 #define SMU_CMD_RTC 0x8e
133 #define SMU_CMD_I2C 0x9a
134 #define SMU_CMD_POWER 0xaa
135 #define SMU_CMD_ADC 0xd8
136 #define SMU_MISC 0xee
137 #define SMU_MISC_GET_DATA 0x02
138 #define SMU_MISC_LED_CTRL 0x04
139
140 #define SMU_CPUTEMP_CAL 0x18
141 #define SMU_CPUVOLT_CAL 0x21
142 #define SMU_SLOTPW_CAL 0x78
143
144 #define SMU_PARTITION 0x3e
145 #define SMU_PARTITION_LATEST 0x01
146 #define SMU_PARTITION_BASE 0x02
147 #define SMU_PARTITION_UPDATE 0x03
148
149 #ifdef SMU_DEBUG
150 #define DPRINTF printf
151 #else
152 #define DPRINTF while (0) printf
153 #endif
154
155 static int smu_match(device_t, struct cfdata *, void *);
156 static void smu_attach(device_t, device_t, void *);
157 static int smu_setup_doorbell(struct smu_softc *);
158 static void smu_setup_fans(struct smu_softc *);
159 static void smu_setup_iicbus(struct smu_softc *);
160 static void smu_setup_sme(struct smu_softc *);
161 static int smu_iicbus_print(void *, const char *);
162 static void smu_sme_refresh(struct sysmon_envsys *, envsys_data_t *);
163 static int smu_do_cmd(struct smu_softc *, struct smu_cmd *, int);
164 static int smu_dbell_gpio_intr(void *);
165 static int smu_todr_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
166 static int smu_todr_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
167 static int smu_fan_update_rpm(struct smu_fan *);
168 static int smu_fan_get_rpm(struct smu_fan *, int *);
169 static int smu_fan_set_rpm(struct smu_fan *, int);
170 static int smu_read_adc(struct smu_softc *, int);
171
172 static int smu_iicbus_exec(void *, i2c_op_t, i2c_addr_t, const void *,
173 size_t, void *, size_t, int);
174 static int smu_sysctl_fan_rpm(SYSCTLFN_ARGS);
175
176 static void smu_setup_zones(struct smu_softc *);
177 static void smu_adjust_zone(struct smu_softc *, int);
178 static void smu_adjust(void *);
179 static bool is_cpu_sensor(const envsys_data_t *);
180 static bool is_drive_sensor(const envsys_data_t *);
181 static bool is_slots_sensor(const envsys_data_t *);
182
183 int smu_get_datablock(int, uint8_t *, size_t);
184
185 CFATTACH_DECL_NEW(smu, sizeof(struct smu_softc),
186 smu_match, smu_attach, NULL, NULL);
187
188 static struct smu_softc *smu0 = NULL;
189
190 static int
191 smu_match(device_t parent, struct cfdata *cf, void *aux)
192 {
193 struct confargs *ca = aux;
194
195 if (strcmp(ca->ca_name, "smu") == 0)
196 return 5;
197
198 return 0;
199 }
200
201 static void
202 smu_attach(device_t parent, device_t self, void *aux)
203 {
204 struct confargs *ca = aux;
205 struct smu_softc *sc = device_private(self);
206 uint16_t data[4];
207
208 sc->sc_dev = self;
209 sc->sc_node = ca->ca_node;
210
211 if (smu0 == NULL)
212 smu0 = sc;
213
214 sysctl_createv(NULL, 0, NULL, (void *) &sc->sc_sysctl_me,
215 CTLFLAG_READWRITE,
216 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
217 NULL, 0, NULL, 0,
218 CTL_MACHDEP, CTL_CREATE, CTL_EOL);
219
220 if (smu_setup_doorbell(sc) != 0) {
221 aprint_normal(": unable to set up doorbell\n");
222 return;
223 }
224
225 aprint_normal("\n");
226
227 smu_setup_fans(sc);
228 smu_setup_iicbus(sc);
229
230 sc->sc_todr.todr_gettime_ymdhms = smu_todr_gettime_ymdhms;
231 sc->sc_todr.todr_settime_ymdhms = smu_todr_settime_ymdhms;
232 sc->sc_todr.cookie = sc;
233 todr_attach(&sc->sc_todr);
234
235 /* calibration data */
236 memset(data, 0, 8);
237 smu_get_datablock(SMU_CPUTEMP_CAL, (void *)data, 8);
238 DPRINTF("data %04x %04x %04x %04x\n", data[0], data[1], data[2], data[3]);
239 sc->cpu_m = data[2];
240 sc->cpu_b = (int16_t)data[3];
241
242 smu_setup_sme(sc);
243
244 smu_setup_zones(sc);
245 }
246
247 static int
248 smu_setup_doorbell(struct smu_softc *sc)
249 {
250 int node, parent, reg[4], gpio_base, irq;
251
252 mutex_init(&sc->sc_cmd_lock, MUTEX_DEFAULT, IPL_NONE);
253 sc->sc_cmd = malloc(4096, M_DEVBUF, M_WAITOK);
254 sc->sc_cmd_paddr = vtophys((vaddr_t) sc->sc_cmd);
255
256 DPRINTF("%s: cmd vaddr 0x%x paddr 0x%x\n",
257 __func__, (unsigned int) sc->sc_cmd,
258 (unsigned int) sc->sc_cmd_paddr);
259
260 if (OF_getprop(sc->sc_node, "platform-doorbell-buff",
261 &node, sizeof(node)) <= 0)
262 return -1;
263
264 if (OF_getprop(node, "platform-do-doorbell-buff",
265 reg, sizeof(reg)) < sizeof(reg))
266 return -1;
267
268 sc->sc_dbell_mbox = reg[3];
269
270 if (OF_getprop(sc->sc_node, "platform-doorbell-ack",
271 &node, sizeof(node)) <= 0)
272 return -1;
273
274 parent = OF_parent(node);
275 if (parent == 0)
276 return -1;
277
278 if (OF_getprop(parent, "reg", &gpio_base, sizeof(gpio_base)) <= 0)
279 return -1;
280
281 if (OF_getprop(node, "reg", reg, sizeof(reg)) <= 0)
282 return -1;
283
284 if (OF_getprop(node, "interrupts", &irq, sizeof(irq)) <= 0)
285 return -1;
286
287 sc->sc_dbell_gpio = gpio_base + reg[0];
288
289 aprint_normal(" mbox 0x%x gpio 0x%x irq %d",
290 sc->sc_dbell_mbox, sc->sc_dbell_gpio, irq);
291
292 intr_establish_xname(irq, IST_EDGE_FALLING, IPL_TTY,
293 smu_dbell_gpio_intr, sc, device_xname(sc->sc_dev));
294
295 return 0;
296 }
297
298 static void
299 smu_setup_fans(struct smu_softc *sc)
300 {
301 struct smu_fan *fan;
302 struct sysctlnode *sysctl_fans, *sysctl_fan, *sysctl_node;
303 char type[32], sysctl_fan_name[32];
304 int node, i, j;
305 const char *fans[] = { "fans", "rpm-fans", 0 };
306 int n = 0;
307
308 while (fans[n][0] != 0) {
309 node = of_getnode_byname(sc->sc_node, fans[n]);
310 for (node = OF_child(node);
311 (node != 0) && (sc->sc_num_fans < SMU_MAX_FANS);
312 node = OF_peer(node)) {
313 fan = &sc->sc_fans[sc->sc_num_fans];
314 fan->sc = sc;
315
316 memset(fan->location, 0, sizeof(fan->location));
317 OF_getprop(node, "location", fan->location,
318 sizeof(fan->location));
319
320 if (OF_getprop(node, "reg", &fan->reg,
321 sizeof(fan->reg)) <= 0)
322 continue;
323
324 if (OF_getprop(node, "zone", &fan->zone ,
325 sizeof(fan->zone)) <= 0)
326 continue;
327
328 memset(type, 0, sizeof(type));
329 OF_getprop(node, "device_type", type, sizeof(type));
330 if (strcmp(type, "fan-rpm-control") == 0)
331 fan->rpm_ctl = 1;
332 else
333 fan->rpm_ctl = 0;
334
335 if (OF_getprop(node, "min-value", &fan->min_rpm,
336 sizeof(fan->min_rpm)) <= 0)
337 fan->min_rpm = 0;
338
339 if (OF_getprop(node, "max-value", &fan->max_rpm,
340 sizeof(fan->max_rpm)) <= 0)
341 fan->max_rpm = 0xffff;
342
343 if (OF_getprop(node, "unmanage-value", &fan->default_rpm,
344 sizeof(fan->default_rpm)) <= 0)
345 fan->default_rpm = fan->max_rpm;
346
347 DPRINTF("fan: location %s reg %x zone %d rpm_ctl %d "
348 "min_rpm %d max_rpm %d default_rpm %d\n",
349 fan->location, fan->reg, fan->zone, fan->rpm_ctl,
350 fan->min_rpm, fan->max_rpm, fan->default_rpm);
351
352 sc->sc_num_fans++;
353 }
354 n++;
355 }
356
357 for (i = 0; i < sc->sc_num_fans; i++) {
358 fan = &sc->sc_fans[i];
359 smu_fan_set_rpm(fan, fan->default_rpm);
360 smu_fan_get_rpm(fan, &fan->current_rpm);
361 }
362
363 /* Create sysctl nodes for each fan */
364
365 sysctl_createv(NULL, 0, NULL, (void *) &sysctl_fans,
366 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
367 CTLTYPE_NODE, "fans", NULL,
368 NULL, 0, NULL, 0,
369 CTL_MACHDEP,
370 sc->sc_sysctl_me->sysctl_num,
371 CTL_CREATE, CTL_EOL);
372
373 for (i = 0; i < sc->sc_num_fans; i++) {
374 fan = &sc->sc_fans[i];
375
376 for (j = 0; j < strlen(fan->location); j++) {
377 sysctl_fan_name[j] = tolower(fan->location[j]);
378 if (sysctl_fan_name[j] == ' ')
379 sysctl_fan_name[j] = '_';
380 }
381 sysctl_fan_name[j] = '\0';
382
383 sysctl_createv(NULL, 0, NULL, (void *) &sysctl_fan,
384 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
385 CTLTYPE_NODE, sysctl_fan_name, "fan information",
386 NULL, 0, NULL, 0,
387 CTL_MACHDEP,
388 sc->sc_sysctl_me->sysctl_num,
389 sysctl_fans->sysctl_num,
390 CTL_CREATE, CTL_EOL);
391
392 sysctl_createv(NULL, 0, NULL, (void *) &sysctl_node,
393 CTLFLAG_READONLY | CTLFLAG_OWNDESC,
394 CTLTYPE_INT, "zone", "fan zone",
395 NULL, 0, &fan->zone, 0,
396 CTL_MACHDEP,
397 sc->sc_sysctl_me->sysctl_num,
398 sysctl_fans->sysctl_num,
399 sysctl_fan->sysctl_num,
400 CTL_CREATE, CTL_EOL);
401
402 sysctl_createv(NULL, 0, NULL, (void *) &sysctl_node,
403 CTLFLAG_READONLY | CTLFLAG_OWNDESC,
404 CTLTYPE_INT, "min_rpm", "fan minimum rpm",
405 NULL, 0, &fan->min_rpm, 0,
406 CTL_MACHDEP,
407 sc->sc_sysctl_me->sysctl_num,
408 sysctl_fans->sysctl_num,
409 sysctl_fan->sysctl_num,
410 CTL_CREATE, CTL_EOL);
411
412 sysctl_createv(NULL, 0, NULL, (void *) &sysctl_node,
413 CTLFLAG_READONLY | CTLFLAG_OWNDESC,
414 CTLTYPE_INT, "max_rpm", "fan maximum rpm",
415 NULL, 0, &fan->max_rpm, 0,
416 CTL_MACHDEP,
417 sc->sc_sysctl_me->sysctl_num,
418 sysctl_fans->sysctl_num,
419 sysctl_fan->sysctl_num,
420 CTL_CREATE, CTL_EOL);
421
422 sysctl_createv(NULL, 0, NULL, (void *) &sysctl_node,
423 CTLFLAG_READONLY | CTLFLAG_OWNDESC,
424 CTLTYPE_INT, "default_rpm", "fan default rpm",
425 NULL, 0, &fan->default_rpm, 0,
426 CTL_MACHDEP,
427 sc->sc_sysctl_me->sysctl_num,
428 sysctl_fans->sysctl_num,
429 sysctl_fan->sysctl_num,
430 CTL_CREATE, CTL_EOL);
431
432 sysctl_createv(NULL, 0, NULL, (void *) &sysctl_node,
433 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
434 CTLTYPE_INT, "rpm", "fan current rpm",
435 smu_sysctl_fan_rpm, 0, (void *) fan, 0,
436 CTL_MACHDEP,
437 sc->sc_sysctl_me->sysctl_num,
438 sysctl_fans->sysctl_num,
439 sysctl_fan->sysctl_num,
440 CTL_CREATE, CTL_EOL);
441 }
442 }
443
444 static void
445 smu_setup_iicbus(struct smu_softc *sc)
446 {
447 struct smu_iicbus *iicbus;
448 struct i2c_controller *i2c;
449 struct smu_iicbus_confargs ca;
450 int node;
451 char name[32];
452
453 node = of_getnode_byname(sc->sc_node, "smu-i2c-control");
454 if (node == 0) node = sc->sc_node;
455 for (node = OF_child(node);
456 (node != 0) && (sc->sc_num_iicbus < SMU_MAX_IICBUS);
457 node = OF_peer(node)) {
458 memset(name, 0, sizeof(name));
459 OF_getprop(node, "name", name, sizeof(name));
460 if ((strcmp(name, "i2c-bus") != 0) &&
461 (strcmp(name, "i2c") != 0))
462 continue;
463
464 iicbus = &sc->sc_iicbus[sc->sc_num_iicbus];
465 iicbus->sc = sc;
466 i2c = &iicbus->i2c;
467
468 if (OF_getprop(node, "reg", &iicbus->reg, sizeof(iicbus->reg)) <= 0)
469 continue;
470
471 DPRINTF("iicbus: reg %x\n", iicbus->reg);
472
473 iic_tag_init(i2c);
474 i2c->ic_cookie = iicbus;
475 i2c->ic_exec = smu_iicbus_exec;
476
477 ca.ca_name = name;
478 ca.ca_node = node;
479 ca.ca_tag = i2c;
480 config_found(sc->sc_dev, &ca, smu_iicbus_print,
481 CFARG_DEVHANDLE, devhandle_from_of(node),
482 CFARG_EOL);
483
484 sc->sc_num_iicbus++;
485 }
486 }
487
488 static void
489 smu_setup_sme(struct smu_softc *sc)
490 {
491 struct smu_fan *fan;
492 envsys_data_t *sme_sensor;
493 int i, sensors, child, reg;
494 char loc[32], type[32];
495
496 sc->sc_sme = sysmon_envsys_create();
497
498 for (i = 0; i < sc->sc_num_fans; i++) {
499 sme_sensor = &sc->sc_sme_sensors[i];
500 fan = &sc->sc_fans[i];
501
502 sme_sensor->units = ENVSYS_SFANRPM;
503 sme_sensor->state = ENVSYS_SINVALID;
504 snprintf(sme_sensor->desc, sizeof(sme_sensor->desc),
505 "%s", fan->location);
506
507 if (sysmon_envsys_sensor_attach(sc->sc_sme, sme_sensor)) {
508 sysmon_envsys_destroy(sc->sc_sme);
509 return;
510 }
511 }
512 sensors = OF_finddevice("/smu/sensors");
513 child = OF_child(sensors);
514 while (child != 0) {
515 sme_sensor = &sc->sc_sme_sensors[i];
516 if (OF_getprop(child, "location", loc, 32) == 0) goto next;
517 if (OF_getprop(child, "device_type", type, 32) == 0) goto next;
518 if (OF_getprop(child, "reg", ®, 4) == 0) goto next;
519 if (strcmp(type, "temp-sensor") == 0) {
520 sme_sensor->units = ENVSYS_STEMP;
521 sme_sensor->state = ENVSYS_SINVALID;
522 strncpy(sme_sensor->desc, loc, sizeof(sme_sensor->desc));
523 sme_sensor->private = reg;
524 sysmon_envsys_sensor_attach(sc->sc_sme, sme_sensor);
525 i++;
526 printf("%s: %s@%x\n", loc, type, reg);
527 }
528 next:
529 child = OF_peer(child);
530 }
531
532 sc->sc_sme->sme_name = device_xname(sc->sc_dev);
533 sc->sc_sme->sme_cookie = sc;
534 sc->sc_sme->sme_refresh = smu_sme_refresh;
535
536 if (sysmon_envsys_register(sc->sc_sme)) {
537 aprint_error_dev(sc->sc_dev,
538 "unable to register with sysmon\n");
539 sysmon_envsys_destroy(sc->sc_sme);
540 }
541 }
542
543 static int
544 smu_iicbus_print(void *aux, const char *smu)
545 {
546 struct smu_iicbus_confargs *ca = aux;
547
548 if (smu)
549 aprint_normal("%s at %s", ca->ca_name, smu);
550
551 return UNCONF;
552 }
553
554 static void
555 smu_sme_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
556 {
557 struct smu_softc *sc = sme->sme_cookie;
558 struct smu_fan *fan;
559 int which = edata->sensor;
560 int ret;
561
562 edata->state = ENVSYS_SINVALID;
563
564 if (which < sc->sc_num_fans) {
565 fan = &sc->sc_fans[which];
566
567 ret = smu_fan_get_rpm(fan, &fan->current_rpm);
568 if (ret == 0) {
569 edata->value_cur = fan->current_rpm;
570 edata->state = ENVSYS_SVALID;
571 }
572 } else if (edata->private > 0) {
573 /* this works only for the CPU diode */
574 int64_t r = smu_read_adc(sc, edata->private);
575 if (r != -1) {
576 r = r * sc->cpu_m;
577 r >>= 3;
578 r += (int64_t)sc->cpu_b << 9;
579 r <<= 1;
580 r *= 15625;
581 r /= 1024;
582 edata->value_cur = r + 273150000;
583 edata->state = ENVSYS_SVALID;
584 }
585 }
586 }
587
588 static int
589 smu_do_cmd(struct smu_softc *sc, struct smu_cmd *cmd, int timo)
590 {
591 int gpio, ret, bail;
592 u_char ack;
593
594 mutex_enter(&sc->sc_cmd_lock);
595
596 DPRINTF("%s: cmd %02x len %02x\n", __func__, cmd->cmd, cmd->len);
597 DPRINTF("%s: data %02x %02x %02x %02x %02x %02x %02x %02x\n", __func__,
598 cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3],
599 cmd->data[4], cmd->data[5], cmd->data[6], cmd->data[7]);
600
601 sc->sc_cmd->cmd = cmd->cmd;
602 sc->sc_cmd->len = cmd->len;
603 memcpy(sc->sc_cmd->data, cmd->data, cmd->len);
604
605 __asm volatile ("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
606
607 obio_write_4(sc->sc_dbell_mbox, sc->sc_cmd_paddr);
608 obio_write_1(sc->sc_dbell_gpio, 0x04);
609
610 bail = 0;
611
612 gpio = obio_read_1(sc->sc_dbell_gpio);
613
614 while (((gpio & 0x07) != 0x07) && (bail < timo)) {
615 ret = tsleep(sc->sc_cmd, PWAIT, "smu_cmd", mstohz(10));
616 if (ret != 0) {
617 bail++;
618 }
619 gpio = obio_read_1(sc->sc_dbell_gpio);
620 }
621
622 if ((gpio & 0x07) != 0x07) {
623 mutex_exit(&sc->sc_cmd_lock);
624 return EWOULDBLOCK;
625 }
626
627 __asm volatile ("dcbf 0,%0; sync" :: "r"(sc->sc_cmd) : "memory");
628
629 ack = (~cmd->cmd) & 0xff;
630 if (sc->sc_cmd->cmd != ack) {
631 DPRINTF("%s: invalid ack, got %x expected %x\n",
632 __func__, sc->sc_cmd->cmd, ack);
633 mutex_exit(&sc->sc_cmd_lock);
634 return EIO;
635 }
636
637 cmd->cmd = sc->sc_cmd->cmd;
638 cmd->len = sc->sc_cmd->len;
639 memcpy(cmd->data, sc->sc_cmd->data, sc->sc_cmd->len);
640
641 mutex_exit(&sc->sc_cmd_lock);
642
643 return 0;
644 }
645
646
647 static int
648 smu_dbell_gpio_intr(void *arg)
649 {
650 struct smu_softc *sc = arg;
651
652 DPRINTF("%s\n", __func__);
653
654 wakeup(sc->sc_cmd);
655
656 return 1;
657 }
658
659 void
660 smu_poweroff(void)
661 {
662 struct smu_cmd cmd;
663
664 if (smu0 == NULL)
665 return;
666
667 cmd.cmd = SMU_CMD_POWER;
668 strcpy(cmd.data, "SHUTDOWN");
669 cmd.len = strlen(cmd.data) + 1;
670 smu_do_cmd(smu0, &cmd, 800);
671
672 for (;;);
673 }
674
675 void
676 smu_restart(void)
677 {
678 struct smu_cmd cmd;
679
680 if (smu0 == NULL)
681 return;
682
683 cmd.cmd = SMU_CMD_POWER;
684 strcpy(cmd.data, "RESTART");
685 cmd.len = strlen(cmd.data) + 1;
686 smu_do_cmd(smu0, &cmd, 800);
687
688 for (;;);
689 }
690
691 static int
692 smu_todr_gettime_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
693 {
694 struct smu_softc *sc = tch->cookie;
695 struct smu_cmd cmd;
696 int ret;
697
698 cmd.cmd = SMU_CMD_RTC;
699 cmd.len = 1;
700 cmd.data[0] = 0x81;
701
702 ret = smu_do_cmd(sc, &cmd, 800);
703 if (ret != 0)
704 return ret;
705
706 dt->dt_sec = bcdtobin(cmd.data[0]);
707 dt->dt_min = bcdtobin(cmd.data[1]);
708 dt->dt_hour = bcdtobin(cmd.data[2]);
709 dt->dt_wday = bcdtobin(cmd.data[3]);
710 dt->dt_day = bcdtobin(cmd.data[4]);
711 dt->dt_mon = bcdtobin(cmd.data[5]);
712 dt->dt_year = bcdtobin(cmd.data[6]) + 2000;
713
714 return 0;
715 }
716
717 static int
718 smu_todr_settime_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
719 {
720 struct smu_softc *sc = tch->cookie;
721 struct smu_cmd cmd;
722
723 cmd.cmd = SMU_CMD_RTC;
724 cmd.len = 8;
725 cmd.data[0] = 0x80;
726 cmd.data[1] = bintobcd(dt->dt_sec);
727 cmd.data[2] = bintobcd(dt->dt_min);
728 cmd.data[3] = bintobcd(dt->dt_hour);
729 cmd.data[4] = bintobcd(dt->dt_wday);
730 cmd.data[5] = bintobcd(dt->dt_day);
731 cmd.data[6] = bintobcd(dt->dt_mon);
732 cmd.data[7] = bintobcd(dt->dt_year - 2000);
733
734 return smu_do_cmd(sc, &cmd, 800);
735 }
736
737 static int
738 smu_fan_update_rpm(struct smu_fan *fan)
739 {
740 struct smu_softc *sc = fan->sc;
741 struct smu_cmd cmd;
742 int ret;
743
744 cmd.cmd = SMU_CMD_FAN;
745 cmd.len = 2;
746 cmd.data[0] = 0x31;
747 cmd.data[1] = fan->reg;
748
749 ret = smu_do_cmd(sc, &cmd, 800);
750 if (ret == 0) {
751 fan->last_update = time_uptime;
752 fan->current_rpm = (cmd.data[0] << 8) | cmd.data[1];
753 } else {
754 cmd.cmd = SMU_CMD_FAN;
755 cmd.len = 1;
756 cmd.data[0] = 0x01;
757
758 ret = smu_do_cmd(sc, &cmd, 800);
759 if (ret == 0) {
760 fan->last_update = time_uptime;
761 fan->current_rpm = (cmd.data[1 + fan->reg * 2] << 8) |
762 cmd.data[2 + fan->reg * 2];
763 }
764 }
765
766 return ret;
767 }
768
769 static int
770 smu_fan_get_rpm(struct smu_fan *fan, int *rpm)
771 {
772 int ret;
773 ret = 0;
774
775 if (time_uptime - fan->last_update > 1) {
776 ret = smu_fan_update_rpm(fan);
777 if (ret != 0)
778 return ret;
779 }
780
781 *rpm = fan->current_rpm;
782
783 return ret;
784 }
785
786 static int
787 smu_fan_set_rpm(struct smu_fan *fan, int rpm)
788 {
789 struct smu_softc *sc = fan->sc;
790 struct smu_cmd cmd;
791 int ret;
792
793 DPRINTF("%s: fan %s rpm %d\n", __func__, fan->location, rpm);
794
795 rpm = uimax(fan->min_rpm, rpm);
796 rpm = uimin(fan->max_rpm, rpm);
797
798 cmd.cmd = SMU_CMD_FAN;
799 cmd.len = 4;
800 cmd.data[0] = 0x30;
801 cmd.data[1] = fan->reg;
802 cmd.data[2] = (rpm >> 8) & 0xff;
803 cmd.data[3] = rpm & 0xff;
804
805 ret = smu_do_cmd(sc, &cmd, 800);
806 if (ret != 0) {
807 cmd.cmd = SMU_CMD_FAN;
808 cmd.len = 14;
809 cmd.data[0] = fan->rpm_ctl ? 0x00 : 0x10;
810 cmd.data[1] = 1 << fan->reg;
811 cmd.data[2] = cmd.data[2 + fan->reg * 2] = (rpm >> 8) & 0xff;
812 cmd.data[3] = cmd.data[3 + fan->reg * 2] = rpm & 0xff;
813
814 ret = smu_do_cmd(sc, &cmd, 800);
815 }
816
817 return ret;
818 }
819
820 static int
821 smu_read_adc(struct smu_softc *sc, int id)
822 {
823 struct smu_cmd cmd;
824 int ret;
825
826 cmd.cmd = SMU_CMD_ADC;
827 cmd.len = 1;
828 cmd.data[0] = id;
829
830 ret = smu_do_cmd(sc, &cmd, 800);
831 if (ret == 0) {
832 return cmd.data[0] << 8 | cmd.data[1];
833 }
834 return -1;
835 }
836
837 static int
838 smu_iicbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *send,
839 size_t send_len, void *recv, size_t recv_len, int flags)
840 {
841 struct smu_iicbus *iicbus = cookie;
842 struct smu_softc *sc = iicbus->sc;
843 struct smu_cmd cmd;
844 int retries, ret;
845
846 DPRINTF("%s: op %x addr %x send_len %d recv_len %d\n",
847 __func__, op, addr, send_len, recv_len);
848
849 cmd.cmd = SMU_CMD_I2C;
850 cmd.len = 9 + recv_len;
851 cmd.data[0] = iicbus->reg;
852 cmd.data[1] = I2C_OP_READ_P(op) ? 0x02 : 0x00;
853 cmd.data[2] = addr << 1;
854 cmd.data[3] = send_len;
855 memcpy(&cmd.data[4], send, send_len);
856 cmd.data[7] = addr << 1;
857 if (I2C_OP_READ_P(op))
858 cmd.data[7] |= 0x01;
859 cmd.data[8] = recv_len;
860 memcpy(&cmd.data[9], recv, recv_len);
861
862 ret = smu_do_cmd(sc, &cmd, 800);
863 if (ret != 0)
864 return (ret);
865
866 for (retries = 0; retries < 10; retries++) {
867 cmd.cmd = SMU_CMD_I2C;
868 cmd.len = 1;
869 cmd.data[0] = 0x00;
870 memset(&cmd.data[1], 0xff, recv_len);
871
872 ret = smu_do_cmd(sc, &cmd, 800);
873
874 DPRINTF("%s: cmd data[0] %x\n", __func__, cmd.data[0]);
875
876 if (ret == 0 && (cmd.data[0] & 0x80) == 0)
877 break;
878
879 DELAY(10000);
880 }
881
882 if (cmd.data[0] & 0x80)
883 return EIO;
884
885 if (I2C_OP_READ_P(op))
886 memcpy(recv, &cmd.data[1], recv_len);
887
888 return 0;
889 }
890
891 static int
892 smu_sysctl_fan_rpm(SYSCTLFN_ARGS)
893 {
894 struct sysctlnode node = *rnode;
895 struct smu_fan *fan = node.sysctl_data;
896 int rpm = 0;
897 int ret;
898
899 node.sysctl_data = &rpm;
900
901 if (newp) {
902 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
903 rpm = *(int *) node.sysctl_data;
904 return smu_fan_set_rpm(fan, rpm);
905 }
906 return EINVAL;
907 } else {
908 ret = smu_fan_get_rpm(fan, &rpm);
909 if (ret != 0)
910 return (ret);
911
912 return sysctl_lookup(SYSCTLFN_CALL(&node));
913 }
914
915 return 0;
916 }
917
918 SYSCTL_SETUP(smu_sysctl_setup, "SMU sysctl subtree setup")
919 {
920 sysctl_createv(NULL, 0, NULL, NULL,
921 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
922 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
923 }
924
925 static void
926 smu_setup_zones(struct smu_softc *sc)
927 {
928 struct smu_zone *z;
929 struct smu_fan *f;
930 int i;
931
932 /* find CPU fans */
933 z = &sc->sc_zones[SMU_ZONE_CPUS];
934 z->nfans = 0;
935 for (i = 0; i < SMU_MAX_FANS; i++) {
936 f = &sc->sc_fans[i];
937 if ((strstr(f->location, "CPU") != NULL) ||
938 (strstr(f->location, "System") != NULL)) {
939 z->fans[z->nfans] = i;
940 z->nfans++;
941 }
942 }
943 aprint_normal_dev(sc->sc_dev,
944 "using %d fans for CPU zone\n", z->nfans);
945 z->threshold = C_TO_uK(45);
946 z->duty = 150;
947 z->step = 3;
948 z->filter = is_cpu_sensor;
949
950 z = &sc->sc_zones[SMU_ZONE_DRIVES];
951 z->nfans = 0;
952 for (i = 0; i < SMU_MAX_FANS; i++) {
953 f = &sc->sc_fans[i];
954 if ((strstr(f->location, "DRIVE") != NULL) ||
955 (strstr(f->location, "Drive") != NULL)) {
956 z->fans[z->nfans] = i;
957 z->nfans++;
958 }
959 }
960 aprint_normal_dev(sc->sc_dev,
961 "using %d fans for drive bay zone\n", z->nfans);
962 z->threshold = C_TO_uK(40);
963 z->duty = 150;
964 z->step = 2;
965 z->filter = is_drive_sensor;
966
967 z = &sc->sc_zones[SMU_ZONE_SLOTS];
968 z->nfans = 0;
969 for (i = 0; i < SMU_MAX_FANS; i++) {
970 f = &sc->sc_fans[i];
971 if ((strstr(f->location, "BACKSIDE") != NULL) ||
972 (strstr(f->location, "SLOTS") != NULL)) {
973 z->fans[z->nfans] = i;
974 z->nfans++;
975 }
976 }
977 aprint_normal_dev(sc->sc_dev,
978 "using %d fans for expansion slots zone\n", z->nfans);
979 z->threshold = C_TO_uK(40);
980 z->duty = 150;
981 z->step = 2;
982 z->filter = is_slots_sensor;
983
984 sc->sc_dying = false;
985 kthread_create(PRI_NONE, 0, curcpu(), smu_adjust, sc, &sc->sc_thread,
986 "fan control");
987 }
988
989 static void
990 smu_adjust_zone(struct smu_softc *sc, int which)
991 {
992 struct smu_zone *z = &sc->sc_zones[which];
993 struct smu_fan *f;
994 long temp, newduty, i, speed, diff;
995
996 DPRINTF("%s %d\n", __func__, which);
997
998 temp = sysmon_envsys_get_max_value(z->filter, true);
999 if (temp == 0) {
1000 /* no sensor data - leave fan alone */
1001 DPRINTF("nodata\n");
1002 return;
1003 }
1004 DPRINTF("temp %ld ", (temp - 273150000) / 1000000);
1005 diff = ((temp - z->threshold) / 1000000) * z->step;
1006
1007 if (diff < 0) newduty = 0;
1008 else if (diff > 100) newduty = 100;
1009 else newduty = diff;
1010
1011 DPRINTF("newduty %ld diff %ld \n", newduty, diff);
1012 if (newduty == z->duty) {
1013 DPRINTF("no change\n");
1014 return;
1015 }
1016 z->duty = newduty;
1017 /* now adjust each fan to the new duty cycle */
1018 for (i = 0; i < z->nfans; i++) {
1019 f = &sc->sc_fans[z->fans[i]];
1020 speed = f->min_rpm + ((f->max_rpm - f->min_rpm) * newduty) / 100;
1021 DPRINTF("fan %d speed %ld ", z->fans[i], speed);
1022 smu_fan_set_rpm(f, speed);
1023 }
1024 DPRINTF("\n");
1025 }
1026
1027 static void
1028 smu_adjust(void *cookie)
1029 {
1030 struct smu_softc *sc = cookie;
1031 int i;
1032
1033 while (!sc->sc_dying) {
1034 for (i = 0; i < SMU_ZONES; i++)
1035 smu_adjust_zone(sc, i);
1036 kpause("fanctrl", true, mstohz(3000), NULL);
1037 }
1038 kthread_exit(0);
1039 }
1040
1041 static bool is_cpu_sensor(const envsys_data_t *edata)
1042 {
1043 if (edata->units != ENVSYS_STEMP)
1044 return false;
1045 if (strstr(edata->desc, "CPU") != NULL)
1046 return TRUE;
1047 return false;
1048 }
1049
1050 static bool is_drive_sensor(const envsys_data_t *edata)
1051 {
1052 if (edata->units != ENVSYS_STEMP)
1053 return false;
1054 if (strstr(edata->desc, "DRIVE") != NULL)
1055 return TRUE;
1056 if (strstr(edata->desc, "drive") != NULL)
1057 return TRUE;
1058 return false;
1059 }
1060
1061 static bool is_slots_sensor(const envsys_data_t *edata)
1062 {
1063 if (edata->units != ENVSYS_STEMP)
1064 return false;
1065 if (strstr(edata->desc, "BACKSIDE") != NULL)
1066 return TRUE;
1067 if (strstr(edata->desc, "INLET") != NULL)
1068 return TRUE;
1069 if (strstr(edata->desc, "DIODE") != NULL)
1070 return TRUE;
1071 if (strstr(edata->desc, "TUNNEL") != NULL)
1072 return TRUE;
1073 return false;
1074 }
1075
1076 int
1077 smu_get_datablock(int id, uint8_t *buf, size_t len)
1078 {
1079 struct smu_cmd cmd;
1080
1081 cmd.cmd = SMU_PARTITION;
1082 cmd.len = 2;
1083 cmd.data[0] = SMU_PARTITION_LATEST;
1084 cmd.data[1] = id;
1085 smu_do_cmd(smu0, &cmd, 100);
1086
1087 cmd.data[4] = cmd.data[0];
1088 cmd.data[5] = cmd.data[1];
1089
1090 cmd.cmd = SMU_MISC;
1091 cmd.len = 7;
1092 cmd.data[0] = SMU_MISC_GET_DATA;
1093 cmd.data[1] = 4;
1094 cmd.data[2] = 0;
1095 cmd.data[3] = 0;
1096 cmd.data[6] = len;
1097 smu_do_cmd(smu0, &cmd, 100);
1098
1099 memcpy(buf, cmd.data, len);
1100 return 0;
1101 }
1102