1 /* $OpenBSD: apldcp.c,v 1.3 2024/08/18 10:50:22 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2023 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/pool.h> 22 23 #include <machine/intr.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/fdt.h> 29 #include <dev/ofw/ofw_power.h> 30 #include <dev/ofw/ofw_clock.h> 31 32 static const void *of_device_get_match_data(const struct device *); 33 34 #include "dcp.c" 35 36 struct apldcp_softc { 37 struct platform_device sc_dev; 38 }; 39 40 int apldcp_match(struct device *, void *, void *); 41 void apldcp_attach(struct device *, struct device *, void *); 42 int apldcp_activate(struct device *, int); 43 44 const struct cfattach apldcp_ca = { 45 sizeof (struct apldcp_softc), apldcp_match, apldcp_attach, 46 NULL, apldcp_activate 47 }; 48 49 struct cfdriver apldcp_cd = { 50 NULL, "apldcp", DV_DULL 51 }; 52 53 int 54 apldcp_match(struct device *parent, void *match, void *aux) 55 { 56 struct fdt_attach_args *faa = aux; 57 58 return OF_is_compatible(faa->fa_node, "apple,dcp") || 59 OF_is_compatible(faa->fa_node, "apple,dcpext"); 60 } 61 62 void 63 apldcp_attach(struct device *parent, struct device *self, void *aux) 64 { 65 struct apldcp_softc *sc = (struct apldcp_softc *)self; 66 struct fdt_attach_args *faa = aux; 67 68 power_domain_enable(faa->fa_node); 69 reset_deassert_all(faa->fa_node); 70 71 printf("\n"); 72 73 sc->sc_dev.faa = faa; 74 platform_device_register(&sc->sc_dev); 75 76 dcp_platform_probe(&sc->sc_dev); 77 } 78 79 int 80 apldcp_activate(struct device *self, int act) 81 { 82 int rv; 83 84 switch (act) { 85 case DVACT_QUIESCE: 86 rv = config_activate_children(self, act); 87 dcp_platform_suspend(self); 88 break; 89 case DVACT_WAKEUP: 90 dcp_platform_resume(self); 91 rv = config_activate_children(self, act); 92 break; 93 default: 94 rv = config_activate_children(self, act); 95 break; 96 } 97 98 return rv; 99 } 100 101 /* 102 * Linux RTKit interfaces. 103 */ 104 105 #include <arm64/dev/rtkit.h> 106 107 struct apple_rtkit_task { 108 struct apple_rtkit_ep *rtkep; 109 struct task task; 110 uint64_t msg; 111 }; 112 113 struct apple_rtkit_ep { 114 struct apple_rtkit *rtk; 115 uint8_t ep; 116 }; 117 118 struct apple_rtkit { 119 struct rtkit_state *state; 120 struct apple_rtkit_ep ep[64]; 121 void *cookie; 122 struct platform_device *pdev; 123 const struct apple_rtkit_ops *ops; 124 struct pool task_pool; 125 struct taskq *tq; 126 }; 127 128 paddr_t 129 apple_rtkit_logmap(void *cookie, bus_addr_t addr) 130 { 131 struct apple_rtkit *rtk = cookie; 132 int idx, len, node; 133 uint32_t *phandles; 134 uint32_t iommu_addresses[5]; 135 bus_addr_t start; 136 bus_size_t size; 137 uint64_t reg[2]; 138 139 len = OF_getproplen(rtk->pdev->node, "memory-region"); 140 idx = OF_getindex(rtk->pdev->node, "dcp_data", "memory-region-names"); 141 if (idx < 0 || idx >= len / sizeof(uint32_t)) 142 return addr; 143 144 phandles = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 145 OF_getpropintarray(rtk->pdev->node, "memory-region", 146 phandles, len); 147 node = OF_getnodebyphandle(phandles[idx]); 148 free(phandles, M_TEMP, len); 149 150 if (node == 0) 151 return addr; 152 153 if (!OF_is_compatible(node, "apple,asc-mem")) 154 return addr; 155 156 if (OF_getpropint64array(node, "reg", reg, sizeof(reg)) != sizeof(reg)) 157 return addr; 158 159 if (OF_getpropintarray(node, "iommu-addresses", iommu_addresses, 160 sizeof(iommu_addresses)) < sizeof(iommu_addresses)) 161 return addr; 162 start = (uint64_t)iommu_addresses[1] << 32 | iommu_addresses[2]; 163 size = (uint64_t)iommu_addresses[3] << 32 | iommu_addresses[4]; 164 if (addr >= start && addr < start + size) 165 return reg[0] + (addr - start); 166 167 /* XXX some machines have truncated DVAs in "iommu-addresses" */ 168 addr &= 0xffffffff; 169 if (addr >= start && addr < start + size) 170 return reg[0] + (addr - start); 171 172 return (paddr_t)-1; 173 } 174 175 void 176 apple_rtkit_do_recv(void *arg) 177 { 178 struct apple_rtkit_task *rtktask = arg; 179 struct apple_rtkit_ep *rtkep = rtktask->rtkep; 180 struct apple_rtkit *rtk = rtkep->rtk; 181 182 rtk->ops->recv_message(rtk->cookie, rtkep->ep, rtktask->msg); 183 pool_put(&rtk->task_pool, rtktask); 184 } 185 186 void 187 apple_rtkit_recv(void *cookie, uint64_t msg) 188 { 189 struct apple_rtkit_ep *rtkep = cookie; 190 struct apple_rtkit *rtk = rtkep->rtk; 191 struct apple_rtkit_task *rtktask; 192 193 rtktask = pool_get(&rtk->task_pool, PR_NOWAIT | PR_ZERO); 194 KASSERT(rtktask != NULL); 195 196 rtktask->rtkep = rtkep; 197 rtktask->msg = msg; 198 task_set(&rtktask->task, apple_rtkit_do_recv, rtktask); 199 task_add(rtk->tq, &rtktask->task); 200 } 201 202 int 203 apple_rtkit_start_ep(struct apple_rtkit *rtk, uint8_t ep) 204 { 205 struct apple_rtkit_ep *rtkep; 206 int error; 207 208 rtkep = &rtk->ep[ep]; 209 rtkep->rtk = rtk; 210 rtkep->ep = ep; 211 error = rtkit_start_endpoint(rtk->state, ep, apple_rtkit_recv, rtkep); 212 return -error; 213 } 214 215 int 216 apple_rtkit_send_message(struct apple_rtkit *rtk, uint8_t ep, uint64_t msg, 217 struct completion *completion, int atomic) 218 { 219 int error; 220 221 error = rtkit_send_endpoint(rtk->state, ep, msg); 222 return -error; 223 } 224 225 int 226 apple_rtkit_wake(struct apple_rtkit *rtk) 227 { 228 int error; 229 230 error = rtkit_set_iop_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_INIT); 231 if (error) 232 return -error; 233 234 error = rtkit_set_ap_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_ON); 235 return -error; 236 } 237 238 struct apple_rtkit * 239 devm_apple_rtkit_init(struct device *dev, void *cookie, 240 const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops) 241 { 242 struct platform_device *pdev = (struct platform_device *)dev; 243 struct apple_rtkit *rtk; 244 struct rtkit *rk; 245 246 rtk = malloc(sizeof(*rtk), M_DEVBUF, M_WAITOK | M_ZERO); 247 rtk->tq = taskq_create("drmrtk", 1, IPL_HIGH, 0); 248 if (rtk->tq == NULL) { 249 free(rtk, M_DEVBUF, sizeof(*rtk)); 250 return ERR_PTR(ENOMEM); 251 } 252 253 pool_init(&rtk->task_pool, sizeof(struct apple_rtkit_task), 0, IPL_TTY, 254 0, "apldcp_rtkit", NULL); 255 256 rk = malloc(sizeof(*rk), M_DEVBUF, M_WAITOK | M_ZERO); 257 rk->rk_cookie = rtk; 258 rk->rk_dmat = pdev->dmat; 259 rk->rk_logmap = apple_rtkit_logmap; 260 261 rtk->state = rtkit_init(pdev->node, mbox_name, 0, rk); 262 rtk->cookie = cookie; 263 rtk->pdev = pdev; 264 rtk->ops = ops; 265 266 return rtk; 267 } 268 269 static const void * 270 of_device_get_match_data(const struct device *dev) 271 { 272 struct platform_device *pdev = (struct platform_device *)dev; 273 int i; 274 275 for (i = 0; i < nitems(of_match); i++) { 276 if (OF_is_compatible(pdev->node, of_match[i].compatible)) 277 return of_match[i].data; 278 } 279 280 return NULL; 281 } 282