1*ff7b876dSkettenis /* $OpenBSD: apldcp.c,v 1.3 2024/08/18 10:50:22 kettenis 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>
21e24fbf55Stobhe #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
apldcp_match(struct device * parent,void * match,void * aux)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
apldcp_attach(struct device * parent,struct device * self,void * aux)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
apldcp_activate(struct device * self,int act)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
107e24fbf55Stobhe struct apple_rtkit_task {
108e24fbf55Stobhe struct apple_rtkit_ep *rtkep;
1095dd0baa8Skettenis struct task task;
1105dd0baa8Skettenis uint64_t msg;
1115dd0baa8Skettenis };
1125dd0baa8Skettenis
113e24fbf55Stobhe struct apple_rtkit_ep {
114e24fbf55Stobhe struct apple_rtkit *rtk;
115e24fbf55Stobhe uint8_t ep;
116e24fbf55Stobhe };
117e24fbf55Stobhe
1185dd0baa8Skettenis struct apple_rtkit {
1195dd0baa8Skettenis struct rtkit_state *state;
1205dd0baa8Skettenis struct apple_rtkit_ep ep[64];
1215dd0baa8Skettenis void *cookie;
1225dd0baa8Skettenis struct platform_device *pdev;
1235dd0baa8Skettenis const struct apple_rtkit_ops *ops;
124*ff7b876dSkettenis struct pool task_pool;
1255dd0baa8Skettenis struct taskq *tq;
1265dd0baa8Skettenis };
1275dd0baa8Skettenis
1285dd0baa8Skettenis paddr_t
apple_rtkit_logmap(void * cookie,bus_addr_t addr)1295dd0baa8Skettenis apple_rtkit_logmap(void *cookie, bus_addr_t addr)
1305dd0baa8Skettenis {
1315dd0baa8Skettenis struct apple_rtkit *rtk = cookie;
1325dd0baa8Skettenis int idx, len, node;
1335dd0baa8Skettenis uint32_t *phandles;
1345dd0baa8Skettenis uint32_t iommu_addresses[5];
1355dd0baa8Skettenis bus_addr_t start;
1365dd0baa8Skettenis bus_size_t size;
1375dd0baa8Skettenis uint64_t reg[2];
1385dd0baa8Skettenis
1395dd0baa8Skettenis len = OF_getproplen(rtk->pdev->node, "memory-region");
1405dd0baa8Skettenis idx = OF_getindex(rtk->pdev->node, "dcp_data", "memory-region-names");
1415dd0baa8Skettenis if (idx < 0 || idx >= len / sizeof(uint32_t))
1425dd0baa8Skettenis return addr;
1435dd0baa8Skettenis
1445dd0baa8Skettenis phandles = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
1455dd0baa8Skettenis OF_getpropintarray(rtk->pdev->node, "memory-region",
1465dd0baa8Skettenis phandles, len);
1475dd0baa8Skettenis node = OF_getnodebyphandle(phandles[idx]);
1485dd0baa8Skettenis free(phandles, M_TEMP, len);
1495dd0baa8Skettenis
1505dd0baa8Skettenis if (node == 0)
1515dd0baa8Skettenis return addr;
1525dd0baa8Skettenis
1535dd0baa8Skettenis if (!OF_is_compatible(node, "apple,asc-mem"))
1545dd0baa8Skettenis return addr;
1555dd0baa8Skettenis
1565dd0baa8Skettenis if (OF_getpropint64array(node, "reg", reg, sizeof(reg)) != sizeof(reg))
1575dd0baa8Skettenis return addr;
1585dd0baa8Skettenis
1595dd0baa8Skettenis if (OF_getpropintarray(node, "iommu-addresses", iommu_addresses,
1605dd0baa8Skettenis sizeof(iommu_addresses)) < sizeof(iommu_addresses))
1615dd0baa8Skettenis return addr;
1625dd0baa8Skettenis start = (uint64_t)iommu_addresses[1] << 32 | iommu_addresses[2];
1635dd0baa8Skettenis size = (uint64_t)iommu_addresses[3] << 32 | iommu_addresses[4];
1645dd0baa8Skettenis if (addr >= start && addr < start + size)
1655dd0baa8Skettenis return reg[0] + (addr - start);
1665dd0baa8Skettenis
1675dd0baa8Skettenis /* XXX some machines have truncated DVAs in "iommu-addresses" */
1685dd0baa8Skettenis addr &= 0xffffffff;
1695dd0baa8Skettenis if (addr >= start && addr < start + size)
1705dd0baa8Skettenis return reg[0] + (addr - start);
1715dd0baa8Skettenis
1725dd0baa8Skettenis return (paddr_t)-1;
1735dd0baa8Skettenis }
1745dd0baa8Skettenis
1755dd0baa8Skettenis void
apple_rtkit_do_recv(void * arg)1765dd0baa8Skettenis apple_rtkit_do_recv(void *arg)
1775dd0baa8Skettenis {
178e24fbf55Stobhe struct apple_rtkit_task *rtktask = arg;
179e24fbf55Stobhe struct apple_rtkit_ep *rtkep = rtktask->rtkep;
1805dd0baa8Skettenis struct apple_rtkit *rtk = rtkep->rtk;
1815dd0baa8Skettenis
182e24fbf55Stobhe rtk->ops->recv_message(rtk->cookie, rtkep->ep, rtktask->msg);
183*ff7b876dSkettenis pool_put(&rtk->task_pool, rtktask);
1845dd0baa8Skettenis }
1855dd0baa8Skettenis
1865dd0baa8Skettenis void
apple_rtkit_recv(void * cookie,uint64_t msg)1875dd0baa8Skettenis apple_rtkit_recv(void *cookie, uint64_t msg)
1885dd0baa8Skettenis {
1895dd0baa8Skettenis struct apple_rtkit_ep *rtkep = cookie;
1905dd0baa8Skettenis struct apple_rtkit *rtk = rtkep->rtk;
191e24fbf55Stobhe struct apple_rtkit_task *rtktask;
1925dd0baa8Skettenis
193*ff7b876dSkettenis rtktask = pool_get(&rtk->task_pool, PR_NOWAIT | PR_ZERO);
194e24fbf55Stobhe KASSERT(rtktask != NULL);
195e24fbf55Stobhe
196e24fbf55Stobhe rtktask->rtkep = rtkep;
197e24fbf55Stobhe rtktask->msg = msg;
198e24fbf55Stobhe task_set(&rtktask->task, apple_rtkit_do_recv, rtktask);
199e24fbf55Stobhe task_add(rtk->tq, &rtktask->task);
2005dd0baa8Skettenis }
2015dd0baa8Skettenis
2025dd0baa8Skettenis int
apple_rtkit_start_ep(struct apple_rtkit * rtk,uint8_t ep)2035dd0baa8Skettenis apple_rtkit_start_ep(struct apple_rtkit *rtk, uint8_t ep)
2045dd0baa8Skettenis {
2055dd0baa8Skettenis struct apple_rtkit_ep *rtkep;
2065dd0baa8Skettenis int error;
2075dd0baa8Skettenis
2085dd0baa8Skettenis rtkep = &rtk->ep[ep];
2095dd0baa8Skettenis rtkep->rtk = rtk;
2105dd0baa8Skettenis rtkep->ep = ep;
2115dd0baa8Skettenis error = rtkit_start_endpoint(rtk->state, ep, apple_rtkit_recv, rtkep);
2125dd0baa8Skettenis return -error;
2135dd0baa8Skettenis }
2145dd0baa8Skettenis
2155dd0baa8Skettenis int
apple_rtkit_send_message(struct apple_rtkit * rtk,uint8_t ep,uint64_t msg,struct completion * completion,int atomic)2165dd0baa8Skettenis apple_rtkit_send_message(struct apple_rtkit *rtk, uint8_t ep, uint64_t msg,
2175dd0baa8Skettenis struct completion *completion, int atomic)
2185dd0baa8Skettenis {
2195dd0baa8Skettenis int error;
2205dd0baa8Skettenis
2215dd0baa8Skettenis error = rtkit_send_endpoint(rtk->state, ep, msg);
2225dd0baa8Skettenis return -error;
2235dd0baa8Skettenis }
2245dd0baa8Skettenis
2255dd0baa8Skettenis int
apple_rtkit_wake(struct apple_rtkit * rtk)2265dd0baa8Skettenis apple_rtkit_wake(struct apple_rtkit *rtk)
2275dd0baa8Skettenis {
2285dd0baa8Skettenis int error;
2295dd0baa8Skettenis
2305dd0baa8Skettenis error = rtkit_set_iop_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_INIT);
2315dd0baa8Skettenis if (error)
2325dd0baa8Skettenis return -error;
2335dd0baa8Skettenis
2345dd0baa8Skettenis error = rtkit_set_ap_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_ON);
2355dd0baa8Skettenis return -error;
2365dd0baa8Skettenis }
2375dd0baa8Skettenis
2385dd0baa8Skettenis struct apple_rtkit *
devm_apple_rtkit_init(struct device * dev,void * cookie,const char * mbox_name,int mbox_idx,const struct apple_rtkit_ops * ops)2395dd0baa8Skettenis devm_apple_rtkit_init(struct device *dev, void *cookie,
2405dd0baa8Skettenis const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops)
2415dd0baa8Skettenis {
2425dd0baa8Skettenis struct platform_device *pdev = (struct platform_device *)dev;
2435dd0baa8Skettenis struct apple_rtkit *rtk;
2445dd0baa8Skettenis struct rtkit *rk;
2455dd0baa8Skettenis
2465dd0baa8Skettenis rtk = malloc(sizeof(*rtk), M_DEVBUF, M_WAITOK | M_ZERO);
2475dd0baa8Skettenis rtk->tq = taskq_create("drmrtk", 1, IPL_HIGH, 0);
2485dd0baa8Skettenis if (rtk->tq == NULL) {
2495dd0baa8Skettenis free(rtk, M_DEVBUF, sizeof(*rtk));
2505dd0baa8Skettenis return ERR_PTR(ENOMEM);
2515dd0baa8Skettenis }
2525dd0baa8Skettenis
253*ff7b876dSkettenis pool_init(&rtk->task_pool, sizeof(struct apple_rtkit_task), 0, IPL_TTY,
254e24fbf55Stobhe 0, "apldcp_rtkit", NULL);
255e24fbf55Stobhe
2565dd0baa8Skettenis rk = malloc(sizeof(*rk), M_DEVBUF, M_WAITOK | M_ZERO);
2575dd0baa8Skettenis rk->rk_cookie = rtk;
2585dd0baa8Skettenis rk->rk_dmat = pdev->dmat;
2595dd0baa8Skettenis rk->rk_logmap = apple_rtkit_logmap;
2605dd0baa8Skettenis
2615dd0baa8Skettenis rtk->state = rtkit_init(pdev->node, mbox_name, 0, rk);
2625dd0baa8Skettenis rtk->cookie = cookie;
2635dd0baa8Skettenis rtk->pdev = pdev;
2645dd0baa8Skettenis rtk->ops = ops;
2655dd0baa8Skettenis
2665dd0baa8Skettenis return rtk;
2675dd0baa8Skettenis }
2685dd0baa8Skettenis
2695dd0baa8Skettenis static const void *
of_device_get_match_data(const struct device * dev)2705dd0baa8Skettenis of_device_get_match_data(const struct device *dev)
2715dd0baa8Skettenis {
2725dd0baa8Skettenis struct platform_device *pdev = (struct platform_device *)dev;
2735dd0baa8Skettenis int i;
2745dd0baa8Skettenis
2755dd0baa8Skettenis for (i = 0; i < nitems(of_match); i++) {
2765dd0baa8Skettenis if (OF_is_compatible(pdev->node, of_match[i].compatible))
2775dd0baa8Skettenis return of_match[i].data;
2785dd0baa8Skettenis }
2795dd0baa8Skettenis
2805dd0baa8Skettenis return NULL;
2815dd0baa8Skettenis }
282