Hi Boris, Thank you for the patch. On Tue, Jan 28, 2020 at 02:55:10PM +0100, Boris Brezillon wrote: > Some DPI -> LVDS encoders might support several input bus width. Add a > DT property to describe the bus width used on a specific design. > > v10: > * Add changelog to the commit message > > v8 -> v9: > * No changes > > v7: > * Fix a use-after-release problem > * Get rid of the data-mapping parsing > * Use kmalloc instead of kcalloc. > > v4 -> v6: > * Not part of the series > > v3: > * Use bus-width for the rgb24/rgb18 distinction > * Adjust code to match core changes > * Get rid of of_get_data_mapping() > * Don't implement ->atomic_check() (the core now takes care of bus > flags propagation) > > v2: > * Make the bus-format negotiation logic more generic > > Signed-off-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxx> > --- > drivers/gpu/drm/bridge/lvds-codec.c | 64 ++++++++++++++++++++++++++--- > 1 file changed, 58 insertions(+), 6 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c > index 5f04cc11227e..f4fd8472c335 100644 > --- a/drivers/gpu/drm/bridge/lvds-codec.c > +++ b/drivers/gpu/drm/bridge/lvds-codec.c > @@ -11,6 +11,7 @@ > #include <linux/of_graph.h> > #include <linux/platform_device.h> > > +#include <drm/drm_atomic_helper.h> > #include <drm/drm_bridge.h> > #include <drm/drm_panel.h> > > @@ -19,6 +20,7 @@ struct lvds_codec { > struct drm_bridge *panel_bridge; > struct gpio_desc *powerdown_gpio; > u32 connector_type; > + u32 input_fmt; > }; > > static int lvds_codec_attach(struct drm_bridge *bridge) > @@ -48,18 +50,47 @@ static void lvds_codec_disable(struct drm_bridge *bridge) > gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1); > } > > +static u32 * > +lvds_codec_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) > +{ > + struct lvds_codec *lvds_codec = container_of(bridge, > + struct lvds_codec, bridge); > + u32 *input_fmts; > + > + input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL); > + if (!input_fmts) { > + *num_input_fmts = 0; > + return NULL; > + } > + > + *num_input_fmts = 1; > + input_fmts[0] = lvds_codec->input_fmt; > + return input_fmts; > +} > + > static struct drm_bridge_funcs funcs = { > .attach = lvds_codec_attach, > .enable = lvds_codec_enable, > .disable = lvds_codec_disable, > + .atomic_reset = drm_atomic_helper_bridge_reset, > + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, > + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, > + .atomic_get_input_bus_fmts = lvds_codec_atomic_get_input_bus_fmts, > }; > > static int lvds_codec_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > - struct device_node *panel_node; > + struct device_node *np; > struct drm_panel *panel; > struct lvds_codec *lvds_codec; > + u32 input_bus_width; > + int err; > > lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL); > if (!lvds_codec) > @@ -69,22 +100,43 @@ static int lvds_codec_probe(struct platform_device *pdev) > lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", > GPIOD_OUT_HIGH); > if (IS_ERR(lvds_codec->powerdown_gpio)) { > - int err = PTR_ERR(lvds_codec->powerdown_gpio); > + err = PTR_ERR(lvds_codec->powerdown_gpio); > > if (err != -EPROBE_DEFER) > dev_err(dev, "powerdown GPIO failure: %d\n", err); > return err; > } > > + np = of_graph_get_port_by_id(dev->of_node, 0); > + if (!np) { > + dev_dbg(dev, "port 0 not found\n"); > + return -ENXIO; > + } > + > + err = of_property_read_u32(np, "bus-width", &input_bus_width); > + of_node_put(np); > + > + if (err) { > + lvds_codec->input_fmt = MEDIA_BUS_FMT_FIXED; > + } else if (input_bus_width == 18) { > + lvds_codec->input_fmt = MEDIA_BUS_FMT_RGB666_1X18; > + } else if (input_bus_width == 24) { > + lvds_codec->input_fmt = MEDIA_BUS_FMT_RGB888_1X24; > + } else { > + dev_dbg(dev, "unsupported bus-width value %u on port 0\n", > + input_bus_width); > + return -ENOTSUPP; ENOTSUPP is "Operation not supported", I'd go for -EINVAL. > + } Doesn't this apply to LVDS encoders only ? For LVDS decoders I don't think we want to report an RGB format on the input. > + > /* Locate the panel DT node. */ > - panel_node = of_graph_get_remote_node(dev->of_node, 1, 0); > - if (!panel_node) { > + np = of_graph_get_remote_node(dev->of_node, 1, 0); > + if (!np) { > dev_dbg(dev, "panel DT node not found\n"); > return -ENXIO; > } > > - panel = of_drm_find_panel(panel_node); > - of_node_put(panel_node); > + panel = of_drm_find_panel(np); > + of_node_put(np); > if (IS_ERR(panel)) { > dev_dbg(dev, "panel not found, deferring probe\n"); > return PTR_ERR(panel); -- Regards, Laurent Pinchart