File Index
Files and directories
Sign in
FILE

panel-himax-hx8279.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-himax-hx8279.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Himax HX8279 DriverIC panels driver
   4 *
   5 * Copyright (c) 2025 Collabora Ltd.
   6 *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
   7 */
   8
   9#include <linux/bitfield.h>
  10#include <linux/delay.h>
  11#include <linux/gpio/consumer.h>
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/of_graph.h>
  15#include <linux/regulator/consumer.h>
  16
  17#include <drm/drm_connector.h>
  18#include <drm/drm_crtc.h>
  19#include <drm/drm_mipi_dsi.h>
  20#include <drm/drm_modes.h>
  21#include <drm/drm_panel.h>
  22
  23/* Page selection */
  24#define HX8279_REG_PAGE			0xb0
  25 #define HX8279_PAGE_SEL		GENMASK(3, 0)
  26
  27/* Page 0 - Driver/Module Configuration */
  28#define HX8279_P0_VGHS			0xbf
  29#define HX8279_P0_VGLS			0xc0
  30#define HX8279_P0_VGPHS			0xc2
  31#define HX8279_P0_VGNHS			0xc4
  32 #define HX8279_P0_VG_SEL		GENMASK(4, 0)
  33 #define HX8279_VGH_MIN_MV		8700
  34 #define HX8279_VGH_STEP_MV		300
  35 #define HX8279_VGL_MIN_MV		6700
  36 #define HX8279_VGL_STEP_MV		300
  37 #define HX8279_VGPNH_MIN_MV		4000
  38 #define HX8279_VGPNX_STEP_MV		50
  39 #define HX8279_VGH_VOLT_SEL(x)		((x - HX8279_VGH_MIN_MV) / HX8279_VGH_STEP_MV)
  40 #define HX8279_VGL_VOLT_SEL(x)		((x - HX8279_VGL_MIN_MV) / HX8279_VGL_STEP_MV)
  41 #define HX8279_VGPN_VOLT_SEL(x)	((x - HX8279_VGPNH_MIN_MV) / HX8279_VGPNX_STEP_MV)
  42
  43/* Page 1 - Gate driver On Array (GOA) Mux */
  44#define HX8279_P1_REG_GOA_L		0xc0
  45#define HX8279_P1_REG_GOUTL(x)		(HX8279_P1_REG_GOA_L + (x))
  46#define HX8279_P1_REG_GOA_R		0xd4
  47#define HX8279_P1_REG_GOUTR(x)		(HX8279_P1_REG_GOA_R + (x))
  48 #define HX8279_GOUT_STB		GENMASK(7, 6)
  49 #define HX8279_GOUT_SEL		GENMASK(5, 0)
  50
  51/* Page 2 - Analog Gamma Configuration */
  52#define HX8279_P2_REG_ANALOG_GAMMA	0xc0
  53 #define HX8279_P2_REG_GAMMA_T_PVP(x)	(HX8279_P2_REG_ANALOG_GAMMA + (x))	/* 0..16 */
  54 #define HX8279_P2_REG_GAMMA_T_PVN(x)	(HX8279_P2_REG_GAMMA_T_PVP(17) + (x))	/* 0..16 */
  55
  56/* Page 3 - Gate driver On Array (GOA) Configuration */
  57#define HX8279_P3_REG_UNKNOWN_BA	0xba
  58#define HX8279_P3_REG_GOA_CKV_FALL_PREC	0xbc
  59#define HX8279_P3_REG_GOA_TIMING_ODD	0xc2
  60 #define HX8279_P3_REG_GOA_TO(x)	(HX8279_P3_REG_GOA_TIMING_ODD + x) /* GOA_T0..5 */
  61#define HX8279_P3_REG_GOA_STVL		0xc8
  62 #define HX8279_P3_GOA_STV_LEAD		GENMASK(4, 0)
  63#define HX8279_P3_REG_GOA_CKVL		0xc9
  64 #define HX8279_P3_GOA_CKV_LEAD		GENMASK(4, 0)
  65#define HX8279_P3_REG_GOA_CKVD		0xca
  66 #define HX8279_P3_GOA_CKV_NONOVERLAP	BIT(7)
  67 #define HX8279_P3_GOA_CKV_RESERVED	BIT(6)
  68 #define HX8279_P3_GOA_CKV_DUMMY	GENMASK(5, 0)
  69#define HX8279_P3_REG_GOA_CKV_RISE_PREC	0xcb
  70#define HX8279_P3_REG_GOA_CLR1_W_ADJ	0xd2
  71#define HX8279_P3_REG_GOA_CLR234_W_ADJ	0xd3
  72#define HX8279_P3_REG_GOA_CLR1_CFG	0xd4
  73#define HX8279_P3_REG_GOA_CLR_CFG(x)	(HX8279_P3_REG_GOA_CLR1_CFG + (x)) /* CLR1..4 */
  74 #define HX8279_P3_GOA_CLR_CFG_POLARITY	BIT(7)
  75 #define HX8279_P3_GOA_CLR_CFG_STARTPOS	GENMASK(6, 0)
  76#define HX8279_P3_REG_GOA_TIMING_EVEN	0xdd
  77 #define HX8279_P3_REG_GOA_TE(x)	(HX8279_P3_REG_GOA_TIMING_EVEN + x)
  78#define HX8279_P3_REG_UNKNOWN_E4	0xe4
  79#define HX8279_P3_REG_UNKNOWN_E5	0xe5
  80
  81/* Page 5 - MIPI */
  82#define HX8279_P5_REG_TIMING		0xb3
  83 #define HX8279_P5_TIMING_THS_SETTLE	GENMASK(7, 5)
  84 #define HX8279_P5_TIMING_LHS_SETTLE	BIT(4)
  85 #define HX8279_P5_TIMING_TLPX		GENMASK(3, 0)
  86#define HX8279_P5_REG_UNKNOWN_B8	0xb8
  87#define HX8279_P5_REG_UNKNOWN_BC	0xbc
  88#define HX8279_P5_REG_UNKNOWN_D6	0xd6
  89
  90/* Page 6 - Engineer */
  91#define HX8279_P6_REG_ENGINEER_PWD	0xb8
  92#define HX8279_P6_REG_INHOUSE_FUNC	0xc0
  93 #define HX8279_P6_ENG_UNLOCK_WORD	0xa5
  94#define HX8279_P6_REG_GAMMA_CHOPPER	0xbc
  95 #define HX8279_P6_GAMMA_POCGM_CTL	GENMASK(6, 4)
  96 #define HX8279_P6_GAMMA_POGCMD_CTL	GENMASK(2, 0)
  97#define HX8279_P6_REG_VOLT_ADJ		0xc7
  98 /* For VCCIFS and VCCS - 0: 1450, 1: 1500, 2: 1550, 3: 1600 uV */
  99 #define HX8279_P6_VOLT_ADJ_VCCIFS	GENMASK(3, 2)
 100 #define HX8279_P6_VOLT_ADJ_VCCS	GENMASK(1, 0)
 101#define HX8279_P6_REG_DLY_TIME_ADJ	0xd5
 102
 103/* Page 7...12 - Digital Gamma Adjustment */
 104#define HX8279_PG_DIGITAL_GAMMA		0xb1
 105#define HX8279_DGAMMA_DGMA1_HI		GENMASK(7, 6)
 106#define HX8279_DGAMMA_DGMA2_HI		GENMASK(5, 4)
 107#define HX8279_DGAMMA_DGMA3_HI		GENMASK(3, 2)
 108#define HX8279_DGAMMA_DGMA4_HI		GENMASK(1, 0)
 109#define HX8279_PG_DGAMMA_NUM_LO_BYTES	24
 110#define HX8279_PG_DGAMMA_NUM_HI_BYTES	6
 111
 112struct hx8279 {
 113	struct drm_panel panel;
 114	struct mipi_dsi_device *dsi[2];
 115	struct regulator_bulk_data vregs[2];
 116	struct gpio_desc *enable_gpio;
 117	struct gpio_desc *reset_gpio;
 118	const struct hx8279_panel_desc *desc;
 119	u8 last_page;
 120	bool skip_voltage_config;
 121	bool skip_goa_config;
 122	bool skip_goa_timing;
 123	bool skip_goa_even_timing;
 124	bool skip_mipi_timing;
 125};
 126
 127struct hx8279_panel_mode {
 128	const struct drm_display_mode mode;
 129	u8 bpc;
 130	bool is_video_mode;
 131};
 132
 133/**
 134 * struct hx8279_goa_mux - Gate driver On Array Muxer
 135 * @gout_l: Mux GOA signal to GOUT Left pin
 136 * @gout_r: Mux GOA signal to GOUT Right pin
 137 */
 138struct hx8279_goa_mux {
 139	u8 gout_l[20];
 140	u8 gout_r[20];
 141};
 142
 143/**
 144 * struct hx8279_analog_gamma - Analog Gamma Adjustment
 145 * @pos: Positive gamma op's input voltage, adjusted by VGP(H/L)
 146 * @neg: Negative gamma op's input voltage, adjusted by VGN(H/L)
 147 *
 148 * Analog Gamma correction is performed with 17+17 reference voltages,
 149 * changed with resistor streams, and defined with 17 register values
 150 * for positive and 17 for negative.
 151 *
 152 * Each register holds resistance values, in 8.5ohms per unit, for the
 153 * following gamma levels:
 154 * 0, 8, 16, 28, 40, 56, 80, 128, 176, 200, 216, 228, 240, 248, 252, 255.
 155 */
 156struct hx8279_analog_gamma {
 157	u8 pos[17];
 158	u8 neg[17];
 159};
 160
 161/**
 162 * struct hx8279_digital_gamma - Digital Gamma Adjustment
 163 * @r: Adjustment for red component
 164 * @g: Adjustment for green component
 165 * @b: Adjustment for blue component
 166 *
 167 * The layout of this structure follows the register layout to simplify
 168 * both the handling and the declaration of those values in the driver.
 169 * Gamma correction is internally done with a 24 segment piecewise
 170 * linear interpolation; those segments are defined with 24 ten bits
 171 * values of which:
 172 *   - The LOW eight bits for the first 24 registers start at the first
 173 *     register (at 0xb1) of the Digital Gamma Adjustment page;
 174 *   - The HIGH two bits for each of the 24 registers are contained
 175 *     in the last six registers;
 176 *   - The last six registers contain four groups of two-bits HI values
 177 *     for each of the first 24 registers, but in an inverted fashion,
 178 *     this means that the first two bits relate to the last register
 179 *     of a set of four.
 180 *
 181 * The 24 segments refer to the following gamma levels:
 182 * 0, 1, 3, 7, 11, 15, 23, 31, 47, 63, 95, 127, 128, 160,
 183 * 192, 208, 224, 232, 240, 244, 248, 252, 254, 255
 184 */
 185struct hx8279_digital_gamma {
 186	u8 r[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES];
 187	u8 g[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES];
 188	u8 b[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES];
 189};
 190
 191struct hx8279_panel_desc {
 192	const struct mipi_dsi_device_info dsi_info;
 193	const struct hx8279_panel_mode *mode_data;
 194	u8 num_lanes;
 195	u8 num_modes;
 196
 197	/* Page 0 */
 198	unsigned int vgh_mv;
 199	unsigned int vgl_mv;
 200	unsigned int vgph_mv;
 201	unsigned int vgnh_mv;
 202
 203	/* Page 1 */
 204	const struct hx8279_goa_mux *gmux;
 205
 206	/* Page 2 */
 207	const struct hx8279_analog_gamma *agamma;
 208
 209	/* Page 3 */
 210	u8 goa_unk_ba;
 211	u8 goa_odd_timing[6];
 212	u8 goa_even_timing[6];
 213	u8 goa_stv_lead_time_ck;
 214	u8 goa_ckv_lead_time_ck;
 215	u8 goa_ckv_dummy_vblank_num;
 216	u8 goa_ckv_rise_precharge;
 217	u8 goa_ckv_fall_precharge;
 218	bool goa_ckv_non_overlap_ctl;
 219	u8 goa_clr1_width_adj;
 220	u8 goa_clr234_width_adj;
 221	s8 goa_clr_polarity[4];
 222	int goa_clr_start_pos[4];
 223	u8 goa_unk_e4;
 224	u8 goa_unk_e5;
 225
 226	/* Page 5 */
 227	u8 bta_tlpx;
 228	bool lhs_settle_time_by_osc25;
 229	u8 ths_settle_time;
 230	u8 timing_unk_b8;
 231	u8 timing_unk_bc;
 232	u8 timing_unk_d6;
 233
 234	/* Page 6 */
 235	u8 gamma_ctl;
 236	u8 volt_adj;
 237	u8 src_delay_time_adj_ck;
 238
 239	/* Page 7..12 */
 240	const struct hx8279_digital_gamma *dgamma;
 241};
 242
 243static inline struct hx8279 *to_hx8279(struct drm_panel *panel)
 244{
 245	return container_of(panel, struct hx8279, panel);
 246}
 247
 248static void hx8279_set_page(struct hx8279 *hx,
 249			    struct mipi_dsi_multi_context *dsi_ctx, u8 page)
 250{
 251	const u8 cmd_set_page[] = { HX8279_REG_PAGE, page };
 252
 253	if (hx->last_page == page)
 254		return;
 255
 256	mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_page, ARRAY_SIZE(cmd_set_page));
 257	if (!dsi_ctx->accum_err)
 258		hx->last_page = page;
 259}
 260
 261static void hx8279_set_module_config(struct hx8279 *hx,
 262				     struct mipi_dsi_multi_context *dsi_ctx)
 263{
 264	const struct hx8279_panel_desc *desc = hx->desc;
 265	u8 cmd_set_voltage[2];
 266
 267	if (hx->skip_voltage_config)
 268		return;
 269
 270	/* Page 0 - Driver/Module Configuration */
 271	hx8279_set_page(hx, dsi_ctx, 0);
 272
 273	if (desc->vgh_mv) {
 274		cmd_set_voltage[0] = HX8279_P0_VGHS;
 275		cmd_set_voltage[1] = HX8279_VGH_VOLT_SEL(desc->vgh_mv);
 276		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage,
 277					     ARRAY_SIZE(cmd_set_voltage));
 278	}
 279
 280	if (desc->vgl_mv) {
 281		cmd_set_voltage[0] = HX8279_P0_VGLS;
 282		cmd_set_voltage[1] = HX8279_VGL_VOLT_SEL(desc->vgl_mv);
 283		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage,
 284					     ARRAY_SIZE(cmd_set_voltage));
 285	}
 286
 287	if (desc->vgph_mv) {
 288		cmd_set_voltage[0] = HX8279_P0_VGPHS;
 289		cmd_set_voltage[1] = HX8279_VGPN_VOLT_SEL(desc->vgph_mv);
 290		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage,
 291					     ARRAY_SIZE(cmd_set_voltage));
 292	}
 293
 294	if (desc->vgnh_mv) {
 295		cmd_set_voltage[0] = HX8279_P0_VGNHS;
 296		cmd_set_voltage[1] = HX8279_VGPN_VOLT_SEL(desc->vgnh_mv);
 297		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_voltage,
 298					     ARRAY_SIZE(cmd_set_voltage));
 299	}
 300}
 301
 302static void hx8279_set_gmux(struct hx8279 *hx,
 303			    struct mipi_dsi_multi_context *dsi_ctx)
 304{
 305	const struct hx8279_goa_mux *gmux = hx->desc->gmux;
 306	u8 cmd_set_gmux[2];
 307	int i;
 308
 309	if (!gmux)
 310		return;
 311
 312	hx8279_set_page(hx, dsi_ctx, 1);
 313
 314	for (i = 0; i < ARRAY_SIZE(gmux->gout_l); i++) {
 315		cmd_set_gmux[0] = HX8279_P1_REG_GOUTL(i);
 316		cmd_set_gmux[1] = gmux->gout_l[i];
 317		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_gmux,
 318					     ARRAY_SIZE(cmd_set_gmux));
 319	}
 320
 321	for (i = 0; i < ARRAY_SIZE(gmux->gout_r); i++) {
 322		cmd_set_gmux[0] = HX8279_P1_REG_GOUTR(i);
 323		cmd_set_gmux[1] = gmux->gout_r[i];
 324		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_gmux,
 325					     ARRAY_SIZE(cmd_set_gmux));
 326	}
 327}
 328
 329static void hx8279_set_analog_gamma(struct hx8279 *hx,
 330				    struct mipi_dsi_multi_context *dsi_ctx)
 331{
 332	const struct hx8279_analog_gamma *agamma = hx->desc->agamma;
 333	u8 cmd_set_ana_gamma[2];
 334	int i;
 335
 336	if (!agamma)
 337		return;
 338
 339	hx8279_set_page(hx, dsi_ctx, 2);
 340
 341	for (i = 0; i < ARRAY_SIZE(agamma->pos); i++) {
 342		cmd_set_ana_gamma[0] = HX8279_P2_REG_GAMMA_T_PVP(i);
 343		cmd_set_ana_gamma[1] = agamma->pos[i];
 344		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_ana_gamma,
 345					     ARRAY_SIZE(cmd_set_ana_gamma));
 346	}
 347
 348	for (i = 0; i < ARRAY_SIZE(agamma->neg); i++) {
 349		cmd_set_ana_gamma[0] = HX8279_P2_REG_GAMMA_T_PVN(i);
 350		cmd_set_ana_gamma[1] = agamma->neg[i];
 351		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_ana_gamma,
 352					     ARRAY_SIZE(cmd_set_ana_gamma));
 353	}
 354}
 355
 356static void hx8279_set_goa_timing(struct hx8279 *hx,
 357				  struct mipi_dsi_multi_context *dsi_ctx)
 358{
 359	const struct hx8279_panel_desc *desc = hx->desc;
 360	u8 cmd_set_goa_t[2];
 361	int i;
 362
 363	if (hx->skip_goa_timing)
 364		return;
 365
 366	hx8279_set_page(hx, dsi_ctx, 3);
 367
 368	for (i = 0; i < ARRAY_SIZE(desc->goa_odd_timing); i++) {
 369		cmd_set_goa_t[0] = HX8279_P3_REG_GOA_TO(i);
 370		cmd_set_goa_t[1] = desc->goa_odd_timing[i];
 371		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa_t,
 372					     ARRAY_SIZE(cmd_set_goa_t));
 373	}
 374
 375	for (i = 0; i < ARRAY_SIZE(desc->goa_even_timing); i++) {
 376		cmd_set_goa_t[0] = HX8279_P3_REG_GOA_TE(i);
 377		cmd_set_goa_t[1] = desc->goa_odd_timing[i];
 378		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa_t,
 379					     ARRAY_SIZE(cmd_set_goa_t));
 380	}
 381}
 382
 383static void hx8279_set_goa_cfg(struct hx8279 *hx,
 384			       struct mipi_dsi_multi_context *dsi_ctx)
 385{
 386	const struct hx8279_panel_desc *desc = hx->desc;
 387	u8 cmd_set_goa[2];
 388	int i;
 389
 390	if (hx->skip_goa_config)
 391		return;
 392
 393	hx8279_set_page(hx, dsi_ctx, 3);
 394
 395	if (desc->goa_unk_ba)  {
 396		cmd_set_goa[0] = HX8279_P3_REG_UNKNOWN_BA;
 397		cmd_set_goa[1] = desc->goa_unk_ba;
 398		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 399					     ARRAY_SIZE(cmd_set_goa));
 400	}
 401
 402	if (desc->goa_stv_lead_time_ck) {
 403		cmd_set_goa[0] = HX8279_P3_REG_GOA_STVL;
 404		cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_STV_LEAD,
 405					    desc->goa_stv_lead_time_ck);
 406		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 407					     ARRAY_SIZE(cmd_set_goa));
 408	}
 409
 410	if (desc->goa_ckv_lead_time_ck) {
 411		cmd_set_goa[0] = HX8279_P3_REG_GOA_CKVL;
 412		cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_CKV_DUMMY,
 413					    desc->goa_ckv_lead_time_ck);
 414		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 415					     ARRAY_SIZE(cmd_set_goa));
 416	}
 417
 418	if (desc->goa_ckv_dummy_vblank_num) {
 419		cmd_set_goa[0] = HX8279_P3_REG_GOA_CKVD;
 420		cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_CKV_LEAD,
 421					    desc->goa_ckv_dummy_vblank_num);
 422		cmd_set_goa[1] |= FIELD_PREP(HX8279_P3_GOA_CKV_NONOVERLAP,
 423					     desc->goa_ckv_non_overlap_ctl);
 424		/* RESERVED must be always set */
 425		cmd_set_goa[1] |= HX8279_P3_GOA_CKV_RESERVED;
 426		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 427					     ARRAY_SIZE(cmd_set_goa));
 428	}
 429
 430	/*
 431	 * One of the two being more than zero means that we want to write
 432	 * both of them. Anyway, the register default is zero in this case.
 433	 */
 434	if (desc->goa_ckv_rise_precharge || desc->goa_ckv_fall_precharge) {
 435		cmd_set_goa[0] = HX8279_P3_REG_GOA_CKV_RISE_PREC;
 436		cmd_set_goa[1] = desc->goa_ckv_rise_precharge;
 437		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 438					     ARRAY_SIZE(cmd_set_goa));
 439
 440		cmd_set_goa[0] = HX8279_P3_REG_GOA_CKV_FALL_PREC;
 441		cmd_set_goa[1] = desc->goa_ckv_fall_precharge;
 442		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 443					     ARRAY_SIZE(cmd_set_goa));
 444	}
 445
 446	if (desc->goa_clr1_width_adj) {
 447		cmd_set_goa[0] = HX8279_P3_REG_GOA_CLR1_W_ADJ;
 448		cmd_set_goa[1] = desc->goa_clr1_width_adj;
 449		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 450					     ARRAY_SIZE(cmd_set_goa));
 451	}
 452
 453	if (desc->goa_clr234_width_adj) {
 454		cmd_set_goa[0] = HX8279_P3_REG_GOA_CLR234_W_ADJ;
 455		cmd_set_goa[1] = desc->goa_clr234_width_adj;
 456		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 457					     ARRAY_SIZE(cmd_set_goa));
 458	}
 459
 460	/* Polarity and Start Position arrays are of the same size */
 461	for (i = 0; i < ARRAY_SIZE(desc->goa_clr_polarity); i++) {
 462		if (desc->goa_clr_polarity[i] < 0 || desc->goa_clr_start_pos[i] < 0)
 463			continue;
 464
 465		cmd_set_goa[0] = HX8279_P3_REG_GOA_CLR_CFG(i);
 466		cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_CLR_CFG_STARTPOS,
 467					    desc->goa_clr_start_pos[i]);
 468		cmd_set_goa[1] |= FIELD_PREP(HX8279_P3_GOA_CLR_CFG_POLARITY,
 469					     desc->goa_clr_polarity[i]);
 470		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 471					     ARRAY_SIZE(cmd_set_goa));
 472	}
 473
 474	if (desc->goa_unk_e4) {
 475		cmd_set_goa[0] = HX8279_P3_REG_UNKNOWN_E4;
 476		cmd_set_goa[1] = desc->goa_unk_e4;
 477		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 478					     ARRAY_SIZE(cmd_set_goa));
 479	}
 480
 481	cmd_set_goa[0] = HX8279_P3_REG_UNKNOWN_E5;
 482	cmd_set_goa[1] = desc->goa_unk_e5;
 483	mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
 484				     ARRAY_SIZE(cmd_set_goa));
 485}
 486
 487static void hx8279_set_mipi_cfg(struct hx8279 *hx,
 488				struct mipi_dsi_multi_context *dsi_ctx)
 489{
 490	const struct hx8279_panel_desc *desc = hx->desc;
 491	u8 cmd_set_mipi[2];
 492
 493	if (hx->skip_mipi_timing)
 494		return;
 495
 496	hx8279_set_page(hx, dsi_ctx, 5);
 497
 498	if (desc->bta_tlpx || desc->ths_settle_time || desc->lhs_settle_time_by_osc25) {
 499		cmd_set_mipi[0] = HX8279_P5_REG_TIMING;
 500		cmd_set_mipi[1] = FIELD_PREP(HX8279_P5_TIMING_TLPX, desc->bta_tlpx);
 501		cmd_set_mipi[1] |= FIELD_PREP(HX8279_P5_TIMING_THS_SETTLE,
 502					      desc->ths_settle_time);
 503		cmd_set_mipi[1] |= FIELD_PREP(HX8279_P5_TIMING_LHS_SETTLE,
 504					      desc->lhs_settle_time_by_osc25);
 505		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi,
 506					     ARRAY_SIZE(cmd_set_mipi));
 507	}
 508
 509	if (desc->timing_unk_b8) {
 510		cmd_set_mipi[0] = HX8279_P5_REG_UNKNOWN_B8;
 511		cmd_set_mipi[1] = desc->timing_unk_b8;
 512		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi,
 513					     ARRAY_SIZE(cmd_set_mipi));
 514	}
 515
 516	if (desc->timing_unk_bc) {
 517		cmd_set_mipi[0] = HX8279_P5_REG_UNKNOWN_BC;
 518		cmd_set_mipi[1] = desc->timing_unk_bc;
 519		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi,
 520					     ARRAY_SIZE(cmd_set_mipi));
 521	}
 522
 523	if (desc->timing_unk_d6) {
 524		cmd_set_mipi[0] = HX8279_P5_REG_UNKNOWN_D6;
 525		cmd_set_mipi[1] = desc->timing_unk_d6;
 526		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_mipi,
 527					     ARRAY_SIZE(cmd_set_mipi));
 528	}
 529}
 530
 531static void hx8279_set_adv_cfg(struct hx8279 *hx,
 532			       struct mipi_dsi_multi_context *dsi_ctx)
 533{
 534	const struct hx8279_panel_desc *desc = hx->desc;
 535	const u8 cmd_set_dly[] = { HX8279_P6_REG_DLY_TIME_ADJ, desc->src_delay_time_adj_ck };
 536	const u8 cmd_set_gamma[] = { HX8279_P6_REG_GAMMA_CHOPPER, desc->gamma_ctl };
 537	const u8 cmd_set_volt_adj[] = { HX8279_P6_REG_VOLT_ADJ, desc->volt_adj };
 538	u8 cmd_set_eng[] = { HX8279_P6_REG_ENGINEER_PWD, HX8279_P6_ENG_UNLOCK_WORD };
 539
 540	if (!desc->gamma_ctl && !desc->src_delay_time_adj_ck && !desc->volt_adj)
 541		return;
 542
 543	hx8279_set_page(hx, dsi_ctx, 6);
 544
 545	/* Unlock ENG settings: write same word to both ENGINEER_PWD and INHOUSE_FUNC */
 546	mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng));
 547
 548	cmd_set_eng[0] = HX8279_P6_REG_INHOUSE_FUNC;
 549	mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng));
 550
 551	/* Set Gamma Chopper and Gamma buffer Chopper control */
 552	mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_gamma, ARRAY_SIZE(cmd_set_gamma));
 553
 554	/* Set Source delay time adjustment (CKV falling to Source off) */
 555	if (desc->src_delay_time_adj_ck)
 556		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dly,
 557					     ARRAY_SIZE(cmd_set_dly));
 558
 559	/* Set voltage adjustment */
 560	if (desc->volt_adj)
 561		mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_volt_adj,
 562					     ARRAY_SIZE(cmd_set_volt_adj));
 563
 564	/* Lock ENG settings again */
 565	cmd_set_eng[0] = HX8279_P6_REG_ENGINEER_PWD;
 566	cmd_set_eng[1] = 0;
 567	mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng));
 568
 569	cmd_set_eng[0] = HX8279_P6_REG_INHOUSE_FUNC;
 570	mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng));
 571}
 572
 573static void hx8279_set_digital_gamma(struct hx8279 *hx,
 574				     struct mipi_dsi_multi_context *dsi_ctx)
 575{
 576	const struct hx8279_digital_gamma *dgamma = hx->desc->dgamma;
 577	u8 cmd_set_dig_gamma[2];
 578	int i;
 579
 580	if (!dgamma)
 581		return;
 582
 583	/*
 584	 * Pages 7..9 are for RGB Positive, 10..12 are for RGB Negative:
 585	 * The first iteration sets all positive component registers,
 586	 * the second one sets all negatives.
 587	 */
 588	for (i = 0; i < 2; i++) {
 589		u8 pg_neg = i * 3;
 590
 591		hx8279_set_page(hx, dsi_ctx, 7 + pg_neg);
 592
 593		for (i = 0; i < ARRAY_SIZE(dgamma->r); i++) {
 594			cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i;
 595			cmd_set_dig_gamma[1] = dgamma->r[i];
 596			mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma,
 597						     ARRAY_SIZE(cmd_set_dig_gamma));
 598		}
 599
 600		hx8279_set_page(hx, dsi_ctx, 8 + pg_neg);
 601
 602		for (i = 0; i < ARRAY_SIZE(dgamma->g); i++) {
 603			cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i;
 604			cmd_set_dig_gamma[1] = dgamma->g[i];
 605			mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma,
 606						     ARRAY_SIZE(cmd_set_dig_gamma));
 607		}
 608
 609		hx8279_set_page(hx, dsi_ctx, 9 + pg_neg);
 610
 611		for (i = 0; i < ARRAY_SIZE(dgamma->b); i++) {
 612			cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i;
 613			cmd_set_dig_gamma[1] = dgamma->b[i];
 614			mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma,
 615						     ARRAY_SIZE(cmd_set_dig_gamma));
 616		}
 617	}
 618}
 619
 620static int hx8279_on(struct hx8279 *hx)
 621{
 622	struct mipi_dsi_device *dsi = hx->dsi[0];
 623	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 624
 625	/* Page 5 */
 626	hx8279_set_mipi_cfg(hx, &dsi_ctx);
 627
 628	/* Page 1 */
 629	hx8279_set_gmux(hx, &dsi_ctx);
 630
 631	/* Page 2 */
 632	hx8279_set_analog_gamma(hx, &dsi_ctx);
 633
 634	/* Page 3 */
 635	hx8279_set_goa_cfg(hx, &dsi_ctx);
 636	hx8279_set_goa_timing(hx, &dsi_ctx);
 637
 638	/* Page 0 - Driver/Module Configuration */
 639	hx8279_set_module_config(hx, &dsi_ctx);
 640
 641	/* Page 6 */
 642	hx8279_set_adv_cfg(hx, &dsi_ctx);
 643
 644	/* Pages 7..12 */
 645	hx8279_set_digital_gamma(hx, &dsi_ctx);
 646
 647	return dsi_ctx.accum_err;
 648}
 649
 650static void hx8279_power_off(struct hx8279 *hx)
 651{
 652	gpiod_set_value_cansleep(hx->reset_gpio, 0);
 653	usleep_range(100, 500);
 654	gpiod_set_value_cansleep(hx->enable_gpio, 0);
 655	regulator_bulk_disable(ARRAY_SIZE(hx->vregs), hx->vregs);
 656}
 657
 658static int hx8279_disable(struct drm_panel *panel)
 659{
 660	struct hx8279 *hx = to_hx8279(panel);
 661	struct mipi_dsi_device *dsi = hx->dsi[0];
 662	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 663
 664	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
 665
 666	return 0;
 667}
 668
 669static int hx8279_enable(struct drm_panel *panel)
 670{
 671	struct hx8279 *hx = to_hx8279(panel);
 672	struct mipi_dsi_device *dsi = hx->dsi[0];
 673	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 674
 675	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
 676
 677	return 0;
 678}
 679
 680static int hx8279_prepare(struct drm_panel *panel)
 681{
 682	struct hx8279 *hx = to_hx8279(panel);
 683	struct mipi_dsi_device *dsi = hx->dsi[0];
 684	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 685	int ret;
 686
 687	ret = regulator_bulk_enable(ARRAY_SIZE(hx->vregs), hx->vregs);
 688	if (ret)
 689		return ret;
 690
 691	gpiod_set_value_cansleep(hx->enable_gpio, 1);
 692	usleep_range(5000, 6000);
 693	gpiod_set_value_cansleep(hx->reset_gpio, 1);
 694	usleep_range(6000, 7000);
 695
 696	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 697	if (hx->dsi[1])
 698		hx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
 699
 700	ret = hx8279_on(hx);
 701	if (ret) {
 702		hx8279_power_off(hx);
 703		return ret;
 704	}
 705
 706	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
 707	mipi_dsi_msleep(&dsi_ctx, 130);
 708
 709	return dsi_ctx.accum_err;
 710}
 711
 712static int hx8279_unprepare(struct drm_panel *panel)
 713{
 714	struct hx8279 *hx = to_hx8279(panel);
 715	struct mipi_dsi_device *dsi = hx->dsi[0];
 716	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 717
 718	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
 719	mipi_dsi_msleep(&dsi_ctx, 130);
 720
 721	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 722	if (hx->dsi[1])
 723		hx->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM;
 724
 725	hx8279_power_off(hx);
 726
 727	return dsi_ctx.accum_err;
 728}
 729
 730static int hx8279_get_modes(struct drm_panel *panel, struct drm_connector *connector)
 731{
 732	struct hx8279 *hx = to_hx8279(panel);
 733	int i;
 734
 735	for (i = 0; i < hx->desc->num_modes; i++) {
 736		struct drm_display_mode *mode;
 737
 738		mode = drm_mode_duplicate(connector->dev, &hx->desc->mode_data[i].mode);
 739		if (!mode)
 740			return -ENOMEM;
 741
 742		drm_mode_set_name(mode);
 743
 744		mode->type |= DRM_MODE_TYPE_DRIVER;
 745		if (hx->desc->num_modes == 1)
 746			mode->type |= DRM_MODE_TYPE_PREFERRED;
 747
 748		drm_mode_probed_add(connector, mode);
 749	}
 750
 751	connector->display_info.bpc = hx->desc->mode_data[0].bpc;
 752	connector->display_info.height_mm = hx->desc->mode_data[0].mode.height_mm;
 753	connector->display_info.width_mm = hx->desc->mode_data[0].mode.width_mm;
 754
 755	return hx->desc->num_modes;
 756}
 757
 758static const struct drm_panel_funcs hx8279_panel_funcs = {
 759	.disable = hx8279_disable,
 760	.unprepare = hx8279_unprepare,
 761	.prepare = hx8279_prepare,
 762	.enable = hx8279_enable,
 763	.get_modes = hx8279_get_modes,
 764};
 765
 766static int hx8279_init_vregs(struct hx8279 *hx, struct device *dev)
 767{
 768	int ret;
 769
 770	hx->vregs[0].supply = "vdd";
 771	hx->vregs[1].supply = "iovcc";
 772	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hx->vregs),
 773				      hx->vregs);
 774	if (ret < 0)
 775		return ret;
 776
 777	ret = regulator_is_supported_voltage(hx->vregs[0].consumer,
 778					     3000000, 5000000);
 779	if (!ret)
 780		return -EINVAL;
 781
 782	ret = regulator_is_supported_voltage(hx->vregs[1].consumer,
 783					     1700000, 1900000);
 784	if (!ret)
 785		return -EINVAL;
 786
 787	return 0;
 788}
 789
 790static int hx8279_check_gmux_config(struct hx8279 *hx, struct device *dev)
 791{
 792	const struct hx8279_panel_desc *desc = hx->desc;
 793	const struct hx8279_goa_mux *gmux = desc->gmux;
 794	int i;
 795
 796	/* No gmux defined means we simply skip the GOA mux configuration */
 797	if (!gmux)
 798		return 0;
 799
 800	for (i = 0; i < ARRAY_SIZE(gmux->gout_l); i++) {
 801		if (gmux->gout_l[i] > (HX8279_GOUT_STB | HX8279_GOUT_SEL))
 802			return dev_err_probe(dev, -EINVAL,
 803					     "Invalid value found in gout_l[%d]\n", i);
 804	}
 805
 806	for (i = 0; i < ARRAY_SIZE(gmux->gout_r); i++) {
 807		if (gmux->gout_r[i] > (HX8279_GOUT_STB | HX8279_GOUT_SEL))
 808			return dev_err_probe(dev, -EINVAL,
 809					     "Invalid value found in gout_r[%d]\n", i);
 810	}
 811
 812	return 0;
 813}
 814
 815static int hx8279_check_goa_config(struct hx8279 *hx, struct device *dev)
 816{
 817	const struct hx8279_panel_desc *desc = hx->desc;
 818	bool goa_odd_valid, goa_even_valid;
 819	int i, num_zero, num_clr = 0;
 820
 821	/* Up to 4 zero values is a valid configuration. Check them all. */
 822	num_zero = 1;
 823	for (i = 0; i < ARRAY_SIZE(desc->goa_odd_timing); i++) {
 824		if (desc->goa_odd_timing[i])
 825			num_zero++;
 826	}
 827
 828	goa_odd_valid = (num_zero != ARRAY_SIZE(desc->goa_odd_timing));
 829
 830	/* Up to 3 zeroes is a valid config. Check them all. */
 831	num_zero = 1;
 832	for (i = 0; i < ARRAY_SIZE(desc->goa_even_timing); i++) {
 833		if (desc->goa_even_timing[i])
 834			num_zero++;
 835	}
 836
 837	goa_even_valid = (num_zero != ARRAY_SIZE(desc->goa_even_timing));
 838
 839	/* Programming one without the other would make no sense! */
 840	if (goa_odd_valid != goa_even_valid)
 841		return -EINVAL;
 842
 843	/* We know that both are either true or false now, check just one */
 844	if (!goa_odd_valid)
 845		hx->skip_goa_timing = true;
 846
 847	if (!desc->goa_unk_ba && !desc->goa_stv_lead_time_ck &&
 848	    !desc->goa_ckv_lead_time_ck && !desc->goa_ckv_dummy_vblank_num &&
 849	    !desc->goa_ckv_rise_precharge && !desc->goa_ckv_fall_precharge &&
 850	    !desc->goa_clr1_width_adj && !desc->goa_clr234_width_adj &&
 851	    !desc->goa_unk_e4 && !desc->goa_unk_e5) {
 852		hx->skip_goa_config = true;
 853		return 0;
 854	}
 855
 856	if ((desc->goa_stv_lead_time_ck > HX8279_P3_GOA_STV_LEAD) ||
 857	    (desc->goa_ckv_lead_time_ck > HX8279_P3_GOA_CKV_LEAD) ||
 858	    (desc->goa_ckv_dummy_vblank_num > HX8279_P3_GOA_CKV_DUMMY))
 859		return dev_err_probe(dev, -EINVAL,
 860				     "Invalid lead timings in GOA config\n");
 861
 862	/*
 863	 * Don't perform zero check for polarity and start position, as
 864	 * both pol=0 and start=0 are valid configuration values.
 865	 */
 866	for (i = 0; i < ARRAY_SIZE(desc->goa_clr_start_pos); i++) {
 867		if (desc->goa_clr_start_pos[i] < 0)
 868			continue;
 869		else if (desc->goa_clr_start_pos[i] > HX8279_P3_GOA_CLR_CFG_STARTPOS)
 870			return dev_err_probe(dev, -EINVAL,
 871					     "Invalid start position for CLR%d\n", i + 1);
 872		else
 873			num_clr++;
 874	}
 875	if (!num_clr)
 876		return -EINVAL;
 877
 878	for (i = 0; i < ARRAY_SIZE(desc->goa_clr_polarity); i++) {
 879		if (num_clr < 0)
 880			return -EINVAL;
 881
 882		if (desc->goa_clr_polarity[i] < 0)
 883			continue;
 884		else if (desc->goa_clr_polarity[i] > 1)
 885			return dev_err_probe(dev, -EINVAL,
 886					     "Invalid polarity for CLR%d\n", i + 1);
 887		else
 888			num_clr--;
 889	}
 890
 891	return 0;
 892}
 893
 894static int hx8279_check_dig_gamma(struct hx8279 *hx, struct device *dev, const u8 *component)
 895{
 896	u8 gamma_high_bits[4];
 897	u16 prev_val = 0;
 898	int i, j, k, x;
 899
 900	/*
 901	 * The gamma values are 10 bits long and shall be incremental
 902	 * to form a digital gamma correction reference curve.
 903	 *
 904	 * As for the registers format: the first 24 bytes contain each the
 905	 * lowest 8 bits for each of the gamma level references, and the last
 906	 * 6 bytes contain the high two bits of 4 registers at a time, where
 907	 * the first two bits are relative to the last register, and the last
 908	 * two are relative to the first register.
 909	 *
 910	 * Another way of saying, those are the first four LOW values:
 911	 * DGMA1_LO = 0xb1, DGMA2_LO = 0xb2, DGMA3_LO = 0xb3, DGMA4_LO = 0xb4
 912	 *
 913	 * The high values for those four are at DGMA1_4_HI = 0xc9;
 914	 * ...and DGMA1_4_HI's data contains the following bits:
 915	 * [1:0] = DGMA4_HI, [3:2] = DGMA3_HI, [5:4] = DGMA2_HI, [7:6] = DGMA1_HI
 916	 */
 917	for (i = 0; i < HX8279_PG_DGAMMA_NUM_HI_BYTES; i++) {
 918		k = HX8279_PG_DGAMMA_NUM_LO_BYTES + i;
 919		j = i * 4;
 920		x = 0;
 921
 922		gamma_high_bits[0] = FIELD_GET(HX8279_DGAMMA_DGMA1_HI, component[k]);
 923		gamma_high_bits[1] = FIELD_GET(HX8279_DGAMMA_DGMA2_HI, component[k]);
 924		gamma_high_bits[2] = FIELD_GET(HX8279_DGAMMA_DGMA3_HI, component[k]);
 925		gamma_high_bits[3] = FIELD_GET(HX8279_DGAMMA_DGMA4_HI, component[k]);
 926
 927		do {
 928			u16 cur_val = component[j] | (gamma_high_bits[x] << 8);
 929
 930			if (cur_val < prev_val)
 931				return dev_err_probe(dev, -EINVAL,
 932						     "Invalid dgamma values: %u < %u!\n",
 933						     cur_val, prev_val);
 934			prev_val = cur_val;
 935			j++;
 936			x++;
 937		} while (x < 4);
 938	}
 939
 940	return 0;
 941}
 942
 943static int hx8279_check_params(struct hx8279 *hx, struct device *dev)
 944{
 945	const struct hx8279_panel_desc *desc = hx->desc;
 946	int ret;
 947
 948	/* Voltages config validation */
 949	if (!desc->vgh_mv && !desc->vgl_mv && !desc->vgph_mv && !desc->vgnh_mv)
 950		hx->skip_voltage_config = true;
 951	else if ((desc->vgh_mv && desc->vgh_mv < HX8279_VGH_MIN_MV) ||
 952		 (desc->vgl_mv && desc->vgl_mv < HX8279_VGL_MIN_MV) ||
 953		 (desc->vgph_mv && desc->vgph_mv < HX8279_VGPNH_MIN_MV) ||
 954		 (desc->vgnh_mv && desc->vgnh_mv < HX8279_VGPNH_MIN_MV))
 955		return -EINVAL;
 956
 957	/* GOA Muxing validation */
 958	ret = hx8279_check_gmux_config(hx, dev);
 959	if (ret)
 960		return ret;
 961
 962	/* GOA Configuration validation */
 963	ret = hx8279_check_goa_config(hx, dev);
 964	if (ret)
 965		return ret;
 966
 967	/* MIPI Configuration validation */
 968	if (!desc->bta_tlpx && !desc->lhs_settle_time_by_osc25 &&
 969	    !desc->ths_settle_time && !desc->timing_unk_b8 &&
 970	    !desc->timing_unk_bc && !desc->timing_unk_d6)
 971		hx->skip_mipi_timing = true;
 972
 973	/* ENG/Gamma Configuration validation */
 974	if (desc->gamma_ctl > (HX8279_P6_GAMMA_POCGM_CTL | HX8279_P6_GAMMA_POGCMD_CTL))
 975		return -EINVAL;
 976
 977	/* Digital Gamma values validation */
 978	if (desc->dgamma) {
 979		ret = hx8279_check_dig_gamma(hx, dev, desc->dgamma->r);
 980		if (ret)
 981			return ret;
 982
 983		ret = hx8279_check_dig_gamma(hx, dev, desc->dgamma->g);
 984		if (ret)
 985			return ret;
 986
 987		ret = hx8279_check_dig_gamma(hx, dev, desc->dgamma->b);
 988		if (ret)
 989			return ret;
 990	}
 991
 992	return 0;
 993}
 994
 995static int hx8279_probe(struct mipi_dsi_device *dsi)
 996{
 997	struct device *dev = &dsi->dev;
 998	struct device_node *dsi_r;
 999	struct hx8279 *hx;
1000	int i, ret;
1001
1002	hx = devm_drm_panel_alloc(dev, struct hx8279, panel,
1003				  &hx8279_panel_funcs, DRM_MODE_CONNECTOR_DSI);
1004	if (IS_ERR(hx))
1005		return PTR_ERR(hx);
1006
1007	ret = hx8279_init_vregs(hx, dev);
1008	if (ret)
1009		return ret;
1010
1011	hx->desc = device_get_match_data(dev);
1012	if (!hx->desc)
1013		return -ENODEV;
1014
1015	/*
1016	 * In some DriverICs some or all fields may be OTP: perform a
1017	 * basic configuration check before writing to help avoiding
1018	 * irreparable mistakes.
1019	 *
1020	 * Please note that this is not perfect and will only check if
1021	 * the values may be plausible; values that are wrong for a
1022	 * specific display, but still plausible for DrIC config will
1023	 * be accepted.
1024	 */
1025	ret = hx8279_check_params(hx, dev);
1026	if (ret)
1027		return dev_err_probe(dev, ret, "Invalid DriverIC configuration\n");
1028
1029	/* The enable line may be always tied to VCCIO, so this is optional */
1030	hx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS);
1031	if (IS_ERR(hx->enable_gpio))
1032		return dev_err_probe(dev, PTR_ERR(hx->enable_gpio),
1033				     "Failed to get enable GPIO\n");
1034
1035	hx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
1036	if (IS_ERR(hx->reset_gpio))
1037		return dev_err_probe(dev, PTR_ERR(hx->reset_gpio),
1038				     "Failed to get reset GPIO\n");
1039
1040	/* If the panel is connected on two DSIs then DSI0 left, DSI1 right */
1041	dsi_r = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
1042	if (dsi_r) {
1043		const struct mipi_dsi_device_info *info = &hx->desc->dsi_info;
1044		struct mipi_dsi_host *dsi_r_host;
1045
1046		dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r);
1047		of_node_put(dsi_r);
1048		if (!dsi_r_host)
1049			return dev_err_probe(dev, -EPROBE_DEFER,
1050					     "Cannot get secondary DSI host\n");
1051
1052		hx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi_r_host, info);
1053		if (IS_ERR(hx->dsi[1]))
1054			return dev_err_probe(dev, PTR_ERR(hx->dsi[1]),
1055					     "Cannot get secondary DSI node\n");
1056		mipi_dsi_set_drvdata(hx->dsi[1], hx);
1057	}
1058
1059	hx->dsi[0] = dsi;
1060	mipi_dsi_set_drvdata(dsi, hx);
1061
1062	ret = drm_panel_of_backlight(&hx->panel);
1063	if (ret)
1064		return dev_err_probe(dev, ret, "Failed to get backlight\n");
1065
1066	drm_panel_add(&hx->panel);
1067
1068	for (i = 0; i < 2; i++) {
1069		if (!hx->dsi[i])
1070			continue;
1071
1072		hx->dsi[i]->lanes = hx->desc->num_lanes;
1073		hx->dsi[i]->format = MIPI_DSI_FMT_RGB888;
1074
1075		hx->dsi[i]->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
1076					 MIPI_DSI_MODE_LPM;
1077
1078		if (hx->desc->mode_data[0].is_video_mode)
1079			hx->dsi[i]->mode_flags |= MIPI_DSI_MODE_VIDEO |
1080						  MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
1081
1082		ret = devm_mipi_dsi_attach(dev, hx->dsi[i]);
1083		if (ret < 0) {
1084			drm_panel_remove(&hx->panel);
1085			return dev_err_probe(dev, ret,
1086					     "Cannot attach to DSI%d host.\n", i);
1087		}
1088	}
1089
1090	return 0;
1091}
1092
1093static void hx8279_remove(struct mipi_dsi_device *dsi)
1094{
1095	struct hx8279 *hx = mipi_dsi_get_drvdata(dsi);
1096
1097	drm_panel_remove(&hx->panel);
1098}
1099
1100static const struct hx8279_panel_mode aoly_sl101pm1794fog_v15_modes[] = {
1101	{
1102		.mode = {
1103			.clock = 159420,
1104			.hdisplay = 1200,
1105			.hsync_start = 1200 + 80,
1106			.hsync_end = 1200 + 80 + 60,
1107			.htotal = 1200 + 80 + 60 + 24,
1108			.vdisplay = 1920,
1109			.vsync_start = 1920 + 10,
1110			.vsync_end = 1920 + 10 + 14,
1111			.vtotal = 1920 + 10 + 14 + 4,
1112			.width_mm = 136,
1113			.height_mm = 217,
1114			.type = DRM_MODE_TYPE_DRIVER
1115		},
1116		.bpc = 8,
1117		.is_video_mode = true,
1118	},
1119};
1120
1121static const struct hx8279_panel_mode startek_kd070fhfid078_modes[] = {
1122	{
1123		.mode = {
1124			.clock = 156458,
1125			.hdisplay = 1200,
1126			.hsync_start = 1200 + 50,
1127			.hsync_end = 1200 + 50 + 24,
1128			.htotal = 1200 + 50 + 24 + 66,
1129			.vdisplay = 1920,
1130			.vsync_start = 1920 + 14,
1131			.vsync_end = 1920 + 14 + 2,
1132			.vtotal = 1920 + 14 + 2 + 10,
1133			.width_mm = 95,
1134			.height_mm = 151,
1135			.type = DRM_MODE_TYPE_DRIVER
1136		},
1137		.bpc = 8,
1138		.is_video_mode = true,
1139	},
1140};
1141
1142static const struct hx8279_goa_mux aoly_sl101pm1794fog_v15_gmux = {
1143	.gout_l = { 0x5, 0x5, 0xb, 0xb, 0x9, 0x9, 0x16, 0x16, 0xe, 0xe,
1144		    0x7, 0x7, 0x26, 0x26, 0x15, 0x15, 0x1, 0x1, 0x3, 0x3 },
1145	.gout_r = { 0x6, 0x6, 0xc, 0xc, 0xa, 0xa, 0x16, 0x16, 0xe, 0xe,
1146		    0x8, 0x8, 0x26, 0x26, 0x15, 0x15, 0x2, 0x2, 0x4, 0x4 },
1147};
1148
1149static const struct hx8279_analog_gamma aoly_sl101pm1794fog_v15_ana_gamma = {
1150	.pos = { 0x0, 0xd, 0x17, 0x26, 0x31, 0x1c, 0x2c, 0x33, 0x31,
1151		 0x37, 0x37, 0x37, 0x39, 0x2e, 0x2f, 0x2f, 0x7 },
1152	.neg = { 0x0, 0xd, 0x17, 0x26, 0x31, 0x3f, 0x3f, 0x3f, 0x3f,
1153		 0x37, 0x37, 0x37, 0x39, 0x2e, 0x2f, 0x2f, 0x7 },
1154};
1155
1156static const struct hx8279_digital_gamma aoly_sl101pm1794fog_v15_dig_gamma = {
1157	.r = { 0x0, 0x5, 0x10, 0x22, 0x36, 0x4a, 0x6c, 0x9a, 0xd7, 0x17,
1158	       0x92, 0x15, 0x18, 0x8c, 0x0, 0x3a, 0x72, 0x8c, 0xa5, 0xb1,
1159	       0xbe, 0xca, 0xd1, 0xd4, 0x0, 0x0, 0x16, 0xaf, 0xff, 0xff },
1160	.g = { 0x4, 0x5, 0x11, 0x24, 0x39, 0x4e, 0x72, 0xa3, 0xe1, 0x25,
1161	       0xa8, 0x2e, 0x32, 0xad, 0x28, 0x63, 0x9b, 0xb5, 0xcf, 0xdb,
1162	       0xe8, 0xf5, 0xfa, 0xfc, 0x0, 0x0, 0x16, 0xaf, 0xff, 0xff },
1163	.b = { 0x4, 0x4, 0xf, 0x22, 0x37, 0x4d, 0x71, 0xa2, 0xe1, 0x26,
1164	       0xa9, 0x2f, 0x33, 0xac, 0x24, 0x5d, 0x94, 0xac, 0xc5, 0xd1,
1165	       0xdc, 0xe8, 0xed, 0xf0, 0x0, 0x0, 0x16, 0xaf, 0xff, 0xff },
1166};
1167
1168static const struct hx8279_panel_desc aoly_sl101pm1794fog_v15 = {
1169	.dsi_info = {
1170		.type = "L101PM1794FOG-V15",
1171		.channel = 0,
1172		.node = NULL,
1173	},
1174	.mode_data = aoly_sl101pm1794fog_v15_modes,
1175	.num_modes = ARRAY_SIZE(aoly_sl101pm1794fog_v15_modes),
1176	.num_lanes = 4,
1177
1178	/* Driver/Module Configuration: LC Matrix voltages */
1179	.vgh_mv = 16500,
1180	.vgl_mv = 11200,
1181	.vgph_mv = 4600,
1182	.vgnh_mv = 4600,
1183
1184	/* Analog Gamma correction */
1185	.agamma = &aoly_sl101pm1794fog_v15_ana_gamma,
1186
1187	/* Gate driver On Array (GOA) Muxing */
1188	.gmux = &aoly_sl101pm1794fog_v15_gmux,
1189
1190	/* Gate driver On Array (GOA) Mux Config */
1191	.goa_unk_ba = 0xf0,
1192	.goa_odd_timing = { 0, 0, 0, 42, 0, 0 },
1193	.goa_even_timing = { 1, 42, 0, 0 },
1194	.goa_stv_lead_time_ck = 11,
1195	.goa_ckv_lead_time_ck = 7,
1196	.goa_ckv_dummy_vblank_num = 3,
1197	.goa_ckv_rise_precharge = 1,
1198	.goa_clr1_width_adj = 0,
1199	.goa_clr234_width_adj = 0,
1200	.goa_clr_polarity = { 1, 0, 0, 0 },
1201	.goa_clr_start_pos = { 8, 9, 3, 4 },
1202	.goa_unk_e4 = 0xc0,
1203	.goa_unk_e5 = 0x0d,
1204
1205	/* MIPI Configuration */
1206	.bta_tlpx = 2,
1207	.lhs_settle_time_by_osc25 = true,
1208	.ths_settle_time = 2,
1209	.timing_unk_b8 = 0xa5,
1210	.timing_unk_bc = 0x20,
1211	.timing_unk_d6 = 0x7f,
1212
1213	/* ENG/Gamma Configuration */
1214	.gamma_ctl = 0,
1215	.volt_adj = FIELD_PREP_CONST(HX8279_P6_VOLT_ADJ_VCCIFS, 3) |
1216		    FIELD_PREP_CONST(HX8279_P6_VOLT_ADJ_VCCS, 3),
1217	.src_delay_time_adj_ck = 50,
1218
1219	/* Digital Gamma Adjustment */
1220	.dgamma = &aoly_sl101pm1794fog_v15_dig_gamma,
1221};
1222
1223static const struct hx8279_goa_mux startek_kd070fhfid078_gmux = {
1224	.gout_l = { 0xd, 0xd, 0x6, 0x6, 0x8, 0x8, 0xa, 0xa, 0xc, 0xc,
1225		    0x0, 0x0, 0xe, 0xe, 0x1, 0x1, 0x4, 0x4, 0x0, 0x0 },
1226	.gout_r = { 0xd, 0xd, 0x5, 0x5, 0x7, 0x7, 0x9, 0x9, 0xb, 0xb,
1227		    0x0, 0x0, 0xe, 0xe, 0x1, 0x1, 0x3, 0x3, 0x0, 0x0 },
1228};
1229
1230static const struct hx8279_panel_desc startek_kd070fhfid078 = {
1231	.dsi_info = {
1232		.type = "KD070FHFID078",
1233		.channel = 0,
1234		.node = NULL,
1235	},
1236	.mode_data = startek_kd070fhfid078_modes,
1237	.num_modes = ARRAY_SIZE(startek_kd070fhfid078_modes),
1238	.num_lanes = 4,
1239
1240	/* Driver/Module Configuration: LC Matrix voltages */
1241	.vgh_mv = 18000,
1242	.vgl_mv = 12100,
1243	.vgph_mv = 5500,
1244	.vgnh_mv = 5500,
1245
1246	/* Gate driver On Array (GOA) Mux Config */
1247	.gmux = &startek_kd070fhfid078_gmux,
1248
1249	/* Gate driver On Array (GOA) Configuration */
1250	.goa_unk_ba = 0xf0,
1251	.goa_stv_lead_time_ck = 7,
1252	.goa_ckv_lead_time_ck = 3,
1253	.goa_ckv_dummy_vblank_num = 1,
1254	.goa_ckv_rise_precharge = 0,
1255	.goa_ckv_fall_precharge = 0,
1256	.goa_clr1_width_adj = 1,
1257	.goa_clr234_width_adj = 5,
1258	.goa_clr_polarity = { 0, 1, -1, -1 },
1259	.goa_clr_start_pos = { 5, 10, -1, -1 },
1260	.goa_unk_e4 = 0xc0,
1261	.goa_unk_e5 = 0x00,
1262
1263	/* MIPI Configuration */
1264	.bta_tlpx = 2,
1265	.lhs_settle_time_by_osc25 = true,
1266	.ths_settle_time = 2,
1267	.timing_unk_b8 = 0x7f,
1268	.timing_unk_bc = 0x20,
1269	.timing_unk_d6 = 0x7f,
1270
1271	/* ENG/Gamma Configuration */
1272	.gamma_ctl = FIELD_PREP_CONST(HX8279_P6_GAMMA_POCGM_CTL, 1) |
1273		     FIELD_PREP_CONST(HX8279_P6_GAMMA_POGCMD_CTL, 1),
1274	.src_delay_time_adj_ck = 72,
1275};
1276
1277static const struct of_device_id hx8279_of_match[] = {
1278	{ .compatible = "aoly,sl101pm1794fog-v15", .data = &aoly_sl101pm1794fog_v15 },
1279	{ .compatible = "startek,kd070fhfid078", .data = &startek_kd070fhfid078 },
1280	{ /* sentinel */ }
1281};
1282MODULE_DEVICE_TABLE(of, hx8279_of_match);
1283
1284static struct mipi_dsi_driver hx8279_driver = {
1285	.probe = hx8279_probe,
1286	.remove = hx8279_remove,
1287	.driver = {
1288		.name = "panel-himax-hx8279",
1289		.of_match_table = hx8279_of_match,
1290	},
1291};
1292module_mipi_dsi_driver(hx8279_driver);
1293
1294MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
1295MODULE_DESCRIPTION("Himax HX8279 DriverIC panels driver");
1296MODULE_LICENSE("GPL");
~/ Read-only file preview.