xref: /openbsd/sys/dev/pci/drm/apple/apldcp.c (revision e24fbf55)
1 /*	$OpenBSD: apldcp.c,v 1.2 2024/07/12 10:01:28 tobhe 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
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
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
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 static struct pool rtktask_pool;
119 
120 struct apple_rtkit {
121 	struct rtkit_state *state;
122 	struct apple_rtkit_ep ep[64];
123 	void *cookie;
124 	struct platform_device *pdev;
125 	const struct apple_rtkit_ops *ops;
126 	struct taskq *tq;
127 };
128 
129 paddr_t
130 apple_rtkit_logmap(void *cookie, bus_addr_t addr)
131 {
132 	struct apple_rtkit *rtk = cookie;
133 	int idx, len, node;
134 	uint32_t *phandles;
135 	uint32_t iommu_addresses[5];
136 	bus_addr_t start;
137 	bus_size_t size;
138 	uint64_t reg[2];
139 
140 	len = OF_getproplen(rtk->pdev->node, "memory-region");
141 	idx = OF_getindex(rtk->pdev->node, "dcp_data", "memory-region-names");
142 	if (idx < 0 || idx >= len / sizeof(uint32_t))
143 		return addr;
144 
145 	phandles = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
146 	OF_getpropintarray(rtk->pdev->node, "memory-region",
147 	    phandles, len);
148 	node = OF_getnodebyphandle(phandles[idx]);
149 	free(phandles, M_TEMP, len);
150 
151 	if (node == 0)
152 		return addr;
153 
154 	if (!OF_is_compatible(node, "apple,asc-mem"))
155 		return addr;
156 
157 	if (OF_getpropint64array(node, "reg", reg, sizeof(reg)) != sizeof(reg))
158 		return addr;
159 
160 	if (OF_getpropintarray(node, "iommu-addresses", iommu_addresses,
161 	    sizeof(iommu_addresses)) < sizeof(iommu_addresses))
162 		return addr;
163 	start = (uint64_t)iommu_addresses[1] << 32 | iommu_addresses[2];
164 	size = (uint64_t)iommu_addresses[3] << 32 | iommu_addresses[4];
165 	if (addr >= start && addr < start + size)
166 		return reg[0] + (addr - start);
167 
168 	/* XXX some machines have truncated DVAs in "iommu-addresses" */
169 	addr &= 0xffffffff;
170 	if (addr >= start && addr < start + size)
171 		return reg[0] + (addr - start);
172 
173 	return (paddr_t)-1;
174 }
175 
176 void
177 apple_rtkit_do_recv(void *arg)
178 {
179 	struct apple_rtkit_task *rtktask = arg;
180 	struct apple_rtkit_ep *rtkep = rtktask->rtkep;
181 	struct apple_rtkit *rtk = rtkep->rtk;
182 
183 	rtk->ops->recv_message(rtk->cookie, rtkep->ep, rtktask->msg);
184 	pool_put(&rtktask_pool, rtktask);
185 }
186 
187 void
188 apple_rtkit_recv(void *cookie, uint64_t msg)
189 {
190 	struct apple_rtkit_ep *rtkep = cookie;
191 	struct apple_rtkit *rtk = rtkep->rtk;
192 	struct apple_rtkit_task *rtktask;
193 
194 	rtktask = pool_get(&rtktask_pool, PR_NOWAIT | PR_ZERO);
195 	KASSERT(rtktask != NULL);
196 
197 	rtktask->rtkep = rtkep;
198 	rtktask->msg = msg;
199 	task_set(&rtktask->task, apple_rtkit_do_recv, rtktask);
200 	task_add(rtk->tq, &rtktask->task);
201 }
202 
203 int
204 apple_rtkit_start_ep(struct apple_rtkit *rtk, uint8_t ep)
205 {
206 	struct apple_rtkit_ep *rtkep;
207 	int error;
208 
209 	rtkep = &rtk->ep[ep];
210 	rtkep->rtk = rtk;
211 	rtkep->ep = ep;
212 	error = rtkit_start_endpoint(rtk->state, ep, apple_rtkit_recv, rtkep);
213 	return -error;
214 }
215 
216 int
217 apple_rtkit_send_message(struct apple_rtkit *rtk, uint8_t ep, uint64_t msg,
218 			 struct completion *completion, int atomic)
219 {
220 	int error;
221 
222 	error = rtkit_send_endpoint(rtk->state, ep, msg);
223 	return -error;
224 }
225 
226 int
227 apple_rtkit_wake(struct apple_rtkit *rtk)
228 {
229 	int error;
230 
231 	error = rtkit_set_iop_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_INIT);
232 	if (error)
233 		return -error;
234 
235 	error = rtkit_set_ap_pwrstate(rtk->state, RTKIT_MGMT_PWR_STATE_ON);
236 	return -error;
237 }
238 
239 struct apple_rtkit *
240 devm_apple_rtkit_init(struct device *dev, void *cookie,
241     const char *mbox_name, int mbox_idx, const struct apple_rtkit_ops *ops)
242 {
243 	struct platform_device *pdev = (struct platform_device *)dev;
244 	struct apple_rtkit *rtk;
245 	struct rtkit *rk;
246 
247 	rtk = malloc(sizeof(*rtk), M_DEVBUF, M_WAITOK | M_ZERO);
248 	rtk->tq = taskq_create("drmrtk", 1, IPL_HIGH, 0);
249 	if (rtk->tq == NULL) {
250 		free(rtk, M_DEVBUF, sizeof(*rtk));
251 		return ERR_PTR(ENOMEM);
252 	}
253 
254 	pool_init(&rtktask_pool, sizeof(struct apple_rtkit_task), 0, IPL_TTY,
255 	    0, "apldcp_rtkit", NULL);
256 
257 	rk = malloc(sizeof(*rk), M_DEVBUF, M_WAITOK | M_ZERO);
258 	rk->rk_cookie = rtk;
259 	rk->rk_dmat = pdev->dmat;
260 	rk->rk_logmap = apple_rtkit_logmap;
261 
262 	rtk->state = rtkit_init(pdev->node, mbox_name, 0, rk);
263 	rtk->cookie = cookie;
264 	rtk->pdev = pdev;
265 	rtk->ops = ops;
266 
267 	return rtk;
268 }
269 
270 static const void *
271 of_device_get_match_data(const struct device *dev)
272 {
273 	struct platform_device *pdev = (struct platform_device *)dev;
274 	int i;
275 
276 	for (i = 0; i < nitems(of_match); i++) {
277 		if (OF_is_compatible(pdev->node, of_match[i].compatible))
278 			return of_match[i].data;
279 	}
280 
281 	return NULL;
282 }
283