Prepare v2023.10
[platform/kernel/u-boot.git] / drivers / video / renesas-r61307.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Renesas R61307 panel driver
4  *
5  * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
6  */
7
8 #include <common.h>
9 #include <backlight.h>
10 #include <dm.h>
11 #include <panel.h>
12 #include <log.h>
13 #include <misc.h>
14 #include <mipi_display.h>
15 #include <mipi_dsi.h>
16 #include <asm/gpio.h>
17 #include <linux/delay.h>
18 #include <linux/err.h>
19 #include <power/regulator.h>
20
21 /*
22  * The datasheet is not publicly available, all values are
23  * taken from the downstream. If you have access to datasheets,
24  * corrections are welcome.
25  */
26
27 #define R61307_MACP             0xB0 /* Manufacturer CMD Protect */
28
29 #define R61307_INVERSION        0xC1
30 #define R61307_GAMMA_SET_A      0xC8 /* Gamma Setting A */
31 #define R61307_GAMMA_SET_B      0xC9 /* Gamma Setting B */
32 #define R61307_GAMMA_SET_C      0xCA /* Gamma Setting C */
33 #define R61307_CONTRAST_SET     0xCC
34
35 struct renesas_r61307_priv {
36         struct udevice *vcc;
37         struct udevice *iovcc;
38
39         struct udevice *backlight;
40
41         struct gpio_desc reset_gpio;
42
43         bool dig_cont_adj;
44         bool inversion;
45         u32 gamma;
46 };
47
48 static const u8 macp_on[] = {
49         R61307_MACP, 0x03
50 };
51
52 static const u8 macp_off[] = {
53         R61307_MACP, 0x04
54 };
55
56 static const u8 address_mode[] = {
57         MIPI_DCS_SET_ADDRESS_MODE
58 };
59
60 static const u8 contrast_setting[] = {
61         R61307_CONTRAST_SET,
62         0xdc, 0xb4, 0xff
63 };
64
65 static const u8 column_inversion[] = {
66         R61307_INVERSION,
67         0x00, 0x50, 0x03, 0x22,
68         0x16, 0x06, 0x60, 0x11
69 };
70
71 static const u8 line_inversion[] = {
72         R61307_INVERSION,
73         0x00, 0x10, 0x03, 0x22,
74         0x16, 0x06, 0x60, 0x01
75 };
76
77 static const u8 gamma_setting[][25] = {
78         {},
79         {
80                 R61307_GAMMA_SET_A,
81                 0x00, 0x06, 0x0a, 0x0f,
82                 0x14, 0x1f, 0x1f, 0x17,
83                 0x12, 0x0c, 0x09, 0x06,
84                 0x00, 0x06, 0x0a, 0x0f,
85                 0x14, 0x1f, 0x1f, 0x17,
86                 0x12, 0x0c, 0x09, 0x06
87         },
88         {
89                 R61307_GAMMA_SET_A,
90                 0x00, 0x05, 0x0b, 0x0f,
91                 0x11, 0x1d, 0x20, 0x18,
92                 0x18, 0x09, 0x07, 0x06,
93                 0x00, 0x05, 0x0b, 0x0f,
94                 0x11, 0x1d, 0x20, 0x18,
95                 0x18, 0x09, 0x07, 0x06
96         },
97         {
98                 R61307_GAMMA_SET_A,
99                 0x0b, 0x0d, 0x10, 0x14,
100                 0x13, 0x1d, 0x20, 0x18,
101                 0x12, 0x09, 0x07, 0x06,
102                 0x0a, 0x0c, 0x10, 0x14,
103                 0x13, 0x1d, 0x20, 0x18,
104                 0x12, 0x09, 0x07, 0x06
105         },
106 };
107
108 static struct display_timing default_timing = {
109         .pixelclock.typ         = 62000000,
110         .hactive.typ            = 768,
111         .hfront_porch.typ       = 116,
112         .hback_porch.typ        = 81,
113         .hsync_len.typ          = 5,
114         .vactive.typ            = 1024,
115         .vfront_porch.typ       = 24,
116         .vback_porch.typ        = 8,
117         .vsync_len.typ          = 2,
118 };
119
120 static int renesas_r61307_enable_backlight(struct udevice *dev)
121 {
122         struct renesas_r61307_priv *priv = dev_get_priv(dev);
123         int ret;
124
125         ret = regulator_set_enable_if_allowed(priv->vcc, 1);
126         if (ret) {
127                 log_err("enabling vcc-supply failed (%d)\n", ret);
128                 return ret;
129         }
130         mdelay(5);
131
132         ret = regulator_set_enable_if_allowed(priv->iovcc, 1);
133         if (ret) {
134                 log_err("enabling iovcc-supply failed (%d)\n", ret);
135                 return ret;
136         }
137
138         ret = dm_gpio_set_value(&priv->reset_gpio, 0);
139         if (ret) {
140                 log_err("changing reset-gpio failed (%d)\n", ret);
141                 return ret;
142         }
143         mdelay(5);
144
145         ret = dm_gpio_set_value(&priv->reset_gpio, 1);
146         if (ret) {
147                 log_err("changing reset-gpio failed (%d)\n", ret);
148                 return ret;
149         }
150
151         mdelay(5);
152
153         return 0;
154 }
155
156 static int renesas_r61307_set_backlight(struct udevice *dev, int percent)
157 {
158         struct renesas_r61307_priv *priv = dev_get_priv(dev);
159         struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
160         struct mipi_dsi_device *dsi = plat->device;
161         int ret;
162
163         ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
164         if (ret < 0) {
165                 log_err("failed to exit sleep mode: %d\n", ret);
166                 return ret;
167         }
168
169         mdelay(80);
170
171         mipi_dsi_dcs_write_buffer(dsi, address_mode,
172                                   sizeof(address_mode));
173
174         mdelay(20);
175
176         ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
177         if (ret < 0) {
178                 log_err("failed to set pixel format: %d\n", ret);
179                 return ret;
180         }
181
182         /* MACP Off */
183         mipi_dsi_generic_write(dsi, macp_off, sizeof(macp_off));
184
185         if (priv->dig_cont_adj)
186                 mipi_dsi_generic_write(dsi, contrast_setting,
187                                        sizeof(contrast_setting));
188
189         if (priv->gamma)
190                 mipi_dsi_generic_write(dsi, gamma_setting[priv->gamma],
191                                        sizeof(gamma_setting[priv->gamma]));
192
193         if (priv->inversion)
194                 mipi_dsi_generic_write(dsi, column_inversion,
195                                        sizeof(column_inversion));
196         else
197                 mipi_dsi_generic_write(dsi, line_inversion,
198                                        sizeof(line_inversion));
199
200         /* MACP On */
201         mipi_dsi_generic_write(dsi, macp_on, sizeof(macp_on));
202
203         ret = mipi_dsi_dcs_set_display_on(dsi);
204         if (ret < 0) {
205                 log_err("failed to set display on: %d\n", ret);
206                 return ret;
207         }
208
209         mdelay(50);
210
211         ret = backlight_enable(priv->backlight);
212         if (ret)
213                 return ret;
214
215         ret = backlight_set_brightness(priv->backlight, percent);
216         if (ret)
217                 return ret;
218
219         return 0;
220 }
221
222 static int renesas_r61307_timings(struct udevice *dev,
223                                   struct display_timing *timing)
224 {
225         memcpy(timing, &default_timing, sizeof(*timing));
226         return 0;
227 }
228
229 static int renesas_r61307_of_to_plat(struct udevice *dev)
230 {
231         struct renesas_r61307_priv *priv = dev_get_priv(dev);
232         int ret;
233
234         ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
235                                            "backlight", &priv->backlight);
236         if (ret) {
237                 log_err("Cannot get backlight: ret = %d\n", ret);
238                 return ret;
239         }
240
241         ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
242                                            "vcc-supply", &priv->vcc);
243         if (ret) {
244                 log_err("Cannot get vcc-supply: ret = %d\n", ret);
245                 return ret;
246         }
247
248         ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
249                                            "iovcc-supply", &priv->iovcc);
250         if (ret) {
251                 log_err("Cannot get iovcc-supply: ret = %d\n", ret);
252                 return ret;
253         }
254
255         ret = gpio_request_by_name(dev, "reset-gpios", 0,
256                                    &priv->reset_gpio, GPIOD_IS_OUT);
257         if (ret) {
258                 log_err("Could not decode reser-gpios (%d)\n", ret);
259                 return ret;
260         }
261
262         priv->dig_cont_adj = dev_read_bool(dev, "renesas,contrast");
263         priv->inversion = dev_read_bool(dev, "renesas,inversion");
264         priv->gamma = dev_read_u32_default(dev, "renesas,gamma", 0);
265
266         return 0;
267 }
268
269 static int renesas_r61307_probe(struct udevice *dev)
270 {
271         struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
272
273         /* fill characteristics of DSI data link */
274         plat->lanes = 4;
275         plat->format = MIPI_DSI_FMT_RGB888;
276         plat->mode_flags = MIPI_DSI_MODE_VIDEO;
277
278         return 0;
279 }
280
281 static const struct panel_ops renesas_r61307_ops = {
282         .enable_backlight       = renesas_r61307_enable_backlight,
283         .set_backlight          = renesas_r61307_set_backlight,
284         .get_display_timing     = renesas_r61307_timings,
285 };
286
287 static const struct udevice_id renesas_r61307_ids[] = {
288         { .compatible = "koe,tx13d100vm0eaa" },
289         { .compatible = "hitachi,tx13d100vm0eaa" },
290         { }
291 };
292
293 U_BOOT_DRIVER(renesas_r61307) = {
294         .name           = "renesas_r61307",
295         .id             = UCLASS_PANEL,
296         .of_match       = renesas_r61307_ids,
297         .ops            = &renesas_r61307_ops,
298         .of_to_plat     = renesas_r61307_of_to_plat,
299         .probe          = renesas_r61307_probe,
300         .plat_auto      = sizeof(struct mipi_dsi_panel_plat),
301         .priv_auto      = sizeof(struct renesas_r61307_priv),
302 };