xref: /openbsd/sys/dev/pci/drm/apple/apldcp.c (revision e24fbf55)
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