1 /* $OpenBSD: simplepanel.c,v 1.6 2021/11/07 15:59:09 patrick Exp $ */ 2 /* 3 * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se> 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 #include <sys/malloc.h> 22 23 #include <machine/fdt.h> 24 25 #include <dev/ofw/openfirm.h> 26 #include <dev/ofw/ofw_gpio.h> 27 #include <dev/ofw/ofw_misc.h> 28 #include <dev/ofw/ofw_pinctrl.h> 29 #include <dev/ofw/ofw_regulator.h> 30 31 #include <drm/drm_modes.h> 32 #include <drm/drm_panel.h> 33 34 const struct drm_display_mode boe_nv140fhmn49_mode = { 35 .clock = 148500, 36 .hdisplay = 1920, 37 .hsync_start = 1920 + 48, 38 .hsync_end = 1920 + 48 + 32, 39 .htotal = 2200, 40 .vdisplay = 1080, 41 .vsync_start = 1080 + 3, 42 .vsync_end = 1080 + 3 + 5, 43 .vtotal = 1125, 44 }; 45 46 int simplepanel_match(struct device *, void *, void *); 47 void simplepanel_attach(struct device *, struct device *, void *); 48 49 struct simplepanel_softc { 50 struct device sc_dev; 51 struct device_ports sc_ports; 52 struct drm_panel sc_panel; 53 const struct drm_display_mode *sc_mode; 54 }; 55 56 const struct cfattach simplepanel_ca = { 57 sizeof (struct simplepanel_softc), 58 simplepanel_match, simplepanel_attach 59 }; 60 61 struct cfdriver simplepanel_cd = { 62 NULL, "simplepanel", DV_DULL 63 }; 64 65 void *simplepanel_ep_get_cookie(void *, struct endpoint *); 66 int simplepanel_get_modes(struct drm_panel *, struct drm_connector *); 67 68 struct drm_panel_funcs simplepanel_funcs = { 69 .get_modes = simplepanel_get_modes 70 }; 71 72 int 73 simplepanel_match(struct device *parent, void *match, void *aux) 74 { 75 struct fdt_attach_args *faa = aux; 76 77 return (OF_is_compatible(faa->fa_node, "simple-panel") || 78 OF_is_compatible(faa->fa_node, "boe,nv140fhmn49")); 79 } 80 81 void 82 simplepanel_attach(struct device *parent, struct device *self, void *aux) 83 { 84 struct simplepanel_softc *sc = (struct simplepanel_softc *)self; 85 struct fdt_attach_args *faa = aux; 86 uint32_t power_supply; 87 uint32_t *gpios; 88 int connector_type = DRM_MODE_CONNECTOR_Unknown; 89 int len; 90 91 pinctrl_byname(faa->fa_node, "default"); 92 93 power_supply = OF_getpropint(faa->fa_node, "power-supply", 0); 94 if (power_supply) 95 regulator_enable(power_supply); 96 97 len = OF_getproplen(faa->fa_node, "enable-gpios"); 98 if (len > 0) { 99 gpios = malloc(len, M_TEMP, M_WAITOK); 100 OF_getpropintarray(faa->fa_node, "enable-gpios", gpios, len); 101 gpio_controller_config_pin(&gpios[0], GPIO_CONFIG_OUTPUT); 102 gpio_controller_set_pin(&gpios[0], 1); 103 free(gpios, M_TEMP, len); 104 } 105 106 if (OF_is_compatible(faa->fa_node, "boe,nv140fhmn49")) { 107 sc->sc_mode = &boe_nv140fhmn49_mode; 108 connector_type = DRM_MODE_CONNECTOR_eDP; 109 } 110 111 drm_panel_init(&sc->sc_panel, self, &simplepanel_funcs, 112 connector_type); 113 drm_panel_add(&sc->sc_panel); 114 115 printf("\n"); 116 117 sc->sc_ports.dp_node = faa->fa_node; 118 sc->sc_ports.dp_cookie = sc; 119 sc->sc_ports.dp_ep_get_cookie = simplepanel_ep_get_cookie; 120 device_ports_register(&sc->sc_ports, EP_DRM_PANEL); 121 } 122 123 void * 124 simplepanel_ep_get_cookie(void *cookie, struct endpoint *ep) 125 { 126 struct simplepanel_softc *sc = cookie; 127 return &sc->sc_panel; 128 } 129 130 static inline struct simplepanel_softc * 131 to_simplepanel(struct drm_panel *panel) 132 { 133 return container_of(panel, struct simplepanel_softc, sc_panel); 134 } 135 136 int 137 simplepanel_get_modes(struct drm_panel *panel, struct drm_connector *connector) 138 { 139 struct simplepanel_softc *sc = to_simplepanel(panel); 140 struct drm_display_mode *mode; 141 142 if (sc->sc_mode == NULL) 143 return 0; 144 145 mode = drm_mode_duplicate(connector->dev, sc->sc_mode); 146 if (mode == NULL) 147 return 0; 148 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 149 150 drm_mode_set_name(mode); 151 drm_mode_probed_add(connector, mode); 152 return 1; 153 } 154