xref: /openbsd-src/sys/arch/arm64/dev/aplsmc.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /*	$OpenBSD: aplsmc.c,v 1.12 2022/06/12 16:00:12 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/sensors.h>
22 
23 #include <machine/apmvar.h>
24 #include <machine/bus.h>
25 #include <machine/fdt.h>
26 
27 #include <dev/clock_subr.h>
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/ofw_gpio.h>
30 #include <dev/ofw/ofw_misc.h>
31 #include <dev/ofw/fdt.h>
32 
33 #include <arm64/dev/aplmbox.h>
34 #include <arm64/dev/rtkit.h>
35 
36 #include "apm.h"
37 
38 extern void (*cpuresetfn)(void);
39 extern void (*powerdownfn)(void);
40 
41 /* SMC mailbox endpoint */
42 #define SMC_EP			32
43 
44 /* SMC commands */
45 #define SMC_READ_KEY		0x10
46 #define SMC_WRITE_KEY		0x11
47 #define SMC_GET_KEY_BY_INDEX	0x12
48 #define SMC_GET_KEY_INFO	0x13
49 #define SMC_GET_SRAM_ADDR	0x17
50 #define  SMC_SRAM_SIZE		0x4000
51 
52 /* SMC errors */
53 #define SMC_ERROR(d)		((d) & 0xff)
54 #define SMC_OK			0x00
55 #define SMC_KEYNOTFOUND		0x84
56 
57 /* SMC keys */
58 #define SMC_KEY(s)	((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
59 
60 struct smc_key_info {
61 	uint8_t		size;
62 	uint8_t		type[4];
63 	uint8_t		flags;
64 };
65 
66 /* SMC GPIO commands */
67 #define SMC_GPIO_CMD_OUTPUT	(0x01 << 24)
68 
69 /* RTC related constants */
70 #define RTC_OFFSET_LEN		6
71 #define SMC_CLKM_LEN		6
72 
73 struct aplsmc_sensor {
74 	const char	*key;
75 	const char	*key_type;
76 	enum sensor_type type;
77 	int		scale;
78 	const char	*desc;
79 	int		flags;
80 };
81 
82 #define APLSMC_BE		(1 << 0)
83 #define APLSMC_HIDDEN		(1 << 1)
84 
85 #define APLSMC_MAX_SENSORS	19
86 
87 struct aplsmc_softc {
88 	struct device		sc_dev;
89 	bus_space_tag_t		sc_iot;
90 	bus_space_handle_t	sc_ioh;
91 	bus_space_handle_t	sc_sram_ioh;
92 
93 	void			*sc_ih;
94 
95 	struct rtkit_state	*sc_rs;
96 	uint8_t			sc_msgid;
97 	uint64_t		sc_data;
98 
99 	struct gpio_controller	sc_gc;
100 
101 	int			sc_rtc_node;
102 	struct todr_chip_handle sc_todr;
103 
104 	int			sc_reboot_node;
105 
106 	struct aplsmc_sensor	*sc_smcsensors[APLSMC_MAX_SENSORS];
107 	struct ksensor		sc_sensors[APLSMC_MAX_SENSORS];
108 	int			sc_nsensors;
109 	struct ksensordev	sc_sensordev;
110 };
111 
112 struct aplsmc_softc *aplsmc_sc;
113 
114 #ifndef SMALL_KERNEL
115 
116 struct aplsmc_sensor aplsmc_sensors[] = {
117 	{ "ACDI", "ui16", SENSOR_INDICATOR, 1, "power supply" },
118 	{ "B0RM", "ui16", SENSOR_AMPHOUR, 1000, "remaining battery capacity",
119 	  APLSMC_BE },
120 	{ "B0FC", "ui16", SENSOR_AMPHOUR, 1000, "last full battery capacity" },
121 	{ "B0DC", "ui16", SENSOR_AMPHOUR, 1000, "battery design capacity" },
122 	{ "B0AV", "ui16", SENSOR_VOLTS_DC, 1000, "battery" },
123 	{ "B0CT", "ui16", SENSOR_INTEGER, 1, "battery discharge cycles" },
124 	{ "B0TF", "ui16", SENSOR_INTEGER, 1, "battery time-to-full",
125 	  APLSMC_HIDDEN },
126 	{ "B0TE", "ui16", SENSOR_INTEGER, 1, "battery time-to-empty",
127 	  APLSMC_HIDDEN },
128 	{ "F0Ac", "flt ", SENSOR_FANRPM, 1, "" },
129 	{ "ID0R", "flt ", SENSOR_AMPS, 1000000, "input" },
130 	{ "PDTR", "flt ", SENSOR_WATTS, 1000000, "input" },
131 	{ "PSTR", "flt ", SENSOR_WATTS, 1000000, "system" },
132 	{ "TB0T", "flt ", SENSOR_TEMP, 1000000, "battery" },
133 	{ "TCHP", "flt ", SENSOR_TEMP, 1000000, "charger" },
134 	{ "TW0P", "flt ", SENSOR_TEMP, 1000000, "wireless" },
135 	{ "Ts0P", "flt ", SENSOR_TEMP, 1000000, "palm rest" },
136 	{ "Ts1P", "flt ", SENSOR_TEMP, 1000000, "palm rest" },
137 	{ "VD0R", "flt ", SENSOR_VOLTS_DC, 1000000, "input" },
138 };
139 
140 #endif
141 
142 int	aplsmc_match(struct device *, void *, void *);
143 void	aplsmc_attach(struct device *, struct device *, void *);
144 
145 const struct cfattach aplsmc_ca = {
146 	sizeof (struct aplsmc_softc), aplsmc_match, aplsmc_attach
147 };
148 
149 struct cfdriver aplsmc_cd = {
150 	NULL, "aplsmc", DV_DULL
151 };
152 
153 void	aplsmc_callback(void *, uint64_t);
154 int	aplsmc_send_cmd(struct aplsmc_softc *, uint16_t, uint32_t, uint16_t);
155 int	aplsmc_wait_cmd(struct aplsmc_softc *sc);
156 int	aplsmc_read_key(struct aplsmc_softc *, uint32_t, void *, size_t);
157 void	aplsmc_refresh_sensors(void *);
158 int	aplsmc_apminfo(struct apm_power_info *);
159 void	aplsmc_set_pin(void *, uint32_t *, int);
160 int	aplsmc_gettime(struct todr_chip_handle *, struct timeval *);
161 int	aplsmc_settime(struct todr_chip_handle *, struct timeval *);
162 void	aplsmc_reset(void);
163 void	aplsmc_powerdown(void);
164 void	aplsmc_reboot_attachhook(struct device *);
165 
166 int
167 aplsmc_match(struct device *parent, void *match, void *aux)
168 {
169 	struct fdt_attach_args *faa = aux;
170 
171 	return OF_is_compatible(faa->fa_node, "apple,smc");
172 }
173 
174 void
175 aplsmc_attach(struct device *parent, struct device *self, void *aux)
176 {
177 	struct aplsmc_softc *sc = (struct aplsmc_softc *)self;
178 	struct fdt_attach_args *faa = aux;
179 	uint8_t data[SMC_CLKM_LEN];
180 	int error, node;
181 #ifndef SMALL_KERNEL
182 	int i;
183 #endif
184 
185 	if (faa->fa_nreg < 1) {
186 		printf(": no registers\n");
187 		return;
188 	}
189 
190 	sc->sc_iot = faa->fa_iot;
191 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
192 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
193 		printf(": can't map registers\n");
194 		return;
195 	}
196 
197 	sc->sc_rs = rtkit_init(faa->fa_node, NULL, NULL);
198 	if (sc->sc_rs == NULL) {
199 		printf(": can't map mailbox channel\n");
200 		return;
201 	}
202 
203 	error = rtkit_boot(sc->sc_rs);
204 	if (error) {
205 		printf(": can't boot firmware\n");
206 		return;
207 	}
208 
209 	error = rtkit_start_endpoint(sc->sc_rs, SMC_EP, aplsmc_callback, sc);
210 	if (error) {
211 		printf(": can't start SMC endpoint\n");
212 		return;
213 	}
214 
215 	aplsmc_send_cmd(sc, SMC_GET_SRAM_ADDR, 0, 0);
216 	error = aplsmc_wait_cmd(sc);
217 	if (error) {
218 		printf(": can't get SRAM address\n");
219 		return;
220 	}
221 
222 	if (bus_space_map(sc->sc_iot, sc->sc_data,
223 	    SMC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) {
224 		printf(": can't map SRAM\n");
225 		return;
226 	}
227 
228 	printf("\n");
229 
230 	aplsmc_sc = sc;
231 
232 	node = OF_getnodebyname(faa->fa_node, "gpio");
233 	if (node) {
234 		sc->sc_gc.gc_node = node;
235 		sc->sc_gc.gc_cookie = sc;
236 		sc->sc_gc.gc_set_pin = aplsmc_set_pin;
237 		gpio_controller_register(&sc->sc_gc);
238 	}
239 
240 	/*
241 	 * Only provide TODR implementation if the "CLKM" key is
242 	 * supported by the SMC firmware.
243 	 */
244 	error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN);
245 	node = OF_getnodebyname(faa->fa_node, "rtc");
246 	if (node && error == 0) {
247 		sc->sc_rtc_node = node;
248 		sc->sc_todr.cookie = sc;
249 		sc->sc_todr.todr_gettime = aplsmc_gettime;
250 		sc->sc_todr.todr_settime = aplsmc_settime;
251 		todr_attach(&sc->sc_todr);
252 	}
253 
254 	node = OF_getnodebyname(faa->fa_node, "reboot");
255 	if (node) {
256 		sc->sc_reboot_node = node;
257 		cpuresetfn = aplsmc_reset;
258 		powerdownfn = aplsmc_powerdown;
259 		config_mountroot(self, aplsmc_reboot_attachhook);
260 	}
261 
262 #ifndef SMALL_KERNEL
263 
264 	for (i = 0; i < nitems(aplsmc_sensors); i++) {
265 		struct smc_key_info info;
266 
267 		aplsmc_send_cmd(sc, SMC_GET_KEY_INFO,
268 		    SMC_KEY(aplsmc_sensors[i].key), 0);
269 		error = aplsmc_wait_cmd(sc);
270 		if (error || SMC_ERROR(sc->sc_data) != SMC_OK)
271 			continue;
272 
273 		bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0,
274 		    (uint8_t *)&info, sizeof(info));
275 
276 		/* Skip if the key type doesn't match. */
277 		if (memcmp(aplsmc_sensors[i].key_type, info.type,
278 		    sizeof(info.type)) != 0)
279 			continue;
280 
281 		if (sc->sc_nsensors >= APLSMC_MAX_SENSORS) {
282 			printf("%s: maximum number of sensors exceeded\n",
283 			    sc->sc_dev.dv_xname);
284 			break;
285 		}
286 
287 		sc->sc_smcsensors[sc->sc_nsensors] = &aplsmc_sensors[i];
288 		strlcpy(sc->sc_sensors[sc->sc_nsensors].desc,
289 		    aplsmc_sensors[i].desc, sizeof(sc->sc_sensors[0].desc));
290 		sc->sc_sensors[sc->sc_nsensors].type = aplsmc_sensors[i].type;
291 		if (!(aplsmc_sensors[i].flags & APLSMC_HIDDEN)) {
292 			sensor_attach(&sc->sc_sensordev,
293 			    &sc->sc_sensors[sc->sc_nsensors]);
294 		}
295 		sc->sc_nsensors++;
296 	}
297 
298 	aplsmc_refresh_sensors(sc);
299 
300 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
301 	    sizeof(sc->sc_sensordev.xname));
302 	sensordev_install(&sc->sc_sensordev);
303 	sensor_task_register(sc, aplsmc_refresh_sensors, 5);
304 
305 #if NAPM > 0
306 	apm_setinfohook(aplsmc_apminfo);
307 #endif
308 
309 #endif
310 }
311 
312 void
313 aplsmc_callback(void *arg, uint64_t data)
314 {
315 	struct aplsmc_softc *sc = arg;
316 
317 	sc->sc_data = data;
318 	wakeup(&sc->sc_data);
319 }
320 
321 int
322 aplsmc_send_cmd(struct aplsmc_softc *sc, uint16_t cmd, uint32_t key,
323     uint16_t len)
324 {
325 	uint64_t data;
326 
327 	data = cmd;
328 	data |= (uint64_t)len << 16;
329 	data |= (uint64_t)key << 32;
330 	data |= (sc->sc_msgid++ & 0xf) << 12;
331 
332 	return rtkit_send_endpoint(sc->sc_rs, SMC_EP, data);
333 }
334 
335 int
336 aplsmc_wait_cmd(struct aplsmc_softc *sc)
337 {
338 	if (cold) {
339 		int error, timo;
340 
341 		/* Poll for completion. */
342 		for (timo = 1000; timo > 0; timo--) {
343 			error = rtkit_poll(sc->sc_rs);
344 			if (error == 0)
345 				return 0;
346 			delay(10);
347 		}
348 
349 		return EWOULDBLOCK;
350 	}
351 
352 	/* Sleep until the callback wakes us up. */
353 	return tsleep_nsec(&sc->sc_data, PWAIT, "apsmc", 10000000);
354 }
355 
356 int
357 aplsmc_read_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len)
358 {
359 	int error;
360 
361 	aplsmc_send_cmd(sc, SMC_READ_KEY, key, len);
362 	error = aplsmc_wait_cmd(sc);
363 	if (error)
364 		return error;
365 	switch (SMC_ERROR(sc->sc_data)) {
366 	case SMC_OK:
367 		break;
368 	case SMC_KEYNOTFOUND:
369 		return EINVAL;
370 		break;
371 	default:
372 		return EIO;
373 		break;
374 	}
375 
376 	len = min(len, (sc->sc_data >> 16) & 0xffff);
377 	if (len > sizeof(uint32_t)) {
378 		bus_space_read_region_1(sc->sc_iot, sc->sc_sram_ioh, 0,
379 		    data, len);
380 	} else {
381 		uint32_t tmp = (sc->sc_data >> 32);
382 		memcpy(data, &tmp, len);
383 	}
384 
385 	return 0;
386 }
387 
388 int
389 aplsmc_write_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len)
390 {
391 	bus_space_write_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, data, len);
392 	bus_space_barrier(sc->sc_iot, sc->sc_sram_ioh, 0, len,
393 	    BUS_SPACE_BARRIER_WRITE);
394 	aplsmc_send_cmd(sc, SMC_WRITE_KEY, key, len);
395 	return aplsmc_wait_cmd(sc);
396 }
397 
398 #ifndef SMALL_KERNEL
399 
400 void
401 aplsmc_refresh_sensors(void *arg)
402 {
403 	extern int hw_power;
404 	struct aplsmc_softc *sc = arg;
405 	struct aplsmc_sensor *sensor;
406 	int64_t value;
407 	uint32_t key;
408 	int i, error;
409 
410 	for (i = 0; i < sc->sc_nsensors; i++) {
411 		sensor = sc->sc_smcsensors[i];
412 		key = SMC_KEY(sensor->key);
413 
414 		if (strcmp(sensor->key_type, "ui8 ") == 0) {
415 			uint8_t ui8;
416 
417 			error = aplsmc_read_key(sc, key, &ui8, sizeof(ui8));
418 			value = (int64_t)ui8 * sensor->scale;
419 		} else if (strcmp(sensor->key_type, "ui16") == 0) {
420 			uint16_t ui16;
421 
422 			error = aplsmc_read_key(sc, key, &ui16, sizeof(ui16));
423 			if (sensor->flags & APLSMC_BE)
424 				ui16 = betoh16(ui16);
425 			value = (int64_t)ui16 * sensor->scale;
426 		} else if (strcmp(sensor->key_type, "flt ") == 0) {
427 			uint32_t flt;
428 			int64_t mant;
429 			int sign, exp;
430 
431 			error = aplsmc_read_key(sc, key, &flt, sizeof(flt));
432 			if (sensor->flags & APLSMC_BE)
433 				flt = betoh32(flt);
434 
435 			/*
436 			 * Convert floating-point to integer, trying
437 			 * to keep as much resolution as possible
438 			 * given the scaling factor for this sensor.
439 			 */
440 			sign = (flt >> 31) ? -1 : 1;
441 			exp = ((flt >> 23) & 0xff) - 127;
442 			mant = (flt & 0x7fffff) | 0x800000;
443 			mant *= sensor->scale;
444 			if (exp < 23)
445 				value = sign * (mant >> (23 - exp));
446 			else
447 				value = sign * (mant << (exp - 23));
448 		}
449 
450 		/* Apple reports temperatures in degC. */
451 		if (sensor->type == SENSOR_TEMP)
452 			value += 273150000;
453 
454 		if (error) {
455 			sc->sc_sensors[i].flags |= SENSOR_FUNKNOWN;
456 		} else {
457 			sc->sc_sensors[i].flags &= ~SENSOR_FUNKNOWN;
458 			sc->sc_sensors[i].value = value;
459 		}
460 
461 		if (strcmp(sensor->key, "ACDI") == 0)
462 			hw_power = (value > 0);
463 	}
464 }
465 
466 #if NAPM > 0
467 
468 int
469 aplsmc_apminfo(struct apm_power_info *info)
470 {
471 	struct aplsmc_sensor *sensor;
472 	struct ksensor *ksensor;
473 	struct aplsmc_softc *sc = aplsmc_sc;
474 	int remaining = -1, capacity = -1, i;
475 
476 	info->battery_state = APM_BATT_UNKNOWN;
477 	info->ac_state = APM_AC_UNKNOWN;
478 	info->battery_life = 0;
479 	info->minutes_left = -1;
480 
481 	for (i = 0; i < sc->sc_nsensors; i++) {
482 		sensor = sc->sc_smcsensors[i];
483 		ksensor = &sc->sc_sensors[i];
484 
485 		if (ksensor->flags & SENSOR_FUNKNOWN)
486 			continue;
487 
488 		if (strcmp(sensor->key, "ACDI") == 0) {
489 			info->ac_state = ksensor->value ?
490 				APM_AC_ON : APM_AC_OFF;
491 		} else if (strcmp(sensor->key, "B0RM") == 0)
492 			remaining = ksensor->value;
493 		else if (strcmp(sensor->key, "B0FC") == 0)
494 			capacity = ksensor->value;
495 		else if ((strcmp(sensor->key, "B0TE") == 0) &&
496 			 (ksensor->value != 0xffff))
497 			info->minutes_left = ksensor->value;
498 		else if ((strcmp(sensor->key, "B0TF") == 0) &&
499 			 (ksensor->value != 0xffff)) {
500 			info->battery_state = APM_BATT_CHARGING;
501 			info->minutes_left = ksensor->value;
502 		}
503 	}
504 
505 	/* calculate remaining battery if we have sane values */
506 	if (remaining > -1 && capacity > 0) {
507 		info->battery_life = ((remaining * 100) / capacity);
508 		if (info->battery_state != APM_BATT_CHARGING) {
509 			if (info->battery_life > 50)
510 				info->battery_state = APM_BATT_HIGH;
511 			else if (info->battery_life > 25)
512 				info->battery_state = APM_BATT_LOW;
513 			else
514 				info->battery_state = APM_BATT_CRITICAL;
515 		}
516 	}
517 
518 	return 0;
519 }
520 
521 #endif
522 #endif
523 
524 void
525 aplsmc_set_pin(void *cookie, uint32_t *cells, int val)
526 {
527 	struct aplsmc_softc *sc = cookie;
528 	static char *digits = "0123456789abcdef";
529 	uint32_t pin = cells[0];
530 	uint32_t flags = cells[1];
531 	uint32_t key = SMC_KEY("gP\0\0");
532 	uint32_t data;
533 
534 	KASSERT(pin < 256);
535 
536 	key |= (digits[(pin >> 0) & 0xf] << 0);
537 	key |= (digits[(pin >> 4) & 0xf] << 8);
538 
539 	if (flags & GPIO_ACTIVE_LOW)
540 		val = !val;
541 	data = SMC_GPIO_CMD_OUTPUT | !!val;
542 
543 	aplsmc_write_key(sc, key, &data, sizeof(data));
544 }
545 
546 int
547 aplsmc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
548 {
549 	struct aplsmc_softc *sc = handle->cookie;
550 	uint8_t data[8] = {};
551 	uint64_t offset, time;
552 	int error;
553 
554 	error = nvmem_read_cell(sc->sc_rtc_node, "rtc_offset", &data,
555 	    RTC_OFFSET_LEN);
556 	if (error)
557 		return error;
558 	offset = lemtoh64(data);
559 
560 	error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN);
561 	if (error)
562 		return error;
563 	time = lemtoh64(data) + offset;
564 
565 	tv->tv_sec = (time >> 15);
566 	tv->tv_usec = (((time & 0x7fff) * 1000000) >> 15);
567 	return 0;
568 }
569 
570 int
571 aplsmc_settime(struct todr_chip_handle *handle, struct timeval *tv)
572 {
573 	struct aplsmc_softc *sc = handle->cookie;
574 	uint8_t data[8] = {};
575 	uint64_t offset, time;
576 	int error;
577 
578 	error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN);
579 	if (error)
580 		return error;
581 
582 	time = ((uint64_t)tv->tv_sec << 15);
583 	time |= ((uint64_t)tv->tv_usec << 15) / 1000000;
584 	offset = time - lemtoh64(data);
585 
586 	htolem64(data, offset);
587 	return nvmem_write_cell(sc->sc_rtc_node, "rtc_offset", &data,
588 	    RTC_OFFSET_LEN);
589 }
590 
591 void
592 aplsmc_reboot_attachhook(struct device *self)
593 {
594 	struct aplsmc_softc *sc = (struct aplsmc_softc *)self;
595 	uint8_t count = 0;
596 
597 	/* Reset error counters. */
598 	nvmem_write_cell(sc->sc_reboot_node, "boot_error_count",
599 	    &count, sizeof(count));
600 	nvmem_write_cell(sc->sc_reboot_node, "panic_count",
601 	    &count, sizeof(count));
602 }
603 
604 void
605 aplsmc_reset(void)
606 {
607 	struct aplsmc_softc *sc = aplsmc_sc;
608 	uint32_t key = SMC_KEY("MBSE");
609 	uint32_t rest = SMC_KEY("rest");
610 	uint32_t phra = SMC_KEY("phra");
611 	uint8_t boot_stage = 0;
612 
613 	aplsmc_write_key(sc, key, &rest, sizeof(rest));
614 	nvmem_write_cell(sc->sc_reboot_node, "boot_stage",
615 	    &boot_stage, sizeof(boot_stage));
616 	aplsmc_write_key(sc, key, &phra, sizeof(phra));
617 }
618 
619 void
620 aplsmc_powerdown(void)
621 {
622 	struct aplsmc_softc *sc = aplsmc_sc;
623 	uint32_t key = SMC_KEY("MBSE");
624 	uint32_t offw = SMC_KEY("offw");
625 	uint32_t off1 = SMC_KEY("off1");
626 	uint8_t boot_stage = 0;
627 	uint8_t shutdown_flag = 1;
628 
629 	aplsmc_write_key(sc, key, &offw, sizeof(offw));
630 	nvmem_write_cell(sc->sc_reboot_node, "boot_stage",
631 	    &boot_stage, sizeof(boot_stage));
632 	nvmem_write_cell(sc->sc_reboot_node, "shutdown_flag",
633 	    &shutdown_flag, sizeof(shutdown_flag));
634 	aplsmc_write_key(sc, key, &off1, sizeof(off1));
635 }
636