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