1*e24fbf55Stobhe /* $OpenBSD: apldcp.c,v 1.2 2024/07/12 10:01:28 tobhe Exp $ */ 25dd0baa8Skettenis /* 35dd0baa8Skettenis * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org> 45dd0baa8Skettenis * 55dd0baa8Skettenis * Permission to use, copy, modify, and distribute this software for any 65dd0baa8Skettenis * purpose with or without fee is hereby granted, provided that the above 75dd0baa8Skettenis * copyright notice and this permission notice appear in all copies. 85dd0baa8Skettenis * 95dd0baa8Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 105dd0baa8Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 115dd0baa8Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 125dd0baa8Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 135dd0baa8Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 145dd0baa8Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 155dd0baa8Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 165dd0baa8Skettenis */ 175dd0baa8Skettenis 185dd0baa8Skettenis #include <sys/param.h> 195dd0baa8Skettenis #include <sys/systm.h> 205dd0baa8Skettenis #include <sys/device.h> 21*e24fbf55Stobhe #include <sys/pool.h> 225dd0baa8Skettenis 235dd0baa8Skettenis #include <machine/intr.h> 245dd0baa8Skettenis #include <machine/bus.h> 255dd0baa8Skettenis #include <machine/fdt.h> 265dd0baa8Skettenis 275dd0baa8Skettenis #include <dev/ofw/openfirm.h> 285dd0baa8Skettenis #include <dev/ofw/fdt.h> 295dd0baa8Skettenis #include <dev/ofw/ofw_power.h> 305dd0baa8Skettenis #include <dev/ofw/ofw_clock.h> 315dd0baa8Skettenis 325dd0baa8Skettenis static const void *of_device_get_match_data(const struct device *); 335dd0baa8Skettenis 345dd0baa8Skettenis #include "dcp.c" 355dd0baa8Skettenis 365dd0baa8Skettenis struct apldcp_softc { 375dd0baa8Skettenis struct platform_device sc_dev; 385dd0baa8Skettenis }; 395dd0baa8Skettenis 405dd0baa8Skettenis int apldcp_match(struct device *, void *, void *); 415dd0baa8Skettenis void apldcp_attach(struct device *, struct device *, void *); 425dd0baa8Skettenis int apldcp_activate(struct device *, int); 435dd0baa8Skettenis 445dd0baa8Skettenis const struct cfattach apldcp_ca = { 455dd0baa8Skettenis sizeof (struct apldcp_softc), apldcp_match, apldcp_attach, 465dd0baa8Skettenis NULL, apldcp_activate 475dd0baa8Skettenis }; 485dd0baa8Skettenis 495dd0baa8Skettenis struct cfdriver apldcp_cd = { 505dd0baa8Skettenis NULL, "apldcp", DV_DULL 515dd0baa8Skettenis }; 525dd0baa8Skettenis 535dd0baa8Skettenis int 545dd0baa8Skettenis apldcp_match(struct device *parent, void *match, void *aux) 555dd0baa8Skettenis { 565dd0baa8Skettenis struct fdt_attach_args *faa = aux; 575dd0baa8Skettenis 585dd0baa8Skettenis return OF_is_compatible(faa->fa_node, "apple,dcp") || 595dd0baa8Skettenis OF_is_compatible(faa->fa_node, "apple,dcpext"); 605dd0baa8Skettenis } 615dd0baa8Skettenis 625dd0baa8Skettenis void 635dd0baa8Skettenis apldcp_attach(struct device *parent, struct device *self, void *aux) 645dd0baa8Skettenis { 655dd0baa8Skettenis struct apldcp_softc *sc = (struct apldcp_softc *)self; 665dd0baa8Skettenis struct fdt_attach_args *faa = aux; 675dd0baa8Skettenis 685dd0baa8Skettenis power_domain_enable(faa->fa_node); 695dd0baa8Skettenis reset_deassert_all(faa->fa_node); 705dd0baa8Skettenis 715dd0baa8Skettenis printf("\n"); 725dd0baa8Skettenis 735dd0baa8Skettenis sc->sc_dev.faa = faa; 745dd0baa8Skettenis platform_device_register(&sc->sc_dev); 755dd0baa8Skettenis 765dd0baa8Skettenis dcp_platform_probe(&sc->sc_dev); 775dd0baa8Skettenis } 785dd0baa8Skettenis 795dd0baa8Skettenis int 805dd0baa8Skettenis apldcp_activate(struct device *self, int act) 815dd0baa8Skettenis { 825dd0baa8Skettenis int rv; 835dd0baa8Skettenis 845dd0baa8Skettenis switch (act) { 855dd0baa8Skettenis case DVACT_QUIESCE: 865dd0baa8Skettenis rv = config_activate_children(self, act); 875dd0baa8Skettenis dcp_platform_suspend(self); 885dd0baa8Skettenis break; 895dd0baa8Skettenis case DVACT_WAKEUP: 905dd0baa8Skettenis dcp_platform_resume(self); 915dd0baa8Skettenis rv = config_activate_children(self, act); 925dd0baa8Skettenis break; 935dd0baa8Skettenis default: 945dd0baa8Skettenis rv = config_activate_children(self, act); 955dd0baa8Skettenis break; 965dd0baa8Skettenis } 975dd0baa8Skettenis 985dd0baa8Skettenis return rv; 995dd0baa8Skettenis } 1005dd0baa8Skettenis 1015dd0baa8Skettenis /* 1025dd0baa8Skettenis * Linux RTKit interfaces. 1035dd0baa8Skettenis */ 1045dd0baa8Skettenis 1055dd0baa8Skettenis #include <arm64/dev/rtkit.h> 1065dd0baa8Skettenis 107*e24fbf55Stobhe struct apple_rtkit_task { 108*e24fbf55Stobhe struct apple_rtkit_ep *rtkep; 1095dd0baa8Skettenis struct task task; 1105dd0baa8Skettenis uint64_t msg; 1115dd0baa8Skettenis }; 1125dd0baa8Skettenis 113*e24fbf55Stobhe struct apple_rtkit_ep { 114*e24fbf55Stobhe struct apple_rtkit *rtk; 115*e24fbf55Stobhe uint8_t ep; 116*e24fbf55Stobhe }; 117*e24fbf55Stobhe 118*e24fbf55Stobhe static struct pool rtktask_pool; 119*e24fbf55Stobhe 1205dd0baa8Skettenis struct apple_rtkit { 1215dd0baa8Skettenis struct rtkit_state *state; 1225dd0baa8Skettenis struct apple_rtkit_ep ep[64]; 1235dd0baa8Skettenis void *cookie; 1245dd0baa8Skettenis struct platform_device *pdev; 1255dd0baa8Skettenis const struct apple_rtkit_ops *ops; 1265dd0baa8Skettenis struct taskq *tq; 1275dd0baa8Skettenis }; 1285dd0baa8Skettenis 1295dd0baa8Skettenis paddr_t 1305dd0baa8Skettenis apple_rtkit_logmap(void *cookie, bus_addr_t addr) 1315dd0baa8Skettenis { 1325dd0baa8Skettenis struct apple_rtkit *rtk = cookie; 1335dd0baa8Skettenis int idx, len, node; 1345dd0baa8Skettenis uint32_t *phandles; 1355dd0baa8Skettenis uint32_t iommu_addresses[5]; 1365dd0baa8Skettenis bus_addr_t start; 1375dd0baa8Skettenis bus_size_t size; 1385dd0baa8Skettenis uint64_t reg[2]; 1395dd0baa8Skettenis 1405dd0baa8Skettenis len = OF_getproplen(rtk->pdev->node, "memory-region"); 1415dd0baa8Skettenis idx = OF_getindex(rtk->pdev->node, "dcp_data", "memory-region-names"); 1425dd0baa8Skettenis if (idx < 0 || idx >= len / sizeof(uint32_t)) 1435dd0baa8Skettenis return addr; 1445dd0baa8Skettenis 1455dd0baa8Skettenis phandles = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 1465dd0baa8Skettenis OF_getpropintarray(rtk->pdev->node, "memory-region", 1475dd0baa8Skettenis phandles, len); 1485dd0baa8Skettenis node = OF_getnodebyphandle(phandles[idx]); 1495dd0baa8Skettenis free(phandles, M_TEMP, len); 1505dd0baa8Skettenis 1515dd0baa8Skettenis if (node == 0) 1525dd0baa8Skettenis return addr; 1535dd0baa8Skettenis 1545dd0baa8Skettenis if (!OF_is_compatible(node, "apple,asc-mem")) 1555dd0baa8Skettenis return addr; 1565dd0baa8Skettenis 1575dd0baa8Skettenis if (OF_getpropint64array(node, "reg", reg, sizeof(reg)) != sizeof(reg)) 1585dd0baa8Skettenis return addr; 1595dd0baa8Skettenis 1605dd0baa8Skettenis if (OF_getpropintarray(node, "iommu-addresses", iommu_addresses, 1615dd0baa8Skettenis sizeof(iommu_addresses)) < sizeof(iommu_addresses)) 1625dd0baa8Skettenis return addr; 1635dd0baa8Skettenis start = (uint64_t)iommu_addresses[1] << 32 | iommu_addresses[2]; 1645dd0baa8Skettenis size = (uint64_t)iommu_addresses[3] << 32 | iommu_addresses[4]; 1655dd0baa8Skettenis if (addr >= start && addr < start + size) 1665dd0baa8Skettenis return reg[0] + (addr - start); 1675dd0baa8Skettenis 1685dd0baa8Skettenis /* XXX some machines have truncated DVAs in "iommu-addresses" */ 1695dd0baa8Skettenis addr &= 0xffffffff; 1705dd0baa8Skettenis if (addr >= start && addr < start + size) 1715dd0baa8Skettenis return reg[0] + (addr - start); 1725dd0baa8Skettenis 1735dd0baa8Skettenis return (paddr_t)-1; 1745dd0baa8Skettenis } 1755dd0baa8Skettenis 1765dd0baa8Skettenis void 1775dd0baa8Skettenis apple_rtkit_do_recv(void *arg) 1785dd0baa8Skettenis { 179*e24fbf55Stobhe struct apple_rtkit_task *rtktask = arg; 180*e24fbf55Stobhe struct apple_rtkit_ep *rtkep = rtktask->rtkep; 1815dd0baa8Skettenis struct apple_rtkit *rtk = rtkep->rtk; 1825dd0baa8Skettenis 183*e24fbf55Stobhe rtk->ops->recv_message(rtk->cookie, rtkep->ep, rtktask->msg); 184*e24fbf55Stobhe pool_put(&rtktask_pool, rtktask); 1855dd0baa8Skettenis } 1865dd0baa8Skettenis 1875dd0baa8Skettenis void 1885dd0baa8Skettenis apple_rtkit_recv(void *cookie, uint64_t msg) 1895dd0baa8Skettenis { 1905dd0baa8Skettenis struct apple_rtkit_ep *rtkep = cookie; 1915dd0baa8Skettenis struct apple_rtkit *rtk = rtkep->rtk; 192*e24fbf55Stobhe struct apple_rtkit_task *rtktask; 1935dd0baa8Skettenis 194*e24fbf55Stobhe rtktask = pool_get(&rtktask_pool, PR_NOWAIT | PR_ZERO); 195*e24fbf55Stobhe KASSERT(rtktask != NULL); 196*e24fbf55Stobhe 197*e24fbf55Stobhe rtktask->rtkep = rtkep; 198*e24fbf55Stobhe rtktask->msg = msg; 199*e24fbf55Stobhe task_set(&rtktask->task, apple_rtkit_do_recv, rtktask); 200*e24fbf55Stobhe task_add(rtk->tq, &rtktask->task); 2015dd0baa8Skettenis } 2025dd0baa8Skettenis 2035dd0baa8Skettenis int 2045dd0baa8Skettenis apple_rtkit_start_ep(struct apple_rtkit *rtk, uint8_t ep) 2055dd0baa8Skettenis { 2065dd0baa8Skettenis struct apple_rtkit_ep *rtkep; 2075dd0baa8Skettenis int error; 2085dd0baa8Skettenis 2095dd0baa8Skettenis rtkep = &rtk->ep[ep]; 2105dd0baa8Skettenis rtkep->rtk = rtk; 2115dd0baa8Skettenis rtkep->ep = ep; 2125dd0baa8Skettenis error = rtkit_start_endpoint(rtk->state, ep, apple_rtkit_recv, rtkep); 2135dd0baa8Skettenis return -error; 2145dd0baa8Skettenis } 2155dd0baa8Skettenis 2165dd0baa8Skettenis int 2175dd0baa8Skettenis apple_rtkit_send_message(struct apple_rtkit *rtk, uint8_t ep, uint64_t msg, 2185dd0baa8Skettenis struct completion *completion, int atomic) 2195dd0baa8Skettenis { 2205dd0baa8Skettenis int error; 2215dd0baa8Skettenis 2225dd0baa8Skettenis error = rtkit_send_endpoint(rtk->state, ep, msg); 2235dd0baa8Skettenis return -error; 2245dd0baa8Skettenis } 2255dd0baa8Skettenis 2265dd0baa8Skettenis int 2275dd0baa8Skettenis apple_rtkit_wake(struct apple_rtkit *rtk) 2285dd0baa8Skettenis { 2295dd0baa8Skettenis int error; 2305dd0baa8Skettenis 2315dd0baa8Skettenis error = rtkit_set_iop_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_INIT); 2325dd0baa8Skettenis if (error) 2335dd0baa8Skettenis return -error; 2345dd0baa8Skettenis 2355dd0baa8Skettenis error = rtkit_set_ap_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_ON); 2365dd0baa8Skettenis return -error; 2375dd0baa8Skettenis } 2385dd0baa8Skettenis 2395dd0baa8Skettenis struct apple_rtkit * 2405dd0baa8Skettenis devm_apple_rtkit_init(struct device *dev, void *cookie, 2415dd0baa8Skettenis const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops) 2425dd0baa8Skettenis { 2435dd0baa8Skettenis struct platform_device *pdev = (struct platform_device *)dev; 2445dd0baa8Skettenis struct apple_rtkit *rtk; 2455dd0baa8Skettenis struct rtkit *rk; 2465dd0baa8Skettenis 2475dd0baa8Skettenis rtk = malloc(sizeof(*rtk), M_DEVBUF, M_WAITOK | M_ZERO); 2485dd0baa8Skettenis rtk->tq = taskq_create("drmrtk", 1, IPL_HIGH, 0); 2495dd0baa8Skettenis if (rtk->tq == NULL) { 2505dd0baa8Skettenis free(rtk, M_DEVBUF, sizeof(*rtk)); 2515dd0baa8Skettenis return ERR_PTR(ENOMEM); 2525dd0baa8Skettenis } 2535dd0baa8Skettenis 254*e24fbf55Stobhe pool_init(&rtktask_pool, sizeof(struct apple_rtkit_task), 0, IPL_TTY, 255*e24fbf55Stobhe 0, "apldcp_rtkit", NULL); 256*e24fbf55Stobhe 2575dd0baa8Skettenis rk = malloc(sizeof(*rk), M_DEVBUF, M_WAITOK | M_ZERO); 2585dd0baa8Skettenis rk->rk_cookie = rtk; 2595dd0baa8Skettenis rk->rk_dmat = pdev->dmat; 2605dd0baa8Skettenis rk->rk_logmap = apple_rtkit_logmap; 2615dd0baa8Skettenis 2625dd0baa8Skettenis rtk->state = rtkit_init(pdev->node, mbox_name, 0, rk); 2635dd0baa8Skettenis rtk->cookie = cookie; 2645dd0baa8Skettenis rtk->pdev = pdev; 2655dd0baa8Skettenis rtk->ops = ops; 2665dd0baa8Skettenis 2675dd0baa8Skettenis return rtk; 2685dd0baa8Skettenis } 2695dd0baa8Skettenis 2705dd0baa8Skettenis static const void * 2715dd0baa8Skettenis of_device_get_match_data(const struct device *dev) 2725dd0baa8Skettenis { 2735dd0baa8Skettenis struct platform_device *pdev = (struct platform_device *)dev; 2745dd0baa8Skettenis int i; 2755dd0baa8Skettenis 2765dd0baa8Skettenis for (i = 0; i < nitems(of_match); i++) { 2775dd0baa8Skettenis if (OF_is_compatible(pdev->node, of_match[i].compatible)) 2785dd0baa8Skettenis return of_match[i].data; 2795dd0baa8Skettenis } 2805dd0baa8Skettenis 2815dd0baa8Skettenis return NULL; 2825dd0baa8Skettenis } 283