xref: /openbsd-src/sys/dev/fdt/rkanxdp.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /* $OpenBSD: rkanxdp.c,v 1.2 2020/03/01 10:19:35 kettenis Exp $ */
2 /* $NetBSD: rk_anxdp.c,v 1.2 2020/01/04 12:08:32 jmcneill Exp $ */
3 /*-
4  * Copyright (c) 2019 Jonathan A. Kollasch <jakllsch@kollasch.net>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/device.h>
31 #include <sys/systm.h>
32 
33 #include <machine/bus.h>
34 #include <machine/fdt.h>
35 
36 #include <dev/ofw/openfirm.h>
37 #include <dev/ofw/ofw_clock.h>
38 #include <dev/ofw/ofw_gpio.h>
39 #include <dev/ofw/ofw_misc.h>
40 #include <dev/ofw/ofw_pinctrl.h>
41 #include <dev/ofw/fdt.h>
42 
43 #include <drm/drmP.h>
44 #include <drm/drm_crtc_helper.h>
45 
46 #include <dev/ic/anxdp.h>
47 
48 #define	RK3399_GRF_SOC_CON20		0x6250
49 #define	 EDP_LCDC_SEL				(1 << 5)
50 
51 enum {
52 	ANXDP_PORT_INPUT = 0,
53 	ANXDP_PORT_OUTPUT = 1,
54 };
55 
56 struct rkanxdp_port {
57 	struct rkanxdp_softc	*sc;
58 	struct rkanxdp_ep	*ep;
59 	int			nep;
60 };
61 
62 struct rkanxdp_ep {
63 	struct rkanxdp_port	*port;
64 	struct video_device	vd;
65 };
66 
67 struct rkanxdp_softc {
68 	struct anxdp_softc	sc_base;
69 
70 	struct drm_encoder	sc_encoder;
71 	struct drm_display_mode	sc_curmode;
72 	struct regmap		*sc_grf;
73 
74 	int			sc_activated;
75 
76 	struct rkanxdp_port	*sc_port;
77 	int			sc_nport;
78 };
79 
80 #define	to_rkanxdp_softc(x)	container_of(x, struct rkanxdp_softc, sc_base)
81 #define	to_rkanxdp_encoder(x)	container_of(x, struct rkanxdp_softc, sc_encoder)
82 
83 int rkanxdp_match(struct device *, void *, void *);
84 void rkanxdp_attach(struct device *, struct device *, void *);
85 
86 void rkanxdp_select_input(struct rkanxdp_softc *, u_int);
87 bool rkanxdp_encoder_mode_fixup(struct drm_encoder *,
88     const struct drm_display_mode *, struct drm_display_mode *);
89 void rkanxdp_encoder_mode_set(struct drm_encoder *,
90     struct drm_display_mode *, struct drm_display_mode *);
91 void rkanxdp_encoder_enable(struct drm_encoder *);
92 void rkanxdp_encoder_disable(struct drm_encoder *);
93 void rkanxdp_encoder_prepare(struct drm_encoder *);
94 void rkanxdp_encoder_commit(struct drm_encoder *);
95 void rkanxdp_encoder_dpms(struct drm_encoder *, int);
96 
97 int rkanxdp_ep_activate(void *, struct drm_device *);
98 void *rkanxdp_ep_get_data(void *);
99 
100 struct cfattach	rkanxdp_ca = {
101 	sizeof (struct rkanxdp_softc), rkanxdp_match, rkanxdp_attach
102 };
103 
104 struct cfdriver rkanxdp_cd = {
105 	NULL, "rkanxdp", DV_DULL
106 };
107 
108 int
109 rkanxdp_match(struct device *parent, void *match, void *aux)
110 {
111 	struct fdt_attach_args *faa = aux;
112 
113 	return OF_is_compatible(faa->fa_node, "rockchip,rk3399-edp");
114 }
115 
116 void
117 rkanxdp_attach(struct device *parent, struct device *self, void *aux)
118 {
119 	struct rkanxdp_softc *sc = (struct rkanxdp_softc *)self;
120 	struct fdt_attach_args *faa = aux;
121 	int i, j, ep, port, ports, grf;
122 
123 	if (faa->fa_nreg < 1) {
124 		printf(": no registers\n");
125 		return;
126 	}
127 
128 	pinctrl_byname(faa->fa_node, "default");
129 
130 	reset_deassert(faa->fa_node, "dp");
131 
132 	clock_enable(faa->fa_node, "pclk");
133 	clock_enable(faa->fa_node, "dp");
134 	clock_enable(faa->fa_node, "grf");
135 
136 	sc->sc_base.sc_iot = faa->fa_iot;
137 	if (bus_space_map(sc->sc_base.sc_iot, faa->fa_reg[0].addr,
138 	    faa->fa_reg[0].size, 0, &sc->sc_base.sc_ioh)) {
139 		printf(": can't map registers\n");
140 		return;
141 	}
142 
143 	grf = OF_getpropint(faa->fa_node, "rockchip,grf", 0);
144 	sc->sc_grf = regmap_byphandle(grf);
145 	if (sc->sc_grf == NULL) {
146 		printf(": can't get grf\n");
147 		return;
148 	}
149 
150 	printf(": eDP TX\n");
151 
152 	sc->sc_base.sc_flags |= ANXDP_FLAG_ROCKCHIP;
153 
154 	if (anxdp_attach(&sc->sc_base) != 0) {
155 		printf("%s: failed to attach driver\n",
156 		    sc->sc_base.sc_dev.dv_xname);
157 		return;
158 	}
159 
160 	ports = OF_getnodebyname(faa->fa_node, "ports");
161 	if (!ports)
162 		return;
163 
164 	for (port = OF_child(ports); port; port = OF_peer(port))
165 		sc->sc_nport++;
166 	if (!sc->sc_nport)
167 		return;
168 
169 	sc->sc_port = mallocarray(sc->sc_nport, sizeof(*sc->sc_port), M_DEVBUF,
170 	    M_WAITOK | M_ZERO);
171 	for (i = 0, port = OF_child(ports); port; port = OF_peer(port), i++) {
172 		for (ep = OF_child(port); ep; ep = OF_peer(ep))
173 			sc->sc_port[i].nep++;
174 		if (!sc->sc_port[i].nep)
175 			continue;
176 		sc->sc_port[i].sc = sc;
177 		sc->sc_port[i].ep = mallocarray(sc->sc_port[i].nep,
178 		    sizeof(*sc->sc_port[i].ep), M_DEVBUF, M_WAITOK | M_ZERO);
179 		for (j = 0, ep = OF_child(port); ep; ep = OF_peer(ep), j++) {
180 			sc->sc_port[i].ep[j].port = &sc->sc_port[i];
181 			sc->sc_port[i].ep[j].vd.vd_node = ep;
182 			sc->sc_port[i].ep[j].vd.vd_cookie =
183 			    &sc->sc_port[i].ep[j];
184 			sc->sc_port[i].ep[j].vd.vd_ep_activate =
185 			    rkanxdp_ep_activate;
186 			sc->sc_port[i].ep[j].vd.vd_ep_get_data =
187 			    rkanxdp_ep_get_data;
188 			video_register(&sc->sc_port[i].ep[j].vd);
189 		}
190 	}
191 }
192 
193 void
194 rkanxdp_select_input(struct rkanxdp_softc *sc, u_int crtc_index)
195 {
196 	uint32_t write_mask = EDP_LCDC_SEL << 16;
197 	uint32_t write_val = crtc_index == 0 ? EDP_LCDC_SEL : 0;
198 
199 	regmap_write_4(sc->sc_grf, RK3399_GRF_SOC_CON20, write_mask | write_val);
200 }
201 
202 bool
203 rkanxdp_encoder_mode_fixup(struct drm_encoder *encoder,
204     const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
205 {
206 	return true;
207 }
208 
209 void
210 rkanxdp_encoder_mode_set(struct drm_encoder *encoder,
211     struct drm_display_mode *mode, struct drm_display_mode *adjusted)
212 {
213 }
214 
215 void
216 rkanxdp_encoder_enable(struct drm_encoder *encoder)
217 {
218 }
219 
220 void
221 rkanxdp_encoder_disable(struct drm_encoder *encoder)
222 {
223 }
224 
225 void
226 rkanxdp_encoder_prepare(struct drm_encoder *encoder)
227 {
228 	struct rkanxdp_softc *sc = to_rkanxdp_encoder(encoder);
229 	u_int crtc_index = drm_crtc_index(encoder->crtc);
230 
231 	rkanxdp_select_input(sc, crtc_index);
232 }
233 
234 void
235 rkanxdp_encoder_commit(struct drm_encoder *encoder)
236 {
237 }
238 
239 void
240 rkanxdp_encoder_dpms(struct drm_encoder *encoder, int mode)
241 {
242 	struct rkanxdp_softc *sc = to_rkanxdp_encoder(encoder);
243 
244 	anxdp_dpms(&sc->sc_base, mode);
245 }
246 
247 struct drm_encoder_funcs rkanxdp_encoder_funcs = {
248 	.destroy = drm_encoder_cleanup,
249 };
250 
251 struct drm_encoder_helper_funcs rkanxdp_encoder_helper_funcs = {
252 	.prepare = rkanxdp_encoder_prepare,
253 	.mode_fixup = rkanxdp_encoder_mode_fixup,
254 	.mode_set = rkanxdp_encoder_mode_set,
255 	.enable = rkanxdp_encoder_enable,
256 	.disable = rkanxdp_encoder_disable,
257 	.commit = rkanxdp_encoder_commit,
258 	.dpms = rkanxdp_encoder_dpms,
259 };
260 
261 int
262 rkanxdp_ep_activate(void *cookie, struct drm_device *ddev)
263 {
264 	struct rkanxdp_ep *ep = cookie;
265 	struct rkanxdp_port *port = ep->port;
266 	struct rkanxdp_softc *sc = port->sc;
267 	int error;
268 
269 	if (sc->sc_activated)
270 		return 0;
271 
272 	if (OF_getpropint(OF_parent(ep->vd.vd_node), "reg", 0) != ANXDP_PORT_INPUT)
273 		return EINVAL;
274 
275 	sc->sc_encoder.possible_crtcs = 0x3; /* XXX */
276 	drm_encoder_init(ddev, &sc->sc_encoder, &rkanxdp_encoder_funcs,
277 	    DRM_MODE_ENCODER_TMDS, NULL);
278 	drm_encoder_helper_add(&sc->sc_encoder, &rkanxdp_encoder_helper_funcs);
279 
280 	sc->sc_base.sc_connector.base.connector_type = DRM_MODE_CONNECTOR_eDP;
281 	error = anxdp_bind(&sc->sc_base, &sc->sc_encoder);
282 	if (error != 0)
283 		return error;
284 
285 	sc->sc_activated = 1;
286 	return 0;
287 }
288 
289 void *
290 rkanxdp_ep_get_data(void *cookie)
291 {
292 	struct rkanxdp_ep *ep = cookie;
293 	struct rkanxdp_port *port = ep->port;
294 	struct rkanxdp_softc *sc = port->sc;
295 
296 	return &sc->sc_encoder;
297 }
298