1 /* $OpenBSD: simplepanel.c,v 1.3 2020/06/08 04:47:58 jsg 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 .vrefresh = 60, 45 }; 46 47 int simplepanel_match(struct device *, void *, void *); 48 void simplepanel_attach(struct device *, struct device *, void *); 49 50 struct simplepanel_softc { 51 struct device sc_dev; 52 struct device_ports sc_ports; 53 struct drm_panel sc_panel; 54 const struct drm_display_mode *sc_mode; 55 }; 56 57 struct cfattach simplepanel_ca = { 58 sizeof (struct simplepanel_softc), 59 simplepanel_match, simplepanel_attach 60 }; 61 62 struct cfdriver simplepanel_cd = { 63 NULL, "simplepanel", DV_DULL 64 }; 65 66 void *simplepanel_ep_get_cookie(void *, struct endpoint *); 67 int simplepanel_get_modes(struct drm_panel *, struct drm_connector *); 68 69 struct drm_panel_funcs simplepanel_funcs = { 70 .get_modes = simplepanel_get_modes 71 }; 72 73 int 74 simplepanel_match(struct device *parent, void *match, void *aux) 75 { 76 struct fdt_attach_args *faa = aux; 77 78 return (OF_is_compatible(faa->fa_node, "simple-panel") || 79 OF_is_compatible(faa->fa_node, "boe,nv140fhmn49")); 80 } 81 82 void 83 simplepanel_attach(struct device *parent, struct device *self, void *aux) 84 { 85 struct simplepanel_softc *sc = (struct simplepanel_softc *)self; 86 struct fdt_attach_args *faa = aux; 87 uint32_t power_supply; 88 uint32_t *gpios; 89 int connector_type = DRM_MODE_CONNECTOR_Unknown; 90 int len, err; 91 92 pinctrl_byname(faa->fa_node, "default"); 93 94 power_supply = OF_getpropint(faa->fa_node, "power-supply", 0); 95 if (power_supply) 96 regulator_enable(power_supply); 97 98 len = OF_getproplen(faa->fa_node, "enable-gpios"); 99 if (len > 0) { 100 gpios = malloc(len, M_TEMP, M_WAITOK); 101 OF_getpropintarray(faa->fa_node, "enable-gpios", gpios, len); 102 gpio_controller_config_pin(&gpios[0], GPIO_CONFIG_OUTPUT); 103 gpio_controller_set_pin(&gpios[0], 1); 104 free(gpios, M_TEMP, len); 105 } 106 107 if (OF_is_compatible(faa->fa_node, "boe,nv140fhmn49")) { 108 sc->sc_mode = &boe_nv140fhmn49_mode; 109 connector_type = DRM_MODE_CONNECTOR_eDP; 110 } 111 112 drm_panel_init(&sc->sc_panel, self, &simplepanel_funcs, 113 connector_type); 114 err = drm_panel_add(&sc->sc_panel); 115 if (err < 0) { 116 printf(": can't register panel\n"); 117 return; 118 } 119 120 printf("\n"); 121 122 sc->sc_ports.dp_node = faa->fa_node; 123 sc->sc_ports.dp_cookie = sc; 124 sc->sc_ports.dp_ep_get_cookie = simplepanel_ep_get_cookie; 125 device_ports_register(&sc->sc_ports, EP_DRM_PANEL); 126 } 127 128 void * 129 simplepanel_ep_get_cookie(void *cookie, struct endpoint *ep) 130 { 131 struct simplepanel_softc *sc = cookie; 132 return &sc->sc_panel; 133 } 134 135 static inline struct simplepanel_softc * 136 to_simplepanel(struct drm_panel *panel) 137 { 138 return container_of(panel, struct simplepanel_softc, sc_panel); 139 } 140 141 int 142 simplepanel_get_modes(struct drm_panel *panel, struct drm_connector *connector) 143 { 144 struct simplepanel_softc *sc = to_simplepanel(panel); 145 struct drm_display_mode *mode; 146 147 if (sc->sc_mode == NULL) 148 return 0; 149 150 mode = drm_mode_duplicate(connector->dev, sc->sc_mode); 151 if (mode == NULL) 152 return 0; 153 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 154 155 drm_mode_set_name(mode); 156 drm_mode_probed_add(connector, mode); 157 return 1; 158 } 159