blob: 1bff641434e1980a7a7b51d551afdbe73f756c33 [file] [log] [blame]
Svyatoslav Ryheldef72d52023-04-25 10:51:47 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#include <common.h>
7#include <backlight.h>
8#include <dm.h>
9#include <panel.h>
10#include <log.h>
11#include <misc.h>
12#include <mipi_display.h>
13#include <mipi_dsi.h>
14#include <asm/gpio.h>
15#include <linux/delay.h>
16#include <linux/err.h>
17#include <power/regulator.h>
18
19struct endeavoru_panel_priv {
20 struct udevice *vdd;
21 struct udevice *vddio;
22
23 struct udevice *backlight;
24
25 struct gpio_desc reset_gpio;
26};
27
28static struct display_timing default_timing = {
29 .pixelclock.typ = 63200000,
30 .hactive.typ = 720,
31 .hfront_porch.typ = 55,
32 .hback_porch.typ = 29,
33 .hsync_len.typ = 16,
34 .vactive.typ = 1280,
35 .vfront_porch.typ = 2,
36 .vback_porch.typ = 1,
37 .vsync_len.typ = 1,
38};
39
40static void dcs_write_one(struct mipi_dsi_device *dsi, u8 cmd, u8 data)
41{
42 mipi_dsi_dcs_write(dsi, cmd, &data, 1);
43}
44
45/*
46 * This panel is not able to auto-increment all cmd addresses so for some of
47 * them, we need to send them one by one...
48 */
49#define dcs_write_seq(dsi, cmd, seq...) \
50({ \
51 static const u8 d[] = { seq }; \
52 unsigned int i; \
53 \
54 for (i = 0; i < ARRAY_SIZE(d) ; i++) \
55 dcs_write_one(dsi, cmd + i, d[i]); \
56})
57
58static int endeavoru_panel_enable_backlight(struct udevice *dev)
59{
Svyatoslav Ryheldef72d52023-04-25 10:51:47 +030060 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
61 struct mipi_dsi_device *dsi = plat->device;
Svyatoslav Ryheldef72d52023-04-25 10:51:47 +030062
63 dcs_write_one(dsi, 0xc2, 0x08);
64
65 /* color enhancement 2.2 */
66 dcs_write_one(dsi, 0xff, 0x03);
67 dcs_write_one(dsi, 0xfe, 0x08);
68 dcs_write_one(dsi, 0x18, 0x00);
69 dcs_write_one(dsi, 0x19, 0x00);
70 dcs_write_one(dsi, 0x1a, 0x00);
71 dcs_write_one(dsi, 0x25, 0x26);
72
73 dcs_write_seq(dsi, 0x00, 0x00, 0x05, 0x10, 0x17,
74 0x22, 0x26, 0x29, 0x29, 0x26, 0x23,
75 0x17, 0x12, 0x06, 0x02, 0x01, 0x00);
76
77 dcs_write_one(dsi, 0xfb, 0x01);
78 dcs_write_one(dsi, 0xff, 0x00);
79 dcs_write_one(dsi, 0xfe, 0x01);
80
81 mipi_dsi_dcs_exit_sleep_mode(dsi);
82
83 mdelay(105);
84
85 dcs_write_one(dsi, 0x35, 0x00);
86
87 /* PWM frequency adjust */
88 dcs_write_one(dsi, 0xff, 0x04);
89 dcs_write_one(dsi, 0x0a, 0x07);
90 dcs_write_one(dsi, 0x09, 0x20);
91 dcs_write_one(dsi, 0xff, 0x00);
92
93 dcs_write_one(dsi, 0xff, 0xee);
94 dcs_write_one(dsi, 0x12, 0x50);
95 dcs_write_one(dsi, 0x13, 0x02);
96 dcs_write_one(dsi, 0x6a, 0x60);
97 dcs_write_one(dsi, 0xfb, 0x01);
98 dcs_write_one(dsi, 0xff, 0x00);
99
100 mipi_dsi_dcs_set_display_on(dsi);
101
102 mdelay(42);
103
104 dcs_write_one(dsi, 0xba, 0x01);
105
106 dcs_write_one(dsi, 0x53, 0x24);
107 dcs_write_one(dsi, 0x55, 0x80);
108 dcs_write_one(dsi, 0x5e, 0x06);
109
Svyatoslav Ryhel2a9ce5f2024-01-31 08:57:19 +0200110 /* Set backlight */
111 dcs_write_one(dsi, 0x51, 0x96);
112
113 return 0;
114}
115
116static int endeavoru_panel_set_backlight(struct udevice *dev, int percent)
117{
118 struct endeavoru_panel_priv *priv = dev_get_priv(dev);
119 int ret;
120
Svyatoslav Ryheldef72d52023-04-25 10:51:47 +0300121 ret = backlight_enable(priv->backlight);
122 if (ret)
123 return ret;
124
Svyatoslav Ryhel2a9ce5f2024-01-31 08:57:19 +0200125 return backlight_set_brightness(priv->backlight, percent);
Svyatoslav Ryheldef72d52023-04-25 10:51:47 +0300126}
127
128static int endeavoru_panel_timings(struct udevice *dev,
129 struct display_timing *timing)
130{
131 memcpy(timing, &default_timing, sizeof(*timing));
132 return 0;
133}
134
135static int endeavoru_panel_of_to_plat(struct udevice *dev)
136{
137 struct endeavoru_panel_priv *priv = dev_get_priv(dev);
138 int ret;
139
140 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
141 "backlight", &priv->backlight);
142 if (ret) {
143 log_err("cannot get backlight: ret = %d\n", ret);
144 return ret;
145 }
146
147 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
148 "vdd-supply", &priv->vdd);
149 if (ret) {
150 log_err("cannot get vdd-supply: ret = %d\n", ret);
151 return ret;
152 }
153
154 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
155 "vddio-supply", &priv->vddio);
156 if (ret) {
157 log_err("cannot get vddio-supply: ret = %d\n", ret);
158 return ret;
159 }
160
161 ret = gpio_request_by_name(dev, "reset-gpios", 0,
162 &priv->reset_gpio, GPIOD_IS_OUT);
163 if (ret) {
164 log_err("could not decode reser-gpios (%d)\n", ret);
165 return ret;
166 }
167
168 return 0;
169}
170
Svyatoslav Ryhel2a9ce5f2024-01-31 08:57:19 +0200171static int endeavoru_panel_hw_init(struct udevice *dev)
172{
173 struct endeavoru_panel_priv *priv = dev_get_priv(dev);
174 int ret;
175
176 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
177 if (ret) {
178 log_debug("%s: error changing reset-gpios (%d)\n",
179 __func__, ret);
180 return ret;
181 }
182 mdelay(5);
183
184 ret = regulator_set_enable_if_allowed(priv->vddio, 1);
185 if (ret) {
186 log_debug("%s: error enabling iovcc-supply (%d)\n",
187 __func__, ret);
188 return ret;
189 }
190 mdelay(1);
191
192 ret = regulator_set_enable_if_allowed(priv->vdd, 1);
193 if (ret) {
194 log_debug("%s: error enabling vcc-supply (%d)\n",
195 __func__, ret);
196 return ret;
197 }
198 mdelay(20);
199
200 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
201 if (ret) {
202 log_debug("%s: error changing reset-gpios (%d)\n",
203 __func__, ret);
204 return ret;
205 }
206 mdelay(2);
207
208 /* Reset panel */
209 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
210 if (ret) {
211 log_debug("%s: error changing reset-gpios (%d)\n",
212 __func__, ret);
213 return ret;
214 }
215 mdelay(1);
216
217 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
218 if (ret) {
219 log_debug("%s: error changing reset-gpios (%d)\n",
220 __func__, ret);
221 return ret;
222 }
223 mdelay(25);
224
225 return 0;
226}
227
Svyatoslav Ryheldef72d52023-04-25 10:51:47 +0300228static int endeavoru_panel_probe(struct udevice *dev)
229{
230 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
231
232 /* fill characteristics of DSI data link */
233 plat->lanes = 2;
234 plat->format = MIPI_DSI_FMT_RGB888;
235 plat->mode_flags = MIPI_DSI_MODE_VIDEO;
236
Svyatoslav Ryhel2a9ce5f2024-01-31 08:57:19 +0200237 return endeavoru_panel_hw_init(dev);
Svyatoslav Ryheldef72d52023-04-25 10:51:47 +0300238}
239
240static const struct panel_ops endeavoru_panel_ops = {
241 .enable_backlight = endeavoru_panel_enable_backlight,
242 .set_backlight = endeavoru_panel_set_backlight,
243 .get_display_timing = endeavoru_panel_timings,
244};
245
246static const struct udevice_id endeavoru_panel_ids[] = {
247 { .compatible = "htc,edge-panel" },
248 { }
249};
250
251U_BOOT_DRIVER(endeavoru_panel) = {
252 .name = "endeavoru_panel",
253 .id = UCLASS_PANEL,
254 .of_match = endeavoru_panel_ids,
255 .ops = &endeavoru_panel_ops,
256 .of_to_plat = endeavoru_panel_of_to_plat,
257 .probe = endeavoru_panel_probe,
258 .plat_auto = sizeof(struct mipi_dsi_panel_plat),
259 .priv_auto = sizeof(struct endeavoru_panel_priv),
260};