diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss/hdmi4.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi4.c | 382 |
1 files changed, 176 insertions, 206 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 5879f45f6fc9..aabdda394c9c 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -108,26 +108,6 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int hdmi_init_regulator(struct omap_hdmi *hdmi) -{ - struct regulator *reg; - - if (hdmi->vdda_reg != NULL) - return 0; - - reg = devm_regulator_get(&hdmi->pdev->dev, "vdda"); - - if (IS_ERR(reg)) { - if (PTR_ERR(reg) != -EPROBE_DEFER) - DSSERR("can't get VDDA regulator\n"); - return PTR_ERR(reg); - } - - hdmi->vdda_reg = reg; - - return 0; -} - static int hdmi_power_on_core(struct omap_hdmi *hdmi) { int r; @@ -174,7 +154,7 @@ static void hdmi_power_off_core(struct omap_hdmi *hdmi) static int hdmi_power_on_full(struct omap_hdmi *hdmi) { int r; - struct videomode *vm; + const struct videomode *vm; struct hdmi_wp_data *wp = &hdmi->wp; struct dss_pll_clock_info hdmi_cinfo = { 0 }; unsigned int pc; @@ -227,9 +207,6 @@ static int hdmi_power_on_full(struct omap_hdmi *hdmi) hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg); - /* tv size */ - dss_mgr_set_timings(&hdmi->output, vm); - r = dss_mgr_enable(&hdmi->output); if (r) goto err_mgr_enable; @@ -271,19 +248,8 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) hdmi_power_off_core(hdmi); } -static int hdmi_display_check_timing(struct omap_dss_device *dssdev, - struct videomode *vm) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm)) - return -EINVAL; - - return 0; -} - -static void hdmi_display_set_timing(struct omap_dss_device *dssdev, - struct videomode *vm) +static void hdmi_display_set_timings(struct omap_dss_device *dssdev, + const struct videomode *vm) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); @@ -296,14 +262,6 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev, mutex_unlock(&hdmi->lock); } -static void hdmi_display_get_timings(struct omap_dss_device *dssdev, - struct videomode *vm) -{ - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - *vm = hdmi->cfg.vm; -} - static int hdmi_dump_regs(struct seq_file *s, void *p) { struct omap_hdmi *hdmi = s->private; @@ -456,44 +414,25 @@ void hdmi4_core_disable(struct hdmi_core_data *core) mutex_unlock(&hdmi->lock); } -static int hdmi_connect(struct omap_dss_device *dssdev, - struct omap_dss_device *dst) +static int hdmi_connect(struct omap_dss_device *src, + struct omap_dss_device *dst) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); int r; - r = hdmi_init_regulator(hdmi); + r = omapdss_device_connect(dst->dss, dst, dst->next); if (r) return r; - r = dss_mgr_connect(&hdmi->output, dssdev); - if (r) - return r; - - r = omapdss_output_set_device(dssdev, dst); - if (r) { - DSSERR("failed to connect output to new device: %s\n", - dst->name); - dss_mgr_disconnect(&hdmi->output, dssdev); - return r; - } - + dst->dispc_channel_connected = true; return 0; } -static void hdmi_disconnect(struct omap_dss_device *dssdev, - struct omap_dss_device *dst) +static void hdmi_disconnect(struct omap_dss_device *src, + struct omap_dss_device *dst) { - struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); - - WARN_ON(dst != dssdev->dst); + dst->dispc_channel_connected = false; - if (dst != dssdev->dst) - return; - - omapdss_output_unset_device(dssdev); - - dss_mgr_disconnect(&hdmi->output, dssdev); + omapdss_device_disconnect(dst, dst->next); } static int hdmi_read_edid(struct omap_dss_device *dssdev, @@ -548,69 +487,28 @@ static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev, return 0; } -static const struct omapdss_hdmi_ops hdmi_ops = { +static const struct omap_dss_device_ops hdmi_ops = { .connect = hdmi_connect, .disconnect = hdmi_disconnect, .enable = hdmi_display_enable, .disable = hdmi_display_disable, - .check_timings = hdmi_display_check_timing, - .set_timings = hdmi_display_set_timing, - .get_timings = hdmi_display_get_timings, + .set_timings = hdmi_display_set_timings, .read_edid = hdmi_read_edid, - .lost_hotplug = hdmi_lost_hotplug, - .set_infoframe = hdmi_set_infoframe, - .set_hdmi_mode = hdmi_set_hdmi_mode, -}; - -static void hdmi_init_output(struct omap_hdmi *hdmi) -{ - struct omap_dss_device *out = &hdmi->output; - - out->dev = &hdmi->pdev->dev; - out->id = OMAP_DSS_OUTPUT_HDMI; - out->output_type = OMAP_DISPLAY_TYPE_HDMI; - out->name = "hdmi.0"; - out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; - out->ops.hdmi = &hdmi_ops; - out->owner = THIS_MODULE; - - omapdss_register_output(out); -} - -static void hdmi_uninit_output(struct omap_hdmi *hdmi) -{ - struct omap_dss_device *out = &hdmi->output; - omapdss_unregister_output(out); -} - -static int hdmi_probe_of(struct omap_hdmi *hdmi) -{ - struct platform_device *pdev = hdmi->pdev; - struct device_node *node = pdev->dev.of_node; - struct device_node *ep; - int r; - - ep = of_graph_get_endpoint_by_regs(node, 0, 0); - if (!ep) - return 0; - - r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy); - if (r) - goto err; - - of_node_put(ep); - return 0; + .hdmi = { + .lost_hotplug = hdmi_lost_hotplug, + .set_infoframe = hdmi_set_infoframe, + .set_hdmi_mode = hdmi_set_hdmi_mode, + }, +}; -err: - of_node_put(ep); - return r; -} +/* ----------------------------------------------------------------------------- + * Audio Callbacks + */ -/* Audio callbacks */ static int hdmi_audio_startup(struct device *dev, void (*abort_cb)(struct device *dev)) { @@ -725,86 +623,49 @@ static int hdmi_audio_register(struct omap_hdmi *hdmi) return 0; } -/* HDMI HW IP initialisation */ +/* ----------------------------------------------------------------------------- + * Component Bind & Unbind + */ + static int hdmi4_bind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); struct dss_device *dss = dss_get_device(master); - struct omap_hdmi *hdmi; + struct omap_hdmi *hdmi = dev_get_drvdata(dev); int r; - int irq; - hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return -ENOMEM; - - hdmi->pdev = pdev; hdmi->dss = dss; - dev_set_drvdata(&pdev->dev, hdmi); - - mutex_init(&hdmi->lock); - spin_lock_init(&hdmi->audio_playing_lock); - r = hdmi_probe_of(hdmi); - if (r) - goto err_free; - - r = hdmi_wp_init(pdev, &hdmi->wp, 4); - if (r) - goto err_free; - - r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp); - if (r) - goto err_free; - - r = hdmi_phy_init(pdev, &hdmi->phy, 4); + r = hdmi_runtime_get(hdmi); if (r) - goto err_pll; + return r; - r = hdmi4_core_init(pdev, &hdmi->core); + r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp); if (r) - goto err_pll; + goto err_runtime_put; - r = hdmi4_cec_init(pdev, &hdmi->core, &hdmi->wp); + r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp); if (r) - goto err_pll; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - DSSERR("platform_get_irq failed\n"); - r = -ENODEV; - goto err_pll; - } - - r = devm_request_threaded_irq(&pdev->dev, irq, - NULL, hdmi_irq_handler, - IRQF_ONESHOT, "OMAP HDMI", hdmi); - if (r) { - DSSERR("HDMI IRQ request failed\n"); - goto err_pll; - } - - pm_runtime_enable(&pdev->dev); - - hdmi_init_output(hdmi); + goto err_pll_uninit; r = hdmi_audio_register(hdmi); if (r) { DSSERR("Registering HDMI audio failed\n"); - hdmi_uninit_output(hdmi); - pm_runtime_disable(&pdev->dev); - return r; + goto err_cec_uninit; } hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs, hdmi); + hdmi_runtime_put(hdmi); + return 0; -err_pll: +err_cec_uninit: + hdmi4_cec_uninit(&hdmi->core); +err_pll_uninit: hdmi_pll_uninit(&hdmi->pll); -err_free: - kfree(hdmi); +err_runtime_put: + hdmi_runtime_put(hdmi); return r; } @@ -817,15 +678,8 @@ static void hdmi4_unbind(struct device *dev, struct device *master, void *data) if (hdmi->audio_pdev) platform_device_unregister(hdmi->audio_pdev); - hdmi_uninit_output(hdmi); - hdmi4_cec_uninit(&hdmi->core); - hdmi_pll_uninit(&hdmi->pll); - - pm_runtime_disable(dev); - - kfree(hdmi); } static const struct component_ops hdmi4_component_ops = { @@ -833,42 +687,159 @@ static const struct component_ops hdmi4_component_ops = { .unbind = hdmi4_unbind, }; -static int hdmi4_probe(struct platform_device *pdev) +/* ----------------------------------------------------------------------------- + * Probe & Remove, Suspend & Resume + */ + +static int hdmi4_init_output(struct omap_hdmi *hdmi) { - return component_add(&pdev->dev, &hdmi4_component_ops); + struct omap_dss_device *out = &hdmi->output; + int r; + + out->dev = &hdmi->pdev->dev; + out->id = OMAP_DSS_OUTPUT_HDMI; + out->output_type = OMAP_DISPLAY_TYPE_HDMI; + out->name = "hdmi.0"; + out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; + out->ops = &hdmi_ops; + out->owner = THIS_MODULE; + out->of_ports = BIT(0); + out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; + + out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); + if (IS_ERR(out->next)) { + if (PTR_ERR(out->next) != -EPROBE_DEFER) + dev_err(out->dev, "failed to find video sink\n"); + return PTR_ERR(out->next); + } + + r = omapdss_output_validate(out); + if (r) { + omapdss_device_put(out->next); + out->next = NULL; + return r; + } + + omapdss_device_register(out); + + return 0; } -static int hdmi4_remove(struct platform_device *pdev) +static void hdmi4_uninit_output(struct omap_hdmi *hdmi) { - component_del(&pdev->dev, &hdmi4_component_ops); - return 0; + struct omap_dss_device *out = &hdmi->output; + + if (out->next) + omapdss_device_put(out->next); + omapdss_device_unregister(out); } -static int hdmi_runtime_suspend(struct device *dev) +static int hdmi4_probe_of(struct omap_hdmi *hdmi) { - struct omap_hdmi *hdmi = dev_get_drvdata(dev); + struct platform_device *pdev = hdmi->pdev; + struct device_node *node = pdev->dev.of_node; + struct device_node *ep; + int r; - dispc_runtime_put(hdmi->dss->dispc); + ep = of_graph_get_endpoint_by_regs(node, 0, 0); + if (!ep) + return 0; - return 0; + r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy); + of_node_put(ep); + return r; } -static int hdmi_runtime_resume(struct device *dev) +static int hdmi4_probe(struct platform_device *pdev) { - struct omap_hdmi *hdmi = dev_get_drvdata(dev); + struct omap_hdmi *hdmi; + int irq; int r; - r = dispc_runtime_get(hdmi->dss->dispc); - if (r < 0) - return r; + hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->pdev = pdev; + + dev_set_drvdata(&pdev->dev, hdmi); + + mutex_init(&hdmi->lock); + spin_lock_init(&hdmi->audio_playing_lock); + + r = hdmi4_probe_of(hdmi); + if (r) + goto err_free; + + r = hdmi_wp_init(pdev, &hdmi->wp, 4); + if (r) + goto err_free; + + r = hdmi_phy_init(pdev, &hdmi->phy, 4); + if (r) + goto err_free; + + r = hdmi4_core_init(pdev, &hdmi->core); + if (r) + goto err_free; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + DSSERR("platform_get_irq failed\n"); + r = -ENODEV; + goto err_free; + } + + r = devm_request_threaded_irq(&pdev->dev, irq, + NULL, hdmi_irq_handler, + IRQF_ONESHOT, "OMAP HDMI", hdmi); + if (r) { + DSSERR("HDMI IRQ request failed\n"); + goto err_free; + } + + hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda"); + if (IS_ERR(hdmi->vdda_reg)) { + r = PTR_ERR(hdmi->vdda_reg); + if (r != -EPROBE_DEFER) + DSSERR("can't get VDDA regulator\n"); + goto err_free; + } + + pm_runtime_enable(&pdev->dev); + + r = hdmi4_init_output(hdmi); + if (r) + goto err_pm_disable; + + r = component_add(&pdev->dev, &hdmi4_component_ops); + if (r) + goto err_uninit_output; return 0; + +err_uninit_output: + hdmi4_uninit_output(hdmi); +err_pm_disable: + pm_runtime_disable(&pdev->dev); +err_free: + kfree(hdmi); + return r; } -static const struct dev_pm_ops hdmi_pm_ops = { - .runtime_suspend = hdmi_runtime_suspend, - .runtime_resume = hdmi_runtime_resume, -}; +static int hdmi4_remove(struct platform_device *pdev) +{ + struct omap_hdmi *hdmi = platform_get_drvdata(pdev); + + component_del(&pdev->dev, &hdmi4_component_ops); + + hdmi4_uninit_output(hdmi); + + pm_runtime_disable(&pdev->dev); + + kfree(hdmi); + return 0; +} static const struct of_device_id hdmi_of_match[] = { { .compatible = "ti,omap4-hdmi", }, @@ -880,7 +851,6 @@ struct platform_driver omapdss_hdmi4hw_driver = { .remove = hdmi4_remove, .driver = { .name = "omapdss_hdmi", - .pm = &hdmi_pm_ops, .of_match_table = hdmi_of_match, .suppress_bind_attrs = true, }, |