File Index
Files and directories
Sign in
FILE

panel-himax-hx8394.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-himax-hx8394.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for panels based on Himax HX8394 controller, such as:
  4 *
  5 * - HannStar HSD060BHW4 5.99" MIPI-DSI panel
  6 *
  7 * Copyright (C) 2021 Kamil Trzciński
  8 *
  9 * Based on drivers/gpu/drm/panel/panel-sitronix-st7703.c
 10 * Copyright (C) Purism SPC 2019
 11 */
 12
 13#include <linux/delay.h>
 14#include <linux/gpio/consumer.h>
 15#include <linux/media-bus-format.h>
 16#include <linux/mod_devicetable.h>
 17#include <linux/module.h>
 18#include <linux/of.h>
 19#include <linux/regulator/consumer.h>
 20
 21#include <video/mipi_display.h>
 22
 23#include <drm/drm_mipi_dsi.h>
 24#include <drm/drm_modes.h>
 25#include <drm/drm_panel.h>
 26
 27#define DRV_NAME "panel-himax-hx8394"
 28
 29/* Manufacturer specific commands sent via DSI, listed in HX8394-F datasheet */
 30#define HX8394_CMD_SETSEQUENCE	  0xb0
 31#define HX8394_CMD_SETPOWER	  0xb1
 32#define HX8394_CMD_SETDISP	  0xb2
 33#define HX8394_CMD_SETCYC	  0xb4
 34#define HX8394_CMD_SETVCOM	  0xb6
 35#define HX8394_CMD_SETTE	  0xb7
 36#define HX8394_CMD_SETSENSOR	  0xb8
 37#define HX8394_CMD_SETEXTC	  0xb9
 38#define HX8394_CMD_SETMIPI	  0xba
 39#define HX8394_CMD_SETOTP	  0xbb
 40#define HX8394_CMD_SETREGBANK	  0xbd
 41#define HX8394_CMD_UNKNOWN5	  0xbf
 42#define HX8394_CMD_UNKNOWN1	  0xc0
 43#define HX8394_CMD_SETDGCLUT	  0xc1
 44#define HX8394_CMD_SETID	  0xc3
 45#define HX8394_CMD_SETDDB	  0xc4
 46#define HX8394_CMD_UNKNOWN2	  0xc6
 47#define HX8394_CMD_SETCABC	  0xc9
 48#define HX8394_CMD_SETCABCGAIN	  0xca
 49#define HX8394_CMD_SETPANEL	  0xcc
 50#define HX8394_CMD_SETOFFSET	  0xd2
 51#define HX8394_CMD_SETGIP0	  0xd3
 52#define HX8394_CMD_UNKNOWN3	  0xd4
 53#define HX8394_CMD_SETGIP1	  0xd5
 54#define HX8394_CMD_SETGIP2	  0xd6
 55#define HX8394_CMD_SETGPO	  0xd6
 56#define HX8394_CMD_UNKNOWN4	  0xd8
 57#define HX8394_CMD_SETSCALING	  0xdd
 58#define HX8394_CMD_SETIDLE	  0xdf
 59#define HX8394_CMD_SETGAMMA	  0xe0
 60#define HX8394_CMD_SETCHEMODE_DYN 0xe4
 61#define HX8394_CMD_SETCHE	  0xe5
 62#define HX8394_CMD_SETCESEL	  0xe6
 63#define HX8394_CMD_SET_SP_CMD	  0xe9
 64#define HX8394_CMD_SETREADINDEX	  0xfe
 65#define HX8394_CMD_GETSPIREAD	  0xff
 66
 67struct hx8394 {
 68	struct device *dev;
 69	struct drm_panel panel;
 70	struct gpio_desc *reset_gpio;
 71	struct regulator *vcc;
 72	struct regulator *iovcc;
 73	enum drm_panel_orientation orientation;
 74
 75	const struct hx8394_panel_desc *desc;
 76};
 77
 78struct hx8394_panel_desc {
 79	const struct drm_display_mode *mode;
 80	unsigned int lanes;
 81	unsigned long mode_flags;
 82	enum mipi_dsi_pixel_format format;
 83	void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
 84};
 85
 86static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel)
 87{
 88	return container_of(panel, struct hx8394, panel);
 89}
 90
 91static void hsd060bhw4_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
 92{
 93	/* 5.19.8 SETEXTC: Set extension command (B9h) */
 94	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC,
 95				     0xff, 0x83, 0x94);
 96
 97	/* 5.19.2 SETPOWER: Set power (B1h) */
 98	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
 99				     0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30);
100
101	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
102	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI,
103				     0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
104
105	/* 5.19.3 SETDISP: Set display related register (B2h) */
106	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP,
107				     0x00, 0x80, 0x78, 0x0c, 0x07);
108
109	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
110	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC,
111				     0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55,
112				     0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c,
113				     0x7c);
114
115	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
116	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0,
117				     0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10,
118				     0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00,
119				     0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00,
120				     0x00, 0x0c, 0x40);
121
122	/* 5.19.20 Set GIP Option1 (D5h) */
123	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1,
124				     0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01,
125				     0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18,
126				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
127				     0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
128				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
129
130	/* 5.19.21 Set GIP Option2 (D6h) */
131	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2,
132				     0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06,
133				     0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18,
134				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
135				     0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
136				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
137
138	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
139	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA,
140				     0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f,
141				     0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a,
142				     0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00,
143				     0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31,
144				     0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f,
145				     0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b,
146				     0x4a, 0x4c, 0x4b, 0x7f);
147
148	/* 5.19.17 SETPANEL (CCh) */
149	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL,
150				     0x0b);
151
152	/* Unknown command, not listed in the HX8394-F datasheet */
153	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1,
154				     0x1f, 0x31);
155
156	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
157	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM,
158				     0x7d, 0x7d);
159
160	/* Unknown command, not listed in the HX8394-F datasheet */
161	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
162				     0x02);
163
164	/* 5.19.11 Set register bank (BDh) */
165	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
166				     0x01);
167
168	/* 5.19.2 SETPOWER: Set power (B1h) */
169	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
170				     0x00);
171
172	/* 5.19.11 Set register bank (BDh) */
173	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
174				     0x00);
175
176	/* Unknown command, not listed in the HX8394-F datasheet */
177	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
178				     0xed);
179}
180
181static const struct drm_display_mode hsd060bhw4_mode = {
182	.hdisplay    = 720,
183	.hsync_start = 720 + 40,
184	.hsync_end   = 720 + 40 + 46,
185	.htotal	     = 720 + 40 + 46 + 40,
186	.vdisplay    = 1440,
187	.vsync_start = 1440 + 9,
188	.vsync_end   = 1440 + 9 + 7,
189	.vtotal	     = 1440 + 9 + 7 + 7,
190	.clock	     = 74250,
191	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
192	.width_mm    = 68,
193	.height_mm   = 136,
194};
195
196static const struct hx8394_panel_desc hsd060bhw4_desc = {
197	.mode = &hsd060bhw4_mode,
198	.lanes = 4,
199	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
200	.format = MIPI_DSI_FMT_RGB888,
201	.init_sequence = hsd060bhw4_init_sequence,
202};
203
204static void powkiddy_x55_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
205{
206	/* 5.19.8 SETEXTC: Set extension command (B9h) */
207	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC,
208				     0xff, 0x83, 0x94);
209
210	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
211	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI,
212				     0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
213
214	/* 5.19.2 SETPOWER: Set power (B1h) */
215	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
216				     0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47);
217
218	/* 5.19.3 SETDISP: Set display related register (B2h) */
219	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP,
220				     0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f);
221
222	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
223	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC,
224				     0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75,
225				     0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c,
226				     0x86);
227
228	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
229	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM,
230				     0x6e, 0x6e);
231
232	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
233	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0,
234				     0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10,
235				     0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15,
236				     0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07,
237				     0x07, 0x0c, 0x40);
238
239	/* 5.19.20 Set GIP Option1 (D5h) */
240	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1,
241				     0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
242				     0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18,
243				     0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
244				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21,
245				     0x18, 0x18, 0x18, 0x18);
246
247	/* 5.19.21 Set GIP Option2 (D6h) */
248	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2,
249				     0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
250				     0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18,
251				     0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
252				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24,
253				     0x18, 0x18, 0x18, 0x18);
254
255	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
256	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA,
257				     0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56,
258				     0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8,
259				     0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00,
260				     0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65,
261				     0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba,
262				     0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f);
263
264	/* Unknown command, not listed in the HX8394-F datasheet */
265	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1,
266				     0x1f, 0x31);
267
268	/* 5.19.17 SETPANEL (CCh) */
269	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL,
270				     0x0b);
271
272	/* Unknown command, not listed in the HX8394-F datasheet */
273	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
274				     0x02);
275
276	/* 5.19.11 Set register bank (BDh) */
277	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
278				     0x02);
279
280	/* Unknown command, not listed in the HX8394-F datasheet */
281	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4,
282				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
283				     0xff, 0xff);
284
285	/* 5.19.11 Set register bank (BDh) */
286	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
287				     0x00);
288
289	/* 5.19.11 Set register bank (BDh) */
290	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
291				     0x01);
292
293	/* 5.19.2 SETPOWER: Set power (B1h) */
294	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
295				     0x00);
296
297	/* 5.19.11 Set register bank (BDh) */
298	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
299				     0x00);
300
301	/* Unknown command, not listed in the HX8394-F datasheet */
302	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN5,
303				     0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01);
304
305	/* Unknown command, not listed in the HX8394-F datasheet */
306	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2,
307				     0xed);
308}
309
310static const struct drm_display_mode powkiddy_x55_mode = {
311	.hdisplay	= 720,
312	.hsync_start	= 720 + 44,
313	.hsync_end	= 720 + 44 + 20,
314	.htotal		= 720 + 44 + 20 + 20,
315	.vdisplay	= 1280,
316	.vsync_start	= 1280 + 12,
317	.vsync_end	= 1280 + 12 + 10,
318	.vtotal		= 1280 + 12 + 10 + 10,
319	.clock		= 63290,
320	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
321	.width_mm	= 67,
322	.height_mm	= 121,
323};
324
325static const struct hx8394_panel_desc powkiddy_x55_desc = {
326	.mode = &powkiddy_x55_mode,
327	.lanes = 4,
328	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
329		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
330	.format = MIPI_DSI_FMT_RGB888,
331	.init_sequence = powkiddy_x55_init_sequence,
332};
333
334static void mchp_ac40t08a_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
335{
336	/* DCS commands do not seem to be sent correclty without this delay */
337	mipi_dsi_msleep(dsi_ctx, 20);
338
339	/* 5.19.8 SETEXTC: Set extension command (B9h) */
340	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC,
341				     0xff, 0x83, 0x94);
342
343	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
344	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI,
345				     0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
346
347	/* 5.19.2 SETPOWER: Set power (B1h) */
348	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
349				     0x48, 0x12, 0x72, 0x09, 0x32, 0x54,
350				     0x71, 0x71, 0x57, 0x47);
351
352	/* 5.19.3 SETDISP: Set display related register (B2h) */
353	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP,
354				     0x00, 0x80, 0x64, 0x0c, 0x0d, 0x2f);
355
356	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
357	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC,
358				     0x73, 0x74, 0x73, 0x74, 0x73, 0x74,
359				     0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f,
360				     0x73, 0x74, 0x73, 0x74, 0x73, 0x74,
361				     0x01, 0x0c, 0x86);
362
363	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
364	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM,
365				     0x6e, 0x6e);
366
367	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
368	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0,
369				     0x00, 0x00, 0x07, 0x07, 0x40, 0x07,
370				     0x0c, 0x00, 0x08, 0x10, 0x08, 0x00,
371				     0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a,
372				     0x02, 0x15, 0x06, 0x05, 0x06, 0x47,
373				     0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07,
374				     0x07, 0x0c, 0x40);
375
376	/* 5.19.20 Set GIP Option1 (D5h) */
377	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1,
378				     0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01,
379				     0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
380				     0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25,
381				     0x18, 0x18, 0x26, 0x27, 0x18, 0x18,
382				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
383				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
384				     0x18, 0x18, 0x20, 0x21, 0x18, 0x18,
385				     0x18, 0x18);
386
387	/* 5.19.21 Set GIP Option2 (D6h) */
388	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2,
389				     0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06,
390				     0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
391				     0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20,
392				     0x18, 0x18, 0x27, 0x26, 0x18, 0x18,
393				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
394				     0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
395				     0x18, 0x18, 0x25, 0x24, 0x18, 0x18,
396				     0x18, 0x18);
397
398	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
399	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA,
400				     0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21,
401				     0x24, 0x22, 0x47, 0x56, 0x65, 0x66,
402				     0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d,
403				     0x98, 0xa8, 0xb9, 0x5d, 0x5c, 0x61,
404				     0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00,
405				     0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24,
406				     0x22, 0x47, 0x56, 0x65, 0x65, 0x6e,
407				     0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99,
408				     0xa8, 0xba, 0x5d, 0x5d, 0x62, 0x67,
409				     0x6b, 0x72, 0x7f, 0x7f);
410
411	/* Unknown command, not listed in the HX8394-F datasheet (C0H) */
412	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1,
413				     0x1f, 0x73);
414
415	/* Set CABC control (C9h)*/
416	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCABC,
417				     0x76, 0x00, 0x30);
418
419	/* 5.19.17 SETPANEL (CCh) */
420	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL,
421				     0x0b);
422
423	/* Unknown command, not listed in the HX8394-F datasheet (D4h) */
424	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3,
425				     0x02);
426
427	/* 5.19.11 Set register bank (BDh) */
428	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
429				     0x02);
430
431	/* 5.19.11 Set register bank (D8h) */
432	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4,
433				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
434				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
435
436	/* 5.19.11 Set register bank (BDh) */
437	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
438				     0x00);
439
440	/* 5.19.11 Set register bank (BDh) */
441	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
442				     0x01);
443
444	/* 5.19.2 SETPOWER: Set power (B1h) */
445	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
446				     0x00);
447
448	/* 5.19.11 Set register bank (BDh) */
449	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
450				     0x00);
451
452	/* Unknown command, not listed in the HX8394-F datasheet (C6h) */
453	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2,
454				     0xed);
455}
456
457static const struct drm_display_mode mchp_ac40t08a_mode = {
458	.hdisplay    = 720,
459	.hsync_start = 720 + 12,
460	.hsync_end   = 720 + 12 + 24,
461	.htotal	     = 720 + 12 + 12 + 24,
462	.vdisplay    = 1280,
463	.vsync_start = 1280 + 13,
464	.vsync_end   = 1280 + 14,
465	.vtotal	     = 1280 + 14 + 13,
466	.clock	     = 60226,
467	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
468	.width_mm    = 76,
469	.height_mm   = 132,
470};
471
472static const struct hx8394_panel_desc mchp_ac40t08a_desc = {
473	.mode = &mchp_ac40t08a_mode,
474	.lanes = 4,
475	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
476	.format = MIPI_DSI_FMT_RGB888,
477	.init_sequence = mchp_ac40t08a_init_sequence,
478};
479
480/*
481 * HL055FHAV028C is based on Himax HX8399, so datasheet pages are
482 * slightly different than HX8394 based panels.
483 */
484static void hl055fhav028c_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
485{
486	/* 6.3.6 SETEXTC: Set extension command (B9h) */
487	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC,
488				     0xff, 0x83, 0x99);
489
490	/* 6.3.17 SETOFFSET: Set offset voltage (D2h) */
491	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETOFFSET,
492				     0x77);
493
494	/* 6.3.1 SETPOWER: Set power (B1h) */
495	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER,
496				     0x02, 0x04, 0x74, 0x94, 0x01, 0x32,
497				     0x33, 0x11, 0x11, 0xab, 0x4d, 0x56,
498				     0x73, 0x02, 0x02);
499
500	/* 6.3.2 SETDISP: Set display related register (B2h) */
501	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP,
502				     0x00, 0x80, 0x80, 0xae, 0x05, 0x07,
503				     0x5a, 0x11, 0x00, 0x00, 0x10, 0x1e,
504				     0x70, 0x03, 0xd4);
505
506	/* 6.3.3 SETCYC: Set display waveform cycles (B4h) */
507	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC,
508				     0x00, 0xff, 0x02, 0xc0, 0x02, 0xc0,
509				     0x00, 0x00, 0x08, 0x00, 0x04, 0x06,
510				     0x00, 0x32, 0x04, 0x0a, 0x08, 0x21,
511				     0x03, 0x01, 0x00, 0x0f, 0xb8, 0x8b,
512				     0x02, 0xc0, 0x02, 0xc0, 0x00, 0x00,
513				     0x08, 0x00, 0x04, 0x06, 0x00, 0x32,
514				     0x04, 0x0a, 0x08, 0x01, 0x00, 0x0f,
515				     0xb8, 0x01);
516
517	/* 6.3.18 SETGIP0: Set GIP Option0 (D3h) */
518	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0,
519				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520				     0x06, 0x00, 0x00, 0x10, 0x04, 0x00,
521				     0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
522				     0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
523				     0x00, 0x05, 0x05, 0x07, 0x00, 0x00,
524				     0x00, 0x05, 0x40);
525
526	/* 6.3.19 Set GIP Option1 (D5h) */
527	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1,
528				     0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
529				     0x21, 0x20, 0x01, 0x00, 0x07, 0x06,
530				     0x05, 0x04, 0x03, 0x02, 0x18, 0x18,
531				     0x18, 0x18, 0x18, 0x18, 0x2f, 0x2f,
532				     0x30, 0x30, 0x31, 0x31, 0x18, 0x18,
533				     0x18, 0x18);
534
535	/* 6.3.20 Set GIP Option2 (D6h) */
536	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2,
537				     0x18, 0x18, 0x19, 0x19, 0x40, 0x40,
538				     0x20, 0x21, 0x02, 0x03, 0x04, 0x05,
539				     0x06, 0x07, 0x00, 0x01, 0x40, 0x40,
540				     0x40, 0x40, 0x40, 0x40, 0x2f, 0x2f,
541				     0x30, 0x30, 0x31, 0x31, 0x40, 0x40,
542				     0x40, 0x40);
543
544	/* 6.3.21 Set GIP Option3 (D8h) */
545	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4,
546				     0xa2, 0xaa, 0x02, 0xa0, 0xa2, 0xa8,
547				     0x02, 0xa0, 0xb0, 0x00, 0x00, 0x00,
548				     0xb0, 0x00, 0x00, 0x00);
549
550	/* 6.3.9 Set register bank (BDh) */
551	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
552				     0x01);
553
554	/* 6.3.21 Set GIP Option3 (D8h) */
555	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4,
556				     0xb0, 0x00, 0x00, 0x00, 0xb0, 0x00,
557				     0x00, 0x00, 0xe2, 0xaa, 0x03, 0xf0,
558				     0xe2, 0xaa, 0x03, 0xf0);
559
560	/* 6.3.9 Set register bank (BDh) */
561	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
562				     0x02);
563
564	/* 6.3.21 Set GIP Option3 (D8h) */
565	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4,
566				     0xe2, 0xaa, 0x03, 0xf0, 0xe2, 0xaa,
567				     0x03, 0xf0);
568
569	/* 6.3.9 Set register bank (BDh) */
570	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK,
571				     0x00);
572
573	/* 6.3.4 SETVCOM: Set VCOM voltage (B6h) */
574	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM,
575				     0x7a, 0x7a);
576
577	/* 6.3.26 SETGAMMA: Set gamma curve related setting (E0h) */
578	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA,
579				     0x00, 0x18, 0x27, 0x24, 0x5a, 0x68,
580				     0x79, 0x78, 0x81, 0x8a, 0x92, 0x99,
581				     0x9e, 0xa7, 0xaf, 0xb4, 0xb9, 0xc3,
582				     0xc7, 0xd1, 0xc6, 0xd4, 0xd5, 0x6c,
583				     0x67, 0x71, 0x77, 0x00, 0x00, 0x18,
584				     0x27, 0x24, 0x5a, 0x68, 0x79, 0x78,
585				     0x81, 0x8a, 0x92, 0x99, 0x9e, 0xa7,
586				     0xaf, 0xb4, 0xb9, 0xc3, 0xc7, 0xd1,
587				     0xc6, 0xd4, 0xd5, 0x6c, 0x67, 0x77);
588
589	/* Unknown command, not listed in the HX8399-C datasheet (C6h) */
590	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2,
591				     0xff, 0xf9);
592
593	/* 6.3.16 SETPANEL (CCh) */
594	mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL,
595				     0x08);
596}
597
598static const struct drm_display_mode hl055fhav028c_mode = {
599	.hdisplay	= 1080,
600	.hsync_start	= 1080 + 32,
601	.hsync_end	= 1080 + 32 + 8,
602	.htotal		= 1080 + 32 + 8 + 32,
603	.vdisplay	= 1920,
604	.vsync_start	= 1920 + 16,
605	.vsync_end	= 1920 + 16 + 2,
606	.vtotal		= 1920 + 16 + 2 + 14,
607	.clock		= 134920,
608	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
609	.width_mm	= 70,
610	.height_mm	= 127,
611};
612
613static const struct hx8394_panel_desc hl055fhav028c_desc = {
614	.mode = &hl055fhav028c_mode,
615	.lanes = 4,
616	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
617	.format = MIPI_DSI_FMT_RGB888,
618	.init_sequence = hl055fhav028c_init_sequence,
619};
620
621static int hx8394_enable(struct drm_panel *panel)
622{
623	struct hx8394 *ctx = panel_to_hx8394(panel);
624	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
625	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
626	int ret;
627
628	ctx->desc->init_sequence(&dsi_ctx);
629
630	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
631
632	if (dsi_ctx.accum_err)
633		return dsi_ctx.accum_err;
634	/* Panel is operational 120 msec after reset */
635	msleep(120);
636
637	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
638	if (dsi_ctx.accum_err)
639		goto sleep_in;
640
641	return 0;
642
643sleep_in:
644	ret = dsi_ctx.accum_err;
645	dsi_ctx.accum_err = 0;
646
647	/* This will probably fail, but let's try orderly power off anyway. */
648	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
649	mipi_dsi_msleep(&dsi_ctx, 50);
650
651	return ret;
652}
653
654static int hx8394_disable(struct drm_panel *panel)
655{
656	struct hx8394 *ctx = panel_to_hx8394(panel);
657	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
658	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
659
660	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
661	mipi_dsi_msleep(&dsi_ctx, 50); /* about 3 frames */
662
663	return dsi_ctx.accum_err;
664}
665
666static int hx8394_unprepare(struct drm_panel *panel)
667{
668	struct hx8394 *ctx = panel_to_hx8394(panel);
669
670	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
671
672	regulator_disable(ctx->iovcc);
673	regulator_disable(ctx->vcc);
674
675	return 0;
676}
677
678static int hx8394_prepare(struct drm_panel *panel)
679{
680	struct hx8394 *ctx = panel_to_hx8394(panel);
681	int ret;
682
683	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
684
685	ret = regulator_enable(ctx->vcc);
686	if (ret) {
687		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
688		return ret;
689	}
690
691	ret = regulator_enable(ctx->iovcc);
692	if (ret) {
693		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
694		goto disable_vcc;
695	}
696
697	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
698
699	msleep(180);
700
701	return 0;
702
703disable_vcc:
704	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
705	regulator_disable(ctx->vcc);
706	return ret;
707}
708
709static int hx8394_get_modes(struct drm_panel *panel,
710			    struct drm_connector *connector)
711{
712	struct hx8394 *ctx = panel_to_hx8394(panel);
713	struct drm_display_mode *mode;
714
715	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
716	if (!mode) {
717		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
718			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
719			drm_mode_vrefresh(ctx->desc->mode));
720		return -ENOMEM;
721	}
722
723	drm_mode_set_name(mode);
724
725	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
726	connector->display_info.width_mm = mode->width_mm;
727	connector->display_info.height_mm = mode->height_mm;
728	drm_mode_probed_add(connector, mode);
729
730	return 1;
731}
732
733static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel)
734{
735	struct hx8394 *ctx = panel_to_hx8394(panel);
736
737	return ctx->orientation;
738}
739
740static const struct drm_panel_funcs hx8394_drm_funcs = {
741	.disable   = hx8394_disable,
742	.unprepare = hx8394_unprepare,
743	.prepare   = hx8394_prepare,
744	.enable	   = hx8394_enable,
745	.get_modes = hx8394_get_modes,
746	.get_orientation = hx8394_get_orientation,
747};
748
749static int hx8394_probe(struct mipi_dsi_device *dsi)
750{
751	struct device *dev = &dsi->dev;
752	struct hx8394 *ctx;
753	int ret;
754
755	ctx = devm_drm_panel_alloc(dev, struct hx8394, panel,
756				   &hx8394_drm_funcs,
757				   DRM_MODE_CONNECTOR_DSI);
758	if (IS_ERR(ctx))
759		return PTR_ERR(ctx);
760
761	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
762	if (IS_ERR(ctx->reset_gpio))
763		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
764				     "Failed to get reset gpio\n");
765
766	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
767	if (ret < 0) {
768		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
769		return ret;
770	}
771
772	mipi_dsi_set_drvdata(dsi, ctx);
773
774	ctx->dev = dev;
775	ctx->desc = of_device_get_match_data(dev);
776
777	dsi->mode_flags = ctx->desc->mode_flags;
778	dsi->format = ctx->desc->format;
779	dsi->lanes = ctx->desc->lanes;
780
781	ctx->vcc = devm_regulator_get(dev, "vcc");
782	if (IS_ERR(ctx->vcc))
783		return dev_err_probe(dev, PTR_ERR(ctx->vcc),
784				     "Failed to request vcc regulator\n");
785
786	ctx->iovcc = devm_regulator_get(dev, "iovcc");
787	if (IS_ERR(ctx->iovcc))
788		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
789				     "Failed to request iovcc regulator\n");
790
791	ret = drm_panel_of_backlight(&ctx->panel);
792	if (ret)
793		return ret;
794
795	drm_panel_add(&ctx->panel);
796
797	ret = mipi_dsi_attach(dsi);
798	if (ret < 0) {
799		dev_err_probe(dev, ret, "mipi_dsi_attach failed\n");
800		drm_panel_remove(&ctx->panel);
801		return ret;
802	}
803
804	dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
805		ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
806		drm_mode_vrefresh(ctx->desc->mode),
807		mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
808
809	return 0;
810}
811
812static void hx8394_remove(struct mipi_dsi_device *dsi)
813{
814	struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
815	int ret;
816
817	ret = mipi_dsi_detach(dsi);
818	if (ret < 0)
819		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
820
821	drm_panel_remove(&ctx->panel);
822}
823
824static const struct of_device_id hx8394_of_match[] = {
825	{ .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc },
826	{ .compatible = "huiling,hl055fhav028c", .data = &hl055fhav028c_desc },
827	{ .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc },
828	{ .compatible = "microchip,ac40t08a-mipi-panel", .data = &mchp_ac40t08a_desc },
829	{ /* sentinel */ }
830};
831MODULE_DEVICE_TABLE(of, hx8394_of_match);
832
833static struct mipi_dsi_driver hx8394_driver = {
834	.probe	= hx8394_probe,
835	.remove = hx8394_remove,
836	.driver = {
837		.name = DRV_NAME,
838		.of_match_table = hx8394_of_match,
839	},
840};
841module_mipi_dsi_driver(hx8394_driver);
842
843MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>");
844MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels");
845MODULE_LICENSE("GPL");
~/ Read-only file preview.