1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018 MediaTek Inc.
4 * Author: Jitao Shi <jitao.shi@mediatek.com>
5 */
6
7#include <linux/delay.h>
8#include <linux/gpio/consumer.h>
9#include <linux/module.h>
10#include <linux/of.h>
11#include <linux/of_device.h>
12#include <linux/regulator/consumer.h>
13
14#include <drm/drm_connector.h>
15#include <drm/drm_crtc.h>
16#include <drm/drm_mipi_dsi.h>
17#include <drm/drm_panel.h>
18
19#include <video/mipi_display.h>
20
21struct panel_desc {
22	const struct drm_display_mode *modes;
23	unsigned int bpc;
24
25	/**
26	 * @width_mm: width of the panel's active display area
27	 * @height_mm: height of the panel's active display area
28	 */
29	struct {
30		unsigned int width_mm;
31		unsigned int height_mm;
32	} size;
33
34	unsigned long mode_flags;
35	enum mipi_dsi_pixel_format format;
36	const struct panel_init_cmd *init_cmds;
37	unsigned int lanes;
38	bool discharge_on_disable;
39	bool lp11_before_reset;
40};
41
42struct boe_panel {
43	struct drm_panel base;
44	struct mipi_dsi_device *dsi;
45
46	const struct panel_desc *desc;
47
48	enum drm_panel_orientation orientation;
49	struct regulator *pp1800;
50	struct regulator *avee;
51	struct regulator *avdd;
52	struct gpio_desc *enable_gpio;
53
54	bool prepared;
55};
56
57enum dsi_cmd_type {
58	INIT_DCS_CMD,
59	DELAY_CMD,
60};
61
62struct panel_init_cmd {
63	enum dsi_cmd_type type;
64	size_t len;
65	const char *data;
66};
67
68#define _INIT_DCS_CMD(...) { \
69	.type = INIT_DCS_CMD, \
70	.len = sizeof((char[]){__VA_ARGS__}), \
71	.data = (char[]){__VA_ARGS__} }
72
73#define _INIT_DELAY_CMD(...) { \
74	.type = DELAY_CMD,\
75	.len = sizeof((char[]){__VA_ARGS__}), \
76	.data = (char[]){__VA_ARGS__} }
77
78static const struct panel_init_cmd boe_init_cmd[] = {
79	_INIT_DELAY_CMD(24),
80	_INIT_DCS_CMD(0xB0, 0x05),
81	_INIT_DCS_CMD(0xB1, 0xE5),
82	_INIT_DCS_CMD(0xB3, 0x52),
83	_INIT_DCS_CMD(0xB0, 0x00),
84	_INIT_DCS_CMD(0xB3, 0x88),
85	_INIT_DCS_CMD(0xB0, 0x04),
86	_INIT_DCS_CMD(0xB8, 0x00),
87	_INIT_DCS_CMD(0xB0, 0x00),
88	_INIT_DCS_CMD(0xB6, 0x03),
89	_INIT_DCS_CMD(0xBA, 0x8B),
90	_INIT_DCS_CMD(0xBF, 0x1A),
91	_INIT_DCS_CMD(0xC0, 0x0F),
92	_INIT_DCS_CMD(0xC2, 0x0C),
93	_INIT_DCS_CMD(0xC3, 0x02),
94	_INIT_DCS_CMD(0xC4, 0x0C),
95	_INIT_DCS_CMD(0xC5, 0x02),
96	_INIT_DCS_CMD(0xB0, 0x01),
97	_INIT_DCS_CMD(0xE0, 0x26),
98	_INIT_DCS_CMD(0xE1, 0x26),
99	_INIT_DCS_CMD(0xDC, 0x00),
100	_INIT_DCS_CMD(0xDD, 0x00),
101	_INIT_DCS_CMD(0xCC, 0x26),
102	_INIT_DCS_CMD(0xCD, 0x26),
103	_INIT_DCS_CMD(0xC8, 0x00),
104	_INIT_DCS_CMD(0xC9, 0x00),
105	_INIT_DCS_CMD(0xD2, 0x03),
106	_INIT_DCS_CMD(0xD3, 0x03),
107	_INIT_DCS_CMD(0xE6, 0x04),
108	_INIT_DCS_CMD(0xE7, 0x04),
109	_INIT_DCS_CMD(0xC4, 0x09),
110	_INIT_DCS_CMD(0xC5, 0x09),
111	_INIT_DCS_CMD(0xD8, 0x0A),
112	_INIT_DCS_CMD(0xD9, 0x0A),
113	_INIT_DCS_CMD(0xC2, 0x0B),
114	_INIT_DCS_CMD(0xC3, 0x0B),
115	_INIT_DCS_CMD(0xD6, 0x0C),
116	_INIT_DCS_CMD(0xD7, 0x0C),
117	_INIT_DCS_CMD(0xC0, 0x05),
118	_INIT_DCS_CMD(0xC1, 0x05),
119	_INIT_DCS_CMD(0xD4, 0x06),
120	_INIT_DCS_CMD(0xD5, 0x06),
121	_INIT_DCS_CMD(0xCA, 0x07),
122	_INIT_DCS_CMD(0xCB, 0x07),
123	_INIT_DCS_CMD(0xDE, 0x08),
124	_INIT_DCS_CMD(0xDF, 0x08),
125	_INIT_DCS_CMD(0xB0, 0x02),
126	_INIT_DCS_CMD(0xC0, 0x00),
127	_INIT_DCS_CMD(0xC1, 0x0D),
128	_INIT_DCS_CMD(0xC2, 0x17),
129	_INIT_DCS_CMD(0xC3, 0x26),
130	_INIT_DCS_CMD(0xC4, 0x31),
131	_INIT_DCS_CMD(0xC5, 0x1C),
132	_INIT_DCS_CMD(0xC6, 0x2C),
133	_INIT_DCS_CMD(0xC7, 0x33),
134	_INIT_DCS_CMD(0xC8, 0x31),
135	_INIT_DCS_CMD(0xC9, 0x37),
136	_INIT_DCS_CMD(0xCA, 0x37),
137	_INIT_DCS_CMD(0xCB, 0x37),
138	_INIT_DCS_CMD(0xCC, 0x39),
139	_INIT_DCS_CMD(0xCD, 0x2E),
140	_INIT_DCS_CMD(0xCE, 0x2F),
141	_INIT_DCS_CMD(0xCF, 0x2F),
142	_INIT_DCS_CMD(0xD0, 0x07),
143	_INIT_DCS_CMD(0xD2, 0x00),
144	_INIT_DCS_CMD(0xD3, 0x0D),
145	_INIT_DCS_CMD(0xD4, 0x17),
146	_INIT_DCS_CMD(0xD5, 0x26),
147	_INIT_DCS_CMD(0xD6, 0x31),
148	_INIT_DCS_CMD(0xD7, 0x3F),
149	_INIT_DCS_CMD(0xD8, 0x3F),
150	_INIT_DCS_CMD(0xD9, 0x3F),
151	_INIT_DCS_CMD(0xDA, 0x3F),
152	_INIT_DCS_CMD(0xDB, 0x37),
153	_INIT_DCS_CMD(0xDC, 0x37),
154	_INIT_DCS_CMD(0xDD, 0x37),
155	_INIT_DCS_CMD(0xDE, 0x39),
156	_INIT_DCS_CMD(0xDF, 0x2E),
157	_INIT_DCS_CMD(0xE0, 0x2F),
158	_INIT_DCS_CMD(0xE1, 0x2F),
159	_INIT_DCS_CMD(0xE2, 0x07),
160	_INIT_DCS_CMD(0xB0, 0x03),
161	_INIT_DCS_CMD(0xC8, 0x0B),
162	_INIT_DCS_CMD(0xC9, 0x07),
163	_INIT_DCS_CMD(0xC3, 0x00),
164	_INIT_DCS_CMD(0xE7, 0x00),
165	_INIT_DCS_CMD(0xC5, 0x2A),
166	_INIT_DCS_CMD(0xDE, 0x2A),
167	_INIT_DCS_CMD(0xCA, 0x43),
168	_INIT_DCS_CMD(0xC9, 0x07),
169	_INIT_DCS_CMD(0xE4, 0xC0),
170	_INIT_DCS_CMD(0xE5, 0x0D),
171	_INIT_DCS_CMD(0xCB, 0x00),
172	_INIT_DCS_CMD(0xB0, 0x06),
173	_INIT_DCS_CMD(0xB8, 0xA5),
174	_INIT_DCS_CMD(0xC0, 0xA5),
175	_INIT_DCS_CMD(0xC7, 0x0F),
176	_INIT_DCS_CMD(0xD5, 0x32),
177	_INIT_DCS_CMD(0xB8, 0x00),
178	_INIT_DCS_CMD(0xC0, 0x00),
179	_INIT_DCS_CMD(0xBC, 0x00),
180	_INIT_DCS_CMD(0xB0, 0x07),
181	_INIT_DCS_CMD(0xB1, 0x00),
182	_INIT_DCS_CMD(0xB2, 0x02),
183	_INIT_DCS_CMD(0xB3, 0x0F),
184	_INIT_DCS_CMD(0xB4, 0x25),
185	_INIT_DCS_CMD(0xB5, 0x39),
186	_INIT_DCS_CMD(0xB6, 0x4E),
187	_INIT_DCS_CMD(0xB7, 0x72),
188	_INIT_DCS_CMD(0xB8, 0x97),
189	_INIT_DCS_CMD(0xB9, 0xDC),
190	_INIT_DCS_CMD(0xBA, 0x22),
191	_INIT_DCS_CMD(0xBB, 0xA4),
192	_INIT_DCS_CMD(0xBC, 0x2B),
193	_INIT_DCS_CMD(0xBD, 0x2F),
194	_INIT_DCS_CMD(0xBE, 0xA9),
195	_INIT_DCS_CMD(0xBF, 0x25),
196	_INIT_DCS_CMD(0xC0, 0x61),
197	_INIT_DCS_CMD(0xC1, 0x97),
198	_INIT_DCS_CMD(0xC2, 0xB2),
199	_INIT_DCS_CMD(0xC3, 0xCD),
200	_INIT_DCS_CMD(0xC4, 0xD9),
201	_INIT_DCS_CMD(0xC5, 0xE7),
202	_INIT_DCS_CMD(0xC6, 0xF4),
203	_INIT_DCS_CMD(0xC7, 0xFA),
204	_INIT_DCS_CMD(0xC8, 0xFC),
205	_INIT_DCS_CMD(0xC9, 0x00),
206	_INIT_DCS_CMD(0xCA, 0x00),
207	_INIT_DCS_CMD(0xCB, 0x16),
208	_INIT_DCS_CMD(0xCC, 0xAF),
209	_INIT_DCS_CMD(0xCD, 0xFF),
210	_INIT_DCS_CMD(0xCE, 0xFF),
211	_INIT_DCS_CMD(0xB0, 0x08),
212	_INIT_DCS_CMD(0xB1, 0x04),
213	_INIT_DCS_CMD(0xB2, 0x05),
214	_INIT_DCS_CMD(0xB3, 0x11),
215	_INIT_DCS_CMD(0xB4, 0x24),
216	_INIT_DCS_CMD(0xB5, 0x39),
217	_INIT_DCS_CMD(0xB6, 0x4F),
218	_INIT_DCS_CMD(0xB7, 0x72),
219	_INIT_DCS_CMD(0xB8, 0x98),
220	_INIT_DCS_CMD(0xB9, 0xDC),
221	_INIT_DCS_CMD(0xBA, 0x23),
222	_INIT_DCS_CMD(0xBB, 0xA6),
223	_INIT_DCS_CMD(0xBC, 0x2C),
224	_INIT_DCS_CMD(0xBD, 0x30),
225	_INIT_DCS_CMD(0xBE, 0xAA),
226	_INIT_DCS_CMD(0xBF, 0x26),
227	_INIT_DCS_CMD(0xC0, 0x62),
228	_INIT_DCS_CMD(0xC1, 0x9B),
229	_INIT_DCS_CMD(0xC2, 0xB5),
230	_INIT_DCS_CMD(0xC3, 0xCF),
231	_INIT_DCS_CMD(0xC4, 0xDB),
232	_INIT_DCS_CMD(0xC5, 0xE8),
233	_INIT_DCS_CMD(0xC6, 0xF5),
234	_INIT_DCS_CMD(0xC7, 0xFA),
235	_INIT_DCS_CMD(0xC8, 0xFC),
236	_INIT_DCS_CMD(0xC9, 0x00),
237	_INIT_DCS_CMD(0xCA, 0x00),
238	_INIT_DCS_CMD(0xCB, 0x16),
239	_INIT_DCS_CMD(0xCC, 0xAF),
240	_INIT_DCS_CMD(0xCD, 0xFF),
241	_INIT_DCS_CMD(0xCE, 0xFF),
242	_INIT_DCS_CMD(0xB0, 0x09),
243	_INIT_DCS_CMD(0xB1, 0x04),
244	_INIT_DCS_CMD(0xB2, 0x02),
245	_INIT_DCS_CMD(0xB3, 0x16),
246	_INIT_DCS_CMD(0xB4, 0x24),
247	_INIT_DCS_CMD(0xB5, 0x3B),
248	_INIT_DCS_CMD(0xB6, 0x4F),
249	_INIT_DCS_CMD(0xB7, 0x73),
250	_INIT_DCS_CMD(0xB8, 0x99),
251	_INIT_DCS_CMD(0xB9, 0xE0),
252	_INIT_DCS_CMD(0xBA, 0x26),
253	_INIT_DCS_CMD(0xBB, 0xAD),
254	_INIT_DCS_CMD(0xBC, 0x36),
255	_INIT_DCS_CMD(0xBD, 0x3A),
256	_INIT_DCS_CMD(0xBE, 0xAE),
257	_INIT_DCS_CMD(0xBF, 0x2A),
258	_INIT_DCS_CMD(0xC0, 0x66),
259	_INIT_DCS_CMD(0xC1, 0x9E),
260	_INIT_DCS_CMD(0xC2, 0xB8),
261	_INIT_DCS_CMD(0xC3, 0xD1),
262	_INIT_DCS_CMD(0xC4, 0xDD),
263	_INIT_DCS_CMD(0xC5, 0xE9),
264	_INIT_DCS_CMD(0xC6, 0xF6),
265	_INIT_DCS_CMD(0xC7, 0xFA),
266	_INIT_DCS_CMD(0xC8, 0xFC),
267	_INIT_DCS_CMD(0xC9, 0x00),
268	_INIT_DCS_CMD(0xCA, 0x00),
269	_INIT_DCS_CMD(0xCB, 0x16),
270	_INIT_DCS_CMD(0xCC, 0xAF),
271	_INIT_DCS_CMD(0xCD, 0xFF),
272	_INIT_DCS_CMD(0xCE, 0xFF),
273	_INIT_DCS_CMD(0xB0, 0x0A),
274	_INIT_DCS_CMD(0xB1, 0x00),
275	_INIT_DCS_CMD(0xB2, 0x02),
276	_INIT_DCS_CMD(0xB3, 0x0F),
277	_INIT_DCS_CMD(0xB4, 0x25),
278	_INIT_DCS_CMD(0xB5, 0x39),
279	_INIT_DCS_CMD(0xB6, 0x4E),
280	_INIT_DCS_CMD(0xB7, 0x72),
281	_INIT_DCS_CMD(0xB8, 0x97),
282	_INIT_DCS_CMD(0xB9, 0xDC),
283	_INIT_DCS_CMD(0xBA, 0x22),
284	_INIT_DCS_CMD(0xBB, 0xA4),
285	_INIT_DCS_CMD(0xBC, 0x2B),
286	_INIT_DCS_CMD(0xBD, 0x2F),
287	_INIT_DCS_CMD(0xBE, 0xA9),
288	_INIT_DCS_CMD(0xBF, 0x25),
289	_INIT_DCS_CMD(0xC0, 0x61),
290	_INIT_DCS_CMD(0xC1, 0x97),
291	_INIT_DCS_CMD(0xC2, 0xB2),
292	_INIT_DCS_CMD(0xC3, 0xCD),
293	_INIT_DCS_CMD(0xC4, 0xD9),
294	_INIT_DCS_CMD(0xC5, 0xE7),
295	_INIT_DCS_CMD(0xC6, 0xF4),
296	_INIT_DCS_CMD(0xC7, 0xFA),
297	_INIT_DCS_CMD(0xC8, 0xFC),
298	_INIT_DCS_CMD(0xC9, 0x00),
299	_INIT_DCS_CMD(0xCA, 0x00),
300	_INIT_DCS_CMD(0xCB, 0x16),
301	_INIT_DCS_CMD(0xCC, 0xAF),
302	_INIT_DCS_CMD(0xCD, 0xFF),
303	_INIT_DCS_CMD(0xCE, 0xFF),
304	_INIT_DCS_CMD(0xB0, 0x0B),
305	_INIT_DCS_CMD(0xB1, 0x04),
306	_INIT_DCS_CMD(0xB2, 0x05),
307	_INIT_DCS_CMD(0xB3, 0x11),
308	_INIT_DCS_CMD(0xB4, 0x24),
309	_INIT_DCS_CMD(0xB5, 0x39),
310	_INIT_DCS_CMD(0xB6, 0x4F),
311	_INIT_DCS_CMD(0xB7, 0x72),
312	_INIT_DCS_CMD(0xB8, 0x98),
313	_INIT_DCS_CMD(0xB9, 0xDC),
314	_INIT_DCS_CMD(0xBA, 0x23),
315	_INIT_DCS_CMD(0xBB, 0xA6),
316	_INIT_DCS_CMD(0xBC, 0x2C),
317	_INIT_DCS_CMD(0xBD, 0x30),
318	_INIT_DCS_CMD(0xBE, 0xAA),
319	_INIT_DCS_CMD(0xBF, 0x26),
320	_INIT_DCS_CMD(0xC0, 0x62),
321	_INIT_DCS_CMD(0xC1, 0x9B),
322	_INIT_DCS_CMD(0xC2, 0xB5),
323	_INIT_DCS_CMD(0xC3, 0xCF),
324	_INIT_DCS_CMD(0xC4, 0xDB),
325	_INIT_DCS_CMD(0xC5, 0xE8),
326	_INIT_DCS_CMD(0xC6, 0xF5),
327	_INIT_DCS_CMD(0xC7, 0xFA),
328	_INIT_DCS_CMD(0xC8, 0xFC),
329	_INIT_DCS_CMD(0xC9, 0x00),
330	_INIT_DCS_CMD(0xCA, 0x00),
331	_INIT_DCS_CMD(0xCB, 0x16),
332	_INIT_DCS_CMD(0xCC, 0xAF),
333	_INIT_DCS_CMD(0xCD, 0xFF),
334	_INIT_DCS_CMD(0xCE, 0xFF),
335	_INIT_DCS_CMD(0xB0, 0x0C),
336	_INIT_DCS_CMD(0xB1, 0x04),
337	_INIT_DCS_CMD(0xB2, 0x02),
338	_INIT_DCS_CMD(0xB3, 0x16),
339	_INIT_DCS_CMD(0xB4, 0x24),
340	_INIT_DCS_CMD(0xB5, 0x3B),
341	_INIT_DCS_CMD(0xB6, 0x4F),
342	_INIT_DCS_CMD(0xB7, 0x73),
343	_INIT_DCS_CMD(0xB8, 0x99),
344	_INIT_DCS_CMD(0xB9, 0xE0),
345	_INIT_DCS_CMD(0xBA, 0x26),
346	_INIT_DCS_CMD(0xBB, 0xAD),
347	_INIT_DCS_CMD(0xBC, 0x36),
348	_INIT_DCS_CMD(0xBD, 0x3A),
349	_INIT_DCS_CMD(0xBE, 0xAE),
350	_INIT_DCS_CMD(0xBF, 0x2A),
351	_INIT_DCS_CMD(0xC0, 0x66),
352	_INIT_DCS_CMD(0xC1, 0x9E),
353	_INIT_DCS_CMD(0xC2, 0xB8),
354	_INIT_DCS_CMD(0xC3, 0xD1),
355	_INIT_DCS_CMD(0xC4, 0xDD),
356	_INIT_DCS_CMD(0xC5, 0xE9),
357	_INIT_DCS_CMD(0xC6, 0xF6),
358	_INIT_DCS_CMD(0xC7, 0xFA),
359	_INIT_DCS_CMD(0xC8, 0xFC),
360	_INIT_DCS_CMD(0xC9, 0x00),
361	_INIT_DCS_CMD(0xCA, 0x00),
362	_INIT_DCS_CMD(0xCB, 0x16),
363	_INIT_DCS_CMD(0xCC, 0xAF),
364	_INIT_DCS_CMD(0xCD, 0xFF),
365	_INIT_DCS_CMD(0xCE, 0xFF),
366	_INIT_DCS_CMD(0xB0, 0x00),
367	_INIT_DCS_CMD(0xB3, 0x08),
368	_INIT_DCS_CMD(0xB0, 0x04),
369	_INIT_DCS_CMD(0xB8, 0x68),
370	_INIT_DELAY_CMD(150),
371	{},
372};
373
374static const struct panel_init_cmd auo_kd101n80_45na_init_cmd[] = {
375	_INIT_DELAY_CMD(24),
376	_INIT_DCS_CMD(0x11),
377	_INIT_DELAY_CMD(120),
378	_INIT_DCS_CMD(0x29),
379	_INIT_DELAY_CMD(120),
380	{},
381};
382
383static const struct panel_init_cmd auo_b101uan08_3_init_cmd[] = {
384	_INIT_DELAY_CMD(24),
385	_INIT_DCS_CMD(0xB0, 0x01),
386	_INIT_DCS_CMD(0xC0, 0x48),
387	_INIT_DCS_CMD(0xC1, 0x48),
388	_INIT_DCS_CMD(0xC2, 0x47),
389	_INIT_DCS_CMD(0xC3, 0x47),
390	_INIT_DCS_CMD(0xC4, 0x46),
391	_INIT_DCS_CMD(0xC5, 0x46),
392	_INIT_DCS_CMD(0xC6, 0x45),
393	_INIT_DCS_CMD(0xC7, 0x45),
394	_INIT_DCS_CMD(0xC8, 0x64),
395	_INIT_DCS_CMD(0xC9, 0x64),
396	_INIT_DCS_CMD(0xCA, 0x4F),
397	_INIT_DCS_CMD(0xCB, 0x4F),
398	_INIT_DCS_CMD(0xCC, 0x40),
399	_INIT_DCS_CMD(0xCD, 0x40),
400	_INIT_DCS_CMD(0xCE, 0x66),
401	_INIT_DCS_CMD(0xCF, 0x66),
402	_INIT_DCS_CMD(0xD0, 0x4F),
403	_INIT_DCS_CMD(0xD1, 0x4F),
404	_INIT_DCS_CMD(0xD2, 0x41),
405	_INIT_DCS_CMD(0xD3, 0x41),
406	_INIT_DCS_CMD(0xD4, 0x48),
407	_INIT_DCS_CMD(0xD5, 0x48),
408	_INIT_DCS_CMD(0xD6, 0x47),
409	_INIT_DCS_CMD(0xD7, 0x47),
410	_INIT_DCS_CMD(0xD8, 0x46),
411	_INIT_DCS_CMD(0xD9, 0x46),
412	_INIT_DCS_CMD(0xDA, 0x45),
413	_INIT_DCS_CMD(0xDB, 0x45),
414	_INIT_DCS_CMD(0xDC, 0x64),
415	_INIT_DCS_CMD(0xDD, 0x64),
416	_INIT_DCS_CMD(0xDE, 0x4F),
417	_INIT_DCS_CMD(0xDF, 0x4F),
418	_INIT_DCS_CMD(0xE0, 0x40),
419	_INIT_DCS_CMD(0xE1, 0x40),
420	_INIT_DCS_CMD(0xE2, 0x66),
421	_INIT_DCS_CMD(0xE3, 0x66),
422	_INIT_DCS_CMD(0xE4, 0x4F),
423	_INIT_DCS_CMD(0xE5, 0x4F),
424	_INIT_DCS_CMD(0xE6, 0x41),
425	_INIT_DCS_CMD(0xE7, 0x41),
426	_INIT_DELAY_CMD(150),
427	{},
428};
429
430static inline struct boe_panel *to_boe_panel(struct drm_panel *panel)
431{
432	return container_of(panel, struct boe_panel, base);
433}
434
435static int boe_panel_init_dcs_cmd(struct boe_panel *boe)
436{
437	struct mipi_dsi_device *dsi = boe->dsi;
438	struct drm_panel *panel = &boe->base;
439	int i, err = 0;
440
441	if (boe->desc->init_cmds) {
442		const struct panel_init_cmd *init_cmds = boe->desc->init_cmds;
443
444		for (i = 0; init_cmds[i].len != 0; i++) {
445			const struct panel_init_cmd *cmd = &init_cmds[i];
446
447			switch (cmd->type) {
448			case DELAY_CMD:
449				msleep(cmd->data[0]);
450				err = 0;
451				break;
452
453			case INIT_DCS_CMD:
454				err = mipi_dsi_dcs_write(dsi, cmd->data[0],
455							 cmd->len <= 1 ? NULL :
456							 &cmd->data[1],
457							 cmd->len - 1);
458				break;
459
460			default:
461				err = -EINVAL;
462			}
463
464			if (err < 0) {
465				dev_err(panel->dev,
466					"failed to write command %u\n", i);
467				return err;
468			}
469		}
470	}
471	return 0;
472}
473
474static int boe_panel_enter_sleep_mode(struct boe_panel *boe)
475{
476	struct mipi_dsi_device *dsi = boe->dsi;
477	int ret;
478
479	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
480
481	ret = mipi_dsi_dcs_set_display_off(dsi);
482	if (ret < 0)
483		return ret;
484
485	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
486	if (ret < 0)
487		return ret;
488
489	return 0;
490}
491
492static int boe_panel_unprepare(struct drm_panel *panel)
493{
494	struct boe_panel *boe = to_boe_panel(panel);
495	int ret;
496
497	if (!boe->prepared)
498		return 0;
499
500	ret = boe_panel_enter_sleep_mode(boe);
501	if (ret < 0) {
502		dev_err(panel->dev, "failed to set panel off: %d\n", ret);
503		return ret;
504	}
505
506	msleep(150);
507
508	if (boe->desc->discharge_on_disable) {
509		regulator_disable(boe->avee);
510		regulator_disable(boe->avdd);
511		usleep_range(5000, 7000);
512		gpiod_set_value(boe->enable_gpio, 0);
513		usleep_range(5000, 7000);
514		regulator_disable(boe->pp1800);
515	} else {
516		gpiod_set_value(boe->enable_gpio, 0);
517		usleep_range(500, 1000);
518		regulator_disable(boe->avee);
519		regulator_disable(boe->avdd);
520		usleep_range(5000, 7000);
521		regulator_disable(boe->pp1800);
522	}
523
524	boe->prepared = false;
525
526	return 0;
527}
528
529static int boe_panel_prepare(struct drm_panel *panel)
530{
531	struct boe_panel *boe = to_boe_panel(panel);
532	int ret;
533
534	if (boe->prepared)
535		return 0;
536
537	gpiod_set_value(boe->enable_gpio, 0);
538	usleep_range(1000, 1500);
539
540	ret = regulator_enable(boe->pp1800);
541	if (ret < 0)
542		return ret;
543
544	usleep_range(3000, 5000);
545
546	ret = regulator_enable(boe->avdd);
547	if (ret < 0)
548		goto poweroff1v8;
549	ret = regulator_enable(boe->avee);
550	if (ret < 0)
551		goto poweroffavdd;
552
553	usleep_range(5000, 10000);
554
555	if (boe->desc->lp11_before_reset) {
556		mipi_dsi_dcs_nop(boe->dsi);
557		usleep_range(1000, 2000);
558	}
559	gpiod_set_value(boe->enable_gpio, 1);
560	usleep_range(1000, 2000);
561	gpiod_set_value(boe->enable_gpio, 0);
562	usleep_range(1000, 2000);
563	gpiod_set_value(boe->enable_gpio, 1);
564	usleep_range(6000, 10000);
565
566	ret = boe_panel_init_dcs_cmd(boe);
567	if (ret < 0) {
568		dev_err(panel->dev, "failed to init panel: %d\n", ret);
569		goto poweroff;
570	}
571
572	boe->prepared = true;
573
574	return 0;
575
576poweroff:
577	regulator_disable(boe->avee);
578poweroffavdd:
579	regulator_disable(boe->avdd);
580poweroff1v8:
581	usleep_range(5000, 7000);
582	regulator_disable(boe->pp1800);
583	gpiod_set_value(boe->enable_gpio, 0);
584
585	return ret;
586}
587
588static int boe_panel_enable(struct drm_panel *panel)
589{
590	msleep(130);
591	return 0;
592}
593
594static const struct drm_display_mode boe_tv101wum_nl6_default_mode = {
595	.clock = 159425,
596	.hdisplay = 1200,
597	.hsync_start = 1200 + 100,
598	.hsync_end = 1200 + 100 + 40,
599	.htotal = 1200 + 100 + 40 + 24,
600	.vdisplay = 1920,
601	.vsync_start = 1920 + 10,
602	.vsync_end = 1920 + 10 + 14,
603	.vtotal = 1920 + 10 + 14 + 4,
604};
605
606static const struct panel_desc boe_tv101wum_nl6_desc = {
607	.modes = &boe_tv101wum_nl6_default_mode,
608	.bpc = 8,
609	.size = {
610		.width_mm = 135,
611		.height_mm = 216,
612	},
613	.lanes = 4,
614	.format = MIPI_DSI_FMT_RGB888,
615	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
616		      MIPI_DSI_MODE_LPM,
617	.init_cmds = boe_init_cmd,
618	.discharge_on_disable = false,
619};
620
621static const struct drm_display_mode auo_kd101n80_45na_default_mode = {
622	.clock = 157000,
623	.hdisplay = 1200,
624	.hsync_start = 1200 + 60,
625	.hsync_end = 1200 + 60 + 24,
626	.htotal = 1200 + 60 + 24 + 56,
627	.vdisplay = 1920,
628	.vsync_start = 1920 + 16,
629	.vsync_end = 1920 + 16 + 4,
630	.vtotal = 1920 + 16 + 4 + 16,
631};
632
633static const struct panel_desc auo_kd101n80_45na_desc = {
634	.modes = &auo_kd101n80_45na_default_mode,
635	.bpc = 8,
636	.size = {
637		.width_mm = 135,
638		.height_mm = 216,
639	},
640	.lanes = 4,
641	.format = MIPI_DSI_FMT_RGB888,
642	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
643		      MIPI_DSI_MODE_LPM,
644	.init_cmds = auo_kd101n80_45na_init_cmd,
645	.discharge_on_disable = true,
646};
647
648static const struct drm_display_mode boe_tv101wum_n53_default_mode = {
649	.clock = 159916,
650	.hdisplay = 1200,
651	.hsync_start = 1200 + 80,
652	.hsync_end = 1200 + 80 + 24,
653	.htotal = 1200 + 80 + 24 + 60,
654	.vdisplay = 1920,
655	.vsync_start = 1920 + 20,
656	.vsync_end = 1920 + 20 + 4,
657	.vtotal = 1920 + 20 + 4 + 10,
658	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
659};
660
661static const struct panel_desc boe_tv101wum_n53_desc = {
662	.modes = &boe_tv101wum_n53_default_mode,
663	.bpc = 8,
664	.size = {
665		.width_mm = 135,
666		.height_mm = 216,
667	},
668	.lanes = 4,
669	.format = MIPI_DSI_FMT_RGB888,
670	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
671		      MIPI_DSI_MODE_LPM,
672	.init_cmds = boe_init_cmd,
673};
674
675static const struct drm_display_mode auo_b101uan08_3_default_mode = {
676	.clock = 159667,
677	.hdisplay = 1200,
678	.hsync_start = 1200 + 60,
679	.hsync_end = 1200 + 60 + 4,
680	.htotal = 1200 + 60 + 4 + 80,
681	.vdisplay = 1920,
682	.vsync_start = 1920 + 34,
683	.vsync_end = 1920 + 34 + 2,
684	.vtotal = 1920 + 34 + 2 + 24,
685	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
686};
687
688static const struct panel_desc auo_b101uan08_3_desc = {
689	.modes = &auo_b101uan08_3_default_mode,
690	.bpc = 8,
691	.size = {
692		.width_mm = 135,
693		.height_mm = 216,
694	},
695	.lanes = 4,
696	.format = MIPI_DSI_FMT_RGB888,
697	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
698		      MIPI_DSI_MODE_LPM,
699	.init_cmds = auo_b101uan08_3_init_cmd,
700	.lp11_before_reset = true,
701};
702
703static const struct drm_display_mode boe_tv105wum_nw0_default_mode = {
704	.clock = 159916,
705	.hdisplay = 1200,
706	.hsync_start = 1200 + 80,
707	.hsync_end = 1200 + 80 + 24,
708	.htotal = 1200 + 80 + 24 + 60,
709	.vdisplay = 1920,
710	.vsync_start = 1920 + 20,
711	.vsync_end = 1920 + 20 + 4,
712	.vtotal = 1920 + 20 + 4 + 10,
713	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
714};
715
716static const struct panel_desc boe_tv105wum_nw0_desc = {
717	.modes = &boe_tv105wum_nw0_default_mode,
718	.bpc = 8,
719	.size = {
720		.width_mm = 141,
721		.height_mm = 226,
722	},
723	.lanes = 4,
724	.format = MIPI_DSI_FMT_RGB888,
725	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
726		      MIPI_DSI_MODE_LPM,
727	.init_cmds = boe_init_cmd,
728	.lp11_before_reset = true,
729};
730
731static int boe_panel_get_modes(struct drm_panel *panel,
732			       struct drm_connector *connector)
733{
734	struct boe_panel *boe = to_boe_panel(panel);
735	const struct drm_display_mode *m = boe->desc->modes;
736	struct drm_display_mode *mode;
737
738	mode = drm_mode_duplicate(connector->dev, m);
739	if (!mode) {
740		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
741			m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
742		return -ENOMEM;
743	}
744
745	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
746	drm_mode_set_name(mode);
747	drm_mode_probed_add(connector, mode);
748
749	connector->display_info.width_mm = boe->desc->size.width_mm;
750	connector->display_info.height_mm = boe->desc->size.height_mm;
751	connector->display_info.bpc = boe->desc->bpc;
752	drm_connector_set_panel_orientation(connector, boe->orientation);
753
754	return 1;
755}
756
757static const struct drm_panel_funcs boe_panel_funcs = {
758	.unprepare = boe_panel_unprepare,
759	.prepare = boe_panel_prepare,
760	.enable = boe_panel_enable,
761	.get_modes = boe_panel_get_modes,
762};
763
764static int boe_panel_add(struct boe_panel *boe)
765{
766	struct device *dev = &boe->dsi->dev;
767	int err;
768
769	boe->avdd = devm_regulator_get(dev, "avdd");
770	if (IS_ERR(boe->avdd))
771		return PTR_ERR(boe->avdd);
772
773	boe->avee = devm_regulator_get(dev, "avee");
774	if (IS_ERR(boe->avee))
775		return PTR_ERR(boe->avee);
776
777	boe->pp1800 = devm_regulator_get(dev, "pp1800");
778	if (IS_ERR(boe->pp1800))
779		return PTR_ERR(boe->pp1800);
780
781	boe->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
782	if (IS_ERR(boe->enable_gpio)) {
783		dev_err(dev, "cannot get reset-gpios %ld\n",
784			PTR_ERR(boe->enable_gpio));
785		return PTR_ERR(boe->enable_gpio);
786	}
787
788	gpiod_set_value(boe->enable_gpio, 0);
789
790	drm_panel_init(&boe->base, dev, &boe_panel_funcs,
791		       DRM_MODE_CONNECTOR_DSI);
792	err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation);
793	if (err < 0) {
794		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
795		return err;
796	}
797
798	err = drm_panel_of_backlight(&boe->base);
799	if (err)
800		return err;
801
802	boe->base.funcs = &boe_panel_funcs;
803	boe->base.dev = &boe->dsi->dev;
804
805	drm_panel_add(&boe->base);
806
807	return 0;
808}
809
810static int boe_panel_probe(struct mipi_dsi_device *dsi)
811{
812	struct boe_panel *boe;
813	int ret;
814	const struct panel_desc *desc;
815
816	boe = devm_kzalloc(&dsi->dev, sizeof(*boe), GFP_KERNEL);
817	if (!boe)
818		return -ENOMEM;
819
820	desc = of_device_get_match_data(&dsi->dev);
821	dsi->lanes = desc->lanes;
822	dsi->format = desc->format;
823	dsi->mode_flags = desc->mode_flags;
824	boe->desc = desc;
825	boe->dsi = dsi;
826	ret = boe_panel_add(boe);
827	if (ret < 0)
828		return ret;
829
830	mipi_dsi_set_drvdata(dsi, boe);
831
832	ret = mipi_dsi_attach(dsi);
833	if (ret)
834		drm_panel_remove(&boe->base);
835
836	return ret;
837}
838
839static void boe_panel_shutdown(struct mipi_dsi_device *dsi)
840{
841	struct boe_panel *boe = mipi_dsi_get_drvdata(dsi);
842
843	drm_panel_disable(&boe->base);
844	drm_panel_unprepare(&boe->base);
845}
846
847static int boe_panel_remove(struct mipi_dsi_device *dsi)
848{
849	struct boe_panel *boe = mipi_dsi_get_drvdata(dsi);
850	int ret;
851
852	boe_panel_shutdown(dsi);
853
854	ret = mipi_dsi_detach(dsi);
855	if (ret < 0)
856		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
857
858	if (boe->base.dev)
859		drm_panel_remove(&boe->base);
860
861	return 0;
862}
863
864static const struct of_device_id boe_of_match[] = {
865	{ .compatible = "boe,tv101wum-nl6",
866	  .data = &boe_tv101wum_nl6_desc
867	},
868	{ .compatible = "auo,kd101n80-45na",
869	  .data = &auo_kd101n80_45na_desc
870	},
871	{ .compatible = "boe,tv101wum-n53",
872	  .data = &boe_tv101wum_n53_desc
873	},
874	{ .compatible = "auo,b101uan08.3",
875	  .data = &auo_b101uan08_3_desc
876	},
877	{ .compatible = "boe,tv105wum-nw0",
878	  .data = &boe_tv105wum_nw0_desc
879	},
880	{ /* sentinel */ }
881};
882MODULE_DEVICE_TABLE(of, boe_of_match);
883
884static struct mipi_dsi_driver boe_panel_driver = {
885	.driver = {
886		.name = "panel-boe-tv101wum-nl6",
887		.of_match_table = boe_of_match,
888	},
889	.probe = boe_panel_probe,
890	.remove = boe_panel_remove,
891	.shutdown = boe_panel_shutdown,
892};
893module_mipi_dsi_driver(boe_panel_driver);
894
895MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
896MODULE_DESCRIPTION("BOE tv101wum-nl6 1200x1920 video mode panel driver");
897MODULE_LICENSE("GPL v2");
898