diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c')
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 94 |
1 files changed, 58 insertions, 36 deletions
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index dc47720c99ba..96532709c2a7 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -5,12 +5,12 @@ #include <linux/component.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_of.h> -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> +#include <drm/drm_simple_kms_helper.h> #include "sun8i_dw_hdmi.h" #include "sun8i_tcon_top.h" @@ -21,8 +21,7 @@ static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder, { struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder); - if (hdmi->quirks->set_rate) - clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000); + clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000); } static const struct drm_encoder_helper_funcs @@ -30,12 +29,9 @@ sun8i_dw_hdmi_encoder_helper_funcs = { .mode_set = sun8i_dw_hdmi_encoder_mode_set, }; -static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - static enum drm_mode_status -sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector, +sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, const struct drm_display_mode *mode) { if (mode->clock > 297000) @@ -45,10 +41,14 @@ sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector, } static enum drm_mode_status -sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector, +sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, const struct drm_display_mode *mode) { - /* This is max for HDMI 2.0b (4K@60Hz) */ + /* + * Controller support maximum of 594 MHz, which correlates to + * 4K@60Hz 4:4:4 or RGB. + */ if (mode->clock > 594000) return MODE_CLOCK_HIGH; @@ -129,22 +129,19 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, return -EPROBE_DEFER; hdmi->rst_ctrl = devm_reset_control_get(dev, "ctrl"); - if (IS_ERR(hdmi->rst_ctrl)) { - dev_err(dev, "Could not get ctrl reset control\n"); - return PTR_ERR(hdmi->rst_ctrl); - } + if (IS_ERR(hdmi->rst_ctrl)) + return dev_err_probe(dev, PTR_ERR(hdmi->rst_ctrl), + "Could not get ctrl reset control\n"); hdmi->clk_tmds = devm_clk_get(dev, "tmds"); - if (IS_ERR(hdmi->clk_tmds)) { - dev_err(dev, "Couldn't get the tmds clock\n"); - return PTR_ERR(hdmi->clk_tmds); - } + if (IS_ERR(hdmi->clk_tmds)) + return dev_err_probe(dev, PTR_ERR(hdmi->clk_tmds), + "Couldn't get the tmds clock\n"); hdmi->regulator = devm_regulator_get(dev, "hvcc"); - if (IS_ERR(hdmi->regulator)) { - dev_err(dev, "Couldn't get regulator\n"); - return PTR_ERR(hdmi->regulator); - } + if (IS_ERR(hdmi->regulator)) + return dev_err_probe(dev, PTR_ERR(hdmi->regulator), + "Couldn't get regulator\n"); ret = regulator_enable(hdmi->regulator); if (ret) { @@ -167,23 +164,26 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, phy_node = of_parse_phandle(dev->of_node, "phys", 0); if (!phy_node) { dev_err(dev, "Can't found PHY phandle\n"); + ret = -EINVAL; goto err_disable_clk_tmds; } - ret = sun8i_hdmi_phy_probe(hdmi, phy_node); + ret = sun8i_hdmi_phy_get(hdmi, phy_node); of_node_put(phy_node); if (ret) { dev_err(dev, "Couldn't get the HDMI PHY\n"); goto err_disable_clk_tmds; } - drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs); - drm_encoder_init(drm, encoder, &sun8i_dw_hdmi_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); + ret = sun8i_hdmi_phy_init(hdmi->phy); + if (ret) + goto err_disable_clk_tmds; - sun8i_hdmi_phy_init(hdmi->phy); + drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs); + drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); plat_data->mode_valid = hdmi->quirks->mode_valid; + plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe; sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data); platform_set_drvdata(pdev, hdmi); @@ -203,7 +203,6 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, cleanup_encoder: drm_encoder_cleanup(encoder); - sun8i_hdmi_phy_remove(hdmi); err_disable_clk_tmds: clk_disable_unprepare(hdmi->clk_tmds); err_assert_ctrl_reset: @@ -220,7 +219,7 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master, struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev); dw_hdmi_unbind(hdmi->hdmi); - sun8i_hdmi_phy_remove(hdmi); + sun8i_hdmi_phy_deinit(hdmi->phy); clk_disable_unprepare(hdmi->clk_tmds); reset_control_assert(hdmi->rst_ctrl); regulator_disable(hdmi->regulator); @@ -236,20 +235,18 @@ static int sun8i_dw_hdmi_probe(struct platform_device *pdev) return component_add(&pdev->dev, &sun8i_dw_hdmi_ops); } -static int sun8i_dw_hdmi_remove(struct platform_device *pdev) +static void sun8i_dw_hdmi_remove(struct platform_device *pdev) { component_del(&pdev->dev, &sun8i_dw_hdmi_ops); - - return 0; } static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = { .mode_valid = sun8i_dw_hdmi_mode_valid_a83t, - .set_rate = true, }; static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = { .mode_valid = sun8i_dw_hdmi_mode_valid_h6, + .use_drm_infoframe = true, }; static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = { @@ -273,7 +270,32 @@ static struct platform_driver sun8i_dw_hdmi_pltfm_driver = { .of_match_table = sun8i_dw_hdmi_dt_ids, }, }; -module_platform_driver(sun8i_dw_hdmi_pltfm_driver); + +static int __init sun8i_dw_hdmi_init(void) +{ + int ret; + + ret = platform_driver_register(&sun8i_dw_hdmi_pltfm_driver); + if (ret) + return ret; + + ret = platform_driver_register(&sun8i_hdmi_phy_driver); + if (ret) { + platform_driver_unregister(&sun8i_dw_hdmi_pltfm_driver); + return ret; + } + + return ret; +} + +static void __exit sun8i_dw_hdmi_exit(void) +{ + platform_driver_unregister(&sun8i_dw_hdmi_pltfm_driver); + platform_driver_unregister(&sun8i_hdmi_phy_driver); +} + +module_init(sun8i_dw_hdmi_init); +module_exit(sun8i_dw_hdmi_exit); MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>"); MODULE_DESCRIPTION("Allwinner DW HDMI bridge"); |
