1 /* $NetBSD: anxedp.c,v 1.8 2021/12/19 11:01:10 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca> 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/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: anxedp.c,v 1.8 2021/12/19 11:01:10 riastradh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/conf.h> 35 #include <sys/device.h> 36 #include <sys/intr.h> 37 #include <sys/kernel.h> 38 #include <sys/systm.h> 39 40 #include <dev/ic/dw_hdmi.h> 41 42 #include <dev/i2c/ddcreg.h> 43 #include <dev/i2c/ddcvar.h> 44 #include <dev/i2c/i2cvar.h> 45 #include <dev/videomode/edidvar.h> 46 47 #include <dev/fdt/fdt_port.h> 48 #include <dev/fdt/fdtvar.h> 49 50 #include <drm/drm_connector.h> 51 #include <drm/drm_crtc.h> 52 #include <drm/drm_crtc_helper.h> 53 #include <drm/drm_drv.h> 54 #include <drm/drm_edid.h> 55 #include <drm/drm_probe_helper.h> 56 57 #define ANX_DP_AUX_CH_CTL_1 0xe5 58 #define ANX_AUX_LENGTH __BITS(7,4) 59 #define ANX_AUX_TX_COMM __BITS(3,0) 60 #define ANX_AUX_TX_COMM_MOT 4 61 #define ANX_AUX_TX_COMM_READ 1 62 #define ANX_DP_AUX_ADDR(n) (0xe6 + (n)) 63 #define ANX_DP_AUX_CH_CTL_2 0xe9 64 #define ANX_ADDR_ONLY __BIT(1) 65 #define ANX_AUX_EN __BIT(0) 66 #define ANX_BUF_DATA(n) (0xf0 + (n)) 67 68 #define ANX_DP_INT_STA 0xf7 69 #define ANX_RPLY_RECEIV __BIT(1) 70 71 static const struct device_compatible_entry compat_data[] = { 72 { .compat = "analogix,anx6345" }, 73 DEVICE_COMPAT_EOL 74 }; 75 76 struct anxedp_softc; 77 78 struct anxedp_connector { 79 struct drm_connector base; 80 struct anxedp_softc *sc; 81 }; 82 83 struct anxedp_softc { 84 device_t sc_dev; 85 i2c_tag_t sc_i2c; 86 i2c_addr_t sc_addr; 87 int sc_phandle; 88 89 struct anxedp_connector sc_connector; 90 struct drm_bridge sc_bridge; 91 92 struct fdt_device_ports sc_ports; 93 struct drm_display_mode sc_curmode; 94 }; 95 96 #define to_anxedp_connector(x) container_of(x, struct anxedp_connector, base) 97 98 static uint8_t 99 anxedp_read(struct anxedp_softc *sc, u_int off, uint8_t reg) 100 { 101 uint8_t val; 102 103 if (iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr + off, reg, &val, 0) != 0) 104 val = 0xff; 105 106 return val; 107 } 108 109 static void 110 anxedp_write(struct anxedp_softc *sc, u_int off, uint8_t reg, uint8_t val) 111 { 112 (void)iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr + off, reg, val, 0); 113 } 114 115 static int 116 anxedp_connector_dpms(struct drm_connector *connector, int mode) 117 { 118 int error; 119 120 if (mode != DRM_MODE_DPMS_ON) 121 pmf_event_inject(NULL, PMFE_DISPLAY_OFF); 122 123 error = drm_helper_connector_dpms(connector, mode); 124 125 if (mode == DRM_MODE_DPMS_ON) 126 pmf_event_inject(NULL, PMFE_DISPLAY_ON); 127 128 return error; 129 } 130 131 static enum drm_connector_status 132 anxedp_connector_detect(struct drm_connector *connector, bool force) 133 { 134 return connector_status_connected; 135 } 136 137 static void 138 anxedp_connector_destroy(struct drm_connector *connector) 139 { 140 drm_connector_unregister(connector); 141 drm_connector_cleanup(connector); 142 } 143 144 static const struct drm_connector_funcs anxedp_connector_funcs = { 145 .dpms = anxedp_connector_dpms, 146 .detect = anxedp_connector_detect, 147 .fill_modes = drm_helper_probe_single_connector_modes, 148 .destroy = anxedp_connector_destroy, 149 }; 150 151 static int 152 anxedp_aux_wait(struct anxedp_softc *sc) 153 { 154 uint8_t val; 155 int retry; 156 157 for (retry = 1000; retry > 0; retry--) { 158 val = anxedp_read(sc, 0, ANX_DP_AUX_CH_CTL_2); 159 if ((val & ANX_AUX_EN) == 0) 160 break; 161 delay(100); 162 } 163 if (retry == 0) { 164 device_printf(sc->sc_dev, "aux transfer timeout\n"); 165 return ETIMEDOUT; 166 } 167 168 for (retry = 1000; retry > 0; retry--) { 169 val = anxedp_read(sc, 1, ANX_DP_INT_STA); 170 if ((val & ANX_RPLY_RECEIV) != 0) { 171 anxedp_write(sc, 1, ANX_DP_INT_STA, val); 172 break; 173 } 174 delay(100); 175 } 176 if (retry == 0) { 177 device_printf(sc->sc_dev, "aux transfer timeout\n"); 178 return ETIMEDOUT; 179 } 180 181 return 0; 182 } 183 184 static int 185 anxedp_aux_transfer(struct anxedp_softc *sc, uint8_t comm, uint32_t addr, 186 uint8_t *buf, int buflen) 187 { 188 uint8_t ctrl[2]; 189 int n, error; 190 191 ctrl[0] = __SHIFTIN(comm, ANX_AUX_TX_COMM); 192 if (buflen > 0) 193 ctrl[0] |= __SHIFTIN(buflen - 1, ANX_AUX_LENGTH); 194 ctrl[1] = ANX_AUX_EN; 195 if (buflen == 0) 196 ctrl[1] |= ANX_ADDR_ONLY; 197 198 if (comm != ANX_AUX_TX_COMM_READ) { 199 for (n = 0; n < buflen; n++) 200 anxedp_write(sc, 0, ANX_BUF_DATA(n), buf[n]); 201 } 202 203 anxedp_write(sc, 0, ANX_DP_AUX_ADDR(0), addr & 0xff); 204 anxedp_write(sc, 0, ANX_DP_AUX_ADDR(1), (addr >> 8) & 0xff); 205 anxedp_write(sc, 0, ANX_DP_AUX_ADDR(2), (addr >> 16) & 0xf); 206 anxedp_write(sc, 0, ANX_DP_AUX_CH_CTL_1, ctrl[0]); 207 anxedp_write(sc, 0, ANX_DP_AUX_CH_CTL_2, ctrl[1]); 208 209 error = anxedp_aux_wait(sc); 210 if (error != 0) 211 return error; 212 213 if (comm == ANX_AUX_TX_COMM_READ) { 214 for (n = 0; n < buflen; n++) 215 buf[n] = anxedp_read(sc, 0, ANX_BUF_DATA(n)); 216 } 217 218 return 0; 219 } 220 221 static int 222 anxedp_read_edid(struct anxedp_softc *sc, uint8_t *edid, int edidlen) 223 { 224 int error; 225 uint8_t n; 226 227 for (n = 0; n < edidlen; n += 16) { 228 const int xferlen = MIN(edidlen - n, 16); 229 230 error = anxedp_aux_transfer(sc, ANX_AUX_TX_COMM_MOT, DDC_ADDR, &n, 1); 231 if (error != 0) 232 return error; 233 234 error = anxedp_aux_transfer(sc, ANX_AUX_TX_COMM_READ, DDC_ADDR, &edid[n], xferlen); 235 if (error != 0) 236 return error; 237 } 238 239 return 0; 240 } 241 242 static int 243 anxedp_connector_get_modes(struct drm_connector *connector) 244 { 245 struct anxedp_connector *anxedp_connector = to_anxedp_connector(connector); 246 struct anxedp_softc * const sc = anxedp_connector->sc; 247 char edid[EDID_LENGTH]; 248 struct edid *pedid = NULL; 249 int error; 250 251 iic_acquire_bus(sc->sc_i2c, 0); 252 error = anxedp_read_edid(sc, edid, sizeof(edid)); 253 iic_release_bus(sc->sc_i2c, 0); 254 if (error == 0) 255 pedid = (struct edid *)edid; 256 257 drm_connector_update_edid_property(connector, pedid); 258 if (pedid == NULL) 259 return 0; 260 261 return drm_add_edid_modes(connector, pedid); 262 } 263 264 static const struct drm_connector_helper_funcs anxedp_connector_helper_funcs = { 265 .get_modes = anxedp_connector_get_modes, 266 }; 267 268 static int 269 anxedp_bridge_attach(struct drm_bridge *bridge) 270 { 271 struct anxedp_softc * const sc = bridge->driver_private; 272 struct anxedp_connector *anxedp_connector = &sc->sc_connector; 273 struct drm_connector *connector = &anxedp_connector->base; 274 int error; 275 276 anxedp_connector->sc = sc; 277 278 connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; 279 connector->interlace_allowed = 0; 280 connector->doublescan_allowed = 0; 281 282 drm_connector_init(bridge->dev, connector, &anxedp_connector_funcs, 283 connector->connector_type); 284 drm_connector_helper_add(connector, &anxedp_connector_helper_funcs); 285 286 error = drm_connector_attach_encoder(connector, bridge->encoder); 287 if (error != 0) 288 return error; 289 290 return drm_connector_register(connector); 291 } 292 293 static void 294 anxedp_bridge_enable(struct drm_bridge *bridge) 295 { 296 } 297 298 static void 299 anxedp_bridge_pre_enable(struct drm_bridge *bridge) 300 { 301 } 302 303 static void 304 anxedp_bridge_disable(struct drm_bridge *bridge) 305 { 306 } 307 308 static void 309 anxedp_bridge_post_disable(struct drm_bridge *bridge) 310 { 311 } 312 313 static void 314 anxedp_bridge_mode_set(struct drm_bridge *bridge, 315 const struct drm_display_mode *mode, 316 const struct drm_display_mode *adjusted_mode) 317 { 318 struct anxedp_softc * const sc = bridge->driver_private; 319 320 sc->sc_curmode = *adjusted_mode; 321 } 322 323 static bool 324 anxedp_bridge_mode_fixup(struct drm_bridge *bridge, 325 const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) 326 { 327 return true; 328 } 329 330 static const struct drm_bridge_funcs anxedp_bridge_funcs = { 331 .attach = anxedp_bridge_attach, 332 .enable = anxedp_bridge_enable, 333 .pre_enable = anxedp_bridge_pre_enable, 334 .disable = anxedp_bridge_disable, 335 .post_disable = anxedp_bridge_post_disable, 336 .mode_set = anxedp_bridge_mode_set, 337 .mode_fixup = anxedp_bridge_mode_fixup, 338 }; 339 340 static int 341 anxedp_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) 342 { 343 struct anxedp_softc * const sc = device_private(dev); 344 struct fdt_endpoint *in_ep = fdt_endpoint_remote(ep); 345 struct drm_encoder *encoder; 346 struct drm_bridge *bridge; 347 int error; 348 349 if (!activate) 350 return EINVAL; 351 352 if (fdt_endpoint_port_index(ep) != 0) 353 return EINVAL; 354 355 switch (fdt_endpoint_type(in_ep)) { 356 case EP_DRM_ENCODER: 357 encoder = fdt_endpoint_get_data(in_ep); 358 break; 359 case EP_DRM_BRIDGE: 360 bridge = fdt_endpoint_get_data(in_ep); 361 encoder = bridge->encoder; 362 break; 363 default: 364 encoder = NULL; 365 break; 366 } 367 368 if (encoder == NULL) 369 return EINVAL; 370 371 sc->sc_connector.base.connector_type = DRM_MODE_CONNECTOR_eDP; 372 373 sc->sc_bridge.driver_private = sc; 374 sc->sc_bridge.funcs = &anxedp_bridge_funcs; 375 sc->sc_bridge.encoder = encoder; 376 377 error = drm_bridge_attach(encoder, &sc->sc_bridge, NULL); 378 if (error != 0) 379 return EIO; 380 381 return 0; 382 } 383 384 static void * 385 anxedp_ep_get_data(device_t dev, struct fdt_endpoint *ep) 386 { 387 struct anxedp_softc * const sc = device_private(dev); 388 389 return &sc->sc_bridge; 390 } 391 392 static int 393 anxedp_match(device_t parent, cfdata_t match, void *aux) 394 { 395 struct i2c_attach_args *ia = aux; 396 int match_result; 397 398 if (iic_use_direct_match(ia, match, compat_data, &match_result)) 399 return match_result; 400 401 /* This device is direct-config only */ 402 403 return 0; 404 } 405 406 static void 407 anxedp_attach(device_t parent, device_t self, void *aux) 408 { 409 struct anxedp_softc * const sc = device_private(self); 410 struct i2c_attach_args * const ia = aux; 411 412 sc->sc_dev = self; 413 sc->sc_i2c = ia->ia_tag; 414 sc->sc_addr = ia->ia_addr; 415 sc->sc_phandle = ia->ia_cookie; 416 417 aprint_naive("\n"); 418 aprint_normal(": eDP TX\n"); 419 420 sc->sc_ports.dp_ep_activate = anxedp_ep_activate; 421 sc->sc_ports.dp_ep_get_data = anxedp_ep_get_data; 422 fdt_ports_register(&sc->sc_ports, self, sc->sc_phandle, EP_DRM_BRIDGE); 423 } 424 425 CFATTACH_DECL_NEW(anxedp, sizeof(struct anxedp_softc), 426 anxedp_match, anxedp_attach, NULL, NULL); 427