blob: 79a272128b87bc02eed50de61417ef4d2e8d6131 [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{
60 struct endeavoru_panel_priv *priv = dev_get_priv(dev);
61 int ret;
62
63 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
64 if (ret) {
65 log_err("error changing reset-gpios (%d)\n", ret);
66 return ret;
67 }
68 mdelay(5);
69
70 ret = regulator_set_enable_if_allowed(priv->vddio, 1);
71 if (ret) {
72 log_err("error enabling iovcc-supply (%d)\n", ret);
73 return ret;
74 }
75 mdelay(1);
76
77 ret = regulator_set_enable_if_allowed(priv->vdd, 1);
78 if (ret) {
79 log_err("error enabling vcc-supply (%d)\n", ret);
80 return ret;
81 }
82 mdelay(20);
83
84 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
85 if (ret) {
86 log_err("error changing reset-gpios (%d)\n", ret);
87 return ret;
88 }
89 mdelay(2);
90
91 /* Reset panel */
92 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
93 if (ret) {
94 log_err("error changing reset-gpios (%d)\n", ret);
95 return ret;
96 }
97 mdelay(1);
98
99 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
100 if (ret) {
101 log_err("error changing reset-gpios (%d)\n", ret);
102 return ret;
103 }
104 mdelay(25);
105
106 return 0;
107}
108
109static int endeavoru_panel_set_backlight(struct udevice *dev, int percent)
110{
111 struct endeavoru_panel_priv *priv = dev_get_priv(dev);
112 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
113 struct mipi_dsi_device *dsi = plat->device;
114 int ret;
115
116 dcs_write_one(dsi, 0xc2, 0x08);
117
118 /* color enhancement 2.2 */
119 dcs_write_one(dsi, 0xff, 0x03);
120 dcs_write_one(dsi, 0xfe, 0x08);
121 dcs_write_one(dsi, 0x18, 0x00);
122 dcs_write_one(dsi, 0x19, 0x00);
123 dcs_write_one(dsi, 0x1a, 0x00);
124 dcs_write_one(dsi, 0x25, 0x26);
125
126 dcs_write_seq(dsi, 0x00, 0x00, 0x05, 0x10, 0x17,
127 0x22, 0x26, 0x29, 0x29, 0x26, 0x23,
128 0x17, 0x12, 0x06, 0x02, 0x01, 0x00);
129
130 dcs_write_one(dsi, 0xfb, 0x01);
131 dcs_write_one(dsi, 0xff, 0x00);
132 dcs_write_one(dsi, 0xfe, 0x01);
133
134 mipi_dsi_dcs_exit_sleep_mode(dsi);
135
136 mdelay(105);
137
138 dcs_write_one(dsi, 0x35, 0x00);
139
140 /* PWM frequency adjust */
141 dcs_write_one(dsi, 0xff, 0x04);
142 dcs_write_one(dsi, 0x0a, 0x07);
143 dcs_write_one(dsi, 0x09, 0x20);
144 dcs_write_one(dsi, 0xff, 0x00);
145
146 dcs_write_one(dsi, 0xff, 0xee);
147 dcs_write_one(dsi, 0x12, 0x50);
148 dcs_write_one(dsi, 0x13, 0x02);
149 dcs_write_one(dsi, 0x6a, 0x60);
150 dcs_write_one(dsi, 0xfb, 0x01);
151 dcs_write_one(dsi, 0xff, 0x00);
152
153 mipi_dsi_dcs_set_display_on(dsi);
154
155 mdelay(42);
156
157 dcs_write_one(dsi, 0xba, 0x01);
158
159 dcs_write_one(dsi, 0x53, 0x24);
160 dcs_write_one(dsi, 0x55, 0x80);
161 dcs_write_one(dsi, 0x5e, 0x06);
162
163 ret = backlight_enable(priv->backlight);
164 if (ret)
165 return ret;
166
167 /* Set backlight */
168 dcs_write_one(dsi, 0x51, 0x96);
169
170 ret = backlight_set_brightness(priv->backlight, percent);
171 if (ret)
172 return ret;
173
174 return 0;
175}
176
177static int endeavoru_panel_timings(struct udevice *dev,
178 struct display_timing *timing)
179{
180 memcpy(timing, &default_timing, sizeof(*timing));
181 return 0;
182}
183
184static int endeavoru_panel_of_to_plat(struct udevice *dev)
185{
186 struct endeavoru_panel_priv *priv = dev_get_priv(dev);
187 int ret;
188
189 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
190 "backlight", &priv->backlight);
191 if (ret) {
192 log_err("cannot get backlight: ret = %d\n", ret);
193 return ret;
194 }
195
196 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
197 "vdd-supply", &priv->vdd);
198 if (ret) {
199 log_err("cannot get vdd-supply: ret = %d\n", ret);
200 return ret;
201 }
202
203 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
204 "vddio-supply", &priv->vddio);
205 if (ret) {
206 log_err("cannot get vddio-supply: ret = %d\n", ret);
207 return ret;
208 }
209
210 ret = gpio_request_by_name(dev, "reset-gpios", 0,
211 &priv->reset_gpio, GPIOD_IS_OUT);
212 if (ret) {
213 log_err("could not decode reser-gpios (%d)\n", ret);
214 return ret;
215 }
216
217 return 0;
218}
219
220static int endeavoru_panel_probe(struct udevice *dev)
221{
222 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
223
224 /* fill characteristics of DSI data link */
225 plat->lanes = 2;
226 plat->format = MIPI_DSI_FMT_RGB888;
227 plat->mode_flags = MIPI_DSI_MODE_VIDEO;
228
229 return 0;
230}
231
232static const struct panel_ops endeavoru_panel_ops = {
233 .enable_backlight = endeavoru_panel_enable_backlight,
234 .set_backlight = endeavoru_panel_set_backlight,
235 .get_display_timing = endeavoru_panel_timings,
236};
237
238static const struct udevice_id endeavoru_panel_ids[] = {
239 { .compatible = "htc,edge-panel" },
240 { }
241};
242
243U_BOOT_DRIVER(endeavoru_panel) = {
244 .name = "endeavoru_panel",
245 .id = UCLASS_PANEL,
246 .of_match = endeavoru_panel_ids,
247 .ops = &endeavoru_panel_ops,
248 .of_to_plat = endeavoru_panel_of_to_plat,
249 .probe = endeavoru_panel_probe,
250 .plat_auto = sizeof(struct mipi_dsi_panel_plat),
251 .priv_auto = sizeof(struct endeavoru_panel_priv),
252};