summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2022-03-15 18:46:16 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2022-03-15 18:46:16 +0000
commit4adf9bcfaf6f3b7c4e888a50963497bcdc292613 (patch)
treea36dbcce3056ea549710529821f7b32ef0d04c40 /sys/arch
parent4e3f18c2cecdcf338924009fd61eac5e317c2d49 (diff)
Implement additional error checking for aplsmc_read_key() such that we can
detect when we read a key that isn't supported by the firmware. Only provide RTC functionality if the "CLKM" key is implemented. Fixes reading the time on machines with old SMC firmware from macOS 11.x. ok jsg@
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/arm64/dev/aplsmc.c40
1 files changed, 31 insertions, 9 deletions
diff --git a/sys/arch/arm64/dev/aplsmc.c b/sys/arch/arm64/dev/aplsmc.c
index bfb466a67a8..c5c9a2c793b 100644
--- a/sys/arch/arm64/dev/aplsmc.c
+++ b/sys/arch/arm64/dev/aplsmc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aplsmc.c,v 1.9 2022/03/02 12:44:48 kettenis Exp $ */
+/* $OpenBSD: aplsmc.c,v 1.10 2022/03/15 18:46:15 kettenis Exp $ */
/*
* Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
*
@@ -37,22 +37,23 @@
extern void (*cpuresetfn)(void);
+/* SMC mailbox endpoint */
#define SMC_EP 32
+/* SMC commands */
#define SMC_READ_KEY 0x10
#define SMC_WRITE_KEY 0x11
#define SMC_GET_KEY_BY_INDEX 0x12
#define SMC_GET_KEY_INFO 0x13
#define SMC_GET_SRAM_ADDR 0x17
+#define SMC_SRAM_SIZE 0x4000
+/* SMC errors */
#define SMC_ERROR(d) ((d) & 0xff)
#define SMC_OK 0x00
#define SMC_KEYNOTFOUND 0x84
-#define SMC_SRAM_SIZE 0x4000
-
-#define SMC_GPIO_CMD_OUTPUT (0x01 << 24)
-
+/* SMC keys */
#define SMC_KEY(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
struct smc_key_info {
@@ -61,6 +62,13 @@ struct smc_key_info {
uint8_t flags;
};
+/* SMC GPIO commands */
+#define SMC_GPIO_CMD_OUTPUT (0x01 << 24)
+
+/* RTC related constants */
+#define RTC_OFFSET_LEN 6
+#define SMC_CLKM_LEN 6
+
struct aplsmc_sensor {
const char *key;
const char *key_type;
@@ -163,6 +171,7 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux)
{
struct aplsmc_softc *sc = (struct aplsmc_softc *)self;
struct fdt_attach_args *faa = aux;
+ uint8_t data[SMC_CLKM_LEN];
int error, node;
#ifndef SMALL_KERNEL
int i;
@@ -221,8 +230,14 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux)
gpio_controller_register(&sc->sc_gc);
}
+ /*
+ * Only provide TODR implementation if the "CLKM" key is
+ * supported by the SMC firmware.
+ */
+ error = aplsmc_read_key(sc, SMC_KEY("CLKM"), &data, SMC_CLKM_LEN);
+
node = OF_getnodebyname(faa->fa_node, "rtc");
- if (node) {
+ if (node && error == 0) {
sc->sc_rtc_node = node;
sc->sc_todr.cookie = sc;
sc->sc_todr.todr_gettime = aplsmc_gettime;
@@ -336,6 +351,16 @@ aplsmc_read_key(struct aplsmc_softc *sc, uint32_t key, void *data, size_t len)
error = aplsmc_wait_cmd(sc);
if (error)
return error;
+ switch (SMC_ERROR(sc->sc_data)) {
+ case SMC_OK:
+ break;
+ case SMC_KEYNOTFOUND:
+ return EINVAL;
+ break;
+ default:
+ return EIO;
+ break;
+ }
len = min(len, (sc->sc_data >> 16) & 0xffff);
if (len > sizeof(uint32_t)) {
@@ -507,9 +532,6 @@ aplsmc_set_pin(void *cookie, uint32_t *cells, int val)
aplsmc_write_key(sc, key, &data, sizeof(data));
}
-#define RTC_OFFSET_LEN 6
-#define SMC_CLKM_LEN 6
-
int
aplsmc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
{