diff options
| author | Philipp Zabel <p.zabel@pengutronix.de> | 2014-12-02 14:22:49 -0500 |
|---|---|---|
| committer | Philipp Zabel <p.zabel@pengutronix.de> | 2015-03-31 06:44:50 -0400 |
| commit | 5e501ed7253b369a8a9ec553c35238a3d6808f28 (patch) | |
| tree | 06e52297f21c7c9c54e7c8ac0efd85aac6bc27f1 /drivers | |
| parent | 3973aff06585309f6215c66ed9d11d74656a9fa6 (diff) | |
drm/imx: imx-ldb: allow to determine bus format from the connected panel
This patch makes the fsl,data-width and fsl,data-mapping device tree
properties optional if a panel is connected to the ldb output port
via the of_graph bindings. The data mapping is determined from the
display_info.bus_format field provided by the panel.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 116 |
1 files changed, 63 insertions, 53 deletions
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 544282bd4f7f..abacc8f67469 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c | |||
| @@ -63,6 +63,7 @@ struct imx_ldb_channel { | |||
| 63 | int edid_len; | 63 | int edid_len; |
| 64 | struct drm_display_mode mode; | 64 | struct drm_display_mode mode; |
| 65 | int mode_valid; | 65 | int mode_valid; |
| 66 | int bus_format; | ||
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | struct bus_mux { | 69 | struct bus_mux { |
| @@ -96,7 +97,11 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) | |||
| 96 | 97 | ||
| 97 | if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && | 98 | if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && |
| 98 | imx_ldb_ch->panel->funcs->get_modes) { | 99 | imx_ldb_ch->panel->funcs->get_modes) { |
| 100 | struct drm_display_info *di = &connector->display_info; | ||
| 101 | |||
| 99 | num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); | 102 | num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); |
| 103 | if (!imx_ldb_ch->bus_format && di->num_bus_formats) | ||
| 104 | imx_ldb_ch->bus_format = di->bus_formats[0]; | ||
| 100 | if (num_modes > 0) | 105 | if (num_modes > 0) |
| 101 | return num_modes; | 106 | return num_modes; |
| 102 | } | 107 | } |
| @@ -173,21 +178,33 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) | |||
| 173 | { | 178 | { |
| 174 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); | 179 | struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); |
| 175 | struct imx_ldb *ldb = imx_ldb_ch->ldb; | 180 | struct imx_ldb *ldb = imx_ldb_ch->ldb; |
| 181 | int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; | ||
| 176 | u32 bus_format; | 182 | u32 bus_format; |
| 177 | 183 | ||
| 178 | switch (imx_ldb_ch->chno) { | 184 | switch (imx_ldb_ch->bus_format) { |
| 179 | case 0: | 185 | default: |
| 180 | bus_format = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ? | 186 | dev_warn(ldb->dev, |
| 181 | MEDIA_BUS_FMT_RGB888_1X24 : MEDIA_BUS_FMT_RGB666_1X18; | 187 | "could not determine data mapping, default to 18-bit \"spwg\"\n"); |
| 188 | /* fallthrough */ | ||
| 189 | case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: | ||
| 190 | bus_format = MEDIA_BUS_FMT_RGB666_1X18; | ||
| 182 | break; | 191 | break; |
| 183 | case 1: | 192 | case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: |
| 184 | bus_format = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ? | 193 | bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
| 185 | MEDIA_BUS_FMT_RGB888_1X24 : MEDIA_BUS_FMT_RGB666_1X18; | 194 | if (imx_ldb_ch->chno == 0 || dual) |
| 195 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; | ||
| 196 | if (imx_ldb_ch->chno == 1 || dual) | ||
| 197 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; | ||
| 186 | break; | 198 | break; |
| 187 | default: | 199 | case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: |
| 188 | dev_err(ldb->dev, "unable to config di%d panel format\n", | ||
| 189 | imx_ldb_ch->chno); | ||
| 190 | bus_format = MEDIA_BUS_FMT_RGB888_1X24; | 200 | bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
| 201 | if (imx_ldb_ch->chno == 0 || dual) | ||
| 202 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | | ||
| 203 | LDB_BIT_MAP_CH0_JEIDA; | ||
| 204 | if (imx_ldb_ch->chno == 1 || dual) | ||
| 205 | ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | | ||
| 206 | LDB_BIT_MAP_CH1_JEIDA; | ||
| 207 | break; | ||
| 191 | } | 208 | } |
| 192 | 209 | ||
| 193 | imx_drm_set_bus_format(encoder, bus_format); | 210 | imx_drm_set_bus_format(encoder, bus_format); |
| @@ -426,25 +443,39 @@ enum { | |||
| 426 | LVDS_BIT_MAP_JEIDA | 443 | LVDS_BIT_MAP_JEIDA |
| 427 | }; | 444 | }; |
| 428 | 445 | ||
| 429 | static const char * const imx_ldb_bit_mappings[] = { | 446 | struct imx_ldb_bit_mapping { |
| 430 | [LVDS_BIT_MAP_SPWG] = "spwg", | 447 | u32 bus_format; |
| 431 | [LVDS_BIT_MAP_JEIDA] = "jeida", | 448 | u32 datawidth; |
| 449 | const char * const mapping; | ||
| 432 | }; | 450 | }; |
| 433 | 451 | ||
| 434 | static const int of_get_data_mapping(struct device_node *np) | 452 | static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = { |
| 453 | { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, "spwg" }, | ||
| 454 | { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, "spwg" }, | ||
| 455 | { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" }, | ||
| 456 | }; | ||
| 457 | |||
| 458 | static u32 of_get_bus_format(struct device *dev, struct device_node *np) | ||
| 435 | { | 459 | { |
| 436 | const char *bm; | 460 | const char *bm; |
| 461 | u32 datawidth = 0; | ||
| 437 | int ret, i; | 462 | int ret, i; |
| 438 | 463 | ||
| 439 | ret = of_property_read_string(np, "fsl,data-mapping", &bm); | 464 | ret = of_property_read_string(np, "fsl,data-mapping", &bm); |
| 440 | if (ret < 0) | 465 | if (ret < 0) |
| 441 | return ret; | 466 | return ret; |
| 442 | 467 | ||
| 443 | for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) | 468 | of_property_read_u32(np, "fsl,data-width", &datawidth); |
| 444 | if (!strcasecmp(bm, imx_ldb_bit_mappings[i])) | 469 | |
| 445 | return i; | 470 | for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) { |
| 471 | if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) && | ||
| 472 | datawidth == imx_ldb_bit_mappings[i].datawidth) | ||
| 473 | return imx_ldb_bit_mappings[i].bus_format; | ||
| 474 | } | ||
| 475 | |||
| 476 | dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm); | ||
| 446 | 477 | ||
| 447 | return -EINVAL; | 478 | return -ENOENT; |
| 448 | } | 479 | } |
| 449 | 480 | ||
| 450 | static struct bus_mux imx6q_lvds_mux[2] = { | 481 | static struct bus_mux imx6q_lvds_mux[2] = { |
| @@ -481,8 +512,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
| 481 | struct device_node *child; | 512 | struct device_node *child; |
| 482 | const u8 *edidp; | 513 | const u8 *edidp; |
| 483 | struct imx_ldb *imx_ldb; | 514 | struct imx_ldb *imx_ldb; |
| 484 | int datawidth; | ||
| 485 | int mapping; | ||
| 486 | int dual; | 515 | int dual; |
| 487 | int ret; | 516 | int ret; |
| 488 | int i; | 517 | int i; |
| @@ -583,39 +612,20 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) | |||
| 583 | channel->mode_valid = 1; | 612 | channel->mode_valid = 1; |
| 584 | } | 613 | } |
| 585 | 614 | ||
| 586 | ret = of_property_read_u32(child, "fsl,data-width", &datawidth); | 615 | channel->bus_format = of_get_bus_format(dev, child); |
| 587 | if (ret) | 616 | if (channel->bus_format == -EINVAL) { |
| 588 | datawidth = 0; | 617 | /* |
| 589 | else if (datawidth != 18 && datawidth != 24) | 618 | * If no bus format was specified in the device tree, |
| 590 | return -EINVAL; | 619 | * we can still get it from the connected panel later. |
| 591 | 620 | */ | |
| 592 | mapping = of_get_data_mapping(child); | 621 | if (channel->panel && channel->panel->funcs && |
| 593 | switch (mapping) { | 622 | channel->panel->funcs->get_modes) |
| 594 | case LVDS_BIT_MAP_SPWG: | 623 | channel->bus_format = 0; |
| 595 | if (datawidth == 24) { | 624 | } |
| 596 | if (i == 0 || dual) | 625 | if (channel->bus_format < 0) { |
| 597 | imx_ldb->ldb_ctrl |= | 626 | dev_err(dev, "could not determine data mapping: %d\n", |
| 598 | LDB_DATA_WIDTH_CH0_24; | 627 | channel->bus_format); |
| 599 | if (i == 1 || dual) | 628 | return channel->bus_format; |
| 600 | imx_ldb->ldb_ctrl |= | ||
| 601 | LDB_DATA_WIDTH_CH1_24; | ||
| 602 | } | ||
| 603 | break; | ||
| 604 | case LVDS_BIT_MAP_JEIDA: | ||
| 605 | if (datawidth == 18) { | ||
| 606 | dev_err(dev, "JEIDA standard only supported in 24 bit\n"); | ||
| 607 | return -EINVAL; | ||
| 608 | } | ||
| 609 | if (i == 0 || dual) | ||
| 610 | imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | | ||
| 611 | LDB_BIT_MAP_CH0_JEIDA; | ||
| 612 | if (i == 1 || dual) | ||
| 613 | imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | | ||
| 614 | LDB_BIT_MAP_CH1_JEIDA; | ||
| 615 | break; | ||
| 616 | default: | ||
| 617 | dev_err(dev, "data mapping not specified or invalid\n"); | ||
| 618 | return -EINVAL; | ||
| 619 | } | 629 | } |
| 620 | 630 | ||
| 621 | ret = imx_ldb_register(drm, channel); | 631 | ret = imx_ldb_register(drm, channel); |
