1*ac412305Spatrick /* $OpenBSD: simplepanel.c,v 1.6 2021/11/07 15:59:09 patrick Exp $ */
2801013ceSpatrick /*
3801013ceSpatrick * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
4801013ceSpatrick *
5801013ceSpatrick * Permission to use, copy, modify, and distribute this software for any
6801013ceSpatrick * purpose with or without fee is hereby granted, provided that the above
7801013ceSpatrick * copyright notice and this permission notice appear in all copies.
8801013ceSpatrick *
9801013ceSpatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10801013ceSpatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11801013ceSpatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12801013ceSpatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13801013ceSpatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14801013ceSpatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15801013ceSpatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16801013ceSpatrick */
17801013ceSpatrick
18801013ceSpatrick #include <sys/param.h>
19801013ceSpatrick #include <sys/systm.h>
20801013ceSpatrick #include <sys/device.h>
21801013ceSpatrick #include <sys/malloc.h>
22801013ceSpatrick
23801013ceSpatrick #include <machine/fdt.h>
24801013ceSpatrick
25801013ceSpatrick #include <dev/ofw/openfirm.h>
26801013ceSpatrick #include <dev/ofw/ofw_gpio.h>
27801013ceSpatrick #include <dev/ofw/ofw_misc.h>
28801013ceSpatrick #include <dev/ofw/ofw_pinctrl.h>
29801013ceSpatrick #include <dev/ofw/ofw_regulator.h>
30801013ceSpatrick
31a8951e27Skettenis #include <drm/drm_modes.h>
32a8951e27Skettenis #include <drm/drm_panel.h>
33a8951e27Skettenis
34a8951e27Skettenis const struct drm_display_mode boe_nv140fhmn49_mode = {
35a8951e27Skettenis .clock = 148500,
36a8951e27Skettenis .hdisplay = 1920,
37a8951e27Skettenis .hsync_start = 1920 + 48,
38a8951e27Skettenis .hsync_end = 1920 + 48 + 32,
39a8951e27Skettenis .htotal = 2200,
40a8951e27Skettenis .vdisplay = 1080,
41a8951e27Skettenis .vsync_start = 1080 + 3,
42a8951e27Skettenis .vsync_end = 1080 + 3 + 5,
43a8951e27Skettenis .vtotal = 1125,
44a8951e27Skettenis };
45a8951e27Skettenis
46801013ceSpatrick int simplepanel_match(struct device *, void *, void *);
47801013ceSpatrick void simplepanel_attach(struct device *, struct device *, void *);
48801013ceSpatrick
49a8951e27Skettenis struct simplepanel_softc {
50a8951e27Skettenis struct device sc_dev;
51a8951e27Skettenis struct device_ports sc_ports;
52a8951e27Skettenis struct drm_panel sc_panel;
53a8951e27Skettenis const struct drm_display_mode *sc_mode;
54a8951e27Skettenis };
55a8951e27Skettenis
56*ac412305Spatrick const struct cfattach simplepanel_ca = {
57a8951e27Skettenis sizeof (struct simplepanel_softc),
58a8951e27Skettenis simplepanel_match, simplepanel_attach
59801013ceSpatrick };
60801013ceSpatrick
61*ac412305Spatrick struct cfdriver simplepanel_cd = {
62801013ceSpatrick NULL, "simplepanel", DV_DULL
63801013ceSpatrick };
64801013ceSpatrick
65a8951e27Skettenis void *simplepanel_ep_get_cookie(void *, struct endpoint *);
66c349dbc7Sjsg int simplepanel_get_modes(struct drm_panel *, struct drm_connector *);
67a8951e27Skettenis
68a8951e27Skettenis struct drm_panel_funcs simplepanel_funcs = {
69a8951e27Skettenis .get_modes = simplepanel_get_modes
70a8951e27Skettenis };
71a8951e27Skettenis
72801013ceSpatrick int
simplepanel_match(struct device * parent,void * match,void * aux)73801013ceSpatrick simplepanel_match(struct device *parent, void *match, void *aux)
74801013ceSpatrick {
75801013ceSpatrick struct fdt_attach_args *faa = aux;
76801013ceSpatrick
77a8951e27Skettenis return (OF_is_compatible(faa->fa_node, "simple-panel") ||
78a8951e27Skettenis OF_is_compatible(faa->fa_node, "boe,nv140fhmn49"));
79801013ceSpatrick }
80801013ceSpatrick
81801013ceSpatrick void
simplepanel_attach(struct device * parent,struct device * self,void * aux)82801013ceSpatrick simplepanel_attach(struct device *parent, struct device *self, void *aux)
83801013ceSpatrick {
84a8951e27Skettenis struct simplepanel_softc *sc = (struct simplepanel_softc *)self;
85801013ceSpatrick struct fdt_attach_args *faa = aux;
86801013ceSpatrick uint32_t power_supply;
87801013ceSpatrick uint32_t *gpios;
88c349dbc7Sjsg int connector_type = DRM_MODE_CONNECTOR_Unknown;
89ad8b1aafSjsg int len;
90801013ceSpatrick
91801013ceSpatrick pinctrl_byname(faa->fa_node, "default");
92801013ceSpatrick
93801013ceSpatrick power_supply = OF_getpropint(faa->fa_node, "power-supply", 0);
94801013ceSpatrick if (power_supply)
95801013ceSpatrick regulator_enable(power_supply);
96801013ceSpatrick
97801013ceSpatrick len = OF_getproplen(faa->fa_node, "enable-gpios");
98801013ceSpatrick if (len > 0) {
99801013ceSpatrick gpios = malloc(len, M_TEMP, M_WAITOK);
100801013ceSpatrick OF_getpropintarray(faa->fa_node, "enable-gpios", gpios, len);
101801013ceSpatrick gpio_controller_config_pin(&gpios[0], GPIO_CONFIG_OUTPUT);
102801013ceSpatrick gpio_controller_set_pin(&gpios[0], 1);
103801013ceSpatrick free(gpios, M_TEMP, len);
104801013ceSpatrick }
105a8951e27Skettenis
106c349dbc7Sjsg if (OF_is_compatible(faa->fa_node, "boe,nv140fhmn49")) {
107a8951e27Skettenis sc->sc_mode = &boe_nv140fhmn49_mode;
108c349dbc7Sjsg connector_type = DRM_MODE_CONNECTOR_eDP;
109c349dbc7Sjsg }
110a8951e27Skettenis
111c349dbc7Sjsg drm_panel_init(&sc->sc_panel, self, &simplepanel_funcs,
112c349dbc7Sjsg connector_type);
113ad8b1aafSjsg drm_panel_add(&sc->sc_panel);
114a8951e27Skettenis
115a8951e27Skettenis printf("\n");
116a8951e27Skettenis
117a8951e27Skettenis sc->sc_ports.dp_node = faa->fa_node;
118a8951e27Skettenis sc->sc_ports.dp_cookie = sc;
119a8951e27Skettenis sc->sc_ports.dp_ep_get_cookie = simplepanel_ep_get_cookie;
120a8951e27Skettenis device_ports_register(&sc->sc_ports, EP_DRM_PANEL);
121a8951e27Skettenis }
122a8951e27Skettenis
123a8951e27Skettenis void *
simplepanel_ep_get_cookie(void * cookie,struct endpoint * ep)124a8951e27Skettenis simplepanel_ep_get_cookie(void *cookie, struct endpoint *ep)
125a8951e27Skettenis {
126a8951e27Skettenis struct simplepanel_softc *sc = cookie;
127a8951e27Skettenis return &sc->sc_panel;
128a8951e27Skettenis }
129a8951e27Skettenis
130a8951e27Skettenis static inline struct simplepanel_softc *
to_simplepanel(struct drm_panel * panel)131a8951e27Skettenis to_simplepanel(struct drm_panel *panel)
132a8951e27Skettenis {
133a8951e27Skettenis return container_of(panel, struct simplepanel_softc, sc_panel);
134a8951e27Skettenis }
135a8951e27Skettenis
136a8951e27Skettenis int
simplepanel_get_modes(struct drm_panel * panel,struct drm_connector * connector)137c349dbc7Sjsg simplepanel_get_modes(struct drm_panel *panel, struct drm_connector *connector)
138a8951e27Skettenis {
139a8951e27Skettenis struct simplepanel_softc *sc = to_simplepanel(panel);
140a8951e27Skettenis struct drm_display_mode *mode;
141a8951e27Skettenis
142a8951e27Skettenis if (sc->sc_mode == NULL)
143a8951e27Skettenis return 0;
144a8951e27Skettenis
145c349dbc7Sjsg mode = drm_mode_duplicate(connector->dev, sc->sc_mode);
146a8951e27Skettenis if (mode == NULL)
147a8951e27Skettenis return 0;
148a8951e27Skettenis mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
149a8951e27Skettenis
150a8951e27Skettenis drm_mode_set_name(mode);
151a8951e27Skettenis drm_mode_probed_add(connector, mode);
152a8951e27Skettenis return 1;
153801013ceSpatrick }
154