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