diff options
-rw-r--r-- | arch/arm/include/asm/arch-apple/rtkit.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-apple/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-apple/rtkit.c | 234 | ||||
-rw-r--r-- | arch/arm/mach-apple/rtkit_helper.c | 145 |
4 files changed, 333 insertions, 52 deletions
diff --git a/arch/arm/include/asm/arch-apple/rtkit.h b/arch/arm/include/asm/arch-apple/rtkit.h index eff18ddb9d2..4b11e2a72dc 100644 --- a/arch/arm/include/asm/arch-apple/rtkit.h +++ b/arch/arm/include/asm/arch-apple/rtkit.h @@ -12,6 +12,7 @@ struct apple_rtkit_buffer { u64 dva; size_t size; bool is_mapped; + int endpoint; }; typedef int (*apple_rtkit_shmem_setup)(void *cookie, @@ -26,4 +27,8 @@ struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie, apple_rtkit_shmem_destroy shmem_destroy); void apple_rtkit_free(struct apple_rtkit *rtk); int apple_rtkit_boot(struct apple_rtkit *rtk); +int apple_rtkit_set_ap_power(struct apple_rtkit *rtk, int pwrstate); +int apple_rtkit_poll(struct apple_rtkit *rtk, ulong timeout); int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate); + +int apple_rtkit_helper_poll(struct udevice *dev, ulong timeout); diff --git a/arch/arm/mach-apple/Makefile b/arch/arm/mach-apple/Makefile index 50b465b9473..d79a3a69592 100644 --- a/arch/arm/mach-apple/Makefile +++ b/arch/arm/mach-apple/Makefile @@ -3,4 +3,5 @@ obj-y += board.o obj-y += lowlevel_init.o obj-y += rtkit.o +obj-$(CONFIG_APPLE_MTP_KEYB) += rtkit_helper.o obj-$(CONFIG_NVME_APPLE) += sart.o diff --git a/arch/arm/mach-apple/rtkit.c b/arch/arm/mach-apple/rtkit.c index b8f4771e5e7..f3561543a35 100644 --- a/arch/arm/mach-apple/rtkit.c +++ b/arch/arm/mach-apple/rtkit.c @@ -11,6 +11,7 @@ #include <linux/apple-mailbox.h> #include <linux/bitfield.h> #include <linux/errno.h> +#include <linux/sizes.h> #include <linux/types.h> #define APPLE_RTKIT_EP_MGMT 0 @@ -18,6 +19,7 @@ #define APPLE_RTKIT_EP_SYSLOG 2 #define APPLE_RTKIT_EP_DEBUG 3 #define APPLE_RTKIT_EP_IOREPORT 4 +#define APPLE_RTKIT_EP_OSLOG 8 #define APPLE_RTKIT_EP_TRACEKIT 10 /* Messages for management endpoint. */ @@ -36,6 +38,7 @@ #define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6 #define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7 +#define APPLE_RTKIT_MGMT_SET_AP_PWR_STATE 11 #define APPLE_RTKIT_MGMT_EPMAP 8 #define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51) @@ -45,6 +48,11 @@ #define APPLE_RTKIT_MGMT_EPMAP_REPLY 8 #define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0) +#define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56) +#define APPLE_RTKIT_OSLOG_BUFFER_REQUEST 1 +#define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36) +#define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0) + #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 @@ -64,6 +72,10 @@ struct apple_rtkit { struct apple_rtkit_buffer syslog_buffer; struct apple_rtkit_buffer crashlog_buffer; struct apple_rtkit_buffer ioreport_buffer; + struct apple_rtkit_buffer oslog_buffer; + + int iop_pwr; + int ap_pwr; }; struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie, @@ -93,6 +105,17 @@ void apple_rtkit_free(struct apple_rtkit *rtk) rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer); if (rtk->ioreport_buffer.buffer) rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer); + if (rtk->oslog_buffer.buffer) + rtk->shmem_destroy(rtk->cookie, &rtk->oslog_buffer); + } else { + if (rtk->syslog_buffer.buffer) + free(rtk->syslog_buffer.buffer); + if (rtk->crashlog_buffer.buffer) + free(rtk->crashlog_buffer.buffer); + if (rtk->ioreport_buffer.buffer) + free(rtk->ioreport_buffer.buffer); + if (rtk->oslog_buffer.buffer) + free(rtk->oslog_buffer.buffer); } free(rtk); } @@ -100,16 +123,8 @@ void apple_rtkit_free(struct apple_rtkit *rtk) static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg) { struct apple_rtkit_buffer *buf; - size_t num_4kpages; int ret; - num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0); - - if (num_4kpages == 0) { - printf("%s: unexpected request for buffer without size\n", __func__); - return -1; - } - switch (endpoint) { case APPLE_RTKIT_EP_CRASHLOG: buf = &rtk->crashlog_buffer; @@ -120,14 +135,33 @@ static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct ap case APPLE_RTKIT_EP_IOREPORT: buf = &rtk->ioreport_buffer; break; + case APPLE_RTKIT_EP_OSLOG: + buf = &rtk->oslog_buffer; + break; default: printf("%s: unexpected endpoint %d\n", __func__, endpoint); return -1; } + switch (endpoint) { + case APPLE_RTKIT_EP_OSLOG: + buf->size = FIELD_GET(APPLE_RTKIT_OSLOG_SIZE, msg->msg0); + buf->dva = FIELD_GET(APPLE_RTKIT_OSLOG_IOVA, msg->msg0 << 12); + break; + default: + buf->size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0) << 12; + buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0); + break; + } + + if (buf->size == 0) { + printf("%s: unexpected request for buffer without size\n", __func__); + return -1; + } + buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0); - buf->size = num_4kpages << 12; - buf->is_mapped = false; + buf->is_mapped = !!buf->dva; + buf->endpoint = endpoint; if (rtk->shmem_setup) { ret = rtk->shmem_setup(rtk->cookie, buf); @@ -136,13 +170,27 @@ static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct ap endpoint); return ret; } + } else if (!buf->is_mapped){ + buf->buffer = memalign(SZ_16K, ALIGN(buf->size, SZ_16K)); + if (!buf->buffer) + return -ENOMEM; + + buf->dva = (u64)buf->buffer; } if (!buf->is_mapped) { - msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) | - FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) | - FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva); - msg->msg1 = endpoint; + /* oslog uses different fields */ + if (endpoint == APPLE_RTKIT_EP_OSLOG) { + msg->msg0 = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, + APPLE_RTKIT_OSLOG_BUFFER_REQUEST); + msg->msg0 |= FIELD_PREP(APPLE_RTKIT_OSLOG_SIZE, buf->size); + msg->msg0 |= FIELD_PREP(APPLE_RTKIT_OSLOG_IOVA, buf->dva >> 12); + } else { + msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, + APPLE_RTKIT_BUFFER_REQUEST); + msg->msg0 |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, buf->size >> 12); + msg->msg0 |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva); + } return mbox_send(rtk->chan, msg); } @@ -150,6 +198,89 @@ static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct ap return 0; } +int apple_rtkit_poll(struct apple_rtkit *rtk, ulong timeout) +{ + struct apple_mbox_msg msg; + int ret; + int endpoint; + int msgtype; + + ret = mbox_recv(rtk->chan, &msg, timeout); + if (ret < 0) + return ret; + + endpoint = msg.msg1; + msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0); + + if (endpoint == APPLE_RTKIT_EP_CRASHLOG || + endpoint == APPLE_RTKIT_EP_SYSLOG || + endpoint == APPLE_RTKIT_EP_IOREPORT) { + if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) { + ret = rtkit_handle_buf_req(rtk, endpoint, &msg); + if (ret < 0) + return ret; + return 0; + } + } + + if (endpoint == APPLE_RTKIT_EP_OSLOG) { + msgtype = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg.msg0); + + if (msgtype == APPLE_RTKIT_OSLOG_BUFFER_REQUEST) { + ret = rtkit_handle_buf_req(rtk, endpoint, &msg); + if (ret < 0) + return ret; + return 0; + } else { + /* Ignore */ + return 0; + } + } + + if (endpoint == APPLE_RTKIT_EP_IOREPORT) { + // these two messages have to be ack-ed for proper startup + if (msgtype == 0xc || msgtype == 0x8) { + ret = mbox_send(rtk->chan, &msg); + if (ret < 0) + return ret; + return 0; + } + } + + if (endpoint == APPLE_RTKIT_EP_SYSLOG) { + /* Ignore init */ + if (msgtype == 0x8) + return 0; + + /* Ack logs */ + if (msgtype == 0x5) { + ret = mbox_send(rtk->chan, &msg); + if (ret < 0) + return ret; + return 0; + } + } + + if (endpoint != APPLE_RTKIT_EP_MGMT) { + printf("%s: unexpected endpoint %d\n", __func__, endpoint); + return -EINVAL; + } + + switch (msgtype) { + case APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK: + rtk->iop_pwr = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0); + return 0; + case APPLE_RTKIT_MGMT_SET_AP_PWR_STATE: + rtk->ap_pwr = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0); + return 0; + default: + printf("%s: unexpected message type %d\n", __func__, msgtype); + + /* Just ignore it */ + return 0; + } +} + int apple_rtkit_boot(struct apple_rtkit *rtk) { struct apple_mbox_msg msg; @@ -157,7 +288,7 @@ int apple_rtkit_boot(struct apple_rtkit *rtk) int nendpoints = 0; int endpoint; int min_ver, max_ver, want_ver; - int msgtype, pwrstate; + int msgtype; u64 reply; u32 bitmap, base; int i, ret; @@ -276,46 +407,37 @@ wait_epmap: return ret; } - pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP; - while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) { - ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US); + rtk->iop_pwr = APPLE_RTKIT_PWR_STATE_SLEEP; + rtk->ap_pwr = APPLE_RTKIT_PWR_STATE_QUIESCED; + + while (rtk->iop_pwr != APPLE_RTKIT_PWR_STATE_ON) { + ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US); if (ret < 0) return ret; + } - endpoint = msg.msg1; - msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0); - - if (endpoint == APPLE_RTKIT_EP_CRASHLOG || - endpoint == APPLE_RTKIT_EP_SYSLOG || - endpoint == APPLE_RTKIT_EP_IOREPORT) { - if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) { - ret = rtkit_handle_buf_req(rtk, endpoint, &msg); - if (ret < 0) - return ret; - continue; - } - } + return 0; +} - if (endpoint == APPLE_RTKIT_EP_IOREPORT) { - // these two messages have to be ack-ed for proper startup - if (msgtype == 0xc || msgtype == 0x8) { - ret = mbox_send(rtk->chan, &msg); - if (ret < 0) - return ret; - continue; - } - } +int apple_rtkit_set_ap_power(struct apple_rtkit *rtk, int pwrstate) +{ + struct apple_mbox_msg msg; + int ret; - if (endpoint != APPLE_RTKIT_EP_MGMT) { - printf("%s: unexpected endpoint %d\n", __func__, endpoint); - return -EINVAL; - } - if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) { - printf("%s: unexpected message type %d\n", __func__, msgtype); - return -EINVAL; - } + if (rtk->ap_pwr == pwrstate) + return 0; - pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0); + msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE) | + FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate); + msg.msg1 = APPLE_RTKIT_EP_MGMT; + ret = mbox_send(rtk->chan, &msg); + if (ret < 0) + return ret; + + while (rtk->ap_pwr != pwrstate) { + ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US); + if (ret < 0) + return ret; } return 0; @@ -326,6 +448,12 @@ int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate) struct apple_mbox_msg msg; int ret; + if (rtk->ap_pwr != APPLE_RTKIT_PWR_STATE_QUIESCED) { + ret = apple_rtkit_set_ap_power(rtk, APPLE_RTKIT_PWR_STATE_QUIESCED); + if (ret < 0) + return ret; + } + msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) | FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate); msg.msg1 = APPLE_RTKIT_EP_MGMT; @@ -333,9 +461,11 @@ int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate) if (ret < 0) return ret; - ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US); - if (ret < 0) - return ret; + while (rtk->iop_pwr != pwrstate) { + ret = apple_rtkit_poll(rtk, TIMEOUT_1SEC_US); + if (ret < 0) + return ret; + } return 0; } diff --git a/arch/arm/mach-apple/rtkit_helper.c b/arch/arm/mach-apple/rtkit_helper.c new file mode 100644 index 00000000000..b7d60e15700 --- /dev/null +++ b/arch/arm/mach-apple/rtkit_helper.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright The Asahi Linux Contributors + */ + +#include <dm.h> +#include <mailbox.h> +#include <mapmem.h> +#include <reset.h> + +#include <asm/io.h> +#include <asm/arch/rtkit.h> +#include <linux/iopoll.h> + +/* ASC registers */ +#define REG_CPU_CTRL 0x0044 +#define REG_CPU_CTRL_RUN BIT(4) + +#define APPLE_RTKIT_EP_OSLOG 8 + +struct rtkit_helper_priv { + void *asc; /* ASC registers */ + struct mbox_chan chan; + struct apple_rtkit *rtk; + bool sram_stolen; +}; + +static int shmem_setup(void *cookie, struct apple_rtkit_buffer *buf) { + struct udevice *dev = cookie; + struct rtkit_helper_priv *priv = dev_get_priv(dev); + + if (!buf->is_mapped) { + /* + * Special case: The OSLog buffer on MTP persists on Linux handoff. + * Steal some SRAM instead of putting this in DRAM, so we don't + * have to hand off DART/DAPF mappings. + */ + if (buf->endpoint == APPLE_RTKIT_EP_OSLOG) { + if (priv->sram_stolen) { + printf("%s: Tried to map more than one OSLog buffer out of SRAM\n", + __func__); + } else { + fdt_size_t size; + fdt_addr_t addr; + + addr = dev_read_addr_size_name(dev, "sram", &size); + + if (addr != FDT_ADDR_T_NONE) { + buf->dva = ALIGN_DOWN(addr + size - buf->size, SZ_16K); + priv->sram_stolen = true; + + return 0; + } else { + printf("%s: No SRAM, falling back to DRAM\n", __func__); + } + } + } + + buf->buffer = memalign(SZ_16K, ALIGN(buf->size, SZ_16K)); + if (!buf->buffer) + return -ENOMEM; + + buf->dva = (u64)buf->buffer; + } + return 0; +} + +static void shmem_destroy(void *cookie, struct apple_rtkit_buffer *buf) { + if (buf->buffer) + free(buf->buffer); +} + +static int rtkit_helper_probe(struct udevice *dev) +{ + struct rtkit_helper_priv *priv = dev_get_priv(dev); + u32 ctrl; + int ret; + + priv->asc = dev_read_addr_ptr(dev); + if (!priv->asc) + return -EINVAL; + + ret = mbox_get_by_index(dev, 0, &priv->chan); + if (ret < 0) + return ret; + + ctrl = readl(priv->asc + REG_CPU_CTRL); + writel(ctrl | REG_CPU_CTRL_RUN, priv->asc + REG_CPU_CTRL); + + priv->rtk = apple_rtkit_init(&priv->chan, dev, shmem_setup, shmem_destroy); + if (!priv->rtk) + return -ENOMEM; + + ret = apple_rtkit_boot(priv->rtk); + if (ret < 0) { + printf("%s: Helper apple_rtkit_boot returned: %d\n", __func__, ret); + return ret; + } + + ret = apple_rtkit_set_ap_power(priv->rtk, APPLE_RTKIT_PWR_STATE_ON); + if (ret < 0) { + printf("%s: Helper apple_rtkit_set_ap_power returned: %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static int rtkit_helper_remove(struct udevice *dev) +{ + struct rtkit_helper_priv *priv = dev_get_priv(dev); + u32 ctrl; + + apple_rtkit_shutdown(priv->rtk, APPLE_RTKIT_PWR_STATE_QUIESCED); + + ctrl = readl(priv->asc + REG_CPU_CTRL); + writel(ctrl & ~REG_CPU_CTRL_RUN, priv->asc + REG_CPU_CTRL); + + apple_rtkit_free(priv->rtk); + priv->rtk = NULL; + + return 0; +} + +int apple_rtkit_helper_poll(struct udevice *dev, ulong timeout) +{ + struct rtkit_helper_priv *priv = dev_get_priv(dev); + + return apple_rtkit_poll(priv->rtk, timeout); +} + +static const struct udevice_id rtkit_helper_ids[] = { + { .compatible = "apple,rtk-helper-asc4" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(rtkit_helper) = { + .name = "rtkit_helper", + .id = UCLASS_MISC, + .of_match = rtkit_helper_ids, + .priv_auto = sizeof(struct rtkit_helper_priv), + .probe = rtkit_helper_probe, + .remove = rtkit_helper_remove, + .flags = DM_FLAG_OS_PREPARE, +}; |