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