Hi Ahmad.
> On 2/1/19 22:37, Sam Ravnborg wrote:
> > The problem with the RED/BLUE lines swapped is something I
> > have encountered while working with DRM support for Atmel at91sam9263 too.
> >
> > The solution selected is to extend the endpoint with
> > a new optional property:
> >
> > - wiring: Wiring of data lines to display.
> > "straight" - normal wiring.
> > "red-blue-reversed" - red and blue lines reversed.
> >
> > (media/video-interfaces.txt)
> >
> >
> > The DT node looks like this:
> >
> > port@0 {
> > reg = <0>;
> > #address-cells = <1>;
> > #size-cells = <0>;
> > lcdc_panel_output: endpoint@0 {
> > reg = <0>;
> > wiring = "red-blue-reversed";
> > remote-endpoint = <&panel_input>;
> > };
> > };
> >
> > This allows us to specify the swapping in the endpoint and
> > not in the panel.
> > So we can use the same panel, with the same bus_format, in several
> > designs some with red-blue swapped (reversed), and some not.
>
> A colleague suggested a property in the endpoint as well, but I shied
> away because of the extra hassle. Seems there's won't be a way around it ^^'..
>
> How do you intend to propagate this different wiring setting?
The way I have it implmented is more or less like this:
First find the wiring property:
1) Look up endpoint using of_graph_get_endpoint_by_regs()
2) Get wiring property
3) of_node_put(endpoint);
And then find and attach the panel:
4) drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge);
5) devm_drm_panel_bridge_add(dev, panel, DRM_MODE_CONNECTOR_DPI);
6) Then based on the wiring property I adjust bus_format
7) drm_simple_display_pipe_init()
8) drm_simple_display_pipe_attach_bridge()
But this is all virgin code that for now can build,
but has not yet seen any testing.
It is a lot of boilerplate for something relatively simple
and I hope there are ways to simplify this.
Relevant parts of the file pasted below.
But the translation of bus_format in a central place may prove a bit
difficult and I assume this as something that can differ
a lot between different HW solutions.
> How about having drm_of_find_panel_or_bridge adjust the
> (*panel)->connector->display_info.bus_formats array to account for the
> different wiring? That way there shouldn't be any need to adjust drivers.
But if you prove me wrong and this fly I am all for it.
Keep in mind that I am novice in the DRM land. So there may be better ways to
do it.
Sam
static int lcdc_get_of_wiring(struct lcdc *lcdc,
const struct device_node *ep)
{
const char *str;
int ret;
ret = of_property_read_string(ep, "wiring", &str);
if (ret)
return ret;
if (strcmp(str, "red-green-reversed") == 0) {
lcdc->wiring_reversed = true;
} else if (strcmp(str, "straight") == 0) {
/* Use default format */
} else {
DRM_DEV_ERROR(lcdc->dev, "unknown \"wiring\" property: %s",
str);
return -EINVAL;
}
return 0;
}
static int lcdc_display_init(struct lcdc *lcdc, struct drm_device *drm)
{
struct drm_display_info *display_info;
const u32 *formats;
size_t nformats;
int ret;
display_info = &lcdc->panel->connector->display_info;
if (!display_info->num_bus_formats || !display_info->bus_formats) {
DRM_DEV_ERROR(lcdc->dev, "missing bus_format from panel");
return -EINVAL;
}
switch (display_info->bus_formats[0]) {
case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_RGB565_1X16:
lcdc->bus_format = display_info->bus_formats[0];
break;
default:
DRM_DEV_ERROR(lcdc->dev, "unsupported bus_format: %d",
display_info->bus_formats[0]);
return -EINVAL;
}
/* Select formats depending on wiring (from bus_formats + from DT) */
if (lcdc->bus_format == MEDIA_BUS_FMT_RGB888_1X24) {
if (!lcdc->wiring_reversed) {
formats = bgr_formats_24;
nformats = ARRAY_SIZE(bgr_formats_24);
} else {
formats = rgb_formats_24;
nformats = ARRAY_SIZE(rgb_formats_24);
}
} else {
if (!lcdc->wiring_reversed) {
formats = bgr_formats_16;
nformats = ARRAY_SIZE(bgr_formats_16);
} else {
formats = rgb_formats_16;
nformats = ARRAY_SIZE(rgb_formats_16);
}
}
ret = drm_simple_display_pipe_init(drm, &lcdc->pipe,
&lcdc_display_funcs,
formats, nformats,
NULL, &lcdc->connector);
if (ret < 0)
DRM_DEV_ERROR(lcdc->dev, "failed to init display pipe: %d",
ret);
return ret;
}
static int lcdc_attach_panel(struct lcdc *lcdc, struct drm_device *drm)
{
struct drm_bridge *bridge;
struct drm_panel *panel;
struct device *dev;
int ret;
dev = lcdc->dev;
ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge);
if (ret < 0)
return ret;
if (panel) {
lcdc->panel = panel;
bridge = devm_drm_panel_bridge_add(dev, panel,
DRM_MODE_CONNECTOR_DPI);
ret = PTR_ERR_OR_ZERO(bridge);
if (ret < 0) {
DRM_DEV_ERROR(dev, "failed to add bridge: %d", ret);
return ret;
}
} else {
DRM_DEV_ERROR(dev, "the bridge is not a panel");
return -ENODEV;
}
ret = lcdc_display_init(lcdc, drm);
if (ret < 0)
return ret;
ret = drm_simple_display_pipe_attach_bridge(&lcdc->pipe, bridge);
if (ret < 0)
DRM_DEV_ERROR(dev, "failed to attach bridge: %d", ret);
return ret;
}
static int lcdc_create_output(struct lcdc *lcdc, struct drm_device *drm)
{
struct device_node *endpoint;
int ret;
/* port@0/endpoint@0 is the only port/endpoint */
endpoint = of_graph_get_endpoint_by_regs(drm->dev->of_node, 0, 0);
if (!endpoint) {
DRM_DEV_ERROR(lcdc->dev, "failed to find endpoint node");
return -ENODEV;
}
lcdc_get_of_wiring(lcdc, endpoint);
of_node_put(endpoint);
ret = lcdc_attach_panel(lcdc, drm);
return ret;
}
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel