diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2017-01-28 00:47:17 -0800 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-01-28 00:47:16 -0800 |
| commit | c619082d26a71475d8d97edb573f7fc879982e65 (patch) | |
| tree | c4b8720c877cdc8e01176d37bf8cff91fa751885 | |
| parent | ff528055ec669b0db90a7f5dae00fd101e57f4c8 (diff) | |
| parent | df131b2a71acd57e96e23fe2c2bbd4867159cf48 (diff) | |
Merge "Revert "drm/msm: add smmu handler""
34 files changed, 402 insertions, 5641 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 05b6ca9b5c55..f8984d673ff0 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -40,10 +40,7 @@ msm-y := \ mdp/mdp5/mdp5_smp.o \ sde/sde_crtc.o \ sde/sde_encoder.o \ - sde/sde_encoder_phys_vid.o \ - sde/sde_encoder_phys_cmd.o \ sde/sde_irq.o \ - sde/sde_kms_utils.o \ sde/sde_kms.o \ sde/sde_plane.o \ msm_atomic.o \ @@ -54,7 +51,6 @@ msm-y := \ msm_gem_submit.o \ msm_gpu.o \ msm_iommu.o \ - msm_smmu.o \ msm_perf.o \ msm_rd.o \ msm_ringbuffer.o @@ -89,7 +85,4 @@ obj-$(CONFIG_DRM_MSM) += sde/sde_hw_catalog.o \ sde/sde_hw_mdp_util.o \ sde/sde_hw_sspp.o \ sde/sde_hw_wb.o \ - sde/sde_hw_pingpong.o \ - sde/sde_hw_mdp_top.o \ - sde/sde_hw_interrupts.o \ - sde/sde_mdp_formats.o + sde/sde_hw_pingpong.o diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 210cedb8134d..b532faa8026d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2014, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -595,8 +595,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) mdelay(16); if (config->platform.iommu) { - mmu = msm_smmu_new(&pdev->dev, - MSM_SMMU_DOMAIN_UNSECURE); + mmu = msm_iommu_new(&pdev->dev, config->platform.iommu); if (IS_ERR(mmu)) { ret = PTR_ERR(mmu); dev_err(dev->dev, "failed to init iommu: %d\n", ret); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 6fa56abf0c78..c76cc853b08a 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -295,23 +295,16 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, if (iommu_present(&platform_bus_type)) { struct msm_mmu *mmu = priv->mmus[id]; + uint32_t offset; if (WARN_ON(!mmu)) return -EINVAL; - if (obj->import_attach && mmu->funcs->map_dma_buf) { - ret = mmu->funcs->map_dma_buf(mmu, msm_obj->sgt, - obj->import_attach->dmabuf, - DMA_BIDIRECTIONAL); - if (ret) { - DRM_ERROR("Unable to map dma buf\n"); - return ret; - } - } - msm_obj->domain[id].iova = - sg_dma_address(msm_obj->sgt->sgl); + offset = (uint32_t)mmap_offset(obj); + ret = mmu->funcs->map(mmu, offset, msm_obj->sgt, + obj->size, IOMMU_READ | IOMMU_WRITE); + msm_obj->domain[id].iova = offset; } else { - WARN_ONCE(1, "physical address being used\n"); msm_obj->domain[id].iova = physaddr(obj); } } @@ -531,11 +524,8 @@ void msm_gem_free_object(struct drm_gem_object *obj) for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { struct msm_mmu *mmu = priv->mmus[id]; if (mmu && msm_obj->domain[id].iova) { - if (obj->import_attach && mmu->funcs->unmap_dma_buf) { - mmu->funcs->unmap_dma_buf(mmu, msm_obj->sgt, - obj->import_attach->dmabuf, - DMA_BIDIRECTIONAL); - } + uint32_t offset = msm_obj->domain[id].iova; + mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size); } } diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 2e4ae6b1c5d0..6fc59bfeedeb 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -53,7 +53,8 @@ struct msm_gem_object { void *vaddr; struct { - dma_addr_t iova; + // XXX + uint32_t iova; } domain[NUM_DOMAINS]; /* normally (resv == &_resv) except for imported bo's */ diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 6d2f5627bfae..7cd88d9dc155 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -20,14 +20,6 @@ #include <linux/iommu.h> -struct msm_mmu; -struct msm_gpu; - -enum msm_mmu_domain_type { - MSM_SMMU_DOMAIN_UNSECURE, - MSM_SMMU_DOMAIN_MAX, -}; - struct msm_mmu_funcs { int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); void (*detach)(struct msm_mmu *mmu, const char **names, int cnt); @@ -35,14 +27,6 @@ struct msm_mmu_funcs { unsigned len, int prot); int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, unsigned len); - int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir); - void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir); - int (*map_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir); - void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir); void (*destroy)(struct msm_mmu *mmu); }; @@ -60,7 +44,5 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu); -struct msm_mmu *msm_smmu_new(struct device *dev, - enum msm_mmu_domain_type domain); #endif /* __MSM_MMU_H__ */ diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c deleted file mode 100644 index d51fbedf90c6..000000000000 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ /dev/null @@ -1,432 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/pm_runtime.h> -#include <linux/msm_dma_iommu_mapping.h> - -#include <asm/dma-iommu.h> -#include <soc/qcom/secure_buffer.h> - -#include "msm_drv.h" -#include "msm_mmu.h" - -struct msm_smmu_client { - struct device *dev; - struct dma_iommu_mapping *mmu_mapping; - bool domain_attached; -}; - -struct msm_smmu { - struct msm_mmu base; - struct device *client_dev; - struct msm_smmu_client client; -}; - -struct msm_smmu_domain { - const char *label; - size_t va_start; - size_t va_size; - bool secure; -}; - -#define to_msm_smmu(x) container_of(x, struct msm_smmu, base) -#define msm_smmu_to_client(smmu) (&smmu->client) - -static int _msm_smmu_create_mapping(struct msm_smmu_client *client, - const struct msm_smmu_domain *domain); - -static int msm_smmu_attach(struct msm_mmu *mmu, const char **names, int cnt) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int rc = 0; - - /* domain attach only once */ - if (client->domain_attached) - return 0; - - rc = arm_iommu_attach_device(client->dev, - client->mmu_mapping); - if (rc) { - dev_err(client->dev, "iommu attach dev failed (%d)\n", - rc); - return rc; - } - - client->domain_attached = true; - - dev_dbg(client->dev, "iommu domain attached\n"); - - return 0; -} - -static void msm_smmu_detach(struct msm_mmu *mmu, const char **names, int cnt) -{ - DBG("detaching"); -} - -static int msm_smmu_map(struct msm_mmu *mmu, uint32_t iova, - struct sg_table *sgt, unsigned len, int prot) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; - struct scatterlist *sg; - unsigned int da = iova; - unsigned int i, j; - int ret; - - if (!client) - return -ENODEV; - - domain = client->mmu_mapping->domain; - if (!domain || !sgt) - return -EINVAL; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - u32 pa = sg_phys(sg) - sg->offset; - size_t bytes = sg->length + sg->offset; - - VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes); - - ret = iommu_map(domain, da, pa, bytes, prot); - if (ret) - goto fail; - - da += bytes; - } - - return 0; - -fail: - da = iova; - - for_each_sg(sgt->sgl, sg, i, j) { - size_t bytes = sg->length + sg->offset; - - iommu_unmap(domain, da, bytes); - da += bytes; - } - return ret; -} - -static int msm_smmu_map_sg(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int ret; - - ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, dir); - if (ret != sgt->nents) - return -ENOMEM; - - return 0; -} - -static void msm_smmu_unmap_sg(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - - dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir); -} - -static int msm_smmu_unmap(struct msm_mmu *mmu, uint32_t iova, - struct sg_table *sgt, unsigned len) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; - struct scatterlist *sg; - unsigned int da = iova; - int i; - - if (!client) - return -ENODEV; - - domain = client->mmu_mapping->domain; - if (!domain || !sgt) - return -EINVAL; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - size_t bytes = sg->length + sg->offset; - size_t unmapped; - - unmapped = iommu_unmap(domain, da, bytes); - if (unmapped < bytes) - return unmapped; - - VERB("unmap[%d]: %08x(%zx)", i, iova, bytes); - - WARN_ON(!PAGE_ALIGNED(bytes)); - - da += bytes; - } - - return 0; -} - -static void msm_smmu_destroy(struct msm_mmu *mmu) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct platform_device *pdev = to_platform_device(smmu->client_dev); - - platform_device_unregister(pdev); - kfree(smmu); -} - -static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int ret; - - ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents, dir, - dma_buf); - if (ret != sgt->nents) { - DRM_ERROR("dma map sg failed\n"); - return -ENOMEM; - } - - return 0; -} - - -static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - - msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf); -} - -static const struct msm_mmu_funcs funcs = { - .attach = msm_smmu_attach, - .detach = msm_smmu_detach, - .map = msm_smmu_map, - .map_sg = msm_smmu_map_sg, - .unmap_sg = msm_smmu_unmap_sg, - .unmap = msm_smmu_unmap, - .map_dma_buf = msm_smmu_map_dma_buf, - .unmap_dma_buf = msm_smmu_unmap_dma_buf, - .destroy = msm_smmu_destroy, -}; - -static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = { - [MSM_SMMU_DOMAIN_UNSECURE] = { - .label = "mdp_ns", - .va_start = SZ_1M, - .va_size = SZ_2G, - }, -}; - -static const struct of_device_id msm_smmu_dt_match[] = { - { .compatible = "qcom,smmu_mdp_unsec", - .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_UNSECURE] }, - {} -}; -MODULE_DEVICE_TABLE(of, msm_smmu_dt_match); - -static struct device *msm_smmu_device_create(struct device *dev, - enum msm_mmu_domain_type domain, - struct msm_smmu *smmu) -{ - struct device_node *child; - struct platform_device *pdev; - int i; - const char *compat = NULL; - - for (i = 0; i < ARRAY_SIZE(msm_smmu_dt_match); i++) { - if (msm_smmu_dt_match[i].data == &msm_smmu_domains[domain]) { - compat = msm_smmu_dt_match[i].compatible; - break; - } - } - - if (!compat) { - DRM_ERROR("unable to find matching domain for %d\n", domain); - return ERR_PTR(-ENOENT); - } - DRM_INFO("found domain %d compat: %s\n", domain, compat); - - if (domain == MSM_SMMU_DOMAIN_UNSECURE) { - int rc; - - smmu->client.dev = dev; - rc = _msm_smmu_create_mapping(msm_smmu_to_client(smmu), - msm_smmu_dt_match[i].data); - if (rc) - return ERR_PTR(rc); - - return NULL; - } - - child = of_find_compatible_node(dev->of_node, NULL, compat); - if (!child) { - DRM_ERROR("unable to find compatible node for %s\n", compat); - return ERR_PTR(-ENODEV); - } - - pdev = of_platform_device_create(child, NULL, dev); - if (!pdev) { - DRM_ERROR("unable to create smmu platform dev for domain %d\n", - domain); - return ERR_PTR(-ENODEV); - } - - return &pdev->dev; -} - -struct msm_mmu *msm_smmu_new(struct device *dev, - enum msm_mmu_domain_type domain) -{ - struct msm_smmu *smmu; - struct device *client_dev; - - smmu = kzalloc(sizeof(*smmu), GFP_KERNEL); - if (!smmu) - return ERR_PTR(-ENOMEM); - - client_dev = msm_smmu_device_create(dev, domain, smmu); - if (IS_ERR(client_dev)) - return (void *)client_dev ? : ERR_PTR(-ENODEV); - - smmu->client_dev = client_dev; - msm_mmu_init(&smmu->base, dev, &funcs); - - return &smmu->base; -} - -static int _msm_smmu_create_mapping(struct msm_smmu_client *client, - const struct msm_smmu_domain *domain) -{ - int disable_htw = 1; - int rc; - - client->mmu_mapping = arm_iommu_create_mapping(&platform_bus_type, - domain->va_start, domain->va_size); - if (IS_ERR(client->mmu_mapping)) { - dev_err(client->dev, - "iommu create mapping failed for domain=%s\n", - domain->label); - return PTR_ERR(client->mmu_mapping); - } - - if (domain->secure) { - int secure_vmid = VMID_CP_PIXEL; - - rc = iommu_domain_set_attr(client->mmu_mapping->domain, - DOMAIN_ATTR_SECURE_VMID, &secure_vmid); - if (rc) { - dev_err(client->dev, "couldn't set secure pix vmid\n"); - goto error; - } - } - - return 0; - -error: - arm_iommu_release_mapping(client->mmu_mapping); - return rc; -} - -/** - * msm_smmu_probe() - * @pdev: platform device - * - * Each smmu context acts as a separate device and the context banks are - * configured with a VA range. - * Registers the clks as each context bank has its own clks, for which voting - * has to be done everytime before using that context bank. - */ -static int msm_smmu_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct msm_smmu_client *client; - const struct msm_smmu_domain *domain; - int rc; - - match = of_match_device(msm_smmu_dt_match, &pdev->dev); - if (!match || !match->data) { - dev_err(&pdev->dev, "probe failed as match data is invalid\n"); - return -EINVAL; - } - - domain = match->data; - if (!domain) { - dev_err(&pdev->dev, "no matching device found\n"); - return -EINVAL; - } - - DRM_INFO("probing device %s\n", match->compatible); - - client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - client->dev = &pdev->dev; - - rc = _msm_smmu_create_mapping(client, domain); - platform_set_drvdata(pdev, client); - - return rc; -} - -static int msm_smmu_remove(struct platform_device *pdev) -{ - struct msm_smmu_client *client; - - client = platform_get_drvdata(pdev); - if (client->domain_attached) { - arm_iommu_detach_device(client->dev); - client->domain_attached = false; - } - arm_iommu_release_mapping(client->mmu_mapping); - - return 0; -} - -static struct platform_driver msm_smmu_driver = { - .probe = msm_smmu_probe, - .remove = msm_smmu_remove, - .driver = { - .name = "msmdrm_smmu", - .of_match_table = msm_smmu_dt_match, - }, -}; - -static int __init msm_smmu_driver_init(void) -{ - int ret; - - ret = platform_driver_register(&msm_smmu_driver); - if (ret) - pr_err("mdss_smmu_register_driver() failed!\n"); - - return ret; -} -module_init(msm_smmu_driver_init); - -static void __exit msm_smmu_driver_cleanup(void) -{ - platform_driver_unregister(&msm_smmu_driver); -} -module_exit(msm_smmu_driver_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("MSM SMMU driver"); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 5fc1664fd9a0..3ddad6f59180 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -10,7 +10,6 @@ * GNU General Public License for more details. */ -#include <linux/sort.h> #include <drm/drm_mode.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> @@ -18,498 +17,73 @@ #include "sde_kms.h" #include "sde_hw_lm.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_crtc.h" +#include "sde_hw_mdss.h" -#define CTL(i) (CTL_0 + (i)) -#define LM(i) (LM_0 + (i)) -#define INTF(i) (INTF_0 + (i)) - -static struct sde_kms *get_kms(struct drm_crtc *crtc) -{ - struct msm_drm_private *priv = crtc->dev->dev_private; - return to_sde_kms(priv->kms); -} - -static int sde_crtc_reserve_hw_resources(struct drm_crtc *crtc, - struct drm_encoder *encoder) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_kms *sde_kms = get_kms(crtc); - struct sde_encoder_hw_resources enc_hw_res; - const struct sde_hw_res_map *plat_hw_res_map; - enum sde_lm unused_lm_id[CRTC_DUAL_MIXERS] = {0}; - enum sde_lm lm_idx; - int i, count = 0; - - if (!sde_kms) { - DBG("[%s] invalid kms", __func__); - return -EINVAL; - } - - if (!sde_kms->mmio) - return -EINVAL; - - /* Get unused LMs */ - for (i = 0; i < sde_kms->catalog->mixer_count; i++) { - if (!sde_rm_get_mixer(sde_kms, LM(i))) { - unused_lm_id[count++] = LM(i); - if (count == CRTC_DUAL_MIXERS) - break; - } - } - - /* query encoder resources */ - sde_encoder_get_hw_resources(sde_crtc->encoder, &enc_hw_res); - - /* parse encoder hw resources, find CTL paths */ - for (i = CTL_0; i <= sde_kms->catalog->ctl_count; i++) { - WARN_ON(sde_crtc->num_ctls > CRTC_DUAL_MIXERS); - if (enc_hw_res.ctls[i]) { - struct sde_crtc_mixer *mixer = - &sde_crtc->mixer[sde_crtc->num_ctls]; - mixer->hw_ctl = sde_rm_get_ctl_path(sde_kms, i); - if (IS_ERR_OR_NULL(mixer->hw_ctl)) { - DBG("[%s], Invalid ctl_path", __func__); - return -EACCES; - } - sde_crtc->num_ctls++; - } - } - - /* shortcut this process if encoder has no ctl paths */ - if (!sde_crtc->num_ctls) - return 0; - - /* - * Get default LMs if specified in platform config - * other wise acquire the free LMs - */ - for (i = INTF_0; i <= sde_kms->catalog->intf_count; i++) { - if (enc_hw_res.intfs[i]) { - struct sde_crtc_mixer *mixer = - &sde_crtc->mixer[sde_crtc->num_mixers]; - plat_hw_res_map = sde_rm_get_res_map(sde_kms, i); - - lm_idx = plat_hw_res_map->lm; - if (!lm_idx) - lm_idx = unused_lm_id[sde_crtc->num_mixers]; - - DBG("Acquiring LM %d", lm_idx); - mixer->hw_lm = sde_rm_acquire_mixer(sde_kms, lm_idx); - if (IS_ERR_OR_NULL(mixer->hw_lm)) { - DBG("[%s], Invalid mixer", __func__); - return -EACCES; - } - /* interface info */ - mixer->intf_idx = i; - mixer->mode = enc_hw_res.intfs[i]; - sde_crtc->num_mixers++; - } - } +struct sde_crtc { + struct drm_crtc base; + char name[8]; + struct drm_plane *plane; + struct drm_plane *planes[8]; + int id; + bool enabled; + enum sde_lm mixer; + enum sde_ctl ctl_path; +}; - DBG("control paths %d, num_mixers %d, lm[0] %d, ctl[0] %d ", - sde_crtc->num_ctls, sde_crtc->num_mixers, - sde_crtc->mixer[0].hw_lm->idx, - sde_crtc->mixer[0].hw_ctl->idx); - if (sde_crtc->num_mixers == CRTC_DUAL_MIXERS) - DBG("lm[1] %d, ctl[1], %d", - sde_crtc->mixer[1].hw_lm->idx, - sde_crtc->mixer[1].hw_ctl->idx); - return 0; -} +#define to_sde_crtc(x) container_of(x, struct sde_crtc, base) static void sde_crtc_destroy(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - DBG(""); drm_crtc_cleanup(crtc); kfree(sde_crtc); } +static void sde_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +} + static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - DBG(""); return true; } -static void sde_crtc_mode_set_nofb(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_crtc_mixer *mixer = sde_crtc->mixer; - struct drm_device *dev = crtc->dev; - struct sde_hw_mixer *lm; - unsigned long flags; - struct drm_display_mode *mode; - struct sde_hw_mixer_cfg cfg; - u32 mixer_width; - int i; - int rc; - - DBG(""); - if (WARN_ON(!crtc->state)) - return; - - mode = &crtc->state->adjusted_mode; - - DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - sde_crtc->name, mode->base.id, mode->name, - mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, - mode->type, mode->flags); - - /* - * reserve mixer(s) if not already avaialable - * if dual mode, mixer_width = half mode width - * program mode configuration on mixer(s) - */ - if ((sde_crtc->num_ctls == 0) || - (sde_crtc->num_mixers == 0)) { - rc = sde_crtc_reserve_hw_resources(crtc, sde_crtc->encoder); - if (rc) { - dev_err(dev->dev, " error reserving HW resource for this CRTC\n"); - return; - } - } - - if (sde_crtc->num_mixers == CRTC_DUAL_MIXERS) - mixer_width = mode->hdisplay >> 1; - else - mixer_width = mode->hdisplay; - - spin_lock_irqsave(&sde_crtc->lm_lock, flags); - - for (i = 0; i < sde_crtc->num_mixers; i++) { - lm = mixer[i].hw_lm; - cfg.out_width = mixer_width; - cfg.out_height = mode->vdisplay; - cfg.right_mixer = (i == 0) ? false : true; - cfg.flags = 0; - lm->ops.setup_mixer_out(lm, &cfg); - } - - spin_unlock_irqrestore(&sde_crtc->lm_lock, flags); -} - -static void sde_crtc_get_blend_cfg(struct sde_hw_blend_cfg *cfg, - struct sde_plane_state *pstate) -{ - const struct mdp_format *format; - struct drm_plane *plane; - - format = to_mdp_format( - msm_framebuffer_format(pstate->base.fb)); - plane = pstate->base.plane; - - cfg->fg.alpha_sel = ALPHA_FG_CONST; - cfg->bg.alpha_sel = ALPHA_BG_CONST; - cfg->fg.const_alpha = pstate->alpha; - cfg->bg.const_alpha = 0xFF - pstate->alpha; - - if (format->alpha_enable && pstate->premultiplied) { - cfg->fg.alpha_sel = ALPHA_FG_CONST; - cfg->bg.alpha_sel = ALPHA_FG_PIXEL; - if (pstate->alpha != 0xff) { - cfg->bg.const_alpha = pstate->alpha; - cfg->bg.inv_alpha_sel = 1; - cfg->bg.mod_alpha = 1; - } else { - cfg->bg.inv_mode_alpha = 1; - } - } else if (format->alpha_enable) { - cfg->fg.alpha_sel = ALPHA_FG_PIXEL; - cfg->bg.alpha_sel = ALPHA_FG_PIXEL; - if (pstate->alpha != 0xff) { - cfg->bg.const_alpha = pstate->alpha; - cfg->fg.mod_alpha = 1; - cfg->bg.inv_alpha_sel = 1; - cfg->bg.mod_alpha = 1; - cfg->bg.inv_mode_alpha = 1; - } else { - cfg->bg.inv_mode_alpha = 1; - } - } -} - -static void blend_setup(struct drm_crtc *crtc) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_crtc_mixer *mixer = sde_crtc->mixer; - struct drm_plane *plane; - struct sde_plane_state *pstate, *pstates[SDE_STAGE_MAX] = {0}; - struct sde_hw_stage_cfg stage_cfg; - struct sde_hw_blend_cfg blend; - struct sde_hw_ctl *ctl; - struct sde_hw_mixer *lm; - u32 flush_mask = 0; - unsigned long flags; - int i, j, plane_cnt = 0; - - DBG(""); - spin_lock_irqsave(&sde_crtc->lm_lock, flags); - - /* ctl could be reserved already */ - if (!sde_crtc->num_ctls) - goto out; - - /* initialize stage cfg */ - memset(&stage_cfg, 0, sizeof(stage_cfg)); - memset(&blend, 0, sizeof(blend)); - - /* Collect all plane information */ - drm_atomic_crtc_for_each_plane(plane, crtc) { - pstate = to_sde_plane_state(plane->state); - pstates[pstate->stage] = pstate; - plane_cnt++; - for (i = 0; i < sde_crtc->num_mixers; i++) { - stage_cfg.stage[pstate->stage][i] = - sde_plane_pipe(plane); - - /* Cache the flushmask for this layer - * sourcesplit is always enabled, so this layer will - * be staged on both the mixers - */ - ctl = mixer[i].hw_ctl; - ctl->ops.get_bitmask_sspp(ctl, &flush_mask, - sde_plane_pipe(plane)); - } - } - - /* - * If there is no base layer, enable border color. - * currently border color is always black - */ - if ((stage_cfg.stage[SDE_STAGE_BASE][0] == SSPP_NONE) && - plane_cnt) { - stage_cfg.border_enable = 1; - DBG("Border Color is enabled\n"); - } - - /* Program hw */ - for (i = 0; i < sde_crtc->num_mixers; i++) { - if (!mixer[i].hw_lm) - continue; - - if (!mixer[i].hw_ctl) - continue; - - ctl = mixer[i].hw_ctl; - lm = mixer[i].hw_lm; - - /* stage config */ - ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, - &stage_cfg); - /* stage config flush mask */ - mixer[i].flush_mask = flush_mask; - /* get the flush mask for mixer */ - ctl->ops.get_bitmask_mixer(ctl, &mixer[i].flush_mask, - mixer[i].hw_lm->idx); - - /* blend config */ - for (j = SDE_STAGE_0; j < SDE_STAGE_MAX; j++) { - if (!pstates[j]) - continue; - sde_crtc_get_blend_cfg(&blend, pstates[j]); - blend.fg.alpha_sel = ALPHA_FG_CONST; - blend.bg.alpha_sel = ALPHA_BG_CONST; - blend.fg.const_alpha = pstate->alpha; - blend.bg.const_alpha = 0xFF - pstate->alpha; - lm->ops.setup_blend_config(lm, j, &blend); - } - } -out: - spin_unlock_irqrestore(&sde_crtc->lm_lock, flags); -} - -/* if file!=NULL, this is preclose potential cancel-flip path */ -static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct drm_pending_vblank_event *event; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - event = sde_crtc->event; - if (event) { - /* if regular vblank case (!file) or if cancel-flip from - * preclose on file that requested flip, then send the - * event: - */ - if (!file || (event->base.file_priv == file)) { - sde_crtc->event = NULL; - DBG("%s: send event: %pK", sde_crtc->name, event); - drm_send_vblank_event(dev, sde_crtc->id, event); - } - } - spin_unlock_irqrestore(&dev->event_lock, flags); -} - -static void sde_crtc_vblank_cb(void *data) -{ - struct drm_crtc *crtc = (struct drm_crtc *)data; - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - unsigned pending; - - /* unregister callback */ - sde_encoder_register_vblank_callback(sde_crtc->encoder, NULL, NULL); - - pending = atomic_xchg(&sde_crtc->pending, 0); - - if (pending & PENDING_FLIP) - complete_flip(crtc, NULL); -} - -static int frame_flushed(struct sde_crtc *sde_crtc) +static int sde_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) { - struct vsync_info vsync; - - /* encoder get vsync_info */ - /* if frame_count does not match frame is flushed */ - sde_encoder_get_vsync_info(sde_crtc->encoder, &vsync); - - return (vsync.frame_count & sde_crtc->vsync_count); - + return 0; } -void sde_crtc_wait_for_commit_done(struct drm_crtc *crtc) +static void sde_crtc_prepare(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - u32 pending; - int i, ret; - - /* ref count the vblank event */ - ret = drm_crtc_vblank_get(crtc); - if (ret) - return; - - /* register callback */ - sde_encoder_register_vblank_callback(sde_crtc->encoder, - sde_crtc_vblank_cb, - (void *)crtc); - - /* wait */ - pending = atomic_read(&sde_crtc->pending); - if (pending & PENDING_FLIP) { - wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, - (frame_flushed(sde_crtc) != 0), - msecs_to_jiffies(CRTC_MAX_WAIT_ONE_FRAME)); - if (ret <= 0) - dev_warn(dev->dev, "vblank time out, crtc=%d\n", - sde_crtc->id); - } - - for (i = 0; i < sde_crtc->num_ctls; i++) - sde_crtc->mixer[i].flush_mask = 0; - - /* release */ - drm_crtc_vblank_put(crtc); } -static void request_pending(struct drm_crtc *crtc, u32 pending) +static void sde_crtc_commit(struct drm_crtc *crtc) { - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct vsync_info vsync; - - /* request vsync info, cache the current frame count */ - sde_encoder_get_vsync_info(sde_crtc->encoder, &vsync); - sde_crtc->vsync_count = vsync.frame_count; - - atomic_or(pending, &sde_crtc->pending); } -/** - * Flush the CTL PATH - */ -static u32 crtc_flush_all(struct drm_crtc *crtc) +static int sde_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) { - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_hw_ctl *ctl; - int i; - - DBG(""); - - for (i = 0; i < sde_crtc->num_ctls; i++) { - ctl = sde_crtc->mixer[i].hw_ctl; - ctl->ops.get_bitmask_intf(ctl, - &(sde_crtc->mixer[i].flush_mask), - sde_crtc->mixer[i].intf_idx); - DBG("Flushing CTL_ID %d, flush_mask %x", ctl->idx, - sde_crtc->mixer[i].flush_mask); - ctl->ops.setup_flush(ctl, - sde_crtc->mixer[i].flush_mask); - } - return 0; } -static void sde_crtc_atomic_begin(struct drm_crtc *crtc, - struct drm_crtc_state *old_crtc_state) +static void sde_crtc_load_lut(struct drm_crtc *crtc) { - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct drm_device *dev = crtc->dev; - unsigned long flags; - - DBG(""); - - WARN_ON(sde_crtc->event); - - spin_lock_irqsave(&dev->event_lock, flags); - sde_crtc->event = crtc->state->event; - spin_unlock_irqrestore(&dev->event_lock, flags); - - /* - * If no CTL has been allocated in sde_crtc_atomic_check(), - * it means we are trying to flush a CRTC whose state is disabled: - * nothing else needs to be done. - */ - if (unlikely(!sde_crtc->num_ctls)) - return; - - blend_setup(crtc); - - /* - * PP_DONE irq is only used by command mode for now. - * It is better to request pending before FLUSH and START trigger - * to make sure no pp_done irq missed. - * This is safe because no pp_done will happen before SW trigger - * in command mode. - */ } -static void sde_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_crtc_state *old_crtc_state) +static int sde_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *new_fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) { - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct drm_device *dev = crtc->dev; - unsigned long flags; - - DBG("%s: event: %pK", sde_crtc->name, crtc->state->event); - - WARN_ON(sde_crtc->event); - - spin_lock_irqsave(&dev->event_lock, flags); - sde_crtc->event = crtc->state->event; - spin_unlock_irqrestore(&dev->event_lock, flags); - - /* - * If no CTL has been allocated in sde_crtc_atomic_check(), - * it means we are trying to flush a CRTC whose state is disabled: - * nothing else needs to be done. - */ - if (unlikely(!sde_crtc->num_ctls)) - return; - - crtc_flush_all(crtc); - - request_pending(crtc, PENDING_FLIP); + return 0; } static int sde_crtc_set_property(struct drm_crtc *crtc, @@ -518,111 +92,21 @@ static int sde_crtc_set_property(struct drm_crtc *crtc, return -EINVAL; } -static int sde_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file, uint32_t handle, - uint32_t width, uint32_t height) -{ - return 0; -} - -static int sde_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) -{ - return 0; -} - -static void sde_crtc_disable(struct drm_crtc *crtc) -{ - DBG(""); -} - -static void sde_crtc_enable(struct drm_crtc *crtc) -{ - DBG(""); -} - -struct plane_state { - struct drm_plane *plane; - struct sde_plane_state *state; -}; - -static int pstate_cmp(const void *a, const void *b) -{ - struct plane_state *pa = (struct plane_state *)a; - struct plane_state *pb = (struct plane_state *)b; - - return pa->state->zpos - pb->state->zpos; -} - -static int sde_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - struct sde_crtc *sde_crtc = to_sde_crtc(crtc); - struct sde_kms *sde_kms = get_kms(crtc); - struct drm_plane *plane; - struct drm_device *dev = crtc->dev; - struct plane_state pstates[SDE_STAGE_MAX]; - int max_stages = CRTC_HW_MIXER_MAXSTAGES(sde_kms->catalog, 0); - int cnt = 0, i; - - DBG("%s: check", sde_crtc->name); - - /* verify that there are not too many planes attached to crtc - * and that we don't have conflicting mixer stages: - */ - drm_atomic_crtc_state_for_each_plane(plane, state) { - struct drm_plane_state *pstate; - - if (cnt >= (max_stages)) { - dev_err(dev->dev, "too many planes!\n"); - return -EINVAL; - } - - pstate = state->state->plane_states[drm_plane_index(plane)]; - - /* plane might not have changed, in which case take - * current state: - */ - if (!pstate) - pstate = plane->state; - pstates[cnt].plane = plane; - pstates[cnt].state = to_sde_plane_state(pstate); - - cnt++; - } - - /* assign a stage based on sorted zpos property */ - sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); - - for (i = 0; i < cnt; i++) { - pstates[i].state->stage = SDE_STAGE_0 + i; - DBG("%s: assign pipe %d on stage=%d", sde_crtc->name, - sde_plane_pipe(pstates[i].plane), - pstates[i].state->stage); - } - - return 0; -} - static const struct drm_crtc_funcs sde_crtc_funcs = { - .set_config = drm_atomic_helper_set_config, + .set_config = drm_crtc_helper_set_config, .destroy = sde_crtc_destroy, - .page_flip = drm_atomic_helper_page_flip, + .page_flip = sde_crtc_page_flip, .set_property = sde_crtc_set_property, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, - .cursor_set = sde_crtc_cursor_set, - .cursor_move = sde_crtc_cursor_move, }; static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = { + .dpms = sde_crtc_dpms, .mode_fixup = sde_crtc_mode_fixup, - .mode_set_nofb = sde_crtc_mode_set_nofb, - .disable = sde_crtc_disable, - .enable = sde_crtc_enable, - .atomic_check = sde_crtc_atomic_check, - .atomic_begin = sde_crtc_atomic_begin, - .atomic_flush = sde_crtc_atomic_flush, + .mode_set = sde_crtc_mode_set, + .prepare = sde_crtc_prepare, + .commit = sde_crtc_commit, + .mode_set_base = sde_crtc_mode_set_base, + .load_lut = sde_crtc_load_lut, }; uint32_t sde_crtc_vblank(struct drm_crtc *crtc) @@ -634,20 +118,20 @@ void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) { } -static void sde_crtc_install_properties(struct drm_crtc *crtc, - struct drm_mode_object *obj) +void sde_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane) { } +void sde_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane) +{ +} -/* initialize crtc */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_encoder *encoder, struct drm_plane *plane, int id) { struct drm_crtc *crtc = NULL; struct sde_crtc *sde_crtc; - int rc; sde_crtc = kzalloc(sizeof(*sde_crtc), GFP_KERNEL); if (!sde_crtc) @@ -656,21 +140,9 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, crtc = &sde_crtc->base; sde_crtc->id = id; - sde_crtc->encoder = encoder; - - sde_crtc_install_properties(crtc, &crtc->base); - drm_crtc_init_with_planes(dev, crtc, plane, NULL, &sde_crtc_funcs); + /* find out if we need one or two lms */ drm_crtc_helper_add(crtc, &sde_crtc_helper_funcs); - plane->crtc = crtc; - - rc = sde_crtc_reserve_hw_resources(crtc, encoder); - if (rc) { - dev_err(dev->dev, " error reserving HW resource for this CRTC\n"); - return ERR_PTR(-EINVAL); - } - - DBG("%s: Successfully initialized crtc", __func__); return crtc; } diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h deleted file mode 100644 index 9f14f999913d..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _SDE_CRTC_H_ -#define _SDE_CRTC_H_ - -#include "drm_crtc.h" - -#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) - -#define CRTC_DUAL_MIXERS 2 -#define PENDING_FLIP 2 -/* worst case one frame wait time based on 30 FPS : 33.33ms*/ -#define CRTC_MAX_WAIT_ONE_FRAME 34 -#define CRTC_HW_MIXER_MAXSTAGES(c, idx) ((c)->mixer[idx].sblk->maxblendstages) - -/** - * struct sde_crtc_mixer - stores the map for each virtual pipeline in the CRTC - * @hw_dspp : DSPP HW Driver context - * @hw_lm : LM HW Driver context - * @hw_ctl : CTL Path HW driver context - * @intf_idx : Interface idx - * @mode : Interface mode Active/CMD - * @flush_mask : Flush mask value for this commit - */ -struct sde_crtc_mixer { - struct sde_hw_dspp *hw_dspp; - struct sde_hw_mixer *hw_lm; - struct sde_hw_ctl *hw_ctl; - enum sde_intf intf_idx; - enum sde_intf_mode mode; - u32 flush_mask; -}; - -/** - * struct sde_crtc - virtualized CRTC data structure - * @base : Base drm crtc structure - * @name : ASCII description of this crtc - * @encoder : Associated drm encoder object - * @id : Unique crtc identifier - * @lm_lock : LM register access spinlock - * @num_ctls : Number of ctl paths in use - * @num_mixers : Number of mixers in use - * @mixer : List of active mixers - * @event : Pointer to last received drm vblank event - * @pending : Whether or not an update is pending - * @vsync_count : Running count of received vsync events - */ -struct sde_crtc { - struct drm_crtc base; - char name[8]; - struct drm_encoder *encoder; - int id; - - spinlock_t lm_lock; /* protect registers */ - - /* HW Resources reserved for the crtc */ - u32 num_ctls; - u32 num_mixers; - struct sde_crtc_mixer mixer[CRTC_DUAL_MIXERS]; - - /*if there is a pending flip, these will be non-null */ - struct drm_pending_vblank_event *event; - atomic_t pending; - u32 vsync_count; -}; - -#define to_sde_crtc(x) container_of(x, struct sde_crtc, base) - -#endif /* _SDE_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index ad72bca11669..11e13849d295 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -10,560 +10,86 @@ * GNU General Public License for more details. */ -#include "msm_drv.h" #include "sde_kms.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_intf.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_mdp_formats.h" - -#include "sde_encoder_phys.h" -#include "display_manager.h" - -#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) - -#ifdef CONFIG_QCOM_BUS_SCALING -#include <linux/msm-bus.h> -#include <linux/msm-bus-board.h> -#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \ - { \ - .src = MSM_BUS_MASTER_MDP_PORT0, \ - .dst = MSM_BUS_SLAVE_EBI_CH0, \ - .ab = (ab_val), \ - .ib = (ib_val), \ - } - -static struct msm_bus_vectors mdp_bus_vectors[] = { - MDP_BUS_VECTOR_ENTRY(0, 0), - MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000), +struct sde_encoder { + struct drm_encoder base; + int intf; }; +#define to_sde_encoder(x) container_of(x, struct sde_encoder, base) -static struct msm_bus_paths mdp_bus_usecases[] = { { - .num_paths = 1, - .vectors = - &mdp_bus_vectors[0], - }, { - .num_paths = 1, - .vectors = - &mdp_bus_vectors[1], - } -}; - -static struct msm_bus_scale_pdata mdp_bus_scale_table = { - .usecase = mdp_bus_usecases, - .num_usecases = ARRAY_SIZE(mdp_bus_usecases), - .name = "mdss_mdp", -}; - -static void bs_init(struct sde_encoder_virt *sde_enc) -{ - sde_enc->bus_scaling_client = - msm_bus_scale_register_client(&mdp_bus_scale_table); - DBG("bus scale client: %08x", sde_enc->bus_scaling_client); -} - -static void bs_fini(struct sde_encoder_virt *sde_enc) +static void sde_encoder_destroy(struct drm_encoder *encoder) { - if (sde_enc->bus_scaling_client) { - msm_bus_scale_unregister_client(sde_enc->bus_scaling_client); - sde_enc->bus_scaling_client = 0; - } -} + struct sde_encoder *sde_encoder = to_sde_encoder(encoder); -static void bs_set(struct sde_encoder_virt *sde_enc, int idx) -{ - if (sde_enc->bus_scaling_client) { - DBG("set bus scaling: %d", idx); - idx = 1; - msm_bus_scale_client_update_request(sde_enc->bus_scaling_client, - idx); - } -} -#else -static void bs_init(struct sde_encoder_virt *sde_enc) -{ + drm_encoder_cleanup(encoder); + kfree(sde_encoder); } -static void bs_fini(struct sde_encoder_virt *sde_enc) -{ -} +static const struct drm_encoder_funcs sde_encoder_funcs = { + .destroy = sde_encoder_destroy, +}; -static void bs_set(struct sde_encoder_virt *sde_enc, int idx) +static void sde_encoder_dpms(struct drm_encoder *encoder, int mode) { } -#endif -void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc, - struct sde_encoder_hw_resources *hw_res) +static bool sde_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - - DBG(""); - - if (!hw_res || !drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - /* Query resources used by phys encs, expected to be without overlap */ - memset(hw_res, 0, sizeof(*hw_res)); - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.get_hw_resources) - phys->phys_ops.get_hw_resources(phys, hw_res); - } -} - -static void sde_encoder_destroy(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - for (i = 0; i < ARRAY_SIZE(sde_enc->phys_encs); i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.destroy) { - phys->phys_ops.destroy(phys); - --sde_enc->num_phys_encs; - sde_enc->phys_encs[i] = NULL; - } - } - - if (sde_enc->num_phys_encs) { - DRM_ERROR("Expected num_phys_encs to be 0 not %d\n", - sde_enc->num_phys_encs); - } - - drm_encoder_cleanup(drm_enc); - bs_fini(sde_enc); - kfree(sde_enc); + return true; } -static bool sde_encoder_virt_mode_fixup(struct drm_encoder *drm_enc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static void sde_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - bool ret = true; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return false; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.mode_fixup) { - ret = - phys->phys_ops.mode_fixup(phys, mode, - adjusted_mode); - if (!ret) { - DBG("Mode unsupported by phys_enc %d", i); - break; - } - - if (sde_enc->num_phys_encs > 1) { - DBG("ModeFix only checking 1 phys_enc"); - break; - } - } - } - - return ret; } -static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static void sde_encoder_prepare(struct drm_encoder *encoder) { - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - bool splitmode = false; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - /* - * Panel is driven by two interfaces ,each interface drives half of - * the horizontal - */ - if (sde_enc->num_phys_encs == 2) - splitmode = true; - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - if (phys) { - phys->phys_ops.mode_set(phys, - mode, - adjusted_mode, - splitmode); - if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0) - DRM_ERROR("adjusted modes not supported\n"); - } - } } -static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) +static void sde_encoder_commit(struct drm_encoder *encoder) { - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - bool splitmode = false; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - bs_set(sde_enc, 1); - - if (sde_enc->num_phys_encs == 2) - splitmode = true; - - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.enable) - - /* enable/disable dual interface top config */ - if (phys->phys_ops.enable_split_config) - phys->phys_ops.enable_split_config(phys, - splitmode); - phys->phys_ops.enable(phys); - } -} - -static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i = 0; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - - if (phys && phys->phys_ops.disable) - phys->phys_ops.disable(phys); - } - - bs_set(sde_enc, 0); } static const struct drm_encoder_helper_funcs sde_encoder_helper_funcs = { - .mode_fixup = sde_encoder_virt_mode_fixup, - .mode_set = sde_encoder_virt_mode_set, - .disable = sde_encoder_virt_disable, - .enable = sde_encoder_virt_enable, -}; - -static const struct drm_encoder_funcs sde_encoder_funcs = { - .destroy = sde_encoder_destroy, + .dpms = sde_encoder_dpms, + .mode_fixup = sde_encoder_mode_fixup, + .mode_set = sde_encoder_mode_set, + .prepare = sde_encoder_prepare, + .commit = sde_encoder_commit, }; -static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog, - enum sde_intf_type type, u32 controller_id) -{ - int i = 0; - - DBG(""); - - for (i = 0; i < catalog->intf_count; i++) { - if (catalog->intf[i].type == type - && catalog->intf[i].controller_id == controller_id) { - return catalog->intf[i].id; - } - } - - return INTF_MAX; -} - -static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - unsigned long lock_flags; - - DBG(""); - - if (!drm_enc) { - DRM_ERROR("Invalid pointer"); - return; - } - - sde_enc = to_sde_encoder_virt(drm_enc); - - spin_lock_irqsave(&sde_enc->spin_lock, lock_flags); - if (sde_enc->kms_vblank_callback) - sde_enc->kms_vblank_callback(sde_enc->kms_vblank_callback_data); - spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags); -} - -static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder_virt *sde_enc, - struct sde_kms *sde_kms, - enum sde_intf intf_idx, - enum sde_ctl ctl_idx) +/* initialize encoder */ +struct drm_encoder *sde_encoder_init(struct drm_device *dev, int intf) { - int ret = 0; - - DBG(""); - - if (sde_enc->num_phys_encs >= ARRAY_SIZE(sde_enc->phys_encs)) { - DRM_ERROR("Too many video encoders %d, unable to add\n", - sde_enc->num_phys_encs); - ret = -EINVAL; - } else { - struct sde_encoder_virt_ops parent_ops = { - sde_encoder_vblank_callback - }; - struct sde_encoder_phys *enc = - sde_encoder_phys_vid_init(sde_kms, intf_idx, ctl_idx, - &sde_enc->base, - parent_ops); - if (IS_ERR(enc)) - ret = PTR_ERR(enc); - - if (!ret) { - sde_enc->phys_encs[sde_enc->num_phys_encs] = enc; - ++sde_enc->num_phys_encs; - } - } - - return ret; -} - -static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, - struct sde_kms *sde_kms, - struct display_info *disp_info, - int *drm_enc_mode) -{ - int ret = 0; - int i = 0; - enum sde_intf_type intf_type = INTF_NONE; - - DBG(""); - - if (disp_info->intf == DISPLAY_INTF_DSI) { - *drm_enc_mode = DRM_MODE_ENCODER_DSI; - intf_type = INTF_DSI; - } else if (disp_info->intf == DISPLAY_INTF_HDMI) { - *drm_enc_mode = DRM_MODE_ENCODER_TMDS; - intf_type = INTF_HDMI; - } else { - DRM_ERROR("Unsupported display interface type"); - return -EINVAL; - } - - WARN_ON(disp_info->num_of_h_tiles < 1); - - DBG("dsi_info->num_of_h_tiles %d", disp_info->num_of_h_tiles); - - for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { - /* - * Left-most tile is at index 0, content is controller id - * h_tile_instance_ids[2] = {0, 1}; DSI0 = left, DSI1 = right - * h_tile_instance_ids[2] = {1, 0}; DSI1 = left, DSI0 = right - */ - const struct sde_hw_res_map *hw_res_map = NULL; - enum sde_intf intf_idx = INTF_MAX; - enum sde_ctl ctl_idx = CTL_MAX; - u32 controller_id = disp_info->h_tile_instance[i]; - - DBG("h_tile_instance %d = %d", i, controller_id); - - intf_idx = sde_encoder_get_intf(sde_kms->catalog, - intf_type, controller_id); - if (intf_idx == INTF_MAX) { - DBG("Error: could not get the interface id"); - ret = -EINVAL; - } - - hw_res_map = sde_rm_get_res_map(sde_kms, intf_idx); - if (IS_ERR_OR_NULL(hw_res_map)) - ret = -EINVAL; - else - ctl_idx = hw_res_map->ctl; - - /* Create both VID and CMD Phys Encoders here */ - if (!ret) - ret = sde_encoder_virt_add_phys_vid_enc( - sde_enc, sde_kms, intf_idx, ctl_idx); - } + struct drm_encoder *encoder = NULL; + struct sde_encoder *sde_encoder; + int ret; - - return ret; -} - -static struct drm_encoder *sde_encoder_virt_init( - struct drm_device *dev, struct display_info *disp_info) -{ - struct msm_drm_private *priv = dev->dev_private; - struct sde_kms *sde_kms = to_sde_kms(priv->kms); - struct drm_encoder *drm_enc = NULL; - struct sde_encoder_virt *sde_enc = NULL; - int drm_enc_mode = DRM_MODE_ENCODER_NONE; - int ret = 0; - - DBG(""); - - sde_enc = kzalloc(sizeof(*sde_enc), GFP_KERNEL); - if (!sde_enc) { + sde_encoder = kzalloc(sizeof(*sde_encoder), GFP_KERNEL); + if (!sde_encoder) { ret = -ENOMEM; goto fail; } - ret = sde_encoder_setup_display(sde_enc, sde_kms, disp_info, - &drm_enc_mode); - if (ret) - goto fail; - - spin_lock_init(&sde_enc->spin_lock); - drm_enc = &sde_enc->base; - drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode); - drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs); - bs_init(sde_enc); + sde_encoder->intf = intf; + encoder = &sde_encoder->base; - DBG("Created encoder"); + drm_encoder_init(dev, encoder, &sde_encoder_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &sde_encoder_helper_funcs); - return drm_enc; + return encoder; fail: - DRM_ERROR("Failed to create encoder\n"); - if (drm_enc) - sde_encoder_destroy(drm_enc); + if (encoder) + sde_encoder_destroy(encoder); return ERR_PTR(ret); } - -void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc, - void (*cb)(void *), void *data) -{ - struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); - unsigned long lock_flags; - - DBG(""); - - spin_lock_irqsave(&sde_enc->spin_lock, lock_flags); - sde_enc->kms_vblank_callback = cb; - sde_enc->kms_vblank_callback_data = data; - spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags); -} - -void sde_encoder_get_vsync_info(struct drm_encoder *drm_enc, - struct vsync_info *vsync) -{ - struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); - struct sde_encoder_phys *phys; - - DBG(""); - - if (!vsync) { - DRM_ERROR("Invalid pointer"); - return; - } - - /* we get the vsync info from the intf at index 0: master index */ - phys = sde_enc->phys_encs[0]; - if (phys) - phys->phys_ops.get_vsync_info(phys, vsync); -} - -/* encoders init, - * initialize encoder based on displays - */ -void sde_encoders_init(struct drm_device *dev) -{ - struct msm_drm_private *priv = NULL; - struct display_manager *disp_man = NULL; - u32 i = 0; - u32 num_displays = 0; - - DBG(""); - - if (!dev || !dev->dev_private) { - DRM_ERROR("Invalid pointer"); - return; - } - - priv = dev->dev_private; - priv->num_encoders = 0; - if (!priv->kms || !priv->dm) { - DRM_ERROR("Invalid pointer"); - return; - } - disp_man = priv->dm; - - num_displays = display_manager_get_count(disp_man); - DBG("num_displays %d", num_displays); - - if (num_displays > ARRAY_SIZE(priv->encoders)) { - num_displays = ARRAY_SIZE(priv->encoders); - DRM_ERROR("Too many displays found, capping to %d", - num_displays); - } - - for (i = 0; i < num_displays; i++) { - struct display_info info = { 0 }; - struct drm_encoder *enc = NULL; - u32 ret = 0; - - ret = display_manager_get_info_by_index(disp_man, i, &info); - if (ret) { - DRM_ERROR("Failed to get display info, %d", ret); - return; - } - - enc = sde_encoder_virt_init(dev, &info); - if (IS_ERR_OR_NULL(enc)) { - DRM_ERROR("Encoder initialization failed"); - return; - } - - ret = display_manager_drm_init_by_index(disp_man, i, enc); - if (ret) { - DRM_ERROR("Display drm_init failed, %d", ret); - return; - } - - priv->encoders[priv->num_encoders++] = enc; - } -} diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h deleted file mode 100644 index d35e084f9bef..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __SDE_ENCODER_PHYS_H__ -#define __SDE_ENCODER_PHYS_H__ - -#include "sde_kms.h" -#include "sde_hw_intf.h" -#include "sde_hw_mdp_ctl.h" - -#define MAX_PHYS_ENCODERS_PER_VIRTUAL 4 - -struct sde_encoder_phys; - -struct sde_encoder_virt_ops { - void (*handle_vblank_virt)(struct drm_encoder *); -}; - -struct sde_encoder_phys_ops { - void (*mode_set)(struct sde_encoder_phys *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - bool splitmode); - bool (*mode_fixup)(struct sde_encoder_phys *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - void (*enable)(struct sde_encoder_phys *encoder); - void (*disable)(struct sde_encoder_phys *encoder); - void (*destroy)(struct sde_encoder_phys *encoder); - void (*get_hw_resources)(struct sde_encoder_phys *encoder, - struct sde_encoder_hw_resources *hw_res); - void (*get_vsync_info)(struct sde_encoder_phys *enc, - struct vsync_info *vsync); - void (*enable_split_config)(struct sde_encoder_phys *enc, - bool enable); -}; - -struct sde_encoder_phys { - struct drm_encoder *parent; - struct sde_encoder_virt_ops parent_ops; - struct sde_encoder_phys_ops phys_ops; - struct sde_hw_intf *hw_intf; - struct sde_hw_ctl *hw_ctl; - struct sde_kms *sde_kms; - struct drm_display_mode cached_mode; - bool enabled; - spinlock_t spin_lock; -}; - -/** - * struct sde_encoder_phys_vid - sub-class of sde_encoder_phys to handle video - * mode specific operations - * @base: Baseclass physical encoder structure - * @irq_idx: IRQ interface lookup index - * @vblank_complete: for vblank irq synchronization - */ -struct sde_encoder_phys_vid { - struct sde_encoder_phys base; - int irq_idx; - struct completion vblank_complete; -}; - -struct sde_encoder_virt { - struct drm_encoder base; - spinlock_t spin_lock; - uint32_t bus_scaling_client; - - int num_phys_encs; - struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; - - void (*kms_vblank_callback)(void *); - void *kms_vblank_callback_data; -}; - -struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms, - enum sde_intf intf_idx, - enum sde_ctl ctl_idx, - struct drm_encoder *parent, - struct sde_encoder_virt_ops - parent_ops); - -#endif /* __sde_encoder_phys_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c deleted file mode 100644 index 693e1f33e7d8..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2015 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "msm_drv.h" -#include "sde_kms.h" -#include "drm_crtc.h" -#include "drm_crtc_helper.h" - -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_intf.h" -#include "sde_mdp_formats.h" - -#include "sde_encoder_phys.h" diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c deleted file mode 100644 index aefa11d5cdde..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ /dev/null @@ -1,559 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "msm_drv.h" -#include "sde_kms.h" -#include "drm_crtc.h" -#include "drm_crtc_helper.h" - -#include "sde_encoder_phys.h" -#include "sde_mdp_formats.h" -#include "sde_hw_mdp_top.h" - -#define VBLANK_TIMEOUT msecs_to_jiffies(100) - -#define to_sde_encoder_phys_vid(x) \ - container_of(x, struct sde_encoder_phys_vid, base) - -static bool sde_encoder_phys_vid_is_master( - struct sde_encoder_phys *phys_enc) -{ - bool ret = true; - - return ret; -} - -static void sde_encoder_phys_vid_wait_for_vblank( - struct sde_encoder_phys_vid *vid_enc) -{ - int rc = 0; - - DBG(""); - rc = wait_for_completion_timeout(&vid_enc->vblank_complete, - VBLANK_TIMEOUT); - if (rc == 0) - DRM_ERROR("Timed out waiting for vblank irq\n"); -} - -static void drm_mode_to_intf_timing_params( - const struct sde_encoder_phys *phys_enc, - const struct drm_display_mode *mode, - struct intf_timing_params *timing) -{ - memset(timing, 0, sizeof(*timing)); - /* - * https://www.kernel.org/doc/htmldocs/drm/ch02s05.html - * Active Region Front Porch Sync Back Porch - * <-----------------><------------><-----><-----------> - * <- [hv]display ---> - * <--------- [hv]sync_start ------> - * <----------------- [hv]sync_end -------> - * <---------------------------- [hv]total -------------> - */ - timing->width = mode->hdisplay; /* active width */ - timing->height = mode->vdisplay; /* active height */ - timing->xres = timing->width; - timing->yres = timing->height; - timing->h_back_porch = mode->htotal - mode->hsync_end; - timing->h_front_porch = mode->hsync_start - mode->hdisplay; - timing->v_back_porch = mode->vtotal - mode->vsync_end; - timing->v_front_porch = mode->vsync_start - mode->vdisplay; - timing->hsync_pulse_width = mode->hsync_end - mode->hsync_start; - timing->vsync_pulse_width = mode->vsync_end - mode->vsync_start; - timing->hsync_polarity = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0; - timing->vsync_polarity = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; - timing->border_clr = 0; - timing->underflow_clr = 0xff; - timing->hsync_skew = mode->hskew; - - /* DSI controller cannot handle active-low sync signals. */ - if (phys_enc->hw_intf->cap->type == INTF_DSI) { - timing->hsync_polarity = 0; - timing->vsync_polarity = 0; - } - - /* - * For edp only: - * DISPLAY_V_START = (VBP * HCYCLE) + HBP - * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP - */ - /* - * if (vid_enc->hw->cap->type == INTF_EDP) { - * display_v_start += mode->htotal - mode->hsync_start; - * display_v_end -= mode->hsync_start - mode->hdisplay; - * } - */ -} - -static inline u32 get_horizontal_total(const struct intf_timing_params *timing) -{ - u32 active = timing->xres; - u32 inactive = - timing->h_back_porch + timing->h_front_porch + - timing->hsync_pulse_width; - return active + inactive; -} - -static inline u32 get_vertical_total(const struct intf_timing_params *timing) -{ - u32 active = timing->yres; - u32 inactive = - timing->v_back_porch + timing->v_front_porch + - timing->vsync_pulse_width; - return active + inactive; -} - -/* - * programmable_fetch_get_num_lines: - * Number of fetch lines in vertical front porch - * @timing: Pointer to the intf timing information for the requested mode - * - * Returns the number of fetch lines in vertical front porch at which mdp - * can start fetching the next frame. - * - * Number of needed prefetch lines is anything that cannot be absorbed in the - * start of frame time (back porch + vsync pulse width). - * - * Some panels have very large VFP, however we only need a total number of - * lines based on the chip worst case latencies. - */ -static u32 programmable_fetch_get_num_lines( - struct sde_encoder_phys *phys_enc, - const struct intf_timing_params *timing) -{ - u32 worst_case_needed_lines = - phys_enc->hw_intf->cap->prog_fetch_lines_worst_case; - u32 start_of_frame_lines = - timing->v_back_porch + timing->vsync_pulse_width; - u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines; - u32 actual_vfp_lines = 0; - - /* Fetch must be outside active lines, otherwise undefined. */ - - if (start_of_frame_lines >= worst_case_needed_lines) { - DBG("Programmable fetch is not needed due to large vbp+vsw"); - actual_vfp_lines = 0; - } else if (timing->v_front_porch < needed_vfp_lines) { - /* Warn fetch needed, but not enough porch in panel config */ - pr_warn_once - ("low vbp+vfp may lead to perf issues in some cases\n"); - DBG("Less vfp than fetch requires, using entire vfp"); - actual_vfp_lines = timing->v_front_porch; - } else { - DBG("Room in vfp for needed prefetch"); - actual_vfp_lines = needed_vfp_lines; - } - - DBG("v_front_porch %u v_back_porch %u vsync_pulse_width %u", - timing->v_front_porch, timing->v_back_porch, - timing->vsync_pulse_width); - DBG("wc_lines %u needed_vfp_lines %u actual_vfp_lines %u", - worst_case_needed_lines, needed_vfp_lines, actual_vfp_lines); - - return actual_vfp_lines; -} - -/* - * programmable_fetch_config: Programs HW to prefetch lines by offsetting - * the start of fetch into the vertical front porch for cases where the - * vsync pulse width and vertical back porch time is insufficient - * - * Gets # of lines to pre-fetch, then calculate VSYNC counter value. - * HW layer requires VSYNC counter of first pixel of tgt VFP line. - * - * @timing: Pointer to the intf timing information for the requested mode - */ -static void programmable_fetch_config(struct sde_encoder_phys *phys_enc, - const struct intf_timing_params *timing) -{ - struct intf_prog_fetch f = { 0 }; - u32 vfp_fetch_lines = 0; - u32 horiz_total = 0; - u32 vert_total = 0; - u32 vfp_fetch_start_vsync_counter = 0; - unsigned long lock_flags; - - if (WARN_ON_ONCE(!phys_enc->hw_intf->ops.setup_prg_fetch)) - return; - - vfp_fetch_lines = programmable_fetch_get_num_lines(phys_enc, timing); - if (vfp_fetch_lines) { - vert_total = get_vertical_total(timing); - horiz_total = get_horizontal_total(timing); - vfp_fetch_start_vsync_counter = - (vert_total - vfp_fetch_lines) * horiz_total + 1; - f.enable = 1; - f.fetch_start = vfp_fetch_start_vsync_counter; - } - - DBG("vfp_fetch_lines %u vfp_fetch_start_vsync_counter %u", - vfp_fetch_lines, vfp_fetch_start_vsync_counter); - - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.setup_prg_fetch(phys_enc->hw_intf, &f); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); -} - -static bool sde_encoder_phys_vid_mode_fixup( - struct sde_encoder_phys *phys_enc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - DBG(""); - - /* - * Modifying mode has consequences when the mode comes back to us - */ - return true; -} - -static void sde_encoder_phys_vid_flush_intf(struct sde_encoder_phys *phys_enc) -{ - struct sde_hw_intf *intf = phys_enc->hw_intf; - struct sde_hw_ctl *ctl = phys_enc->hw_ctl; - u32 flush_mask = 0; - - DBG(""); - - ctl->ops.get_bitmask_intf(ctl, &flush_mask, intf->idx); - ctl->ops.setup_flush(ctl, flush_mask); - - DBG("Flushing CTL_ID %d, flush_mask %x, INTF %d", - ctl->idx, flush_mask, intf->idx); -} - -static void sde_encoder_phys_vid_mode_set(struct sde_encoder_phys *phys_enc, - struct drm_display_mode *mode, - struct drm_display_mode - *adjusted_mode, - bool splitmode) -{ - mode = adjusted_mode; - phys_enc->cached_mode = *adjusted_mode; - if (splitmode) { - phys_enc->cached_mode.hdisplay >>= 1; - phys_enc->cached_mode.htotal >>= 1; - phys_enc->cached_mode.hsync_start >>= 1; - phys_enc->cached_mode.hsync_end >>= 1; - } - - DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, - mode->type, mode->flags); -} - -static void sde_encoder_phys_vid_setup_timing_engine( - struct sde_encoder_phys *phys_enc) -{ - struct drm_display_mode *mode = &phys_enc->cached_mode; - struct intf_timing_params p = { 0 }; - struct sde_mdp_format_params *sde_fmt_params = NULL; - u32 fmt_fourcc = DRM_FORMAT_RGB888; - u32 fmt_mod = 0; - unsigned long lock_flags; - struct sde_hw_intf_cfg intf_cfg = { 0 }; - - if (WARN_ON(!phys_enc->hw_intf->ops.setup_timing_gen)) - return; - - if (WARN_ON(!phys_enc->hw_ctl->ops.setup_intf_cfg)) - return; - - DBG("enable mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, - mode->type, mode->flags); - - drm_mode_to_intf_timing_params(phys_enc, mode, &p); - - sde_fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod); - - intf_cfg.intf = phys_enc->hw_intf->idx; - intf_cfg.wb = SDE_NONE; - - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &p, - sde_fmt_params); - phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); - - programmable_fetch_config(phys_enc, &p); -} - -static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) -{ - struct sde_encoder_phys_vid *vid_enc = arg; - struct sde_encoder_phys *phys_enc = &vid_enc->base; - - phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent); - - /* signal VBLANK completion */ - complete_all(&vid_enc->vblank_complete); -} - -static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc) -{ - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - struct sde_irq_callback irq_cb; - int ret = 0; - - vid_enc->irq_idx = sde_irq_idx_lookup(phys_enc->sde_kms, - SDE_IRQ_TYPE_INTF_VSYNC, phys_enc->hw_intf->idx); - if (vid_enc->irq_idx < 0) { - DRM_ERROR( - "Failed to lookup IRQ index for INTF_VSYNC with intf=%d\n", - phys_enc->hw_intf->idx); - return -EINVAL; - } - - irq_cb.func = sde_encoder_phys_vid_vblank_irq; - irq_cb.arg = vid_enc; - ret = sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx, - &irq_cb); - if (ret) { - DRM_ERROR("Failed to register IRQ callback INTF_VSYNC\n"); - return ret; - } - - ret = sde_enable_irq(phys_enc->sde_kms, &vid_enc->irq_idx, 1); - if (ret) { - DRM_ERROR( - "Failed to enable IRQ for INTF_VSYNC, intf %d, irq_idx=%d\n", - phys_enc->hw_intf->idx, - vid_enc->irq_idx); - vid_enc->irq_idx = -EINVAL; - - /* Unregister callback on IRQ enable failure */ - sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx, - NULL); - return ret; - } - - DBG("Registered IRQ for intf %d, irq_idx=%d\n", - phys_enc->hw_intf->idx, - vid_enc->irq_idx); - - return ret; -} - -static int sde_encoder_phys_vid_unregister_irq( - struct sde_encoder_phys *phys_enc) -{ - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - - sde_register_irq_callback(phys_enc->sde_kms, vid_enc->irq_idx, NULL); - sde_disable_irq(phys_enc->sde_kms, &vid_enc->irq_idx, 1); - - DBG("Un-Register IRQ for intf %d, irq_idx=%d\n", - phys_enc->hw_intf->idx, - vid_enc->irq_idx); - - return 0; -} - -static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) -{ - int ret = 0; - - DBG(""); - - if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing)) - return; - - sde_encoder_phys_vid_setup_timing_engine(phys_enc); - - sde_encoder_phys_vid_flush_intf(phys_enc); - - /* Register for interrupt unless we're the slave encoder */ - if (sde_encoder_phys_vid_is_master(phys_enc)) - ret = sde_encoder_phys_vid_register_irq(phys_enc); - - if (!ret && !phys_enc->enabled) { - unsigned long lock_flags = 0; - - /* Now enable timing engine */ - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 1); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); - - phys_enc->enabled = true; - } -} - -static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc) -{ - unsigned long lock_flags; - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - - DBG(""); - - if (WARN_ON(!phys_enc->enabled)) - return; - - if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing)) - return; - - spin_lock_irqsave(&phys_enc->spin_lock, lock_flags); - phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 0); - reinit_completion(&vid_enc->vblank_complete); - spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags); - - /* - * Wait for a vsync so we know the ENABLE=0 latched before - * the (connector) source of the vsync's gets disabled, - * otherwise we end up in a funny state if we re-enable - * before the disable latches, which results that some of - * the settings changes for the new modeset (like new - * scanout buffer) don't latch properly.. - */ - sde_encoder_phys_vid_wait_for_vblank(vid_enc); - sde_encoder_phys_vid_unregister_irq(phys_enc); - phys_enc->enabled = false; -} - -static void sde_encoder_phys_vid_destroy(struct sde_encoder_phys *phys_enc) -{ - struct sde_encoder_phys_vid *vid_enc = - to_sde_encoder_phys_vid(phys_enc); - DBG(""); - kfree(phys_enc->hw_intf); - kfree(vid_enc); -} - -static void sde_encoder_phys_vid_get_hw_resources( - struct sde_encoder_phys *phys_enc, - struct sde_encoder_hw_resources *hw_res) -{ - struct msm_drm_private *priv = phys_enc->parent->dev->dev_private; - struct sde_kms *sde_kms = to_sde_kms(priv->kms); - const struct sde_hw_res_map *hw_res_map; - - DBG("Intf %d\n", phys_enc->hw_intf->idx); - - hw_res->intfs[phys_enc->hw_intf->idx] = INTF_MODE_VIDEO; - /* - * defaults should not be in use, - * otherwise signal/return failure - */ - hw_res_map = sde_rm_get_res_map(sde_kms, phys_enc->hw_intf->idx); - - /* This is video mode panel so PINGPONG will be in by-pass mode - * only assign ctl path.For cmd panel check if pp_split is - * enabled, override default map - */ - hw_res->ctls[hw_res_map->ctl] = true; -} - -/** - * video mode will use the intf (get_status) - * cmd mode will use the pingpong (get_vsync_info) - * to get this information - */ -static void sde_encoder_intf_get_vsync_info(struct sde_encoder_phys *phys_enc, - struct vsync_info *vsync) -{ - struct intf_status status; - - DBG(""); - phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &status); - vsync->frame_count = status.frame_count; - vsync->line_count = status.line_count; - DBG(" sde_encoder_intf_get_vsync_info, count %d", vsync->frame_count); -} - -static void sde_encoder_intf_split_config(struct sde_encoder_phys *phys_enc, - bool enable) -{ - struct msm_drm_private *priv = phys_enc->parent->dev->dev_private; - struct sde_kms *sde_kms = to_sde_kms(priv->kms); - struct sde_hw_mdp *mdp = sde_hw_mdptop_init(MDP_TOP, sde_kms->mmio, - sde_kms->catalog); - struct split_pipe_cfg cfg; - - DBG("%p", mdp); - cfg.en = true; - cfg.mode = INTF_MODE_VIDEO; - if (!IS_ERR_OR_NULL(mdp)) - mdp->ops.setup_split_pipe(mdp, &cfg); -} - -static void sde_encoder_phys_vid_init_cbs(struct sde_encoder_phys_ops *ops) -{ - ops->mode_set = sde_encoder_phys_vid_mode_set; - ops->mode_fixup = sde_encoder_phys_vid_mode_fixup; - ops->enable = sde_encoder_phys_vid_enable; - ops->disable = sde_encoder_phys_vid_disable; - ops->destroy = sde_encoder_phys_vid_destroy; - ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources; - ops->get_vsync_info = sde_encoder_intf_get_vsync_info; - ops->enable_split_config = sde_encoder_intf_split_config; -} - -struct sde_encoder_phys *sde_encoder_phys_vid_init( - struct sde_kms *sde_kms, - enum sde_intf intf_idx, - enum sde_ctl ctl_idx, - struct drm_encoder *parent, - struct sde_encoder_virt_ops parent_ops) -{ - struct sde_encoder_phys *phys_enc = NULL; - struct sde_encoder_phys_vid *vid_enc = NULL; - int ret = 0; - - DBG(""); - - vid_enc = kzalloc(sizeof(*vid_enc), GFP_KERNEL); - if (!vid_enc) { - ret = -ENOMEM; - goto fail; - } - vid_enc->irq_idx = -EINVAL; - init_completion(&vid_enc->vblank_complete); - - phys_enc = &vid_enc->base; - - phys_enc->hw_intf = - sde_hw_intf_init(intf_idx, sde_kms->mmio, sde_kms->catalog); - if (!phys_enc->hw_intf) { - ret = -ENOMEM; - goto fail; - } - - phys_enc->hw_ctl = sde_rm_acquire_ctl_path(sde_kms, ctl_idx); - if (!phys_enc->hw_ctl) { - ret = -ENOMEM; - goto fail; - } - - sde_encoder_phys_vid_init_cbs(&phys_enc->phys_ops); - phys_enc->parent = parent; - phys_enc->parent_ops = parent_ops; - phys_enc->sde_kms = sde_kms; - spin_lock_init(&phys_enc->spin_lock); - - DBG("Created sde_encoder_phys_vid for intf %d", phys_enc->hw_intf->idx); - - return phys_enc; - -fail: - DRM_ERROR("Failed to create encoder\n"); - if (vid_enc) - sde_encoder_phys_vid_destroy(phys_enc); - - return ERR_PTR(ret); -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index 46972f2d5dfd..64751fa4fddf 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -282,10 +282,6 @@ struct sde_wb_sub_blocks { u32 maxlinewidth; }; -struct sde_mdss_base_cfg { - SDE_HW_BLK_INFO; -}; - /* struct sde_mdp_cfg : MDP TOP-BLK instance info * @id: index identifying this block * @base: register base offset to mdss @@ -375,14 +371,10 @@ struct sde_cdm_cfg { * @base register offset of this block * @features bit mask identifying sub-blocks/features * @type: Interface type(DSI, DP, HDMI) - * @controller_id: Controller Instance ID in case of multiple of intf type - * @prog_fetch_lines_worst_case Worst case latency num lines needed to prefetch */ struct sde_intf_cfg { SDE_HW_BLK_INFO; u32 type; /* interface type*/ - u32 controller_id; - u32 prog_fetch_lines_worst_case; }; /** @@ -415,9 +407,6 @@ struct sde_ad_cfg { struct sde_mdss_cfg { u32 hwversion; - u32 mdss_count; - struct sde_mdss_base_cfg mdss[MAX_BLOCKS]; - u32 mdp_count; struct sde_mdp_cfg mdp[MAX_BLOCKS]; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c index 7fb5a0616838..a9a1f05a00eb 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c @@ -146,10 +146,6 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg) /* Setup Register maps and defaults */ *cfg = (struct sde_mdss_cfg){ - .mdss_count = 1, - .mdss = { - {.id = MDP_TOP, .base = 0x00000000, .features = 0} - }, .mdp_count = 1, .mdp = { {.id = MDP_TOP, .base = 0x00001000, .features = 0, @@ -175,13 +171,13 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg) {.id = SSPP_VIG3, .base = 0x0000b000, .features = VIG_17X_MASK, .sblk = &layer}, - {.id = SSPP_RGB0, .base = 0x00015000, + {.id = SSPP_RGB0, .base = 0x00001500, .features = RGB_17X_MASK, .sblk = &layer}, - {.id = SSPP_RGB1, .base = 0x00017000, + {.id = SSPP_RGB1, .base = 0x00001700, .features = RGB_17X_MASK, .sblk = &layer}, - {.id = SSPP_RGB2, .base = 0x00019000, + {.id = SSPP_RGB2, .base = 0x00001900, .features = RGB_17X_MASK, .sblk = &layer}, - {.id = SSPP_RGB3, .base = 0x0001B000, + {.id = SSPP_RGB3, .base = 0x00001B00, .features = RGB_17X_MASK, .sblk = &layer}, {.id = SSPP_DMA0, .base = 0x00025000, @@ -248,17 +244,13 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg) .intf_count = 4, .intf = { {.id = INTF_0, .base = 0x0006B000, - .type = INTF_NONE, .controller_id = 0, - .prog_fetch_lines_worst_case = 21}, + .type = INTF_NONE}, {.id = INTF_1, .base = 0x0006B800, - .type = INTF_DSI, .controller_id = 0, - .prog_fetch_lines_worst_case = 21}, + .type = INTF_DSI}, {.id = INTF_2, .base = 0x0006C000, - .type = INTF_DSI, .controller_id = 1, - .prog_fetch_lines_worst_case = 21}, + .type = INTF_DSI}, {.id = INTF_3, .base = 0x0006C800, - .type = INTF_HDMI, .controller_id = 0, - .prog_fetch_lines_worst_case = 21}, + .type = INTF_HDMI}, }, .wb_count = 3, .wb = { diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c deleted file mode 100644 index 99aa2e59dd85..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c +++ /dev/null @@ -1,969 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/bitops.h> -#include <linux/slab.h> - -#include "sde_kms.h" -#include "sde_hw_interrupts.h" -#include "sde_hw_mdp_util.h" -#include "sde_hw_mdss.h" - -/** - * Register offsets in MDSS register file for the interrupt registers - * w.r.t. to the MDSS base - */ -#define HW_INTR_STATUS 0x0010 -#define MDP_SSPP_TOP0_OFF 0x1000 -#define MDP_INTF_0_OFF 0x6B000 -#define MDP_INTF_1_OFF 0x6B800 -#define MDP_INTF_2_OFF 0x6C000 -#define MDP_INTF_3_OFF 0x6C800 -#define MDP_INTF_4_OFF 0x6D000 - -/** - * WB interrupt status bit definitions - */ -#define SDE_INTR_WB_0_DONE BIT(0) -#define SDE_INTR_WB_1_DONE BIT(1) -#define SDE_INTR_WB_2_DONE BIT(4) - -/** - * WDOG timer interrupt status bit definitions - */ -#define SDE_INTR_WD_TIMER_0_DONE BIT(2) -#define SDE_INTR_WD_TIMER_1_DONE BIT(3) -#define SDE_INTR_WD_TIMER_2_DONE BIT(5) -#define SDE_INTR_WD_TIMER_3_DONE BIT(6) -#define SDE_INTR_WD_TIMER_4_DONE BIT(7) - -/** - * Pingpong interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_0_DONE BIT(8) -#define SDE_INTR_PING_PONG_1_DONE BIT(9) -#define SDE_INTR_PING_PONG_2_DONE BIT(10) -#define SDE_INTR_PING_PONG_3_DONE BIT(11) -#define SDE_INTR_PING_PONG_0_RD_PTR BIT(12) -#define SDE_INTR_PING_PONG_1_RD_PTR BIT(13) -#define SDE_INTR_PING_PONG_2_RD_PTR BIT(14) -#define SDE_INTR_PING_PONG_3_RD_PTR BIT(15) -#define SDE_INTR_PING_PONG_0_WR_PTR BIT(16) -#define SDE_INTR_PING_PONG_1_WR_PTR BIT(17) -#define SDE_INTR_PING_PONG_2_WR_PTR BIT(18) -#define SDE_INTR_PING_PONG_3_WR_PTR BIT(19) -#define SDE_INTR_PING_PONG_0_AUTOREFRESH_DONE BIT(20) -#define SDE_INTR_PING_PONG_1_AUTOREFRESH_DONE BIT(21) -#define SDE_INTR_PING_PONG_2_AUTOREFRESH_DONE BIT(22) -#define SDE_INTR_PING_PONG_3_AUTOREFRESH_DONE BIT(23) - -/** - * Interface interrupt status bit definitions - */ -#define SDE_INTR_INTF_0_UNDERRUN BIT(24) -#define SDE_INTR_INTF_1_UNDERRUN BIT(26) -#define SDE_INTR_INTF_2_UNDERRUN BIT(28) -#define SDE_INTR_INTF_3_UNDERRUN BIT(30) -#define SDE_INTR_INTF_0_VSYNC BIT(25) -#define SDE_INTR_INTF_1_VSYNC BIT(27) -#define SDE_INTR_INTF_2_VSYNC BIT(29) -#define SDE_INTR_INTF_3_VSYNC BIT(31) - -/** - * Pingpong Secondary interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE BIT(0) -#define SDE_INTR_PING_PONG_S0_WR_PTR BIT(4) -#define SDE_INTR_PING_PONG_S0_RD_PTR BIT(8) -#define SDE_INTR_PING_PONG_S0_TEAR_DETECTED BIT(22) -#define SDE_INTR_PING_PONG_S0_TE_DETECTED BIT(28) - -/** - * Pingpong TEAR detection interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_0_TEAR_DETECTED BIT(16) -#define SDE_INTR_PING_PONG_1_TEAR_DETECTED BIT(17) -#define SDE_INTR_PING_PONG_2_TEAR_DETECTED BIT(18) -#define SDE_INTR_PING_PONG_3_TEAR_DETECTED BIT(19) - -/** - * Pingpong TE detection interrupt status bit definitions - */ -#define SDE_INTR_PING_PONG_0_TE_DETECTED BIT(24) -#define SDE_INTR_PING_PONG_1_TE_DETECTED BIT(25) -#define SDE_INTR_PING_PONG_2_TE_DETECTED BIT(26) -#define SDE_INTR_PING_PONG_3_TE_DETECTED BIT(27) - -/** - * Concurrent WB overflow interrupt status bit definitions - */ -#define SDE_INTR_CWB_2_OVERFLOW BIT(14) -#define SDE_INTR_CWB_3_OVERFLOW BIT(15) - -/** - * Histogram VIG done interrupt status bit definitions - */ -#define SDE_INTR_HIST_VIG_0_DONE BIT(0) -#define SDE_INTR_HIST_VIG_1_DONE BIT(4) -#define SDE_INTR_HIST_VIG_2_DONE BIT(8) -#define SDE_INTR_HIST_VIG_3_DONE BIT(10) - -/** - * Histogram VIG reset Sequence done interrupt status bit definitions - */ -#define SDE_INTR_HIST_VIG_0_RSTSEQ_DONE BIT(1) -#define SDE_INTR_HIST_VIG_1_RSTSEQ_DONE BIT(5) -#define SDE_INTR_HIST_VIG_2_RSTSEQ_DONE BIT(9) -#define SDE_INTR_HIST_VIG_3_RSTSEQ_DONE BIT(11) - -/** - * Histogram DSPP done interrupt status bit definitions - */ -#define SDE_INTR_HIST_DSPP_0_DONE BIT(12) -#define SDE_INTR_HIST_DSPP_1_DONE BIT(16) -#define SDE_INTR_HIST_DSPP_2_DONE BIT(20) -#define SDE_INTR_HIST_DSPP_3_DONE BIT(22) - -/** - * Histogram DSPP reset Sequence done interrupt status bit definitions - */ -#define SDE_INTR_HIST_DSPP_0_RSTSEQ_DONE BIT(13) -#define SDE_INTR_HIST_DSPP_1_RSTSEQ_DONE BIT(17) -#define SDE_INTR_HIST_DSPP_2_RSTSEQ_DONE BIT(21) -#define SDE_INTR_HIST_DSPP_3_RSTSEQ_DONE BIT(23) - -/** - * INTF interrupt status bit definitions - */ -#define SDE_INTR_VIDEO_INTO_STATIC BIT(0) -#define SDE_INTR_VIDEO_OUTOF_STATIC BIT(1) -#define SDE_INTR_DSICMD_0_INTO_STATIC BIT(2) -#define SDE_INTR_DSICMD_0_OUTOF_STATIC BIT(3) -#define SDE_INTR_DSICMD_1_INTO_STATIC BIT(4) -#define SDE_INTR_DSICMD_1_OUTOF_STATIC BIT(5) -#define SDE_INTR_DSICMD_2_INTO_STATIC BIT(6) -#define SDE_INTR_DSICMD_2_OUTOF_STATIC BIT(7) -#define SDE_INTR_PROG_LINE BIT(8) - -/** - * struct sde_intr_reg - array of SDE register sets - * @clr_off: offset to CLEAR reg - * @en_off: offset to ENABLE reg - * @status_off: offset to STATUS reg - */ -struct sde_intr_reg { - u32 clr_off; - u32 en_off; - u32 status_off; -}; - -/** - * struct sde_irq_type - maps each irq with i/f - * @intr_type: type of interrupt listed in sde_intr_type - * @instance_idx: instance index of the associated HW block in SDE - * @irq_mask: corresponding bit in the interrupt status reg - * @reg_idx: which reg set to use - */ -struct sde_irq_type { - u32 intr_type; - u32 instance_idx; - u32 irq_mask; - u32 reg_idx; -}; - -/** - * List of SDE interrupt registers - */ -static const struct sde_intr_reg sde_intr_set[] = { - { - MDP_SSPP_TOP0_OFF+INTR_CLEAR, - MDP_SSPP_TOP0_OFF+INTR_EN, - MDP_SSPP_TOP0_OFF+INTR_STATUS - }, - { - MDP_SSPP_TOP0_OFF+INTR2_CLEAR, - MDP_SSPP_TOP0_OFF+INTR2_EN, - MDP_SSPP_TOP0_OFF+INTR2_STATUS - }, - { - MDP_SSPP_TOP0_OFF+HIST_INTR_CLEAR, - MDP_SSPP_TOP0_OFF+HIST_INTR_EN, - MDP_SSPP_TOP0_OFF+HIST_INTR_STATUS - }, - { - MDP_INTF_0_OFF+INTF_INTR_CLEAR, - MDP_INTF_0_OFF+INTF_INTR_EN, - MDP_INTF_0_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_1_OFF+INTF_INTR_CLEAR, - MDP_INTF_1_OFF+INTF_INTR_EN, - MDP_INTF_1_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_2_OFF+INTF_INTR_CLEAR, - MDP_INTF_2_OFF+INTF_INTR_EN, - MDP_INTF_2_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_3_OFF+INTF_INTR_CLEAR, - MDP_INTF_3_OFF+INTF_INTR_EN, - MDP_INTF_3_OFF+INTF_INTR_STATUS - }, - { - MDP_INTF_4_OFF+INTF_INTR_CLEAR, - MDP_INTF_4_OFF+INTF_INTR_EN, - MDP_INTF_4_OFF+INTF_INTR_STATUS - } -}; - -/** - * IRQ mapping table - use for lookup an irq_idx in this table that have - * a matching interface type and instance index. - */ -static const struct sde_irq_type sde_irq_map[] = { - /* BEGIN MAP_RANGE: 0-31, INTR */ - /* irq_idx: 0-3 */ - { SDE_IRQ_TYPE_WB_ROT_COMP, WB_0, SDE_INTR_WB_0_DONE, 0}, - { SDE_IRQ_TYPE_WB_ROT_COMP, WB_1, SDE_INTR_WB_1_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_0, SDE_INTR_WD_TIMER_0_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_1, SDE_INTR_WD_TIMER_1_DONE, 0}, - /* irq_idx: 4-7 */ - { SDE_IRQ_TYPE_WB_WFD_COMP, WB_2, SDE_INTR_WB_2_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_2, SDE_INTR_WD_TIMER_2_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_3, SDE_INTR_WD_TIMER_3_DONE, 0}, - { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_4, SDE_INTR_WD_TIMER_4_DONE, 0}, - /* irq_idx: 8-11 */ - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_0, - SDE_INTR_PING_PONG_0_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_1, - SDE_INTR_PING_PONG_1_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_2, - SDE_INTR_PING_PONG_2_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_3, - SDE_INTR_PING_PONG_3_DONE, 0}, - /* irq_idx: 12-15 */ - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_0, - SDE_INTR_PING_PONG_0_RD_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_1, - SDE_INTR_PING_PONG_1_RD_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_2, - SDE_INTR_PING_PONG_2_RD_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_3, - SDE_INTR_PING_PONG_3_RD_PTR, 0}, - /* irq_idx: 16-19 */ - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_0, - SDE_INTR_PING_PONG_0_WR_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_1, - SDE_INTR_PING_PONG_1_WR_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_2, - SDE_INTR_PING_PONG_2_WR_PTR, 0}, - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_3, - SDE_INTR_PING_PONG_3_WR_PTR, 0}, - /* irq_idx: 20-23 */ - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_0, - SDE_INTR_PING_PONG_0_AUTOREFRESH_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_1, - SDE_INTR_PING_PONG_1_AUTOREFRESH_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_2, - SDE_INTR_PING_PONG_2_AUTOREFRESH_DONE, 0}, - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_3, - SDE_INTR_PING_PONG_3_AUTOREFRESH_DONE, 0}, - /* irq_idx: 24-27 */ - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_0, SDE_INTR_INTF_0_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_0, SDE_INTR_INTF_0_VSYNC, 0}, - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_1, SDE_INTR_INTF_1_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_1, SDE_INTR_INTF_1_VSYNC, 0}, - /* irq_idx: 28-31 */ - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_2, SDE_INTR_INTF_2_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_2, SDE_INTR_INTF_2_VSYNC, 0}, - { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_3, SDE_INTR_INTF_3_UNDERRUN, 0}, - { SDE_IRQ_TYPE_INTF_VSYNC, INTF_3, SDE_INTR_INTF_3_VSYNC, 0}, - - /* BEGIN MAP_RANGE: 32-64, INTR2 */ - /* irq_idx: 32-35 */ - { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 36-39 */ - { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_WR_PTR, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 40-43 */ - { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_RD_PTR, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 44-47 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_2, SDE_INTR_CWB_2_OVERFLOW, 1}, - { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_3, SDE_INTR_CWB_3_OVERFLOW, 1}, - /* irq_idx: 48-51 */ - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_0, - SDE_INTR_PING_PONG_0_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_1, - SDE_INTR_PING_PONG_1_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_2, - SDE_INTR_PING_PONG_2_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_3, - SDE_INTR_PING_PONG_3_TEAR_DETECTED, 1}, - /* irq_idx: 52-55 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_TEAR_DETECTED, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - /* irq_idx: 56-59 */ - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_0, - SDE_INTR_PING_PONG_0_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_1, - SDE_INTR_PING_PONG_1_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_2, - SDE_INTR_PING_PONG_2_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_3, - SDE_INTR_PING_PONG_3_TE_DETECTED, 1}, - /* irq_idx: 60-63 */ - { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_S0, - SDE_INTR_PING_PONG_S0_TE_DETECTED, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 1}, - - /* BEGIN MAP_RANGE: 64-95 HIST */ - /* irq_idx: 64-67 */ - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG0, SDE_INTR_HIST_VIG_0_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG0, - SDE_INTR_HIST_VIG_0_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 68-71 */ - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG1, SDE_INTR_HIST_VIG_1_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG1, - SDE_INTR_HIST_VIG_1_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 68-71 */ - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG2, SDE_INTR_HIST_VIG_2_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG2, - SDE_INTR_HIST_VIG_2_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG3, SDE_INTR_HIST_VIG_3_DONE, 2}, - { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG3, - SDE_INTR_HIST_VIG_3_RSTSEQ_DONE, 2}, - /* irq_idx: 72-75 */ - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_0, SDE_INTR_HIST_DSPP_0_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_0, - SDE_INTR_HIST_DSPP_0_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 76-79 */ - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_1, SDE_INTR_HIST_DSPP_1_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_1, - SDE_INTR_HIST_DSPP_1_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 80-83 */ - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_2, SDE_INTR_HIST_DSPP_2_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_2, - SDE_INTR_HIST_DSPP_2_RSTSEQ_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_3, SDE_INTR_HIST_DSPP_3_DONE, 2}, - { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_3, - SDE_INTR_HIST_DSPP_3_RSTSEQ_DONE, 2}, - /* irq_idx: 84-87 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 88-91 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - /* irq_idx: 92-95 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 2}, - - /* BEGIN MAP_RANGE: 96-127 INTF_0_INTR */ - /* irq_idx: 96-99 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_0, - SDE_INTR_VIDEO_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_0, - SDE_INTR_VIDEO_OUTOF_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_0, - SDE_INTR_DSICMD_0_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_0, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 3}, - /* irq_idx: 100-103 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_0, - SDE_INTR_DSICMD_1_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_0, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_0, - SDE_INTR_DSICMD_2_INTO_STATIC, 3}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_0, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 3}, - /* irq_idx: 104-107 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_0, SDE_INTR_PROG_LINE, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 108-111 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 112-115 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 116-119 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 120-123 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - /* irq_idx: 124-127 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 3}, - - /* BEGIN MAP_RANGE: 128-159 INTF_1_INTR */ - /* irq_idx: 128-131 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_1, - SDE_INTR_VIDEO_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_1, - SDE_INTR_VIDEO_OUTOF_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_1, - SDE_INTR_DSICMD_0_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_1, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 4}, - /* irq_idx: 132-135 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_1, - SDE_INTR_DSICMD_1_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_1, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_1, - SDE_INTR_DSICMD_2_INTO_STATIC, 4}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_1, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 4}, - /* irq_idx: 136-139 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_1, SDE_INTR_PROG_LINE, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 140-143 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 144-147 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 148-151 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 152-155 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - /* irq_idx: 156-159 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 4}, - - /* BEGIN MAP_RANGE: 160-191 INTF_2_INTR */ - /* irq_idx: 160-163 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_2, - SDE_INTR_VIDEO_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_2, - SDE_INTR_VIDEO_OUTOF_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_2, - SDE_INTR_DSICMD_0_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_2, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 5}, - /* irq_idx: 164-167 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_2, - SDE_INTR_DSICMD_1_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_2, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_2, - SDE_INTR_DSICMD_2_INTO_STATIC, 5}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_2, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 5}, - /* irq_idx: 168-171 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_2, SDE_INTR_PROG_LINE, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 172-175 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 176-179 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 180-183 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 184-187 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - /* irq_idx: 188-191 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 5}, - - /* BEGIN MAP_RANGE: 192-223 INTF_3_INTR */ - /* irq_idx: 192-195 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_3, - SDE_INTR_VIDEO_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_3, - SDE_INTR_VIDEO_OUTOF_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_3, - SDE_INTR_DSICMD_0_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_3, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 6}, - /* irq_idx: 196-199 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_3, - SDE_INTR_DSICMD_1_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_3, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_3, - SDE_INTR_DSICMD_2_INTO_STATIC, 6}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_3, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 6}, - /* irq_idx: 200-203 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_3, SDE_INTR_PROG_LINE, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 204-207 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 208-211 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 212-215 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 216-219 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - /* irq_idx: 220-223 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 6}, - - /* BEGIN MAP_RANGE: 224-255 INTF_4_INTR */ - /* irq_idx: 224-227 */ - { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_4, - SDE_INTR_VIDEO_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_4, - SDE_INTR_VIDEO_OUTOF_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_4, - SDE_INTR_DSICMD_0_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_4, - SDE_INTR_DSICMD_0_OUTOF_STATIC, 7}, - /* irq_idx: 228-231 */ - { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_4, - SDE_INTR_DSICMD_1_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_4, - SDE_INTR_DSICMD_1_OUTOF_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_4, - SDE_INTR_DSICMD_2_INTO_STATIC, 7}, - { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_4, - SDE_INTR_DSICMD_2_OUTOF_STATIC, 7}, - /* irq_idx: 232-235 */ - { SDE_IRQ_TYPE_PROG_LINE, INTF_4, SDE_INTR_PROG_LINE, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 236-239 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 240-243 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 244-247 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 248-251 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - /* irq_idx: 252-255 */ - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, - { SDE_IRQ_TYPE_RESERVED, 0, 0, 7}, -}; - -static int sde_hw_intr_irqidx_lookup(enum sde_intr_type intr_type, - u32 instance_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sde_irq_map); i++) { - if (intr_type == sde_irq_map[i].intr_type && - instance_idx == sde_irq_map[i].instance_idx) - return i; - } - - pr_debug("IRQ lookup fail!! intr_type=%d, instance_idx=%d\n", - intr_type, instance_idx); - return -EINVAL; -} - -static void sde_hw_intr_set_mask(struct sde_hw_intr *intr, uint32_t reg_off, - uint32_t mask) -{ - SDE_REG_WRITE(&intr->hw, reg_off, mask); -} - -static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr, - void (*cbfunc)(void *, int), - void *arg) -{ - int reg_idx; - int irq_idx; - int start_idx; - int end_idx; - u32 irq_status; - unsigned long irq_flags; - - /* - * The dispatcher will save the IRQ status before calling here. - * Now need to go through each IRQ status and find matching - * irq lookup index. - */ - spin_lock_irqsave(&intr->status_lock, irq_flags); - for (reg_idx = 0; reg_idx < ARRAY_SIZE(sde_intr_set); reg_idx++) { - irq_status = intr->save_irq_status[reg_idx]; - - /* - * Each Interrupt register has a range of 32 indexes, and - * that is static for sde_irq_map. - */ - start_idx = reg_idx * 32; - end_idx = start_idx + 32; - - /* - * Search through matching intr status from irq map. - * start_idx and end_idx defined the search range in - * the sde_irq_map. - */ - for (irq_idx = start_idx; - (irq_idx < end_idx) && irq_status; - irq_idx++) - if ((irq_status & sde_irq_map[irq_idx].irq_mask) && - (sde_irq_map[irq_idx].reg_idx == reg_idx)) { - /* - * Once a match on irq mask, perform a callback - * to the given cbfunc. cbfunc will take care - * the interrupt status clearing. If cbfunc is - * not provided, then the interrupt clearing - * is here. - */ - if (cbfunc) - cbfunc(arg, irq_idx); - else - intr->ops.clear_interrupt_status( - intr, irq_idx); - - /* - * When callback finish, clear the irq_status - * with the matching mask. Once irq_status - * is all cleared, the search can be stopped. - */ - irq_status &= ~sde_irq_map[irq_idx].irq_mask; - } - } - spin_unlock_irqrestore(&intr->status_lock, irq_flags); -} - -static int sde_hw_intr_enable_irq(struct sde_hw_intr *intr, int irq_idx) -{ - int reg_idx; - unsigned long irq_flags; - const struct sde_intr_reg *reg; - const struct sde_irq_type *irq; - const char *dbgstr = NULL; - uint32_t cache_irq_mask; - - if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) { - pr_err("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - irq = &sde_irq_map[irq_idx]; - reg_idx = irq->reg_idx; - reg = &sde_intr_set[reg_idx]; - - spin_lock_irqsave(&intr->mask_lock, irq_flags); - cache_irq_mask = intr->cache_irq_mask[reg_idx]; - if (cache_irq_mask & irq->irq_mask) { - dbgstr = "SDE IRQ already set:"; - } else { - dbgstr = "SDE IRQ enabled:"; - - cache_irq_mask |= irq->irq_mask; - /* Cleaning any pending interrupt */ - SDE_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); - /* Enabling interrupts with the new mask */ - SDE_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); - - intr->cache_irq_mask[reg_idx] = cache_irq_mask; - } - spin_unlock_irqrestore(&intr->mask_lock, irq_flags); - - pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, - irq->irq_mask, cache_irq_mask); - - return 0; -} - -static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx) -{ - int reg_idx; - unsigned long irq_flags; - const struct sde_intr_reg *reg; - const struct sde_irq_type *irq; - const char *dbgstr = NULL; - uint32_t cache_irq_mask; - - if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) { - pr_err("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - irq = &sde_irq_map[irq_idx]; - reg_idx = irq->reg_idx; - reg = &sde_intr_set[reg_idx]; - - spin_lock_irqsave(&intr->mask_lock, irq_flags); - cache_irq_mask = intr->cache_irq_mask[reg_idx]; - if ((cache_irq_mask & irq->irq_mask) == 0) { - dbgstr = "SDE IRQ is already cleared:"; - } else { - dbgstr = "SDE IRQ mask disable:"; - - cache_irq_mask &= ~irq->irq_mask; - /* Disable interrupts based on the new mask */ - SDE_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); - /* Cleaning any pending interrupt */ - SDE_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); - - intr->cache_irq_mask[reg_idx] = cache_irq_mask; - } - spin_unlock_irqrestore(&intr->mask_lock, irq_flags); - - pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, - irq->irq_mask, cache_irq_mask); - - return 0; -} - -static int sde_hw_intr_clear_irqs(struct sde_hw_intr *intr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) - SDE_REG_WRITE(&intr->hw, sde_intr_set[i].clr_off, 0xffffffff); - - return 0; -} - -static int sde_hw_intr_disable_irqs(struct sde_hw_intr *intr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) - SDE_REG_WRITE(&intr->hw, sde_intr_set[i].en_off, 0x00000000); - - return 0; -} - -static int sde_hw_intr_get_valid_interrupts(struct sde_hw_intr *intr, - uint32_t *mask) -{ - *mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1 - | IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP; - return 0; -} - -static int sde_hw_intr_get_interrupt_sources(struct sde_hw_intr *intr, - uint32_t *sources) -{ - *sources = SDE_REG_READ(&intr->hw, HW_INTR_STATUS); - return 0; -} - -static void sde_hw_intr_get_interrupt_statuses(struct sde_hw_intr *intr) -{ - int i; - u32 enable_mask; - unsigned long irq_flags; - - spin_lock_irqsave(&intr->status_lock, irq_flags); - for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) { - /* Read interrupt status */ - intr->save_irq_status[i] = SDE_REG_READ(&intr->hw, - sde_intr_set[i].status_off); - - /* Read enable mask */ - enable_mask = SDE_REG_READ(&intr->hw, sde_intr_set[i].en_off); - - /* and clear the interrupt */ - if (intr->save_irq_status[i]) - SDE_REG_WRITE(&intr->hw, sde_intr_set[i].clr_off, - intr->save_irq_status[i]); - - /* Finally update IRQ status based on enable mask */ - intr->save_irq_status[i] &= enable_mask; - } - spin_unlock_irqrestore(&intr->status_lock, irq_flags); -} - -static void sde_hw_intr_clear_interrupt_status(struct sde_hw_intr *intr, - int irq_idx) -{ - int reg_idx; - unsigned long irq_flags; - - spin_lock_irqsave(&intr->mask_lock, irq_flags); - - reg_idx = sde_irq_map[irq_idx].reg_idx; - SDE_REG_WRITE(&intr->hw, sde_intr_set[reg_idx].clr_off, - sde_irq_map[irq_idx].irq_mask); - - spin_unlock_irqrestore(&intr->mask_lock, irq_flags); -} - - -static void __setup_intr_ops(struct sde_hw_intr_ops *ops) -{ - ops->set_mask = sde_hw_intr_set_mask; - ops->irq_idx_lookup = sde_hw_intr_irqidx_lookup; - ops->enable_irq = sde_hw_intr_enable_irq; - ops->disable_irq = sde_hw_intr_disable_irq; - ops->dispatch_irqs = sde_hw_intr_dispatch_irq; - ops->clear_all_irqs = sde_hw_intr_clear_irqs; - ops->disable_all_irqs = sde_hw_intr_disable_irqs; - ops->get_valid_interrupts = sde_hw_intr_get_valid_interrupts; - ops->get_interrupt_sources = sde_hw_intr_get_interrupt_sources; - ops->get_interrupt_statuses = sde_hw_intr_get_interrupt_statuses; - ops->clear_interrupt_status = sde_hw_intr_clear_interrupt_status; -} - -static struct sde_mdss_base_cfg *__intr_offset(struct sde_mdss_cfg *m, - void __iomem *addr, struct sde_hw_blk_reg_map *hw) -{ - if (m->mdp_count == 0) - return NULL; - - hw->base_off = addr; - hw->blk_off = m->mdss[0].base; - hw->hwversion = m->hwversion; - return &m->mdss[0]; -} - -struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr, - struct sde_mdss_cfg *m) -{ - struct sde_hw_intr *intr = kzalloc(sizeof(*intr), GFP_KERNEL); - struct sde_mdss_base_cfg *cfg; - - if (!intr) - return ERR_PTR(-ENOMEM); - - cfg = __intr_offset(m, addr, &intr->hw); - if (!cfg) { - kfree(intr); - return ERR_PTR(-EINVAL); - } - __setup_intr_ops(&intr->ops); - - intr->irq_idx_tbl_size = ARRAY_SIZE(sde_irq_map); - - intr->cache_irq_mask = kcalloc(ARRAY_SIZE(sde_intr_set), sizeof(u32), - GFP_KERNEL); - if (intr->cache_irq_mask == NULL) { - kfree(intr); - return ERR_PTR(-ENOMEM); - } - - intr->save_irq_status = kcalloc(ARRAY_SIZE(sde_intr_set), sizeof(u32), - GFP_KERNEL); - if (intr->save_irq_status == NULL) { - kfree(intr->cache_irq_mask); - kfree(intr); - return ERR_PTR(-ENOMEM); - } - - spin_lock_init(&intr->mask_lock); - spin_lock_init(&intr->status_lock); - - return intr; -} - -void sde_hw_intr_destroy(struct sde_hw_intr *intr) -{ - if (intr) { - kfree(intr->cache_irq_mask); - kfree(intr->save_irq_status); - kfree(intr); - } -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h deleted file mode 100644 index 0ddb1e78a953..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h +++ /dev/null @@ -1,245 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _SDE_HW_INTERRUPTS_H -#define _SDE_HW_INTERRUPTS_H - -#include <linux/types.h> - -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_mdp_util.h" -#include "sde_hw_mdss.h" - -#define IRQ_SOURCE_MDP BIT(0) -#define IRQ_SOURCE_DSI0 BIT(4) -#define IRQ_SOURCE_DSI1 BIT(5) -#define IRQ_SOURCE_HDMI BIT(8) -#define IRQ_SOURCE_EDP BIT(12) -#define IRQ_SOURCE_MHL BIT(16) - -/** - * sde_intr_type - HW Interrupt Type - * @SDE_IRQ_TYPE_WB_ROT_COMP: WB rotator done - * @SDE_IRQ_TYPE_WB_WFD_COMP: WB WFD done - * @SDE_IRQ_TYPE_PING_PONG_COMP: PingPong done - * @SDE_IRQ_TYPE_PING_PONG_RD_PTR: PingPong read pointer - * @SDE_IRQ_TYPE_PING_PONG_WR_PTR: PingPong write pointer - * @SDE_IRQ_TYPE_PING_PONG_AUTO_REF: PingPong auto refresh - * @SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK: PingPong Tear check - * @SDE_IRQ_TYPE_PING_PONG_TE_CHECK: PingPong TE detection - * @SDE_IRQ_TYPE_INTF_UNDER_RUN: INTF underrun - * @SDE_IRQ_TYPE_INTF_VSYNC: INTF VSYNC - * @SDE_IRQ_TYPE_CWB_OVERFLOW: Concurrent WB overflow - * @SDE_IRQ_TYPE_HIST_VIG_DONE: VIG Histogram done - * @SDE_IRQ_TYPE_HIST_VIG_RSTSEQ: VIG Histogram reset - * @SDE_IRQ_TYPE_HIST_DSPP_DONE: DSPP Histogram done - * @SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ: DSPP Histogram reset - * @SDE_IRQ_TYPE_WD_TIMER: Watchdog timer - * @SDE_IRQ_TYPE_SFI_VIDEO_IN: Video static frame INTR into static - * @SDE_IRQ_TYPE_SFI_VIDEO_OUT: Video static frame INTR out-of static - * @SDE_IRQ_TYPE_SFI_CMD_0_IN: DSI CMD0 static frame INTR into static - * @SDE_IRQ_TYPE_SFI_CMD_0_OUT: DSI CMD0 static frame INTR out-of static - * @SDE_IRQ_TYPE_SFI_CMD_1_IN: DSI CMD1 static frame INTR into static - * @SDE_IRQ_TYPE_SFI_CMD_1_OUT: DSI CMD1 static frame INTR out-of static - * @SDE_IRQ_TYPE_SFI_CMD_2_IN: DSI CMD2 static frame INTR into static - * @SDE_IRQ_TYPE_SFI_CMD_2_OUT: DSI CMD2 static frame INTR out-of static - * @SDE_IRQ_TYPE_PROG_LINE: Programmable Line interrupt - * @SDE_IRQ_TYPE_RESERVED: Reserved for expansion - */ -enum sde_intr_type { - SDE_IRQ_TYPE_WB_ROT_COMP, - SDE_IRQ_TYPE_WB_WFD_COMP, - SDE_IRQ_TYPE_PING_PONG_COMP, - SDE_IRQ_TYPE_PING_PONG_RD_PTR, - SDE_IRQ_TYPE_PING_PONG_WR_PTR, - SDE_IRQ_TYPE_PING_PONG_AUTO_REF, - SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, - SDE_IRQ_TYPE_PING_PONG_TE_CHECK, - SDE_IRQ_TYPE_INTF_UNDER_RUN, - SDE_IRQ_TYPE_INTF_VSYNC, - SDE_IRQ_TYPE_CWB_OVERFLOW, - SDE_IRQ_TYPE_HIST_VIG_DONE, - SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, - SDE_IRQ_TYPE_HIST_DSPP_DONE, - SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, - SDE_IRQ_TYPE_WD_TIMER, - SDE_IRQ_TYPE_SFI_VIDEO_IN, - SDE_IRQ_TYPE_SFI_VIDEO_OUT, - SDE_IRQ_TYPE_SFI_CMD_0_IN, - SDE_IRQ_TYPE_SFI_CMD_0_OUT, - SDE_IRQ_TYPE_SFI_CMD_1_IN, - SDE_IRQ_TYPE_SFI_CMD_1_OUT, - SDE_IRQ_TYPE_SFI_CMD_2_IN, - SDE_IRQ_TYPE_SFI_CMD_2_OUT, - SDE_IRQ_TYPE_PROG_LINE, - SDE_IRQ_TYPE_RESERVED, -}; - -struct sde_hw_intr; - -/** - * Interrupt operations. - */ -struct sde_hw_intr_ops { - /** - * set_mask - Programs the given interrupt register with the - * given interrupt mask. Register value will get overwritten. - * @intr: HW interrupt handle - * @reg_off: MDSS HW register offset - * @irqmask: IRQ mask value - */ - void (*set_mask)( - struct sde_hw_intr *intr, - uint32_t reg, - uint32_t irqmask); - - /** - * irq_idx_lookup - Lookup IRQ index on the HW interrupt type - * Used for all irq related ops - * @intr_type: Interrupt type defined in sde_intr_type - * @instance_idx: HW interrupt block instance - * @return: irq_idx or -EINVAL for lookup fail - */ - int (*irq_idx_lookup)( - enum sde_intr_type intr_type, - u32 instance_idx); - - /** - * enable_irq - Enable IRQ based on lookup IRQ index - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - * @return: 0 for success, otherwise failure - */ - int (*enable_irq)( - struct sde_hw_intr *intr, - int irq_idx); - - /** - * disable_irq - Disable IRQ based on lookup IRQ index - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - * @return: 0 for success, otherwise failure - */ - int (*disable_irq)( - struct sde_hw_intr *intr, - int irq_idx); - - /** - * clear_all_irqs - Clears all the interrupts (i.e. acknowledges - * any asserted IRQs). Useful during reset. - * @intr: HW interrupt handle - * @return: 0 for success, otherwise failure - */ - int (*clear_all_irqs)( - struct sde_hw_intr *intr); - - /** - * disable_all_irqs - Disables all the interrupts. Useful during reset. - * @intr: HW interrupt handle - * @return: 0 for success, otherwise failure - */ - int (*disable_all_irqs)( - struct sde_hw_intr *intr); - - /** - * dispatch_irqs - IRQ dispatcher will call the given callback - * function when a matching interrupt status bit is - * found in the irq mapping table. - * @intr: HW interrupt handle - * @cbfunc: Callback function pointer - * @arg: Argument to pass back during callback - */ - void (*dispatch_irqs)( - struct sde_hw_intr *intr, - void (*cbfunc)(void *arg, int irq_idx), - void *arg); - - /** - * get_interrupt_statuses - Gets and store value from all interrupt - * status registers that are currently fired. - * @intr: HW interrupt handle - */ - void (*get_interrupt_statuses)( - struct sde_hw_intr *intr); - - /** - * clear_interrupt_status - Clears HW interrupt status based on given - * lookup IRQ index. - * @intr: HW interrupt handle - * @irq_idx: Lookup irq index return from irq_idx_lookup - */ - void (*clear_interrupt_status)( - struct sde_hw_intr *intr, - int irq_idx); - - /** - * get_valid_interrupts - Gets a mask of all valid interrupt sources - * within SDE. These are actually status bits - * within interrupt registers that specify the - * source of the interrupt in IRQs. For example, - * valid interrupt sources can be MDP, DSI, - * HDMI etc. - * @intr: HW interrupt handle - * @mask: Returning the interrupt source MASK - * @return: 0 for success, otherwise failure - */ - int (*get_valid_interrupts)( - struct sde_hw_intr *intr, - uint32_t *mask); - - /** - * get_interrupt_sources - Gets the bitmask of the SDE interrupt - * source that are currently fired. - * @intr: HW interrupt handle - * @sources: Returning the SDE interrupt source status bit mask - * @return: 0 for success, otherwise failure - */ - int (*get_interrupt_sources)( - struct sde_hw_intr *intr, - uint32_t *sources); -}; - -/** - * struct sde_hw_intr: hw interrupts handling data structure - * @hw: virtual address mapping - * @ops: function pointer mapping for IRQ handling - * @cache_irq_mask: array of IRQ enable masks reg storage created during init - * @save_irq_status: array of IRQ status reg storage created during init - * @irq_idx_tbl_size: total number of irq_idx mapped in the hw_interrupts - * @mask_lock: spinlock for accessing IRQ mask - * @status_lock: spinlock for accessing IRQ status - */ -struct sde_hw_intr { - struct sde_hw_blk_reg_map hw; - struct sde_hw_intr_ops ops; - u32 *cache_irq_mask; - u32 *save_irq_status; - u32 irq_idx_tbl_size; - spinlock_t mask_lock; - spinlock_t status_lock; -}; - -/** - * sde_hw_intr_init(): Initializes the interrupts hw object - * @addr: mapped register io address of MDP - * @m : pointer to mdss catalog data - */ -struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr, - struct sde_mdss_cfg *m); - -/** - * sde_hw_intr_destroy(): Cleanup interrutps hw object - * @intr: pointer to interrupts hw object - */ -void sde_hw_intr_destroy(struct sde_hw_intr *intr); -#endif diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c index 8dd306720e90..b108e34de24f 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c @@ -13,7 +13,6 @@ #include "sde_hwio.h" #include "sde_hw_catalog.h" #include "sde_hw_intf.h" -#include "sde_hw_mdp_top.h" #define INTF_TIMING_ENGINE_EN 0x000 #define INTF_CONFIG 0x004 @@ -71,8 +70,7 @@ static struct sde_intf_cfg *_intf_offset(enum sde_intf intf, int i; for (i = 0; i < m->intf_count; i++) { - if ((intf == m->intf[i].id) && - (m->intf[i].type != INTF_NONE)) { + if (intf == m->intf[i].id) { b->base_off = addr; b->blk_off = m->intf[i].base; b->hwversion = m->hwversion; @@ -160,13 +158,13 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, (hsync_polarity << 0); /* HSYNC Polarity */ if (!fmt->is_yuv) - panel_format = (fmt->bits[C0_G_Y] | - (fmt->bits[C1_B_Cb] << 2) | - (fmt->bits[C2_R_Cr] << 4) | + panel_format = (fmt->bits[0] | + (fmt->bits[1] << 2) | + (fmt->bits[2] << 4) | (0x21 << 8)); else - /* Interface treats all the pixel data in RGB888 format */ - panel_format = (COLOR_8BIT | + /* Interface treats all the pixel data in RGB888 format */ + panel_format |= (COLOR_8BIT | (COLOR_8BIT << 2) | (COLOR_8BIT << 4) | (0x21 << 8)); @@ -206,16 +204,10 @@ static void sde_hw_intf_enable_timing_engine( /* Display interface select */ if (enable) { - /* top block */ - struct sde_hw_mdp *mdp = sde_hw_mdptop_init(MDP_TOP, - c->base_off, - intf->mdss); - struct sde_hw_blk_reg_map *top = &mdp->hw; + intf_sel = SDE_REG_READ(c, DISP_INTF_SEL); - intf_sel = SDE_REG_READ(top, DISP_INTF_SEL); - - intf_sel |= (intf->cap->type << ((intf->idx - INTF_0) * 8)); - SDE_REG_WRITE(top, DISP_INTF_SEL, intf_sel); + intf_sel |= (intf->cap->type << ((intf->idx) * 8)); + SDE_REG_WRITE(c, DISP_INTF_SEL, intf_sel); } SDE_REG_WRITE(c, INTF_TIMING_ENGINE_EN, @@ -362,9 +354,8 @@ struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, return ERR_PTR(-ENOMEM); cfg = _intf_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { + if (!cfg) { kfree(c); - pr_err("Error Panic\n"); return ERR_PTR(-EINVAL); } @@ -373,7 +364,6 @@ struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, */ c->idx = idx; c->cap = cfg; - c->mdss = m; _setup_intf_ops(&c->ops, c->cap->features); /* @@ -381,9 +371,3 @@ struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, */ return c; } - -void sde_hw_intf_deinit(struct sde_hw_intf *intf) -{ - kfree(intf); -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h index 2de57868901a..f0d8a32dc802 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h @@ -15,7 +15,6 @@ #include "sde_hw_catalog.h" #include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" struct sde_hw_intf; @@ -85,7 +84,6 @@ struct sde_hw_intf { /* intf */ enum sde_intf idx; const struct sde_intf_cfg *cap; - const struct sde_mdss_cfg *mdss; /* ops */ struct sde_hw_intf_ops ops; @@ -102,6 +100,4 @@ struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, void __iomem *addr, struct sde_mdss_cfg *m); -void sde_hw_intf_deinit(struct sde_hw_intf *intf); - #endif /*_SDE_HW_INTF_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c index 56ebe8fa05b5..0a20821f3a32 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c @@ -58,7 +58,7 @@ static inline int _stage_offset(struct sde_hw_mixer *ctx, enum sde_stage stage) return -EINVAL; if ((stage - SDE_STAGE_0) <= sblk->maxblendstages) - return sblk->blendstage_base[stage - 1]; + return sblk->blendstage_base[stage]; else return -EINVAL; } @@ -76,7 +76,7 @@ static void sde_hw_lm_setup_out(struct sde_hw_mixer *ctx, SDE_REG_WRITE(c, LM_OUT_SIZE, outsize); /* SPLIT_LEFT_RIGHT */ - opmode = (opmode & ~(1 << 31)) | ((mixer->right_mixer) ? (1 << 31) : 0); + opmode = (opmode & ~(1 << 31)) | (mixer->right_mixer & 1 << 31); SDE_REG_WRITE(c, LM_OP_MODE, opmode); } @@ -126,9 +126,9 @@ static void sde_hw_lm_setup_blendcfg(struct sde_hw_mixer *ctx, SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg->const_alpha); - SDE_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, + SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, bg->const_alpha); - SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); + SDE_REG_WRITE(c, LM_OP_MODE, blend_op); } static void sde_hw_lm_setup_color3(struct sde_hw_mixer *ctx, diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c index f7181ab9ed3d..4886cdf87c9f 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c @@ -15,9 +15,9 @@ #include "sde_hw_mdp_ctl.h" #define CTL_LAYER(lm) \ - (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004)) + (((lm) == 5) ? (0x024) : ((lm) * 0x004)) #define CTL_LAYER_EXT(lm) \ - (0x40 + (((lm) - LM_0) * 0x004)) + (0x40 + ((lm) * 0x004)) #define CTL_TOP 0x014 #define CTL_FLUSH 0x018 #define CTL_START 0x01C @@ -61,14 +61,15 @@ static int _mixer_stages(const struct sde_lm_cfg *mixer, int count, return stages; } -static inline void sde_hw_ctl_force_start(struct sde_hw_ctl *ctx) +static inline void sde_hw_ctl_setup_flush(struct sde_hw_ctl *ctx, u32 flushbits, + u8 force_start) { - SDE_REG_WRITE(&ctx->hw, CTL_START, 0x1); -} + struct sde_hw_blk_reg_map *c = &ctx->hw; -static inline void sde_hw_ctl_setup_flush(struct sde_hw_ctl *ctx, u32 flushbits) -{ - SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, flushbits); + SDE_REG_WRITE(c, CTL_FLUSH, flushbits); + + if (force_start) + SDE_REG_WRITE(c, CTL_START, 0x1); } static inline int sde_hw_ctl_get_bitmask_sspp(struct sde_hw_ctl *ctx, @@ -221,7 +222,7 @@ static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx, struct sde_hw_stage_cfg *cfg) { struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 mixercfg, mixercfg_ext = 0; + u32 mixercfg, mixercfg_ext; int i, j; u8 stages; int pipes_per_stage; @@ -236,8 +237,8 @@ static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx, else pipes_per_stage = 1; - mixercfg = cfg->border_enable << 24; /* BORDER_OUT */ - + mixercfg = cfg->border_enable >> 24; /* BORDER_OUT */ +; for (i = 0; i <= stages; i++) { for (j = 0; j < pipes_per_stage; j++) { switch (cfg->stage[i][j]) { @@ -297,38 +298,17 @@ static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx, SDE_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext); } -static void sde_hw_ctl_intf_cfg(struct sde_hw_ctl *ctx, - struct sde_hw_intf_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &ctx->hw; - u32 intf_cfg = 0; - - intf_cfg |= (cfg->intf & 0xF) << 4; - - if (cfg->wb) - intf_cfg |= (cfg->wb & 0x3) + 2; - - if (cfg->mode_3d) { - intf_cfg |= BIT(19); - intf_cfg |= (cfg->mode_3d - 1) << 20; - } - - SDE_REG_WRITE(c, CTL_TOP, intf_cfg); -} - static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, unsigned long cap) { ops->setup_flush = sde_hw_ctl_setup_flush; - ops->setup_start = sde_hw_ctl_force_start; - ops->setup_intf_cfg = sde_hw_ctl_intf_cfg; ops->reset = sde_hw_ctl_reset_control; - ops->setup_blendstage = sde_hw_ctl_setup_blendstage; ops->get_bitmask_sspp = sde_hw_ctl_get_bitmask_sspp; ops->get_bitmask_mixer = sde_hw_ctl_get_bitmask_mixer; ops->get_bitmask_dspp = sde_hw_ctl_get_bitmask_dspp; ops->get_bitmask_intf = sde_hw_ctl_get_bitmask_intf; ops->get_bitmask_cdm = sde_hw_ctl_get_bitmask_cdm; + ops->setup_blendstage = sde_hw_ctl_setup_blendstage; }; struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, @@ -343,9 +323,8 @@ struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, return ERR_PTR(-ENOMEM); cfg = _ctl_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { + if (cfg) { kfree(c); - pr_err("Error Panic\n"); return ERR_PTR(-EINVAL); } @@ -357,8 +336,3 @@ struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, return c; } - -void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx) -{ - kfree(ctx); -} diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h index e914abd69906..5782b356bcf6 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h @@ -14,7 +14,6 @@ #define _SDE_HW_MDP_CTL_H #include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" #include "sde_hw_catalog.h" struct sde_hw_ctl; @@ -29,45 +28,13 @@ struct sde_hw_stage_cfg { }; /** - * struct sde_hw_intf_cfg :Desbribes how the mdp writes data to - * output interface - * @intf : Interface id - * @wb: writeback id - * @mode_3d: 3d mux configuration - */ -struct sde_hw_intf_cfg { - enum sde_intf intf; - enum sde_wb wb; - enum sde_3d_blend_mode mode_3d; -}; - -/** * struct sde_hw_ctl_ops - Interface to the wb Hw driver functions * Assumption is these functions will be called after clocks are enabled */ struct sde_hw_ctl_ops { - /** - * kickoff hw operation for Sw controlled interfaces - * DSI cmd mode and WB interface are SW controlled - * @ctx : ctl path ctx pointer - */ - void (*setup_start)(struct sde_hw_ctl *ctx); - - /** - * FLUSH the modules for this control path - * @ctx : ctl path ctx pointer - * @flushbits : module flushmask - */ void (*setup_flush)(struct sde_hw_ctl *ctx, - u32 flushbits); - - /** - * Setup ctl_path interface config - * @ctx - * @cfg : interface config structure pointer - */ - void (*setup_intf_cfg)(struct sde_hw_ctl *ctx, - struct sde_hw_intf_cfg *cfg); + u32 flushbits, + u8 force_start); int (*reset)(struct sde_hw_ctl *c); @@ -120,7 +87,7 @@ struct sde_hw_ctl { /** * sde_hw_ctl_init(): Initializes the ctl_path hw driver object. - * should be called before accessing every ctl path registers. + * should be called before accessing every mixer. * @idx: ctl_path index for which driver object is required * @addr: mapped register io address of MDP * @m : pointer to mdss catalog data @@ -129,10 +96,4 @@ struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, void __iomem *addr, struct sde_mdss_cfg *m); -/** - * sde_hw_ctl_destroy(): Destroys ctl driver context - * should be called to free the context - */ -void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx); - #endif /*_SDE_HW_MDP_CTL_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c deleted file mode 100644 index 92c08fff2031..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sde_hwio.h" -#include "sde_hw_catalog.h" -#include "sde_hw_mdp_top.h" - -#define SPLIT_DISPLAY_ENABLE 0x2F4 -#define LOWER_PIPE_CTRL 0x2F8 -#define UPPER_PIPE_CTRL 0x3F0 -#define TE_LINE_INTERVAL 0x3F4 - -static void sde_hw_setup_split_pipe_control(struct sde_hw_mdp *mdp, - struct split_pipe_cfg *cfg) -{ - struct sde_hw_blk_reg_map *c = &mdp->hw; - u32 upper_pipe; - u32 lower_pipe; - - if (cfg->en) { - upper_pipe = BIT(8); - lower_pipe = BIT(8); - - if (cfg->mode == INTF_MODE_CMD) { - upper_pipe |= BIT(0); - lower_pipe |= BIT(0); - } - - SDE_REG_WRITE(c, LOWER_PIPE_CTRL, lower_pipe); - SDE_REG_WRITE(c, UPPER_PIPE_CTRL, upper_pipe); - } - - SDE_REG_WRITE(c, SPLIT_DISPLAY_ENABLE, cfg->en & 0x1); -} - -static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, - unsigned long cap) -{ - ops->setup_split_pipe = sde_hw_setup_split_pipe_control; -} - -static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp, - const struct sde_mdss_cfg *m, - void __iomem *addr, - struct sde_hw_blk_reg_map *b) -{ - int i; - - for (i = 0; i < m->mdp_count; i++) { - if (mdp == m->mdp[i].id) { - b->base_off = addr; - b->blk_off = m->mdp[i].base; - b->hwversion = m->hwversion; - return &m->mdp[i]; - } - } - - return ERR_PTR(-EINVAL); -} - -struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx, - void __iomem *addr, - const struct sde_mdss_cfg *m) -{ - static struct sde_hw_mdp *c; - const struct sde_mdp_cfg *cfg; - - /* mdp top is singleton */ - if (c) { - pr_err(" %s returning %pK", __func__, c); - return c; - } - - c = kzalloc(sizeof(*c), GFP_KERNEL); - pr_err(" %s returning %pK", __func__, c); - if (!c) - return ERR_PTR(-ENOMEM); - - cfg = _top_offset(idx, m, addr, &c->hw); - if (IS_ERR_OR_NULL(cfg)) { - kfree(c); - return ERR_PTR(-EINVAL); - } - - /* - * Assign ops - */ - c->idx = idx; - c->cap = cfg; - _setup_mdp_ops(&c->ops, c->cap->features); - - /* - * Perform any default initialization for the intf - */ - return c; -} - -void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp) -{ -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.h deleted file mode 100644 index 216a27e93d46..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _SDE_HW_MDP_TOP_H -#define _SDE_HW_MDP_TOP_H - -#include "sde_hw_catalog.h" -#include "sde_hw_mdss.h" -#include "sde_hw_mdp_util.h" - -struct sde_hw_mdp; - -/** - * struct split_pipe_cfg - pipe configuration for dual display panels - * @en : Enable/disable dual pipe confguration - * @mode : Panel interface mode - */ -struct split_pipe_cfg { - bool en; - enum sde_intf_mode mode; -}; - -/** - * struct sde_hw_mdp_ops - interface to the MDP TOP Hw driver functions - * Assumption is these functions will be called after clocks are enabled. - * @setup_split_pipe : Programs the pipe control registers - */ -struct sde_hw_mdp_ops { - void (*setup_split_pipe)(struct sde_hw_mdp *mdp, - struct split_pipe_cfg *p); -}; - -struct sde_hw_mdp { - /* base */ - struct sde_hw_blk_reg_map hw; - - /* intf */ - enum sde_mdp idx; - const struct sde_mdp_cfg *cap; - - /* ops */ - struct sde_hw_mdp_ops ops; -}; - -/** - * sde_hw_intf_init - initializes the intf driver for the passed interface idx - * @idx: Interface index for which driver object is required - * @addr: Mapped register io address of MDP - * @m: Pointer to mdss catalog data - */ -struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx, - void __iomem *addr, - const struct sde_mdss_cfg *m); - -void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp); - -#endif /*_SDE_HW_MDP_TOP_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index 075e78042f17..ce7ecbf4c8c1 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/err.h> -#define SDE_NONE 0 #define SDE_CSC_MATRIX_COEFF_SIZE 9 #define SDE_CSC_CLAMP_SIZE 6 #define SDE_CSC_BIAS_SIZE 3 @@ -58,7 +57,7 @@ enum sde_sspp_type { }; enum sde_lm { - LM_0 = 1, + LM_0 = 0, LM_1, LM_2, LM_3, @@ -80,7 +79,7 @@ enum sde_stage { SDE_STAGE_MAX }; enum sde_dspp { - DSPP_0 = 1, + DSPP_0 = 0, DSPP_1, DSPP_2, DSPP_3, @@ -88,7 +87,7 @@ enum sde_dspp { }; enum sde_ctl { - CTL_0 = 1, + CTL_0 = 0, CTL_1, CTL_2, CTL_3, @@ -97,23 +96,22 @@ enum sde_ctl { }; enum sde_cdm { - CDM_0 = 1, + CDM_0 = 0, CDM_1, CDM_MAX }; enum sde_pingpong { - PINGPONG_0 = 1, + PINGPONG_0 = 0, PINGPONG_1, PINGPONG_2, PINGPONG_3, PINGPONG_4, - PINGPONG_S0, PINGPONG_MAX }; enum sde_intf { - INTF_0 = 1, + INTF_0 = 0, INTF_1, INTF_2, INTF_3, @@ -155,24 +153,6 @@ enum sde_ad { AD_MAX }; -enum sde_cwb { - CWB_0 = 0x1, - CWB_1, - CWB_2, - CWB_3, - CWB_MAX -}; - -enum sde_wd_timer { - WD_TIMER_0 = 0x1, - WD_TIMER_1, - WD_TIMER_2, - WD_TIMER_3, - WD_TIMER_4, - WD_TIMER_5, - WD_TIMER_MAX -}; - /** * MDP HW,Component order color map */ @@ -228,10 +208,12 @@ enum sde_mdp_fetch_type { * expected by the HW programming. */ enum { - COLOR_1BIT = 0, - COLOR_5BIT = 1, - COLOR_6BIT = 2, - COLOR_8BIT = 3, + COLOR_4BIT, + COLOR_5BIT, + COLOR_6BIT, + COLOR_8BIT, + COLOR_ALPHA_1BIT = 0, + COLOR_ALPHA_4BIT = 1, }; enum sde_alpha_blend_type { @@ -242,26 +224,6 @@ enum sde_alpha_blend_type { ALPHA_MAX }; - -/** - * enum sde_3d_blend_mode - * Desribes how the 3d data is blended - * @BLEND_3D_NONE : 3d blending not enabled - * @BLEND_3D_FRAME_INT : Frame interleaving - * @BLEND_3D_H_ROW_INT : Horizontal row interleaving - * @BLEND_3D_V_ROW_INT : vertical row interleaving - * @BLEND_3D_COL_INT : column interleaving - * @BLEND_3D_MAX : - */ -enum sde_3d_blend_mode { - BLEND_3D_NONE = 0, - BLEND_3D_FRAME_INT, - BLEND_3D_H_ROW_INT, - BLEND_3D_V_ROW_INT, - BLEND_3D_COL_INT, - BLEND_3D_MAX -}; - struct addr_info { u32 plane[SDE_MAX_PLANES]; }; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c index 8180078ac950..e179220daab9 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c @@ -182,7 +182,7 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, u32 opmode = 0; u32 idx; - if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + if (!_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) return; opmode = SDE_REG_READ(c, SSPP_SRC_OP_MODE + idx); @@ -210,7 +210,7 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, src_format = (chroma_samp << 23) | (fmt->fetch_planes << 19) | (fmt->bits[C3_ALPHA] << 6) | (fmt->bits[C2_R_Cr] << 4) | - (fmt->bits[C1_B_Cb] << 2) | (fmt->bits[C0_G_Y] << 0); + (fmt->bits[C0_G_Y] << 0); if (flags & SDE_SSPP_ROT_90) src_format |= BIT(11); /* ROT90 */ @@ -235,9 +235,12 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, } /* if this is YUV pixel format, enable CSC */ - if (fmt->is_yuv) + if (fmt->is_yuv) { + _sspp_setup_opmode(ctx, CSC, 0x0); + } else { src_format |= BIT(15); - _sspp_setup_opmode(ctx, CSC, fmt->is_yuv); + _sspp_setup_opmode(ctx, CSC, 0x1); + } opmode |= MDSS_MDP_OP_PE_OVERRIDE; @@ -257,8 +260,8 @@ static void sde_hw_sspp_setup_pe_config(struct sde_hw_pipe *ctx, struct sde_hw_blk_reg_map *c = &ctx->hw; u8 color; u32 lr_pe[4], tb_pe[4], tot_req_pixels[4]; - const u32 bytemask = 0xff; - const u32 shortmask = 0xffff; + const u32 bytemask = 0xffff; + const u8 shortmask = 0xff; u32 idx; if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) @@ -280,7 +283,7 @@ static void sde_hw_sspp_setup_pe_config(struct sde_hw_pipe *ctx, ((pe_ext->top_ftch[color] & bytemask) << 8)| (pe_ext->top_rpt[color] & bytemask); - tot_req_pixels[color] = (((pe_ext->roi_h[color] + + tot_req_pixels[color] = (((cfg->src.height + pe_ext->num_ext_pxls_top[color] + pe_ext->num_ext_pxls_btm[color]) & shortmask) << 16) | ((pe_ext->roi_w[color] + @@ -320,30 +323,30 @@ static void sde_hw_sspp_setup_scalar(struct sde_hw_pipe *ctx, scale_config = BIT(0) | BIT(1); /* RGB/YUV config */ - scale_config |= (pe_ext->horz_filter[SDE_SSPP_COMP_LUMA] & mask) << 8; - scale_config |= (pe_ext->vert_filter[SDE_SSPP_COMP_LUMA] & mask) << 10; + scale_config |= (pe_ext->horz_filter[0] & mask) << 8; + scale_config |= (pe_ext->vert_filter[0] & mask) << 10; /* Aplha config*/ - scale_config |= (pe_ext->horz_filter[SDE_SSPP_COMP_ALPHA] & mask) << 16; - scale_config |= (pe_ext->vert_filter[SDE_SSPP_COMP_ALPHA] & mask) << 18; + scale_config |= (pe_ext->horz_filter[3] & mask) << 16; + scale_config |= (pe_ext->vert_filter[3] & mask) << 18; SDE_REG_WRITE(c, SCALE_CONFIG + idx, scale_config); SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_X + idx, - pe_ext->init_phase_x[SDE_SSPP_COMP_LUMA]); + pe_ext->init_phase_x[0]); SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_Y + idx, - pe_ext->init_phase_y[SDE_SSPP_COMP_LUMA]); + pe_ext->init_phase_y[0]); SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_X + idx, - pe_ext->phase_step_x[SDE_SSPP_COMP_LUMA]); + pe_ext->phase_step_x[0]); SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_Y + idx, - pe_ext->phase_step_y[SDE_SSPP_COMP_LUMA]); + pe_ext->phase_step_y[0]); SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_X + idx, - pe_ext->init_phase_x[SDE_SSPP_COMP_CHROMA]); + pe_ext->init_phase_x[1]); SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_Y + idx, - pe_ext->init_phase_y[SDE_SSPP_COMP_CHROMA]); + pe_ext->init_phase_y[1]); SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_X + idx, - pe_ext->phase_step_x[SDE_SSPP_COMP_CHROMA]); + pe_ext->phase_step_x[1]); SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_Y + idx, - pe_ext->phase_step_y[SDE_SSPP_COMP_CHROMA]); + pe_ext->phase_step_y[0]); } /** @@ -362,7 +365,7 @@ static void sde_hw_sspp_setup_rects(struct sde_hw_pipe *ctx, return; /* program pixel extension override */ - if (pe_ext) + if (!pe_ext) sde_hw_sspp_setup_pe_config(ctx, cfg, pe_ext); /* src and dest rect programming */ @@ -385,8 +388,10 @@ static void sde_hw_sspp_setup_rects(struct sde_hw_pipe *ctx, if (test_bit(SDE_SSPP_SCALAR_RGB, &ctx->cap->features) || test_bit(SDE_SSPP_SCALAR_QSEED2, &ctx->cap->features)) { /* program decimation */ - decimation = ((1 << cfg->horz_decimation) - 1) << 8; - decimation |= ((1 << cfg->vert_decimation) - 1); + if (!cfg->horz_decimation) + decimation = (cfg->horz_decimation - 1) << 8; + if (!cfg->vert_decimation) + decimation |= (cfg->vert_decimation - 1); sde_hw_sspp_setup_scalar(ctx, pe_ext); } @@ -414,8 +419,9 @@ static void sde_hw_sspp_setup_sourceaddress(struct sde_hw_pipe *ctx, return; for (i = 0; i < cfg->src.num_planes; i++) - SDE_REG_WRITE(c, SSPP_SRC0_ADDR + idx + i*0x4, + SDE_REG_WRITE(c, SSPP_SRC0_ADDR + idx + i*0x4, cfg->addr.plane[i]); + } static void sde_hw_sspp_setup_csc_8bit(struct sde_hw_pipe *ctx, @@ -470,6 +476,7 @@ static void sde_hw_sspp_setup_solidfill(struct sde_hw_pipe *ctx, static void sde_hw_sspp_setup_histogram_v1(struct sde_hw_pipe *ctx, void *cfg) { + } static void sde_hw_sspp_setup_memcolor(struct sde_hw_pipe *ctx, @@ -582,8 +589,3 @@ struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx, return c; } -void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx) -{ - kfree(ctx); -} - diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h index 0e78c52cde56..733837286241 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h @@ -15,6 +15,7 @@ #include "sde_hw_catalog.h" #include "sde_hw_mdss.h" +#include "sde_mdp_formats.h" #include "sde_hw_mdp_util.h" struct sde_hw_pipe; @@ -28,15 +29,6 @@ struct sde_hw_pipe; #define SDE_SSPP_SOURCE_ROTATED_90 0x8 #define SDE_SSPP_ROT_90 0x10 -/** - * Component indices - */ -enum { - SDE_SSPP_COMP_LUMA = 0, - SDE_SSPP_COMP_CHROMA = 1, - SDE_SSPP_COMP_ALPHA = 3 -}; - enum { SDE_MDP_FRAME_LINEAR, SDE_MDP_FRAME_TILE_A4X, @@ -96,7 +88,6 @@ struct sde_hw_pixel_ext { int btm_rpt[SDE_MAX_PLANES]; uint32_t roi_w[SDE_MAX_PLANES]; - uint32_t roi_h[SDE_MAX_PLANES]; /* * Filter type to be used for scaling in horizontal and vertical @@ -271,12 +262,5 @@ struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx, void __iomem *addr, struct sde_mdss_cfg *m); -/** - * sde_hw_sspp_destroy(): Destroys SSPP driver context - * should be called during Hw pipe cleanup. - * @ctx: Pointer to SSPP driver context returned by sde_hw_sspp_init - */ -void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx); - #endif /*_SDE_HW_SSPP_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h index 2531463b654e..df0530ecfa34 100644 --- a/drivers/gpu/drm/msm/sde/sde_hwio.h +++ b/drivers/gpu/drm/msm/sde/sde_hwio.h @@ -28,9 +28,6 @@ #define HIST_INTR_EN 0x01c #define HIST_INTR_STATUS 0x020 #define HIST_INTR_CLEAR 0x024 -#define INTF_INTR_EN 0x1C0 -#define INTF_INTR_STATUS 0x1C4 -#define INTF_INTR_CLEAR 0x1C8 #define SPLIT_DISPLAY_EN 0x2F4 #define SPLIT_DISPLAY_UPPER_PIPE_CTRL 0x2F8 #define DSPP_IGC_COLOR0_RAM_LUTN 0x300 diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c index 722845df3d0b..7f87acb86c96 100644 --- a/drivers/gpu/drm/msm/sde/sde_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_irq.c @@ -12,263 +12,36 @@ #include <linux/irqdomain.h> #include <linux/irq.h> -#include <linux/kthread.h> #include "msm_drv.h" #include "sde_kms.h" -static void sde_irq_callback_handler(void *arg, int irq_idx) +void sde_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, + uint32_t old_irqmask) { - struct sde_kms *sde_kms = arg; - struct sde_irq *irq_obj = &sde_kms->irq_obj; - - /* - * Perform registered function callback - */ - if (irq_obj->irq_cb_tbl && irq_obj->irq_cb_tbl[irq_idx].func) - irq_obj->irq_cb_tbl[irq_idx].func( - irq_obj->irq_cb_tbl[irq_idx].arg, - irq_idx); - - /* - * Clear pending interrupt status in HW. - * NOTE: sde_irq_callback_handler is protected by top-level - * spinlock, so it is safe to clear any interrupt status here. - */ - sde_kms->hw_intr->ops.clear_interrupt_status( - sde_kms->hw_intr, - irq_idx); -} - -static void sde_irq_intf_error_handler(void *arg, int irq_idx) -{ - DRM_ERROR("INTF underrun detected, irq_idx=%d\n", irq_idx); -} - -void sde_set_irqmask(struct sde_kms *sde_kms, uint32_t reg, uint32_t irqmask) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.set_mask) - return; - - sde_kms->hw_intr->ops.set_mask(sde_kms->hw_intr, reg, irqmask); -} - -int sde_irq_idx_lookup(struct sde_kms *sde_kms, enum sde_intr_type intr_type, - u32 instance_idx) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.irq_idx_lookup) - return -EINVAL; - - return sde_kms->hw_intr->ops.irq_idx_lookup(intr_type, - instance_idx); -} - -int sde_enable_irq(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count) -{ - int i; - int ret = 0; - - if (!sde_kms || !irq_idxs || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.enable_irq) - return -EINVAL; - - for (i = 0; i < irq_count; i++) { - ret = sde_kms->hw_intr->ops.enable_irq( - sde_kms->hw_intr, - irq_idxs[i]); - if (ret) { - DRM_ERROR("Fail to enable IRQ for irq_idx:%d\n", - irq_idxs[i]); - return ret; - } - } - - return ret; -} - -int sde_disable_irq(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count) -{ - int i; - int ret = 0; - - if (!sde_kms || !irq_idxs || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.disable_irq) - return -EINVAL; - - for (i = 0; i < irq_count; i++) { - ret = sde_kms->hw_intr->ops.disable_irq( - sde_kms->hw_intr, - irq_idxs[i]); - if (ret) { - DRM_ERROR("Fail to disable IRQ for irq_idx:%d\n", - irq_idxs[i]); - return ret; - } - } - - return ret; -} - -int sde_register_irq_callback(struct sde_kms *sde_kms, int irq_idx, - struct sde_irq_callback *register_irq_cb) -{ - struct sde_irq_callback *irq_cb_tbl; - unsigned long irq_flags; - - /* - * We allow NULL register_irq_cb as input for callback registration - */ - if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl) - return -EINVAL; - - if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) { - DRM_ERROR("invalid IRQ index: [%d]\n", irq_idx); - return -EINVAL; - } - - irq_cb_tbl = sde_kms->irq_obj.irq_cb_tbl; - spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); - irq_cb_tbl[irq_idx].func = register_irq_cb ? - register_irq_cb->func : NULL; - irq_cb_tbl[irq_idx].arg = register_irq_cb ? - register_irq_cb->arg : NULL; - spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); - - return 0; -} - -void sde_clear_all_irqs(struct sde_kms *sde_kms) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.clear_all_irqs) - return; - - sde_kms->hw_intr->ops.clear_all_irqs(sde_kms->hw_intr); -} - -void sde_disable_all_irqs(struct sde_kms *sde_kms) -{ - if (!sde_kms || !sde_kms->hw_intr || - !sde_kms->hw_intr->ops.disable_all_irqs) - return; - - sde_kms->hw_intr->ops.disable_all_irqs(sde_kms->hw_intr); } void sde_irq_preinstall(struct msm_kms *kms) { - struct sde_kms *sde_kms = to_sde_kms(kms); - - sde_enable(sde_kms); - sde_clear_all_irqs(sde_kms); - sde_disable_all_irqs(sde_kms); - sde_disable(sde_kms); - - spin_lock_init(&sde_kms->irq_obj.cb_lock); - - /* Create irq callbacks for all possible irq_idx */ - sde_kms->irq_obj.total_irqs = sde_kms->hw_intr->irq_idx_tbl_size; - sde_kms->irq_obj.irq_cb_tbl = kcalloc(sde_kms->irq_obj.total_irqs, - sizeof(struct sde_irq_callback), GFP_KERNEL); - if (!sde_kms->irq_obj.irq_cb_tbl) - DRM_ERROR("Fail to allocate memory of IRQ callback list\n"); } int sde_irq_postinstall(struct msm_kms *kms) { - struct sde_kms *sde_kms = to_sde_kms(kms); - struct sde_irq_callback irq_cb; - int irq_idx; - int i; - - irq_cb.func = sde_irq_intf_error_handler; - irq_cb.arg = sde_kms; - - /* Register interface underrun callback */ - sde_enable(sde_kms); - for (i = 0; i < sde_kms->catalog->intf_count; i++) { - irq_idx = sde_irq_idx_lookup(sde_kms, - SDE_IRQ_TYPE_INTF_UNDER_RUN, i+INTF_0); - sde_register_irq_callback(sde_kms, irq_idx, &irq_cb); - sde_enable_irq(sde_kms, &irq_idx, 1); - } - sde_disable(sde_kms); - return 0; } void sde_irq_uninstall(struct msm_kms *kms) { - struct sde_kms *sde_kms = to_sde_kms(kms); - - sde_enable(sde_kms); - sde_clear_all_irqs(sde_kms); - sde_disable_all_irqs(sde_kms); - sde_disable(sde_kms); - - kfree(sde_kms->irq_obj.irq_cb_tbl); -} - -static void _sde_irq_mdp_done(struct sde_kms *sde_kms) -{ - /* - * Read interrupt status from all sources. Interrupt status are - * stored within hw_intr. - * Function will also clear the interrupt status after reading. - * Individual interrupt status bit will only get stored if it - * is enabled. - */ - sde_kms->hw_intr->ops.get_interrupt_statuses(sde_kms->hw_intr); - - /* - * Dispatch to HW driver to handle interrupt lookup that is being - * fired. When matching interrupt is located, HW driver will call to - * sde_irq_callback_handler with the irq_idx from the lookup table. - * sde_irq_callback_handler will perform the registered function - * callback, and do the interrupt status clearing once the registered - * callback is finished. - */ - sde_kms->hw_intr->ops.dispatch_irqs( - sde_kms->hw_intr, - sde_irq_callback_handler, - sde_kms); } irqreturn_t sde_irq(struct msm_kms *kms) { - struct sde_kms *sde_kms = to_sde_kms(kms); - u32 interrupts; - - sde_kms->hw_intr->ops.get_interrupt_sources(sde_kms->hw_intr, - &interrupts); - - /* - * Taking care of MDP interrupt - */ - if (interrupts & IRQ_SOURCE_MDP) { - interrupts &= ~IRQ_SOURCE_MDP; - _sde_irq_mdp_done(sde_kms); - } - - /* - * Routing all other interrupts to external drivers - */ - while (interrupts) { - irq_hw_number_t hwirq = fls(interrupts) - 1; - - generic_handle_irq(irq_find_mapping( - sde_kms->irqcontroller.domain, hwirq)); - interrupts &= ~(1 << hwirq); - } - return IRQ_HANDLED; } int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { - return sde_crtc_vblank(crtc); + return 0; } void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) @@ -303,13 +76,6 @@ static int sde_hw_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct sde_kms *sde_kms = d->host_data; - uint32_t valid_irqs; - - sde_kms->hw_intr->ops.get_valid_interrupts(sde_kms->hw_intr, - &valid_irqs); - - if (!(valid_irqs & (1 << hwirq))) - return -EPERM; irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq); irq_set_chip_data(irq, sde_kms); diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 7fba38b9e60d..2cbff04e98cd 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -12,65 +12,31 @@ #include <drm/drm_crtc.h> #include "msm_drv.h" -#include "msm_mmu.h" #include "sde_kms.h" #include "sde_hw_mdss.h" -#include "sde_hw_intf.h" -static const char * const iommu_ports[] = { - "mdp_0", -}; - -static const struct sde_hw_res_map res_table[INTF_MAX] = { - { SDE_NONE, SDE_NONE, SDE_NONE, SDE_NONE}, - { INTF_0, SDE_NONE, SDE_NONE, SDE_NONE}, - { INTF_1, LM_0, PINGPONG_0, CTL_0}, - { INTF_2, LM_1, PINGPONG_1, CTL_1}, - { INTF_3, SDE_NONE, SDE_NONE, CTL_2}, -}; - - -#define DEFAULT_MDP_SRC_CLK 200000000 - -int sde_disable(struct sde_kms *sde_kms) -{ - DBG(""); - - return 0; -} - -int sde_enable(struct sde_kms *sde_kms) +static int modeset_init_intf(struct sde_kms *sde_kms, int intf_num) { - DBG(""); - - clk_prepare_enable(sde_kms->ahb_clk); - clk_prepare_enable(sde_kms->axi_clk); - clk_prepare_enable(sde_kms->core_clk); - if (sde_kms->lut_clk) - clk_prepare_enable(sde_kms->lut_clk); + struct sde_mdss_cfg *catalog = sde_kms->catalog; + u32 intf_type = catalog->intf[intf_num].type; + + switch (intf_type) { + case INTF_NONE: + break; + case INTF_DSI: + break; + case INTF_LCDC: + break; + case INTF_HDMI: + break; + case INTF_EDP: + default: + break; + } return 0; } -static void sde_prepare_commit(struct msm_kms *kms, - struct drm_atomic_state *state) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - sde_enable(sde_kms); -} - -static void sde_complete_commit(struct msm_kms *kms, - struct drm_atomic_state *state) -{ - struct sde_kms *sde_kms = to_sde_kms(kms); - sde_disable(sde_kms); -} - -static void sde_wait_for_crtc_commit_done(struct msm_kms *kms, - struct drm_crtc *crtc) -{ - sde_crtc_wait_for_commit_done(crtc); -} static int modeset_init(struct sde_kms *sde_kms) { struct msm_drm_private *priv = sde_kms->dev->dev_private; @@ -96,9 +62,8 @@ static int modeset_init(struct sde_kms *sde_kms) || !num_private_planes) primary = false; - plane = sde_plane_init(dev, catalog->sspp[i].id, primary); + plane = sde_plane_init(dev, primary); if (IS_ERR(plane)) { - pr_err("%s: sde_plane_init failed", __func__); ret = PTR_ERR(plane); goto fail; } @@ -106,7 +71,7 @@ static int modeset_init(struct sde_kms *sde_kms) if (primary) primary_planes[primary_planes_idx++] = plane; - if (primary && num_private_planes) + if (num_private_planes) num_private_planes--; } @@ -116,21 +81,15 @@ static int modeset_init(struct sde_kms *sde_kms) goto fail; } - /* - * Enumerate displays supported - */ - sde_encoders_init(dev); - - /* Create one CRTC per display */ - for (i = 0; i < priv->num_encoders; i++) { + /* Create one CRTC per mixer */ + for (i = 0; i < catalog->mixer_count; i++) { /* - * Each CRTC receives a private plane. We start + * Each mixer receives a private plane. We start * with first RGB, and then DMA and then VIG. */ struct drm_crtc *crtc; - crtc = sde_crtc_init(dev, priv->encoders[i], - primary_planes[i], i); + crtc = sde_crtc_init(dev, NULL, primary_planes[i], i); if (IS_ERR(crtc)) { ret = PTR_ERR(crtc); goto fail; @@ -138,13 +97,11 @@ static int modeset_init(struct sde_kms *sde_kms) priv->crtcs[priv->num_crtcs++] = crtc; } - /* - * Iterate through the list of encoders and - * set the possible CRTCs - */ - for (i = 0; i < priv->num_encoders; i++) - priv->encoders[i]->possible_crtcs = (1 << priv->num_crtcs) - 1; - + for (i = 0; i < catalog->intf_count; i++) { + ret = modeset_init_intf(sde_kms, i); + if (ret) + goto fail; + } return 0; fail: return ret; @@ -167,28 +124,27 @@ static void sde_preclose(struct msm_kms *kms, struct drm_file *file) static void sde_destroy(struct msm_kms *kms) { - struct sde_kms *sde_kms = to_sde_kms(kms); + struct sde_kms *sde_kms = to_sde_kms(to_mdp_kms(kms)); sde_irq_domain_fini(sde_kms); - sde_hw_intr_destroy(sde_kms->hw_intr); kfree(sde_kms); } -static const struct msm_kms_funcs kms_funcs = { - .hw_init = sde_hw_init, - .irq_preinstall = sde_irq_preinstall, - .irq_postinstall = sde_irq_postinstall, - .irq_uninstall = sde_irq_uninstall, - .irq = sde_irq, - .prepare_commit = sde_prepare_commit, - .complete_commit = sde_complete_commit, - .wait_for_crtc_commit_done = sde_wait_for_crtc_commit_done, - .enable_vblank = sde_enable_vblank, - .disable_vblank = sde_disable_vblank, - .get_format = mdp_get_format, - .round_pixclk = sde_round_pixclk, - .preclose = sde_preclose, - .destroy = sde_destroy, +static const struct mdp_kms_funcs kms_funcs = { + .base = { + .hw_init = sde_hw_init, + .irq_preinstall = sde_irq_preinstall, + .irq_postinstall = sde_irq_postinstall, + .irq_uninstall = sde_irq_uninstall, + .irq = sde_irq, + .enable_vblank = sde_enable_vblank, + .disable_vblank = sde_disable_vblank, + .get_format = mdp_get_format, + .round_pixclk = sde_round_pixclk, + .preclose = sde_preclose, + .destroy = sde_destroy, + }, + .set_irqmask = sde_set_irqmask, }; static int get_clk(struct platform_device *pdev, struct clk **clkp, @@ -219,16 +175,15 @@ struct sde_kms *sde_hw_setup(struct platform_device *pdev) if (!sde_kms) return NULL; - msm_kms_init(&sde_kms->base, &kms_funcs); + mdp_kms_init(&sde_kms->base, &kms_funcs); - kms = &sde_kms->base; + kms = &sde_kms->base.base; sde_kms->mmio = msm_ioremap(pdev, "mdp_phys", "SDE"); if (IS_ERR(sde_kms->mmio)) { ret = PTR_ERR(sde_kms->mmio); goto fail; } - pr_err("Mapped Mdp address space @%pK", sde_kms->mmio); sde_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); if (IS_ERR(sde_kms->vbif)) { @@ -292,27 +247,8 @@ struct sde_kms *sde_hw_setup(struct platform_device *pdev) get_clk(pdev, &sde_kms->mmagic_clk, "mmagic_clk", false); get_clk(pdev, &sde_kms->iommu_clk, "iommu_clk", false); - if (sde_kms->mmagic) { - ret = regulator_enable(sde_kms->mmagic); - if (ret) { - dev_err(sde_kms->dev->dev, - "failed to enable mmagic GDSC: %d\n", ret); - goto fail; - } - } - if (sde_kms->mmagic_clk) { - clk_prepare_enable(sde_kms->mmagic_clk); - if (ret) { - dev_err(sde_kms->dev->dev, "failed to enable mmagic_clk\n"); - goto undo_gdsc; - } - } - return sde_kms; -undo_gdsc: - if (sde_kms->mmagic) - regulator_disable(sde_kms->mmagic); fail: if (kms) sde_destroy(kms); @@ -320,111 +256,6 @@ fail: return ERR_PTR(ret); } -static int sde_translation_ctrl_pwr(struct sde_kms *sde_kms, bool on) -{ - struct device *dev = sde_kms->dev->dev; - int ret; - - if (on) { - if (sde_kms->iommu_clk) { - ret = clk_prepare_enable(sde_kms->iommu_clk); - if (ret) { - dev_err(dev, "failed to enable iommu_clk\n"); - goto undo_mmagic_clk; - } - } - } else { - if (sde_kms->iommu_clk) - clk_disable_unprepare(sde_kms->iommu_clk); - if (sde_kms->mmagic_clk) - clk_disable_unprepare(sde_kms->mmagic_clk); - if (sde_kms->mmagic) - regulator_disable(sde_kms->mmagic); - } - - return 0; - -undo_mmagic_clk: - if (sde_kms->mmagic_clk) - clk_disable_unprepare(sde_kms->mmagic_clk); - - return ret; -} -int sde_mmu_init(struct sde_kms *sde_kms) -{ - struct sde_mdss_cfg *catalog = sde_kms->catalog; - struct sde_hw_intf *intf = NULL; - struct iommu_domain *iommu; - struct msm_mmu *mmu; - int i, ret; - - /* - * Make sure things are off before attaching iommu (bootloader could - * have left things on, in which case we'll start getting faults if - * we don't disable): - */ - sde_enable(sde_kms); - for (i = 0; i < catalog->intf_count; i++) { - intf = sde_hw_intf_init(catalog->intf[i].id, - sde_kms->mmio, - catalog); - if (!IS_ERR_OR_NULL(intf)) { - intf->ops.enable_timing(intf, 0x0); - sde_hw_intf_deinit(intf); - } - } - sde_disable(sde_kms); - msleep(20); - - iommu = iommu_domain_alloc(&platform_bus_type); - - if (!IS_ERR_OR_NULL(iommu)) { - mmu = msm_smmu_new(sde_kms->dev->dev, MSM_SMMU_DOMAIN_UNSECURE); - if (IS_ERR(mmu)) { - ret = PTR_ERR(mmu); - dev_err(sde_kms->dev->dev, - "failed to init iommu: %d\n", ret); - iommu_domain_free(iommu); - goto fail; - } - - ret = sde_translation_ctrl_pwr(sde_kms, true); - if (ret) { - dev_err(sde_kms->dev->dev, - "failed to power iommu: %d\n", ret); - mmu->funcs->destroy(mmu); - goto fail; - } - - ret = mmu->funcs->attach(mmu, (const char **)iommu_ports, - ARRAY_SIZE(iommu_ports)); - if (ret) { - dev_err(sde_kms->dev->dev, - "failed to attach iommu: %d\n", ret); - mmu->funcs->destroy(mmu); - goto fail; - } - } else { - dev_info(sde_kms->dev->dev, - "no iommu, fallback to phys contig buffers for scanout\n"); - mmu = NULL; - } - sde_kms->mmu = mmu; - - sde_kms->mmu_id = msm_register_mmu(sde_kms->dev, mmu); - if (sde_kms->mmu_id < 0) { - ret = sde_kms->mmu_id; - dev_err(sde_kms->dev->dev, - "failed to register sde iommu: %d\n", ret); - goto fail; - } - - return 0; -fail: - return ret; - -} - struct msm_kms *sde_kms_init(struct drm_device *dev) { struct platform_device *pdev = dev->platformdev; @@ -440,7 +271,7 @@ struct msm_kms *sde_kms_init(struct drm_device *dev) } sde_kms->dev = dev; - msm_kms = &sde_kms->base; + msm_kms = &sde_kms->base.base; /* * Currently hardcoding to MDSS version 1.7.0 (8996) @@ -451,21 +282,10 @@ struct msm_kms *sde_kms_init(struct drm_device *dev) sde_kms->catalog = catalog; - /* we need to set a default rate before enabling. - * Set a safe rate first, before initializing catalog - * later set more optimal rate based on bandwdith/clock - * requirements - */ - - clk_set_rate(sde_kms->src_clk, DEFAULT_MDP_SRC_CLK); - sde_enable(sde_kms); - sde_kms->hw_res.res_table = res_table; - /* * Now we need to read the HW catalog and initialize resources such as * clocks, regulators, GDSC/MMAGIC, ioremap the register ranges etc */ - sde_mmu_init(sde_kms); /* * modeset_init should create the DRM related objects i.e. CRTCs, @@ -476,19 +296,6 @@ struct msm_kms *sde_kms_init(struct drm_device *dev) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; - /* - * we can assume the max crtc width is equal to the max supported - * by LM_0 - * Also fixing the max height to 4k - */ - dev->mode_config.max_width = catalog->mixer[0].sblk->maxwidth; - dev->mode_config.max_height = 4096; - - sde_kms->hw_intr = sde_rm_acquire_intr(sde_kms); - - if (IS_ERR_OR_NULL(sde_kms->hw_intr)) - goto fail; - return msm_kms; fail: diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 7ac1b6b827bc..24dabc93583f 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -17,72 +17,15 @@ #include "msm_kms.h" #include "mdp/mdp_kms.h" #include "sde_hw_catalog.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_hw_lm.h" -#include "sde_hw_interrupts.h" - -/* - * struct sde_irq_callback - IRQ callback handlers - * @func: intr handler - * @arg: argument for the handler - */ -struct sde_irq_callback { - void (*func)(void *arg, int irq_idx); - void *arg; -}; - -/** - * struct sde_irq: IRQ structure contains callback registration info - * @total_irq: total number of irq_idx obtained from HW interrupts mapping - * @irq_cb_tbl: array of IRQ callbacks setting - * @cb_lock: callback lock - */ -struct sde_irq { - u32 total_irqs; - struct sde_irq_callback *irq_cb_tbl; - spinlock_t cb_lock; -}; - -/** - * struct sde_hw_res_map : Default resource table identifying default - * hw resource map. Primarily used for forcing DSI to use CTL_0/1 - * and Pingpong 0/1, if the field is set to SDE_NONE means any HW - * intstance for that tpye is allowed as long as it is unused. - */ -struct sde_hw_res_map { - enum sde_intf intf; - enum sde_lm lm; - enum sde_pingpong pp; - enum sde_ctl ctl; -}; - -/* struct sde_hw_resource_manager : Resource mananger maintains the current - * platform configuration and manages shared - * hw resources ex:ctl_path hw driver context - * is needed by CRTCs/PLANEs/ENCODERs - * @ctl : table of control path hw driver contexts allocated - * @mixer : list of mixer hw drivers contexts allocated - * @intr : pointer to hw interrupt context - * @res_table : pointer to default hw_res table for this platform - * @feature_map :BIT map for default enabled features ex:specifies if PP_SPLIT - * is enabled/disabled by defalt for this platform - */ -struct sde_hw_resource_manager { - struct sde_hw_ctl *ctl[CTL_MAX]; - struct sde_hw_mixer *mixer[LM_MAX]; - struct sde_hw_intr *intr; - const struct sde_hw_res_map *res_table; - bool feature_map; -}; +#include "sde_hw_mdss.h" struct sde_kms { - struct msm_kms base; + struct mdp_kms base; struct drm_device *dev; int rev; struct sde_mdss_cfg *catalog; struct msm_mmu *mmu; - int mmu_id; /* io/register spaces: */ void __iomem *mmio, *vbif; @@ -104,15 +47,6 @@ struct sde_kms { unsigned long enabled_mask; struct irq_domain *domain; } irqcontroller; - - struct sde_hw_intr *hw_intr; - struct sde_irq irq_obj; - struct sde_hw_resource_manager hw_res; -}; - -struct vsync_info { - u32 frame_count; - u32 line_count; }; #define to_sde_kms(x) container_of(x, struct sde_kms, base) @@ -142,163 +76,41 @@ struct sde_plane_state { int sde_disable(struct sde_kms *sde_kms); int sde_enable(struct sde_kms *sde_kms); -/** - * HW resource manager functions - * @sde_rm_acquire_ctl_path : Allocates control path - * @sde_rm_get_ctl_path : returns control path driver context for already - * acquired ctl path - * @sde_rm_release_ctl_path : Frees control path driver context - * @sde_rm_acquire_mixer : Allocates mixer hw driver context - * @sde_rm_get_mixer : returns mixer context for already - * acquired mixer - * @sde_rm_release_mixer : Frees mixer hw driver context - * @sde_rm_get_hw_res_map : Returns map for the passed INTF - */ -struct sde_hw_ctl *sde_rm_acquire_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx); -struct sde_hw_ctl *sde_rm_get_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx); -void sde_rm_release_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx); -struct sde_hw_mixer *sde_rm_acquire_mixer(struct sde_kms *sde_kms, - enum sde_lm idx); -struct sde_hw_mixer *sde_rm_get_mixer(struct sde_kms *sde_kms, - enum sde_lm idx); -void sde_rm_release_mixer(struct sde_kms *sde_kms, - enum sde_lm idx); -struct sde_hw_intr *sde_rm_acquire_intr(struct sde_kms *sde_kms); -struct sde_hw_intr *sde_rm_get_intr(struct sde_kms *sde_kms); - -const struct sde_hw_res_map *sde_rm_get_res_map(struct sde_kms *sde_kms, - enum sde_intf idx); - -/** - * IRQ functions - */ -int sde_irq_domain_init(struct sde_kms *sde_kms); -int sde_irq_domain_fini(struct sde_kms *sde_kms); +void sde_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, + uint32_t old_irqmask); void sde_irq_preinstall(struct msm_kms *kms); int sde_irq_postinstall(struct msm_kms *kms); void sde_irq_uninstall(struct msm_kms *kms); irqreturn_t sde_irq(struct msm_kms *kms); - -/** - * sde_set_irqmask - IRQ helper function for writing IRQ mask - * to SDE HW interrupt register. - * @sde_kms: SDE handle - * @reg_off: SDE HW interrupt register offset - * @irqmask: IRQ mask - */ -void sde_set_irqmask( - struct sde_kms *sde_kms, - uint32_t reg_off, - uint32_t irqmask); - -/** - * sde_irq_idx_lookup - IRQ helper function for lookup irq_idx from HW - * interrupt mapping table. - * @sde_kms: SDE handle - * @intr_type: SDE HW interrupt type for lookup - * @instance_idx: SDE HW block instance defined in sde_hw_mdss.h - * @return: irq_idx or -EINVAL when fail to lookup - */ -int sde_irq_idx_lookup( - struct sde_kms *sde_kms, - enum sde_intr_type intr_type, - uint32_t instance_idx); - -/** - * sde_enable_irq - IRQ helper function for enabling one or more IRQs - * @sde_kms: SDE handle - * @irq_idxs: Array of irq index - * @irq_count: Number of irq_idx provided in the array - * @return: 0 for success enabling IRQ, otherwise failure - */ -int sde_enable_irq( - struct sde_kms *sde_kms, - int *irq_idxs, - uint32_t irq_count); - -/** - * sde_disable_irq - IRQ helper function for diabling one of more IRQs - * @sde_kms: SDE handle - * @irq_idxs: Array of irq index - * @irq_count: Number of irq_idx provided in the array - * @return: 0 for success disabling IRQ, otherwise failure - */ -int sde_disable_irq( - struct sde_kms *sde_kms, - int *irq_idxs, - uint32_t irq_count); - -/** - * sde_register_irq_callback - For registering callback function on IRQ - * interrupt - * @sde_kms: SDE handle - * @irq_idx: irq index - * @irq_cb: IRQ callback structure, containing callback function - * and argument. Passing NULL for irq_cb will unregister - * the callback for the given irq_idx - * @return: 0 for success registering callback, otherwise failure - */ -int sde_register_irq_callback( - struct sde_kms *sde_kms, - int irq_idx, - struct sde_irq_callback *irq_cb); - -/** - * sde_clear_all_irqs - Clearing all SDE IRQ interrupt status - * @sde_kms: SDE handle - */ -void sde_clear_all_irqs(struct sde_kms *sde_kms); - -/** - * sde_disable_all_irqs - Diabling all SDE IRQ interrupt - * @sde_kms: SDE handle - */ -void sde_disable_all_irqs(struct sde_kms *sde_kms); - -/** - * Vblank enable/disable functions - */ int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); -/** - * Plane functions - */ enum sde_sspp sde_plane_pipe(struct drm_plane *plane); -struct drm_plane *sde_plane_init(struct drm_device *dev, uint32_t pipe, - bool private_plane); +void sde_plane_install_properties(struct drm_plane *plane, + struct drm_mode_object *obj); +void sde_plane_set_scanout(struct drm_plane *plane, + struct drm_framebuffer *fb); +int sde_plane_mode_set(struct drm_plane *plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); +void sde_plane_complete_flip(struct drm_plane *plane); +struct drm_plane *sde_plane_init(struct drm_device *dev, bool private_plane); -/** - * CRTC functions - */ uint32_t sde_crtc_vblank(struct drm_crtc *crtc); -void sde_crtc_wait_for_commit_done(struct drm_crtc *crtc); + void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); +void sde_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); +void sde_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane); struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_encoder *encoder, struct drm_plane *plane, int id); -/** - * Encoder functions and data types - */ -struct sde_encoder_hw_resources { - enum sde_intf_mode intfs[INTF_MAX]; - bool pingpongs[PINGPONG_MAX]; - bool ctls[CTL_MAX]; - bool pingpongsplit; -}; - -void sde_encoder_get_hw_resources(struct drm_encoder *encoder, - struct sde_encoder_hw_resources *hw_res); -void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc, - void (*cb)(void *), void *data); -void sde_encoders_init(struct drm_device *dev); -void sde_encoder_get_vsync_info(struct drm_encoder *encoder, - struct vsync_info *vsync); - +struct drm_encoder *sde_encoder_init(struct drm_device *dev, int intf); +int sde_irq_domain_init(struct sde_kms *sde_kms); +int sde_irq_domain_fini(struct sde_kms *sde_kms); #endif /* __sde_kms_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_kms_utils.c b/drivers/gpu/drm/msm/sde/sde_kms_utils.c deleted file mode 100644 index 9d6f28cfc06c..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_kms_utils.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "sde_kms.h" -#include "sde_hw_lm.h" -#include "sde_hw_mdp_ctl.h" - -struct sde_hw_intr *sde_rm_acquire_intr(struct sde_kms *sde_kms) -{ - struct sde_hw_intr *hw_intr; - - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - if (sde_kms->hw_res.intr) { - DRM_ERROR("intr already in use "); - return ERR_PTR(-ENODEV); - } - - sde_enable(sde_kms); - hw_intr = sde_hw_intr_init(sde_kms->mmio, - sde_kms->catalog); - sde_disable(sde_kms); - - if (!IS_ERR_OR_NULL(hw_intr)) - sde_kms->hw_res.intr = hw_intr; - - return hw_intr; -} - -struct sde_hw_intr *sde_rm_get_intr(struct sde_kms *sde_kms) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - return sde_kms->hw_res.intr; -} - -struct sde_hw_ctl *sde_rm_acquire_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx) -{ - struct sde_hw_ctl *hw_ctl; - - if (!sde_kms) { - DRM_ERROR("Invalid KMS driver"); - return ERR_PTR(-EINVAL); - } - - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->ctl_count)) { - DRM_ERROR("Invalid Ctl Path Idx %d", idx); - return ERR_PTR(-EINVAL); - } - - if (sde_kms->hw_res.ctl[idx]) { - DRM_ERROR("CTL path %d already in use ", idx); - return ERR_PTR(-ENODEV); - } - - sde_enable(sde_kms); - hw_ctl = sde_hw_ctl_init(idx, sde_kms->mmio, sde_kms->catalog); - sde_disable(sde_kms); - - if (!IS_ERR_OR_NULL(hw_ctl)) - sde_kms->hw_res.ctl[idx] = hw_ctl; - - return hw_ctl; -} - -struct sde_hw_ctl *sde_rm_get_ctl_path(struct sde_kms *sde_kms, - enum sde_ctl idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->ctl_count)) { - DRM_ERROR("Invalid Ctl path Idx %d", idx); - return ERR_PTR(-EINVAL); - } - - return sde_kms->hw_res.ctl[idx]; -} - -void sde_rm_release_ctl_path(struct sde_kms *sde_kms, enum sde_ctl idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid pointer\n"); - return; - } - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->ctl_count)) { - DRM_ERROR("Invalid Ctl path Idx %d", idx); - return; - } -} - -struct sde_hw_mixer *sde_rm_acquire_mixer(struct sde_kms *sde_kms, - enum sde_lm idx) -{ - struct sde_hw_mixer *mixer; - - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->mixer_count)) { - DBG("Invalid mixer id %d", idx); - return ERR_PTR(-EINVAL); - } - - if (sde_kms->hw_res.mixer[idx]) { - DRM_ERROR("mixer %d already in use ", idx); - return ERR_PTR(-ENODEV); - } - - sde_enable(sde_kms); - mixer = sde_hw_lm_init(idx, sde_kms->mmio, sde_kms->catalog); - sde_disable(sde_kms); - - if (!IS_ERR_OR_NULL(mixer)) - sde_kms->hw_res.mixer[idx] = mixer; - - return mixer; -} - -struct sde_hw_mixer *sde_rm_get_mixer(struct sde_kms *sde_kms, - enum sde_lm idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->mixer_count)) { - DRM_ERROR("Invalid mixer id %d", idx); - return ERR_PTR(-EINVAL); - } - - return sde_kms->hw_res.mixer[idx]; -} - -const struct sde_hw_res_map *sde_rm_get_res_map(struct sde_kms *sde_kms, - enum sde_intf idx) -{ - if (!sde_kms) { - DRM_ERROR("Invalid KMS Driver"); - return ERR_PTR(-EINVAL); - } - if ((idx == SDE_NONE) || (idx > sde_kms->catalog->intf_count)) { - DRM_ERROR("Invalid intf id %d", idx); - return ERR_PTR(-EINVAL); - } - - DBG(" Platform Resource map for INTF %d -> lm %d, pp %d ctl %d", - sde_kms->hw_res.res_table[idx].intf, - sde_kms->hw_res.res_table[idx].lm, - sde_kms->hw_res.res_table[idx].pp, - sde_kms->hw_res.res_table[idx].ctl); - return &(sde_kms->hw_res.res_table[idx]); -} diff --git a/drivers/gpu/drm/msm/sde/sde_mdp_formats.c b/drivers/gpu/drm/msm/sde/sde_mdp_formats.c deleted file mode 100644 index 56b65d4bd45e..000000000000 --- a/drivers/gpu/drm/msm/sde/sde_mdp_formats.c +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include "sde_mdp_formats.h" - -static struct sde_mdp_format_params sde_mdp_format_map[] = { - INTERLEAVED_RGB_FMT(ARGB8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, - true, 4, 0), - - INTERLEAVED_RGB_FMT(ABGR8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, - true, 4, 0), - - INTERLEAVED_RGB_FMT(RGBA8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, - true, 4, 0), - - INTERLEAVED_RGB_FMT(BGRA8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, - true, 4, 0), - - INTERLEAVED_RGB_FMT(XRGB8888, - COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, - true, 4, 0), - - INTERLEAVED_RGB_FMT(RGB888, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, 0, - false, 3, 0), - - INTERLEAVED_RGB_FMT(BGR888, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, 0, - false, 3, 0), - - INTERLEAVED_RGB_FMT(RGB565, - 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, 0, - false, 2, 0), - - INTERLEAVED_RGB_FMT(BGR565, - 0, 5, 6, 5, - C2_R_Cr, C0_G_Y, C1_B_Cb, 0, - false, 2, 0), - - PSEDUO_YUV_FMT(NV12, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C2_R_Cr, - SDE_MDP_CHROMA_420, 0), - - PSEDUO_YUV_FMT(NV21, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C1_B_Cb, - SDE_MDP_CHROMA_420, 0), - - PSEDUO_YUV_FMT(NV16, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C2_R_Cr, - SDE_MDP_CHROMA_H2V1, 0), - - PSEDUO_YUV_FMT(NV61, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C1_B_Cb, - SDE_MDP_CHROMA_H2V1, 0), - - INTERLEAVED_YUV_FMT(VYUY, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - INTERLEAVED_YUV_FMT(UYVY, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - INTERLEAVED_YUV_FMT(YUYV, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - INTERLEAVED_YUV_FMT(YVYU, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, - false, SDE_MDP_CHROMA_H2V1, 4, 2, - 0), - - PLANAR_YUV_FMT(YUV420, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C2_R_Cr, C1_B_Cb, C0_G_Y, - false, SDE_MDP_CHROMA_420, 2, - 0), - - PLANAR_YUV_FMT(YVU420, - 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, - C1_B_Cb, C2_R_Cr, C0_G_Y, - false, SDE_MDP_CHROMA_420, 2, - 0), -}; - -struct sde_mdp_format_params *sde_mdp_get_format_params(u32 format, - u32 fmt_modifier) -{ - u32 i = 0; - struct sde_mdp_format_params *fmt = NULL; - - for (i = 0; i < sizeof(sde_mdp_format_map)/sizeof(*sde_mdp_format_map); - i++) - if (format == sde_mdp_format_map[i].format) { - fmt = &sde_mdp_format_map[i]; - break; - } - - return fmt; -} - diff --git a/drivers/gpu/drm/msm/sde/sde_mdp_formats.h b/drivers/gpu/drm/msm/sde/sde_mdp_formats.h index e6f1c60aad11..dfd5076bb9dc 100644 --- a/drivers/gpu/drm/msm/sde/sde_mdp_formats.h +++ b/drivers/gpu/drm/msm/sde/sde_mdp_formats.h @@ -58,7 +58,6 @@ alpha, chroma, count, bp, flg) \ .is_yuv = true, \ .flag = flg \ } - #define PSEDUO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg) \ { \ .format = DRM_FORMAT_ ## fmt, \ @@ -93,12 +92,122 @@ alpha, chroma, count, bp, flg) \ .flag = flg \ } -/** - * sde_mdp_get_format_params(): Returns sde format structure pointer. - * @format: DRM format - * @fmt_modifier: DRM format modifier - */ +static struct sde_mdp_format_params sde_mdp_format_map[] = { + INTERLEAVED_RGB_FMT(ARGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + true, 4, 0), + + INTERLEAVED_RGB_FMT(ABGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + true, 4, 0), + + INTERLEAVED_RGB_FMT(RGBA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + true, 4, 0), + + INTERLEAVED_RGB_FMT(BGRA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + true, 4, 0), + + INTERLEAVED_RGB_FMT(XRGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + true, 4, 0), + + INTERLEAVED_RGB_FMT(RGB888, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, 0, + false, 3, 0), + + INTERLEAVED_RGB_FMT(BGR888, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, + false, 3, 0), + + INTERLEAVED_RGB_FMT(RGB565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, 0, + false, 2, 0), + + INTERLEAVED_RGB_FMT(BGR565, + 0, 5, 6, 5, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, + false, 2, 0), + + PSEDUO_YUV_FMT(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_MDP_CHROMA_420, 0), + + PSEDUO_YUV_FMT(NV21, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + SDE_MDP_CHROMA_420, 0), + + PSEDUO_YUV_FMT(NV16, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_MDP_CHROMA_H2V1, 0), + + PSEDUO_YUV_FMT(NV61, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + SDE_MDP_CHROMA_H2V1, 0), + + INTERLEAVED_YUV_FMT(VYUY, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, + false, SDE_MDP_CHROMA_H2V1, 4, 2, + 0), + + INTERLEAVED_YUV_FMT(UYVY, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, + false, SDE_MDP_CHROMA_H2V1, 4, 2, + 0), + + INTERLEAVED_YUV_FMT(YUYV, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, + false, SDE_MDP_CHROMA_H2V1, 4, 2, + 0), + + INTERLEAVED_YUV_FMT(YVYU, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, + false, SDE_MDP_CHROMA_H2V1, 4, 2, + 0), + + PLANAR_YUV_FMT(YUV420, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, C0_G_Y, + false, SDE_MDP_CHROMA_420, 2, + 0), + + PLANAR_YUV_FMT(YVU420, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, C0_G_Y, + false, SDE_MDP_CHROMA_420, 2, + 0), +}; + struct sde_mdp_format_params *sde_mdp_get_format_params(u32 format, - u32 fmt_modifier); + u32 fmt_modifier) +{ + u32 i = 0; + struct sde_mdp_format_params *fmt = NULL; + + for (i = 0; i < ARRAY_SIZE(sde_mdp_format_map); i++) + if (format == sde_mdp_format_map[i].format) { + fmt = &sde_mdp_format_map[i]; + break; + } + + return fmt; +} #endif /*_SDE_MDP_FORMATS_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index cf34de2f1e3d..6f2dd9dee668 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -11,757 +11,105 @@ */ #include "sde_kms.h" -#include "sde_hwio.h" -#include "sde_hw_mdp_ctl.h" -#include "sde_mdp_formats.h" -#include "sde_hw_sspp.h" - -#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci)) -#define PHASE_STEP_SHIFT 21 -#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT)) -#define PHASE_RESIDUAL 15 - -#define SDE_PLANE_FEATURE_SCALER \ - (BIT(SDE_SSPP_SCALAR_QSEED2)| \ - BIT(SDE_SSPP_SCALAR_QSEED3)| \ - BIT(SDE_SSPP_SCALAR_RGB)) - -#ifndef SDE_PLANE_DEBUG_START -#define SDE_PLANE_DEBUG_START() -#endif - -#ifndef SDE_PLANE_DEBUG_END -#define SDE_PLANE_DEBUG_END() -#endif struct sde_plane { struct drm_plane base; const char *name; - - int mmu_id; - - enum sde_sspp pipe; - uint32_t features; /* capabilities from catalog */ - uint32_t flush_mask; /* used to commit pipe registers */ uint32_t nformats; uint32_t formats[32]; - - struct sde_hw_pipe *pipe_hw; - struct sde_hw_pipe_cfg pipe_cfg; - struct sde_hw_pixel_ext pixel_ext; }; #define to_sde_plane(x) container_of(x, struct sde_plane, base) -static bool sde_plane_enabled(struct drm_plane_state *state) -{ - return state->fb && state->crtc; -} - -static void sde_plane_set_scanout(struct drm_plane *plane, - struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb) -{ - struct sde_plane *psde = to_sde_plane(plane); - int i; - - if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) { - /* stride */ - i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES); - while (i) { - --i; - pipe_cfg->src.ystride[i] = fb->pitches[i]; - } - - /* address */ - for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i) - pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb, - psde->mmu_id, i); - - /* hw driver */ - psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg); - } -} - -static void sde_plane_scale_helper(struct drm_plane *plane, - uint32_t src, uint32_t dst, uint32_t *phase_steps, - enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt, - uint32_t chroma_subsampling) -{ - /* calcualte phase steps, leave init phase as zero */ - phase_steps[SDE_SSPP_COMP_LUMA] = - mult_frac(1 << PHASE_STEP_SHIFT, src, dst); - phase_steps[SDE_SSPP_COMP_CHROMA] = - phase_steps[SDE_SSPP_COMP_LUMA] / chroma_subsampling; - - /* calculate scaler config, if necessary */ - if (src != dst) { - filter[SDE_SSPP_COMP_ALPHA] = (src < dst) ? - SDE_MDP_SCALE_FILTER_BIL : - SDE_MDP_SCALE_FILTER_PCMN; - - if (fmt->is_yuv) - filter[SDE_SSPP_COMP_LUMA] = SDE_MDP_SCALE_FILTER_CA; - else - filter[SDE_SSPP_COMP_LUMA] = - filter[SDE_SSPP_COMP_ALPHA]; - } -} - -/* CIFIX: clean up fmt/subsampling params once we're using fourcc formats */ -static void _sde_plane_pixel_ext_helper(struct drm_plane *plane, - uint32_t src, uint32_t dst, uint32_t decimated_src, - uint32_t *phase_steps, uint32_t *out_src, int *out_edge1, - int *out_edge2, struct sde_mdp_format_params *fmt, - uint32_t chroma_subsampling, bool post_compare) -{ - /* CIFIX: adapted from mdss_mdp_pipe_calc_pixel_extn() */ - int64_t edge1, edge2, caf; - uint32_t src_work; - int i, tmp; - - if (plane && phase_steps && out_src && out_edge1 && out_edge2 && fmt) { - /* enable CAF for YUV formats */ - if (fmt->is_yuv) - caf = PHASE_STEP_UNIT_SCALE; - else - caf = 0; - - for (i = 0; i < SDE_MAX_PLANES; i++) { - src_work = decimated_src; - if (i == 1 || i == 2) - src_work /= chroma_subsampling; - if (post_compare) - src = src_work; - if (!(fmt->is_yuv) && (src == dst)) { - /* unity */ - edge1 = 0; - edge2 = 0; - } else if (dst >= src) { - /* upscale */ - edge1 = (1 << PHASE_RESIDUAL); - edge1 -= caf; - edge2 = (1 << PHASE_RESIDUAL); - edge2 += (dst - 1) * *(phase_steps + i); - edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE; - edge2 += caf; - edge2 = -(edge2); - } else { - /* downscale */ - edge1 = 0; - edge2 = (dst - 1) * *(phase_steps + i); - edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE; - edge2 += *(phase_steps + i); - edge2 = -(edge2); - } - - /* only enable CAF for luma plane */ - caf = 0; - - /* populate output arrays */ - *(out_src + i) = src_work; - - /* edge updates taken from __pxl_extn_helper */ - /* CIFIX: why are we casting first to uint32_t? */ - if (edge1 >= 0) { - tmp = (uint32_t)edge1; - tmp >>= PHASE_STEP_SHIFT; - *(out_edge1 + i) = -tmp; - } else { - tmp = (uint32_t)(-edge1); - *(out_edge1 + i) = (tmp + PHASE_STEP_UNIT_SCALE - - 1) >> PHASE_STEP_SHIFT; - } - if (edge2 >= 0) { - tmp = (uint32_t)edge2; - tmp >>= PHASE_STEP_SHIFT; - *(out_edge2 + i) = -tmp; - } else { - tmp = (uint32_t)(-edge2); - *(out_edge2 + i) = (tmp + PHASE_STEP_UNIT_SCALE - - 1) >> PHASE_STEP_SHIFT; - } - } - } -} - -static int sde_plane_mode_set(struct drm_plane *plane, +static int sde_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { - struct sde_plane *psde = to_sde_plane(plane); - struct sde_plane_state *pstate; - const struct mdp_format *format; - uint32_t nplanes, pix_format, tmp; - int i; - struct sde_mdp_format_params *fmt; - struct sde_hw_pixel_ext *pe; - int ret = 0; - - SDE_PLANE_DEBUG_START(); - nplanes = drm_format_num_planes(fb->pixel_format); - - pstate = to_sde_plane_state(plane->state); - - format = to_mdp_format(msm_framebuffer_format(fb)); - pix_format = format->base.pixel_format; - - /* src values are in Q16 fixed point, convert to integer */ - src_x = src_x >> 16; - src_y = src_y >> 16; - src_w = src_w >> 16; - src_h = src_h >> 16; - - DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->name, - fb->base.id, src_x, src_y, src_w, src_h, - crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); - - /* update format configuration */ - memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg)); - - psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format, - 0/* CIFIX: fmt_modifier */); - psde->pipe_cfg.src.width = fb->width; - psde->pipe_cfg.src.height = fb->height; - psde->pipe_cfg.src.num_planes = nplanes; - - sde_plane_set_scanout(plane, &psde->pipe_cfg, fb); - - psde->pipe_cfg.src_rect.x = src_x; - psde->pipe_cfg.src_rect.y = src_y; - psde->pipe_cfg.src_rect.w = src_w; - psde->pipe_cfg.src_rect.h = src_h; - - psde->pipe_cfg.dst_rect.x = crtc_x; - psde->pipe_cfg.dst_rect.y = crtc_y; - psde->pipe_cfg.dst_rect.w = crtc_w; - psde->pipe_cfg.dst_rect.h = crtc_h; - - psde->pipe_cfg.horz_decimation = 0; - psde->pipe_cfg.vert_decimation = 0; - - /* get sde pixel format definition */ - fmt = psde->pipe_cfg.src.format; - - /* update pixel extensions */ - pe = &(psde->pixel_ext); - if (!pe->enable_pxl_ext) { - uint32_t chroma_subsample_h, chroma_subsample_v; - - chroma_subsample_h = psde->pipe_cfg.horz_decimation ? 1 : - drm_format_horz_chroma_subsampling(pix_format); - chroma_subsample_v = psde->pipe_cfg.vert_decimation ? 1 : - drm_format_vert_chroma_subsampling(pix_format); - - memset(pe, 0, sizeof(struct sde_hw_pixel_ext)); - - /* calculate phase steps */ - sde_plane_scale_helper(plane, src_w, crtc_w, - pe->phase_step_x, - pe->horz_filter, fmt, chroma_subsample_h); - sde_plane_scale_helper(plane, src_h, crtc_h, - pe->phase_step_y, - pe->vert_filter, fmt, chroma_subsample_v); - - /* calculate left/right/top/bottom pixel extentions */ - tmp = DECIMATED_DIMENSION(src_w, - psde->pipe_cfg.horz_decimation); - if (fmt->is_yuv) - tmp &= ~0x1; - _sde_plane_pixel_ext_helper(plane, src_w, crtc_w, tmp, - pe->phase_step_x, - pe->roi_w, - pe->num_ext_pxls_left, - pe->num_ext_pxls_right, fmt, - chroma_subsample_h, 0); - - tmp = DECIMATED_DIMENSION(src_h, - psde->pipe_cfg.vert_decimation); - _sde_plane_pixel_ext_helper(plane, src_h, crtc_h, tmp, - pe->phase_step_y, - pe->roi_h, - pe->num_ext_pxls_top, - pe->num_ext_pxls_btm, fmt, - chroma_subsample_v, 1); - - /* CIFIX: port "Single pixel rgb scale adjustment"? */ - - for (i = 0; i < SDE_MAX_PLANES; i++) { - if (pe->num_ext_pxls_left[i] >= 0) - pe->left_rpt[i] = - pe->num_ext_pxls_left[i]; - else - pe->left_ftch[i] = - pe->num_ext_pxls_left[i]; - - if (pe->num_ext_pxls_right[i] >= 0) - pe->right_rpt[i] = - pe->num_ext_pxls_right[i]; - else - pe->right_ftch[i] = - pe->num_ext_pxls_right[i]; - - if (pe->num_ext_pxls_top[i] >= 0) - pe->top_rpt[i] = - pe->num_ext_pxls_top[i]; - else - pe->top_ftch[i] = - pe->num_ext_pxls_top[i]; - - if (pe->num_ext_pxls_btm[i] >= 0) - pe->btm_rpt[i] = - pe->num_ext_pxls_btm[i]; - else - pe->btm_ftch[i] = - pe->num_ext_pxls_btm[i]; - } - } - - if (psde->pipe_hw->ops.setup_sourceformat) - psde->pipe_hw->ops.setup_sourceformat(psde->pipe_hw, - &psde->pipe_cfg, 0 /* CIFIX: flags */); - if (psde->pipe_hw->ops.setup_rects) - psde->pipe_hw->ops.setup_rects(psde->pipe_hw, - &psde->pipe_cfg, &psde->pixel_ext); - - /* update csc */ - - SDE_PLANE_DEBUG_END(); - return ret; -} - -static int sde_plane_prepare_fb(struct drm_plane *plane, - const struct drm_plane_state *new_state) -{ - struct drm_framebuffer *fb = new_state->fb; - struct sde_plane *psde = to_sde_plane(plane); - - if (!new_state->fb) - return 0; - - SDE_PLANE_DEBUG_START(); - SDE_PLANE_DEBUG_END(); - DBG("%s: prepare: FB[%u]", psde->name, fb->base.id); - return msm_framebuffer_prepare(fb, psde->mmu_id); -} - -static void sde_plane_cleanup_fb(struct drm_plane *plane, - const struct drm_plane_state *old_state) -{ - struct drm_framebuffer *fb = old_state->fb; - struct sde_plane *psde = to_sde_plane(plane); - - if (!fb) - return; - - SDE_PLANE_DEBUG_START(); - SDE_PLANE_DEBUG_END(); - DBG("%s: cleanup: FB[%u]", psde->name, fb->base.id); - msm_framebuffer_cleanup(fb, psde->mmu_id); + return 0; } -static int sde_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state) +static int sde_plane_disable(struct drm_plane *plane) { - struct sde_plane *psde = to_sde_plane(plane); - struct drm_plane_state *old_state = plane->state; - const struct mdp_format *format; - - SDE_PLANE_DEBUG_START(); - SDE_PLANE_DEBUG_END(); - DBG("%s: check (%d -> %d)", psde->name, - sde_plane_enabled(old_state), sde_plane_enabled(state)); - - if (sde_plane_enabled(state)) { - /* CIFIX: don't use mdp format? */ - format = to_mdp_format(msm_framebuffer_format(state->fb)); - if (MDP_FORMAT_IS_YUV(format) && - (!(psde->features & SDE_PLANE_FEATURE_SCALER) || - !(psde->features & BIT(SDE_SSPP_CSC)))) { - dev_err(plane->dev->dev, - "Pipe doesn't support YUV\n"); - - return -EINVAL; - } - - if (!(psde->features & SDE_PLANE_FEATURE_SCALER) && - (((state->src_w >> 16) != state->crtc_w) || - ((state->src_h >> 16) != state->crtc_h))) { - dev_err(plane->dev->dev, - "Pipe doesn't support scaling (%dx%d -> %dx%d)\n", - state->src_w >> 16, state->src_h >> 16, - state->crtc_w, state->crtc_h); - - return -EINVAL; - } - } - - if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) { - /* we cannot change SMP block configuration during scanout: */ - bool full_modeset = false; - - if (state->fb->pixel_format != old_state->fb->pixel_format) { - DBG("%s: pixel_format change!", psde->name); - full_modeset = true; - } - if (state->src_w != old_state->src_w) { - DBG("%s: src_w change!", psde->name); - full_modeset = true; - } - if (to_sde_plane_state(old_state)->pending) { - DBG("%s: still pending!", psde->name); - full_modeset = true; - } - if (full_modeset) { - struct drm_crtc_state *crtc_state = - drm_atomic_get_crtc_state(state->state, - state->crtc); - crtc_state->mode_changed = true; - to_sde_plane_state(state)->mode_changed = true; - } - } else { - to_sde_plane_state(state)->mode_changed = true; - } - return 0; } -static void sde_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *old_state) +static void sde_plane_destroy(struct drm_plane *plane) { struct sde_plane *sde_plane = to_sde_plane(plane); - struct drm_plane_state *state = plane->state; + struct msm_drm_private *priv = plane->dev->dev_private; - DBG("%s: update", sde_plane->name); + if (priv->kms) + sde_plane_disable(plane); - SDE_PLANE_DEBUG_START(); - if (!sde_plane_enabled(state)) { - to_sde_plane_state(state)->pending = true; - } else if (to_sde_plane_state(state)->mode_changed) { - int ret; + drm_plane_cleanup(plane); - to_sde_plane_state(state)->pending = true; - ret = sde_plane_mode_set(plane, - state->crtc, state->fb, - state->crtc_x, state->crtc_y, - state->crtc_w, state->crtc_h, - state->src_x, state->src_y, - state->src_w, state->src_h); - /* atomic_check should have ensured that this doesn't fail */ - WARN_ON(ret < 0); - } else { - sde_plane_set_scanout(plane, &sde_plane->pipe_cfg, state->fb); - } - SDE_PLANE_DEBUG_END(); + kfree(sde_plane); } /* helper to install properties which are common to planes and crtcs */ -static void sde_plane_install_properties(struct drm_plane *plane, +void sde_plane_install_properties(struct drm_plane *plane, struct drm_mode_object *obj) { - struct drm_device *dev = plane->dev; - struct msm_drm_private *dev_priv = dev->dev_private; - struct drm_property *prop; - - SDE_PLANE_DEBUG_START(); -#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \ - prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \ - if (!prop) { \ - prop = drm_property_##fnc(dev, 0, #name, \ - ##__VA_ARGS__); \ - if (!prop) { \ - dev_warn(dev->dev, \ - "Create property %s failed\n", \ - #name); \ - return; \ - } \ - dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \ - } \ - drm_object_attach_property(&plane->base, prop, init_val); \ - } while (0) - -#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \ - INSTALL_PROPERTY(name, NAME, init_val, \ - create_range, min, max) - -#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \ - INSTALL_PROPERTY(name, NAME, init_val, \ - create_enum, name##_prop_enum_list, \ - ARRAY_SIZE(name##_prop_enum_list)) - - INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1); - -#undef INSTALL_RANGE_PROPERTY -#undef INSTALL_ENUM_PROPERTY -#undef INSTALL_PROPERTY - SDE_PLANE_DEBUG_END(); } -static int sde_plane_atomic_set_property(struct drm_plane *plane, - struct drm_plane_state *state, struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = plane->dev; - struct sde_plane_state *pstate; - struct msm_drm_private *dev_priv = dev->dev_private; - int ret = 0; - - SDE_PLANE_DEBUG_START(); - - pstate = to_sde_plane_state(state); - -#define SET_PROPERTY(name, NAME, type) do { \ - if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ - pstate->name = (type)val; \ - DBG("Set property %s %d", #name, (type)val); \ - goto done; \ - } \ - } while (0) - - SET_PROPERTY(zpos, ZPOS, uint8_t); - - dev_err(dev->dev, "Invalid property\n"); - ret = -EINVAL; -done: - SDE_PLANE_DEBUG_END(); - return ret; -#undef SET_PROPERTY -} - -static int sde_plane_set_property(struct drm_plane *plane, +int sde_plane_set_property(struct drm_plane *plane, struct drm_property *property, uint64_t val) { - int rc; - - SDE_PLANE_DEBUG_START(); - rc = sde_plane_atomic_set_property(plane, plane->state, property, - val); - SDE_PLANE_DEBUG_END(); - return rc; -} - -static int sde_plane_atomic_get_property(struct drm_plane *plane, - const struct drm_plane_state *state, - struct drm_property *property, uint64_t *val) -{ - struct drm_device *dev = plane->dev; - struct sde_plane_state *pstate; - struct msm_drm_private *dev_priv = dev->dev_private; - int ret = 0; - - SDE_PLANE_DEBUG_START(); - pstate = to_sde_plane_state(state); - -#define GET_PROPERTY(name, NAME, type) do { \ - if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \ - *val = pstate->name; \ - DBG("Get property %s %lld", #name, *val); \ - goto done; \ - } \ - } while (0) - - GET_PROPERTY(zpos, ZPOS, uint8_t); - - dev_err(dev->dev, "Invalid property\n"); - ret = -EINVAL; -done: - SDE_PLANE_DEBUG_END(); - return ret; -#undef SET_PROPERTY -} - -static void sde_plane_destroy(struct drm_plane *plane) -{ - struct sde_plane *psde = to_sde_plane(plane); - - SDE_PLANE_DEBUG_START(); - - if (psde->pipe_hw) - sde_hw_sspp_destroy(psde->pipe_hw); - - drm_plane_helper_disable(plane); - drm_plane_cleanup(plane); - - kfree(psde); - - SDE_PLANE_DEBUG_END(); -} - -static void sde_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) -{ - SDE_PLANE_DEBUG_START(); - if (state->fb) - drm_framebuffer_unreference(state->fb); - - kfree(to_sde_plane_state(state)); - SDE_PLANE_DEBUG_END(); -} - -static struct drm_plane_state * -sde_plane_duplicate_state(struct drm_plane *plane) -{ - struct sde_plane_state *pstate; - - if (WARN_ON(!plane->state)) - return NULL; - - SDE_PLANE_DEBUG_START(); - pstate = kmemdup(to_sde_plane_state(plane->state), - sizeof(*pstate), GFP_KERNEL); - - if (pstate && pstate->base.fb) - drm_framebuffer_reference(pstate->base.fb); - - pstate->mode_changed = false; - pstate->pending = false; - SDE_PLANE_DEBUG_END(); - - return &pstate->base; -} - -static void sde_plane_reset(struct drm_plane *plane) -{ - struct sde_plane_state *pstate; - - SDE_PLANE_DEBUG_START(); - if (plane->state && plane->state->fb) - drm_framebuffer_unreference(plane->state->fb); - - kfree(to_sde_plane_state(plane->state)); - pstate = kzalloc(sizeof(*pstate), GFP_KERNEL); - - memset(pstate, 0, sizeof(struct sde_plane_state)); - - /* assign default blend parameters */ - pstate->alpha = 255; - pstate->premultiplied = 0; - - if (plane->type == DRM_PLANE_TYPE_PRIMARY) - pstate->zpos = STAGE_BASE; - else - pstate->zpos = STAGE0 + drm_plane_index(plane); - - pstate->base.plane = plane; - - plane->state = &pstate->base; - SDE_PLANE_DEBUG_END(); + return -EINVAL; } static const struct drm_plane_funcs sde_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, + .update_plane = sde_plane_update, + .disable_plane = sde_plane_disable, .destroy = sde_plane_destroy, .set_property = sde_plane_set_property, - .atomic_set_property = sde_plane_atomic_set_property, - .atomic_get_property = sde_plane_atomic_get_property, - .reset = sde_plane_reset, - .atomic_duplicate_state = sde_plane_duplicate_state, - .atomic_destroy_state = sde_plane_destroy_state, }; -static const struct drm_plane_helper_funcs sde_plane_helper_funcs = { - .prepare_fb = sde_plane_prepare_fb, - .cleanup_fb = sde_plane_cleanup_fb, - .atomic_check = sde_plane_atomic_check, - .atomic_update = sde_plane_atomic_update, -}; - -enum sde_sspp sde_plane_pipe(struct drm_plane *plane) +void sde_plane_set_scanout(struct drm_plane *plane, + struct drm_framebuffer *fb) { - struct sde_plane *sde_plane = to_sde_plane(plane); +} - return sde_plane->pipe; +int sde_plane_mode_set(struct drm_plane *plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + return 0; } /* initialize plane */ -struct drm_plane *sde_plane_init(struct drm_device *dev, uint32_t pipe, - bool private_plane) +struct drm_plane *sde_plane_init(struct drm_device *dev, bool private_plane) { - static const char tmp_name[] = "---"; struct drm_plane *plane = NULL; - struct sde_plane *psde; - struct sde_hw_ctl *sde_ctl; - struct msm_drm_private *priv; - struct sde_kms *kms; - struct sde_mdss_cfg *sde_cat; + struct sde_plane *sde_plane; int ret; enum drm_plane_type type; - priv = dev->dev_private; - if (!priv) { - DRM_ERROR("[%u]Private data is NULL\n", pipe); - goto exit; - } - - if (!priv->kms) { - DRM_ERROR("[%u]Invalid KMS reference\n", pipe); - goto exit; - } - kms = to_sde_kms(priv->kms); - - psde = kzalloc(sizeof(*psde), GFP_KERNEL); - if (!psde) { + sde_plane = kzalloc(sizeof(*sde_plane), GFP_KERNEL); + if (!sde_plane) { ret = -ENOMEM; goto fail; } - memset(psde, 0, sizeof(*psde)); - - plane = &psde->base; - - psde->pipe = pipe; - psde->name = tmp_name; - - if (kms) { - /* mmu id for buffer mapping */ - psde->mmu_id = kms->mmu_id; - - /* check catalog for features mask */ - sde_cat = kms->catalog; - if (sde_cat) - psde->features = sde_cat->sspp[pipe].features; - } - psde->nformats = mdp_get_formats(psde->formats, - ARRAY_SIZE(psde->formats), - !(psde->features & BIT(SDE_SSPP_CSC)) || - !(psde->features & SDE_PLANE_FEATURE_SCALER)); + plane = &sde_plane->base; type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; - ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs, - psde->formats, psde->nformats, - type); - if (ret) - goto fail; - - drm_plane_helper_add(plane, &sde_plane_helper_funcs); + drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs, + sde_plane->formats, sde_plane->nformats, + type); sde_plane_install_properties(plane, &plane->base); - psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat); - if (IS_ERR(psde->pipe_hw)) { - ret = PTR_ERR(psde->pipe_hw); - psde->pipe_hw = NULL; - goto fail; - } - - /* cache flush mask for later */ - sde_ctl = sde_hw_ctl_init(CTL_0, kms->mmio, sde_cat); - if (!IS_ERR(sde_ctl)) { - if (sde_ctl->ops.get_bitmask_sspp) - sde_ctl->ops.get_bitmask_sspp(sde_ctl, - &psde->flush_mask, pipe); - sde_hw_ctl_destroy(sde_ctl); - } - - pr_err("%s: Successfully created plane\n", __func__); return plane; fail: - pr_err("%s: Plane creation failed\n", __func__); if (plane) sde_plane_destroy(plane); -exit: + return ERR_PTR(ret); } |
