Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 248 additions & 1 deletion drivers/gpu/drm/panel/panel-sitronix-st7701.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/bitfield.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
Expand Down Expand Up @@ -106,6 +107,7 @@ struct st7701_panel_desc {
const struct drm_display_mode *mode;
unsigned int lanes;
enum mipi_dsi_pixel_format format;
u32 mediabus_format;
unsigned int panel_sleep_delay;

/* TFT matrix driver configuration, panel specific. */
Expand Down Expand Up @@ -520,6 +522,94 @@ static void rg28xx_gip_sequence(struct st7701 *st7701)
st7701_switch_cmd_bkx(st7701, false, 0);
}

static void txw210001b0_gip_sequence(struct st7701 *st7701)
{
ST7701_WRITE(st7701, MIPI_DCS_SOFT_RESET);

usleep_range(5000, 7000);

st7701_switch_cmd_bkx(st7701, true, 0);

ST7701_WRITE(st7701, ST7701_CMD2_BK0_LNESET, 0x3B, 0x0);

ST7701_WRITE(st7701, ST7701_CMD2_BK0_PORCTRL, 0xB, 0x2);

ST7701_WRITE(st7701, ST7701_CMD2_BK0_INVSEL, 0x0, 0x2);

ST7701_WRITE(st7701, 0xCC, 0x10);

st7701_switch_cmd_bkx(st7701, true, 1);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_VRHS, 0x5D);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_VCOM, 0x43);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGHSS, 0x81);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_TESTCMD, 0x80);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGLS, 0x43);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR1, 0x85);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR2, 0x20);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD1, 0x78);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD2, 0x78);

ST7701_WRITE(st7701, ST7701_CMD2_BK1_MIPISET1, 0x88);

ST7701_WRITE(st7701, 0xE0, 0x0, 0x0, 0x2);

ST7701_WRITE(st7701, 0xE1,
0x3, 0xA0, 0x0, 0x0, 0x4, 0xA0, 0x0, 0x0,
0x0, 0x20, 0x20);

ST7701_WRITE(st7701, 0xE2,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0);

ST7701_WRITE(st7701, 0xE3, 0x0, 0x0, 0x11, 0x0);

ST7701_WRITE(st7701, 0xE4, 0x22, 0x0);

ST7701_WRITE(st7701, 0xE5,
0x5, 0xEC, 0xA0, 0xA0, 0x7, 0xEE, 0xA0, 0xA0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);

ST7701_WRITE(st7701, 0xE6, 0x0, 0x0, 0x11, 0x0);

ST7701_WRITE(st7701, 0xE7, 0x22, 0x0);

ST7701_WRITE(st7701, 0xE8,
0x6, 0xED, 0xA0, 0xA0, 0x8, 0xEF, 0xA0, 0xA0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);

ST7701_WRITE(st7701, 0xEB,
0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0);

ST7701_WRITE(st7701, 0xED,
0xFF, 0xFF, 0xFF, 0xBA, 0xA, 0xBF, 0x45, 0xFF,
0xFF, 0x54, 0xFB, 0xA0, 0xAB, 0xFF, 0xFF, 0xFF);

ST7701_WRITE(st7701, 0xEF, 0x10, 0xD, 0x4, 0x8, 0x3F, 0x1F);

st7701_switch_cmd_bkx(st7701, true, 3);

ST7701_WRITE(st7701, 0xEF, 0x8);

st7701_switch_cmd_bkx(st7701, false, 0);

ST7701_WRITE(st7701, 0xCD, 0x8); /* RGB format COLCTRL */

ST7701_WRITE(st7701, 0x36, 0x8); /* MadCtl */

ST7701_WRITE(st7701, 0x3A, 0x66); /* Colmod */

ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE);
}

static int st7701_prepare(struct drm_panel *panel)
{
struct st7701 *st7701 = panel_to_st7701(panel);
Expand Down Expand Up @@ -609,6 +699,11 @@ static int st7701_get_modes(struct drm_panel *panel,
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);

if (st7701->desc->mediabus_format)
drm_display_info_set_bus_formats(&connector->display_info,
&st7701->desc->mediabus_format,
1);

connector->display_info.width_mm = desc_mode->width_mm;
connector->display_info.height_mm = desc_mode->height_mm;

Expand Down Expand Up @@ -1135,6 +1230,154 @@ static const struct st7701_panel_desc rg28xx_desc = {
.gip_sequence = rg28xx_gip_sequence,
};

static const struct drm_display_mode txw210001b0_mode = {
.clock = 19200,

.hdisplay = 480,
.hsync_start = 480 + 10,
.hsync_end = 480 + 10 + 16,
.htotal = 480 + 10 + 16 + 56,

.vdisplay = 480,
.vsync_start = 480 + 15,
.vsync_end = 480 + 15 + 60,
.vtotal = 480 + 15 + 60 + 15,

.width_mm = 53,
.height_mm = 53,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,

.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};

static const struct st7701_panel_desc txw210001b0_desc = {
.mode = &txw210001b0_mode,
.mediabus_format = MEDIA_BUS_FMT_RGB888_1X24,
.pv_gamma = {
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x2),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
},
.nv_gamma = {
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x5),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
},
.gip_sequence = txw210001b0_gip_sequence,
};

static const struct st7701_panel_desc hyperpixel2r_desc = {
.mode = &txw210001b0_mode,
.mediabus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
.pv_gamma = {
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x2),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
},
.nv_gamma = {
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x5),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),

CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33),
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |
CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d)
},
.gip_sequence = txw210001b0_gip_sequence,
};

static void st7701_cleanup(void *data)
{
struct st7701 *st7701 = (struct st7701 *)data;
Expand Down Expand Up @@ -1166,7 +1409,7 @@ static int st7701_probe(struct device *dev, int connector_type)
if (ret < 0)
return ret;

st7701->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
st7701->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(st7701->reset)) {
dev_err(dev, "Couldn't get our reset GPIO\n");
return PTR_ERR(st7701->reset);
Expand Down Expand Up @@ -1271,12 +1514,16 @@ MODULE_DEVICE_TABLE(of, st7701_dsi_of_match);

static const struct of_device_id st7701_spi_of_match[] = {
{ .compatible = "anbernic,rg28xx-panel", .data = &rg28xx_desc },
{ .compatible = "txw,txw210001b0", .data = &txw210001b0_desc },
{ .compatible = "pimoroni,hyperpixel2round", .data = &hyperpixel2r_desc },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, st7701_spi_of_match);

static const struct spi_device_id st7701_spi_ids[] = {
{ "rg28xx-panel" },
{ "txw210001b0" },
{ "hyperpixel2round" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, st7701_spi_ids);
Expand Down