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