1 From bf46a7be6f5355d9ea63fec37e283058a6679d2e Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Tue, 1 Feb 2022 15:27:01 +0000
4 Subject: [PATCH 0414/1085] drm/panel/panel-sitronix-st7701: Support SPI config
7 The ST7701 supports numerous different interface mechanisms for
8 MIPI DSI, RGB, or SPI. The driver was only implementing DSI input,
9 so add RGB parallel input with SPI configuration.
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
13 drivers/gpu/drm/panel/panel-sitronix-st7701.c | 397 ++++++++++++++++--
14 1 file changed, 370 insertions(+), 27 deletions(-)
16 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c
17 +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 +#include <drm/drm_print.h>
24 #include <linux/bitfield.h>
25 #include <linux/gpio/consumer.h>
26 #include <linux/delay.h>
27 +#include <linux/media-bus-format.h>
28 #include <linux/module.h>
30 #include <linux/regulator/consumer.h>
31 +#include <linux/spi/spi.h>
33 #include <video/mipi_display.h>
35 +#define SPI_DATA_FLAG 0x100
37 /* Command2 BKx selection command */
38 #define DSI_CMD2BKX_SEL 0xFF
41 #define DSI_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */
42 #define DSI_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */
45 + * Command2 with BK function selection.
49 + * 1:00 = CMD2BK0, Command2 BK0
50 + * 1:01 = CMD2BK1, Command2 BK1
51 + * 1:11 = CMD2BK3, Command2 BK3
52 + * 0:00 = Command2 disable
54 +#define DSI_CMD2BK0_SEL 0x10
55 +#define DSI_CMD2BK1_SEL 0x11
56 +#define DSI_CMD2BK3_SEL 0x13
57 +#define DSI_CMD2BKX_SEL_NONE 0x00
58 +#define SPI_CMD2BK3_SEL (SPI_DATA_FLAG | DSI_CMD2BK3_SEL)
59 +#define SPI_CMD2BK1_SEL (SPI_DATA_FLAG | DSI_CMD2BK1_SEL)
60 +#define SPI_CMD2BK0_SEL (SPI_DATA_FLAG | DSI_CMD2BK0_SEL)
61 +#define SPI_CMD2BKX_SEL_NONE (SPI_DATA_FLAG | DSI_CMD2BKX_SEL_NONE)
63 /* Command2, BK0 bytes */
64 #define DSI_CMD2_BK0_GAMCTRL_AJ_MASK GENMASK(7, 6)
65 #define DSI_CMD2_BK0_GAMCTRL_VC0_MASK GENMASK(3, 0)
66 @@ -100,11 +124,23 @@ enum op_bias {
72 +enum st7701_ctrl_if {
77 struct st7701_panel_desc {
78 const struct drm_display_mode *mode;
80 enum mipi_dsi_pixel_format format;
81 + u32 mediabus_format;
82 unsigned int panel_sleep_delay;
83 + void (*init_sequence)(struct st7701 *st7701);
84 + unsigned int conn_type;
85 + enum st7701_ctrl_if interface;
88 /* TFT matrix driver configuration, panel specific. */
89 const u8 pv_gamma[16]; /* Positive voltage gamma control */
90 @@ -130,6 +166,9 @@ struct st7701_panel_desc {
92 struct drm_panel panel;
93 struct mipi_dsi_device *dsi;
94 + struct spi_device *spi;
95 + const struct device *dev;
97 const struct st7701_panel_desc *desc;
99 struct regulator_bulk_data supplies[2];
100 @@ -192,7 +231,23 @@ static void st7701_switch_cmd_bkx(struct
101 ST7701_DSI(st7701, DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, val);
104 -static void st7701_init_sequence(struct st7701 *st7701)
105 +#define ST7701_SPI(st7701, seq...) \
107 + const u16 d[] = { seq }; \
108 + struct spi_transfer xfer = { }; \
109 + struct spi_message spi; \
111 + spi_message_init(&spi); \
114 + xfer.bits_per_word = 9; \
115 + xfer.len = sizeof(u16) * ARRAY_SIZE(d); \
117 + spi_message_add_tail(&xfer, &spi); \
118 + spi_sync((st7701)->spi, &spi); \
121 +static void ts8550b_init_sequence(struct st7701 *st7701)
123 const struct st7701_panel_desc *desc = st7701->desc;
124 const struct drm_display_mode *mode = desc->mode;
125 @@ -423,6 +478,111 @@ static void kd50t048a_gip_sequence(struc
126 0xFF, 0xFF, 0xFF, 0xFF, 0x10, 0x45, 0x67, 0x98, 0xBA);
129 +static void txw210001b0_init_sequence(struct st7701 *st7701)
131 + ST7701_SPI(st7701, MIPI_DCS_SOFT_RESET);
133 + usleep_range(5000, 7000);
135 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
136 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK0_SEL);
138 + ST7701_SPI(st7701, DSI_CMD2_BK0_LNESET, 0x13B, 0x100);
140 + ST7701_SPI(st7701, DSI_CMD2_BK0_PORCTRL, 0x10B, 0x102);
142 + ST7701_SPI(st7701, DSI_CMD2_BK0_INVSEL, 0x100, 0x102);
144 + ST7701_SPI(st7701, 0xCC, 0x110);
148 + * Positive Voltage Gamma Control
150 + ST7701_SPI(st7701, DSI_CMD2_BK0_PVGAMCTRL,
151 + 0x102, 0x113, 0x11B, 0x10D, 0x110, 0x105, 0x108, 0x107,
152 + 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D);
154 + /* Negative Voltage Gamma Control */
155 + ST7701_SPI(st7701, DSI_CMD2_BK0_NVGAMCTRL,
156 + 0x105, 0x113, 0x11B, 0x10D, 0x111, 0x105, 0x108, 0x107,
157 + 0x107, 0x124, 0x104, 0x111, 0x10E, 0x12C, 0x133, 0x11D);
159 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
160 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK1_SEL);
162 + ST7701_SPI(st7701, DSI_CMD2_BK1_VRHS, 0x15D);
164 + ST7701_SPI(st7701, DSI_CMD2_BK1_VCOM, 0x143);
166 + ST7701_SPI(st7701, DSI_CMD2_BK1_VGHSS, 0x181);
168 + ST7701_SPI(st7701, DSI_CMD2_BK1_TESTCMD, 0x180);
170 + ST7701_SPI(st7701, DSI_CMD2_BK1_VGLS, 0x143);
172 + ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR1, 0x185);
174 + ST7701_SPI(st7701, DSI_CMD2_BK1_PWCTLR2, 0x120);
176 + ST7701_SPI(st7701, DSI_CMD2_BK1_SPD1, 0x178);
178 + ST7701_SPI(st7701, DSI_CMD2_BK1_SPD2, 0x178);
180 + ST7701_SPI(st7701, DSI_CMD2_BK1_MIPISET1, 0x188);
182 + ST7701_SPI(st7701, 0xE0, 0x100, 0x100, 0x102);
184 + ST7701_SPI(st7701, 0xE1,
185 + 0x103, 0x1A0, 0x100, 0x100, 0x104, 0x1A0, 0x100, 0x100,
186 + 0x100, 0x120, 0x120);
188 + ST7701_SPI(st7701, 0xE2,
189 + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100,
190 + 0x100, 0x100, 0x100, 0x100, 0x100);
192 + ST7701_SPI(st7701, 0xE3, 0x100, 0x100, 0x111, 0x100);
194 + ST7701_SPI(st7701, 0xE4, 0x122, 0x100);
196 + ST7701_SPI(st7701, 0xE5,
197 + 0x105, 0x1EC, 0x1A0, 0x1A0, 0x107, 0x1EE, 0x1A0, 0x1A0,
198 + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100);
200 + ST7701_SPI(st7701, 0xE6, 0x100, 0x100, 0x111, 0x100);
202 + ST7701_SPI(st7701, 0xE7, 0x122, 0x100);
204 + ST7701_SPI(st7701, 0xE8,
205 + 0x106, 0x1ED, 0x1A0, 0x1A0, 0x108, 0x1EF, 0x1A0, 0x1A0,
206 + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100);
208 + ST7701_SPI(st7701, 0xEB,
209 + 0x100, 0x100, 0x140, 0x140, 0x100, 0x100, 0x100);
211 + ST7701_SPI(st7701, 0xED,
212 + 0x1FF, 0x1FF, 0x1FF, 0x1BA, 0x10A, 0x1BF, 0x145, 0x1FF,
213 + 0x1FF, 0x154, 0x1FB, 0x1A0, 0x1AB, 0x1FF, 0x1FF, 0x1FF);
215 + ST7701_SPI(st7701, 0xEF, 0x110, 0x10D, 0x104, 0x108, 0x13F, 0x11F);
217 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
218 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BK3_SEL);
220 + ST7701_SPI(st7701, 0xEF, 0x108);
222 + ST7701_SPI(st7701, DSI_CMD2BKX_SEL,
223 + 0x177, 0x101, 0x100, 0x100, SPI_CMD2BKX_SEL_NONE);
225 + ST7701_SPI(st7701, 0xCD, 0x108); /* RGB format COLCTRL */
227 + ST7701_SPI(st7701, 0x36, 0x108); /* MadCtl */
229 + ST7701_SPI(st7701, 0x3A, 0x166); /* Colmod */
231 + ST7701_SPI(st7701, MIPI_DCS_EXIT_SLEEP_MODE);
234 static int st7701_prepare(struct drm_panel *panel)
236 struct st7701 *st7701 = panel_to_st7701(panel);
237 @@ -439,7 +599,7 @@ static int st7701_prepare(struct drm_pan
238 gpiod_set_value(st7701->reset, 1);
241 - st7701_init_sequence(st7701);
242 + st7701->desc->init_sequence(st7701);
244 if (st7701->desc->gip_sequence)
245 st7701->desc->gip_sequence(st7701);
246 @@ -454,7 +614,15 @@ static int st7701_enable(struct drm_pane
248 struct st7701 *st7701 = panel_to_st7701(panel);
250 - ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00);
251 + switch (st7701->desc->interface) {
252 + case ST7701_CTRL_DSI:
253 + ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00);
255 + case ST7701_CTRL_SPI:
256 + ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_ON);
263 @@ -463,7 +631,14 @@ static int st7701_disable(struct drm_pan
265 struct st7701 *st7701 = panel_to_st7701(panel);
267 - ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);
268 + switch (st7701->desc->interface) {
269 + case ST7701_CTRL_DSI:
270 + ST7701_DSI(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);
272 + case ST7701_CTRL_SPI:
273 + ST7701_SPI(st7701, MIPI_DCS_SET_DISPLAY_OFF);
279 @@ -472,7 +647,14 @@ static int st7701_unprepare(struct drm_p
281 struct st7701 *st7701 = panel_to_st7701(panel);
283 - ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00);
284 + switch (st7701->desc->interface) {
285 + case ST7701_CTRL_DSI:
286 + ST7701_DSI(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00);
288 + case ST7701_CTRL_SPI:
289 + ST7701_SPI(st7701, MIPI_DCS_ENTER_SLEEP_MODE);
293 msleep(st7701->sleep_delay);
295 @@ -503,7 +685,7 @@ static int st7701_get_modes(struct drm_p
297 mode = drm_mode_duplicate(connector->dev, desc_mode);
299 - dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n",
300 + dev_err(st7701->dev, "failed to add mode %ux%u@%u\n",
301 desc_mode->hdisplay, desc_mode->vdisplay,
302 drm_mode_vrefresh(desc_mode));
304 @@ -512,6 +694,12 @@ static int st7701_get_modes(struct drm_p
305 drm_mode_set_name(mode);
306 drm_mode_probed_add(connector, mode);
308 + if (st7701->desc->mediabus_format)
309 + drm_display_info_set_bus_formats(&connector->display_info,
310 + &st7701->desc->mediabus_format,
312 + connector->display_info.bus_flags = 0;
314 connector->display_info.width_mm = desc_mode->width_mm;
315 connector->display_info.height_mm = desc_mode->height_mm;
317 @@ -521,6 +709,9 @@ static int st7701_get_modes(struct drm_p
319 drm_connector_set_panel_orientation(connector, st7701->orientation);
321 + if (st7701->desc->bus_flags)
322 + connector->display_info.bus_flags = st7701->desc->bus_flags;
327 @@ -564,6 +755,9 @@ static const struct st7701_panel_desc ts
329 .format = MIPI_DSI_FMT_RGB888,
330 .panel_sleep_delay = 80, /* panel need extra 80ms for sleep out cmd */
331 + .init_sequence = ts8550b_init_sequence,
332 + .conn_type = DRM_MODE_CONNECTOR_DSI,
333 + .interface = ST7701_CTRL_DSI,
336 CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
337 @@ -759,6 +953,26 @@ static const struct drm_display_mode kd5
338 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
341 +static const struct drm_display_mode txw210001b0_mode = {
345 + .hsync_start = 480 + 10,
346 + .hsync_end = 480 + 10 + 16,
347 + .htotal = 480 + 10 + 16 + 56,
350 + .vsync_start = 480 + 15,
351 + .vsync_end = 480 + 15 + 60,
352 + .vtotal = 480 + 15 + 60 + 15,
356 + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
358 + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
361 static const struct st7701_panel_desc kd50t048a_desc = {
362 .mode = &kd50t048a_mode,
364 @@ -839,42 +1053,54 @@ static const struct st7701_panel_desc kd
365 .gip_sequence = kd50t048a_gip_sequence,
368 -static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
369 +static const struct st7701_panel_desc txw210001b0_desc = {
370 + .mode = &txw210001b0_mode,
371 + .mediabus_format = MEDIA_BUS_FMT_RGB888_1X24,
372 + .init_sequence = txw210001b0_init_sequence,
373 + .conn_type = DRM_MODE_CONNECTOR_DPI,
374 + .interface = ST7701_CTRL_SPI,
375 + .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
378 +static const struct st7701_panel_desc hyperpixel2r_desc = {
379 + .mode = &txw210001b0_mode,
380 + .mediabus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
381 + .init_sequence = txw210001b0_init_sequence,
382 + .conn_type = DRM_MODE_CONNECTOR_DPI,
383 + .interface = ST7701_CTRL_SPI,
384 + .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
387 +static int st7701_probe(struct device *dev, struct st7701 **ret_st7701)
389 const struct st7701_panel_desc *desc;
390 struct st7701 *st7701;
393 - st7701 = devm_kzalloc(&dsi->dev, sizeof(*st7701), GFP_KERNEL);
394 + st7701 = devm_kzalloc(dev, sizeof(*st7701), GFP_KERNEL);
398 - desc = of_device_get_match_data(&dsi->dev);
399 - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
400 - MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS;
401 - dsi->format = desc->format;
402 - dsi->lanes = desc->lanes;
403 + desc = of_device_get_match_data(dev);
407 st7701->supplies[0].supply = "VCC";
408 st7701->supplies[1].supply = "IOVCC";
410 - ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(st7701->supplies),
411 + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st7701->supplies),
416 - st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
417 + st7701->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
418 if (IS_ERR(st7701->reset)) {
419 - dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
420 + dev_err(dev, "Couldn't get our reset GPIO\n");
421 return PTR_ERR(st7701->reset);
424 - ret = of_drm_get_panel_orientation(dsi->dev.of_node, &st7701->orientation);
426 - return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
428 - drm_panel_init(&st7701->panel, &dsi->dev, &st7701_funcs,
429 - DRM_MODE_CONNECTOR_DSI);
430 + drm_panel_init(&st7701->panel, dev, &st7701_funcs,
434 * Once sleep out has been issued, ST7701 IC required to wait 120ms
435 @@ -893,14 +1119,39 @@ static int st7701_dsi_probe(struct mipi_
437 drm_panel_add(&st7701->panel);
439 + st7701->desc = desc;
442 + *ret_st7701 = st7701;
447 +static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
449 + struct st7701 *st7701;
452 + ret = st7701_probe(&dsi->dev, &st7701);
457 + dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
458 + dsi->format = st7701->desc->format;
459 + dsi->lanes = st7701->desc->lanes;
461 mipi_dsi_set_drvdata(dsi, st7701);
463 - st7701->desc = desc;
465 ret = mipi_dsi_attach(dsi);
469 + ret = of_drm_get_panel_orientation(dsi->dev.of_node, &st7701->orientation);
471 + return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
476 @@ -916,23 +1167,115 @@ static void st7701_dsi_remove(struct mip
477 drm_panel_remove(&st7701->panel);
480 -static const struct of_device_id st7701_of_match[] = {
481 +static const struct of_device_id st7701_dsi_of_match[] = {
482 { .compatible = "densitron,dmt028vghmcmi-1a", .data = &dmt028vghmcmi_1a_desc },
483 { .compatible = "elida,kd50t048a", .data = &kd50t048a_desc },
484 { .compatible = "techstar,ts8550b", .data = &ts8550b_desc },
487 -MODULE_DEVICE_TABLE(of, st7701_of_match);
488 +MODULE_DEVICE_TABLE(of, st7701_dsi_of_match);
490 static struct mipi_dsi_driver st7701_dsi_driver = {
491 .probe = st7701_dsi_probe,
492 .remove = st7701_dsi_remove,
495 - .of_match_table = st7701_of_match,
496 + .of_match_table = st7701_dsi_of_match,
499 -module_mipi_dsi_driver(st7701_dsi_driver);
501 +/* SPI display probe */
502 +static const struct of_device_id st7701_spi_of_match[] = {
503 + { .compatible = "txw,txw210001b0",
504 + .data = &txw210001b0_desc,
506 + .compatible = "pimoroni,hyperpixel2round",
507 + .data = &hyperpixel2r_desc,
512 +MODULE_DEVICE_TABLE(of, st7701_spi_of_match);
514 +static int st7701_spi_probe(struct spi_device *spi)
516 + struct st7701 *st7701;
519 + spi->mode = SPI_MODE_3;
520 + spi->bits_per_word = 9;
521 + ret = spi_setup(spi);
523 + dev_err(&spi->dev, "failed to setup SPI: %d\n", ret);
527 + ret = st7701_probe(&spi->dev, &st7701);
532 + spi_set_drvdata(spi, st7701);
538 +static void st7701_spi_remove(struct spi_device *spi)
540 + struct st7701 *ctx = spi_get_drvdata(spi);
542 + drm_panel_remove(&ctx->panel);
545 +static const struct spi_device_id st7701_spi_ids[] = {
546 + { "txw210001b0", 0 },
547 + { "hyperpixel2round", 0 },
550 +MODULE_DEVICE_TABLE(spi, st7701_spi_ids);
552 +static struct spi_driver st7701_spi_driver = {
553 + .probe = st7701_spi_probe,
554 + .remove = st7701_spi_remove,
557 + .of_match_table = st7701_spi_of_match,
559 + .id_table = st7701_spi_ids,
562 +static int __init panel_st7701_init(void)
566 + err = spi_register_driver(&st7701_spi_driver);
570 + if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
571 + err = mipi_dsi_driver_register(&st7701_dsi_driver);
573 + goto err_did_spi_register;
578 +err_did_spi_register:
579 + spi_unregister_driver(&st7701_spi_driver);
583 +module_init(panel_st7701_init);
585 +static void __exit panel_st7701_exit(void)
587 + if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
588 + mipi_dsi_driver_unregister(&st7701_dsi_driver);
590 + spi_unregister_driver(&st7701_spi_driver);
592 +module_exit(panel_st7701_exit);
594 MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
595 MODULE_DESCRIPTION("Sitronix ST7701 LCD Panel Driver");