xref: /openbsd-src/sys/dev/fdt/simplepanel.c (revision ac412305e8e9374467e4ac2c371c2d4a758065fb)
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