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