1 /* $OpenBSD: apldcp.c,v 1.2 2024/07/12 10:01:28 tobhe 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 static struct pool rtktask_pool; 119 120 struct apple_rtkit { 121 struct rtkit_state *state; 122 struct apple_rtkit_ep ep[64]; 123 void *cookie; 124 struct platform_device *pdev; 125 const struct apple_rtkit_ops *ops; 126 struct taskq *tq; 127 }; 128 129 paddr_t 130 apple_rtkit_logmap(void *cookie, bus_addr_t addr) 131 { 132 struct apple_rtkit *rtk = cookie; 133 int idx, len, node; 134 uint32_t *phandles; 135 uint32_t iommu_addresses[5]; 136 bus_addr_t start; 137 bus_size_t size; 138 uint64_t reg[2]; 139 140 len = OF_getproplen(rtk->pdev->node, "memory-region"); 141 idx = OF_getindex(rtk->pdev->node, "dcp_data", "memory-region-names"); 142 if (idx < 0 || idx >= len / sizeof(uint32_t)) 143 return addr; 144 145 phandles = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 146 OF_getpropintarray(rtk->pdev->node, "memory-region", 147 phandles, len); 148 node = OF_getnodebyphandle(phandles[idx]); 149 free(phandles, M_TEMP, len); 150 151 if (node == 0) 152 return addr; 153 154 if (!OF_is_compatible(node, "apple,asc-mem")) 155 return addr; 156 157 if (OF_getpropint64array(node, "reg", reg, sizeof(reg)) != sizeof(reg)) 158 return addr; 159 160 if (OF_getpropintarray(node, "iommu-addresses", iommu_addresses, 161 sizeof(iommu_addresses)) < sizeof(iommu_addresses)) 162 return addr; 163 start = (uint64_t)iommu_addresses[1] << 32 | iommu_addresses[2]; 164 size = (uint64_t)iommu_addresses[3] << 32 | iommu_addresses[4]; 165 if (addr >= start && addr < start + size) 166 return reg[0] + (addr - start); 167 168 /* XXX some machines have truncated DVAs in "iommu-addresses" */ 169 addr &= 0xffffffff; 170 if (addr >= start && addr < start + size) 171 return reg[0] + (addr - start); 172 173 return (paddr_t)-1; 174 } 175 176 void 177 apple_rtkit_do_recv(void *arg) 178 { 179 struct apple_rtkit_task *rtktask = arg; 180 struct apple_rtkit_ep *rtkep = rtktask->rtkep; 181 struct apple_rtkit *rtk = rtkep->rtk; 182 183 rtk->ops->recv_message(rtk->cookie, rtkep->ep, rtktask->msg); 184 pool_put(&rtktask_pool, rtktask); 185 } 186 187 void 188 apple_rtkit_recv(void *cookie, uint64_t msg) 189 { 190 struct apple_rtkit_ep *rtkep = cookie; 191 struct apple_rtkit *rtk = rtkep->rtk; 192 struct apple_rtkit_task *rtktask; 193 194 rtktask = pool_get(&rtktask_pool, PR_NOWAIT | PR_ZERO); 195 KASSERT(rtktask != NULL); 196 197 rtktask->rtkep = rtkep; 198 rtktask->msg = msg; 199 task_set(&rtktask->task, apple_rtkit_do_recv, rtktask); 200 task_add(rtk->tq, &rtktask->task); 201 } 202 203 int 204 apple_rtkit_start_ep(struct apple_rtkit *rtk, uint8_t ep) 205 { 206 struct apple_rtkit_ep *rtkep; 207 int error; 208 209 rtkep = &rtk->ep[ep]; 210 rtkep->rtk = rtk; 211 rtkep->ep = ep; 212 error = rtkit_start_endpoint(rtk->state, ep, apple_rtkit_recv, rtkep); 213 return -error; 214 } 215 216 int 217 apple_rtkit_send_message(struct apple_rtkit *rtk, uint8_t ep, uint64_t msg, 218 struct completion *completion, int atomic) 219 { 220 int error; 221 222 error = rtkit_send_endpoint(rtk->state, ep, msg); 223 return -error; 224 } 225 226 int 227 apple_rtkit_wake(struct apple_rtkit *rtk) 228 { 229 int error; 230 231 error = rtkit_set_iop_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_INIT); 232 if (error) 233 return -error; 234 235 error = rtkit_set_ap_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_ON); 236 return -error; 237 } 238 239 struct apple_rtkit * 240 devm_apple_rtkit_init(struct device *dev, void *cookie, 241 const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops) 242 { 243 struct platform_device *pdev = (struct platform_device *)dev; 244 struct apple_rtkit *rtk; 245 struct rtkit *rk; 246 247 rtk = malloc(sizeof(*rtk), M_DEVBUF, M_WAITOK | M_ZERO); 248 rtk->tq = taskq_create("drmrtk", 1, IPL_HIGH, 0); 249 if (rtk->tq == NULL) { 250 free(rtk, M_DEVBUF, sizeof(*rtk)); 251 return ERR_PTR(ENOMEM); 252 } 253 254 pool_init(&rtktask_pool, sizeof(struct apple_rtkit_task), 0, IPL_TTY, 255 0, "apldcp_rtkit", NULL); 256 257 rk = malloc(sizeof(*rk), M_DEVBUF, M_WAITOK | M_ZERO); 258 rk->rk_cookie = rtk; 259 rk->rk_dmat = pdev->dmat; 260 rk->rk_logmap = apple_rtkit_logmap; 261 262 rtk->state = rtkit_init(pdev->node, mbox_name, 0, rk); 263 rtk->cookie = cookie; 264 rtk->pdev = pdev; 265 rtk->ops = ops; 266 267 return rtk; 268 } 269 270 static const void * 271 of_device_get_match_data(const struct device *dev) 272 { 273 struct platform_device *pdev = (struct platform_device *)dev; 274 int i; 275 276 for (i = 0; i < nitems(of_match); i++) { 277 if (OF_is_compatible(pdev->node, of_match[i].compatible)) 278 return of_match[i].data; 279 } 280 281 return NULL; 282 } 283