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