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