diff options
Diffstat (limited to 'drivers/gpu/drm/bridge/display-connector.c')
| -rw-r--r-- | drivers/gpu/drm/bridge/display-connector.c | 116 |
1 files changed, 62 insertions, 54 deletions
diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index 9a12449ad7b8..e9f16dbc9535 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -24,7 +23,7 @@ struct display_connector { struct gpio_desc *hpd_gpio; int hpd_irq; - struct regulator *dp_pwr; + struct regulator *supply; struct gpio_desc *ddc_en; }; @@ -35,13 +34,13 @@ to_display_connector(struct drm_bridge *bridge) } static int display_connector_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, enum drm_bridge_attach_flags flags) { return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL; } -static enum drm_connector_status -display_connector_detect(struct drm_bridge *bridge) +static enum drm_connector_status display_connector_detect(struct drm_bridge *bridge) { struct display_connector *conn = to_display_connector(bridge); @@ -82,12 +81,18 @@ display_connector_detect(struct drm_bridge *bridge) } } -static struct edid *display_connector_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static enum drm_connector_status +display_connector_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) +{ + return display_connector_detect(bridge); +} + +static const struct drm_edid *display_connector_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct display_connector *conn = to_display_connector(bridge); - return drm_get_edid(connector, conn->bridge.ddc); + return drm_edid_read_ddc(connector, conn->bridge.ddc); } /* @@ -103,7 +108,7 @@ static u32 *display_connector_get_output_bus_fmts(struct drm_bridge *bridge, struct drm_connector_state *conn_state, unsigned int *num_output_fmts) { - struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); + struct drm_bridge *prev_bridge __free(drm_bridge_put) = drm_bridge_get_prev_bridge(bridge); struct drm_bridge_state *prev_bridge_state; if (!prev_bridge || !prev_bridge->funcs->atomic_get_output_bus_fmts) { @@ -146,7 +151,7 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, u32 output_fmt, unsigned int *num_input_fmts) { - struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); + struct drm_bridge *prev_bridge __free(drm_bridge_put) = drm_bridge_get_prev_bridge(bridge); struct drm_bridge_state *prev_bridge_state; if (!prev_bridge || !prev_bridge->funcs->atomic_get_input_bus_fmts) { @@ -172,8 +177,8 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, static const struct drm_bridge_funcs display_connector_bridge_funcs = { .attach = display_connector_attach, - .detect = display_connector_detect, - .get_edid = display_connector_get_edid, + .detect = display_connector_bridge_detect, + .edid_read = display_connector_edid_read, .atomic_get_output_bus_fmts = display_connector_get_output_bus_fmts, .atomic_get_input_bus_fmts = display_connector_get_input_bus_fmts, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, @@ -191,6 +196,18 @@ static irqreturn_t display_connector_hpd_irq(int irq, void *arg) return IRQ_HANDLED; } +static int display_connector_get_supply(struct platform_device *pdev, + struct display_connector *conn, + const char *name) +{ + conn->supply = devm_regulator_get_optional(&pdev->dev, name); + + if (conn->supply == ERR_PTR(-ENODEV)) + conn->supply = NULL; + + return PTR_ERR_OR_ZERO(conn->supply); +} + static int display_connector_probe(struct platform_device *pdev) { struct display_connector *conn; @@ -198,9 +215,10 @@ static int display_connector_probe(struct platform_device *pdev) const char *label = NULL; int ret; - conn = devm_kzalloc(&pdev->dev, sizeof(*conn), GFP_KERNEL); - if (!conn) - return -ENOMEM; + conn = devm_drm_bridge_alloc(&pdev->dev, struct display_connector, bridge, + &display_connector_bridge_funcs); + if (IS_ERR(conn)) + return PTR_ERR(conn); platform_set_drvdata(pdev, conn); @@ -259,6 +277,10 @@ static int display_connector_probe(struct platform_device *pdev) /* All the supported connector types support interlaced modes. */ conn->bridge.interlace_allowed = true; + if (type == DRM_MODE_CONNECTOR_HDMIA || + type == DRM_MODE_CONNECTOR_DisplayPort) + conn->bridge.ycbcr_420_allowed = true; + /* Get the optional connector label. */ of_property_read_string(pdev->dev.of_node, "label", &label); @@ -271,12 +293,9 @@ static int display_connector_probe(struct platform_device *pdev) type == DRM_MODE_CONNECTOR_DisplayPort) { conn->hpd_gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); - if (IS_ERR(conn->hpd_gpio)) { - if (PTR_ERR(conn->hpd_gpio) != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Unable to retrieve HPD GPIO\n"); - return PTR_ERR(conn->hpd_gpio); - } + if (IS_ERR(conn->hpd_gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(conn->hpd_gpio), + "Unable to retrieve HPD GPIO\n"); conn->hpd_irq = gpiod_to_irq(conn->hpd_gpio); } else { @@ -319,36 +338,15 @@ static int display_connector_probe(struct platform_device *pdev) if (type == DRM_MODE_CONNECTOR_DisplayPort) { int ret; - conn->dp_pwr = devm_regulator_get_optional(&pdev->dev, "dp-pwr"); - - if (IS_ERR(conn->dp_pwr)) { - ret = PTR_ERR(conn->dp_pwr); - - switch (ret) { - case -ENODEV: - conn->dp_pwr = NULL; - break; - - case -EPROBE_DEFER: - return -EPROBE_DEFER; - - default: - dev_err(&pdev->dev, "failed to get DP PWR regulator: %d\n", ret); - return ret; - } - } - - if (conn->dp_pwr) { - ret = regulator_enable(conn->dp_pwr); - if (ret) { - dev_err(&pdev->dev, "failed to enable DP PWR regulator: %d\n", ret); - return ret; - } - } + ret = display_connector_get_supply(pdev, conn, "dp-pwr"); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to get DP PWR regulator\n"); } /* enable DDC */ if (type == DRM_MODE_CONNECTOR_HDMIA) { + int ret; + conn->ddc_en = devm_gpiod_get_optional(&pdev->dev, "ddc-en", GPIOD_OUT_HIGH); @@ -356,15 +354,27 @@ static int display_connector_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Couldn't get ddc-en gpio\n"); return PTR_ERR(conn->ddc_en); } + + ret = display_connector_get_supply(pdev, conn, "hdmi-pwr"); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to get HDMI +5V Power regulator\n"); + } + + if (conn->supply) { + ret = regulator_enable(conn->supply); + if (ret) { + dev_err(&pdev->dev, "failed to enable PWR regulator: %d\n", ret); + return ret; + } } - conn->bridge.funcs = &display_connector_bridge_funcs; conn->bridge.of_node = pdev->dev.of_node; if (conn->bridge.ddc) conn->bridge.ops |= DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT; - if (conn->hpd_gpio) + /* Detecting the monitor requires reading DPCD */ + if (conn->hpd_gpio && type != DRM_MODE_CONNECTOR_DisplayPort) conn->bridge.ops |= DRM_BRIDGE_OP_DETECT; if (conn->hpd_irq >= 0) conn->bridge.ops |= DRM_BRIDGE_OP_HPD; @@ -382,22 +392,20 @@ static int display_connector_probe(struct platform_device *pdev) return 0; } -static int display_connector_remove(struct platform_device *pdev) +static void display_connector_remove(struct platform_device *pdev) { struct display_connector *conn = platform_get_drvdata(pdev); if (conn->ddc_en) gpiod_set_value(conn->ddc_en, 0); - if (conn->dp_pwr) - regulator_disable(conn->dp_pwr); + if (conn->supply) + regulator_disable(conn->supply); drm_bridge_remove(&conn->bridge); if (!IS_ERR(conn->bridge.ddc)) i2c_put_adapter(conn->bridge.ddc); - - return 0; } static const struct of_device_id display_connector_match[] = { @@ -426,7 +434,7 @@ MODULE_DEVICE_TABLE(of, display_connector_match); static struct platform_driver display_connector_driver = { .probe = display_connector_probe, - .remove = display_connector_remove, + .remove = display_connector_remove, .driver = { .name = "display-connector", .of_match_table = display_connector_match, |
