Message ID | 20190826152649.13820-19-boris.brezillon@collabora.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm: Add support for bus-format negotiation | expand |
Hi Boris! Dne ponedeljek, 26. avgust 2019 ob 17:26:46 CEST je Boris Brezillon napisal(a): > Some LVDS encoder might support several input/output bus formats. Add > a way to describe the one used on a specific design by adding optional > 'data-mapping' properties to the input/output ports. > > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> > --- > Changes in v2: > * Make the bus-format negotiation logic more generic > --- > .../display/bridge/lvds-transmitter.txt | 12 ++ > drivers/gpu/drm/bridge/lvds-encoder.c | 105 ++++++++++++++++++ > 2 files changed, 117 insertions(+) > > diff --git > a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > index 60091db5dfa5..db51eab216f7 100644 > --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > @@ -36,6 +36,18 @@ graph bindings specified in > Documentation/devicetree/bindings/graph.txt. - Video port 0 for parallel > input > - Video port 1 for LVDS output > > +Optional port 0 node properties: > + > +- data-mapping: can be one of the following values > + "rgb-24" > + "rgb-18" > + > +Optional port 0 node properties: You probably mean port 1 ^^^ ? Anyway, devicetree doc changes should be separate patch and be send to DT ML (I can't see it in CC). Best regards, Jernej > + > +- data-mapping: can be one of the following values > + "jeida-18" > + "jeida-24" > + "vesa-24" > > Example > ------- > diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c > b/drivers/gpu/drm/bridge/lvds-encoder.c index 2ab2c234f26c..38cad7a7d828 > 100644 > --- a/drivers/gpu/drm/bridge/lvds-encoder.c > +++ b/drivers/gpu/drm/bridge/lvds-encoder.c > @@ -6,6 +6,7 @@ > #include <linux/gpio/consumer.h> > #include <linux/module.h> > #include <linux/of.h> > +#include <linux/of_device.h> > #include <linux/of_graph.h> > #include <linux/platform_device.h> > > @@ -16,6 +17,8 @@ struct lvds_encoder { > struct drm_bridge bridge; > struct drm_bridge *panel_bridge; > struct gpio_desc *powerdown_gpio; > + u32 output_fmt; > + u32 input_fmt; > }; > > static int lvds_encoder_attach(struct drm_bridge *bridge) > @@ -48,12 +51,86 @@ static void lvds_encoder_disable(struct drm_bridge > *bridge) gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); > } > > +static void lvds_atomic_get_input_bus_fmts(struct drm_bridge *bridge, > + struct drm_bridge_state *bridge_state, > + struct drm_crtc_state *crtc_state, > + struct drm_connector_state *conn_state, > + u32 output_fmt, > + unsigned int *num_input_fmts, > + u32 *input_fmts) > +{ > + struct lvds_encoder *lvds_encoder = container_of(bridge, > + struct lvds_encoder, > + bridge); > + > + if (output_fmt == MEDIA_BUS_FMT_FIXED || > + output_fmt == lvds_encoder->output_fmt) > + *num_input_fmts = 1; > + else > + *num_input_fmts = 0; > + > + if (*num_input_fmts && input_fmts) > + input_fmts[0] = lvds_encoder->input_fmt; > +} > + > +static int lvds_encoder_atomic_check(struct drm_bridge *bridge, > + struct drm_bridge_state *bridge_state, > + struct drm_crtc_state *crtc_state, > + struct drm_connector_state *conn_state) > +{ > + /* Propagate the bus_flags. */ > + bridge_state->input_bus_cfg.flags = bridge_state- >output_bus_cfg.flags; > + return 0; > +} > + > static struct drm_bridge_funcs funcs = { > .attach = lvds_encoder_attach, > .enable = lvds_encoder_enable, > .disable = lvds_encoder_disable, > + .atomic_get_input_bus_fmts = lvds_atomic_get_input_bus_fmts, > + .atomic_check = lvds_encoder_atomic_check, > }; > > +struct of_data_mapping { > + const char *name; > + u32 id; > +}; > + > +static const struct of_data_mapping output_data_mappings[] = { > + { "jeida-18", MEDIA_BUS_FMT_RGB666_1X7X3_SPWG }, > + { "jeida-24", MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA }, > + { "vesa-24", MEDIA_BUS_FMT_RGB888_1X7X4_SPWG }, > +}; > + > +static const struct of_data_mapping input_data_mappings[] = { > + { "rgb-24", MEDIA_BUS_FMT_RGB888_1X24 }, > + { "rgb-18", MEDIA_BUS_FMT_RGB666_1X18 }, > +}; > + > +static int of_get_data_mapping(struct device_node *port, > + const struct of_data_mapping *mappings, > + unsigned int num_mappings, > + u32 *fmt) > +{ > + const char *name = NULL; > + unsigned int i; > + > + of_property_read_string(port, "data-mapping", &name); > + if (!name) { > + *fmt = MEDIA_BUS_FMT_FIXED; > + return 0; > + } > + > + for (i = 0; i < num_mappings; i++) { > + if (!strcmp(mappings[i].name, name)) { > + *fmt = mappings[i].id; > + return 0; > + } > + } > + > + return -ENOTSUPP; > +} > + > static int lvds_encoder_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > @@ -62,11 +139,15 @@ static int lvds_encoder_probe(struct platform_device > *pdev) struct device_node *panel_node; > struct drm_panel *panel; > struct lvds_encoder *lvds_encoder; > + int ret; > > lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL); > if (!lvds_encoder) > return -ENOMEM; > > + lvds_encoder->input_fmt = MEDIA_BUS_FMT_FIXED; > + lvds_encoder->output_fmt = MEDIA_BUS_FMT_FIXED; > + > lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", > GPIOD_OUT_HIGH); > if (IS_ERR(lvds_encoder->powerdown_gpio)) { > @@ -77,6 +158,21 @@ static int lvds_encoder_probe(struct platform_device > *pdev) return err; > } > > + port = of_graph_get_port_by_id(dev->of_node, 0); > + if (!port) { > + dev_dbg(dev, "port 0 not found\n"); > + return -ENXIO; > + } > + > + ret = of_get_data_mapping(port, input_data_mappings, > + ARRAY_SIZE(input_data_mappings), > + &lvds_encoder->input_fmt); > + of_node_put(port); > + if (ret) { > + dev_dbg(dev, "unsupported input data-mapping\n"); > + return ret; > + } > + > /* Locate the panel DT node. */ > port = of_graph_get_port_by_id(dev->of_node, 1); > if (!port) { > @@ -84,6 +180,15 @@ static int lvds_encoder_probe(struct platform_device > *pdev) return -ENXIO; > } > > + ret = of_get_data_mapping(port, output_data_mappings, > + ARRAY_SIZE(output_data_mappings), > + &lvds_encoder->output_fmt); > + if (ret) { > + of_node_put(port); > + dev_dbg(dev, "unsupported output data-mapping\n"); > + return ret; > + } > + > endpoint = of_get_child_by_name(port, "endpoint"); > of_node_put(port); > if (!endpoint) {
On Mon, 26 Aug 2019 18:15:41 +0200 Jernej Škrabec <jernej.skrabec@siol.net> wrote: > Hi Boris! > > Dne ponedeljek, 26. avgust 2019 ob 17:26:46 CEST je Boris Brezillon > napisal(a): > > Some LVDS encoder might support several input/output bus formats. Add > > a way to describe the one used on a specific design by adding optional > > 'data-mapping' properties to the input/output ports. > > > > Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> > > --- > > Changes in v2: > > * Make the bus-format negotiation logic more generic > > --- > > .../display/bridge/lvds-transmitter.txt | 12 ++ > > drivers/gpu/drm/bridge/lvds-encoder.c | 105 ++++++++++++++++++ > > 2 files changed, 117 insertions(+) > > > > diff --git > > a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > > b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > > index 60091db5dfa5..db51eab216f7 100644 > > --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > > +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt > > @@ -36,6 +36,18 @@ graph bindings specified in > > Documentation/devicetree/bindings/graph.txt. - Video port 0 for parallel > > input > > - Video port 1 for LVDS output > > > > +Optional port 0 node properties: > > + > > +- data-mapping: can be one of the following values > > + "rgb-24" > > + "rgb-18" > > + > > +Optional port 0 node properties: > > You probably mean port 1 ^^^ ? Yes. > > Anyway, devicetree doc changes should be separate patch and be send to DT ML > (I can't see it in CC). I'll fix that in v3. In the meantime, I'd really like to have feedback on patches 1 to 16 as this is where core changes are.
diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt index 60091db5dfa5..db51eab216f7 100644 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt @@ -36,6 +36,18 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt. - Video port 0 for parallel input - Video port 1 for LVDS output +Optional port 0 node properties: + +- data-mapping: can be one of the following values + "rgb-24" + "rgb-18" + +Optional port 0 node properties: + +- data-mapping: can be one of the following values + "jeida-18" + "jeida-24" + "vesa-24" Example ------- diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c index 2ab2c234f26c..38cad7a7d828 100644 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -6,6 +6,7 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_graph.h> #include <linux/platform_device.h> @@ -16,6 +17,8 @@ struct lvds_encoder { struct drm_bridge bridge; struct drm_bridge *panel_bridge; struct gpio_desc *powerdown_gpio; + u32 output_fmt; + u32 input_fmt; }; static int lvds_encoder_attach(struct drm_bridge *bridge) @@ -48,12 +51,86 @@ static void lvds_encoder_disable(struct drm_bridge *bridge) gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); } +static void lvds_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts, + u32 *input_fmts) +{ + struct lvds_encoder *lvds_encoder = container_of(bridge, + struct lvds_encoder, + bridge); + + if (output_fmt == MEDIA_BUS_FMT_FIXED || + output_fmt == lvds_encoder->output_fmt) + *num_input_fmts = 1; + else + *num_input_fmts = 0; + + if (*num_input_fmts && input_fmts) + input_fmts[0] = lvds_encoder->input_fmt; +} + +static int lvds_encoder_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + /* Propagate the bus_flags. */ + bridge_state->input_bus_cfg.flags = bridge_state->output_bus_cfg.flags; + return 0; +} + static struct drm_bridge_funcs funcs = { .attach = lvds_encoder_attach, .enable = lvds_encoder_enable, .disable = lvds_encoder_disable, + .atomic_get_input_bus_fmts = lvds_atomic_get_input_bus_fmts, + .atomic_check = lvds_encoder_atomic_check, }; +struct of_data_mapping { + const char *name; + u32 id; +}; + +static const struct of_data_mapping output_data_mappings[] = { + { "jeida-18", MEDIA_BUS_FMT_RGB666_1X7X3_SPWG }, + { "jeida-24", MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA }, + { "vesa-24", MEDIA_BUS_FMT_RGB888_1X7X4_SPWG }, +}; + +static const struct of_data_mapping input_data_mappings[] = { + { "rgb-24", MEDIA_BUS_FMT_RGB888_1X24 }, + { "rgb-18", MEDIA_BUS_FMT_RGB666_1X18 }, +}; + +static int of_get_data_mapping(struct device_node *port, + const struct of_data_mapping *mappings, + unsigned int num_mappings, + u32 *fmt) +{ + const char *name = NULL; + unsigned int i; + + of_property_read_string(port, "data-mapping", &name); + if (!name) { + *fmt = MEDIA_BUS_FMT_FIXED; + return 0; + } + + for (i = 0; i < num_mappings; i++) { + if (!strcmp(mappings[i].name, name)) { + *fmt = mappings[i].id; + return 0; + } + } + + return -ENOTSUPP; +} + static int lvds_encoder_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -62,11 +139,15 @@ static int lvds_encoder_probe(struct platform_device *pdev) struct device_node *panel_node; struct drm_panel *panel; struct lvds_encoder *lvds_encoder; + int ret; lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL); if (!lvds_encoder) return -ENOMEM; + lvds_encoder->input_fmt = MEDIA_BUS_FMT_FIXED; + lvds_encoder->output_fmt = MEDIA_BUS_FMT_FIXED; + lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); if (IS_ERR(lvds_encoder->powerdown_gpio)) { @@ -77,6 +158,21 @@ static int lvds_encoder_probe(struct platform_device *pdev) return err; } + port = of_graph_get_port_by_id(dev->of_node, 0); + if (!port) { + dev_dbg(dev, "port 0 not found\n"); + return -ENXIO; + } + + ret = of_get_data_mapping(port, input_data_mappings, + ARRAY_SIZE(input_data_mappings), + &lvds_encoder->input_fmt); + of_node_put(port); + if (ret) { + dev_dbg(dev, "unsupported input data-mapping\n"); + return ret; + } + /* Locate the panel DT node. */ port = of_graph_get_port_by_id(dev->of_node, 1); if (!port) { @@ -84,6 +180,15 @@ static int lvds_encoder_probe(struct platform_device *pdev) return -ENXIO; } + ret = of_get_data_mapping(port, output_data_mappings, + ARRAY_SIZE(output_data_mappings), + &lvds_encoder->output_fmt); + if (ret) { + of_node_put(port); + dev_dbg(dev, "unsupported output data-mapping\n"); + return ret; + } + endpoint = of_get_child_by_name(port, "endpoint"); of_node_put(port); if (!endpoint) {
Some LVDS encoder might support several input/output bus formats. Add a way to describe the one used on a specific design by adding optional 'data-mapping' properties to the input/output ports. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> --- Changes in v2: * Make the bus-format negotiation logic more generic --- .../display/bridge/lvds-transmitter.txt | 12 ++ drivers/gpu/drm/bridge/lvds-encoder.c | 105 ++++++++++++++++++ 2 files changed, 117 insertions(+)