/** * struct hx8279_goa_mux - Gate driver On Array Muxer * @gout_l: Mux GOA signal to GOUT Left pin * @gout_r: Mux GOA signal to GOUT Right pin
*/ struct hx8279_goa_mux {
u8 gout_l[20];
u8 gout_r[20];
};
/** * struct hx8279_analog_gamma - Analog Gamma Adjustment * @pos: Positive gamma op's input voltage, adjusted by VGP(H/L) * @neg: Negative gamma op's input voltage, adjusted by VGN(H/L) * * Analog Gamma correction is performed with 17+17 reference voltages, * changed with resistor streams, and defined with 17 register values * for positive and 17 for negative. * * Each register holds resistance values, in 8.5ohms per unit, for the * following gamma levels: * 0, 8, 16, 28, 40, 56, 80, 128, 176, 200, 216, 228, 240, 248, 252, 255.
*/ struct hx8279_analog_gamma {
u8 pos[17];
u8 neg[17];
};
/** * struct hx8279_digital_gamma - Digital Gamma Adjustment * @r: Adjustment for red component * @g: Adjustment for green component * @b: Adjustment for blue component * * The layout of this structure follows the register layout to simplify * both the handling and the declaration of those values in the driver. * Gamma correction is internally done with a 24 segment piecewise * linear interpolation; those segments are defined with 24 ten bits * values of which: * - The LOW eight bits for the first 24 registers start at the first * register (at 0xb1) of the Digital Gamma Adjustment page; * - The HIGH two bits for each of the 24 registers are contained * in the last six registers; * - The last six registers contain four groups of two-bits HI values * for each of the first 24 registers, but in an inverted fashion, * this means that the first two bits relate to the last register * of a set of four. * * The 24 segments refer to the following gamma levels: * 0, 1, 3, 7, 11, 15, 23, 31, 47, 63, 95, 127, 128, 160, * 192, 208, 224, 232, 240, 244, 248, 252, 254, 255
*/ struct hx8279_digital_gamma {
u8 r[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES];
u8 g[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES];
u8 b[HX8279_PG_DGAMMA_NUM_LO_BYTES + HX8279_PG_DGAMMA_NUM_HI_BYTES];
};
if (desc->goa_ckv_dummy_vblank_num) {
cmd_set_goa[0] = HX8279_P3_REG_GOA_CKVD;
cmd_set_goa[1] = FIELD_PREP(HX8279_P3_GOA_CKV_LEAD,
desc->goa_ckv_dummy_vblank_num);
cmd_set_goa[1] |= FIELD_PREP(HX8279_P3_GOA_CKV_NONOVERLAP,
desc->goa_ckv_non_overlap_ctl); /* RESERVED must be always set */
cmd_set_goa[1] |= HX8279_P3_GOA_CKV_RESERVED;
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
ARRAY_SIZE(cmd_set_goa));
}
/* * One of the two being more than zero means that we want to write * both of them. Anyway, the register default is zero in this case.
*/ if (desc->goa_ckv_rise_precharge || desc->goa_ckv_fall_precharge) {
cmd_set_goa[0] = HX8279_P3_REG_GOA_CKV_RISE_PREC;
cmd_set_goa[1] = desc->goa_ckv_rise_precharge;
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_goa,
ARRAY_SIZE(cmd_set_goa));
/* Polarity and Start Position arrays are of the same size */ for (i = 0; i < ARRAY_SIZE(desc->goa_clr_polarity); i++) { if (desc->goa_clr_polarity[i] < 0 || desc->goa_clr_start_pos[i] < 0) continue;
if (!desc->gamma_ctl && !desc->src_delay_time_adj_ck && !desc->volt_adj) return;
hx8279_set_page(hx, dsi_ctx, 6);
/* Unlock ENG settings: write same word to both ENGINEER_PWD and INHOUSE_FUNC */
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng));
/* Set Gamma Chopper and Gamma buffer Chopper control */
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_gamma, ARRAY_SIZE(cmd_set_gamma));
/* Set Source delay time adjustment (CKV falling to Source off) */ if (desc->src_delay_time_adj_ck)
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dly,
ARRAY_SIZE(cmd_set_dly));
/* Set voltage adjustment */ if (desc->volt_adj)
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_volt_adj,
ARRAY_SIZE(cmd_set_volt_adj));
/* Lock ENG settings again */
cmd_set_eng[0] = HX8279_P6_REG_ENGINEER_PWD;
cmd_set_eng[1] = 0;
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_eng, ARRAY_SIZE(cmd_set_eng));
/* * Pages 7..9 are for RGB Positive, 10..12 are for RGB Negative: * The first iteration sets all positive component registers, * the second one sets all negatives.
*/ for (i = 0; i < 2; i++) {
u8 pg_neg = i * 3;
hx8279_set_page(hx, dsi_ctx, 7 + pg_neg);
for (i = 0; i < ARRAY_SIZE(dgamma->r); i++) {
cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i;
cmd_set_dig_gamma[1] = dgamma->r[i];
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma,
ARRAY_SIZE(cmd_set_dig_gamma));
}
hx8279_set_page(hx, dsi_ctx, 8 + pg_neg);
for (i = 0; i < ARRAY_SIZE(dgamma->g); i++) {
cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i;
cmd_set_dig_gamma[1] = dgamma->g[i];
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma,
ARRAY_SIZE(cmd_set_dig_gamma));
}
hx8279_set_page(hx, dsi_ctx, 9 + pg_neg);
for (i = 0; i < ARRAY_SIZE(dgamma->b); i++) {
cmd_set_dig_gamma[0] = HX8279_PG_DIGITAL_GAMMA + i;
cmd_set_dig_gamma[1] = dgamma->b[i];
mipi_dsi_generic_write_multi(dsi_ctx, cmd_set_dig_gamma,
ARRAY_SIZE(cmd_set_dig_gamma));
}
}
}
/* No gmux defined means we simply skip the GOA mux configuration */ if (!gmux) return 0;
for (i = 0; i < ARRAY_SIZE(gmux->gout_l); i++) { if (gmux->gout_l[i] > (HX8279_GOUT_STB | HX8279_GOUT_SEL)) return dev_err_probe(dev, -EINVAL, "Invalid value found in gout_l[%d]\n", i);
}
for (i = 0; i < ARRAY_SIZE(gmux->gout_r); i++) { if (gmux->gout_r[i] > (HX8279_GOUT_STB | HX8279_GOUT_SEL)) return dev_err_probe(dev, -EINVAL, "Invalid value found in gout_r[%d]\n", i);
}
/* Up to 4 zero values is a valid configuration. Check them all. */
num_zero = 1; for (i = 0; i < ARRAY_SIZE(desc->goa_odd_timing); i++) { if (desc->goa_odd_timing[i])
num_zero++;
}
/* Up to 3 zeroes is a valid config. Check them all. */
num_zero = 1; for (i = 0; i < ARRAY_SIZE(desc->goa_even_timing); i++) { if (desc->goa_even_timing[i])
num_zero++;
}
if ((desc->goa_stv_lead_time_ck > HX8279_P3_GOA_STV_LEAD) ||
(desc->goa_ckv_lead_time_ck > HX8279_P3_GOA_CKV_LEAD) ||
(desc->goa_ckv_dummy_vblank_num > HX8279_P3_GOA_CKV_DUMMY)) return dev_err_probe(dev, -EINVAL, "Invalid lead timings in GOA config\n");
/* * Don't perform zero check for polarity and start position, as * both pol=0 and start=0 are valid configuration values.
*/ for (i = 0; i < ARRAY_SIZE(desc->goa_clr_start_pos); i++) { if (desc->goa_clr_start_pos[i] < 0) continue; elseif (desc->goa_clr_start_pos[i] > HX8279_P3_GOA_CLR_CFG_STARTPOS) return dev_err_probe(dev, -EINVAL, "Invalid start position for CLR%d\n", i + 1); else
num_clr++;
} if (!num_clr) return -EINVAL;
for (i = 0; i < ARRAY_SIZE(desc->goa_clr_polarity); i++) { if (num_clr < 0) return -EINVAL;
if (desc->goa_clr_polarity[i] < 0) continue; elseif (desc->goa_clr_polarity[i] > 1) return dev_err_probe(dev, -EINVAL, "Invalid polarity for CLR%d\n", i + 1); else
num_clr--;
}
/* * The gamma values are 10 bits long and shall be incremental * to form a digital gamma correction reference curve. * * As for the registers format: the first 24 bytes contain each the * lowest 8 bits for each of the gamma level references, and the last * 6 bytes contain the high two bits of 4 registers at a time, where * the first two bits are relative to the last register, and the last * two are relative to the first register. * * Another way of saying, those are the first four LOW values: * DGMA1_LO = 0xb1, DGMA2_LO = 0xb2, DGMA3_LO = 0xb3, DGMA4_LO = 0xb4 * * The high values for those four are at DGMA1_4_HI = 0xc9; * ...and DGMA1_4_HI's data contains the following bits: * [1:0] = DGMA4_HI, [3:2] = DGMA3_HI, [5:4] = DGMA2_HI, [7:6] = DGMA1_HI
*/ for (i = 0; i < HX8279_PG_DGAMMA_NUM_HI_BYTES; i++) {
k = HX8279_PG_DGAMMA_NUM_LO_BYTES + i;
j = i * 4;
x = 0;
ret = hx8279_init_vregs(hx, dev); if (ret) return ret;
hx->desc = device_get_match_data(dev); if (!hx->desc) return -ENODEV;
/* * In some DriverICs some or all fields may be OTP: perform a * basic configuration check before writing to help avoiding * irreparable mistakes. * * Please note that this is not perfect and will only check if * the values may be plausible; values that are wrong for a * specific display, but still plausible for DrIC config will * be accepted.
*/
ret = hx8279_check_params(hx, dev); if (ret) return dev_err_probe(dev, ret, "Invalid DriverIC configuration\n");
/* The enable line may be always tied to VCCIO, so this is optional */
hx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS); if (IS_ERR(hx->enable_gpio)) return dev_err_probe(dev, PTR_ERR(hx->enable_gpio), "Failed to get enable GPIO\n");
hx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); if (IS_ERR(hx->reset_gpio)) return dev_err_probe(dev, PTR_ERR(hx->reset_gpio), "Failed to get reset GPIO\n");
/* If the panel is connected on two DSIs then DSI0 left, DSI1 right */
dsi_r = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); if (dsi_r) { conststruct mipi_dsi_device_info *info = &hx->desc->dsi_info; struct mipi_dsi_host *dsi_r_host;
dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r);
of_node_put(dsi_r); if (!dsi_r_host) return dev_err_probe(dev, -EPROBE_DEFER, "Cannot get secondary DSI host\n");
hx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi_r_host, info); if (IS_ERR(hx->dsi[1])) return dev_err_probe(dev, PTR_ERR(hx->dsi[1]), "Cannot get secondary DSI node\n");
mipi_dsi_set_drvdata(hx->dsi[1], hx);
}
hx->dsi[0] = dsi;
mipi_dsi_set_drvdata(dsi, hx);
ret = drm_panel_of_backlight(&hx->panel); if (ret) return dev_err_probe(dev, ret, "Failed to get backlight\n");
drm_panel_add(&hx->panel);
for (i = 0; i < 2; i++) { if (!hx->dsi[i]) continue;
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
MODULE_DESCRIPTION("Himax HX8279 DriverIC panels driver");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.