Skip to content

Commit 0b851f1

Browse files
Akkiesoftpopcornmix
authored andcommitted
drm/panel: st7701: Add support for Pimoroni HyperPixel 2.1 Round
HyperPixel2R is another DPI fed/SPI configured panel using ST7701. Add the relevant configuration information to the driver. Signed-off-by: Akira Ouchi <akkiesoft@marokun.net> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
1 parent ce16d31 commit 0b851f1

File tree

1 file changed

+248
-1
lines changed

1 file changed

+248
-1
lines changed

drivers/gpu/drm/panel/panel-sitronix-st7701.c

Lines changed: 248 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/bitfield.h>
1313
#include <linux/gpio/consumer.h>
1414
#include <linux/delay.h>
15+
#include <linux/media-bus-format.h>
1516
#include <linux/module.h>
1617
#include <linux/of.h>
1718
#include <linux/regulator/consumer.h>
@@ -106,6 +107,7 @@ struct st7701_panel_desc {
106107
const struct drm_display_mode *mode;
107108
unsigned int lanes;
108109
enum mipi_dsi_pixel_format format;
110+
u32 mediabus_format;
109111
unsigned int panel_sleep_delay;
110112

111113
/* TFT matrix driver configuration, panel specific. */
@@ -542,6 +544,94 @@ static void wf40eswaa6mnn0_gip_sequence(struct st7701 *st7701)
542544
ST7701_WRITE(st7701, MIPI_DCS_SET_ADDRESS_MODE, 0);
543545
}
544546

547+
static void txw210001b0_gip_sequence(struct st7701 *st7701)
548+
{
549+
ST7701_WRITE(st7701, MIPI_DCS_SOFT_RESET);
550+
551+
usleep_range(5000, 7000);
552+
553+
st7701_switch_cmd_bkx(st7701, true, 0);
554+
555+
ST7701_WRITE(st7701, ST7701_CMD2_BK0_LNESET, 0x3B, 0x0);
556+
557+
ST7701_WRITE(st7701, ST7701_CMD2_BK0_PORCTRL, 0xB, 0x2);
558+
559+
ST7701_WRITE(st7701, ST7701_CMD2_BK0_INVSEL, 0x0, 0x2);
560+
561+
ST7701_WRITE(st7701, 0xCC, 0x10);
562+
563+
st7701_switch_cmd_bkx(st7701, true, 1);
564+
565+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_VRHS, 0x5D);
566+
567+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_VCOM, 0x43);
568+
569+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGHSS, 0x81);
570+
571+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_TESTCMD, 0x80);
572+
573+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGLS, 0x43);
574+
575+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR1, 0x85);
576+
577+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR2, 0x20);
578+
579+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD1, 0x78);
580+
581+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD2, 0x78);
582+
583+
ST7701_WRITE(st7701, ST7701_CMD2_BK1_MIPISET1, 0x88);
584+
585+
ST7701_WRITE(st7701, 0xE0, 0x0, 0x0, 0x2);
586+
587+
ST7701_WRITE(st7701, 0xE1,
588+
0x3, 0xA0, 0x0, 0x0, 0x4, 0xA0, 0x0, 0x0,
589+
0x0, 0x20, 0x20);
590+
591+
ST7701_WRITE(st7701, 0xE2,
592+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
593+
0x0, 0x0, 0x0, 0x0, 0x0);
594+
595+
ST7701_WRITE(st7701, 0xE3, 0x0, 0x0, 0x11, 0x0);
596+
597+
ST7701_WRITE(st7701, 0xE4, 0x22, 0x0);
598+
599+
ST7701_WRITE(st7701, 0xE5,
600+
0x5, 0xEC, 0xA0, 0xA0, 0x7, 0xEE, 0xA0, 0xA0,
601+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);
602+
603+
ST7701_WRITE(st7701, 0xE6, 0x0, 0x0, 0x11, 0x0);
604+
605+
ST7701_WRITE(st7701, 0xE7, 0x22, 0x0);
606+
607+
ST7701_WRITE(st7701, 0xE8,
608+
0x6, 0xED, 0xA0, 0xA0, 0x8, 0xEF, 0xA0, 0xA0,
609+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);
610+
611+
ST7701_WRITE(st7701, 0xEB,
612+
0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0);
613+
614+
ST7701_WRITE(st7701, 0xED,
615+
0xFF, 0xFF, 0xFF, 0xBA, 0xA, 0xBF, 0x45, 0xFF,
616+
0xFF, 0x54, 0xFB, 0xA0, 0xAB, 0xFF, 0xFF, 0xFF);
617+
618+
ST7701_WRITE(st7701, 0xEF, 0x10, 0xD, 0x4, 0x8, 0x3F, 0x1F);
619+
620+
st7701_switch_cmd_bkx(st7701, true, 3);
621+
622+
ST7701_WRITE(st7701, 0xEF, 0x8);
623+
624+
st7701_switch_cmd_bkx(st7701, false, 0);
625+
626+
ST7701_WRITE(st7701, 0xCD, 0x8); /* RGB format COLCTRL */
627+
628+
ST7701_WRITE(st7701, 0x36, 0x8); /* MadCtl */
629+
630+
ST7701_WRITE(st7701, 0x3A, 0x66); /* Colmod */
631+
632+
ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE);
633+
}
634+
545635
static int st7701_prepare(struct drm_panel *panel)
546636
{
547637
struct st7701 *st7701 = panel_to_st7701(panel);
@@ -631,6 +721,11 @@ static int st7701_get_modes(struct drm_panel *panel,
631721
drm_mode_set_name(mode);
632722
drm_mode_probed_add(connector, mode);
633723

724+
if (st7701->desc->mediabus_format)
725+
drm_display_info_set_bus_formats(&connector->display_info,
726+
&st7701->desc->mediabus_format,
727+
1);
728+
634729
connector->display_info.width_mm = desc_mode->width_mm;
635730
connector->display_info.height_mm = desc_mode->height_mm;
636731

@@ -1178,6 +1273,26 @@ static const struct drm_display_mode wf40eswaa6mnn0_mode = {
11781273
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
11791274
};
11801275

1276+
static const struct drm_display_mode txw210001b0_mode = {
1277+
.clock = 19200,
1278+
1279+
.hdisplay = 480,
1280+
.hsync_start = 480 + 10,
1281+
.hsync_end = 480 + 10 + 16,
1282+
.htotal = 480 + 10 + 16 + 56,
1283+
1284+
.vdisplay = 480,
1285+
.vsync_start = 480 + 15,
1286+
.vsync_end = 480 + 15 + 60,
1287+
.vtotal = 480 + 15 + 60 + 15,
1288+
1289+
.width_mm = 53,
1290+
.height_mm = 53,
1291+
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
1292+
1293+
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
1294+
};
1295+
11811296
static const struct st7701_panel_desc wf40eswaa6mnn0_desc = {
11821297
.mode = &wf40eswaa6mnn0_mode,
11831298
.lanes = 2,
@@ -1258,6 +1373,134 @@ static const struct st7701_panel_desc wf40eswaa6mnn0_desc = {
12581373
.gip_sequence = wf40eswaa6mnn0_gip_sequence,
12591374
};
12601375

1376+
static const struct st7701_panel_desc txw210001b0_desc = {
1377+
.mode = &txw210001b0_mode,
1378+
.mediabus_format = MEDIA_BUS_FMT_RGB888_1X24,
1379+
.pv_gamma = {
1380+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1381+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x2),
1382+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1383+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
1384+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1385+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
1386+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),
1387+
1388+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1389+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10),
1390+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
1391+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
1392+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),
1393+
1394+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
1395+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
1396+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
1397+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1398+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),
1399+
1400+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
1401+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1402+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
1403+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1404+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
1405+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1406+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
1407+
},
1408+
.nv_gamma = {
1409+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1410+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x5),
1411+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1412+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
1413+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x0) |
1414+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
1415+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),
1416+
1417+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1418+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),
1419+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
1420+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
1421+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),
1422+
1423+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
1424+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
1425+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
1426+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1427+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),
1428+
1429+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
1430+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1431+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
1432+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1433+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
1434+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1435+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
1436+
},
1437+
.gip_sequence = txw210001b0_gip_sequence,
1438+
};
1439+
1440+
static const struct st7701_panel_desc hyperpixel2r_desc = {
1441+
.mode = &txw210001b0_mode,
1442+
.mediabus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
1443+
.pv_gamma = {
1444+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1445+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x2),
1446+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1447+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
1448+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1449+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
1450+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),
1451+
1452+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1453+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10),
1454+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
1455+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
1456+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),
1457+
1458+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
1459+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
1460+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
1461+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1462+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),
1463+
1464+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
1465+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1466+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
1467+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1468+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
1469+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1470+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
1471+
},
1472+
.nv_gamma = {
1473+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1474+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x5),
1475+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1476+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
1477+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x0) |
1478+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
1479+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),
1480+
1481+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1482+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),
1483+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
1484+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
1485+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),
1486+
1487+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
1488+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
1489+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
1490+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1491+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),
1492+
1493+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
1494+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1495+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
1496+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1497+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
1498+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
1499+
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
1500+
},
1501+
.gip_sequence = txw210001b0_gip_sequence,
1502+
};
1503+
12611504
static void st7701_cleanup(void *data)
12621505
{
12631506
struct st7701 *st7701 = (struct st7701 *)data;
@@ -1290,7 +1533,7 @@ static int st7701_probe(struct device *dev, int connector_type)
12901533
if (ret < 0)
12911534
return ret;
12921535

1293-
st7701->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
1536+
st7701->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
12941537
if (IS_ERR(st7701->reset)) {
12951538
dev_err(dev, "Couldn't get our reset GPIO\n");
12961539
return PTR_ERR(st7701->reset);
@@ -1395,12 +1638,16 @@ MODULE_DEVICE_TABLE(of, st7701_dsi_of_match);
13951638

13961639
static const struct of_device_id st7701_spi_of_match[] = {
13971640
{ .compatible = "anbernic,rg28xx-panel", .data = &rg28xx_desc },
1641+
{ .compatible = "txw,txw210001b0", .data = &txw210001b0_desc },
1642+
{ .compatible = "pimoroni,hyperpixel2round", .data = &hyperpixel2r_desc },
13981643
{ /* sentinel */ }
13991644
};
14001645
MODULE_DEVICE_TABLE(of, st7701_spi_of_match);
14011646

14021647
static const struct spi_device_id st7701_spi_ids[] = {
14031648
{ "rg28xx-panel" },
1649+
{ "txw210001b0" },
1650+
{ "hyperpixel2round" },
14041651
{ /* sentinel */ }
14051652
};
14061653
MODULE_DEVICE_TABLE(spi, st7701_spi_ids);

0 commit comments

Comments
 (0)