Refactor the function to easaly construct error paths later on. The error handling gets dirty if we don't refactor the code yet. While on it I fixed a missing i2c_put_adapter() if the bind() fails. Signed-off-by: Marco Felsch <m.felsch@xxxxxxxxxxxxxx> --- drivers/gpu/drm/imx/imx-ldb.c | 246 ++++++++++++++++++---------------- 1 file changed, 132 insertions(+), 114 deletions(-) diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 0e5a3c84df10..5e6c1b09dbfa 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -441,64 +441,6 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno) return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]); } -static int imx_ldb_register_channel(struct drm_device *drm, - struct imx_ldb_channel *imx_ldb_ch, - struct imx_ldb_connector *imx_ldb_con) -{ - struct imx_ldb *ldb = imx_ldb_ch->ldb; - struct drm_encoder *encoder = &imx_ldb_ch->encoder; - struct drm_connector *connector = &imx_ldb_con->connector; - int ret; - - ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child); - if (ret) - return ret; - - ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno); - if (ret) - return ret; - - if (imx_ldb_is_dual(ldb)) { - ret = imx_ldb_get_clk(ldb, 1); - if (ret) - return ret; - } - - drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs); - drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs, - DRM_MODE_ENCODER_LVDS, NULL); - - if (imx_ldb_ch->bridge) { - ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL); - if (ret) { - DRM_ERROR("Failed to initialize bridge with drm\n"); - return ret; - } - } else { - /* - * We want to add the connector whenever there is no bridge - * that brings its own, not only when there is a panel. For - * historical reasons, the ldb driver can also work without - * a panel. - */ - drm_connector_helper_add(connector, - &imx_ldb_connector_helper_funcs); - drm_connector_init_with_ddc(drm, connector, - &imx_ldb_connector_funcs, - DRM_MODE_CONNECTOR_LVDS, - imx_ldb_con->ddc); - drm_connector_attach_encoder(connector, encoder); - } - - if (imx_ldb_ch->panel) { - ret = drm_panel_attach(imx_ldb_ch->panel, connector); - if (ret) - return ret; - } - - return 0; -} - struct imx_ldb_bit_mapping { u32 bus_format; u32 datawidth; @@ -576,6 +518,136 @@ static int imx_ldb_panel_ddc(struct device *dev, return 0; } +static int imx_ldb_setup_channel(struct device *dev, + struct device_node *child, + struct drm_device *drm, + struct imx_ldb *ldb, + int channel_number) +{ + struct imx_ldb_channel *channel; + struct imx_ldb_connector *imx_ldb_con; + struct drm_encoder *encoder; + struct drm_connector *connector = NULL; + int bus_format; + int ret; + + /* + * 1) Parse all available data and alloc needed structs + * 2) Setup the HW + * 3) Register it with the DRM framework + * 4) Attach bridge or connector to encoder + */ + channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL); + if (!channel) + return -ENOMEM; + + channel->ldb = ldb; + channel->chno = channel_number; + channel->child = child; + encoder = &channel->encoder; + + /* + * The output port is port@4 with an external 4-port mux or + * port@2 with the internal 2-port mux. + */ + ret = drm_of_find_panel_or_bridge(child, + ldb->lvds_mux ? 4 : 2, 0, + &channel->panel, &channel->bridge); + if (ret && ret != -ENODEV) + return ret; + + /* panel ddc only if there is no bridge */ + if (!channel->bridge) { + imx_ldb_con = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); + if (!imx_ldb_con) + return -ENOMEM; + + ret = imx_ldb_panel_ddc(dev, channel, imx_ldb_con, child); + if (ret) + return ret; + + imx_ldb_con->ldb_channel = channel; + connector = &imx_ldb_con->connector; + } + + bus_format = of_get_bus_format(dev, child); + if (bus_format == -EINVAL) { + /* + * If no bus format was specified in the device tree, + * we can still get it from the connected panel later. + */ + if (channel->panel && channel->panel->funcs && + channel->panel->funcs->get_modes) + bus_format = 0; + } + if (bus_format < 0) { + dev_err(dev, "could not determine data mapping: %d\n", + bus_format); + ret = bus_format; + goto err_put_ddc; + } + channel->bus_format = bus_format; + + /* 2) Setup the HW */ + ret = imx_ldb_get_clk(channel->ldb, channel->chno); + if (ret) + goto err_put_ddc; + + if (imx_ldb_is_dual(ldb)) { + ret = imx_ldb_get_clk(ldb, 1); + if (ret) + goto err_put_ddc; + } + + /* 3) Register it with the DRM framework */ + ret = imx_drm_encoder_parse_of(drm, encoder, channel->child); + if (ret) + goto err_put_ddc; + + drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs); + drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs, + DRM_MODE_ENCODER_LVDS, NULL); + + if (!channel->bridge) { + /* + * We want to add the connector whenever there is no bridge + * that brings its own, not only when there is a panel. For + * historical reasons, the ldb driver can also work without + * a panel. + */ + drm_connector_helper_add(connector, + &imx_ldb_connector_helper_funcs); + drm_connector_init_with_ddc(drm, connector, + &imx_ldb_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + imx_ldb_con->ddc); + } + + /* 4) Attach bridge or connector to encoder */ + if (channel->bridge) { + ret = drm_bridge_attach(encoder, channel->bridge, NULL); + if (ret) { + DRM_ERROR("Failed to initialize bridge with drm\n"); + goto err_put_ddc; + } + } else { + drm_connector_attach_encoder(connector, encoder); + } + + if (channel->panel) { + ret = drm_panel_attach(channel->panel, connector); + if (ret) + goto err_put_ddc; + } + + return 0; + +err_put_ddc: + if (imx_ldb_con) + i2c_put_adapter(imx_ldb_con->ddc); + return ret; +} + static int imx_ldb_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = data; @@ -587,9 +659,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) int i; for_each_child_of_node(np, child) { - struct imx_ldb_channel *channel; - struct imx_ldb_connector *connector; - int bus_format; ret = of_property_read_u32(child, "reg", &i); if (ret || i < 0 || i > 1) { @@ -605,60 +674,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) continue; } - channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL); - if (!channel) - return -ENOMEM; - - channel->ldb = imx_ldb; - channel->chno = i; - - /* - * The output port is port@4 with an external 4-port mux or - * port@2 with the internal 2-port mux. - */ - ret = drm_of_find_panel_or_bridge(child, - imx_ldb->lvds_mux ? 4 : 2, 0, - &channel->panel, &channel->bridge); - if (ret && ret != -ENODEV) - goto free_child; - - /* panel ddc only if there is no bridge */ - if (!channel->bridge) { - connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); - if (!connector) - return -ENOMEM; - - ret = imx_ldb_panel_ddc(dev, channel, connector, child); - if (ret) - goto free_child; - - connector->ldb_channel = channel; - } - - bus_format = of_get_bus_format(dev, child); - if (bus_format == -EINVAL) { - /* - * If no bus format was specified in the device tree, - * we can still get it from the connected panel later. - */ - if (channel->panel && channel->panel->funcs && - channel->panel->funcs->get_modes) - bus_format = 0; - } - if (bus_format < 0) { - dev_err(dev, "could not determine data mapping: %d\n", - bus_format); - ret = bus_format; - goto free_child; - } - channel->bus_format = bus_format; - channel->child = child; - - ret = imx_ldb_register_channel(drm, channel, connector); - if (ret) { - channel->child = NULL; + ret = imx_ldb_setup_channel(dev, child, drm, imx_ldb, i); + if (ret) goto free_child; - } } return 0; -- 2.20.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel