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>
This commit is contained in:
parent
3973aff065
commit
5e501ed725
@ -63,6 +63,7 @@ struct imx_ldb_channel {
|
|||||||
int edid_len;
|
int edid_len;
|
||||||
struct drm_display_mode mode;
|
struct drm_display_mode mode;
|
||||||
int mode_valid;
|
int mode_valid;
|
||||||
|
int bus_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bus_mux {
|
struct bus_mux {
|
||||||
@ -96,7 +97,11 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
|
|||||||
|
|
||||||
if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs &&
|
if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs &&
|
||||||
imx_ldb_ch->panel->funcs->get_modes) {
|
imx_ldb_ch->panel->funcs->get_modes) {
|
||||||
|
struct drm_display_info *di = &connector->display_info;
|
||||||
|
|
||||||
num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
|
num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
|
||||||
|
if (!imx_ldb_ch->bus_format && di->num_bus_formats)
|
||||||
|
imx_ldb_ch->bus_format = di->bus_formats[0];
|
||||||
if (num_modes > 0)
|
if (num_modes > 0)
|
||||||
return num_modes;
|
return num_modes;
|
||||||
}
|
}
|
||||||
@ -173,21 +178,33 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
|
|||||||
{
|
{
|
||||||
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
|
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
|
||||||
struct imx_ldb *ldb = imx_ldb_ch->ldb;
|
struct imx_ldb *ldb = imx_ldb_ch->ldb;
|
||||||
|
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
|
||||||
u32 bus_format;
|
u32 bus_format;
|
||||||
|
|
||||||
switch (imx_ldb_ch->chno) {
|
switch (imx_ldb_ch->bus_format) {
|
||||||
case 0:
|
|
||||||
bus_format = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ?
|
|
||||||
MEDIA_BUS_FMT_RGB888_1X24 : MEDIA_BUS_FMT_RGB666_1X18;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
bus_format = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ?
|
|
||||||
MEDIA_BUS_FMT_RGB888_1X24 : MEDIA_BUS_FMT_RGB666_1X18;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
dev_err(ldb->dev, "unable to config di%d panel format\n",
|
dev_warn(ldb->dev,
|
||||||
imx_ldb_ch->chno);
|
"could not determine data mapping, default to 18-bit \"spwg\"\n");
|
||||||
|
/* fallthrough */
|
||||||
|
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
|
||||||
|
bus_format = MEDIA_BUS_FMT_RGB666_1X18;
|
||||||
|
break;
|
||||||
|
case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
|
||||||
bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||||
|
if (imx_ldb_ch->chno == 0 || dual)
|
||||||
|
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
|
||||||
|
if (imx_ldb_ch->chno == 1 || dual)
|
||||||
|
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
|
||||||
|
break;
|
||||||
|
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
|
||||||
|
bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||||
|
if (imx_ldb_ch->chno == 0 || dual)
|
||||||
|
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
|
||||||
|
LDB_BIT_MAP_CH0_JEIDA;
|
||||||
|
if (imx_ldb_ch->chno == 1 || dual)
|
||||||
|
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
|
||||||
|
LDB_BIT_MAP_CH1_JEIDA;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
imx_drm_set_bus_format(encoder, bus_format);
|
imx_drm_set_bus_format(encoder, bus_format);
|
||||||
@ -426,25 +443,39 @@ enum {
|
|||||||
LVDS_BIT_MAP_JEIDA
|
LVDS_BIT_MAP_JEIDA
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const imx_ldb_bit_mappings[] = {
|
struct imx_ldb_bit_mapping {
|
||||||
[LVDS_BIT_MAP_SPWG] = "spwg",
|
u32 bus_format;
|
||||||
[LVDS_BIT_MAP_JEIDA] = "jeida",
|
u32 datawidth;
|
||||||
|
const char * const mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int of_get_data_mapping(struct device_node *np)
|
static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = {
|
||||||
|
{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, "spwg" },
|
||||||
|
{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, "spwg" },
|
||||||
|
{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static u32 of_get_bus_format(struct device *dev, struct device_node *np)
|
||||||
{
|
{
|
||||||
const char *bm;
|
const char *bm;
|
||||||
|
u32 datawidth = 0;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
ret = of_property_read_string(np, "fsl,data-mapping", &bm);
|
ret = of_property_read_string(np, "fsl,data-mapping", &bm);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++)
|
of_property_read_u32(np, "fsl,data-width", &datawidth);
|
||||||
if (!strcasecmp(bm, imx_ldb_bit_mappings[i]))
|
|
||||||
return i;
|
|
||||||
|
|
||||||
return -EINVAL;
|
for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) {
|
||||||
|
if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) &&
|
||||||
|
datawidth == imx_ldb_bit_mappings[i].datawidth)
|
||||||
|
return imx_ldb_bit_mappings[i].bus_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm);
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bus_mux imx6q_lvds_mux[2] = {
|
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)
|
|||||||
struct device_node *child;
|
struct device_node *child;
|
||||||
const u8 *edidp;
|
const u8 *edidp;
|
||||||
struct imx_ldb *imx_ldb;
|
struct imx_ldb *imx_ldb;
|
||||||
int datawidth;
|
|
||||||
int mapping;
|
|
||||||
int dual;
|
int dual;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
@ -583,39 +612,20 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
|
|||||||
channel->mode_valid = 1;
|
channel->mode_valid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_property_read_u32(child, "fsl,data-width", &datawidth);
|
channel->bus_format = of_get_bus_format(dev, child);
|
||||||
if (ret)
|
if (channel->bus_format == -EINVAL) {
|
||||||
datawidth = 0;
|
/*
|
||||||
else if (datawidth != 18 && datawidth != 24)
|
* If no bus format was specified in the device tree,
|
||||||
return -EINVAL;
|
* we can still get it from the connected panel later.
|
||||||
|
*/
|
||||||
mapping = of_get_data_mapping(child);
|
if (channel->panel && channel->panel->funcs &&
|
||||||
switch (mapping) {
|
channel->panel->funcs->get_modes)
|
||||||
case LVDS_BIT_MAP_SPWG:
|
channel->bus_format = 0;
|
||||||
if (datawidth == 24) {
|
}
|
||||||
if (i == 0 || dual)
|
if (channel->bus_format < 0) {
|
||||||
imx_ldb->ldb_ctrl |=
|
dev_err(dev, "could not determine data mapping: %d\n",
|
||||||
LDB_DATA_WIDTH_CH0_24;
|
channel->bus_format);
|
||||||
if (i == 1 || dual)
|
return channel->bus_format;
|
||||||
imx_ldb->ldb_ctrl |=
|
|
||||||
LDB_DATA_WIDTH_CH1_24;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LVDS_BIT_MAP_JEIDA:
|
|
||||||
if (datawidth == 18) {
|
|
||||||
dev_err(dev, "JEIDA standard only supported in 24 bit\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (i == 0 || dual)
|
|
||||||
imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
|
|
||||||
LDB_BIT_MAP_CH0_JEIDA;
|
|
||||||
if (i == 1 || dual)
|
|
||||||
imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
|
|
||||||
LDB_BIT_MAP_CH1_JEIDA;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dev_err(dev, "data mapping not specified or invalid\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = imx_ldb_register(drm, channel);
|
ret = imx_ldb_register(drm, channel);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user