From 69be1f4e6f4bd92fa96c2de80982f045f9fa9ccc Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Sun, 17 Apr 2016 20:28:43 +0530 Subject: [PATCH 01/52] drm/msm: Use correct type for physical addresses The u32 type used to pass the physical addresses to iommu_map can't accommodate 64 bit addresses. Move to dma_addr_t to ensure wrong addresses aren't provided to the IOMMU driver. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index a7a0b6d9b057..3bc8fd327eed 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -59,10 +59,10 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova, return -EINVAL; for_each_sg(sgt->sgl, sg, sgt->nents, i) { - u32 pa = sg_phys(sg) - sg->offset; + dma_addr_t pa = sg_phys(sg) - sg->offset; size_t bytes = sg->length + sg->offset; - VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes); + VERB("map[%d]: %08x %08lx(%zx)", i, iova, (unsigned long)pa, bytes); ret = iommu_map(domain, da, pa, bytes, prot); if (ret) From cbe4295a4c0aa4758ed4dff91e631e224734034b Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 18 Apr 2016 12:26:21 +0530 Subject: [PATCH 02/52] drm/msm: Print the correct virtual addresses in map/unmap funcs The msm_iommu_map/unmap funcs have debug prints to show the list of VA:PA mappings. Use the correct variable to print the VAs. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 3bc8fd327eed..3a294d0da3a0 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -62,7 +62,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova, dma_addr_t pa = sg_phys(sg) - sg->offset; size_t bytes = sg->length + sg->offset; - VERB("map[%d]: %08x %08lx(%zx)", i, iova, (unsigned long)pa, bytes); + VERB("map[%d]: %08x %08lx(%zx)", i, da, (unsigned long)pa, bytes); ret = iommu_map(domain, da, pa, bytes, prot); if (ret) @@ -101,7 +101,7 @@ static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova, if (unmapped < bytes) return unmapped; - VERB("unmap[%d]: %08x(%zx)", i, iova, bytes); + VERB("unmap[%d]: %08x(%zx)", i, da, bytes); BUG_ON(!PAGE_ALIGNED(bytes)); From 0e0d9dfeea38b20f54d5e056ea8b4d7e1adb2745 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 9 Jun 2016 17:11:08 +0530 Subject: [PATCH 03/52] drm/msm/mdp5: Don't get source of MDP core clock The driver expects DT to provide the parent to MDP core clock. The only operation done to the parent clock is to set a rate. This can be achieved by setting the rate on the core clock itsef. Don't try to get the parent clock anymore. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 7 ++----- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index f0c285b1c027..16316bc4933d 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -627,9 +627,6 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) if (ret) goto fail; ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk", true); - if (ret) - goto fail; - ret = get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src", true); if (ret) goto fail; ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk", true); @@ -646,7 +643,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) * rate first, then figure out hw revision, and then set a * more optimal rate: */ - clk_set_rate(mdp5_kms->src_clk, 200000000); + clk_set_rate(mdp5_kms->core_clk, 200000000); read_hw_revision(mdp5_kms, &major, &minor); @@ -661,7 +658,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) 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); + clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk); /* * Some chipsets have a Shared Memory Pool (SMP), while others diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 9a25898239d3..9cf5aa4e5ec3 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -49,7 +49,6 @@ struct mdp5_kms { struct clk *axi_clk; struct clk *ahb_clk; - struct clk *src_clk; struct clk *core_clk; struct clk *lut_clk; struct clk *vsync_clk; From db9e44fb057311ca3f41ba63eb5f3b5c5ab7632d Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 10 Jun 2016 11:55:43 +0530 Subject: [PATCH 04/52] drm/msm/mdp4: Clean up some MDP4 clocks Fix some issues with MDP4 clocks: - mdp4_dtv_encoder tries to get "src_clk", which is a RCG(TV_SRC) in MSM8960 and APQ8064. This isn't something the driver should access or configure. Instead of this, configure the "mdp_clk" (MDP_TV_CLK), a branch clock in MMCC that has the TV_SRC as its parent. Setting rate/enabling the "mdp_clk" will eventually configure "src_clk", which is what we want. - Rename "mdp_clk" to "tv_clk" because that's slightly less confusing. - Rename "mdp_axi_clk" to "bus_clk" because that's what we do elsewhere too. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c | 31 +++++++------------ drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 2 +- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c index 35ad78a1dc1c..24258e3025e3 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c @@ -23,7 +23,6 @@ struct mdp4_dtv_encoder { struct drm_encoder base; - struct clk *src_clk; struct clk *hdmi_clk; struct clk *mdp_clk; unsigned long int pixclock; @@ -179,7 +178,6 @@ static void mdp4_dtv_encoder_disable(struct drm_encoder *encoder) */ mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC); - clk_disable_unprepare(mdp4_dtv_encoder->src_clk); clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk); clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk); @@ -208,19 +206,21 @@ static void mdp4_dtv_encoder_enable(struct drm_encoder *encoder) bs_set(mdp4_dtv_encoder, 1); - DBG("setting src_clk=%lu", pc); + DBG("setting mdp_clk=%lu", pc); - ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc); + ret = clk_set_rate(mdp4_dtv_encoder->mdp_clk, pc); if (ret) - dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret); - clk_prepare_enable(mdp4_dtv_encoder->src_clk); - ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk); - if (ret) - dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret); + dev_err(dev->dev, "failed to set mdp_clk to %lu: %d\n", + pc, ret); + ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk); if (ret) dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret); + ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk); + if (ret) + dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret); + mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1); mdp4_dtv_encoder->enabled = true; @@ -235,7 +235,7 @@ static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = { long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate) { struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); - return clk_round_rate(mdp4_dtv_encoder->src_clk, rate); + return clk_round_rate(mdp4_dtv_encoder->mdp_clk, rate); } /* initialize encoder */ @@ -257,13 +257,6 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev) DRM_MODE_ENCODER_TMDS, NULL); drm_encoder_helper_add(encoder, &mdp4_dtv_encoder_helper_funcs); - mdp4_dtv_encoder->src_clk = devm_clk_get(dev->dev, "src_clk"); - if (IS_ERR(mdp4_dtv_encoder->src_clk)) { - dev_err(dev->dev, "failed to get src_clk\n"); - ret = PTR_ERR(mdp4_dtv_encoder->src_clk); - goto fail; - } - mdp4_dtv_encoder->hdmi_clk = devm_clk_get(dev->dev, "hdmi_clk"); if (IS_ERR(mdp4_dtv_encoder->hdmi_clk)) { dev_err(dev->dev, "failed to get hdmi_clk\n"); @@ -271,9 +264,9 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev) goto fail; } - mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "mdp_clk"); + mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "tv_clk"); if (IS_ERR(mdp4_dtv_encoder->mdp_clk)) { - dev_err(dev->dev, "failed to get mdp_clk\n"); + dev_err(dev->dev, "failed to get tv_clk\n"); ret = PTR_ERR(mdp4_dtv_encoder->mdp_clk); goto fail; } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index f145d256e332..388663afd23f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -492,7 +492,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) goto fail; } - mdp4_kms->axi_clk = devm_clk_get(&pdev->dev, "mdp_axi_clk"); + mdp4_kms->axi_clk = devm_clk_get(&pdev->dev, "bus_clk"); if (IS_ERR(mdp4_kms->axi_clk)) { dev_err(dev->dev, "failed to get axi_clk\n"); ret = PTR_ERR(mdp4_kms->axi_clk); From 1f238536ae37b179e8beb679bcd0b7259eb5e886 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 10 Jun 2016 12:01:58 +0530 Subject: [PATCH 05/52] dt-bindings: msm/mdp: Fix up clock related bindings Address some issues wiht clock related bindings. It's okay to change these since these bindings aren't used in any dtsi files until now. MDP5: - Don't ask for source clock MDP4: - Give a better name for MDP_TV_CLK - Remove TV_SRC - Add MDP_AXI_CLK Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/mdp.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/mdp.txt b/Documentation/devicetree/bindings/display/msm/mdp.txt index a214f6cd0363..ebfe0165b9a6 100644 --- a/Documentation/devicetree/bindings/display/msm/mdp.txt +++ b/Documentation/devicetree/bindings/display/msm/mdp.txt @@ -13,14 +13,13 @@ Required properties: For MDP4: * "core_clk" * "iface_clk" + * "bus_clk" * "lut_clk" - * "src_clk" * "hdmi_clk" - * "mdp_clk" + * "tv_clk" For MDP5: * "bus_clk" * "iface_clk" - * "core_clk_src" * "core_clk" * "lut_clk" (some MDP5 versions may not need this) * "vsync_clk" @@ -45,14 +44,13 @@ Example: "core_clk", "iface_clk", "lut_clk", - "src_clk", "hdmi_clk", - "mdp_clk"; + "tv_clk"; clocks = - <&mmcc MDP_SRC>, + <&mmcc MDP_CLK>, <&mmcc MDP_AHB_CLK>, + <&mmcc MDP_AXI_CLK>, <&mmcc MDP_LUT_CLK>, - <&mmcc TV_SRC>, <&mmcc HDMI_TV_CLK>, <&mmcc MDP_TV_CLK>; }; From b9ac76f6ac984158175f8928d10bc1a7038b699b Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 27 Apr 2016 15:36:53 +0530 Subject: [PATCH 06/52] drm/msm/dsi: Modify port parsing The DSI interface is going to have two ports defined in its device node. The first port is always going to be the link between the MDP output and the input to DSI, the second port is going to be the link between the DSI output and the connected panel/bridge: ----- ----- ------- | MDP | ------> | DSI | ------> | Panel | ----- ----- ------- (Port 0) (Port 1) Until now, there was only one Port representing the output. Update the DSI host driver such that it parses Port #1 for a connected device. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index a3e47ad83eb3..4f1335e47f5e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1602,12 +1602,12 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) } /* - * Get the first endpoint node. In our case, dsi has one output port - * to which the panel is connected. Don't return an error if a port - * isn't defined. It's possible that there is nothing connected to - * the dsi output. + * Get the endpoint of the output port of the DSI host. In our case, + * this is mapped to port number with reg = 1. Don't return an error if + * the remote endpoint isn't defined. It's possible that there is + * nothing connected to the dsi output. */ - endpoint = of_graph_get_next_endpoint(np, NULL); + endpoint = of_graph_get_endpoint_by_regs(np, 1, -1); if (!endpoint) { dev_dbg(dev, "%s: no endpoint\n", __func__); return 0; From 69696ea041fa7bffb04d2141f6ec997c24cf09da Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 29 Apr 2016 18:04:47 +0530 Subject: [PATCH 07/52] drm/msm/dsi: Use generic PHY bindings The DSI host links to the DSI PHY device using a custom binding. Switch to the generic PHY bindings. The DSI PHY driver itself doesn't use the common PHY framework for now. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 6edcd6f57e70..ec572f8389ed 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -29,7 +29,7 @@ static int dsi_get_phy(struct msm_dsi *msm_dsi) struct platform_device *phy_pdev; struct device_node *phy_node; - phy_node = of_parse_phandle(pdev->dev.of_node, "qcom,dsi-phy", 0); + phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0); if (!phy_node) { dev_err(&pdev->dev, "cannot find phy device\n"); return -ENXIO; From 60282cea5bfa934694decfe836ee4600504bdeb1 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 8 Jun 2016 16:14:19 +0530 Subject: [PATCH 08/52] drm/msm/dsi: Use a standard DT binding for data lanes A more standard DT binding describing data lanes already exists here: Documentation/devicetree/bindings/media/video-interfaces.txt Use this binding instead of "qcom,data-lane-map". One difference in the standard binding w.r.t to the existing binding is that it provides a logical to physical mapping instead of the other way round. Tweak the code to translate the data the way we want it. The MSM DSI DT bindings aren't used anywhere at the moment, so it's okay to update this property. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 4f1335e47f5e..e6a8cd1b6462 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1543,7 +1543,7 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host, u32 lane_map[4]; int ret, i, len, num_lanes; - prop = of_find_property(ep, "qcom,data-lane-map", &len); + prop = of_find_property(ep, "data-lanes", &len); if (!prop) { dev_dbg(dev, "failed to find data lane mapping\n"); return -EINVAL; @@ -1558,7 +1558,7 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host, msm_host->num_data_lanes = num_lanes; - ret = of_property_read_u32_array(ep, "qcom,data-lane-map", lane_map, + ret = of_property_read_u32_array(ep, "data-lanes", lane_map, num_lanes); if (ret) { dev_err(dev, "failed to read lane data\n"); @@ -1573,8 +1573,19 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host, const int *swap = supported_data_lane_swaps[i]; int j; + /* + * the data-lanes array we get from DT has a logical->physical + * mapping. The "data lane swap" register field represents + * supported configurations in a physical->logical mapping. + * Translate the DT mapping to what we understand and find a + * configuration that works. + */ for (j = 0; j < num_lanes; j++) { - if (swap[j] != lane_map[j]) + if (lane_map[j] < 0 || lane_map[j] > 3) + dev_err(dev, "bad physical lane entry %u\n", + lane_map[j]); + + if (swap[lane_map[j]] != j) break; } From cb9b08e9c11a3413b6db866d11a7c6348da44931 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 9 Jun 2016 11:51:33 +0530 Subject: [PATCH 09/52] dt-bindings: msm/dsi: Use standard data lanes binding The "qcom,data-lane-map" binding mentioned in the document is changed to the more generic "data-lanes" property specified in: Documentation/devicetree/bindings/media/video-interfaces.txt The previous binding expressed physical to logical data lane mappings, the standard "data-lanes" binding uses logical to physical data lane mappings. Update the docs to reflect this change. The example had the property incorrectly named as "lanes", update this too. The MSM DSI DT bindings aren't used anywhere at the moment, so it's okay to update this property. Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/dsi.txt | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index f5948c48b9a2..9d2d2bb60c42 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -49,29 +49,30 @@ Optional properties: DSI Endpoint properties: - remote-endpoint: set to phandle of the connected panel's endpoint. See Documentation/devicetree/bindings/graph.txt for device graph info. - - qcom,data-lane-map: this describes how the logical DSI lanes are mapped - to the physical lanes on the given platform. The value contained in - index n describes what logical data lane is mapped to the physical data - lane n (DATAn, where n lies between 0 and 3). + - data-lanes: this describes how the physical DSI data lanes are mapped + to the logical lanes on the given platform. The value contained in + index n describes what physical lane is mapped to the logical lane n + (DATAn, where n lies between 0 and 3). The clock lane position is fixed + and can't be changed. Hence, they aren't a part of the DT bindings. For + more info, see Documentation/devicetree/bindings/media/video-interfaces.txt For example: - qcom,data-lane-map = <3 0 1 2>; + data-lanes = <3 0 1 2>; - The above mapping describes that the logical data lane DATA3 is mapped to - the physical data lane DATA0, logical DATA0 to physical DATA1, logic DATA1 - to phys DATA2 and logic DATA2 to phys DATA3. + The above mapping describes that the logical data lane DATA0 is mapped to + the physical data lane DATA3, logical DATA1 to physical DATA0, logic DATA2 + to phys DATA1 and logic DATA3 to phys DATA2. There are only a limited number of physical to logical mappings possible: - - "0123": Logic 0->Phys 0; Logic 1->Phys 1; Logic 2->Phys 2; Logic 3->Phys 3; - "3012": Logic 3->Phys 0; Logic 0->Phys 1; Logic 1->Phys 2; Logic 2->Phys 3; - "2301": Logic 2->Phys 0; Logic 3->Phys 1; Logic 0->Phys 2; Logic 1->Phys 3; - "1230": Logic 1->Phys 0; Logic 2->Phys 1; Logic 3->Phys 2; Logic 0->Phys 3; - "0321": Logic 0->Phys 0; Logic 3->Phys 1; Logic 2->Phys 2; Logic 1->Phys 3; - "1032": Logic 1->Phys 0; Logic 0->Phys 1; Logic 3->Phys 2; Logic 2->Phys 3; - "2103": Logic 2->Phys 0; Logic 1->Phys 1; Logic 0->Phys 2; Logic 3->Phys 3; - "3210": Logic 3->Phys 0; Logic 2->Phys 1; Logic 1->Phys 2; Logic 0->Phys 3; + <0 1 2 3> + <1 2 3 0> + <2 3 0 1> + <3 0 1 2> + <0 3 2 1> + <1 0 3 2> + <2 1 0 3> + <3 2 1 0> DSI PHY: Required properties: @@ -156,7 +157,7 @@ Example: port { dsi0_out: endpoint { remote-endpoint = <&panel_in>; - lanes = <0 1 2 3>; + data-lanes = <0 1 2 3>; }; }; }; From 8042b778995255ef6d695a665818ec23ee75043f Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 9 Jun 2016 15:46:24 +0530 Subject: [PATCH 10/52] dt-bindings: msm/dsi: Modify port and PHY bindings The DSI node now has two ports that describe the connection between the MDP interface output and the DSI input, and the connection between the DSI output and the connected panel/bridge. Update the properties and the example. Also, use generic PHY bindings instead of the custom one. Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/dsi.txt | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index 9d2d2bb60c42..64424081d9c5 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -26,8 +26,14 @@ Required properties: - vdd-supply: phandle to vdd regulator device node - vddio-supply: phandle to vdd-io regulator device node - vdda-supply: phandle to vdda regulator device node -- qcom,dsi-phy: phandle to DSI PHY device node +- phys: phandle to DSI PHY device node +- phy-names: the name of the corresponding PHY device - syscon-sfpb: A phandle to mmss_sfpb syscon node (only for DSIv2) +- ports: Contains 2 DSI controller ports as child nodes. Each port contains + an endpoint subnode as defined in these documents: + + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt Optional properties: - panel@0: Node of panel connected to this DSI controller. @@ -44,11 +50,14 @@ Optional properties: - pinctrl-names: the pin control state names; should contain "default" - pinctrl-0: the default pinctrl state (active) - pinctrl-n: the "sleep" pinctrl state -- port: DSI controller output port, containing one endpoint subnode. +- ports: contains DSI controller input and output ports as children, each + containing one endpoint subnode. DSI Endpoint properties: - - remote-endpoint: set to phandle of the connected panel's endpoint. + - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's + input endpoint. For port@1, set to the MDP interface output. See Documentation/devicetree/bindings/graph.txt for device graph info. + - data-lanes: this describes how the physical DSI data lanes are mapped to the logical lanes on the given platform. The value contained in index n describes what physical lane is mapped to the logical lane n @@ -129,7 +138,8 @@ Example: vdd-supply = <&pma8084_l22>; vddio-supply = <&pma8084_l12>; - qcom,dsi-phy = <&mdss_dsi_phy0>; + phys = <&mdss_dsi_phy0>; + phy-names ="dsi-phy"; qcom,dual-dsi-mode; qcom,master-dsi; @@ -139,6 +149,26 @@ Example: pinctrl-0 = <&mdss_dsi_active>; pinctrl-1 = <&mdss_dsi_suspend>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&mdp_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + remote-endpoint = <&panel_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; + panel: panel@0 { compatible = "sharp,lq101r1sx01"; reg = <0>; @@ -153,13 +183,6 @@ Example: }; }; }; - - port { - dsi0_out: endpoint { - remote-endpoint = <&panel_in>; - data-lanes = <0 1 2 3>; - }; - }; }; mdss_dsi_phy0: qcom,mdss_dsi_phy@fd922a00 { From 9097209d4d0cc3bb6be7149a14276e8fe0ce7438 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 9 Jun 2016 15:51:44 +0530 Subject: [PATCH 11/52] dt-bindings: msm/dsi: Add assigned clocks bindings The PLL in the DSI PHY block generates 2 clock outputs (Byte and Pixel clocks) that are fed into the Multimedia Clock Controller (MMCC). The MMCC uses these as source clocks for some of its RCGs to generate clocks that finally feed to the DSI host controller. Use the assigned clocks DT bindings to set up the MMCC RCGs that feed to the DSI host. Use the DSI PHY provided clocks to set up the parents of these assigned clocks. Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/dsi.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index 64424081d9c5..f458929324aa 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -12,7 +12,6 @@ Required properties: - interrupts: The interrupt signal from the DSI block. - power-domains: Should be <&mmcc MDSS_GDSC>. - clocks: device clocks - See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details. - clock-names: the following clocks are required: * "mdp_core_clk" * "iface_clk" @@ -23,6 +22,10 @@ Required properties: * "core_clk" For DSIv2, we need an additional clock: * "src_clk" +- assigned-clocks: Parents of "byte_clk" and "pixel_clk" for the given platform. +- assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided + by a DSI PHY block. + See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details. - vdd-supply: phandle to vdd regulator device node - vddio-supply: phandle to vdd-io regulator device node - vdda-supply: phandle to vdda regulator device node @@ -96,6 +99,8 @@ Required properties: * "dsi_pll" * "dsi_phy" * "dsi_phy_regulator" +- clock-cells: Must be 1. The DSI PHY block acts as a clock provider, creating + 2 clocks: A byte clock (index 0), and a pixel clock (index 1). - qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should be 0 or 1, since we have 2 DSI PHYs at most for now. - power-domains: Should be <&mmcc MDSS_GDSC>. @@ -134,6 +139,14 @@ Example: <&mmcc MDSS_AHB_CLK>, <&mmcc MDSS_MDP_CLK>, <&mmcc MDSS_PCLK0_CLK>; + + assigned-clocks = + <&mmcc BYTE0_CLK_SRC>, + <&mmcc PCLK0_CLK_SRC>; + assigned-clock-parents = + <&mdss_dsi_phy0 0>, + <&mdss_dsi_phy0 1>; + vdda-supply = <&pma8084_l2>; vdd-supply = <&pma8084_l22>; vddio-supply = <&pma8084_l12>; @@ -197,6 +210,7 @@ Example: <0xfd922d80 0x7b>; clock-names = "iface_clk"; clocks = <&mmcc MDSS_AHB_CLK>; + #clock-cells = <1>; vddio-supply = <&pma8084_l12>; qcom,dsi-phy-regulator-ldo-mode; From a3c463e0961c924aaeb64274906343ee2b814d99 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 9 Jun 2016 17:07:25 +0530 Subject: [PATCH 12/52] dt-bindings: msm/dsi: Some binding doc cleanups Some cleanups: - Use simpler names for DT nodes in the example - Use references instead of dumping Document links everywhere Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/dsi.txt | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index f458929324aa..6b1cab17f52d 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -11,7 +11,7 @@ Required properties: be 0 or 1, since we have 2 DSI controllers at most for now. - interrupts: The interrupt signal from the DSI block. - power-domains: Should be <&mmcc MDSS_GDSC>. -- clocks: device clocks +- clocks: Phandles to device clocks. - clock-names: the following clocks are required: * "mdp_core_clk" * "iface_clk" @@ -24,8 +24,7 @@ Required properties: * "src_clk" - assigned-clocks: Parents of "byte_clk" and "pixel_clk" for the given platform. - assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided - by a DSI PHY block. - See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details. + by a DSI PHY block. See [1] for details on clock bindings. - vdd-supply: phandle to vdd regulator device node - vddio-supply: phandle to vdd-io regulator device node - vdda-supply: phandle to vdda regulator device node @@ -33,15 +32,11 @@ Required properties: - phy-names: the name of the corresponding PHY device - syscon-sfpb: A phandle to mmss_sfpb syscon node (only for DSIv2) - ports: Contains 2 DSI controller ports as child nodes. Each port contains - an endpoint subnode as defined in these documents: - - Documentation/devicetree/bindings/graph.txt - Documentation/devicetree/bindings/media/video-interfaces.txt + an endpoint subnode as defined in [2] and [3]. Optional properties: - panel@0: Node of panel connected to this DSI controller. - See files in Documentation/devicetree/bindings/display/panel/ for each supported - panel. + See files in [4] for each supported panel. - qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is driving a panel which needs 2 DSI links. - qcom,master-dsi: Boolean value indicating if the DSI controller is driving @@ -58,15 +53,15 @@ Optional properties: DSI Endpoint properties: - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's - input endpoint. For port@1, set to the MDP interface output. - See Documentation/devicetree/bindings/graph.txt for device graph info. + input endpoint. For port@1, set to the MDP interface output. See [2] for + device graph info. - data-lanes: this describes how the physical DSI data lanes are mapped to the logical lanes on the given platform. The value contained in index n describes what physical lane is mapped to the logical lane n (DATAn, where n lies between 0 and 3). The clock lane position is fixed - and can't be changed. Hence, they aren't a part of the DT bindings. For - more info, see Documentation/devicetree/bindings/media/video-interfaces.txt + and can't be changed. Hence, they aren't a part of the DT bindings. See + [3] for more info on the data-lanes property. For example: @@ -104,8 +99,7 @@ Required properties: - qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should be 0 or 1, since we have 2 DSI PHYs at most for now. - power-domains: Should be <&mmcc MDSS_GDSC>. -- clocks: device clocks - See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details. +- clocks: Phandles to device clocks. See [1] for details on clock bindings. - clock-names: the following clocks are required: * "iface_clk" - vddio-supply: phandle to vdd-io regulator device node @@ -114,11 +108,16 @@ Optional properties: - qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY regulator is wanted. +[1] Documentation/devicetree/bindings/clocks/clock-bindings.txt +[2] Documentation/devicetree/bindings/graph.txt +[3] Documentation/devicetree/bindings/media/video-interfaces.txt +[4] Documentation/devicetree/bindings/display/panel/ + Example: - mdss_dsi0: qcom,mdss_dsi@fd922800 { + dsi0: dsi@fd922800 { compatible = "qcom,mdss-dsi-ctrl"; qcom,dsi-host-index = <0>; - interrupt-parent = <&mdss_mdp>; + interrupt-parent = <&mdp>; interrupts = <4 0>; reg-names = "dsi_ctrl"; reg = <0xfd922800 0x200>; @@ -144,14 +143,14 @@ Example: <&mmcc BYTE0_CLK_SRC>, <&mmcc PCLK0_CLK_SRC>; assigned-clock-parents = - <&mdss_dsi_phy0 0>, - <&mdss_dsi_phy0 1>; + <&dsi_phy0 0>, + <&dsi_phy0 1>; vdda-supply = <&pma8084_l2>; vdd-supply = <&pma8084_l22>; vddio-supply = <&pma8084_l12>; - phys = <&mdss_dsi_phy0>; + phys = <&dsi_phy0>; phy-names ="dsi-phy"; qcom,dual-dsi-mode; @@ -159,8 +158,8 @@ Example: qcom,sync-dual-dsi; pinctrl-names = "default", "sleep"; - pinctrl-0 = <&mdss_dsi_active>; - pinctrl-1 = <&mdss_dsi_suspend>; + pinctrl-0 = <&dsi_active>; + pinctrl-1 = <&dsi_suspend>; ports { #address-cells = <1>; @@ -198,7 +197,7 @@ Example: }; }; - mdss_dsi_phy0: qcom,mdss_dsi_phy@fd922a00 { + dsi_phy0: dsi-phy@fd922a00 { compatible = "qcom,dsi-phy-28nm-hpm"; qcom,dsi-phy-index = <0>; reg-names = From 6a5625d82704b1777696048e837c51418cfad1d8 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 5 May 2016 21:26:34 +0530 Subject: [PATCH 13/52] drm/msm: Drop the id_table in platform_driver This isn't needed as we only support OF. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index a02dc2b27739..476eafef7add 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -852,11 +852,6 @@ static int msm_pdev_remove(struct platform_device *pdev) return 0; } -static const struct platform_device_id msm_id[] = { - { "mdp", 0 }, - { } -}; - static const struct of_device_id dt_match[] = { { .compatible = "qcom,mdp4", .data = (void *) 4 }, /* mdp4 */ { .compatible = "qcom,mdp5", .data = (void *) 5 }, /* mdp5 */ @@ -874,7 +869,6 @@ static struct platform_driver msm_platform_driver = { .of_match_table = dt_match, .pm = &msm_pm_ops, }, - .id_table = msm_id, }; static int __init msm_drm_register(void) From 7429d860c1dce7361f97179ad096f1b0e64d40c4 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 6 May 2016 18:17:15 +0530 Subject: [PATCH 14/52] drm/msm: Remove unused fields These aren't used. Probably left overs when driver was refactored to support both MDP4 and MDP5. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_kms.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index e32222c3d44f..00998f9ef16a 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -60,11 +60,6 @@ struct msm_kms_funcs { struct msm_kms { const struct msm_kms_funcs *funcs; - - /* irq handling: */ - bool in_irq; - struct list_head irq_list; /* list of mdp4_irq */ - uint32_t vblank_mask; /* irq bits set for userspace vblank */ }; static inline void msm_kms_init(struct msm_kms *kms, From a2b3a5571f386e23b56164396292675bac6f2a19 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 18 May 2016 15:06:03 +0530 Subject: [PATCH 15/52] drm/msm: Get irq number within kms driver itself The driver gets the irq number using platform_get_irq on the main kms platform device. This works fine since both MDP4 and MDP5 currently have a flat device hierarchy. The platform device tied with the drm_device points to the MDP DT node in both cases. This won't work when MDP5 supports a tree-like hierarchy. In this case, the platform device tied to the top level drm_device is the MDSS DT node, and the irq we need for KMS is the one generated by MDP5, not MDSS. Get the irq number from the MDP4/5 kms driver itself. Each driver can later provide the irq number based on what device hierarchy it uses. While we're at it, call drm_irq_install only when we have a valid KMS driver. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 11 ++++++++++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 11 ++++++++++- drivers/gpu/drm/msm/msm_drv.c | 14 ++++++++------ drivers/gpu/drm/msm/msm_kms.h | 3 +++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 388663afd23f..b6920917c4a9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -436,7 +436,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) struct mdp4_kms *mdp4_kms; struct msm_kms *kms = NULL; struct msm_mmu *mmu; - int ret; + int irq, ret; mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL); if (!mdp4_kms) { @@ -457,6 +457,15 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) goto fail; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + dev_err(dev->dev, "failed to get irq: %d\n", ret); + goto fail; + } + + kms->irq = irq; + /* NOTE: driver for this regulator still missing upstream.. use * _get_exclusive() and ignore the error if it does not exist * (and hope that the bootloader left it on for us) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 16316bc4933d..e5b63611cbc2 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -580,7 +580,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) struct msm_kms *kms = NULL; struct msm_mmu *mmu; uint32_t major, minor; - int i, ret; + int irq, i, ret; mdp5_kms = kzalloc(sizeof(*mdp5_kms), GFP_KERNEL); if (!mdp5_kms) { @@ -610,6 +610,15 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) goto fail; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + dev_err(dev->dev, "failed to get irq: %d\n", ret); + goto fail; + } + + kms->irq = irq; + mdp5_kms->vdd = devm_regulator_get(&pdev->dev, "vdd"); if (IS_ERR(mdp5_kms->vdd)) { ret = PTR_ERR(mdp5_kms->vdd); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 476eafef7add..092926b35baf 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -417,12 +417,14 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) goto fail; } - pm_runtime_get_sync(dev); - ret = drm_irq_install(ddev, platform_get_irq(pdev, 0)); - pm_runtime_put_sync(dev); - if (ret < 0) { - dev_err(dev, "failed to install IRQ handler\n"); - goto fail; + if (kms) { + pm_runtime_get_sync(dev); + ret = drm_irq_install(ddev, kms->irq); + pm_runtime_put_sync(dev); + if (ret < 0) { + dev_err(dev, "failed to install IRQ handler\n"); + goto fail; + } } ret = drm_dev_register(ddev, 0); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 00998f9ef16a..0452856355c1 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -60,6 +60,9 @@ struct msm_kms_funcs { struct msm_kms { const struct msm_kms_funcs *funcs; + + /* irq number to be passed on to drm_irq_install */ + int irq; }; static inline void msm_kms_init(struct msm_kms *kms, From 990a40079a55b81b5b6aef91a24aa053fb370072 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Sat, 7 May 2016 23:11:25 +0530 Subject: [PATCH 16/52] drm/msm/mdp5: Add MDSS top level driver SoCs that contain MDP5 have a top level wrapper called MDSS that manages clocks, power and irq for the sub-blocks within it. Currently, the MDSS portions are stuffed into the MDP5 driver. This makes it hard to represent the DT bindings in the correct way. We create a top level MDSS helper that handles these parts. This is essentially moving out some of the mdp5_kms irq code and MDSS register space and keeping it as a separate entity. We haven't given any clocks to the top level MDSS yet, but a AHB clock would be added in the future to access registers. One thing to note is that the resources allocated by this helper are tied to the top level platform_device (the one that allocates the drm_device struct too). This device would be the parent to MDSS sub-blocks like MDP5, DSI, eDP etc. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c | 223 +++++++++++++++++++++++ drivers/gpu/drm/msm/msm_drv.h | 4 + drivers/gpu/drm/msm/msm_kms.h | 2 + 4 files changed, 230 insertions(+) create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 60cb02624dc0..4727d045f179 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -35,6 +35,7 @@ msm-y := \ mdp/mdp5/mdp5_crtc.o \ mdp/mdp5/mdp5_encoder.o \ mdp/mdp5/mdp5_irq.o \ + mdp/mdp5/mdp5_mdss.o \ mdp/mdp5/mdp5_kms.o \ mdp/mdp5/mdp5_plane.o \ mdp/mdp5/mdp5_smp.o \ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c new file mode 100644 index 000000000000..871c4424a820 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c @@ -0,0 +1,223 @@ +/* + * 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 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include + +#include "msm_drv.h" +#include "mdp5_kms.h" + +/* + * If needed, this can become more specific: something like struct mdp5_mdss, + * which contains a 'struct msm_mdss base' member. + */ +struct msm_mdss { + struct drm_device *dev; + + void __iomem *mmio, *vbif; + + struct regulator *vdd; + + struct { + volatile unsigned long enabled_mask; + struct irq_domain *domain; + } irqcontroller; +}; + +static inline void mdss_write(struct msm_mdss *mdss, u32 reg, u32 data) +{ + msm_writel(data, mdss->mmio + reg); +} + +static inline u32 mdss_read(struct msm_mdss *mdss, u32 reg) +{ + return msm_readl(mdss->mmio + reg); +} + +static irqreturn_t mdss_irq(int irq, void *arg) +{ + struct msm_mdss *mdss = arg; + u32 intr; + + intr = mdss_read(mdss, REG_MDSS_HW_INTR_STATUS); + + VERB("intr=%08x", intr); + + while (intr) { + irq_hw_number_t hwirq = fls(intr) - 1; + + generic_handle_irq(irq_find_mapping( + mdss->irqcontroller.domain, hwirq)); + intr &= ~(1 << hwirq); + } + + return IRQ_HANDLED; +} + +/* + * interrupt-controller implementation, so sub-blocks (MDP/HDMI/eDP/DSI/etc) + * can register to get their irq's delivered + */ + +#define VALID_IRQS (MDSS_HW_INTR_STATUS_INTR_MDP | \ + MDSS_HW_INTR_STATUS_INTR_DSI0 | \ + MDSS_HW_INTR_STATUS_INTR_DSI1 | \ + MDSS_HW_INTR_STATUS_INTR_HDMI | \ + MDSS_HW_INTR_STATUS_INTR_EDP) + +static void mdss_hw_mask_irq(struct irq_data *irqd) +{ + struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd); + + smp_mb__before_atomic(); + clear_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask); + smp_mb__after_atomic(); +} + +static void mdss_hw_unmask_irq(struct irq_data *irqd) +{ + struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd); + + smp_mb__before_atomic(); + set_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask); + smp_mb__after_atomic(); +} + +static struct irq_chip mdss_hw_irq_chip = { + .name = "mdss", + .irq_mask = mdss_hw_mask_irq, + .irq_unmask = mdss_hw_unmask_irq, +}; + +static int mdss_hw_irqdomain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct msm_mdss *mdss = d->host_data; + + if (!(VALID_IRQS & (1 << hwirq))) + return -EPERM; + + irq_set_chip_and_handler(irq, &mdss_hw_irq_chip, handle_level_irq); + irq_set_chip_data(irq, mdss); + + return 0; +} + +static struct irq_domain_ops mdss_hw_irqdomain_ops = { + .map = mdss_hw_irqdomain_map, + .xlate = irq_domain_xlate_onecell, +}; + + +static int mdss_irq_domain_init(struct msm_mdss *mdss) +{ + struct device *dev = mdss->dev->dev; + struct irq_domain *d; + + d = irq_domain_add_linear(dev->of_node, 32, &mdss_hw_irqdomain_ops, + mdss); + if (!d) { + dev_err(dev, "mdss irq domain add failed\n"); + return -ENXIO; + } + + mdss->irqcontroller.enabled_mask = 0; + mdss->irqcontroller.domain = d; + + return 0; +} + +void msm_mdss_destroy(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_mdss *mdss = priv->mdss; + + if (!mdss) + return; + + irq_domain_remove(mdss->irqcontroller.domain); + mdss->irqcontroller.domain = NULL; + + regulator_disable(mdss->vdd); +} + +int msm_mdss_init(struct drm_device *dev) +{ + struct platform_device *pdev = dev->platformdev; + struct msm_drm_private *priv = dev->dev_private; + struct msm_mdss *mdss; + int ret; + + DBG(""); + + if (!of_device_is_compatible(dev->dev->of_node, "qcom,mdss")) + return 0; + + mdss = devm_kzalloc(dev->dev, sizeof(*mdss), GFP_KERNEL); + if (!mdss) { + ret = -ENOMEM; + goto fail; + } + + mdss->dev = dev; + + mdss->mmio = msm_ioremap(pdev, "mdss_phys", "MDSS"); + if (IS_ERR(mdss->mmio)) { + ret = PTR_ERR(mdss->mmio); + goto fail; + } + + mdss->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); + if (IS_ERR(mdss->vbif)) { + ret = PTR_ERR(mdss->vbif); + goto fail; + } + + /* Regulator to enable GDSCs in downstream kernels */ + mdss->vdd = devm_regulator_get(dev->dev, "vdd"); + if (IS_ERR(mdss->vdd)) { + ret = PTR_ERR(mdss->vdd); + goto fail; + } + + ret = regulator_enable(mdss->vdd); + if (ret) { + dev_err(dev->dev, "failed to enable regulator vdd: %d\n", + ret); + goto fail; + } + + ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0), + mdss_irq, 0, "mdss_isr", mdss); + if (ret) { + dev_err(dev->dev, "failed to init irq: %d\n", ret); + goto fail_irq; + } + + ret = mdss_irq_domain_init(mdss); + if (ret) { + dev_err(dev->dev, "failed to init sub-block irqs: %d\n", ret); + goto fail_irq; + } + + priv->mdss = mdss; + + return 0; +fail_irq: + regulator_disable(mdss->vdd); +fail: + return ret; +} diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 5b2963f32291..a7acd839282e 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -46,6 +46,7 @@ struct msm_kms; struct msm_gpu; struct msm_mmu; +struct msm_mdss; struct msm_rd_state; struct msm_perf_state; struct msm_gem_submit; @@ -82,6 +83,9 @@ struct msm_drm_private { /* subordinate devices, if present: */ struct platform_device *gpu_pdev; + /* top level MDSS wrapper device (for MDP5 only) */ + struct msm_mdss *mdss; + /* possibly this should be in the kms component, but it is * shared by both mdp4 and mdp5.. */ diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 0452856355c1..40e41e5cdbc6 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -73,5 +73,7 @@ static inline void msm_kms_init(struct msm_kms *kms, struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); +int msm_mdss_init(struct drm_device *dev); +void msm_mdss_destroy(struct drm_device *dev); #endif /* __MSM_KMS_H__ */ From 1dd0a0b18697e59c0928cea41b7e922e80d7d246 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 30 May 2016 16:36:50 +0530 Subject: [PATCH 17/52] drm/msm/mdp5: Create a separate MDP5 device In order to have a tree-like device hierarchy between MDSS and its sub-blocks (MDP5, DSI, HDMI, eDP etc), we need to create a separate device/driver for MDP5. Currently, MDP5 and MDSS are squashed together are are tied to the top level platform_device, which is also the one used to create drm_device. The mdp5_kms_init code is split into two parts. The part where device resources are allocated are associated with the MDP5 driver's probe, the rest is executed later when we initialize modeset. With this change, unlike MDP4, the MDP5 platform_device isn't tied to the top level drm_device anymore. The top level drm_device is now associated with a platform device that corresponds to MDSS wrapper hardware. Create mdp5_init/destroy funcs that will be used by the MDP5 driver probe/remove. Use the HW_VERSION register in the MDP5 register address space. Both the MDSS and MDP VERSION registers give out identical version info. The older mdp5_kms_init code is left as is for now, this would be removed later when we have all the pieces to support the new device hierarchy. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 185 +++++++++++++++++++++++- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 2 + drivers/gpu/drm/msm/msm_drv.c | 2 + drivers/gpu/drm/msm/msm_drv.h | 3 + 4 files changed, 189 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index e5b63611cbc2..fcb1bf450883 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -111,7 +111,7 @@ static int mdp5_set_split_display(struct msm_kms *kms, return mdp5_encoder_set_split_display(encoder, slave_encoder); } -static void mdp5_destroy(struct msm_kms *kms) +static void mdp5_kms_destroy(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct msm_mmu *mmu = mdp5_kms->mmu; @@ -148,7 +148,7 @@ static const struct mdp_kms_funcs kms_funcs = { .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, .set_split_display = mdp5_set_split_display, - .destroy = mdp5_destroy, + .destroy = mdp5_kms_destroy, }, .set_irqmask = mdp5_set_irqmask, }; @@ -434,6 +434,21 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms, DBG("MDP5 version v%d.%d", *major, *minor); } +static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, + u32 *major, u32 *minor) +{ + u32 version; + + mdp5_enable(mdp5_kms); + version = mdp5_read(mdp5_kms, REG_MDP5_MDP_HW_VERSION(0)); + mdp5_disable(mdp5_kms); + + *major = FIELD(version, MDP5_MDP_HW_VERSION_MAJOR); + *minor = FIELD(version, MDP5_MDP_HW_VERSION_MINOR); + + DBG("MDP5 version v%d.%d", *major, *minor); +} + static int get_clk(struct platform_device *pdev, struct clk **clkp, const char *name, bool mandatory) { @@ -757,6 +772,170 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) fail: if (kms) - mdp5_destroy(kms); + mdp5_kms_destroy(kms); return ERR_PTR(ret); } + +static void mdp5_destroy(struct platform_device *pdev) +{ + struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); + + if (mdp5_kms->ctlm) + mdp5_ctlm_destroy(mdp5_kms->ctlm); + if (mdp5_kms->smp) + mdp5_smp_destroy(mdp5_kms->smp); + if (mdp5_kms->cfg) + mdp5_cfg_destroy(mdp5_kms->cfg); +} + +static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct mdp5_kms *mdp5_kms; + struct mdp5_cfg *config; + u32 major, minor; + int ret; + + mdp5_kms = devm_kzalloc(&pdev->dev, sizeof(*mdp5_kms), GFP_KERNEL); + if (!mdp5_kms) { + ret = -ENOMEM; + goto fail; + } + + platform_set_drvdata(pdev, mdp5_kms); + + spin_lock_init(&mdp5_kms->resource_lock); + + mdp5_kms->dev = dev; + mdp5_kms->pdev = pdev; + + mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); + if (IS_ERR(mdp5_kms->mmio)) { + ret = PTR_ERR(mdp5_kms->mmio); + goto fail; + } + + /* mandatory clocks: */ + ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk", true); + if (ret) + goto fail; + ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk", true); + if (ret) + goto fail; + ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk", true); + if (ret) + goto fail; + ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk", true); + if (ret) + goto fail; + + /* optional clocks: */ + get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk", false); + + /* we need to set a default rate before enabling. Set a safe + * rate first, then figure out hw revision, and then set a + * more optimal rate: + */ + clk_set_rate(mdp5_kms->core_clk, 200000000); + + read_mdp_hw_revision(mdp5_kms, &major, &minor); + + mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor); + if (IS_ERR(mdp5_kms->cfg)) { + ret = PTR_ERR(mdp5_kms->cfg); + mdp5_kms->cfg = NULL; + goto fail; + } + + config = mdp5_cfg_get_config(mdp5_kms->cfg); + mdp5_kms->caps = config->hw->mdp.caps; + + /* TODO: compute core clock rate at runtime */ + clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk); + + /* + * Some chipsets have a Shared Memory Pool (SMP), while others + * have dedicated latency buffering per source pipe instead; + * this section initializes the SMP: + */ + if (mdp5_kms->caps & MDP_CAP_SMP) { + mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); + if (IS_ERR(mdp5_kms->smp)) { + ret = PTR_ERR(mdp5_kms->smp); + mdp5_kms->smp = NULL; + goto fail; + } + } + + mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg); + if (IS_ERR(mdp5_kms->ctlm)) { + ret = PTR_ERR(mdp5_kms->ctlm); + mdp5_kms->ctlm = NULL; + goto fail; + } + + /* set uninit-ed kms */ + priv->kms = &mdp5_kms->base.base; + + return 0; +fail: + mdp5_destroy(pdev); + return ret; +} + +static int mdp5_bind(struct device *dev, struct device *master, void *data) +{ + struct drm_device *ddev = dev_get_drvdata(master); + struct platform_device *pdev = to_platform_device(dev); + + DBG(""); + + return mdp5_init(pdev, ddev); +} + +static void mdp5_unbind(struct device *dev, struct device *master, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + + mdp5_destroy(pdev); +} + +static const struct component_ops mdp5_ops = { + .bind = mdp5_bind, + .unbind = mdp5_unbind, +}; + +static int mdp5_dev_probe(struct platform_device *pdev) +{ + DBG(""); + return component_add(&pdev->dev, &mdp5_ops); +} + +static int mdp5_dev_remove(struct platform_device *pdev) +{ + DBG(""); + component_del(&pdev->dev, &mdp5_ops); + return 0; +} + +static struct platform_driver mdp5_driver = { + .probe = mdp5_dev_probe, + .remove = mdp5_dev_remove, + .driver = { + .name = "msm_mdp", + /* Add a DT match field once we move to new hierarchy */ + }, +}; + +void __init msm_mdp_register(void) +{ + DBG(""); + platform_driver_register(&mdp5_driver); +} + +void __exit msm_mdp_unregister(void) +{ + DBG(""); + platform_driver_unregister(&mdp5_driver); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 9cf5aa4e5ec3..d681c026aad5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -31,6 +31,8 @@ struct mdp5_kms { struct drm_device *dev; + struct platform_device *pdev; + struct mdp5_cfg_handler *cfg; uint32_t caps; /* MDP capabilities (MDP_CAP_XXX bits) */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 092926b35baf..570139234210 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -876,6 +876,7 @@ static struct platform_driver msm_platform_driver = { static int __init msm_drm_register(void) { DBG("init"); + msm_mdp_register(); msm_dsi_register(); msm_edp_register(); msm_hdmi_register(); @@ -891,6 +892,7 @@ static void __exit msm_drm_unregister(void) adreno_unregister(); msm_edp_unregister(); msm_dsi_unregister(); + msm_mdp_unregister(); } module_init(msm_drm_register); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index a7acd839282e..be01e3895178 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -261,6 +261,9 @@ static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, } #endif +void __init msm_mdp_register(void); +void __exit msm_mdp_unregister(void); + #ifdef CONFIG_DEBUG_FS void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m); void msm_gem_describe_objects(struct list_head *list, struct seq_file *m); From aec095ecbcc70653a014ccb8c57abc094089e9fa Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 14 Jun 2016 18:23:52 +0530 Subject: [PATCH 18/52] drm/msm/mdp5: Prepare new kms_init funcs With MDP5 as a new device, we need to do less for MDP when initializing modeset after all the components are bound. Create mdp5_kms_init2/destroy2 funcs that inits modeset. These will eventually replace the older kms_init/destroy funcs. In the new kms_init2, the platform_device used is the one corresponding to the new MDP5 platform_device. The new change here is that the irq is now retrieved using irq_of_parse_and_map(), since MDP5 is a child interrupt of the MDSS interrupt controller. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 115 ++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_kms.h | 1 + 2 files changed, 116 insertions(+) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index fcb1bf450883..9f69924ec326 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -16,6 +16,7 @@ * this program. If not, see . */ +#include #include "msm_drv.h" #include "msm_mmu.h" @@ -133,6 +134,17 @@ static void mdp5_kms_destroy(struct msm_kms *kms) kfree(mdp5_kms); } +static void mdp5_kms_destroy2(struct msm_kms *kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + struct msm_mmu *mmu = mdp5_kms->mmu; + + if (mmu) { + mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); + mmu->funcs->destroy(mmu); + } +} + static const struct mdp_kms_funcs kms_funcs = { .base = { .hw_init = mdp5_hw_init, @@ -776,6 +788,109 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) return ERR_PTR(ret); } +struct msm_kms *mdp5_kms_init2(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev; + struct mdp5_kms *mdp5_kms; + struct mdp5_cfg *config; + struct msm_kms *kms; + struct msm_mmu *mmu; + int irq, i, ret; + + /* priv->kms would have been populated by the MDP5 driver */ + kms = priv->kms; + if (!kms) + return NULL; + + mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + + mdp_kms_init(&mdp5_kms->base, &kms_funcs); + + pdev = mdp5_kms->pdev; + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (irq < 0) { + ret = irq; + dev_err(&pdev->dev, "failed to get irq: %d\n", ret); + goto fail; + } + + kms->irq = irq; + + config = mdp5_cfg_get_config(mdp5_kms->cfg); + + /* 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): + */ + mdp5_enable(mdp5_kms); + for (i = 0; i < MDP5_INTF_NUM_MAX; i++) { + if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) || + !config->hw->intf.base[i]) + continue; + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0); + + mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3); + } + mdp5_disable(mdp5_kms); + mdelay(16); + + if (config->platform.iommu) { + mmu = msm_iommu_new(&pdev->dev, config->platform.iommu); + if (IS_ERR(mmu)) { + ret = PTR_ERR(mmu); + dev_err(&pdev->dev, "failed to init iommu: %d\n", ret); + iommu_domain_free(config->platform.iommu); + goto fail; + } + + ret = mmu->funcs->attach(mmu, iommu_ports, + ARRAY_SIZE(iommu_ports)); + if (ret) { + dev_err(&pdev->dev, "failed to attach iommu: %d\n", + ret); + mmu->funcs->destroy(mmu); + goto fail; + } + } else { + dev_info(&pdev->dev, + "no iommu, fallback to phys contig buffers for scanout\n"); + mmu = NULL; + } + mdp5_kms->mmu = mmu; + + mdp5_kms->id = msm_register_mmu(dev, mmu); + if (mdp5_kms->id < 0) { + ret = mdp5_kms->id; + dev_err(&pdev->dev, "failed to register mdp5 iommu: %d\n", ret); + goto fail; + } + + ret = modeset_init(mdp5_kms); + if (ret) { + dev_err(&pdev->dev, "modeset_init failed: %d\n", ret); + goto fail; + } + + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + dev->mode_config.max_width = config->hw->lm.max_width; + dev->mode_config.max_height = config->hw->lm.max_height; + + dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp; + dev->driver->get_scanout_position = mdp5_get_scanoutpos; + dev->driver->get_vblank_counter = mdp5_get_vblank_counter; + dev->max_vblank_count = 0xffffffff; + dev->vblank_disable_immediate = true; + + return kms; +fail: + if (kms) + mdp5_kms_destroy2(kms); + return ERR_PTR(ret); +} + static void mdp5_destroy(struct platform_device *pdev) { struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 40e41e5cdbc6..13f893d1a518 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -73,6 +73,7 @@ static inline void msm_kms_init(struct msm_kms *kms, struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); +struct msm_kms *mdp5_kms_init2(struct drm_device *dev); int msm_mdss_init(struct drm_device *dev); void msm_mdss_destroy(struct drm_device *dev); From 0a6030d224d3a446624a06e2858a69974738bd2a Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Sun, 8 May 2016 21:36:28 +0530 Subject: [PATCH 19/52] drm/msm/mdp5: Use the new hierarchy and drop old irq management Call msm_mdss_init in msm_drv to set up top level registers/irq line. Start using the new kms_init2/destroy2 funcs to inititalize MDP5 KMS. With the MDSS interrupt and irqdomain set up, the old MDP5 irq code can be dropped. The mdp5_hw_init kms func now uses the platform device tied to MDP5 instead of the one tied to the drm_device/MDSS. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c | 105 +----------------------- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 17 +--- drivers/gpu/drm/msm/msm_drv.c | 15 +++- 3 files changed, 18 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index 73bc3e312fd4..c6562d191eaf 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -15,7 +15,6 @@ * this program. If not, see . */ -#include #include #include "msm_drv.h" @@ -68,8 +67,9 @@ void mdp5_irq_uninstall(struct msm_kms *kms) mdp5_disable(mdp5_kms); } -static void mdp5_irq_mdp(struct mdp_kms *mdp_kms) +irqreturn_t mdp5_irq(struct msm_kms *kms) { + struct mdp_kms *mdp_kms = to_mdp_kms(kms); struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); struct drm_device *dev = mdp5_kms->dev; struct msm_drm_private *priv = dev->dev_private; @@ -87,29 +87,6 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms) for (id = 0; id < priv->num_crtcs; id++) if (status & mdp5_crtc_vblank(priv->crtcs[id])) drm_handle_vblank(dev, id); -} - -irqreturn_t mdp5_irq(struct msm_kms *kms) -{ - struct mdp_kms *mdp_kms = to_mdp_kms(kms); - struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); - uint32_t intr; - - intr = mdp5_read(mdp5_kms, REG_MDSS_HW_INTR_STATUS); - - VERB("intr=%08x", intr); - - if (intr & MDSS_HW_INTR_STATUS_INTR_MDP) { - mdp5_irq_mdp(mdp_kms); - intr &= ~MDSS_HW_INTR_STATUS_INTR_MDP; - } - - while (intr) { - irq_hw_number_t hwirq = fls(intr) - 1; - generic_handle_irq(irq_find_mapping( - mdp5_kms->irqcontroller.domain, hwirq)); - intr &= ~(1 << hwirq); - } return IRQ_HANDLED; } @@ -135,81 +112,3 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) mdp5_crtc_vblank(crtc), false); mdp5_disable(mdp5_kms); } - -/* - * interrupt-controller implementation, so sub-blocks (hdmi/eDP/dsi/etc) - * can register to get their irq's delivered - */ - -#define VALID_IRQS (MDSS_HW_INTR_STATUS_INTR_DSI0 | \ - MDSS_HW_INTR_STATUS_INTR_DSI1 | \ - MDSS_HW_INTR_STATUS_INTR_HDMI | \ - MDSS_HW_INTR_STATUS_INTR_EDP) - -static void mdp5_hw_mask_irq(struct irq_data *irqd) -{ - struct mdp5_kms *mdp5_kms = irq_data_get_irq_chip_data(irqd); - smp_mb__before_atomic(); - clear_bit(irqd->hwirq, &mdp5_kms->irqcontroller.enabled_mask); - smp_mb__after_atomic(); -} - -static void mdp5_hw_unmask_irq(struct irq_data *irqd) -{ - struct mdp5_kms *mdp5_kms = irq_data_get_irq_chip_data(irqd); - smp_mb__before_atomic(); - set_bit(irqd->hwirq, &mdp5_kms->irqcontroller.enabled_mask); - smp_mb__after_atomic(); -} - -static struct irq_chip mdp5_hw_irq_chip = { - .name = "mdp5", - .irq_mask = mdp5_hw_mask_irq, - .irq_unmask = mdp5_hw_unmask_irq, -}; - -static int mdp5_hw_irqdomain_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hwirq) -{ - struct mdp5_kms *mdp5_kms = d->host_data; - - if (!(VALID_IRQS & (1 << hwirq))) - return -EPERM; - - irq_set_chip_and_handler(irq, &mdp5_hw_irq_chip, handle_level_irq); - irq_set_chip_data(irq, mdp5_kms); - - return 0; -} - -static struct irq_domain_ops mdp5_hw_irqdomain_ops = { - .map = mdp5_hw_irqdomain_map, - .xlate = irq_domain_xlate_onecell, -}; - - -int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms) -{ - struct device *dev = mdp5_kms->dev->dev; - struct irq_domain *d; - - d = irq_domain_add_linear(dev->of_node, 32, - &mdp5_hw_irqdomain_ops, mdp5_kms); - if (!d) { - dev_err(dev, "mdp5 irq domain add failed\n"); - return -ENXIO; - } - - mdp5_kms->irqcontroller.enabled_mask = 0; - mdp5_kms->irqcontroller.domain = d; - - return 0; -} - -void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms) -{ - if (mdp5_kms->irqcontroller.domain) { - irq_domain_remove(mdp5_kms->irqcontroller.domain); - mdp5_kms->irqcontroller.domain = NULL; - } -} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 9f69924ec326..52d756d66016 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -29,10 +29,10 @@ static const char *iommu_ports[] = { static int mdp5_hw_init(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); - struct drm_device *dev = mdp5_kms->dev; + struct platform_device *pdev = mdp5_kms->pdev; unsigned long flags; - pm_runtime_get_sync(dev->dev); + pm_runtime_get_sync(&pdev->dev); /* Magic unknown register writes: * @@ -64,7 +64,7 @@ static int mdp5_hw_init(struct msm_kms *kms) mdp5_ctlm_hw_reset(mdp5_kms->ctlm); - pm_runtime_put_sync(dev->dev); + pm_runtime_put_sync(&pdev->dev); return 0; } @@ -117,8 +117,6 @@ static void mdp5_kms_destroy(struct msm_kms *kms) struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct msm_mmu *mmu = mdp5_kms->mmu; - mdp5_irq_domain_fini(mdp5_kms); - if (mmu) { mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); mmu->funcs->destroy(mmu); @@ -160,7 +158,7 @@ static const struct mdp_kms_funcs kms_funcs = { .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, .set_split_display = mdp5_set_split_display, - .destroy = mdp5_kms_destroy, + .destroy = mdp5_kms_destroy2, }, .set_irqmask = mdp5_set_irqmask, }; @@ -357,13 +355,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); - /* register our interrupt-controller for hdmi/eDP/dsi/etc - * to use for irqs routed through mdp: - */ - ret = mdp5_irq_domain_init(mdp5_kms); - if (ret) - goto fail; - /* construct CRTCs and their private planes: */ for (i = 0; i < hw_cfg->pipe_rgb.count; i++) { struct drm_plane *plane; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 570139234210..517f0ae51335 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -237,6 +237,8 @@ static int msm_drm_uninit(struct device *dev) component_unbind_all(dev, ddev); + msm_mdss_destroy(ddev); + ddev->dev_private = NULL; drm_dev_unref(ddev); @@ -351,6 +353,13 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->dev_private = priv; + ret = msm_mdss_init(ddev); + if (ret) { + kfree(priv); + drm_dev_unref(ddev); + return ret; + } + priv->wq = alloc_ordered_workqueue("msm", 0); priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); init_waitqueue_head(&priv->pending_crtcs_event); @@ -365,6 +374,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) /* Bind all our sub-components: */ ret = component_bind_all(dev, ddev); if (ret) { + msm_mdss_destroy(ddev); kfree(priv); drm_dev_unref(ddev); return ret; @@ -377,9 +387,10 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) switch (get_mdp_ver(pdev)) { case 4: kms = mdp4_kms_init(ddev); + priv->kms = kms; break; case 5: - kms = mdp5_kms_init(ddev); + kms = mdp5_kms_init2(ddev); break; default: kms = ERR_PTR(-ENODEV); @@ -398,8 +409,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) goto fail; } - priv->kms = kms; - if (kms) { pm_runtime_enable(dev); ret = kms->funcs->hw_init(kms); From 392ae6e0efa5e27e977b1cdf88c619c0434a7417 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 14 Jun 2016 18:24:54 +0530 Subject: [PATCH 20/52] drm/msm/mdp5: Remove old kms init/destroy funcs With the new kms_init/destroy funcs in place for MDP5, we can get rid of the old kms funcs. Some members of the mdp5_kms struct also become redundant, so we remove those too. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 228 +----------------------- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 9 +- drivers/gpu/drm/msm/msm_drv.c | 2 +- drivers/gpu/drm/msm/msm_kms.h | 1 - 4 files changed, 4 insertions(+), 236 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 52d756d66016..e2caa877460a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -121,26 +121,6 @@ static void mdp5_kms_destroy(struct msm_kms *kms) mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); mmu->funcs->destroy(mmu); } - - if (mdp5_kms->ctlm) - mdp5_ctlm_destroy(mdp5_kms->ctlm); - if (mdp5_kms->smp) - mdp5_smp_destroy(mdp5_kms->smp); - if (mdp5_kms->cfg) - mdp5_cfg_destroy(mdp5_kms->cfg); - - kfree(mdp5_kms); -} - -static void mdp5_kms_destroy2(struct msm_kms *kms) -{ - struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); - struct msm_mmu *mmu = mdp5_kms->mmu; - - if (mmu) { - mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); - mmu->funcs->destroy(mmu); - } } static const struct mdp_kms_funcs kms_funcs = { @@ -158,7 +138,7 @@ static const struct mdp_kms_funcs kms_funcs = { .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, .set_split_display = mdp5_set_split_display, - .destroy = mdp5_kms_destroy2, + .destroy = mdp5_kms_destroy, }, .set_irqmask = mdp5_set_irqmask, }; @@ -422,21 +402,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) return ret; } -static void read_hw_revision(struct mdp5_kms *mdp5_kms, - uint32_t *major, uint32_t *minor) -{ - uint32_t version; - - mdp5_enable(mdp5_kms); - version = mdp5_read(mdp5_kms, REG_MDSS_HW_VERSION); - mdp5_disable(mdp5_kms); - - *major = FIELD(version, MDSS_HW_VERSION_MAJOR); - *minor = FIELD(version, MDSS_HW_VERSION_MINOR); - - DBG("MDP5 version v%d.%d", *major, *minor); -} - static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, u32 *major, u32 *minor) { @@ -591,195 +556,6 @@ static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe) } struct msm_kms *mdp5_kms_init(struct drm_device *dev) -{ - struct platform_device *pdev = dev->platformdev; - struct mdp5_cfg *config; - struct mdp5_kms *mdp5_kms; - struct msm_kms *kms = NULL; - struct msm_mmu *mmu; - uint32_t major, minor; - int irq, i, ret; - - mdp5_kms = kzalloc(sizeof(*mdp5_kms), GFP_KERNEL); - if (!mdp5_kms) { - dev_err(dev->dev, "failed to allocate kms\n"); - ret = -ENOMEM; - goto fail; - } - - spin_lock_init(&mdp5_kms->resource_lock); - - mdp_kms_init(&mdp5_kms->base, &kms_funcs); - - kms = &mdp5_kms->base.base; - - mdp5_kms->dev = dev; - - /* mdp5_kms->mmio actually represents the MDSS base address */ - mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); - if (IS_ERR(mdp5_kms->mmio)) { - ret = PTR_ERR(mdp5_kms->mmio); - goto fail; - } - - mdp5_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); - if (IS_ERR(mdp5_kms->vbif)) { - ret = PTR_ERR(mdp5_kms->vbif); - goto fail; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(dev->dev, "failed to get irq: %d\n", ret); - goto fail; - } - - kms->irq = irq; - - mdp5_kms->vdd = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(mdp5_kms->vdd)) { - ret = PTR_ERR(mdp5_kms->vdd); - goto fail; - } - - ret = regulator_enable(mdp5_kms->vdd); - if (ret) { - dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret); - goto fail; - } - - /* mandatory clocks: */ - ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk", true); - if (ret) - goto fail; - ret = get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk", true); - if (ret) - goto fail; - ret = get_clk(pdev, &mdp5_kms->core_clk, "core_clk", true); - if (ret) - goto fail; - ret = get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk", true); - if (ret) - goto fail; - - /* optional clocks: */ - get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk", false); - - /* we need to set a default rate before enabling. Set a safe - * rate first, then figure out hw revision, and then set a - * more optimal rate: - */ - clk_set_rate(mdp5_kms->core_clk, 200000000); - - read_hw_revision(mdp5_kms, &major, &minor); - - mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor); - if (IS_ERR(mdp5_kms->cfg)) { - ret = PTR_ERR(mdp5_kms->cfg); - mdp5_kms->cfg = NULL; - goto fail; - } - - config = mdp5_cfg_get_config(mdp5_kms->cfg); - mdp5_kms->caps = config->hw->mdp.caps; - - /* TODO: compute core clock rate at runtime */ - clk_set_rate(mdp5_kms->core_clk, config->hw->max_clk); - - /* - * Some chipsets have a Shared Memory Pool (SMP), while others - * have dedicated latency buffering per source pipe instead; - * this section initializes the SMP: - */ - if (mdp5_kms->caps & MDP_CAP_SMP) { - mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp); - if (IS_ERR(mdp5_kms->smp)) { - ret = PTR_ERR(mdp5_kms->smp); - mdp5_kms->smp = NULL; - goto fail; - } - } - - mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, mdp5_kms->cfg); - if (IS_ERR(mdp5_kms->ctlm)) { - ret = PTR_ERR(mdp5_kms->ctlm); - mdp5_kms->ctlm = NULL; - goto fail; - } - - /* 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): - */ - mdp5_enable(mdp5_kms); - for (i = 0; i < MDP5_INTF_NUM_MAX; i++) { - if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) || - !config->hw->intf.base[i]) - continue; - mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0); - - mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3); - } - mdp5_disable(mdp5_kms); - mdelay(16); - - if (config->platform.iommu) { - 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); - iommu_domain_free(config->platform.iommu); - goto fail; - } - - ret = mmu->funcs->attach(mmu, iommu_ports, - ARRAY_SIZE(iommu_ports)); - if (ret) { - dev_err(dev->dev, "failed to attach iommu: %d\n", ret); - mmu->funcs->destroy(mmu); - goto fail; - } - } else { - dev_info(dev->dev, "no iommu, fallback to phys " - "contig buffers for scanout\n"); - mmu = NULL; - } - mdp5_kms->mmu = mmu; - - mdp5_kms->id = msm_register_mmu(dev, mmu); - if (mdp5_kms->id < 0) { - ret = mdp5_kms->id; - dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret); - goto fail; - } - - ret = modeset_init(mdp5_kms); - if (ret) { - dev_err(dev->dev, "modeset_init failed: %d\n", ret); - goto fail; - } - - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - dev->mode_config.max_width = config->hw->lm.max_width; - dev->mode_config.max_height = config->hw->lm.max_height; - - dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp; - dev->driver->get_scanout_position = mdp5_get_scanoutpos; - dev->driver->get_vblank_counter = mdp5_get_vblank_counter; - dev->max_vblank_count = 0xffffffff; - dev->vblank_disable_immediate = true; - - return kms; - -fail: - if (kms) - mdp5_kms_destroy(kms); - return ERR_PTR(ret); -} - -struct msm_kms *mdp5_kms_init2(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; struct platform_device *pdev; @@ -878,7 +654,7 @@ struct msm_kms *mdp5_kms_init2(struct drm_device *dev) return kms; fail: if (kms) - mdp5_kms_destroy2(kms); + mdp5_kms_destroy(kms); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index d681c026aad5..d6a85fcbb592 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -45,9 +45,7 @@ struct mdp5_kms { struct mdp5_ctl_manager *ctlm; /* io/register spaces: */ - void __iomem *mmio, *vbif; - - struct regulator *vdd; + void __iomem *mmio; struct clk *axi_clk; struct clk *ahb_clk; @@ -62,11 +60,6 @@ struct mdp5_kms { spinlock_t resource_lock; struct mdp_irq error_handler; - - struct { - volatile unsigned long enabled_mask; - struct irq_domain *domain; - } irqcontroller; }; #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 517f0ae51335..d650aaca60f8 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -390,7 +390,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv->kms = kms; break; case 5: - kms = mdp5_kms_init2(ddev); + kms = mdp5_kms_init(ddev); break; default: kms = ERR_PTR(-ENODEV); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 13f893d1a518..40e41e5cdbc6 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -73,7 +73,6 @@ static inline void msm_kms_init(struct msm_kms *kms, struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); -struct msm_kms *mdp5_kms_init2(struct drm_device *dev); int msm_mdss_init(struct drm_device *dev); void msm_mdss_destroy(struct drm_device *dev); From 7b59c7e44940cae1b5506ab9fbe69d7bd202b3ca Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 10 May 2016 11:05:58 +0530 Subject: [PATCH 21/52] drm/msm/mdp5: Use updated MDP5 register names Since MDSS registers were stuffed within the the MDP5 register space, we had an __offset_MDP() macro to identify the offset between the start of MDSS and MDP5 address spaces. This offset macro expected a MDP index argument, which didn't make much sense since we don't have multiple MDPs. The offset is no longer needed now that we have devices for the 2 different register address spaces. Also, remove the "REG_MDP5_MDP_" prefix to "REG_MDP5_". Update the generated headers in mdp5.xml.h We generally update headers as a separate patch, but we need to do these together to prevent breaking build. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h | 201 ++++++++---------- .../gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c | 14 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c | 26 +-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c | 10 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c | 18 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 8 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 2 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c | 22 +- 8 files changed, 142 insertions(+), 159 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h index b275ce11b24b..ca6ca30650a0 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -8,19 +8,11 @@ This file was generated by the rules-ng-ng headergen tool in this git repository git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-02-10 17:07:21) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 37194 bytes, from 2015-09-18 12:07:28) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 41472 bytes, from 2016-01-22 18:18:18) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14) +- /local/mnt/workspace/source_trees/envytools/rnndb/../rnndb/mdp/mdp5.xml ( 36965 bytes, from 2016-05-10 05:06:30) +- /local/mnt/workspace/source_trees/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-05-09 06:32:54) +- /local/mnt/workspace/source_trees/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2016-01-07 08:45:55) -Copyright (C) 2013-2015 by the following authors: +Copyright (C) 2013-2016 by the following authors: - Rob Clark (robclark) - Ilia Mirkin (imirkin) @@ -198,118 +190,109 @@ static inline uint32_t MDSS_HW_VERSION_MAJOR(uint32_t val) #define MDSS_HW_INTR_STATUS_INTR_HDMI 0x00000100 #define MDSS_HW_INTR_STATUS_INTR_EDP 0x00001000 -static inline uint32_t __offset_MDP(uint32_t idx) +#define REG_MDP5_HW_VERSION 0x00000000 +#define MDP5_HW_VERSION_STEP__MASK 0x0000ffff +#define MDP5_HW_VERSION_STEP__SHIFT 0 +static inline uint32_t MDP5_HW_VERSION_STEP(uint32_t val) { - switch (idx) { - case 0: return (mdp5_cfg->mdp.base[0]); - default: return INVALID_IDX(idx); - } + return ((val) << MDP5_HW_VERSION_STEP__SHIFT) & MDP5_HW_VERSION_STEP__MASK; } -static inline uint32_t REG_MDP5_MDP(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); } - -static inline uint32_t REG_MDP5_MDP_HW_VERSION(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); } -#define MDP5_MDP_HW_VERSION_STEP__MASK 0x0000ffff -#define MDP5_MDP_HW_VERSION_STEP__SHIFT 0 -static inline uint32_t MDP5_MDP_HW_VERSION_STEP(uint32_t val) +#define MDP5_HW_VERSION_MINOR__MASK 0x0fff0000 +#define MDP5_HW_VERSION_MINOR__SHIFT 16 +static inline uint32_t MDP5_HW_VERSION_MINOR(uint32_t val) { - return ((val) << MDP5_MDP_HW_VERSION_STEP__SHIFT) & MDP5_MDP_HW_VERSION_STEP__MASK; + return ((val) << MDP5_HW_VERSION_MINOR__SHIFT) & MDP5_HW_VERSION_MINOR__MASK; } -#define MDP5_MDP_HW_VERSION_MINOR__MASK 0x0fff0000 -#define MDP5_MDP_HW_VERSION_MINOR__SHIFT 16 -static inline uint32_t MDP5_MDP_HW_VERSION_MINOR(uint32_t val) +#define MDP5_HW_VERSION_MAJOR__MASK 0xf0000000 +#define MDP5_HW_VERSION_MAJOR__SHIFT 28 +static inline uint32_t MDP5_HW_VERSION_MAJOR(uint32_t val) { - return ((val) << MDP5_MDP_HW_VERSION_MINOR__SHIFT) & MDP5_MDP_HW_VERSION_MINOR__MASK; -} -#define MDP5_MDP_HW_VERSION_MAJOR__MASK 0xf0000000 -#define MDP5_MDP_HW_VERSION_MAJOR__SHIFT 28 -static inline uint32_t MDP5_MDP_HW_VERSION_MAJOR(uint32_t val) -{ - return ((val) << MDP5_MDP_HW_VERSION_MAJOR__SHIFT) & MDP5_MDP_HW_VERSION_MAJOR__MASK; + return ((val) << MDP5_HW_VERSION_MAJOR__SHIFT) & MDP5_HW_VERSION_MAJOR__MASK; } -static inline uint32_t REG_MDP5_MDP_DISP_INTF_SEL(uint32_t i0) { return 0x00000004 + __offset_MDP(i0); } -#define MDP5_MDP_DISP_INTF_SEL_INTF0__MASK 0x000000ff -#define MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT 0 -static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val) +#define REG_MDP5_DISP_INTF_SEL 0x00000004 +#define MDP5_DISP_INTF_SEL_INTF0__MASK 0x000000ff +#define MDP5_DISP_INTF_SEL_INTF0__SHIFT 0 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val) { - return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF0__MASK; + return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK; } -#define MDP5_MDP_DISP_INTF_SEL_INTF1__MASK 0x0000ff00 -#define MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT 8 -static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val) +#define MDP5_DISP_INTF_SEL_INTF1__MASK 0x0000ff00 +#define MDP5_DISP_INTF_SEL_INTF1__SHIFT 8 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val) { - return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF1__MASK; + return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK; } -#define MDP5_MDP_DISP_INTF_SEL_INTF2__MASK 0x00ff0000 -#define MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT 16 -static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val) +#define MDP5_DISP_INTF_SEL_INTF2__MASK 0x00ff0000 +#define MDP5_DISP_INTF_SEL_INTF2__SHIFT 16 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val) { - return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF2__MASK; + return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK; } -#define MDP5_MDP_DISP_INTF_SEL_INTF3__MASK 0xff000000 -#define MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT 24 -static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val) +#define MDP5_DISP_INTF_SEL_INTF3__MASK 0xff000000 +#define MDP5_DISP_INTF_SEL_INTF3__SHIFT 24 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val) { - return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF3__MASK; + return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK; } -static inline uint32_t REG_MDP5_MDP_INTR_EN(uint32_t i0) { return 0x00000010 + __offset_MDP(i0); } +#define REG_MDP5_INTR_EN 0x00000010 -static inline uint32_t REG_MDP5_MDP_INTR_STATUS(uint32_t i0) { return 0x00000014 + __offset_MDP(i0); } +#define REG_MDP5_INTR_STATUS 0x00000014 -static inline uint32_t REG_MDP5_MDP_INTR_CLEAR(uint32_t i0) { return 0x00000018 + __offset_MDP(i0); } +#define REG_MDP5_INTR_CLEAR 0x00000018 -static inline uint32_t REG_MDP5_MDP_HIST_INTR_EN(uint32_t i0) { return 0x0000001c + __offset_MDP(i0); } +#define REG_MDP5_HIST_INTR_EN 0x0000001c -static inline uint32_t REG_MDP5_MDP_HIST_INTR_STATUS(uint32_t i0) { return 0x00000020 + __offset_MDP(i0); } +#define REG_MDP5_HIST_INTR_STATUS 0x00000020 -static inline uint32_t REG_MDP5_MDP_HIST_INTR_CLEAR(uint32_t i0) { return 0x00000024 + __offset_MDP(i0); } +#define REG_MDP5_HIST_INTR_CLEAR 0x00000024 -static inline uint32_t REG_MDP5_MDP_SPARE_0(uint32_t i0) { return 0x00000028 + __offset_MDP(i0); } -#define MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN 0x00000001 +#define REG_MDP5_SPARE_0 0x00000028 +#define MDP5_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN 0x00000001 -static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; } +static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000080 + 0x4*i0; } -static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W_REG(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; } -#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK 0x000000ff -#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT 0 -static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(uint32_t val) +static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000080 + 0x4*i0; } +#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK 0x000000ff +#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT 0 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(uint32_t val) { - return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK; + return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; } -#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK 0x0000ff00 -#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT 8 -static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(uint32_t val) +#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK 0x0000ff00 +#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT 8 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(uint32_t val) { - return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK; + return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; } -#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK 0x00ff0000 -#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT 16 -static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(uint32_t val) +#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK 0x00ff0000 +#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT 16 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(uint32_t val) { - return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK; + return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; } -static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; } +static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000130 + 0x4*i0; } -static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R_REG(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; } -#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK 0x000000ff -#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT 0 -static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0(uint32_t val) +static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000130 + 0x4*i0; } +#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK 0x000000ff +#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT 0 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(uint32_t val) { - return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK; + return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK; } -#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK 0x0000ff00 -#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT 8 -static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1(uint32_t val) +#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK 0x0000ff00 +#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT 8 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(uint32_t val) { - return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK; + return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK; } -#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK 0x00ff0000 -#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT 16 -static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2(uint32_t val) +#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK 0x00ff0000 +#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT 16 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(uint32_t val) { - return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK; + return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK; } static inline uint32_t __offset_IGC(enum mdp5_igc_type idx) @@ -322,35 +305,35 @@ static inline uint32_t __offset_IGC(enum mdp5_igc_type idx) default: return INVALID_IDX(idx); } } -static inline uint32_t REG_MDP5_MDP_IGC(uint32_t i0, enum mdp5_igc_type i1) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1); } +static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); } -static inline uint32_t REG_MDP5_MDP_IGC_LUT(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; } +static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } -static inline uint32_t REG_MDP5_MDP_IGC_LUT_REG(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; } -#define MDP5_MDP_IGC_LUT_REG_VAL__MASK 0x00000fff -#define MDP5_MDP_IGC_LUT_REG_VAL__SHIFT 0 -static inline uint32_t MDP5_MDP_IGC_LUT_REG_VAL(uint32_t val) +static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } +#define MDP5_IGC_LUT_REG_VAL__MASK 0x00000fff +#define MDP5_IGC_LUT_REG_VAL__SHIFT 0 +static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val) { - return ((val) << MDP5_MDP_IGC_LUT_REG_VAL__SHIFT) & MDP5_MDP_IGC_LUT_REG_VAL__MASK; + return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK; } -#define MDP5_MDP_IGC_LUT_REG_INDEX_UPDATE 0x02000000 -#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_0 0x10000000 -#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000 -#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000 +#define MDP5_IGC_LUT_REG_INDEX_UPDATE 0x02000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0 0x10000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000 -static inline uint32_t REG_MDP5_MDP_SPLIT_DPL_EN(uint32_t i0) { return 0x000002f4 + __offset_MDP(i0); } +#define REG_MDP5_SPLIT_DPL_EN 0x000002f4 -static inline uint32_t REG_MDP5_MDP_SPLIT_DPL_UPPER(uint32_t i0) { return 0x000002f8 + __offset_MDP(i0); } -#define MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL 0x00000002 -#define MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN 0x00000004 -#define MDP5_MDP_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX 0x00000010 -#define MDP5_MDP_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX 0x00000100 +#define REG_MDP5_SPLIT_DPL_UPPER 0x000002f8 +#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL 0x00000002 +#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN 0x00000004 +#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX 0x00000010 +#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX 0x00000100 -static inline uint32_t REG_MDP5_MDP_SPLIT_DPL_LOWER(uint32_t i0) { return 0x000003f0 + __offset_MDP(i0); } -#define MDP5_MDP_SPLIT_DPL_LOWER_SMART_PANEL 0x00000002 -#define MDP5_MDP_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN 0x00000004 -#define MDP5_MDP_SPLIT_DPL_LOWER_INTF1_TG_SYNC 0x00000010 -#define MDP5_MDP_SPLIT_DPL_LOWER_INTF2_TG_SYNC 0x00000100 +#define REG_MDP5_SPLIT_DPL_LOWER 0x000003f0 +#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL 0x00000002 +#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN 0x00000004 +#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC 0x00000010 +#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC 0x00000100 static inline uint32_t __offset_CTL(uint32_t idx) { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c index 69094cb28103..c627ab6d0061 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c @@ -272,22 +272,22 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder, * start signal for the slave encoder */ if (intf_num == 1) - data |= MDP5_MDP_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX; + data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX; else if (intf_num == 2) - data |= MDP5_MDP_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX; + data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX; else return -EINVAL; /* Smart Panel, Sync mode */ - data |= MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL; + data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL; /* Make sure clocks are on when connectors calling this function. */ mdp5_enable(mdp5_kms); - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_UPPER(0), data); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data); - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_LOWER(0), - MDP5_MDP_SPLIT_DPL_LOWER_SMART_PANEL); - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_EN(0), 1); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, + MDP5_SPLIT_DPL_LOWER_SMART_PANEL); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); mdp5_disable(mdp5_kms); return 0; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c index 4e81ca4f964a..d021edc3b307 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c @@ -118,31 +118,31 @@ static void set_display_intf(struct mdp5_kms *mdp5_kms, u32 intf_sel; spin_lock_irqsave(&mdp5_kms->resource_lock, flags); - intf_sel = mdp5_read(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0)); + intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL); switch (intf->num) { case 0: - intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF0__MASK; - intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF0(intf->type); + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf->type); break; case 1: - intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF1__MASK; - intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF1(intf->type); + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf->type); break; case 2: - intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF2__MASK; - intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF2(intf->type); + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf->type); break; case 3: - intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF3__MASK; - intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF3(intf->type); + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf->type); break; default: BUG(); break; } - mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), intf_sel); + mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel); spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags); } @@ -557,7 +557,7 @@ int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable) if (!enable) { ctlx->pair = NULL; ctly->pair = NULL; - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0), 0); + mdp5_write(mdp5_kms, REG_MDP5_SPARE_0, 0); return 0; } else if ((ctlx->pair != NULL) || (ctly->pair != NULL)) { dev_err(ctl_mgr->dev->dev, "CTLs already paired\n"); @@ -570,8 +570,8 @@ int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable) ctlx->pair = ctly; ctly->pair = ctlx; - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0), - MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN); + mdp5_write(mdp5_kms, REG_MDP5_SPARE_0, + MDP5_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN); return 0; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c index 1d95f9fd9dc7..fe0c22230883 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c @@ -322,18 +322,18 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder, * to use the master's enable signal for the slave encoder. */ if (intf_num == 1) - data |= MDP5_MDP_SPLIT_DPL_LOWER_INTF2_TG_SYNC; + data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC; else if (intf_num == 2) - data |= MDP5_MDP_SPLIT_DPL_LOWER_INTF1_TG_SYNC; + data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC; else return -EINVAL; /* Make sure clocks are on when connectors calling this function. */ mdp5_enable(mdp5_kms); /* Dumb Panel, Sync mode */ - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_UPPER(0), 0); - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_LOWER(0), data); - mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_EN(0), 1); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data); + mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index c6562d191eaf..1c3c9098a86b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -23,9 +23,9 @@ void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, uint32_t old_irqmask) { - mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_CLEAR(0), - irqmask ^ (irqmask & old_irqmask)); - mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_EN(0), irqmask); + mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_CLEAR, + irqmask ^ (irqmask & old_irqmask)); + mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask); } static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) @@ -37,8 +37,8 @@ void mdp5_irq_preinstall(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); mdp5_enable(mdp5_kms); - mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), 0xffffffff); - mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000); + mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff); + mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); mdp5_disable(mdp5_kms); } @@ -63,7 +63,7 @@ void mdp5_irq_uninstall(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); mdp5_enable(mdp5_kms); - mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000); + mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); mdp5_disable(mdp5_kms); } @@ -76,9 +76,9 @@ irqreturn_t mdp5_irq(struct msm_kms *kms) unsigned int id; uint32_t status, enable; - enable = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_EN(0)); - status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0)) & enable; - mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status); + enable = mdp5_read(mdp5_kms, REG_MDP5_INTR_EN); + status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS) & enable; + mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status); VERB("status=%08x", status); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index e2caa877460a..a0b974772cf6 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -59,7 +59,7 @@ static int mdp5_hw_init(struct msm_kms *kms) */ spin_lock_irqsave(&mdp5_kms->resource_lock, flags); - mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), 0); + mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0); spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags); mdp5_ctlm_hw_reset(mdp5_kms->ctlm); @@ -408,11 +408,11 @@ static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, u32 version; mdp5_enable(mdp5_kms); - version = mdp5_read(mdp5_kms, REG_MDP5_MDP_HW_VERSION(0)); + version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION); mdp5_disable(mdp5_kms); - *major = FIELD(version, MDP5_MDP_HW_VERSION_MAJOR); - *minor = FIELD(version, MDP5_MDP_HW_VERSION_MINOR); + *major = FIELD(version, MDP5_HW_VERSION_MAJOR); + *minor = FIELD(version, MDP5_HW_VERSION_MINOR); DBG("MDP5 version v%d.%d", *major, *minor); } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index d6a85fcbb592..d214d50bbd46 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -55,7 +55,7 @@ struct mdp5_kms { /* * lock to protect access to global resources: ie., following register: - * - REG_MDP5_MDP_DISP_INTF_SEL + * - REG_MDP5_DISP_INTF_SEL */ spinlock_t resource_lock; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c index 6f425c25d9fe..27d7b55b52c9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c @@ -42,7 +42,7 @@ * * configured: * The block is allocated to some client, and assigned to that - * client in MDP5_MDP_SMP_ALLOC registers. + * client in MDP5_SMP_ALLOC registers. * * inuse: * The block is being actively used by a client. @@ -59,7 +59,7 @@ * mdp5_smp_commit. * * 2) mdp5_smp_configure(): - * As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers + * As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers * are configured for the union(pending, inuse) * Current pending is copied to configured. * It is assumed that mdp5_smp_request and mdp5_smp_configure not run @@ -311,25 +311,25 @@ static void update_smp_state(struct mdp5_smp *smp, int idx = blk / 3; int fld = blk % 3; - val = mdp5_read(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx)); + val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx)); switch (fld) { case 0: - val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK; - val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(cid); + val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; + val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid); break; case 1: - val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK; - val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(cid); + val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; + val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid); break; case 2: - val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK; - val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(cid); + val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; + val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid); break; } - mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx), val); - mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_R_REG(0, idx), val); + mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val); + mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val); } } From 031d63dd9d06b7f70b060e461b18ccdd2e7e80bc Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 9 May 2016 12:14:49 +0530 Subject: [PATCH 22/52] drm/msm/mdp5: Update the register offsets of MDP5 sub-blocks The MDP5 sub-block register offsets are relative to the top level MDSS register address. Now that we have the start of MDP5 register address space, provide the offsets relative to that. This involves subtracting the offsets with 0x1000 or 0x100 depending on the MDP5 version. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 113 +++++++++++------------- 1 file changed, 54 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index 57f73f0c120d..ac9e4cde1380 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c @@ -26,7 +26,6 @@ const struct mdp5_cfg_hw msm8x74v1_config = { .name = "msm8x74v1", .mdp = { .count = 1, - .base = { 0x00100 }, .caps = MDP_CAP_SMP | 0, }, @@ -41,12 +40,12 @@ const struct mdp5_cfg_hw msm8x74v1_config = { }, .ctl = { .count = 5, - .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, + .base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 }, .flush_hw_mask = 0x0003ffff, }, .pipe_vig = { .count = 3, - .base = { 0x01200, 0x01600, 0x01a00 }, + .base = { 0x01100, 0x01500, 0x01900 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | @@ -55,7 +54,7 @@ const struct mdp5_cfg_hw msm8x74v1_config = { }, .pipe_rgb = { .count = 3, - .base = { 0x01e00, 0x02200, 0x02600 }, + .base = { 0x01d00, 0x02100, 0x02500 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | @@ -63,26 +62,26 @@ const struct mdp5_cfg_hw msm8x74v1_config = { }, .pipe_dma = { .count = 2, - .base = { 0x02a00, 0x02e00 }, + .base = { 0x02900, 0x02d00 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | 0, }, .lm = { .count = 5, - .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 }, + .base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 }, .nb_stages = 5, }, .dspp = { .count = 3, - .base = { 0x04600, 0x04a00, 0x04e00 }, + .base = { 0x04500, 0x04900, 0x04d00 }, }, .pp = { .count = 3, - .base = { 0x21b00, 0x21c00, 0x21d00 }, + .base = { 0x21a00, 0x21b00, 0x21c00 }, }, .intf = { - .base = { 0x21100, 0x21300, 0x21500, 0x21700 }, + .base = { 0x21000, 0x21200, 0x21400, 0x21600 }, .connect = { [0] = INTF_eDP, [1] = INTF_DSI, @@ -97,7 +96,6 @@ const struct mdp5_cfg_hw msm8x74v2_config = { .name = "msm8x74", .mdp = { .count = 1, - .base = { 0x00100 }, .caps = MDP_CAP_SMP | 0, }, @@ -112,48 +110,48 @@ const struct mdp5_cfg_hw msm8x74v2_config = { }, .ctl = { .count = 5, - .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, + .base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 }, .flush_hw_mask = 0x0003ffff, }, .pipe_vig = { .count = 3, - .base = { 0x01200, 0x01600, 0x01a00 }, + .base = { 0x01100, 0x01500, 0x01900 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | MDP_PIPE_CAP_DECIMATION, }, .pipe_rgb = { .count = 3, - .base = { 0x01e00, 0x02200, 0x02600 }, + .base = { 0x01d00, 0x02100, 0x02500 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, }, .pipe_dma = { .count = 2, - .base = { 0x02a00, 0x02e00 }, + .base = { 0x02900, 0x02d00 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, }, .lm = { .count = 5, - .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 }, + .base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 }, .nb_stages = 5, .max_width = 2048, .max_height = 0xFFFF, }, .dspp = { .count = 3, - .base = { 0x04600, 0x04a00, 0x04e00 }, + .base = { 0x04500, 0x04900, 0x04d00 }, }, .ad = { .count = 2, - .base = { 0x13100, 0x13300 }, + .base = { 0x13000, 0x13200 }, }, .pp = { .count = 3, - .base = { 0x12d00, 0x12e00, 0x12f00 }, + .base = { 0x12c00, 0x12d00, 0x12e00 }, }, .intf = { - .base = { 0x12500, 0x12700, 0x12900, 0x12b00 }, + .base = { 0x12400, 0x12600, 0x12800, 0x12a00 }, .connect = { [0] = INTF_eDP, [1] = INTF_DSI, @@ -168,7 +166,6 @@ const struct mdp5_cfg_hw apq8084_config = { .name = "apq8084", .mdp = { .count = 1, - .base = { 0x00100 }, .caps = MDP_CAP_SMP | 0, }, @@ -190,49 +187,49 @@ const struct mdp5_cfg_hw apq8084_config = { }, .ctl = { .count = 5, - .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, + .base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 }, .flush_hw_mask = 0x003fffff, }, .pipe_vig = { .count = 4, - .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 }, + .base = { 0x01100, 0x01500, 0x01900, 0x01d00 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | MDP_PIPE_CAP_DECIMATION, }, .pipe_rgb = { .count = 4, - .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 }, + .base = { 0x02100, 0x02500, 0x02900, 0x02d00 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, }, .pipe_dma = { .count = 2, - .base = { 0x03200, 0x03600 }, + .base = { 0x03100, 0x03500 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, }, .lm = { .count = 6, - .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 }, + .base = { 0x03900, 0x03d00, 0x04100, 0x04500, 0x04900, 0x04d00 }, .nb_stages = 5, .max_width = 2048, .max_height = 0xFFFF, }, .dspp = { .count = 4, - .base = { 0x05200, 0x05600, 0x05a00, 0x05e00 }, + .base = { 0x05100, 0x05500, 0x05900, 0x05d00 }, }, .ad = { .count = 3, - .base = { 0x13500, 0x13700, 0x13900 }, + .base = { 0x13400, 0x13600, 0x13800 }, }, .pp = { .count = 4, - .base = { 0x12f00, 0x13000, 0x13100, 0x13200 }, + .base = { 0x12e00, 0x12f00, 0x13000, 0x13100 }, }, .intf = { - .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 }, + .base = { 0x12400, 0x12600, 0x12800, 0x12a00, 0x12c00 }, .connect = { [0] = INTF_eDP, [1] = INTF_DSI, @@ -247,7 +244,7 @@ const struct mdp5_cfg_hw msm8x16_config = { .name = "msm8x16", .mdp = { .count = 1, - .base = { 0x01000 }, + .base = { 0x0 }, .caps = MDP_CAP_SMP | 0, }, @@ -261,41 +258,41 @@ const struct mdp5_cfg_hw msm8x16_config = { }, .ctl = { .count = 5, - .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, + .base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 }, .flush_hw_mask = 0x4003ffff, }, .pipe_vig = { .count = 1, - .base = { 0x05000 }, + .base = { 0x04000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | MDP_PIPE_CAP_DECIMATION, }, .pipe_rgb = { .count = 2, - .base = { 0x15000, 0x17000 }, + .base = { 0x14000, 0x16000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, }, .pipe_dma = { .count = 1, - .base = { 0x25000 }, + .base = { 0x24000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, }, .lm = { .count = 2, /* LM0 and LM3 */ - .base = { 0x45000, 0x48000 }, + .base = { 0x44000, 0x47000 }, .nb_stages = 5, .max_width = 2048, .max_height = 0xFFFF, }, .dspp = { .count = 1, - .base = { 0x55000 }, + .base = { 0x54000 }, }, .intf = { - .base = { 0x00000, 0x6b800 }, + .base = { 0x00000, 0x6a800 }, .connect = { [0] = INTF_DISABLED, [1] = INTF_DSI, @@ -308,7 +305,6 @@ const struct mdp5_cfg_hw msm8x94_config = { .name = "msm8x94", .mdp = { .count = 1, - .base = { 0x01000 }, .caps = MDP_CAP_SMP | 0, }, @@ -330,49 +326,49 @@ const struct mdp5_cfg_hw msm8x94_config = { }, .ctl = { .count = 5, - .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 }, + .base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 }, .flush_hw_mask = 0xf0ffffff, }, .pipe_vig = { .count = 4, - .base = { 0x05000, 0x07000, 0x09000, 0x0b000 }, + .base = { 0x04000, 0x06000, 0x08000, 0x0a000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC | MDP_PIPE_CAP_DECIMATION, }, .pipe_rgb = { .count = 4, - .base = { 0x15000, 0x17000, 0x19000, 0x1b000 }, + .base = { 0x14000, 0x16000, 0x18000, 0x1a000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION, }, .pipe_dma = { .count = 2, - .base = { 0x25000, 0x27000 }, + .base = { 0x24000, 0x26000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP, }, .lm = { .count = 6, - .base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 }, + .base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 }, .nb_stages = 8, .max_width = 2048, .max_height = 0xFFFF, }, .dspp = { .count = 4, - .base = { 0x55000, 0x57000, 0x59000, 0x5b000 }, + .base = { 0x54000, 0x56000, 0x58000, 0x5a000 }, }, .ad = { .count = 3, - .base = { 0x79000, 0x79800, 0x7a000 }, + .base = { 0x78000, 0x78800, 0x79000 }, }, .pp = { .count = 4, - .base = { 0x71000, 0x71800, 0x72000, 0x72800 }, + .base = { 0x70000, 0x70800, 0x71000, 0x71800 }, }, .intf = { - .base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 }, + .base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 }, .connect = { [0] = INTF_DISABLED, [1] = INTF_DSI, @@ -387,19 +383,18 @@ 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 }, + .base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 }, .flush_hw_mask = 0xf4ffffff, }, .pipe_vig = { .count = 4, - .base = { 0x05000, 0x07000, 0x09000, 0x0b000 }, + .base = { 0x04000, 0x06000, 0x08000, 0x0a000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | @@ -410,7 +405,7 @@ const struct mdp5_cfg_hw msm8x96_config = { }, .pipe_rgb = { .count = 4, - .base = { 0x15000, 0x17000, 0x19000, 0x1b000 }, + .base = { 0x14000, 0x16000, 0x18000, 0x1a000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SCALE | @@ -420,7 +415,7 @@ const struct mdp5_cfg_hw msm8x96_config = { }, .pipe_dma = { .count = 2, - .base = { 0x25000, 0x27000 }, + .base = { 0x24000, 0x26000 }, .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP | MDP_PIPE_CAP_SW_PIX_EXT | @@ -428,33 +423,33 @@ const struct mdp5_cfg_hw msm8x96_config = { }, .lm = { .count = 6, - .base = { 0x45000, 0x46000, 0x47000, 0x48000, 0x49000, 0x4a000 }, + .base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 }, .nb_stages = 8, .max_width = 2560, .max_height = 0xFFFF, }, .dspp = { .count = 2, - .base = { 0x55000, 0x57000 }, + .base = { 0x54000, 0x56000 }, }, .ad = { .count = 3, - .base = { 0x79000, 0x79800, 0x7a000 }, + .base = { 0x78000, 0x78800, 0x79000 }, }, .pp = { .count = 4, - .base = { 0x71000, 0x71800, 0x72000, 0x72800 }, + .base = { 0x70000, 0x70800, 0x71000, 0x71800 }, }, .cdm = { .count = 1, - .base = { 0x7a200 }, + .base = { 0x79200 }, }, .dsc = { .count = 2, - .base = { 0x81000, 0x81400 }, + .base = { 0x80000, 0x80400 }, }, .intf = { - .base = { 0x6b000, 0x6b800, 0x6c000, 0x6c800, 0x6d000 }, + .base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 }, .connect = { [0] = INTF_DISABLED, [1] = INTF_DSI, From cd79272696ef21fb03d8b140c4530ac6b049e417 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 15 Jun 2016 18:04:31 +0530 Subject: [PATCH 23/52] drm/msm: Call pm_runtime_enable/disable for newly created devices With the new device hierarchy for MDP5, we need to enable runtime PM for both the toplevel MDSS device and the MDP5 device itself. Enable runtime PM for the new devices. Since MDP4 and MDP5 now have different places where runtime PM is enabled, remove the previous pm_runtime_enable/disable calls, and squash them in the respective kms drivers. The new device hierarchy (as expressed in the DT bindings) has the GDSC tied only to the MDSS wrapper device. This GDSC needs to be enabled for accessing any register in the MDSS sub-blocks. Once every driver is runtime adapted, the GDSC will be enabled when any sub-block device calls runtime_get because of the parent-child relationship with MDSS. Until then, we call pm_runtime_get_sync() once for the MDSS device to ensure the GDSC is never disabled. This will be removed once all the drivers are runtime PM adapted. The error handling paths become a bit tricky when we call these runtime PM funcs. There doesn't seem to be any helper that checks if runtime PM is enabled already. Add bool variables in mdp4_kms/mdp5_kms structs to check if the driver had managed to call pm_runtime_enable before bailing out. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 8 ++++++++ drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h | 2 ++ drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 6 ++++++ drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 2 ++ drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c | 12 ++++++++++++ drivers/gpu/drm/msm/msm_drv.c | 5 +---- 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index b6920917c4a9..ba8df15605d7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -158,6 +158,7 @@ static const char * const iommu_ports[] = { static void mdp4_destroy(struct msm_kms *kms) { struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + struct device *dev = mdp4_kms->dev->dev; struct msm_mmu *mmu = mdp4_kms->mmu; if (mmu) { @@ -169,6 +170,10 @@ static void mdp4_destroy(struct msm_kms *kms) msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id); if (mdp4_kms->blank_cursor_bo) drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); + + if (mdp4_kms->rpm_enabled) + pm_runtime_disable(dev); + kfree(mdp4_kms); } @@ -511,6 +516,9 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) clk_set_rate(mdp4_kms->clk, config->max_clk); clk_set_rate(mdp4_kms->lut_clk, config->max_clk); + pm_runtime_enable(dev->dev); + mdp4_kms->rpm_enabled = true; + /* 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): diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index c5d045d5680d..25fb83997119 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -47,6 +47,8 @@ struct mdp4_kms { struct mdp_irq error_handler; + bool rpm_enabled; + /* empty/blank cursor bo to use when cursor is "disabled" */ struct drm_gem_object *blank_cursor_bo; uint32_t blank_cursor_iova; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index a0b974772cf6..5d6d9e146aaa 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -668,6 +668,9 @@ static void mdp5_destroy(struct platform_device *pdev) mdp5_smp_destroy(mdp5_kms->smp); if (mdp5_kms->cfg) mdp5_cfg_destroy(mdp5_kms->cfg); + + if (mdp5_kms->rpm_enabled) + pm_runtime_disable(&pdev->dev); } static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) @@ -720,6 +723,9 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) */ clk_set_rate(mdp5_kms->core_clk, 200000000); + pm_runtime_enable(&pdev->dev); + mdp5_kms->rpm_enabled = true; + read_mdp_hw_revision(mdp5_kms, &major, &minor); mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index d214d50bbd46..03738927be10 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -59,6 +59,8 @@ struct mdp5_kms { */ spinlock_t resource_lock; + bool rpm_enabled; + struct mdp_irq error_handler; }; #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c index 871c4424a820..d444a6901fff 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c @@ -152,6 +152,10 @@ void msm_mdss_destroy(struct drm_device *dev) mdss->irqcontroller.domain = NULL; regulator_disable(mdss->vdd); + + pm_runtime_put_sync(dev->dev); + + pm_runtime_disable(dev->dev); } int msm_mdss_init(struct drm_device *dev) @@ -215,6 +219,14 @@ int msm_mdss_init(struct drm_device *dev) priv->mdss = mdss; + pm_runtime_enable(dev->dev); + + /* + * TODO: This is needed as the MDSS GDSC is only tied to MDSS's power + * domain. Remove this once runtime PM is adapted for all the devices. + */ + pm_runtime_get_sync(dev->dev); + return 0; fail_irq: regulator_disable(mdss->vdd); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d650aaca60f8..1c1869011092 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -215,10 +215,8 @@ static int msm_drm_uninit(struct device *dev) flush_workqueue(priv->atomic_wq); destroy_workqueue(priv->atomic_wq); - if (kms) { - pm_runtime_disable(dev); + if (kms) kms->funcs->destroy(kms); - } if (gpu) { mutex_lock(&ddev->struct_mutex); @@ -410,7 +408,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) } if (kms) { - pm_runtime_enable(dev); ret = kms->funcs->hw_init(kms); if (ret) { dev_err(dev, "kms hw init failed: %d\n", ret); From 7c8f023565f56ccb11167e5aac6466b211977dcb Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 15 Jun 2016 15:48:15 +0530 Subject: [PATCH 24/52] drm/msm/mdp5: Add missing mdp5_enable/disable calls Since runtime PM isn't implemented yet, we need to call mdp5_enable/disable in a few more places. These would later be replaced by runtime PM get/put calls. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c | 2 ++ drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index 1c3c9098a86b..d53e5510fd7c 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -54,7 +54,9 @@ int mdp5_irq_postinstall(struct msm_kms *kms) MDP5_IRQ_INTF2_UNDER_RUN | MDP5_IRQ_INTF3_UNDER_RUN; + mdp5_enable(mdp5_kms); mdp_irq_register(mdp_kms, error_handler); + mdp5_disable(mdp5_kms); return 0; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 5d6d9e146aaa..174d7e7969fd 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -33,6 +33,7 @@ static int mdp5_hw_init(struct msm_kms *kms) unsigned long flags; pm_runtime_get_sync(&pdev->dev); + mdp5_enable(mdp5_kms); /* Magic unknown register writes: * @@ -64,6 +65,7 @@ static int mdp5_hw_init(struct msm_kms *kms) mdp5_ctlm_hw_reset(mdp5_kms->ctlm); + mdp5_disable(mdp5_kms); pm_runtime_put_sync(&pdev->dev); return 0; From 7d526fcf205ad011c6e5bce819b2b8a1698f7152 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 19 May 2016 10:33:57 +0530 Subject: [PATCH 25/52] drm/msm: Create separate funcs for adding display/gpu components Simplifies some of the code that we'll add later. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 1c1869011092..132c81333491 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -823,6 +823,18 @@ static int add_components(struct device *dev, struct component_match **matchptr, return 0; } +static int add_display_components(struct device *dev, + struct component_match **matchptr) +{ + return add_components(dev, matchptr, "connectors"); +} + +static int add_gpu_components(struct device *dev, + struct component_match **matchptr) +{ + return add_components(dev, matchptr, "gpus"); +} + static int msm_drm_bind(struct device *dev) { return msm_drm_init(dev, &msm_driver); @@ -845,9 +857,15 @@ static const struct component_master_ops msm_drm_ops = { static int msm_pdev_probe(struct platform_device *pdev) { struct component_match *match = NULL; + int ret; - add_components(&pdev->dev, &match, "connectors"); - add_components(&pdev->dev, &match, "gpus"); + ret = add_display_components(&pdev->dev, &match); + if (ret) + return ret; + + ret = add_gpu_components(&pdev->dev, &match); + if (ret) + return ret; pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match); From 812070eb090350af69848f462fe5266e25c5df6e Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 19 May 2016 10:38:39 +0530 Subject: [PATCH 26/52] drm/msm: Add display components by parsing MDP ports The kms driver currently identifies all the mdss components it needs by parsing a phandle list from the 'connectors' DT property. Instead of this, describe a list of ports that the MDP hardware provides to the external world. These ports are linked to external encoder interfaces such as DSI, HDMI. These are also the subcomponent devices that we need add. This description of ports complies with the generic graph bindings. The LVDS port is a special case since it is a part of MDP4 itself, and its output connects directly to the LVDS panel. In this case, we don't try to add it as a component. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 56 ++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 132c81333491..73510d0cc60a 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -823,10 +823,64 @@ static int add_components(struct device *dev, struct component_match **matchptr, return 0; } +/* + * Identify what components need to be added by parsing what remote-endpoints + * our MDP output ports are connected to. In the case of LVDS on MDP4, there + * is no external component that we need to add since LVDS is within MDP4 + * itself. + */ +static int add_components_mdp(struct device *mdp_dev, + struct component_match **matchptr) +{ + struct device_node *np = mdp_dev->of_node; + struct device_node *ep_node; + + for_each_endpoint_of_node(np, ep_node) { + struct device_node *intf; + struct of_endpoint ep; + int ret; + + ret = of_graph_parse_endpoint(ep_node, &ep); + if (ret) { + dev_err(mdp_dev, "unable to parse port endpoint\n"); + of_node_put(ep_node); + return ret; + } + + /* + * The LCDC/LVDS port on MDP4 is a speacial case where the + * remote-endpoint isn't a component that we need to add + */ + if (of_device_is_compatible(np, "qcom,mdp4") && + ep.port == 0) { + of_node_put(ep_node); + continue; + } + + /* + * It's okay if some of the ports don't have a remote endpoint + * specified. It just means that the port isn't connected to + * any external interface. + */ + intf = of_graph_get_remote_port_parent(ep_node); + if (!intf) { + of_node_put(ep_node); + continue; + } + + component_match_add(mdp_dev, matchptr, compare_of, intf); + + of_node_put(intf); + of_node_put(ep_node); + } + + return 0; +} + static int add_display_components(struct device *dev, struct component_match **matchptr) { - return add_components(dev, matchptr, "connectors"); + return add_components_mdp(dev, matchptr); } static int add_gpu_components(struct device *dev, From 54011e266499ec80104136bcecec5e8c7e21340c Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 6 Jun 2016 13:45:34 +0530 Subject: [PATCH 27/52] drm/msm: Add components for MDP5 For MDP5 based platforms, the master device isn't the MDP5 platform device, but the top level MDSS device, which is a parent to MDP5 and interface (DSI, HDMI, eDP etc) devices. In order to add components on MDP5 platforms, we first need to populate the MDSS children, locate the MDP5 child, and then parse its ports to get the display interfaces. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 61 +++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 73510d0cc60a..7333efd1eae8 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -834,6 +834,20 @@ static int add_components_mdp(struct device *mdp_dev, { struct device_node *np = mdp_dev->of_node; struct device_node *ep_node; + struct device *master_dev; + + /* + * on MDP4 based platforms, the MDP platform device is the component + * master that adds other display interface components to itself. + * + * on MDP5 based platforms, the MDSS platform device is the component + * master that adds MDP5 and other display interface components to + * itself. + */ + if (of_device_is_compatible(np, "qcom,mdp4")) + master_dev = mdp_dev; + else + master_dev = mdp_dev->parent; for_each_endpoint_of_node(np, ep_node) { struct device_node *intf; @@ -868,7 +882,7 @@ static int add_components_mdp(struct device *mdp_dev, continue; } - component_match_add(mdp_dev, matchptr, compare_of, intf); + component_match_add(master_dev, matchptr, compare_of, intf); of_node_put(intf); of_node_put(ep_node); @@ -877,10 +891,52 @@ static int add_components_mdp(struct device *mdp_dev, return 0; } +static int compare_name_mdp(struct device *dev, void *data) +{ + return (strstr(dev_name(dev), "mdp") != NULL); +} + static int add_display_components(struct device *dev, struct component_match **matchptr) { - return add_components_mdp(dev, matchptr); + struct device *mdp_dev; + int ret; + + /* + * MDP5 based devices don't have a flat hierarchy. There is a top level + * parent: MDSS, and children: MDP5, DSI, HDMI, eDP etc. Populate the + * children devices, find the MDP5 node, and then add the interfaces + * to our components list. + */ + if (of_device_is_compatible(dev->of_node, "qcom,mdss")) { + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) { + dev_err(dev, "failed to populate children devices\n"); + return ret; + } + + mdp_dev = device_find_child(dev, NULL, compare_name_mdp); + if (!mdp_dev) { + dev_err(dev, "failed to find MDSS MDP node\n"); + of_platform_depopulate(dev); + return -ENODEV; + } + + put_device(mdp_dev); + + /* add the MDP component itself */ + component_match_add(dev, matchptr, compare_of, + mdp_dev->of_node); + } else { + /* MDP4 */ + mdp_dev = dev; + } + + ret = add_components_mdp(mdp_dev, matchptr); + if (ret) + of_platform_depopulate(dev); + + return ret; } static int add_gpu_components(struct device *dev, @@ -928,6 +984,7 @@ static int msm_pdev_probe(struct platform_device *pdev) static int msm_pdev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &msm_drm_ops); + of_platform_depopulate(&pdev->dev); return 0; } From dc3ea265b856c11ab7f6a9c7e504f16d545f53a2 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 19 May 2016 13:33:52 +0530 Subject: [PATCH 28/52] drm/msm: Drop the gpu binding The driver currently identifies the GPU components it needs by parsing a phandle list from the 'gpus' DT property. This isn't the right binding to go with. So, for now, just search all device nodes and find the gpu node we need by parsing a list of compatible strings. Once we know how to link the kms and gpu drivers, we'll drop this method and use the correct binding. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 42 ++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 7333efd1eae8..66371f23cc22 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -804,25 +804,6 @@ static int compare_of(struct device *dev, void *data) return dev->of_node == data; } -static int add_components(struct device *dev, struct component_match **matchptr, - const char *name) -{ - struct device_node *np = dev->of_node; - unsigned i; - - for (i = 0; ; i++) { - struct device_node *node; - - node = of_parse_phandle(np, name, i); - if (!node) - break; - - component_match_add(dev, matchptr, compare_of, node); - } - - return 0; -} - /* * Identify what components need to be added by parsing what remote-endpoints * our MDP output ports are connected to. In the case of LVDS on MDP4, there @@ -939,10 +920,31 @@ static int add_display_components(struct device *dev, return ret; } +/* + * We don't know what's the best binding to link the gpu with the drm device. + * Fow now, we just hunt for all the possible gpus that we support, and add them + * as components. + */ +static const struct of_device_id msm_gpu_match[] = { + { .compatible = "qcom,adreno-3xx" }, + { .compatible = "qcom,kgsl-3d0" }, + { }, +}; + static int add_gpu_components(struct device *dev, struct component_match **matchptr) { - return add_components(dev, matchptr, "gpus"); + struct device_node *np; + + np = of_find_matching_node(NULL, msm_gpu_match); + if (!np) + return 0; + + component_match_add(dev, matchptr, compare_of, np); + + of_node_put(np); + + return 0; } static int msm_drm_bind(struct device *dev) From 96a611b54f7f0564886d64c43485402fa2530bf4 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 30 May 2016 17:02:00 +0530 Subject: [PATCH 29/52] drm/msm/mdp5: Update compatible strings for MDSS/MDP5 Introduce new compatible strings for the top level MDSS wrapper device, and the MDP5 device. Previously, the "qcom,mdp5" and "qcom,mdss_mdp" compatible strings were used to match the top level platform_device (which was also tied to the top level drm_device struct). Now, these strings are used to match the MDP5 platform device. Use "qcom,mdss" as the compatible string for top level MDSS device. This is now used to match the top level platform_device (which is tied to the drm_device struct). Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 10 +++++++++- drivers/gpu/drm/msm/msm_drv.c | 6 ++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 174d7e7969fd..ed7143d35b25 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -809,12 +809,20 @@ static int mdp5_dev_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id mdp5_dt_match[] = { + { .compatible = "qcom,mdp5", }, + /* to support downstream DT files */ + { .compatible = "qcom,mdss_mdp", }, + {} +}; +MODULE_DEVICE_TABLE(of, mdp5_dt_match); + static struct platform_driver mdp5_driver = { .probe = mdp5_dev_probe, .remove = mdp5_dev_remove, .driver = { .name = "msm_mdp", - /* Add a DT match field once we move to new hierarchy */ + .of_match_table = mdp5_dt_match, }, }; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 66371f23cc22..435a8f90c290 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -992,10 +992,8 @@ static int msm_pdev_remove(struct platform_device *pdev) } static const struct of_device_id dt_match[] = { - { .compatible = "qcom,mdp4", .data = (void *) 4 }, /* mdp4 */ - { .compatible = "qcom,mdp5", .data = (void *) 5 }, /* mdp5 */ - /* to support downstream DT files */ - { .compatible = "qcom,mdss_mdp", .data = (void *) 5 }, /* mdp5 */ + { .compatible = "qcom,mdp4", .data = (void *)4 }, /* MDP4 */ + { .compatible = "qcom,mdss", .data = (void *)5 }, /* MDP5 MDSS */ {} }; MODULE_DEVICE_TABLE(of, dt_match); From 32280d66fd44de231b1d1a015e4ef41cac2d295c Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 23 Jun 2016 15:26:04 +0530 Subject: [PATCH 30/52] drm/msm/dsi: Don't get DSI index from DT The DSI host and PHY driver currently expects the DT bindings to provide custom properties "qcom,dsi-host-index" and "qcom,dsi-phy-index" so that the driver can identify which DSI instance it is. The binding isn't acceptable, but the driver still needs to figure out what its instance id. This is now done by storing the mmio starting addresses for each DSI instance in every SoC version in the driver. The driver then identifies the index number by trying to match the stored address with comparing the resource start address we get from DT. We don't have compatible strings for DSI PHY on each SoC, but only the DSI PHY type. We only support one SoC version for each PHY type, so we get away doing the same thing above for the PHY driver. We can revisit this when we support two SoCs with the same DSI PHY. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_cfg.c | 8 +++++ drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 ++ drivers/gpu/drm/msm/dsi/dsi_host.c | 33 +++++++++++++++---- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 32 +++++++++++++++--- drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 2 ++ drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c | 4 ++- drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c | 4 +++ .../gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c | 2 ++ 8 files changed, 75 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 93c1ee094eac..63436d8ee470 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -29,6 +29,8 @@ static const struct msm_dsi_config apq8064_dsi_cfg = { }, .bus_clk_names = dsi_v2_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_v2_bus_clk_names), + .io_start = { 0x4700000, 0x5800000 }, + .num_dsi = 2, }; static const char * const dsi_6g_bus_clk_names[] = { @@ -48,6 +50,8 @@ static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = { }, .bus_clk_names = dsi_6g_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names), + .io_start = { 0xfd922800, 0xfd922b00 }, + .num_dsi = 2, }; static const char * const dsi_8916_bus_clk_names[] = { @@ -66,6 +70,8 @@ static const struct msm_dsi_config msm8916_dsi_cfg = { }, .bus_clk_names = dsi_8916_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_8916_bus_clk_names), + .io_start = { 0x1a98000 }, + .num_dsi = 1, }; static const struct msm_dsi_config msm8994_dsi_cfg = { @@ -84,6 +90,8 @@ static const struct msm_dsi_config msm8994_dsi_cfg = { }, .bus_clk_names = dsi_6g_bus_clk_names, .num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names), + .io_start = { 0xfd998000, 0xfd9a0000 }, + .num_dsi = 2, }; static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index a68c836744a3..eeacc3232494 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -34,6 +34,8 @@ struct msm_dsi_config { struct dsi_reg_config reg_cfg; const char * const *bus_clk_names; const int num_bus_clks; + const resource_size_t io_start[DSI_MAX]; + const int num_dsi; }; struct msm_dsi_cfg_handler { diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index e6a8cd1b6462..80d8594c68ba 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1605,13 +1605,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) struct device_node *endpoint, *device_node; int ret; - ret = of_property_read_u32(np, "qcom,dsi-host-index", &msm_host->id); - if (ret) { - dev_err(dev, "%s: host index not specified, ret=%d\n", - __func__, ret); - return ret; - } - /* * Get the endpoint of the output port of the DSI host. In our case, * this is mapped to port number with reg = 1. Don't return an error if @@ -1659,6 +1652,25 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) return ret; } +static int dsi_host_get_id(struct msm_dsi_host *msm_host) +{ + struct platform_device *pdev = msm_host->pdev; + const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg; + struct resource *res; + int i; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dsi_ctrl"); + if (!res) + return -EINVAL; + + for (i = 0; i < cfg->num_dsi; i++) { + if (cfg->io_start[i] == res->start) + return i; + } + + return -EINVAL; +} + int msm_dsi_host_init(struct msm_dsi *msm_dsi) { struct msm_dsi_host *msm_host = NULL; @@ -1695,6 +1707,13 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) goto fail; } + msm_host->id = dsi_host_get_id(msm_host); + if (msm_host->id < 0) { + ret = msm_host->id; + pr_err("%s: unable to identify DSI host index\n", __func__); + goto fail; + } + /* fixup base address by io offset */ msm_host->ctrl_base += msm_host->cfg_hnd->cfg->io_offset; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index e2f42d8ea294..f39386ed75e4 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -271,6 +271,30 @@ static const struct of_device_id dsi_phy_dt_match[] = { {} }; +/* + * Currently, we only support one SoC for each PHY type. When we have multiple + * SoCs for the same PHY, we can try to make the index searching a bit more + * clever. + */ +static int dsi_phy_get_id(struct msm_dsi_phy *phy) +{ + struct platform_device *pdev = phy->pdev; + const struct msm_dsi_phy_cfg *cfg = phy->cfg; + struct resource *res; + int i; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dsi_phy"); + if (!res) + return -EINVAL; + + for (i = 0; i < cfg->num_dsi_phy; i++) { + if (cfg->io_start[i] == res->start) + return i; + } + + return -EINVAL; +} + static int dsi_phy_driver_probe(struct platform_device *pdev) { struct msm_dsi_phy *phy; @@ -289,10 +313,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) phy->cfg = match->data; phy->pdev = pdev; - ret = of_property_read_u32(dev->of_node, - "qcom,dsi-phy-index", &phy->id); - if (ret) { - dev_err(dev, "%s: PHY index not specified, %d\n", + phy->id = dsi_phy_get_id(phy); + if (phy->id < 0) { + ret = phy->id; + dev_err(dev, "%s: couldn't identify PHY index, %d\n", __func__, ret); goto fail; } diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 0d54ed00386d..f24a85439b94 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -38,6 +38,8 @@ struct msm_dsi_phy_cfg { * Fill default H/W values in illegal cells, eg. cell {0, 1}. */ bool src_pll_truthtable[DSI_MAX][DSI_MAX]; + const resource_size_t io_start[DSI_MAX]; + const int num_dsi_phy; }; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c index f4bc11af849a..c757e2070cac 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c @@ -145,6 +145,8 @@ const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs = { .ops = { .enable = dsi_20nm_phy_enable, .disable = dsi_20nm_phy_disable, - } + }, + .io_start = { 0xfd998300, 0xfd9a0300 }, + .num_dsi_phy = 2, }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c index 96d1852af418..63d7fba31380 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c @@ -145,6 +145,8 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = { .enable = dsi_28nm_phy_enable, .disable = dsi_28nm_phy_disable, }, + .io_start = { 0xfd922b00, 0xfd923100 }, + .num_dsi_phy = 2, }; const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = { @@ -160,5 +162,7 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = { .enable = dsi_28nm_phy_enable, .disable = dsi_28nm_phy_disable, }, + .io_start = { 0x1a98500 }, + .num_dsi_phy = 1, }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c index 213355a3e767..7bdb9de54968 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -192,4 +192,6 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = { .enable = dsi_28nm_phy_enable, .disable = dsi_28nm_phy_disable, }, + .io_start = { 0x4700300, 0x5800300 }, + .num_dsi_phy = 2, }; From acc58caa7016784cc52e8bcb4268191a1e03cfa6 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 13 Jun 2016 19:37:37 +0530 Subject: [PATCH 31/52] dt-bindings: msm/mdp4: Create a separate binding doc for MDP4 MDP4 and MDP5 vary a bit in terms of device hierarchy and the properties they require. Rename the binding doc to mdp4.txt and remove MDP5 specific pieces. A separate document will be created for MDP5 Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../display/msm/{mdp.txt => mdp4.txt} | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) rename Documentation/devicetree/bindings/display/msm/{mdp.txt => mdp4.txt} (75%) diff --git a/Documentation/devicetree/bindings/display/msm/mdp.txt b/Documentation/devicetree/bindings/display/msm/mdp4.txt similarity index 75% rename from Documentation/devicetree/bindings/display/msm/mdp.txt rename to Documentation/devicetree/bindings/display/msm/mdp4.txt index ebfe0165b9a6..1de9b17da2e1 100644 --- a/Documentation/devicetree/bindings/display/msm/mdp.txt +++ b/Documentation/devicetree/bindings/display/msm/mdp4.txt @@ -1,28 +1,25 @@ -Qualcomm adreno/snapdragon display controller +Qualcomm adreno/snapdragon MDP4 display controller + +Description: + +This is the bindings documentation for the MDP4 display controller found in +SoCs like MSM8960, APQ8064 and MSM8660. Required properties: - compatible: * "qcom,mdp4" - mdp4 - * "qcom,mdp5" - mdp5 - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt signal from the display controller. - connectors: array of phandles for output device(s) - clocks: device clocks See ../clocks/clock-bindings.txt for details. - clock-names: the following clocks are required. - For MDP4: - * "core_clk" - * "iface_clk" - * "bus_clk" - * "lut_clk" - * "hdmi_clk" - * "tv_clk" - For MDP5: - * "bus_clk" - * "iface_clk" - * "core_clk" - * "lut_clk" (some MDP5 versions may not need this) - * "vsync_clk" + * "core_clk" + * "iface_clk" + * "bus_clk" + * "lut_clk" + * "hdmi_clk" + * "tv_clk" Optional properties: - gpus: phandle for gpu device From fd7ef70617ff0c93f3d5f2ff64237bb670edd231 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 14 Jun 2016 16:13:51 +0530 Subject: [PATCH 32/52] dt-bindings: msm/mdp5: Add MDP5 display bindings Add a new doc for DT bindings for platforms that contain MDP5 display controller hardware. The doc describes bindings for the top level MDSS wrapper hardware and MDP5 itself. Add an example for the bindings as found in MSM8916. Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/mdp5.txt | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/mdp5.txt diff --git a/Documentation/devicetree/bindings/display/msm/mdp5.txt b/Documentation/devicetree/bindings/display/msm/mdp5.txt new file mode 100644 index 000000000000..b395905ae04f --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/mdp5.txt @@ -0,0 +1,114 @@ +Qualcomm adreno/snapdragon MDP5 display controller + +Description: + +This is the bindings documentation for the Mobile Display Subsytem(MDSS) that +encapsulates sub-blocks like MDP5, DSI, HDMI, eDP etc, and the MDP5 display +controller found in SoCs like MSM8974, APQ8084, MSM8916, MSM8994 and MSM8996. + +MDSS: +Required properties: +- compatible: + * "qcom,mdss" - MDSS +- reg: Physical base address and length of the controller's registers. +- reg-names: The names of register regions. The following regions are required: + * "mdss_phys" + * "vbif_phys" +- interrupts: The interrupt signal from MDSS. +- interrupt-controller: identifies the node as an interrupt controller. +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- power-domains: a power domain consumer specifier according to + Documentation/devicetree/bindings/power/power_domain.txt +- clocks: device clocks. See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. + * "iface_clk" + * "bus_clk" + * "vsync_clk" +- #address-cells: number of address cells for the MDSS children. Should be 1. +- #size-cells: Should be 1. +- ranges: parent bus address space is the same as the child bus address space. + +Optional properties: +- clock-names: the following clocks are optional: + * "lut_clk" + +MDP5: +Required properties: +- compatible: + * "qcom,mdp5" - MDP5 +- reg: Physical base address and length of the controller's registers. +- reg-names: The names of register regions. The following regions are required: + * "mdp_phys" +- interrupts: Interrupt line from MDP5 to MDSS interrupt controller. +- interrupt-parent: phandle to the MDSS block + through MDP block +- clocks: device clocks. See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. +- * "bus_clk" +- * "iface_clk" +- * "core_clk" +- * "vsync_clk" + +Optional properties: +- clock-names: the following clocks are optional: + * "lut_clk" + + +Example: + +/ { + ... + + mdss: mdss@1a00000 { + compatible = "qcom,mdss"; + reg = <0x1a00000 0x1000>, + <0x1ac8000 0x3000>; + reg-names = "mdss_phys", "vbif_phys"; + + power-domains = <&gcc MDSS_GDSC>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface_clk", + "bus_clk", + "vsync_clk" + + interrupts = <0 72 0>; + + interrupt-controller; + #interrupt-cells = <1>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mdp: mdp@1a01000 { + compatible = "qcom,mdp5"; + reg = <0x1a01000 0x90000>; + reg-names = "mdp_phys"; + + interrupt-parent = <&mdss>; + interrupts = <0 0>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_MDP_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface_clk", + "bus_clk", + "core_clk", + "vsync_clk"; + + }; + + dsi0: dsi@1a98000 { + ... + }; + + dsi_phy0: dsi-phy@1a98300 { + ... + }; + }; +}; From b137bb4bec515c243eb42127ccf5ba2765fbed7c Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 14 Jun 2016 17:47:26 +0530 Subject: [PATCH 33/52] dt-bindings: msm/mdp: Provide details on MDP interface ports The MDP4/5 DT node now contains a list of ports that describe how it connects to external encoder interfaces like DSI and HDMI. These follow the standard of_graph bindings, and allow us to get rid of the 'connectors' phandle that contained a list of all the external encoders connected to MDP. Acked-by: Rob Herring Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- .../devicetree/bindings/display/msm/mdp4.txt | 68 +++++++++++++++++-- .../devicetree/bindings/display/msm/mdp5.txt | 48 ++++++++++++- 2 files changed, 110 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/mdp4.txt b/Documentation/devicetree/bindings/display/msm/mdp4.txt index 1de9b17da2e1..3c341a15ccdc 100644 --- a/Documentation/devicetree/bindings/display/msm/mdp4.txt +++ b/Documentation/devicetree/bindings/display/msm/mdp4.txt @@ -10,7 +10,6 @@ Required properties: * "qcom,mdp4" - mdp4 - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt signal from the display controller. -- connectors: array of phandles for output device(s) - clocks: device clocks See ../clocks/clock-bindings.txt for details. - clock-names: the following clocks are required. @@ -20,9 +19,23 @@ Required properties: * "lut_clk" * "hdmi_clk" * "tv_clk" +- ports: contains the list of output ports from MDP. These connect to interfaces + that are external to the MDP hardware, such as HDMI, DSI, EDP etc (LVDS is a + special case since it is a part of the MDP block itself). + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + The output port mappings are: + Port 0 -> LCDC/LVDS + Port 1 -> DSI1 Cmd/Video + Port 2 -> DSI2 Cmd/Video + Port 3 -> DTV Optional properties: -- gpus: phandle for gpu device - clock-names: the following clocks are optional: * "lut_clk" @@ -31,12 +44,27 @@ Example: / { ... - mdp: qcom,mdp@5100000 { + hdmi: hdmi@4a00000 { + ... + ports { + ... + port@0 { + reg = <0>; + hdmi_in: endpoint { + remote-endpoint = <&mdp_dtv_out>; + }; + }; + ... + }; + ... + }; + + ... + + mdp: mdp@5100000 { compatible = "qcom,mdp4"; reg = <0x05100000 0xf0000>; interrupts = ; - connectors = <&hdmi>; - gpus = <&gpu>; clock-names = "core_clk", "iface_clk", @@ -50,5 +78,35 @@ Example: <&mmcc MDP_LUT_CLK>, <&mmcc HDMI_TV_CLK>, <&mmcc MDP_TV_CLK>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdp_lvds_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + mdp_dsi1_out: endpoint { + }; + }; + + port@2 { + reg = <2>; + mdp_dsi2_out: endpoint { + }; + }; + + port@3 { + reg = <3>; + mdp_dtv_out: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + }; }; }; diff --git a/Documentation/devicetree/bindings/display/msm/mdp5.txt b/Documentation/devicetree/bindings/display/msm/mdp5.txt index b395905ae04f..30c11ea83754 100644 --- a/Documentation/devicetree/bindings/display/msm/mdp5.txt +++ b/Documentation/devicetree/bindings/display/msm/mdp5.txt @@ -49,12 +49,36 @@ Required properties: - * "iface_clk" - * "core_clk" - * "vsync_clk" +- ports: contains the list of output ports from MDP. These connect to interfaces + that are external to the MDP hardware, such as HDMI, DSI, EDP etc (LVDS is a + special case since it is a part of the MDP block itself). + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + The availability of output ports can vary across SoC revisions: + + For MSM8974 and APQ8084: + Port 0 -> MDP_INTF0 (eDP) + Port 1 -> MDP_INTF1 (DSI1) + Port 2 -> MDP_INTF2 (DSI2) + Port 3 -> MDP_INTF3 (HDMI) + + For MSM8916: + Port 0 -> MDP_INTF1 (DSI1) + + For MSM8994 and MSM8996: + Port 0 -> MDP_INTF1 (DSI1) + Port 1 -> MDP_INTF2 (DSI2) + Port 2 -> MDP_INTF3 (HDMI) Optional properties: - clock-names: the following clocks are optional: * "lut_clk" - Example: / { @@ -101,10 +125,32 @@ Example: "core_clk", "vsync_clk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdp5_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; }; dsi0: dsi@1a98000 { ... + ports { + ... + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&mdp5_intf1_out>; + }; + }; + ... + }; + ... }; dsi_phy0: dsi-phy@1a98300 { From b5b4c264df4d270819676b290cef9a11d04c35f0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 17 May 2016 15:43:35 -0400 Subject: [PATCH 34/52] drm/msm: use mutex_lock_interruptible for submit ioctl Be kinder to things that do lots of signal handling (ie. Xorg) Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem_submit.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index eb4bb8b2f3a5..ea5f709e2e27 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -372,11 +372,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (args->nr_cmds > MAX_CMDS) return -EINVAL; - submit = submit_create(dev, gpu, args->nr_bos); - if (!submit) - return -ENOMEM; + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; - mutex_lock(&dev->struct_mutex); + submit = submit_create(dev, gpu, args->nr_bos); + if (!submit) { + ret = -ENOMEM; + goto out_unlock; + } ret = submit_lookup_objects(submit, args, file); if (ret) @@ -462,6 +466,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, submit_cleanup(submit); if (ret) msm_gem_submit_free(submit); +out_unlock: mutex_unlock(&dev->struct_mutex); return ret; } From 4cd33c48ea25ba17e9d0383fe914c3e58b48f7dd Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 17 May 2016 15:44:49 -0400 Subject: [PATCH 35/52] drm/msm: add madvise ioctl Doesn't do anything too interesting until we wire up shrinker. Pretty much lifted from i915. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 39 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_drv.h | 1 + drivers/gpu/drm/msm/msm_gem.c | 35 +++++++++++++++++++++++++++++-- drivers/gpu/drm/msm/msm_gem.h | 5 +++++ include/uapi/drm/msm_drm.h | 25 +++++++++++++++++++++- 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 435a8f90c290..00881f3ed32e 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -690,6 +690,44 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, return msm_wait_fence(priv->gpu->fctx, args->fence, &timeout, true); } +static int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_msm_gem_madvise *args = data; + struct drm_gem_object *obj; + int ret; + + switch (args->madv) { + case MSM_MADV_DONTNEED: + case MSM_MADV_WILLNEED: + break; + default: + return -EINVAL; + } + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) { + ret = -ENOENT; + goto unlock; + } + + ret = msm_gem_madvise(obj, args->madv); + if (ret >= 0) { + args->retained = ret; + ret = 0; + } + + drm_gem_object_unreference(obj); + +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW), @@ -698,6 +736,7 @@ static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_MADVISE, msm_ioctl_gem_madvise, DRM_AUTH|DRM_RENDER_ALLOW), }; static const struct vm_operations_struct vm_ops = { diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index be01e3895178..a49d7fd67ec3 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -195,6 +195,7 @@ int msm_gem_prime_pin(struct drm_gem_object *obj); void msm_gem_prime_unpin(struct drm_gem_object *obj); void *msm_gem_vaddr_locked(struct drm_gem_object *obj); void *msm_gem_vaddr(struct drm_gem_object *obj); +int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv); int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive); void msm_gem_move_to_active(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 69836f5685b1..c40db08647d1 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -413,6 +413,21 @@ void *msm_gem_vaddr(struct drm_gem_object *obj) return ret; } +/* Update madvise status, returns true if not purged, else + * false or -errno. + */ +int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); + + if (msm_obj->madv != __MSM_MADV_PURGED) + msm_obj->madv = madv; + + return (msm_obj->madv != __MSM_MADV_PURGED); +} + /* must be called before _move_to_active().. */ int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive) @@ -464,6 +479,7 @@ void msm_gem_move_to_active(struct drm_gem_object *obj, struct msm_gpu *gpu, bool exclusive, struct fence *fence) { struct msm_gem_object *msm_obj = to_msm_bo(obj); + WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED); msm_obj->gpu = gpu; if (exclusive) reservation_object_add_excl_fence(msm_obj->resv, fence); @@ -532,13 +548,27 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) struct reservation_object_list *fobj; struct fence *fence; uint64_t off = drm_vma_node_start(&obj->vma_node); + const char *madv; WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); - seq_printf(m, "%08x: %c %2d (%2d) %08llx %p %zu\n", + switch (msm_obj->madv) { + case __MSM_MADV_PURGED: + madv = " purged"; + break; + case MSM_MADV_DONTNEED: + madv = " purgeable"; + break; + case MSM_MADV_WILLNEED: + default: + madv = ""; + break; + } + + seq_printf(m, "%08x: %c %2d (%2d) %08llx %p %zu%s\n", msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', obj->name, obj->refcount.refcount.counter, - off, msm_obj->vaddr, obj->size); + off, msm_obj->vaddr, obj->size, madv); rcu_read_lock(); fobj = rcu_dereference(robj->fence); @@ -688,6 +718,7 @@ static int msm_gem_new_impl(struct drm_device *dev, msm_obj->vram_node = (void *)&msm_obj[1]; msm_obj->flags = flags; + msm_obj->madv = MSM_MADV_WILLNEED; if (resv) { msm_obj->resv = resv; diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 9facd4b6ffd9..fa8e1f16f18e 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -29,6 +29,11 @@ struct msm_gem_object { uint32_t flags; + /** + * Advice: are the backing pages purgeable? + */ + uint8_t madv; + /* And object is either: * inactive - on priv->inactive_list * active - on one one of the gpu's active_list.. well, at diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index bf19d2cd9078..49f778de8e06 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -201,6 +201,27 @@ struct drm_msm_wait_fence { struct drm_msm_timespec timeout; /* in */ }; +/* madvise provides a way to tell the kernel in case a buffers contents + * can be discarded under memory pressure, which is useful for userspace + * bo cache where we want to optimistically hold on to buffer allocate + * and potential mmap, but allow the pages to be discarded under memory + * pressure. + * + * Typical usage would involve madvise(DONTNEED) when buffer enters BO + * cache, and madvise(WILLNEED) if trying to recycle buffer from BO cache. + * In the WILLNEED case, 'retained' indicates to userspace whether the + * backing pages still exist. + */ +#define MSM_MADV_WILLNEED 0 /* backing pages are needed, status returned in 'retained' */ +#define MSM_MADV_DONTNEED 1 /* backing pages not needed */ +#define __MSM_MADV_PURGED 2 /* internal state */ + +struct drm_msm_gem_madvise { + __u32 handle; /* in, GEM handle */ + __u32 madv; /* in, MSM_MADV_x */ + __u32 retained; /* out, whether backing store still exists */ +}; + #define DRM_MSM_GET_PARAM 0x00 /* placeholder: #define DRM_MSM_SET_PARAM 0x01 @@ -211,7 +232,8 @@ struct drm_msm_wait_fence { #define DRM_MSM_GEM_CPU_FINI 0x05 #define DRM_MSM_GEM_SUBMIT 0x06 #define DRM_MSM_WAIT_FENCE 0x07 -#define DRM_MSM_NUM_IOCTLS 0x08 +#define DRM_MSM_GEM_MADVISE 0x08 +#define DRM_MSM_NUM_IOCTLS 0x09 #define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param) #define DRM_IOCTL_MSM_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new) @@ -220,6 +242,7 @@ struct drm_msm_wait_fence { #define DRM_IOCTL_MSM_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_GEM_CPU_FINI, struct drm_msm_gem_cpu_fini) #define DRM_IOCTL_MSM_GEM_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_SUBMIT, struct drm_msm_gem_submit) #define DRM_IOCTL_MSM_WAIT_FENCE DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_WAIT_FENCE, struct drm_msm_wait_fence) +#define DRM_IOCTL_MSM_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_MADVISE, struct drm_msm_gem_madvise) #if defined(__cplusplus) } From 4fe5f65e66823dcb212a0404af47389b2b1c58f0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 1 Jun 2016 11:38:28 -0400 Subject: [PATCH 36/52] drm/msm: add put_iova() helper We'll need this too for shrinker/purging. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index c40db08647d1..2636c279d504 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -276,6 +276,26 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj) return offset; } +static void +put_iova(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct msm_drm_private *priv = obj->dev->dev_private; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + int id; + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { + struct msm_mmu *mmu = priv->mmus[id]; + if (mmu && msm_obj->domain[id].iova) { + uint32_t offset = msm_obj->domain[id].iova; + mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size); + msm_obj->domain[id].iova = 0; + } + } +} + /* should be called under struct_mutex.. although it can be called * from atomic context without struct_mutex to acquire an extra * iova ref if you know one is already held. @@ -608,9 +628,7 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) void msm_gem_free_object(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - struct msm_drm_private *priv = obj->dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); - int id; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -619,13 +637,7 @@ void msm_gem_free_object(struct drm_gem_object *obj) list_del(&msm_obj->mm_list); - for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { - struct msm_mmu *mmu = priv->mmus[id]; - if (mmu && msm_obj->domain[id].iova) { - uint32_t offset = msm_obj->domain[id].iova; - mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size); - } - } + put_iova(obj); if (obj->import_attach) { if (msm_obj->vaddr) From 68209390f116034449fa6a3ae03f7b100b3d894a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 17 May 2016 16:19:32 -0400 Subject: [PATCH 37/52] drm/msm: shrinker support For a first step, only purge obj->madv==DONTNEED objects. We could be more agressive and next try unpinning inactive objects.. but that is only useful if you have swap. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/msm_drv.c | 5 + drivers/gpu/drm/msm/msm_drv.h | 8 ++ drivers/gpu/drm/msm/msm_gem.c | 32 +++++++ drivers/gpu/drm/msm/msm_gem.h | 6 ++ drivers/gpu/drm/msm/msm_gem_shrinker.c | 128 +++++++++++++++++++++++++ 6 files changed, 180 insertions(+) create mode 100644 drivers/gpu/drm/msm/msm_gem_shrinker.c diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 4727d045f179..4e2806cf778c 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -46,6 +46,7 @@ msm-y := \ msm_fence.o \ msm_gem.o \ msm_gem_prime.o \ + msm_gem_shrinker.o \ msm_gem_submit.o \ msm_gpu.o \ msm_iommu.o \ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 00881f3ed32e..f3b8f69ea9ae 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -195,6 +195,8 @@ static int msm_drm_uninit(struct device *dev) kfree(vbl_ev); } + msm_gem_shrinker_cleanup(ddev); + drm_kms_helper_poll_fini(ddev); drm_dev_unregister(ddev); @@ -350,6 +352,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) } ddev->dev_private = priv; + priv->dev = ddev; ret = msm_mdss_init(ddev); if (ret) { @@ -382,6 +385,8 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) if (ret) goto fail; + msm_gem_shrinker_init(ddev); + switch (get_mdp_ver(pdev)) { case 4: kms = mdp4_kms_init(ddev); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index a49d7fd67ec3..4755894d9229 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -78,6 +78,8 @@ struct msm_vblank_ctrl { struct msm_drm_private { + struct drm_device *dev; + struct msm_kms *kms; /* subordinate devices, if present: */ @@ -151,6 +153,8 @@ struct msm_drm_private { struct drm_mm mm; } vram; + struct shrinker shrinker; + struct msm_vblank_ctrl vblank_ctrl; }; @@ -169,6 +173,9 @@ void msm_gem_submit_free(struct msm_gem_submit *submit); int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); +void msm_gem_shrinker_init(struct drm_device *dev); +void msm_gem_shrinker_cleanup(struct drm_device *dev); + int msm_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma); int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma); @@ -196,6 +203,7 @@ void msm_gem_prime_unpin(struct drm_gem_object *obj); void *msm_gem_vaddr_locked(struct drm_gem_object *obj); void *msm_gem_vaddr(struct drm_gem_object *obj); int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv); +void msm_gem_purge(struct drm_gem_object *obj); int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive); void msm_gem_move_to_active(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 2636c279d504..444d0b5680f5 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -448,6 +448,38 @@ int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv) return (msm_obj->madv != __MSM_MADV_PURGED); } +void msm_gem_purge(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!is_purgeable(msm_obj)); + WARN_ON(obj->import_attach); + + put_iova(obj); + + vunmap(msm_obj->vaddr); + msm_obj->vaddr = NULL; + + put_pages(obj); + + msm_obj->madv = __MSM_MADV_PURGED; + + drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping); + drm_gem_free_mmap_offset(obj); + + /* Our goal here is to return as much of the memory as + * is possible back to the system as we are called from OOM. + * To do this we must instruct the shmfs to drop all of its + * backing pages, *now*. + */ + shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1); + + invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, + 0, (loff_t)-1); +} + /* must be called before _move_to_active().. */ int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index fa8e1f16f18e..631dab56b8fd 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -77,6 +77,12 @@ static inline bool is_active(struct msm_gem_object *msm_obj) return msm_obj->gpu != NULL; } +static inline bool is_purgeable(struct msm_gem_object *msm_obj) +{ + return (msm_obj->madv == MSM_MADV_DONTNEED) && msm_obj->sgt && + !msm_obj->base.dma_buf && !msm_obj->base.import_attach; +} + #define MAX_CMDS 4 /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c new file mode 100644 index 000000000000..70fba9baddde --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2016 Red Hat + * Author: Rob Clark + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "msm_drv.h" +#include "msm_gem.h" + +static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) +{ + if (!mutex_is_locked(mutex)) + return false; + +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES) + return mutex->owner == task; +#else + /* Since UP may be pre-empted, we cannot assume that we own the lock */ + return false; +#endif +} + +static bool msm_gem_shrinker_lock(struct drm_device *dev, bool *unlock) +{ + if (!mutex_trylock(&dev->struct_mutex)) { + if (!mutex_is_locked_by(&dev->struct_mutex, current)) + return false; + *unlock = false; + } else { + *unlock = true; + } + + return true; +} + + +static unsigned long +msm_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct msm_drm_private *priv = + container_of(shrinker, struct msm_drm_private, shrinker); + struct drm_device *dev = priv->dev; + struct msm_gem_object *msm_obj; + unsigned long count = 0; + bool unlock; + + if (!msm_gem_shrinker_lock(dev, &unlock)) + return 0; + + list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) { + if (is_purgeable(msm_obj)) + count += msm_obj->base.size >> PAGE_SHIFT; + } + + if (unlock) + mutex_unlock(&dev->struct_mutex); + + return count; +} + +static unsigned long +msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct msm_drm_private *priv = + container_of(shrinker, struct msm_drm_private, shrinker); + struct drm_device *dev = priv->dev; + struct msm_gem_object *msm_obj; + unsigned long freed = 0; + bool unlock; + + if (!msm_gem_shrinker_lock(dev, &unlock)) + return SHRINK_STOP; + + list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) { + if (freed >= sc->nr_to_scan) + break; + if (is_purgeable(msm_obj)) { + msm_gem_purge(&msm_obj->base); + freed += msm_obj->base.size >> PAGE_SHIFT; + } + } + + if (unlock) + mutex_unlock(&dev->struct_mutex); + + if (freed > 0) + pr_info_ratelimited("Purging %lu bytes\n", freed << PAGE_SHIFT); + + return freed; +} + +/** + * msm_gem_shrinker_init - Initialize msm shrinker + * @dev_priv: msm device + * + * This function registers and sets up the msm shrinker. + */ +void msm_gem_shrinker_init(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + priv->shrinker.count_objects = msm_gem_shrinker_count; + priv->shrinker.scan_objects = msm_gem_shrinker_scan; + priv->shrinker.seeks = DEFAULT_SEEKS; + WARN_ON(register_shrinker(&priv->shrinker)); +} + +/** + * msm_gem_shrinker_cleanup - Clean up msm shrinker + * @dev_priv: msm device + * + * This function unregisters the msm shrinker. + */ +void msm_gem_shrinker_cleanup(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + unregister_shrinker(&priv->shrinker); +} From 18f23049f640e2590930c34009418c66e6ebf7b6 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 26 May 2016 16:24:35 -0400 Subject: [PATCH 38/52] drm/msm: change gem->vmap() to get/put Before we can add vmap shrinking, we really need to know which vmap'ings are currently being used. So switch to get/put interface. Stubbed put fxns for now. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 6 +++++- drivers/gpu/drm/msm/dsi/dsi_host.c | 5 ++++- drivers/gpu/drm/msm/msm_drv.h | 6 ++++-- drivers/gpu/drm/msm/msm_fbdev.c | 3 ++- drivers/gpu/drm/msm/msm_gem.c | 17 ++++++++++++++--- drivers/gpu/drm/msm/msm_gem_prime.c | 4 ++-- drivers/gpu/drm/msm/msm_gem_submit.c | 4 +++- drivers/gpu/drm/msm/msm_rd.c | 4 +++- drivers/gpu/drm/msm/msm_ringbuffer.c | 6 ++++-- 9 files changed, 41 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 2aec27dbb5bb..7dfe22ea2920 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -407,7 +407,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, return ret; } - adreno_gpu->memptrs = msm_gem_vaddr(adreno_gpu->memptrs_bo); + adreno_gpu->memptrs = msm_gem_get_vaddr(adreno_gpu->memptrs_bo); if (IS_ERR(adreno_gpu->memptrs)) { dev_err(drm->dev, "could not vmap memptrs\n"); return -ENOMEM; @@ -426,8 +426,12 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, void adreno_gpu_cleanup(struct adreno_gpu *gpu) { if (gpu->memptrs_bo) { + if (gpu->memptrs) + msm_gem_put_vaddr(gpu->memptrs_bo); + if (gpu->memptrs_iova) msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id); + drm_gem_object_unreference_unlocked(gpu->memptrs_bo); } release_firmware(gpu->pm4); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 80d8594c68ba..ddc4c7d678ed 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1066,7 +1066,7 @@ static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host, } if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { - data = msm_gem_vaddr(msm_host->tx_gem_obj); + data = msm_gem_get_vaddr(msm_host->tx_gem_obj); if (IS_ERR(data)) { ret = PTR_ERR(data); pr_err("%s: get vaddr failed, %d\n", __func__, ret); @@ -1094,6 +1094,9 @@ static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host, if (packet.size < len) memset(data + packet.size, 0xff, len - packet.size); + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) + msm_gem_put_vaddr(msm_host->tx_gem_obj); + return len; } diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 4755894d9229..ecf0b3b03e0e 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -200,8 +200,10 @@ struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg); int msm_gem_prime_pin(struct drm_gem_object *obj); void msm_gem_prime_unpin(struct drm_gem_object *obj); -void *msm_gem_vaddr_locked(struct drm_gem_object *obj); -void *msm_gem_vaddr(struct drm_gem_object *obj); +void *msm_gem_get_vaddr_locked(struct drm_gem_object *obj); +void *msm_gem_get_vaddr(struct drm_gem_object *obj); +void msm_gem_put_vaddr_locked(struct drm_gem_object *obj); +void msm_gem_put_vaddr(struct drm_gem_object *obj); int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv); void msm_gem_purge(struct drm_gem_object *obj); int msm_gem_sync_object(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index a9223bea871b..ffd4a338ca12 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -158,7 +158,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, dev->mode_config.fb_base = paddr; - fbi->screen_base = msm_gem_vaddr_locked(fbdev->bo); + fbi->screen_base = msm_gem_get_vaddr_locked(fbdev->bo); if (IS_ERR(fbi->screen_base)) { ret = PTR_ERR(fbi->screen_base); goto fail_unlock; @@ -251,6 +251,7 @@ void msm_fbdev_free(struct drm_device *dev) /* this will free the backing object */ if (fbdev->fb) { + msm_gem_put_vaddr(fbdev->bo); drm_framebuffer_unregister_private(fbdev->fb); drm_framebuffer_remove(fbdev->fb); } diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 444d0b5680f5..c05fc1d0dce7 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -408,7 +408,7 @@ int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, return ret; } -void *msm_gem_vaddr_locked(struct drm_gem_object *obj) +void *msm_gem_get_vaddr_locked(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); @@ -424,15 +424,26 @@ void *msm_gem_vaddr_locked(struct drm_gem_object *obj) return msm_obj->vaddr; } -void *msm_gem_vaddr(struct drm_gem_object *obj) +void *msm_gem_get_vaddr(struct drm_gem_object *obj) { void *ret; mutex_lock(&obj->dev->struct_mutex); - ret = msm_gem_vaddr_locked(obj); + ret = msm_gem_get_vaddr_locked(obj); mutex_unlock(&obj->dev->struct_mutex); return ret; } +void msm_gem_put_vaddr_locked(struct drm_gem_object *obj) +{ + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); + /* no-op for now */ +} + +void msm_gem_put_vaddr(struct drm_gem_object *obj) +{ + /* no-op for now */ +} + /* Update madvise status, returns true if not purged, else * false or -errno. */ diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 6b90890faffe..60bb290700ce 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -33,12 +33,12 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj) void *msm_gem_prime_vmap(struct drm_gem_object *obj) { - return msm_gem_vaddr(obj); + return msm_gem_get_vaddr(obj); } void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) { - /* TODO msm_gem_vunmap() */ + msm_gem_put_vaddr(obj); } int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index ea5f709e2e27..736f15881b6a 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -279,7 +279,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob /* For now, just map the entire thing. Eventually we probably * to do it page-by-page, w/ kmap() if not vmap()d.. */ - ptr = msm_gem_vaddr_locked(&obj->base); + ptr = msm_gem_get_vaddr_locked(&obj->base); if (IS_ERR(ptr)) { ret = PTR_ERR(ptr); @@ -332,6 +332,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob last_offset = off; } + msm_gem_put_vaddr_locked(&obj->base); + return 0; } diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 0857710c2ff2..3eeb8af0c855 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -310,7 +310,7 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) uint32_t iova = submit->cmd[i].iova; uint32_t szd = submit->cmd[i].size; /* in dwords */ struct msm_gem_object *obj = submit->bos[idx].obj; - const char *buf = msm_gem_vaddr_locked(&obj->base); + const char *buf = msm_gem_get_vaddr_locked(&obj->base); if (IS_ERR(buf)) continue; @@ -335,6 +335,8 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) (uint32_t[2]){ iova, szd }, 8); break; } + + msm_gem_put_vaddr_locked(&obj->base); } } #endif diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 42f5359cf988..f326cf6a32e6 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -39,7 +39,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) goto fail; } - ring->start = msm_gem_vaddr_locked(ring->bo); + ring->start = msm_gem_get_vaddr_locked(ring->bo); if (IS_ERR(ring->start)) { ret = PTR_ERR(ring->start); goto fail; @@ -59,7 +59,9 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) void msm_ringbuffer_destroy(struct msm_ringbuffer *ring) { - if (ring->bo) + if (ring->bo) { + msm_gem_put_vaddr(ring->bo); drm_gem_object_unreference_unlocked(ring->bo); + } kfree(ring); } From e1e9db2ca79575b8d6b4b5891194bb29c630c42d Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 27 May 2016 11:16:28 -0400 Subject: [PATCH 39/52] drm/msm: wire up vmap shrinker Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.h | 2 ++ drivers/gpu/drm/msm/msm_gem.c | 25 ++++++++++++---- drivers/gpu/drm/msm/msm_gem.h | 10 +++++++ drivers/gpu/drm/msm/msm_gem_shrinker.c | 40 ++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index ecf0b3b03e0e..b4bc7f1ef717 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -153,6 +153,7 @@ struct msm_drm_private { struct drm_mm mm; } vram; + struct notifier_block vmap_notifier; struct shrinker shrinker; struct msm_vblank_ctrl vblank_ctrl; @@ -206,6 +207,7 @@ void msm_gem_put_vaddr_locked(struct drm_gem_object *obj); void msm_gem_put_vaddr(struct drm_gem_object *obj); int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv); void msm_gem_purge(struct drm_gem_object *obj); +void msm_gem_vunmap(struct drm_gem_object *obj); int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive); void msm_gem_move_to_active(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index c05fc1d0dce7..886cfe0383ff 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -421,6 +421,7 @@ void *msm_gem_get_vaddr_locked(struct drm_gem_object *obj) if (msm_obj->vaddr == NULL) return ERR_PTR(-ENOMEM); } + msm_obj->vmap_count++; return msm_obj->vaddr; } @@ -435,13 +436,17 @@ void *msm_gem_get_vaddr(struct drm_gem_object *obj) void msm_gem_put_vaddr_locked(struct drm_gem_object *obj) { + struct msm_gem_object *msm_obj = to_msm_bo(obj); WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); - /* no-op for now */ + WARN_ON(msm_obj->vmap_count < 1); + msm_obj->vmap_count--; } void msm_gem_put_vaddr(struct drm_gem_object *obj) { - /* no-op for now */ + mutex_lock(&obj->dev->struct_mutex); + msm_gem_put_vaddr_locked(obj); + mutex_unlock(&obj->dev->struct_mutex); } /* Update madvise status, returns true if not purged, else @@ -470,8 +475,7 @@ void msm_gem_purge(struct drm_gem_object *obj) put_iova(obj); - vunmap(msm_obj->vaddr); - msm_obj->vaddr = NULL; + msm_gem_vunmap(obj); put_pages(obj); @@ -491,6 +495,17 @@ void msm_gem_purge(struct drm_gem_object *obj) 0, (loff_t)-1); } +void msm_gem_vunmap(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + if (!msm_obj->vaddr || WARN_ON(!is_vunmapable(msm_obj))) + return; + + vunmap(msm_obj->vaddr); + msm_obj->vaddr = NULL; +} + /* must be called before _move_to_active().. */ int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive) @@ -694,7 +709,7 @@ void msm_gem_free_object(struct drm_gem_object *obj) drm_prime_gem_destroy(obj, msm_obj->sgt); } else { - vunmap(msm_obj->vaddr); + msm_gem_vunmap(obj); put_pages(obj); } diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 631dab56b8fd..7a4da819731a 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -34,6 +34,11 @@ struct msm_gem_object { */ uint8_t madv; + /** + * count of active vmap'ing + */ + uint8_t vmap_count; + /* And object is either: * inactive - on priv->inactive_list * active - on one one of the gpu's active_list.. well, at @@ -83,6 +88,11 @@ static inline bool is_purgeable(struct msm_gem_object *msm_obj) !msm_obj->base.dma_buf && !msm_obj->base.import_attach; } +static inline bool is_vunmapable(struct msm_gem_object *msm_obj) +{ + return (msm_obj->vmap_count == 0) && msm_obj->vaddr; +} + #define MAX_CMDS 4 /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 70fba9baddde..283d2841ba58 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -100,6 +100,42 @@ msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) return freed; } +static int +msm_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr) +{ + struct msm_drm_private *priv = + container_of(nb, struct msm_drm_private, vmap_notifier); + struct drm_device *dev = priv->dev; + struct msm_gem_object *msm_obj; + unsigned unmapped = 0; + bool unlock; + + if (!msm_gem_shrinker_lock(dev, &unlock)) + return NOTIFY_DONE; + + list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) { + if (is_vunmapable(msm_obj)) { + msm_gem_vunmap(&msm_obj->base); + /* since we don't know any better, lets bail after a few + * and if necessary the shrinker will be invoked again. + * Seems better than unmapping *everything* + */ + if (++unmapped >= 15) + break; + } + } + + if (unlock) + mutex_unlock(&dev->struct_mutex); + + *(unsigned long *)ptr += unmapped; + + if (unmapped > 0) + pr_info_ratelimited("Purging %u vmaps\n", unmapped); + + return NOTIFY_DONE; +} + /** * msm_gem_shrinker_init - Initialize msm shrinker * @dev_priv: msm device @@ -113,6 +149,9 @@ void msm_gem_shrinker_init(struct drm_device *dev) priv->shrinker.scan_objects = msm_gem_shrinker_scan; priv->shrinker.seeks = DEFAULT_SEEKS; WARN_ON(register_shrinker(&priv->shrinker)); + + priv->vmap_notifier.notifier_call = msm_gem_shrinker_vmap; + WARN_ON(register_vmap_purge_notifier(&priv->vmap_notifier)); } /** @@ -124,5 +163,6 @@ void msm_gem_shrinker_init(struct drm_device *dev) void msm_gem_shrinker_cleanup(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; + WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier)); unregister_shrinker(&priv->shrinker); } From 6b597ce2f7c7a0f8116d753902db9aba6bc05cb0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 1 Jun 2016 14:17:40 -0400 Subject: [PATCH 40/52] drm/msm: deal with arbitrary # of cmd buffers For some optimizations coming on the userspace side, splitting larger draw or gmem cmds into multiple cmdstream buffers, we need to support much more than the previous small/arbitrary limit. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 11 ++--------- drivers/gpu/drm/msm/msm_gem.h | 4 +--- drivers/gpu/drm/msm/msm_gem_submit.c | 11 +++++------ 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 7dfe22ea2920..f386f463278d 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -139,7 +139,7 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct msm_drm_private *priv = gpu->dev->dev_private; struct msm_ringbuffer *ring = gpu->rb; - unsigned i, ibs = 0; + unsigned i; for (i = 0; i < submit->nr_cmds; i++) { switch (submit->cmd[i].type) { @@ -155,18 +155,11 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2); OUT_RING(ring, submit->cmd[i].iova); OUT_RING(ring, submit->cmd[i].size); - ibs++; + OUT_PKT2(ring); break; } } - /* on a320, at least, we seem to need to pad things out to an - * even number of qwords to avoid issue w/ CP hanging on wrap- - * around: - */ - if (ibs % 2) - OUT_PKT2(ring); - OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1); OUT_RING(ring, submit->fence->seqno); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 7a4da819731a..b2f13cfe945e 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -93,8 +93,6 @@ static inline bool is_vunmapable(struct msm_gem_object *msm_obj) return (msm_obj->vmap_count == 0) && msm_obj->vaddr; } -#define MAX_CMDS 4 - /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, * associated with the cmdstream submission for synchronization (and * make it easier to unwind when things go wrong, etc). This only @@ -116,7 +114,7 @@ struct msm_gem_submit { uint32_t size; /* in dwords */ uint32_t iova; uint32_t idx; /* cmdstream buffer idx in bos[] */ - } cmd[MAX_CMDS]; + } *cmd; /* array of size nr_cmds */ struct { uint32_t flags; struct msm_gem_object *obj; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 736f15881b6a..9766f9ae4b7d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -29,10 +29,11 @@ #define BO_PINNED 0x2000 static struct msm_gem_submit *submit_create(struct drm_device *dev, - struct msm_gpu *gpu, int nr) + struct msm_gpu *gpu, int nr_bos, int nr_cmds) { struct msm_gem_submit *submit; - int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0])); + int sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) + + (nr_cmds * sizeof(*submit->cmd)); submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (!submit) @@ -42,6 +43,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, submit->gpu = gpu; submit->fence = NULL; submit->pid = get_pid(task_pid(current)); + submit->cmd = (void *)&submit->bos[nr_bos]; /* initially, until copy_from_user() and bo lookup succeeds: */ submit->nr_bos = 0; @@ -371,14 +373,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (args->pipe != MSM_PIPE_3D0) return -EINVAL; - if (args->nr_cmds > MAX_CMDS) - return -EINVAL; - ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - submit = submit_create(dev, gpu, args->nr_bos); + submit = submit_create(dev, gpu, args->nr_bos, args->nr_cmds); if (!submit) { ret = -ENOMEM; goto out_unlock; From a8d854c102f880984c9c21241483716ee4054ff2 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 1 Jun 2016 14:02:02 -0400 Subject: [PATCH 41/52] drm/msm: bump kernel api version Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f3b8f69ea9ae..9cfa348fd2bb 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -21,6 +21,16 @@ #include "msm_gpu.h" #include "msm_kms.h" + +/* + * MSM driver version: + * - 1.0.0 - initial interface + * - 1.1.0 - adds madvise, and support for submits with > 4 cmd buffers + */ +#define MSM_VERSION_MAJOR 1 +#define MSM_VERSION_MINOR 1 +#define MSM_VERSION_PATCHLEVEL 0 + static void msm_fb_output_poll_changed(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; @@ -807,8 +817,9 @@ static struct drm_driver msm_driver = { .name = "msm", .desc = "MSM Snapdragon DRM", .date = "20130625", - .major = 1, - .minor = 0, + .major = MSM_VERSION_MAJOR, + .minor = MSM_VERSION_MINOR, + .patchlevel = MSM_VERSION_PATCHLEVEL, }; #ifdef CONFIG_PM_SLEEP From 6507e799f432d9fa86ba398b095ef1139a70deac Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 16 Jun 2016 11:49:09 -0400 Subject: [PATCH 42/52] drm/msm/rd: split out snapshot_buf helper (reduce the noise in next patch) Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_rd.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 3eeb8af0c855..fa02b5a50f31 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -277,6 +277,26 @@ void msm_rd_debugfs_cleanup(struct drm_minor *minor) kfree(rd); } +static void snapshot_buf(struct msm_rd_state *rd, + struct msm_gem_submit *submit, int idx, + uint32_t iova, uint32_t size) +{ + struct msm_gem_object *obj = submit->bos[idx].obj; + const char *buf; + + buf = msm_gem_get_vaddr_locked(&obj->base); + if (IS_ERR(buf)) + return; + + buf += iova - submit->bos[idx].iova; + + rd_write_section(rd, RD_GPUADDR, + (uint32_t[2]){ iova, size }, 8); + rd_write_section(rd, RD_BUFFER_CONTENTS, buf, size); + + msm_gem_put_vaddr_locked(&obj->base); +} + /* called under struct_mutex */ void msm_rd_dump_submit(struct msm_gem_submit *submit) { @@ -306,21 +326,11 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) */ for (i = 0; i < submit->nr_cmds; i++) { - uint32_t idx = submit->cmd[i].idx; uint32_t iova = submit->cmd[i].iova; uint32_t szd = submit->cmd[i].size; /* in dwords */ - struct msm_gem_object *obj = submit->bos[idx].obj; - const char *buf = msm_gem_get_vaddr_locked(&obj->base); - if (IS_ERR(buf)) - continue; - - buf += iova - submit->bos[idx].iova; - - rd_write_section(rd, RD_GPUADDR, - (uint32_t[2]){ iova, szd * 4 }, 8); - rd_write_section(rd, RD_BUFFER_CONTENTS, - buf, szd * 4); + snapshot_buf(rd, submit, submit->cmd[i].idx, + submit->cmd[i].iova, szd * 4); switch (submit->cmd[i].type) { case MSM_SUBMIT_CMD_IB_TARGET_BUF: @@ -335,8 +345,6 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) (uint32_t[2]){ iova, szd }, 8); break; } - - msm_gem_put_vaddr_locked(&obj->base); } } #endif From 79c21187ca370f37302f0d5c16c387985d7b8ba1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 16 Jun 2016 11:54:41 -0400 Subject: [PATCH 43/52] drm/msm/rd: add module param to dump all bo's By default, if using $debugfs/.../rd to log cmdstream, only the cmdstream buffers themselves are logged. But in some cases we want to capture other buffers in the submit (to see VBO's or shaders). So add a mod-param knob to control this. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_rd.c | 38 +++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index fa02b5a50f31..24254e07bcd5 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -27,6 +27,11 @@ * This bypasses drm_debugfs_create_files() mainly because we need to use * our own fops for a bit more control. In particular, we don't want to * do anything if userspace doesn't have the debugfs file open. + * + * The module-param "rd_full", which defaults to false, enables snapshotting + * all (non-written) buffers in the submit, rather than just cmdstream bo's. + * This is useful to capture the contents of (for example) vbo's or textures, + * or shader programs (if not emitted inline in cmdstream). */ #ifdef CONFIG_DEBUG_FS @@ -40,6 +45,10 @@ #include "msm_gpu.h" #include "msm_gem.h" +static bool rd_full = false; +MODULE_PARM_DESC(rd_full, "If true, $debugfs/.../rd will snapshot all buffer contents"); +module_param_named(rd_full, rd_full, bool, 0600); + enum rd_sect_type { RD_NONE, RD_TEST, /* ascii text */ @@ -288,7 +297,12 @@ static void snapshot_buf(struct msm_rd_state *rd, if (IS_ERR(buf)) return; - buf += iova - submit->bos[idx].iova; + if (iova) { + buf += iova - submit->bos[idx].iova; + } else { + iova = submit->bos[idx].iova; + size = obj->base.size; + } rd_write_section(rd, RD_GPUADDR, (uint32_t[2]){ iova, size }, 8); @@ -320,17 +334,27 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); - /* could be nice to have an option (module-param?) to snapshot - * all the bo's associated with the submit. Handy to see vtx - * buffers, etc. For now just the cmdstream bo's is enough. - */ + if (rd_full) { + for (i = 0; i < submit->nr_bos; i++) { + /* buffers that are written to probably don't start out + * with anything interesting: + */ + if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) + continue; + + snapshot_buf(rd, submit, i, 0, 0); + } + } for (i = 0; i < submit->nr_cmds; i++) { uint32_t iova = submit->cmd[i].iova; uint32_t szd = submit->cmd[i].size; /* in dwords */ - snapshot_buf(rd, submit, submit->cmd[i].idx, - submit->cmd[i].iova, szd * 4); + /* snapshot cmdstream bo's (if we haven't already): */ + if (!rd_full) { + snapshot_buf(rd, submit, submit->cmd[i].idx, + submit->cmd[i].iova, szd * 4); + } switch (submit->cmd[i].type) { case MSM_SUBMIT_CMD_IB_TARGET_BUF: From f14270161a236235537338d042015988aac354f9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 10 Jun 2016 10:45:56 +0100 Subject: [PATCH 44/52] drm: msm: Add ASoC generic hdmi audio codec support. This patch adds support to generic audio codec via ASoC hdmi-codec infrastucture which is merged recently. Signed-off-by: Srinivas Kandagatla [rebased on efc9194] Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/msm/hdmi/hdmi.c | 120 +++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/hdmi/hdmi.h | 14 ++++ 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 167a4971f47c..7c7a0314a756 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -10,6 +10,7 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM + select SND_SOC_HDMI_CODEC if SND_SOC default y help DRM/KMS driver for MSM/snapdragon. diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 51b9ea552f97..33bf52c6b312 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -19,6 +19,7 @@ #include #include +#include #include "hdmi.h" void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on) @@ -434,6 +435,114 @@ static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name) return gpio; } +/* + * HDMI audio codec callbacks + */ +static int msm_hdmi_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct hdmi *hdmi = dev_get_drvdata(dev); + unsigned int chan; + unsigned int channel_allocation = 0; + unsigned int rate; + unsigned int level_shift = 0; /* 0dB */ + bool down_mix = false; + + dev_dbg(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate, + params->sample_width, params->cea.channels); + + switch (params->cea.channels) { + case 2: + /* FR and FL speakers */ + channel_allocation = 0; + chan = MSM_HDMI_AUDIO_CHANNEL_2; + break; + case 4: + /* FC, LFE, FR and FL speakers */ + channel_allocation = 0x3; + chan = MSM_HDMI_AUDIO_CHANNEL_4; + break; + case 6: + /* RR, RL, FC, LFE, FR and FL speakers */ + channel_allocation = 0x0B; + chan = MSM_HDMI_AUDIO_CHANNEL_6; + break; + case 8: + /* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */ + channel_allocation = 0x1F; + chan = MSM_HDMI_AUDIO_CHANNEL_8; + break; + default: + return -EINVAL; + } + + switch (params->sample_rate) { + case 32000: + rate = HDMI_SAMPLE_RATE_32KHZ; + break; + case 44100: + rate = HDMI_SAMPLE_RATE_44_1KHZ; + break; + case 48000: + rate = HDMI_SAMPLE_RATE_48KHZ; + break; + case 88200: + rate = HDMI_SAMPLE_RATE_88_2KHZ; + break; + case 96000: + rate = HDMI_SAMPLE_RATE_96KHZ; + break; + case 176400: + rate = HDMI_SAMPLE_RATE_176_4KHZ; + break; + case 192000: + rate = HDMI_SAMPLE_RATE_192KHZ; + break; + default: + dev_err(dev, "rate[%d] not supported!\n", + params->sample_rate); + return -EINVAL; + } + + msm_hdmi_audio_set_sample_rate(hdmi, rate); + msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation, + level_shift, down_mix); + + return 0; +} + +static void msm_hdmi_audio_shutdown(struct device *dev, void *data) +{ + struct hdmi *hdmi = dev_get_drvdata(dev); + + msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0); +} + +static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = { + .hw_params = msm_hdmi_audio_hw_params, + .audio_shutdown = msm_hdmi_audio_shutdown, +}; + +static struct hdmi_codec_pdata codec_data = { + .ops = &msm_hdmi_audio_codec_ops, + .max_i2s_channels = 8, + .i2s = 1, +}; + +static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) +{ + hdmi->audio_pdev = platform_device_register_data(dev, + HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, + &codec_data, + sizeof(codec_data)); + if (IS_ERR(hdmi->audio_pdev)) + return PTR_ERR(hdmi->audio_pdev); + + return 0; +} + static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = dev_get_drvdata(master); @@ -441,7 +550,7 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) static struct hdmi_platform_config *hdmi_cfg; struct hdmi *hdmi; struct device_node *of_node = dev->of_node; - int i; + int i, err; hdmi_cfg = (struct hdmi_platform_config *) of_device_get_match_data(dev); @@ -468,6 +577,12 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(hdmi); priv->hdmi = hdmi; + err = msm_hdmi_register_audio_driver(hdmi, dev); + if (err) { + DRM_ERROR("Failed to attach an audio codec %d\n", err); + hdmi->audio_pdev = NULL; + } + return 0; } @@ -477,6 +592,9 @@ static void msm_hdmi_unbind(struct device *dev, struct device *master, struct drm_device *drm = dev_get_drvdata(master); struct msm_drm_private *priv = drm->dev_private; if (priv->hdmi) { + if (priv->hdmi->audio_pdev) + platform_device_unregister(priv->hdmi->audio_pdev); + msm_hdmi_destroy(priv->hdmi); priv->hdmi = NULL; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index bc7ba0bdee07..accc9a61611d 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -50,6 +50,7 @@ struct hdmi_hdcp_ctrl; struct hdmi { struct drm_device *dev; struct platform_device *pdev; + struct platform_device *audio_pdev; const struct hdmi_platform_config *config; @@ -210,6 +211,19 @@ static inline int msm_hdmi_pll_8996_init(struct platform_device *pdev) /* * audio: */ +/* Supported HDMI Audio channels and rates */ +#define MSM_HDMI_AUDIO_CHANNEL_2 0 +#define MSM_HDMI_AUDIO_CHANNEL_4 1 +#define MSM_HDMI_AUDIO_CHANNEL_6 2 +#define MSM_HDMI_AUDIO_CHANNEL_8 3 + +#define HDMI_SAMPLE_RATE_32KHZ 0 +#define HDMI_SAMPLE_RATE_44_1KHZ 1 +#define HDMI_SAMPLE_RATE_48KHZ 2 +#define HDMI_SAMPLE_RATE_88_2KHZ 3 +#define HDMI_SAMPLE_RATE_96KHZ 4 +#define HDMI_SAMPLE_RATE_176_4KHZ 5 +#define HDMI_SAMPLE_RATE_192KHZ 6 int msm_hdmi_audio_update(struct hdmi *hdmi); int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, From 2abe1f2509bf4976dce9a220cab3f1424f0cbb0f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 18 Jun 2016 17:26:37 +0000 Subject: [PATCH 45/52] drm/msm/dsi: Fix return value check in msm_dsi_host_set_display_mode() In case of error, the function drm_mode_duplicate() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Signed-off-by: Wei Yongjun Reviewed-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index ddc4c7d678ed..f05ed0e1f3d6 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -2278,9 +2278,9 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, } msm_host->mode = drm_mode_duplicate(msm_host->dev, mode); - if (IS_ERR(msm_host->mode)) { + if (!msm_host->mode) { pr_err("%s: cannot duplicate mode\n", __func__); - return PTR_ERR(msm_host->mode); + return -ENOMEM; } return 0; From d13b33fa7d76b8f7cbf0212d570aa82887b6db0f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 9 Jun 2016 02:32:10 +0300 Subject: [PATCH 46/52] drm/msm: Replace drm_fb_get_bpp_depth() with drm_format_plane_cpp() The driver needs the number of bytes per pixel, not the bpp and depth info meant for fbdev compatibility. Use the right API. Signed-off-by: Laurent Pinchart Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 4e8ed739f558..fa2be7ce9468 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -490,8 +490,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, struct mdp5_kms *mdp5_kms = get_kms(crtc); struct drm_gem_object *cursor_bo, *old_bo = NULL; uint32_t blendcfg, cursor_addr, stride; - int ret, bpp, lm; - unsigned int depth; + int ret, lm; enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL; uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0); uint32_t roi_w, roi_h; @@ -521,8 +520,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; lm = mdp5_crtc->lm; - drm_fb_get_bpp_depth(DRM_FORMAT_ARGB8888, &depth, &bpp); - stride = width * (bpp >> 3); + stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0); spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags); old_bo = mdp5_crtc->cursor.scanout_bo; From 2ca41c176a5d2197572153bf543a3f758c13a4d3 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 4 Jul 2016 16:49:50 +0800 Subject: [PATCH 47/52] drm/msm: add missing of_node_put after calling of_parse_phandle of_node_put needs to be called when the device node which is got from of_parse_phandle has finished using. Signed-off-by: Peter Chen [rebased on top of Archit's DT rework, so looses one hunk] Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9cfa348fd2bb..26f859ec24b3 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -294,6 +294,7 @@ static int msm_init_vram(struct drm_device *dev) if (node) { struct resource r; ret = of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) return ret; size = r.end - r.start; From 06f3217207766b4bc2e56b88e0736037ae92fd30 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Jul 2016 11:06:52 +0000 Subject: [PATCH 48/52] drm/msm/hdmi: use PTR_ERR_OR_ZERO() to simplify the code Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR. Generated by: scripts/coccinelle/api/ptr_ret.cocci Signed-off-by: Wei Yongjun Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/hdmi/hdmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 33bf52c6b312..973720792236 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -537,10 +537,7 @@ static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) PLATFORM_DEVID_AUTO, &codec_data, sizeof(codec_data)); - if (IS_ERR(hdmi->audio_pdev)) - return PTR_ERR(hdmi->audio_pdev); - - return 0; + return PTR_ERR_OR_ZERO(hdmi->audio_pdev); } static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) From 5745d21f9a92fa3b70149df69574a13becc3d53e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Jul 2016 13:35:29 +0300 Subject: [PATCH 49/52] drm/msm: return -EFAULT instead of bytes remaining copy_to/from_user returns the number of bytes remaining to be copied but we want to return -EFAULT. Signed-off-by: Dan Carpenter Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_perf.c | 7 ++++--- drivers/gpu/drm/msm/msm_rd.c | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c index 830857c47c86..17fe4e53e0d1 100644 --- a/drivers/gpu/drm/msm/msm_perf.c +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -132,7 +132,7 @@ static ssize_t perf_read(struct file *file, char __user *buf, size_t sz, loff_t *ppos) { struct msm_perf_state *perf = file->private_data; - int n = 0, ret; + int n = 0, ret = 0; mutex_lock(&perf->read_lock); @@ -143,9 +143,10 @@ static ssize_t perf_read(struct file *file, char __user *buf, } n = min((int)sz, perf->buftot - perf->bufpos); - ret = copy_to_user(buf, &perf->buf[perf->bufpos], n); - if (ret) + if (copy_to_user(buf, &perf->buf[perf->bufpos], n)) { + ret = -EFAULT; goto out; + } perf->bufpos += n; *ppos += n; diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 24254e07bcd5..3a5fdfcd67ae 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -149,9 +149,10 @@ static ssize_t rd_read(struct file *file, char __user *buf, goto out; n = min_t(int, sz, circ_count_to_end(&rd->fifo)); - ret = copy_to_user(buf, fptr, n); - if (ret) + if (copy_to_user(buf, fptr, n)) { + ret = -EFAULT; goto out; + } fifo->tail = (fifo->tail + n) & (BUF_SZ - 1); *ppos += n; From 851dd75d64dbfc9a97d5109659e82e95d6bbe5bf Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 13 Jul 2016 18:54:11 +0200 Subject: [PATCH 50/52] drm/msm/hdmi: Delete an unnecessary check before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c index 0baaaaabd002..6e767979aab3 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c @@ -1430,7 +1430,7 @@ struct hdmi_hdcp_ctrl *msm_hdmi_hdcp_init(struct hdmi *hdmi) void msm_hdmi_hdcp_destroy(struct hdmi *hdmi) { - if (hdmi && hdmi->hdcp_ctrl) { + if (hdmi) { kfree(hdmi->hdcp_ctrl); hdmi->hdcp_ctrl = NULL; } From e73a8569731aebd21832b34bf7ce8121dec2e98d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 13 Jul 2016 19:15:35 +0200 Subject: [PATCH 51/52] drm/msm: Delete unnecessary checks before drm_gem_object_unreference_unlocked() The drm_gem_object_unreference_unlocked() function tests whether its argument is NULL and then returns immediately. Thus the test around the calls is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 3 +-- drivers/gpu/drm/msm/msm_fb.c | 4 ++-- drivers/gpu/drm/msm/msm_gem.c | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index ba8df15605d7..7b39e89fbc2b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -168,8 +168,7 @@ static void mdp4_destroy(struct msm_kms *kms) if (mdp4_kms->blank_cursor_iova) msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id); - if (mdp4_kms->blank_cursor_bo) - drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); + drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); if (mdp4_kms->rpm_enabled) pm_runtime_disable(dev); diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index 7919c24c6ddd..95cf8fe72ee5 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -49,8 +49,8 @@ static void msm_framebuffer_destroy(struct drm_framebuffer *fb) for (i = 0; i < n; i++) { struct drm_gem_object *bo = msm_fb->planes[i]; - if (bo) - drm_gem_object_unreference_unlocked(bo); + + drm_gem_object_unreference_unlocked(bo); } kfree(msm_fb); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 886cfe0383ff..9a713fbb2d01 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -875,8 +875,6 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, return obj; fail: - if (obj) - drm_gem_object_unreference_unlocked(obj); - + drm_gem_object_unreference_unlocked(obj); return ERR_PTR(ret); } From 0a677125d0ff726ed3d75ab311cf54674bf512bc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 13 Jul 2016 19:29:19 +0200 Subject: [PATCH 52/52] drm/msm: Delete an unnecessary check before drm_gem_object_unreference() The drm_gem_object_unreference() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 9a713fbb2d01..6cd4af443139 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -830,9 +830,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, return obj; fail: - if (obj) - drm_gem_object_unreference(obj); - + drm_gem_object_unreference(obj); return ERR_PTR(ret); }