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