This series of patches adds support for MSM8996, including MDP5 v1.7. Note that only the HDMI interface is supported for now.
Stephane Viau (10): drm/msm/mdp5: remove the cfg pointer from SMP struct drm/msm/mdp5: Disable hardware translation table walks (MSM8996) drm/msm: Fix IOMMU clean up path in case msm_iommu_new() fails drm/msm/mdp5: Avoid printing error messages for optional clocks drm/msm/mdp5: Vote for SMMU power when performing translations drm/msm/hdmi: Add basic HDMI support for msm8996 drm/msm/mdp: Update generated headers (Pixel Extension) drm/msm/mdp5: Use the newly introduced enum mdp_component_type drm/msm/mdp: Add Software Pixel Extension support drm/msm/mdp5: Basic support for MDP5 v1.7 (MSM8996)
Documentation/devicetree/bindings/drm/msm/hdmi.txt | 3 + Documentation/devicetree/bindings/drm/msm/mdp.txt | 8 +- drivers/gpu/drm/msm/hdmi/hdmi.c | 17 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h | 82 ++++++++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 95 +++++++++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | 11 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 126 +++++++++++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 5 + drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 201 ++++++++++++++++----- drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c | 8 +- drivers/gpu/drm/msm/mdp/mdp_common.xml.h | 11 +- drivers/gpu/drm/msm/mdp/mdp_kms.h | 6 + drivers/gpu/drm/msm/msm_gpu.c | 8 + 13 files changed, 501 insertions(+), 80 deletions(-)
We want to make sure we control all the information being passed down to SMP block. Having access to the cfg pointer here may create bad things in the future.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | 2 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h index efb918d..a6facaf 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h @@ -61,7 +61,7 @@ struct mdp5_smp_block { int mmb_size; /* MMB: size in bytes */ uint32_t clients[MAX_CLIENTS]; /* SMP port allocation /pipe */ mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */ - int reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */ + uint8_t reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */ };
#define MDP5_INTF_NUM_MAX 5 diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c index 563cca9..6f425c2 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c @@ -90,7 +90,7 @@ struct mdp5_smp { struct drm_device *dev;
- const struct mdp5_smp_block *cfg; + uint8_t reserved[MAX_CLIENTS]; /* fixed MMBs allocation per client */
int blk_cnt; int blk_size; @@ -141,10 +141,10 @@ static int smp_request_block(struct mdp5_smp *smp, struct mdp5_kms *mdp5_kms = get_kms(smp); struct mdp5_client_smp_state *ps = &smp->client_state[cid]; int i, ret, avail, cur_nblks, cnt = smp->blk_cnt; - int reserved; + uint8_t reserved; unsigned long flags;
- reserved = smp->cfg->reserved[cid]; + reserved = smp->reserved[cid];
spin_lock_irqsave(&smp->state_lock, flags);
@@ -405,12 +405,12 @@ struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_blo }
smp->dev = dev; - smp->cfg = cfg; smp->blk_cnt = cfg->mmb_count; smp->blk_size = cfg->mmb_size;
/* statically tied MMBs cannot be re-allocated: */ bitmap_copy(smp->state, cfg->reserved_state, smp->blk_cnt); + memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved)); spin_lock_init(&smp->state_lock);
return smp;
On certain targets (eg, MSM8996) we need to set the following domain attribute for correct operation of the SMMU: DOMAIN_ATTR_COHERENT_HTW_DISABLE.
Setting that attribute is very important on 8996. Without it, we would see crazy translation faults.
Note: There could be support for coherent hardware table walks in the future
Signed-off-by: Stephane Viau sviau@codeaurora.org --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index bbab6e6..14ac20a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -584,6 +584,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) mdelay(16);
if (config->platform.iommu) { + int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg); + mmu = msm_iommu_new(&pdev->dev, config->platform.iommu); if (IS_ERR(mmu)) { ret = PTR_ERR(mmu); @@ -591,6 +593,19 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) goto fail; }
+ /* + * On certain targets (8996, for example) we need to set the + * following domain attribute for correct operation of the SMMU; + * Without it, we would see crazy translation faults.. + */ + if (rev == 7) { + int disable_htw = 1; + + iommu_domain_set_attr(config->platform.iommu, + DOMAIN_ATTR_COHERENT_HTW_DISABLE, &disable_htw); + DBG("coherent hardware translation table walks is off"); + } + ret = mmu->funcs->attach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); if (ret) {
msm_iommu_new() can fail and this change makes sure that we detect the failure and free the allocated domain before going any further.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 1 + drivers/gpu/drm/msm/msm_gpu.c | 8 ++++++++ 2 files changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 14ac20a..e11028c6 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -590,6 +590,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) if (IS_ERR(mmu)) { ret = PTR_ERR(mmu); dev_err(dev->dev, "failed to init iommu: %d\n", ret); + iommu_domain_free(config->platform.iommu); goto fail; }
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 5d31b5a..aed9f37 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -651,6 +651,14 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, if (iommu) { dev_info(drm->dev, "%s: using IOMMU\n", name); gpu->mmu = msm_iommu_new(&pdev->dev, iommu); + if (IS_ERR(gpu->mmu)) { + ret = PTR_ERR(gpu->mmu); + dev_err(drm->dev, "failed to init iommu: %d\n", ret); + gpu->mmu = NULL; + iommu_domain_free(iommu); + goto fail; + } + } else { dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); }
The current behavior is to try to get optional clocks and print a dev_err message in case of failure. This looks rather confusing and may increase with the amount of optional clocks.
We may need a cleaner way to handle per-device clocks but in the meantime, let's reduce the amount of dev_err messages during the probe.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- Documentation/devicetree/bindings/drm/msm/mdp.txt | 3 ++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 27 ++++++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt index 1a0598e..0833eda 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdp.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdp.txt @@ -11,13 +11,14 @@ Required properties: - clock-names: the following clocks are required: * "core_clk" * "iface_clk" - * "lut_clk" * "src_clk" * "hdmi_clk" * "mpd_clk"
Optional properties: - gpus: phandle for gpu device +- clock-names: the following clocks are optional: + * "lut_clk"
Example:
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index e11028c6..61fcb41 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -454,15 +454,19 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms, }
static int get_clk(struct platform_device *pdev, struct clk **clkp, - const char *name) + const char *name, bool mandatory) { struct device *dev = &pdev->dev; struct clk *clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { + if (IS_ERR(clk) && mandatory) { dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk)); return PTR_ERR(clk); } - *clkp = clk; + if (IS_ERR(clk)) + DBG("skipping %s", name); + else + *clkp = clk; + return 0; }
@@ -516,25 +520,26 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) goto fail; }
- ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk"); + /* mandatory clocks: */ + ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk"); + ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src"); + ret = get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk"); + ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk", true); if (ret) goto fail; - ret = get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk"); - if (ret) - DBG("failed to get (optional) lut_clk clock"); - ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk"); + ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk", true); if (ret) goto fail;
+ /* optional clocks: */ + get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk", false); + /* we need to set a default rate before enabling. Set a safe * rate first, then figure out hw revision, and then set a * more optimal rate:
On most recent chipsets, clients need to vote for SMMU power (regulator and clock) themselves for as long as they want the SMMU to be on, performing translations.
This change enables (disables) the SMMU power just before attaching (after detaching) MDP5 device to the SMMU.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- Documentation/devicetree/bindings/drm/msm/mdp.txt | 3 ++ drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 65 +++++++++++++++++++++++ drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 3 ++ 3 files changed, 71 insertions(+)
diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt index 0833eda..99ba764 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdp.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdp.txt @@ -19,6 +19,9 @@ Optional properties: - gpus: phandle for gpu device - clock-names: the following clocks are optional: * "lut_clk" + * "iommu_clk" + * "mmagic_clk" +- mmagic-supply: phandle for mmagic GDSC regulator used during IOMMU translation
Example:
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 61fcb41..983bd53 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -129,6 +129,54 @@ static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file) mdp5_crtc_cancel_pending_flip(priv->crtcs[i], file); }
+static int mdp5_translation_ctrl_pwr(struct mdp5_kms *mdp5_kms, bool on) +{ + struct device *dev = mdp5_kms->dev->dev; + int ret; + + if (on) { + if (mdp5_kms->mmagic) { + ret = regulator_enable(mdp5_kms->mmagic); + if (ret) { + dev_err(dev, "failed to enable mmagic GDSC: %d\n", ret); + return ret; + } + } + if (mdp5_kms->mmagic_clk) { + clk_prepare_enable(mdp5_kms->mmagic_clk); + if (ret) { + dev_err(dev, "failed to enable mmagic_clk\n"); + goto undo_gdsc; + } + } + if (mdp5_kms->iommu_clk) { + ret = clk_prepare_enable(mdp5_kms->iommu_clk); + if (ret) { + dev_err(dev, "failed to enable iommu_clk\n"); + goto undo_mmagic_clk; + } + } + } else { + if (mdp5_kms->iommu_clk) + clk_disable_unprepare(mdp5_kms->iommu_clk); + if (mdp5_kms->mmagic_clk) + clk_disable_unprepare(mdp5_kms->mmagic_clk); + if (mdp5_kms->mmagic) + regulator_disable(mdp5_kms->mmagic); + } + + return 0; + +undo_mmagic_clk: + if (mdp5_kms->mmagic_clk) + clk_disable_unprepare(mdp5_kms->mmagic_clk); +undo_gdsc: + if (mdp5_kms->mmagic) + regulator_disable(mdp5_kms->mmagic); + + return ret; +} + static void mdp5_destroy(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); @@ -138,6 +186,7 @@ static void mdp5_destroy(struct msm_kms *kms)
if (mmu) { mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); + mdp5_translation_ctrl_pwr(mdp5_kms, false); mmu->funcs->destroy(mmu); }
@@ -520,6 +569,13 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) goto fail; }
+ mdp5_kms->mmagic = devm_regulator_get_optional(&pdev->dev, "mmagic"); + if (IS_ERR(mdp5_kms->mmagic)) { + ret = PTR_ERR(mdp5_kms->mmagic); + DBG("failed to get mmagic GDSC regulator: %d\n", ret); + mdp5_kms->mmagic = NULL; + } + /* mandatory clocks: */ ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk", true); if (ret) @@ -539,6 +595,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
/* optional clocks: */ get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk", false); + get_clk(pdev, &mdp5_kms->mmagic_clk, "mmagic_clk", false); + get_clk(pdev, &mdp5_kms->iommu_clk, "iommu_clk", false);
/* we need to set a default rate before enabling. Set a safe * rate first, then figure out hw revision, and then set a @@ -612,6 +670,13 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) DBG("coherent hardware translation table walks is off"); }
+ ret = mdp5_translation_ctrl_pwr(mdp5_kms, true); + if (ret) { + dev_err(dev->dev, "failed to power iommu: %d\n", ret); + mmu->funcs->destroy(mmu); + goto fail; + } + ret = mmu->funcs->attach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); if (ret) { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 1e1a6b0..ab19d52a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -44,12 +44,15 @@ struct mdp5_kms { void __iomem *mmio, *vbif;
struct regulator *vdd; + struct regulator *mmagic;
struct clk *axi_clk; struct clk *ahb_clk; struct clk *src_clk; struct clk *core_clk; struct clk *lut_clk; + struct clk *mmagic_clk; + struct clk *iommu_clk; struct clk *vsync_clk;
/*
The HDMI controller is new in MDP5 v1.7. As of now, this change doesn't reflect the novelty and only adds the basics so the probe gets triggered.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- Documentation/devicetree/bindings/drm/msm/hdmi.txt | 3 +++ drivers/gpu/drm/msm/hdmi/hdmi.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/drm/msm/hdmi.txt b/Documentation/devicetree/bindings/drm/msm/hdmi.txt index e926239..379ee2e 100644 --- a/Documentation/devicetree/bindings/drm/msm/hdmi.txt +++ b/Documentation/devicetree/bindings/drm/msm/hdmi.txt @@ -2,6 +2,7 @@ Qualcomm adreno/snapdragon hdmi output
Required properties: - compatible: one of the following + * "qcom,hdmi-tx-8996" * "qcom,hdmi-tx-8994" * "qcom,hdmi-tx-8084" * "qcom,hdmi-tx-8974" @@ -21,6 +22,7 @@ Required properties: Optional properties: - qcom,hdmi-tx-mux-en-gpio: hdmi mux enable pin - qcom,hdmi-tx-mux-sel-gpio: hdmi mux select pin +- power-domains: reference to the power domain(s), if available. - pinctrl-names: the pin control state names; should contain "default" - pinctrl-0: the default pinctrl state (active) - pinctrl-1: the "sleep" pinctrl state @@ -35,6 +37,7 @@ Example: reg-names = "core_physical"; reg = <0x04a00000 0x1000>; interrupts = <GIC_SPI 79 0>; + power-domains = <&mmcc MDSS_GDSC>; clock-names = "core_clk", "master_iface_clk", diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 101b324..1f4a95e 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -328,6 +328,9 @@ fail: .item ## _names = item ##_names_ ## entry, \ .item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry)
+static const char *pwr_reg_names_none[] = {}; +static const char *hpd_reg_names_none[] = {}; + static struct hdmi_platform_config hdmi_tx_8660_config = { .phy_init = hdmi_phy_8x60_init, }; @@ -367,18 +370,26 @@ static struct hdmi_platform_config hdmi_tx_8084_config = { .hpd_freq = hpd_clk_freq_8x74, };
-static const char *hpd_reg_names_8x94[] = {}; - static struct hdmi_platform_config hdmi_tx_8994_config = { .phy_init = NULL, /* nothing to do for this HDMI PHY 20nm */ HDMI_CFG(pwr_reg, 8x74), - HDMI_CFG(hpd_reg, 8x94), + HDMI_CFG(hpd_reg, none), + HDMI_CFG(pwr_clk, 8x74), + HDMI_CFG(hpd_clk, 8x74), + .hpd_freq = hpd_clk_freq_8x74, +}; + +static struct hdmi_platform_config hdmi_tx_8996_config = { + .phy_init = NULL, + HDMI_CFG(pwr_reg, none), + HDMI_CFG(hpd_reg, none), HDMI_CFG(pwr_clk, 8x74), HDMI_CFG(hpd_clk, 8x74), .hpd_freq = hpd_clk_freq_8x74, };
static const struct of_device_id dt_match[] = { + { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config }, { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config }, { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config }, { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
This change is the output of Envytools change:
"rnndb: Add Pixel Extension registers"
Signed-off-by: Stephane Viau sviau@codeaurora.org --- drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h | 82 +++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/mdp/mdp_common.xml.h | 11 ++++- 2 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h index af9b932..bb4eae3 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -8,9 +8,9 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are: -- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 36021 bytes, from 2015-07-31 21:25:50) +- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-07-31 21:28:36) - /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-04-30 16:26:30) -- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-31 21:25:50) +- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-07-31 21:28:36)
Copyright (C) 2013-2015 by the following authors: - Rob Clark robdclark@gmail.com (robclark) @@ -887,6 +887,7 @@ static inline uint32_t MDP5_PIPE_SRC_OP_MODE_BWC(enum mdp5_pipe_bwc val) #define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_1 0x00040000 #define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE 0x00400000 #define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE_ODD 0x00800000 +#define MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE 0x80000000
static inline uint32_t REG_MDP5_PIPE_SRC_CONSTANT_COLOR(enum mdp5_pipe i0) { return 0x0000003c + __offset_PIPE(i0); }
@@ -924,6 +925,83 @@ static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val) return ((val) << MDP5_PIPE_DECIMATION_HORZ__SHIFT) & MDP5_PIPE_DECIMATION_HORZ__MASK; }
+static inline uint32_t __offset_SW_PIX_EXT(enum mdp_component_type idx) +{ + switch (idx) { + case COMP_0: return 0x00000100; + case COMP_1_2: return 0x00000110; + case COMP_3: return 0x00000120; + default: return INVALID_IDX(idx); + } +} +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } + +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_LR(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000000 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK 0x000000ff +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT 0 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK 0x0000ff00 +#define MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT 8 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK 0x00ff0000 +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT 16 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK 0xff000000 +#define MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT 24 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_TB(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000004 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK 0x000000ff +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT 0 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK 0x0000ff00 +#define MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT 8 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK 0x00ff0000 +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT 16 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK 0xff000000 +#define MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT 24 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(int32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__SHIFT) & MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(enum mdp5_pipe i0, enum mdp_component_type i1) { return 0x00000008 + __offset_PIPE(i0) + __offset_SW_PIX_EXT(i1); } +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK 0x0000ffff +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT 0 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT__MASK; +} +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK 0xffff0000 +#define MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT 16 +static inline uint32_t MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(uint32_t val) +{ + return ((val) << MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__SHIFT) & MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM__MASK; +} + static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00000204 + __offset_PIPE(i0); } #define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN 0x00000001 #define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN 0x00000002 diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h index 4ddc488..7239a82 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h @@ -8,7 +8,9 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are: -- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2576 bytes, from 2015-07-31 21:25:50) +- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-07-31 21:28:36) +- /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-04-30 16:26:30) +- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-07-31 21:28:36)
Copyright (C) 2015 */ @@ -47,6 +49,13 @@ enum mdp_alpha_type { BG_PIXEL = 3, };
+enum mdp_component_type { + COMP_0 = 0, + COMP_1_2 = 1, + COMP_3 = 2, + COMP_MAX = 3, +}; + enum mdp_bpc { BPC1 = 0, BPC5 = 1,
Pixel Extension are extra pixels fed to the QSEED2 scalar; this information is needed to produce an output image. These values depend on various parameters, such as scalar type, initial phase, phase step, etc.
Pixel extension values used to be handled and calculated by hardware; however, software could also overwrite those values for optimization.
In some hardware (eg: MDP5 v1.7), software *must* program those values since they are not handled in hardware.
Change-Id: I4900165e770f8da702a4f938044616daf5aa81af Signed-off-by: Stephane Viau sviau@codeaurora.org --- rnndb/mdp/mdp5.xml | 24 ++++++++++++++++++++++++ rnndb/mdp/mdp_common.xml | 7 +++++++ 2 files changed, 31 insertions(+)
diff --git a/rnndb/mdp/mdp5.xml b/rnndb/mdp/mdp5.xml index df02377..c829737 100644 --- a/rnndb/mdp/mdp5.xml +++ b/rnndb/mdp/mdp5.xml @@ -390,6 +390,7 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> <bitfield name="IGC_ROM_1" pos="18" type="boolean"/> <bitfield name="DEINTERLACE" pos="22" type="boolean"/> <bitfield name="DEINTERLACE_ODD" pos="23" type="boolean"/> + <bitfield name="SW_PIX_EXT_OVERRIDE" pos="31" type="boolean"/> </reg32> <reg32 offset="0x03c" name="SRC_CONSTANT_COLOR"/> <reg32 offset="0x048" name="FETCH_CONFIG"/> @@ -406,6 +407,29 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> <bitfield name="VERT" low="0" high="7" type="uint"/> <bitfield name="HORZ" low="8" high="15" type="uint"/> </reg32> + <array offsets="0x100,0x110,0x120" name="SW_PIX_EXT" length="3" stride="0x10" index="mdp_component_type"> + <!-- + Notes: + o These value only take effect if SW_PIX_EXT_OVERRIDE is set in SRC_OP_MODE register + o For signed values (int): + indicates overfetch, - indicates line drop + --> + <reg32 offset="0x00" name="LR"> + <bitfield name="LEFT_RPT" low="0" high="7" type="uint"/> + <bitfield name="LEFT_OVF" low="8" high="15" type="int"/> + <bitfield name="RIGHT_RPT" low="16" high="23" type="uint"/> + <bitfield name="RIGHT_OVF" low="24" high="31" type="int"/> + </reg32> + <reg32 offset="0x04" name="TB"> + <bitfield name="TOP_RPT" low="0" high="7" type="uint"/> + <bitfield name="TOP_OVF" low="8" high="15" type="int"/> + <bitfield name="BOTTOM_RPT" low="16" high="23" type="uint"/> + <bitfield name="BOTTOM_OVF" low="24" high="31" type="int"/> + </reg32> + <reg32 offset="0x08" name="REQ_PIXELS"> + <bitfield name="LEFT_RIGHT" low="0" high="15" type="uint"/> + <bitfield name="TOP_BOTTOM" low="16" high="31" type="uint"/> + </reg32> + </array> <reg32 offset="0x204" name="SCALE_CONFIG"> <bitfield name="SCALEX_EN" pos="0" type="boolean"/> <bitfield name="SCALEY_EN" pos="1" type="boolean"/> diff --git a/rnndb/mdp/mdp_common.xml b/rnndb/mdp/mdp_common.xml index 5e8e421..226596a 100644 --- a/rnndb/mdp/mdp_common.xml +++ b/rnndb/mdp/mdp_common.xml @@ -39,6 +39,13 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd"> <value name="BG_PIXEL" value="3"/> </enum>
+<enum name="mdp_component_type"> + <value name="COMP_0" value="0"/> <!-- Y component --> + <value name="COMP_1_2" value="1"/> <!-- Cb/Cr comp. --> + <value name="COMP_3" value="2"/> <!-- Trans comp. --> + <value name="COMP_MAX" value="3"/> +</enum> + <enum name="mdp_bpc"> <brief>bits per component (non-alpha channel)</brief> <value name="BPC1" value="0"/> <!-- 1 bit -->
When calculating phase steps, let's use the same enum mdp_component_type in order to ease the readability; 0/1 indexes are a bit confusing and we now have explicit values to index this type of arrays.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 07fb62f..c294033 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -494,7 +494,7 @@ static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
static int calc_scalex_steps(struct drm_plane *plane, uint32_t pixel_format, uint32_t src, uint32_t dest, - uint32_t phasex_steps[2]) + uint32_t phasex_steps[COMP_MAX]) { struct mdp5_kms *mdp5_kms = get_kms(plane); struct device *dev = mdp5_kms->dev->dev; @@ -510,15 +510,16 @@ static int calc_scalex_steps(struct drm_plane *plane,
hsub = drm_format_horz_chroma_subsampling(pixel_format);
- phasex_steps[0] = phasex_step; - phasex_steps[1] = phasex_step / hsub; + phasex_steps[COMP_0] = phasex_step; + phasex_steps[COMP_3] = phasex_step; + phasex_steps[COMP_1_2] = phasex_step / hsub;
return 0; }
static int calc_scaley_steps(struct drm_plane *plane, uint32_t pixel_format, uint32_t src, uint32_t dest, - uint32_t phasey_steps[2]) + uint32_t phasey_steps[COMP_MAX]) { struct mdp5_kms *mdp5_kms = get_kms(plane); struct device *dev = mdp5_kms->dev->dev; @@ -534,8 +535,9 @@ static int calc_scaley_steps(struct drm_plane *plane,
vsub = drm_format_vert_chroma_subsampling(pixel_format);
- phasey_steps[0] = phasey_step; - phasey_steps[1] = phasey_step / vsub; + phasey_steps[COMP_0] = phasey_step; + phasey_steps[COMP_3] = phasey_step; + phasey_steps[COMP_1_2] = phasey_step / vsub;
return 0; } @@ -587,8 +589,7 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, enum mdp5_pipe pipe = mdp5_plane->pipe; const struct mdp_format *format; uint32_t nplanes, config = 0; - /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */ - uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,}; + uint32_t phasex_step[COMP_MAX] = {0,}, phasey_step[COMP_MAX] = {0,}; uint32_t hdecm = 0, vdecm = 0; uint32_t pix_format; bool vflip, hflip; @@ -696,13 +697,13 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) { mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), - phasex_step[0]); + phasex_step[COMP_0]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), - phasey_step[0]); + phasey_step[COMP_0]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe), - phasex_step[1]); + phasex_step[COMP_1_2]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe), - phasey_step[1]); + phasey_step[COMP_1_2]); mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), MDP5_PIPE_DECIMATION_VERT(vdecm) | MDP5_PIPE_DECIMATION_HORZ(hdecm));
In order to produce an image, the scalar needs to be fed extra pixels. These top/bottom/left/right values depend on a various of factors, including resolution, scaling type, phase step and initial phase.
Pixel Extension are programmed by hardware in most targets - and can be overwritten by software. For some targets (e.g.: msm8996), software *must* program those registers.
In order to ease this computation, let's always use bilinear filters, which are easier to program from kernel. Eventually, all of these values will come down from user space for better quality.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 158 ++++++++++++++++++++++++------ drivers/gpu/drm/msm/mdp/mdp_kms.h | 1 + 2 files changed, 128 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index c294033..c86f49f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -542,40 +542,120 @@ static int calc_scaley_steps(struct drm_plane *plane, return 0; }
-static uint32_t get_scale_config(enum mdp_chroma_samp_type chroma_sample, - uint32_t src, uint32_t dest, bool hor) +static uint32_t get_scale_config(const struct mdp_format *format, + uint32_t src, uint32_t dst, bool horz) { - uint32_t y_filter = (src <= dest) ? SCALE_FILTER_CA : SCALE_FILTER_PCMN; - uint32_t y_a_filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; - uint32_t uv_filter = ((src / 2) <= dest) ? /* 2x upsample */ - SCALE_FILTER_BIL : SCALE_FILTER_PCMN; - uint32_t value = 0; - - if (chroma_sample == CHROMA_420 || chroma_sample == CHROMA_H2V1) { - if (hor) - value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter); - else - value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter); - } else if (src != dest) { - if (hor) - value = MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(y_a_filter); - else - value = MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(y_a_filter) | - MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(y_a_filter); + bool scaling = format->is_yuv ? true : (src != dst); + uint32_t sub, pix_fmt = format->base.pixel_format; + uint32_t ya_filter, uv_filter; + bool yuv = format->is_yuv; + + if (!scaling) + return 0; + + if (yuv) { + sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) : + drm_format_vert_chroma_subsampling(pix_fmt); + uv_filter = ((src / sub) <= dst) ? + SCALE_FILTER_BIL : SCALE_FILTER_PCMN; } + ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN; + + if (horz) + return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN | + MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) | + MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) | + COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter)); + else + return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN | + MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) | + MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) | + COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter)); +} + +static void calc_pixel_ext(const struct mdp_format *format, + uint32_t src, uint32_t dst, uint32_t phase_step[2], + int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX], + bool horz) +{ + bool scaling = format->is_yuv ? true : (src != dst); + int i; + + /* + * Note: + * We assume here that: + * 1. PCMN filter is used for downscale + * 2. bilinear filter is used for upscale + * 3. we are in a single pipe configuration + */
- return value; + for (i = 0; i < COMP_MAX; i++) { + pix_ext_edge1[i] = 0; + pix_ext_edge2[i] = scaling ? 1 : 0; + } }
+static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe, + const struct mdp_format *format, + uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX], + uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX]) +{ + uint32_t pix_fmt = format->base.pixel_format; + uint32_t lr, tb, req; + int i; + + for (i = 0; i < COMP_MAX; i++) { + uint32_t roi_w = src_w; + uint32_t roi_h = src_h; + + if (format->is_yuv && i == COMP_1_2) { + roi_w /= drm_format_horz_chroma_subsampling(pix_fmt); + roi_h /= drm_format_vert_chroma_subsampling(pix_fmt); + } + + lr = (pe_left[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) : + MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]); + + lr |= (pe_right[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) : + MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]); + + tb = (pe_top[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) : + MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]); + + tb |= (pe_bottom[i] >= 0) ? + MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) : + MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]); + + req = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w + + pe_left[i] + pe_right[i]); + + req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h + + pe_top[i] + pe_bottom[i]); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req); + + DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i, + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT), + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT), + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF), + FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF), + FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT)); + + DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i, + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT), + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT), + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF), + FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF), + FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM)); + } +} + + static int mdp5_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -590,6 +670,9 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, const struct mdp_format *format; uint32_t nplanes, config = 0; uint32_t phasex_step[COMP_MAX] = {0,}, phasey_step[COMP_MAX] = {0,}; + bool pe = mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT; + int pe_left[COMP_MAX], pe_right[COMP_MAX]; + int pe_top[COMP_MAX], pe_bottom[COMP_MAX]; uint32_t hdecm = 0, vdecm = 0; uint32_t pix_format; bool vflip, hflip; @@ -637,11 +720,18 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, if (ret) return ret;
+ if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) { + calc_pixel_ext(format, src_w, crtc_w, phasex_step, + pe_left, pe_right, true); + calc_pixel_ext(format, src_h, crtc_h, phasey_step, + pe_top, pe_bottom, false); + } + /* TODO calc hdecm, vdecm */
/* SCALE is used to both scale and up-sample chroma components */ - config |= get_scale_config(format->chroma_sample, src_w, crtc_w, true); - config |= get_scale_config(format->chroma_sample, src_h, crtc_h, false); + config |= get_scale_config(format, src_w, crtc_w, true); + config |= get_scale_config(format, src_h, crtc_h, false); DBG("scale config = %x", config);
hflip = !!(pstate->rotation & BIT(DRM_REFLECT_X)); @@ -690,11 +780,17 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) | (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) | + COND(pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) | MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
/* not using secure mode: */ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
+ if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) + mdp5_write_pixel_ext(mdp5_kms, pipe, format, + src_w, pe_left, pe_right, + src_h, pe_top, pe_bottom); + if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) { mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step[COMP_0]); diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h index 46a94e7..0af2a541 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -106,6 +106,7 @@ const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format); #define MDP_PIPE_CAP_SCALE BIT(2) #define MDP_PIPE_CAP_CSC BIT(3) #define MDP_PIPE_CAP_DECIMATION BIT(4) +#define MDP_PIPE_CAP_SW_PIX_EXT BIT(5)
static inline bool pipe_supports_yuv(uint32_t pipe_caps) {
This change adds the basic MDP5 support for MSM8996.
Signed-off-by: Stephane Viau sviau@codeaurora.org --- Documentation/devicetree/bindings/drm/msm/mdp.txt | 2 + drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 95 ++++++++++++++++++++++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | 9 ++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 18 +++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 2 + drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 18 +++-- drivers/gpu/drm/msm/mdp/mdp_kms.h | 5 ++ 7 files changed, 135 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt index 99ba764..0114a87 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdp.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdp.txt @@ -22,6 +22,7 @@ Optional properties: * "iommu_clk" * "mmagic_clk" - mmagic-supply: phandle for mmagic GDSC regulator used during IOMMU translation +- iommus: phandle for IOMMU v2 device
Example:
@@ -48,5 +49,6 @@ Example: <&mmcc TV_SRC>, <&mmcc HDMI_TV_CLK>, <&mmcc MDP_TV_CLK>; + iommus = <&mdp_smmu 0>; }; }; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index a1e26f2..bb1225a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c @@ -27,6 +27,8 @@ const struct mdp5_cfg_hw msm8x74v1_config = { .mdp = { .count = 1, .base = { 0x00100 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 22, @@ -96,6 +98,8 @@ const struct mdp5_cfg_hw msm8x74v2_config = { .mdp = { .count = 1, .base = { 0x00100 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 22, @@ -165,6 +169,8 @@ const struct mdp5_cfg_hw apq8084_config = { .mdp = { .count = 1, .base = { 0x00100 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 44, @@ -242,6 +248,8 @@ const struct mdp5_cfg_hw msm8x16_config = { .mdp = { .count = 1, .base = { 0x01000 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 8, @@ -301,6 +309,8 @@ const struct mdp5_cfg_hw msm8x94_config = { .mdp = { .count = 1, .base = { 0x01000 }, + .caps = MDP_CAP_SMP | + 0, }, .smp = { .mmb_count = 44, @@ -370,7 +380,89 @@ const struct mdp5_cfg_hw msm8x94_config = { [3] = INTF_HDMI, }, }, - .max_clk = 320000000, + .max_clk = 400000000, +}; + +const struct mdp5_cfg_hw msm8x96_config = { + .name = "msm8x96", + .mdp = { + .count = 1, + .base = { 0x01000 }, + .caps = MDP_CAP_DSC | + MDP_CAP_CDM | + 0, + }, + .ctl = { + .count = 5, + .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, + .flush_hw_mask = 0xf4ffffff, + }, + .pipe_vig = { + .count = 4, + .base = { 0x05000, 0x07000, 0x09000, 0x0b000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_CSC | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_rgb = { + .count = 4, + .base = { 0x15000, 0x17000, 0x19000, 0x1b000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SCALE | + MDP_PIPE_CAP_DECIMATION | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .pipe_dma = { + .count = 2, + .base = { 0x25000, 0x27000 }, + .caps = MDP_PIPE_CAP_HFLIP | + MDP_PIPE_CAP_VFLIP | + MDP_PIPE_CAP_SW_PIX_EXT | + 0, + }, + .lm = { + .count = 6, + .base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 }, + .nb_stages = 8, + .max_width = 2560, + .max_height = 0xFFFF, + }, + .dspp = { + .count = 2, + .base = { 0x55000, 0x57000 }, + }, + .ad = { + .count = 3, + .base = { 0x79000, 0x79800, 0x7a000 }, + }, + .pp = { + .count = 4, + .base = { 0x71000, 0x71800, 0x72000, 0x72800 }, + }, + .cdm = { + .count = 1, + .base = { 0x7a200 }, + }, + .dsc = { + .count = 2, + .base = { 0x81000, 0x81400 }, + }, + .intf = { + .base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 }, + .connect = { + [0] = INTF_DISABLED, + [1] = INTF_DSI, + [2] = INTF_DSI, + [3] = INTF_HDMI, + }, + }, + .max_clk = 412500000, };
static const struct mdp5_cfg_handler cfg_handlers[] = { @@ -379,6 +471,7 @@ static const struct mdp5_cfg_handler cfg_handlers[] = { { .revision = 3, .config = { .hw = &apq8084_config } }, { .revision = 6, .config = { .hw = &msm8x16_config } }, { .revision = 9, .config = { .hw = &msm8x94_config } }, + { .revision = 7, .config = { .hw = &msm8x96_config } }, };
static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h index a6facaf..050e161 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h @@ -64,6 +64,11 @@ struct mdp5_smp_block { uint8_t reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */ };
+struct mdp5_mdp_block { + MDP5_SUB_BLOCK_DEFINITION; + uint32_t caps; /* MDP capabilities: MDP_CAP_xxx bits */ +}; + #define MDP5_INTF_NUM_MAX 5
struct mdp5_intf_block { @@ -74,7 +79,7 @@ struct mdp5_intf_block { struct mdp5_cfg_hw { char *name;
- struct mdp5_sub_block mdp; + struct mdp5_mdp_block mdp; struct mdp5_smp_block smp; struct mdp5_ctl_block ctl; struct mdp5_pipe_block pipe_vig; @@ -84,6 +89,8 @@ struct mdp5_cfg_hw { struct mdp5_sub_block dspp; struct mdp5_sub_block ad; struct mdp5_sub_block pp; + struct mdp5_sub_block dsc; + struct mdp5_sub_block cdm; struct mdp5_intf_block intf;
uint32_t max_clk; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 983bd53..0041d64 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -614,15 +614,23 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) }
config = mdp5_cfg_get_config(mdp5_kms->cfg); + mdp5_kms->caps = config->hw->mdp.caps;
/* TODO: compute core clock rate at runtime */ clk_set_rate(mdp5_kms->src_clk, config->hw->max_clk);
- mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); - if (IS_ERR(mdp5_kms->smp)) { - ret = PTR_ERR(mdp5_kms->smp); - mdp5_kms->smp = NULL; - goto fail; + /* + * Some chipsets have a Shared Memory Pool (SMP), while others + * have dedicated latency buffering per source pipe instead; + * this section initializes the SMP: + */ + if (mdp5_kms->caps & MDP_CAP_SMP) { + mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); + if (IS_ERR(mdp5_kms->smp)) { + ret = PTR_ERR(mdp5_kms->smp); + mdp5_kms->smp = NULL; + goto fail; + } }
mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index ab19d52a..977ef62 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -32,6 +32,8 @@ struct mdp5_kms { struct drm_device *dev;
struct mdp5_cfg_handler *cfg; + uint32_t caps; /* MDP capabilities (MDP_CAP_XXX bits) */ +
/* mapper-id used to request GEM buffer mapped for scanout: */ int id; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index c86f49f..8ee62dc 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -699,10 +699,12 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
/* Request some memory from the SMP: */ - ret = mdp5_smp_request(mdp5_kms->smp, - mdp5_plane->pipe, format, src_w, false); - if (ret) - return ret; + if (mdp5_kms->smp) { + ret = mdp5_smp_request(mdp5_kms->smp, + mdp5_plane->pipe, format, src_w, false); + if (ret) + return ret; + }
/* * Currently we update the hw for allocations/requests immediately, @@ -710,7 +712,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, * would move into atomic->check_plane_state(), while updating the * hw would remain here: */ - mdp5_smp_configure(mdp5_kms->smp, pipe); + if (mdp5_kms->smp) + mdp5_smp_configure(mdp5_kms->smp, pipe);
ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step); if (ret) @@ -829,7 +832,8 @@ void mdp5_plane_complete_flip(struct drm_plane *plane)
DBG("%s: complete flip", mdp5_plane->name);
- mdp5_smp_commit(mdp5_kms->smp, pipe); + if (mdp5_kms->smp) + mdp5_smp_commit(mdp5_kms->smp, pipe);
to_mdp5_plane_state(plane->state)->pending = false; } @@ -855,7 +859,7 @@ void mdp5_plane_complete_commit(struct drm_plane *plane, struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); enum mdp5_pipe pipe = mdp5_plane->pipe;
- if (!plane_enabled(plane->state)) { + if (!plane_enabled(plane->state) && mdp5_kms->smp) { DBG("%s: free SMP", mdp5_plane->name); mdp5_smp_release(mdp5_kms->smp, pipe); } diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h index 0af2a541..3031303 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -100,6 +100,11 @@ struct mdp_format { uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats, bool rgb_only); const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format);
+/* MDP capabilities */ +#define MDP_CAP_SMP BIT(0) /* Shared Memory Pool */ +#define MDP_CAP_DSC BIT(1) /* VESA Display Stream Compression */ +#define MDP_CAP_CDM BIT(2) /* Chroma Down Module (HDMI 2.0 YUV) */ + /* MDP pipe capabilities */ #define MDP_PIPE_CAP_HFLIP BIT(0) #define MDP_PIPE_CAP_VFLIP BIT(1)
dri-devel@lists.freedesktop.org