Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 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, }; |