diff options
author | Archit Taneja <architt@codeaurora.org> | 2016-05-30 11:06:50 (GMT) |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2016-07-16 14:08:56 (GMT) |
commit | 1dd0a0b18697e59c0928cea41b7e922e80d7d246 (patch) | |
tree | 7baae7fa7bf7bf90e998a0ce310cf8c7ad9eed8f | |
parent | 990a40079a55b81b5b6aef91a24aa053fb370072 (diff) | |
download | linux-1dd0a0b18697e59c0928cea41b7e922e80d7d246.tar.xz |
drm/msm/mdp5: Create a separate MDP5 device
In order to have a tree-like device hierarchy between MDSS and its
sub-blocks (MDP5, DSI, HDMI, eDP etc), we need to create a separate
device/driver for MDP5. Currently, MDP5 and MDSS are squashed
together are are tied to the top level platform_device, which is
also the one used to create drm_device.
The mdp5_kms_init code is split into two parts. The part where device
resources are allocated are associated with the MDP5 driver's probe,
the rest is executed later when we initialize modeset.
With this change, unlike MDP4, the MDP5 platform_device isn't tied to
the top level drm_device anymore. The top level drm_device is now
associated with a platform device that corresponds to MDSS wrapper
hardware.
Create mdp5_init/destroy funcs that will be used by the MDP5 driver
probe/remove. Use the HW_VERSION register in the MDP5 register address
space. Both the MDSS and MDP VERSION registers give out identical
version info.
The older mdp5_kms_init code is left as is for now, this would be removed
later when we have all the pieces to support the new device hierarchy.
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 185 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 3 |
4 files changed, 189 insertions, 3 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index e5b6361..fcb1bf4 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -111,7 +111,7 @@ static int mdp5_set_split_display(struct msm_kms *kms, return mdp5_encoder_set_split_display(encoder, slave_encoder); } -static void mdp5_destroy(struct msm_kms *kms) +static void mdp5_kms_destroy(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct msm_mmu *mmu = mdp5_kms->mmu; @@ -148,7 +148,7 @@ static const struct mdp_kms_funcs kms_funcs = { .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, .set_split_display = mdp5_set_split_display, - .destroy = mdp5_destroy, + .destroy = mdp5_kms_destroy, }, .set_irqmask = mdp5_set_irqmask, }; @@ -434,6 +434,21 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms, DBG("MDP5 version v%d.%d", *major, *minor); } +static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, + u32 *major, u32 *minor) +{ + u32 version; + + mdp5_enable(mdp5_kms); + version = mdp5_read(mdp5_kms, REG_MDP5_MDP_HW_VERSION(0)); + mdp5_disable(mdp5_kms); + + *major = FIELD(version, MDP5_MDP_HW_VERSION_MAJOR); + *minor = FIELD(version, MDP5_MDP_HW_VERSION_MINOR); + + DBG("MDP5 version v%d.%d", *major, *minor); +} + static int get_clk(struct platform_device *pdev, struct clk **clkp, const char *name, bool mandatory) { @@ -757,6 +772,170 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) fail: if (kms) - mdp5_destroy(kms); + mdp5_kms_destroy(kms); return ERR_PTR(ret); } + +static void mdp5_destroy(struct platform_device *pdev) +{ + struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); + + if (mdp5_kms->ctlm) + mdp5_ctlm_destroy(mdp5_kms->ctlm); + if (mdp5_kms->smp) + mdp5_smp_destroy(mdp5_kms->smp); + if (mdp5_kms->cfg) + mdp5_cfg_destroy(mdp5_kms->cfg); +} + +static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct mdp5_kms *mdp5_kms; + struct mdp5_cfg *config; + u32 major, minor; + int ret; + + mdp5_kms = devm_kzalloc(&pdev->dev, sizeof(*mdp5_kms), GFP_KERNEL); + if (!mdp5_kms) { + ret = -ENOMEM; + goto fail; + } + + platform_set_drvdata(pdev, mdp5_kms); + + spin_lock_init(&mdp5_kms->resource_lock); + + mdp5_kms->dev = dev; + mdp5_kms->pdev = pdev; + + mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); + if (IS_ERR(mdp5_kms->mmio)) { + ret = PTR_ERR(mdp5_kms->mmio); + goto fail; + } + + /* mandatory clocks: */ + ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk", true); + if (ret) + goto fail; + ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk", true); + if (ret) + goto fail; + ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk", true); + if (ret) + goto fail; + ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk", true); + if (ret) + goto fail; + + /* optional clocks: */ + get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk", false); + + /* we need to set a default rate before enabling. Set a safe + * rate first, then figure out hw revision, and then set a + * more optimal rate: + */ + clk_set_rate(mdp5_kms->core_clk, 200000000); + + read_mdp_hw_revision(mdp5_kms, &major, &minor); + + mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor); + if (IS_ERR(mdp5_kms->cfg)) { + ret = PTR_ERR(mdp5_kms->cfg); + mdp5_kms->cfg = NULL; + goto fail; + } + + config = mdp5_cfg_get_config(mdp5_kms->cfg); + mdp5_kms->caps = config->hw->mdp.caps; + + /* TODO: compute core clock rate at runtime */ + clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk); + + /* + * Some chipsets have a Shared Memory Pool (SMP), while others + * have dedicated latency buffering per source pipe instead; + * this section initializes the SMP: + */ + if (mdp5_kms->caps & MDP_CAP_SMP) { + mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); + if (IS_ERR(mdp5_kms->smp)) { + ret = PTR_ERR(mdp5_kms->smp); + mdp5_kms->smp = NULL; + goto fail; + } + } + + mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg); + if (IS_ERR(mdp5_kms->ctlm)) { + ret = PTR_ERR(mdp5_kms->ctlm); + mdp5_kms->ctlm = NULL; + goto fail; + } + + /* set uninit-ed kms */ + priv->kms = &mdp5_kms->base.base; + + return 0; +fail: + mdp5_destroy(pdev); + return ret; +} + +static int mdp5_bind(struct device *dev, struct device *master, void *data) +{ + struct drm_device *ddev = dev_get_drvdata(master); + struct platform_device *pdev = to_platform_device(dev); + + DBG(""); + + return mdp5_init(pdev, ddev); +} + +static void mdp5_unbind(struct device *dev, struct device *master, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + + mdp5_destroy(pdev); +} + +static const struct component_ops mdp5_ops = { + .bind = mdp5_bind, + .unbind = mdp5_unbind, +}; + +static int mdp5_dev_probe(struct platform_device *pdev) +{ + DBG(""); + return component_add(&pdev->dev, &mdp5_ops); +} + +static int mdp5_dev_remove(struct platform_device *pdev) +{ + DBG(""); + component_del(&pdev->dev, &mdp5_ops); + return 0; +} + +static struct platform_driver mdp5_driver = { + .probe = mdp5_dev_probe, + .remove = mdp5_dev_remove, + .driver = { + .name = "msm_mdp", + /* Add a DT match field once we move to new hierarchy */ + }, +}; + +void __init msm_mdp_register(void) +{ + DBG(""); + platform_driver_register(&mdp5_driver); +} + +void __exit msm_mdp_unregister(void) +{ + DBG(""); + platform_driver_unregister(&mdp5_driver); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 9cf5aa4..d681c02 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -31,6 +31,8 @@ struct mdp5_kms { struct drm_device *dev; + struct platform_device *pdev; + struct mdp5_cfg_handler *cfg; uint32_t caps; /* MDP capabilities (MDP_CAP_XXX bits) */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 092926b..5701392 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -876,6 +876,7 @@ static struct platform_driver msm_platform_driver = { static int __init msm_drm_register(void) { DBG("init"); + msm_mdp_register(); msm_dsi_register(); msm_edp_register(); msm_hdmi_register(); @@ -891,6 +892,7 @@ static void __exit msm_drm_unregister(void) adreno_unregister(); msm_edp_unregister(); msm_dsi_unregister(); + msm_mdp_unregister(); } module_init(msm_drm_register); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index a7acd83..be01e38 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -261,6 +261,9 @@ static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, } #endif +void __init msm_mdp_register(void); +void __exit msm_mdp_unregister(void); + #ifdef CONFIG_DEBUG_FS void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m); void msm_gem_describe_objects(struct list_head *list, struct seq_file *m); |