drm/panel/panel-sitronix-st7701: Parametrize voltage and timing

Instead of hard-coding TFT matrix voltage and timing settings, which can
even lead to permanent TFT matrix damage, parametrize them in TFT matrix
descriptor.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Guido Günther <agx@sigxcpu.org>
Cc: Jagan Teki <jagan@amarulasolutions.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220710194437.289042-8-marex@denx.de
This commit is contained in:
Marek Vasut 2022-07-10 21:44:36 +02:00 committed by Linus Walleij
parent de2b491784
commit 83b7a8e7e8
1 changed files with 127 additions and 28 deletions

View File

@ -79,30 +79,34 @@
#define DSI_CMD2_BK0_INVSEL_RTNI_MASK GENMASK(4, 0) #define DSI_CMD2_BK0_INVSEL_RTNI_MASK GENMASK(4, 0)
/* Command2, BK1 bytes */ /* Command2, BK1 bytes */
#define DSI_CMD2_BK1_VRHA_SET 0x45 #define DSI_CMD2_BK1_VRHA_MASK GENMASK(7, 0)
#define DSI_CMD2_BK1_VCOM_SET 0x13 #define DSI_CMD2_BK1_VCOM_MASK GENMASK(7, 0)
#define DSI_CMD2_BK1_VGHSS_SET GENMASK(2, 0) #define DSI_CMD2_BK1_VGHSS_MASK GENMASK(3, 0)
#define DSI_CMD2_BK1_TESTCMD_VAL BIT(7) #define DSI_CMD2_BK1_TESTCMD_VAL BIT(7)
#define DSI_VGLS_DEFAULT BIT(6) #define DSI_CMD2_BK1_VGLS_ONES BIT(6)
#define DSI_VGLS_SEL GENMASK(2, 0) #define DSI_CMD2_BK1_VGLS_MASK GENMASK(3, 0)
#define DSI_CMD2_BK1_VGLS_SET (DSI_VGLS_DEFAULT | DSI_VGLS_SEL) #define DSI_CMD2_BK1_PWRCTRL1_AP_MASK GENMASK(7, 6)
#define DSI_PWCTLR1_AP BIT(7) /* Gamma OP bias, max */ #define DSI_CMD2_BK1_PWRCTRL1_APIS_MASK GENMASK(3, 2)
#define DSI_PWCTLR1_APIS BIT(2) /* Source OP input bias, min */ #define DSI_CMD2_BK1_PWRCTRL1_APOS_MASK GENMASK(1, 0)
#define DSI_PWCTLR1_APOS BIT(0) /* Source OP output bias, min */ #define DSI_CMD2_BK1_PWRCTRL2_AVDD_MASK GENMASK(5, 4)
#define DSI_CMD2_BK1_PWCTLR1_SET (DSI_PWCTLR1_AP | DSI_PWCTLR1_APIS | \ #define DSI_CMD2_BK1_PWRCTRL2_AVCL_MASK GENMASK(1, 0)
DSI_PWCTLR1_APOS) #define DSI_CMD2_BK1_SPD1_ONES_MASK GENMASK(6, 4)
#define DSI_PWCTLR2_AVDD BIT(5) /* AVDD 6.6v */ #define DSI_CMD2_BK1_SPD1_T2D_MASK GENMASK(3, 0)
#define DSI_PWCTLR2_AVCL 0x0 /* AVCL -4.4v */ #define DSI_CMD2_BK1_SPD2_ONES_MASK GENMASK(6, 4)
#define DSI_CMD2_BK1_PWCTLR2_SET (DSI_PWCTLR2_AVDD | DSI_PWCTLR2_AVCL) #define DSI_CMD2_BK1_SPD2_T3D_MASK GENMASK(3, 0)
#define DSI_SPD1_T2D BIT(3) #define DSI_CMD2_BK1_MIPISET1_ONES BIT(7)
#define DSI_CMD2_BK1_SPD1_SET (GENMASK(6, 4) | DSI_SPD1_T2D) #define DSI_CMD2_BK1_MIPISET1_EOT_EN BIT(3)
#define DSI_CMD2_BK1_SPD2_SET DSI_CMD2_BK1_SPD1_SET
#define DSI_MIPISET1_EOT_EN BIT(3)
#define DSI_CMD2_BK1_MIPISET1_SET (BIT(7) | DSI_MIPISET1_EOT_EN)
#define CFIELD_PREP(_mask, _val) \ #define CFIELD_PREP(_mask, _val) \
(((typeof(_mask))(_val) << (__builtin_ffsll(_mask) - 1)) & (_mask)) (((typeof(_mask))(_val) << (__builtin_ffsll(_mask) - 1)) & (_mask))
enum op_bias {
OP_BIAS_OFF = 0,
OP_BIAS_MIN,
OP_BIAS_MIDDLE,
OP_BIAS_MAX
};
struct st7701_panel_desc { struct st7701_panel_desc {
const struct drm_display_mode *mode; const struct drm_display_mode *mode;
unsigned int lanes; unsigned int lanes;
@ -113,6 +117,18 @@ struct st7701_panel_desc {
const u8 pv_gamma[16]; /* Positive voltage gamma control */ const u8 pv_gamma[16]; /* Positive voltage gamma control */
const u8 nv_gamma[16]; /* Negative voltage gamma control */ const u8 nv_gamma[16]; /* Negative voltage gamma control */
const u8 nlinv; /* Inversion selection */ const u8 nlinv; /* Inversion selection */
const u32 vop_uv; /* Vop in uV */
const u32 vcom_uv; /* Vcom in uV */
const u16 vgh_mv; /* Vgh in mV */
const s16 vgl_mv; /* Vgl in mV */
const u16 avdd_mv; /* Avdd in mV */
const s16 avcl_mv; /* Avcl in mV */
const enum op_bias gamma_op_bias;
const enum op_bias input_op_bias;
const enum op_bias output_op_bias;
const u16 t2d_ns; /* T2D in ns */
const u16 t3d_ns; /* T3D in ns */
const bool eot_en;
}; };
struct st7701 { struct st7701 {
@ -142,6 +158,31 @@ static inline int st7701_dsi_write(struct st7701 *st7701, const void *seq,
st7701_dsi_write(st7701, d, ARRAY_SIZE(d)); \ st7701_dsi_write(st7701, d, ARRAY_SIZE(d)); \
} }
static u8 st7701_vgls_map(struct st7701 *st7701)
{
const struct st7701_panel_desc *desc = st7701->desc;
struct {
s32 vgl;
u8 val;
} map[16] = {
{ -7060, 0x0 }, { -7470, 0x1 },
{ -7910, 0x2 }, { -8140, 0x3 },
{ -8650, 0x4 }, { -8920, 0x5 },
{ -9210, 0x6 }, { -9510, 0x7 },
{ -9830, 0x8 }, { -10170, 0x9 },
{ -10530, 0xa }, { -10910, 0xb },
{ -11310, 0xc }, { -11730, 0xd },
{ -12200, 0xe }, { -12690, 0xf }
};
int i;
for (i = 0; i < ARRAY_SIZE(map); i++)
if (desc->vgl_mv == map[i].vgl)
return map[i].val;
return 0;
}
static void st7701_init_sequence(struct st7701 *st7701) static void st7701_init_sequence(struct st7701 *st7701)
{ {
const struct st7701_panel_desc *desc = st7701->desc; const struct st7701_panel_desc *desc = st7701->desc;
@ -200,16 +241,62 @@ static void st7701_init_sequence(struct st7701 *st7701)
/* Command2, BK1 */ /* Command2, BK1 */
ST7701_DSI(st7701, DSI_CMD2BKX_SEL, ST7701_DSI(st7701, DSI_CMD2BKX_SEL,
0x77, 0x01, 0x00, 0x00, DSI_CMD2BK1_SEL); 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK1_SEL);
ST7701_DSI(st7701, DSI_CMD2_BK1_VRHS, DSI_CMD2_BK1_VRHA_SET);
ST7701_DSI(st7701, DSI_CMD2_BK1_VCOM, DSI_CMD2_BK1_VCOM_SET); /* Vop = 3.5375V + (VRHA[7:0] * 0.0125V) */
ST7701_DSI(st7701, DSI_CMD2_BK1_VGHSS, DSI_CMD2_BK1_VGHSS_SET); ST7701_DSI(st7701, DSI_CMD2_BK1_VRHS,
FIELD_PREP(DSI_CMD2_BK1_VRHA_MASK,
DIV_ROUND_CLOSEST(desc->vop_uv - 3537500, 12500)));
/* Vcom = 0.1V + (VCOM[7:0] * 0.0125V) */
ST7701_DSI(st7701, DSI_CMD2_BK1_VCOM,
FIELD_PREP(DSI_CMD2_BK1_VCOM_MASK,
DIV_ROUND_CLOSEST(desc->vcom_uv - 100000, 12500)));
/* Vgh = 11.5V + (VGHSS[7:0] * 0.5V) */
ST7701_DSI(st7701, DSI_CMD2_BK1_VGHSS,
FIELD_PREP(DSI_CMD2_BK1_VGHSS_MASK,
DIV_ROUND_CLOSEST(clamp(desc->vgh_mv,
(u16)11500,
(u16)17000) - 11500,
500)));
ST7701_DSI(st7701, DSI_CMD2_BK1_TESTCMD, DSI_CMD2_BK1_TESTCMD_VAL); ST7701_DSI(st7701, DSI_CMD2_BK1_TESTCMD, DSI_CMD2_BK1_TESTCMD_VAL);
ST7701_DSI(st7701, DSI_CMD2_BK1_VGLS, DSI_CMD2_BK1_VGLS_SET);
ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR1, DSI_CMD2_BK1_PWCTLR1_SET); /* Vgl is non-linear */
ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR2, DSI_CMD2_BK1_PWCTLR2_SET); ST7701_DSI(st7701, DSI_CMD2_BK1_VGLS,
ST7701_DSI(st7701, DSI_CMD2_BK1_SPD1, DSI_CMD2_BK1_SPD1_SET); DSI_CMD2_BK1_VGLS_ONES |
ST7701_DSI(st7701, DSI_CMD2_BK1_SPD2, DSI_CMD2_BK1_SPD2_SET); FIELD_PREP(DSI_CMD2_BK1_VGLS_MASK, st7701_vgls_map(st7701)));
ST7701_DSI(st7701, DSI_CMD2_BK1_MIPISET1, DSI_CMD2_BK1_MIPISET1_SET);
ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR1,
FIELD_PREP(DSI_CMD2_BK1_PWRCTRL1_AP_MASK,
desc->gamma_op_bias) |
FIELD_PREP(DSI_CMD2_BK1_PWRCTRL1_APIS_MASK,
desc->input_op_bias) |
FIELD_PREP(DSI_CMD2_BK1_PWRCTRL1_APOS_MASK,
desc->output_op_bias));
/* Avdd = 6.2V + (AVDD[1:0] * 0.2V) , Avcl = -4.4V - (AVCL[1:0] * 0.2V) */
ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR2,
FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVDD_MASK,
DIV_ROUND_CLOSEST(desc->avdd_mv - 6200, 200)) |
FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVCL_MASK,
DIV_ROUND_CLOSEST(-4400 + desc->avcl_mv, 200)));
/* T2D = 0.2us * T2D[3:0] */
ST7701_DSI(st7701, DSI_CMD2_BK1_SPD1,
DSI_CMD2_BK1_SPD1_ONES_MASK |
FIELD_PREP(DSI_CMD2_BK1_SPD1_T2D_MASK,
DIV_ROUND_CLOSEST(desc->t2d_ns, 200)));
/* T3D = 4us + (0.8us * T3D[3:0]) */
ST7701_DSI(st7701, DSI_CMD2_BK1_SPD2,
DSI_CMD2_BK1_SPD2_ONES_MASK |
FIELD_PREP(DSI_CMD2_BK1_SPD2_T3D_MASK,
DIV_ROUND_CLOSEST(desc->t3d_ns - 4000, 800)));
ST7701_DSI(st7701, DSI_CMD2_BK1_MIPISET1,
DSI_CMD2_BK1_MIPISET1_ONES |
(desc->eot_en ? DSI_CMD2_BK1_MIPISET1_EOT_EN : 0));
/** /**
* ST7701_SPEC_V1.2 is unable to provide enough information above this * ST7701_SPEC_V1.2 is unable to provide enough information above this
@ -419,6 +506,18 @@ static const struct st7701_panel_desc ts8550b_desc = {
CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f) CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)
}, },
.nlinv = 7, .nlinv = 7,
.vop_uv = 4400000,
.vcom_uv = 337500,
.vgh_mv = 15000,
.vgl_mv = -9510,
.avdd_mv = 6600,
.avcl_mv = -4400,
.gamma_op_bias = OP_BIAS_MAX,
.input_op_bias = OP_BIAS_MIN,
.output_op_bias = OP_BIAS_MIN,
.t2d_ns = 1600,
.t3d_ns = 10400,
.eot_en = true,
}; };
static int st7701_dsi_probe(struct mipi_dsi_device *dsi) static int st7701_dsi_probe(struct mipi_dsi_device *dsi)