[Freedreno] [PATCH v3 3/4] drm/msm: re-factor devfreq code

2018-08-30 Thread Sharat Masetty
The devfreq framework requires the drivers to provide busy time estimations.
The GPU driver relies on the hardware performance counteres for the busy time
estimations, but different hardware revisions have counters which can be
sourced from different clocks. So the busy time estimation will be target
dependent.  Additionally on targets where the clocks are completely controlled
by the on chip microcontroller, fetching and setting the current GPU frequency
will be different. This patch aims to embrace these differences by re-factoring
the devfreq code a bit.

Signed-off-by: Sharat Masetty 
---
 drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 16 +---
 drivers/gpu/drm/msm/msm_gpu.c | 49 ---
 drivers/gpu/drm/msm/msm_gpu.h |  5 +++-
 3 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c 
b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 897f3e2..043e680 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1369,12 +1369,20 @@ static struct msm_ringbuffer *a5xx_active_ring(struct 
msm_gpu *gpu)
return a5xx_gpu->cur_ring;
 }
 
-static int a5xx_gpu_busy(struct msm_gpu *gpu, uint64_t *value)
+static unsigned long a5xx_gpu_busy(struct msm_gpu *gpu)
 {
-   *value = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO,
-   REG_A5XX_RBBM_PERFCTR_RBBM_0_HI);
+   u64 busy_cycles;
+   unsigned long busy_time;
 
-   return 0;
+   busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO,
+   REG_A5XX_RBBM_PERFCTR_RBBM_0_HI);
+
+   busy_time = (busy_cycles - gpu->devfreq.busy_cycles) /
+   (clk_get_rate(gpu->core_clk) / 100);
+
+   gpu->devfreq.busy_cycles = busy_cycles;
+
+   return busy_time;
 }
 
 static const struct adreno_gpu_funcs funcs = {
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 04f9604..6a2569a 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -36,12 +36,16 @@ static int msm_devfreq_target(struct device *dev, unsigned 
long *freq,
struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
struct dev_pm_opp *opp;
 
-   opp = dev_pm_opp_find_freq_ceil(dev, freq);
+   opp = devfreq_recommended_opp(dev, freq, flags);
+   if (IS_ERR(opp))
+   return PTR_ERR(opp);
 
-   if (!IS_ERR(opp)) {
+   if (gpu->funcs->gpu_set_freq)
+   gpu->funcs->gpu_set_freq(gpu, (u64)*freq);
+   else
clk_set_rate(gpu->core_clk, *freq);
-   dev_pm_opp_put(opp);
-   }
+
+   dev_pm_opp_put(opp);
 
return 0;
 }
@@ -50,16 +54,14 @@ static int msm_devfreq_get_dev_status(struct device *dev,
struct devfreq_dev_status *status)
 {
struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
-   u64 cycles;
ktime_t time;
 
-   status->current_frequency = (unsigned long) clk_get_rate(gpu->core_clk);
-   gpu->funcs->gpu_busy(gpu, );
-
-   status->busy_time = (cycles - gpu->devfreq.busy_cycles) /
-   (status->current_frequency / 100);
+   if (gpu->funcs->gpu_get_freq)
+   status->current_frequency = gpu->funcs->gpu_get_freq(gpu);
+   else
+   status->current_frequency = clk_get_rate(gpu->core_clk);
 
-   gpu->devfreq.busy_cycles = cycles;
+   status->busy_time = gpu->funcs->gpu_busy(gpu);
 
time = ktime_get();
status->total_time = ktime_us_delta(time, gpu->devfreq.time);
@@ -72,7 +74,10 @@ static int msm_devfreq_get_cur_freq(struct device *dev, 
unsigned long *freq)
 {
struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
 
-   *freq = (unsigned long) clk_get_rate(gpu->core_clk);
+   if (gpu->funcs->gpu_get_freq)
+   *freq = gpu->funcs->gpu_get_freq(gpu);
+   else
+   *freq = clk_get_rate(gpu->core_clk);
 
return 0;
 }
@@ -87,7 +92,7 @@ static int msm_devfreq_get_cur_freq(struct device *dev, 
unsigned long *freq)
 static void msm_devfreq_init(struct msm_gpu *gpu)
 {
/* We need target support to do devfreq */
-   if (!gpu->funcs->gpu_busy || !gpu->core_clk)
+   if (!gpu->funcs->gpu_busy)
return;
 
msm_devfreq_profile.initial_freq = gpu->fast_rate;
@@ -185,6 +190,14 @@ static int disable_axi(struct msm_gpu *gpu)
return 0;
 }
 
+void msm_gpu_resume_devfreq(struct msm_gpu *gpu)
+{
+   gpu->devfreq.busy_cycles = 0;
+   gpu->devfreq.time = ktime_get();
+
+   devfreq_resume_device(gpu->devfreq.devfreq);
+}
+
 int msm_gpu_pm_resume(struct msm_gpu *gpu)
 {
int ret;
@@ -203,12 +216,7 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
if (ret)
return ret;
 
-   if (gpu->devfreq.devfreq) {
-   gpu->devfreq.busy_cycles = 0;
-   gpu->devfreq.time = 

[Freedreno] [PATCH v3 2/4] drm/msm/A6xx: Add gmu_read64() register read op

2018-08-30 Thread Sharat Masetty
Add a simple function to read 64 registers in the GMU domain

Signed-off-by: Sharat Masetty 
---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index a08ee8f..09fd3a7 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -106,6 +106,16 @@ static inline void gmu_rmw(struct a6xx_gmu *gmu, u32 reg, 
u32 mask, u32 or)
gmu_write(gmu, reg, val | or);
 }
 
+static inline u64 gmu_read64(struct a6xx_gmu *gmu, u32 lo, u32 hi)
+{
+   u64 val;
+
+   val = (u64) msm_readl(gmu->mmio + (lo << 2));
+   val |= ((u64) msm_readl(gmu->mmio + (hi << 2)) << 32);
+
+   return val;
+}
+
 #define gmu_poll_timeout(gmu, addr, val, cond, interval, timeout) \
readl_poll_timeout((gmu)->mmio + ((addr) << 2), val, cond, \
interval, timeout)
-- 
1.9.1

___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH v3 4/4] drm/msm/A6xx: Add devfreq support for A6xx

2018-08-30 Thread Sharat Masetty
Implement routines to estimate GPU busy time and fetching the
current frequency for the polling interval. This is required by
the devfreq framework which recommends a frequency change if needed.
The driver code then tries to set this new frequency on the GPU by
sending an Out Of Band(OOB) request to the GMU.

Signed-off-by: Sharat Masetty 
---
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 39 +++
 drivers/gpu/drm/msm/adreno/a6xx_gmu.h |  2 ++
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 27 
 drivers/gpu/drm/msm/adreno/a6xx_gpu.h |  2 ++
 4 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index f6634c0..27cc800 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -67,7 +67,7 @@ static bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu)
A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF));
 }
 
-static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
+static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
 {
gmu_write(gmu, REG_A6XX_GMU_DCVS_ACK_OPTION, 0);
 
@@ -84,7 +84,38 @@ static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index)
a6xx_gmu_set_oob(gmu, GMU_OOB_DCVS_SET);
a6xx_gmu_clear_oob(gmu, GMU_OOB_DCVS_SET);
 
-   return gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN);
+   if (gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN) != 0) {
+   dev_err_ratelimited(gmu->dev, "Unable to set GPU frequency\n");
+   return;
+   }
+
+   gmu->freq = gmu->gpu_freqs[index];
+}
+
+void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq)
+{
+   struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+   struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+   struct a6xx_gmu *gmu = _gpu->gmu;
+   u32 perf_index = 0;
+
+   if (freq == gmu->freq)
+   return;
+
+   for (perf_index = 0; perf_index < gmu->nr_gpu_freqs - 1; perf_index++)
+   if (freq == gmu->gpu_freqs[perf_index])
+   break;
+
+   __a6xx_gmu_set_freq(gmu, perf_index);
+}
+
+unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu)
+{
+   struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+   struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+   struct a6xx_gmu *gmu = _gpu->gmu;
+
+   return  gmu->freq;
 }
 
 static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu)
@@ -630,7 +661,7 @@ int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu)
ret = a6xx_hfi_start(gmu, GMU_COLD_BOOT);
 
/* Set the GPU back to the highest power frequency */
-   a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
+   __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
 
 out:
if (ret)
@@ -671,7 +702,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
ret = a6xx_hfi_start(gmu, status);
 
/* Set the GPU to the highest power frequency */
-   a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
+   __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1);
 
 out:
/* Make sure to turn off the boot OOB request on error */
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h 
b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
index 09fd3a7..13b064f 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h
@@ -77,6 +77,8 @@ struct a6xx_gmu {
unsigned long gmu_freqs[4];
u32 cx_arc_votes[4];
 
+   unsigned long freq;
+
struct a6xx_hfi_queue queues[2];
 
struct tasklet_struct hfi_tasklet;
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c 
b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 3429d33a..af90706 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -7,6 +7,8 @@
 #include "a6xx_gpu.h"
 #include "a6xx_gmu.xml.h"
 
+#include 
+
 static inline bool _a6xx_check_idle(struct msm_gpu *gpu)
 {
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -682,6 +684,8 @@ static int a6xx_pm_resume(struct msm_gpu *gpu)
 
gpu->needs_hw_init = true;
 
+   msm_gpu_resume_devfreq(gpu);
+
return ret;
 }
 
@@ -690,6 +694,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
 
+   devfreq_suspend_device(gpu->devfreq.devfreq);
+
/*
 * Make sure the GMU is idle before continuing (because some transitions
 * may use VBIF
@@ -753,6 +759,24 @@ static void a6xx_destroy(struct msm_gpu *gpu)
kfree(a6xx_gpu);
 }
 
+static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu)
+{
+   struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+   struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
+   u64 busy_cycles;
+   unsigned long busy_time;
+
+   busy_cycles = gmu_read64(_gpu->gmu,
+   

Re: [Freedreno] [PATCH 08/14] drm/msm/dpu: avoid querying for hw intf before assignment

2018-08-30 Thread Sean Paul
On Tue, Aug 28, 2018 at 05:39:57PM -0700, Jeykumar Sankaran wrote:
> Resource manager assigns hw_intf blocks for the encoder only on
> modeset. If queried for hw_intf objects during init, it will be
> NULL. Since hw_intf objects are needed only during encoder enable,

s/during/after/ it looks like you need it on disable as well.

> defer the query to encoder enable which will be triggered after
> modeset.
> 

Missing changelog again.

With that,

Reviewed-by: Sean Paul 


> Signed-off-by: Jeykumar Sankaran 
> ---
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 53 
> +++---
>  1 file changed, 16 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> index ca0963c..6de13f4 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> @@ -462,7 +462,7 @@ static void dpu_encoder_phys_vid_enable(struct 
> dpu_encoder_phys *phys_enc)
>  {
>   struct msm_drm_private *priv;
>   struct dpu_encoder_phys_vid *vid_enc;
> - struct dpu_hw_intf *intf;
> + struct dpu_rm_hw_iter iter;
>   struct dpu_hw_ctl *ctl;
>   u32 flush_mask = 0;
>  
> @@ -474,11 +474,20 @@ static void dpu_encoder_phys_vid_enable(struct 
> dpu_encoder_phys *phys_enc)
>   priv = phys_enc->parent->dev->dev_private;
>  
>   vid_enc = to_dpu_encoder_phys_vid(phys_enc);
> - intf = vid_enc->hw_intf;
>   ctl = phys_enc->hw_ctl;
> - if (!vid_enc->hw_intf || !phys_enc->hw_ctl) {
> - DPU_ERROR("invalid hw_intf %d hw_ctl %d\n",
> - vid_enc->hw_intf != 0, phys_enc->hw_ctl != 0);
> +
> + dpu_rm_init_hw_iter(, phys_enc->parent->base.id, DPU_HW_BLK_INTF);
> + while (dpu_rm_get_hw(_enc->dpu_kms->rm, )) {
> + struct dpu_hw_intf *hw_intf = (struct dpu_hw_intf *)iter.hw;
> +
> + if (hw_intf->idx == phys_enc->intf_idx) {
> + vid_enc->hw_intf = hw_intf;
> + break;
> + }
> + }
> +
> + if (!vid_enc->hw_intf) {
> + DPU_ERROR("hw_intf not assigned\n");
>   return;
>   }
>  
> @@ -500,7 +509,7 @@ static void dpu_encoder_phys_vid_enable(struct 
> dpu_encoder_phys *phys_enc)
>   !dpu_encoder_phys_vid_is_master(phys_enc))
>   goto skip_flush;
>  
> - ctl->ops.get_bitmask_intf(ctl, _mask, intf->idx);
> + ctl->ops.get_bitmask_intf(ctl, _mask, vid_enc->hw_intf->idx);
>   ctl->ops.update_pending_flush(ctl, flush_mask);
>  
>  skip_flush:
> @@ -531,22 +540,13 @@ static void dpu_encoder_phys_vid_get_hw_resources(
>   struct dpu_encoder_hw_resources *hw_res,
>   struct drm_connector_state *conn_state)
>  {
> - struct dpu_encoder_phys_vid *vid_enc;
> -
>   if (!phys_enc || !hw_res) {
>   DPU_ERROR("invalid arg(s), enc %d hw_res %d conn_state %d\n",
>   phys_enc != 0, hw_res != 0, conn_state != 0);
>   return;
>   }
>  
> - vid_enc = to_dpu_encoder_phys_vid(phys_enc);
> - if (!vid_enc->hw_intf) {
> - DPU_ERROR("invalid arg(s), hw_intf\n");
> - return;
> - }
> -
> - DPU_DEBUG_VIDENC(vid_enc, "\n");
> - hw_res->intfs[vid_enc->hw_intf->idx - INTF_0] = INTF_MODE_VIDEO;
> + hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_VIDEO;
>  }
>  
>  static int _dpu_encoder_phys_vid_wait_for_vblank(
> @@ -781,7 +781,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init(
>  {
>   struct dpu_encoder_phys *phys_enc = NULL;
>   struct dpu_encoder_phys_vid *vid_enc = NULL;
> - struct dpu_rm_hw_iter iter;
>   struct dpu_encoder_irq *irq;
>   int i, ret = 0;
>  
> @@ -801,26 +800,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init(
>   phys_enc->hw_mdptop = p->dpu_kms->hw_mdp;
>   phys_enc->intf_idx = p->intf_idx;
>  
> - /**
> -  * hw_intf resource permanently assigned to this encoder
> -  * Other resources allocated at atomic commit time by use case
> -  */
> - dpu_rm_init_hw_iter(, 0, DPU_HW_BLK_INTF);
> - while (dpu_rm_get_hw(>dpu_kms->rm, )) {
> - struct dpu_hw_intf *hw_intf = (struct dpu_hw_intf *)iter.hw;
> -
> - if (hw_intf->idx == p->intf_idx) {
> - vid_enc->hw_intf = hw_intf;
> - break;
> - }
> - }
> -
> - if (!vid_enc->hw_intf) {
> - ret = -EINVAL;
> - DPU_ERROR("failed to get hw_intf\n");
> - goto fail;
> - }
> -
>   DPU_DEBUG_VIDENC(vid_enc, "\n");
>  
>   dpu_encoder_phys_vid_init_ops(_enc->ops);
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS
___
Freedreno 

Re: [Freedreno] [PATCH 07/14] drm/msm/dpu: iterate for assigned hw ctl in virtual encoder

2018-08-30 Thread Sean Paul
On Tue, Aug 28, 2018 at 05:39:56PM -0700, Jeykumar Sankaran wrote:
> Instead of iterating for hw ctrl per physical encoder, this
> patch moves the iterations and assignment to the virtual encoder.
> 

Missing "Changes in" section as well as _why_ you're doing this in your
description.

> Signed-off-by: Jeykumar Sankaran 
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 22 
> +++---
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c   | 19 ---
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 19 ---
>  3 files changed, 19 insertions(+), 41 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index b223bd2..dbf669e 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -1011,9 +1011,10 @@ static void dpu_encoder_virt_mode_set(struct 
> drm_encoder *drm_enc,
>   struct dpu_kms *dpu_kms;
>   struct list_head *connector_list;
>   struct drm_connector *conn = NULL, *conn_iter;
> - struct dpu_rm_hw_iter pp_iter;
> + struct dpu_rm_hw_iter pp_iter, ctl_iter;
>   struct msm_display_topology topology;
>   enum dpu_rm_topology_name topology_name;
> + struct dpu_hw_ctl *hw_ctl[MAX_CHANNELS_PER_ENC] = { NULL };
>   int i = 0, ret;
>  
>   if (!drm_enc) {
> @@ -1061,17 +1062,32 @@ static void dpu_encoder_virt_mode_set(struct 
> drm_encoder *drm_enc,
>   dpu_enc->hw_pp[i] = (struct dpu_hw_pingpong *) pp_iter.hw;
>   }
>  
> + dpu_rm_init_hw_iter(_iter, drm_enc->base.id, DPU_HW_BLK_CTL);
> + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
> + if (!dpu_rm_get_hw(_kms->rm, _iter))
> + break;
> + hw_ctl[i] = (struct dpu_hw_ctl *)ctl_iter.hw;
> + }
> +
>   topology_name = dpu_rm_get_topology_name(topology);
>   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
>   struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
>  
>   if (phys) {
>   if (!dpu_enc->hw_pp[i]) {
> - DPU_ERROR_ENC(dpu_enc,
> - "invalid pingpong block for the encoder\n");
> + DPU_ERROR_ENC(dpu_enc, "no pp block assigned"
> +  "at idx: %d\n", i);
>   return;
>   }
>   phys->hw_pp = dpu_enc->hw_pp[i];
> +
> + if (!hw_ctl[i]) {

Should you check this before you assign hw_pp?

> + DPU_ERROR_ENC(dpu_enc, "no ctl block assigned"
> +  "at idx: %d\n", i);
> + return;
> + }
> + phys->hw_ctl = hw_ctl[i];
> +
>   phys->connector = conn->state->connector;
>   phys->topology_name = topology_name;
>   if (phys->ops.mode_set)
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
> index c8c4612..5c89868 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
> @@ -196,9 +196,6 @@ static void dpu_encoder_phys_cmd_mode_set(
>  {
>   struct dpu_encoder_phys_cmd *cmd_enc =
>   to_dpu_encoder_phys_cmd(phys_enc);
> - struct dpu_rm *rm = _enc->dpu_kms->rm;
> - struct dpu_rm_hw_iter iter;
> - int i, instance;
>  
>   if (!phys_enc || !mode || !adj_mode) {
>   DPU_ERROR("invalid args\n");
> @@ -208,22 +205,6 @@ static void dpu_encoder_phys_cmd_mode_set(
>   DPU_DEBUG_CMDENC(cmd_enc, "caching mode:\n");
>   drm_mode_debug_printmodeline(adj_mode);
>  
> - instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0;
> -
> - /* Retrieve previously allocated HW Resources. Shouldn't fail */
> - dpu_rm_init_hw_iter(, phys_enc->parent->base.id, DPU_HW_BLK_CTL);
> - for (i = 0; i <= instance; i++) {
> - if (dpu_rm_get_hw(rm, ))
> - phys_enc->hw_ctl = (struct dpu_hw_ctl *)iter.hw;
> - }
> -
> - if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) {
> - DPU_ERROR_CMDENC(cmd_enc, "failed to init ctl: %ld\n",
> - PTR_ERR(phys_enc->hw_ctl));
> - phys_enc->hw_ctl = NULL;
> - return;
> - }
> -
>   _dpu_encoder_phys_cmd_setup_irq_hw_idx(phys_enc);
>  }
>  
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> index ecb8c65..ca0963c 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> @@ -395,9 +395,6 @@ static void dpu_encoder_phys_vid_mode_set(
>   struct drm_display_mode 

Re: [Freedreno] [PATCH 05/14] drm/msm/dpu: enable master-slave encoders explicitly

2018-08-30 Thread Sean Paul
On Tue, Aug 28, 2018 at 05:39:54PM -0700, Jeykumar Sankaran wrote:
> Identify slave-master encoders during initialization and enable
> the encoders explicitly as the current logic has redundant and
> ambiguous loops.

Please include a "Changes in vX" section so I don't need to figure it out 
myself.

> 
> Signed-off-by: Jeykumar Sankaran 
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 46 
> ++---
>  1 file changed, 15 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 991b22c..b223bd2 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -180,6 +180,7 @@ struct dpu_encoder_virt {
>   unsigned int num_phys_encs;
>   struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
>   struct dpu_encoder_phys *cur_master;
> + struct dpu_encoder_phys *cur_slave;
>   struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
>  
>   bool intfs_swapped;
> @@ -1141,7 +1142,8 @@ void dpu_encoder_virt_restore(struct drm_encoder 
> *drm_enc)
>  static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
>  {
>   struct dpu_encoder_virt *dpu_enc = NULL;
> - int i, ret = 0;
> + struct dpu_encoder_phys *phys  = NULL;
> + int ret = 0;
>   struct drm_display_mode *cur_mode = NULL;
>  
>   if (!drm_enc) {
> @@ -1154,21 +1156,14 @@ static void dpu_encoder_virt_enable(struct 
> drm_encoder *drm_enc)
>   trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
>cur_mode->vdisplay);
>  
> - dpu_enc->cur_master = NULL;
> - for (i = 0; i < dpu_enc->num_phys_encs; i++) {
> - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
> + /* always enable slave encoder before master */
> + phys = dpu_enc->cur_slave;

I think this variable makes things less readable. It made sense in the loop 
since
you're indented an extra level and they're obfuscated anyways, but since they're
explicit now, could you please just use dpu_enc->cur_slave/master directly?

With this nit and the added changelog in the commit addressed,

Reviewed-by: Sean Paul 


> + if (phys && phys->ops.enable)
> + phys->ops.enable(phys);
>  
> - if (phys && phys->ops.is_master && phys->ops.is_master(phys)) {
> - DPU_DEBUG_ENC(dpu_enc, "master is now idx %d\n", i);
> - dpu_enc->cur_master = phys;
> - break;
> - }
> - }
> -
> - if (!dpu_enc->cur_master) {
> - DPU_ERROR("virt encoder has no master! num_phys %d\n", i);
> - return;
> - }
> + phys = dpu_enc->cur_master;
> + if (phys && phys->ops.enable)
> + phys->ops.enable(phys);
>  
>   ret = dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_KICKOFF);
>   if (ret) {
> @@ -1177,21 +1172,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
> *drm_enc)
>   return;
>   }
>  
> - for (i = 0; i < dpu_enc->num_phys_encs; i++) {
> - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
> -
> - if (!phys)
> - continue;
> -
> - if (phys != dpu_enc->cur_master) {
> - if (phys->ops.enable)
> - phys->ops.enable(phys);
> - }
> - }
> -
> - if (dpu_enc->cur_master->ops.enable)
> - dpu_enc->cur_master->ops.enable(dpu_enc->cur_master);
> -
>   _dpu_encoder_virt_enable_helper(drm_enc);
>  }
>  
> @@ -2062,6 +2042,11 @@ static int dpu_encoder_virt_add_phys_encs(
>   ++dpu_enc->num_phys_encs;
>   }
>  
> + if (params->split_role == ENC_ROLE_SLAVE)
> + dpu_enc->cur_slave = enc;
> + else
> + dpu_enc->cur_master = enc;
> +
>   return 0;
>  }
>  
> @@ -2228,7 +2213,6 @@ int dpu_encoder_setup(struct drm_device *dev, struct 
> drm_encoder *enc,
>   if (ret)
>   goto fail;
>  
> - dpu_enc->cur_master = NULL;
>   spin_lock_init(_enc->enc_spinlock);
>  
>   atomic_set(_enc->frame_done_timeout, 0);
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


Re: [Freedreno] [PATCH 01/14] drm/msm/dpu: remove debugfs support for misr

2018-08-30 Thread Sean Paul
On Tue, Aug 28, 2018 at 05:39:50PM -0700, Jeykumar Sankaran wrote:
> Strip down debugfs support for misr data read on layer mixers
> and interfaces.

Could you please start explaining not only the what, but also the why? I'm
certain there's a very good reason for this change, however you don't state it,
so I'm left to figure it out on my own. No one has ever said "your commit
message is too detailed, please make it more vague" :)

> 
> Signed-off-by: Jeykumar Sankaran 
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   | 139 
> -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h   |   6 -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 127 ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   6 -
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  28 -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  29 -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h|   7 --
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c  |  29 -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h  |   7 --
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c|   3 -
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h|   6 -
>  11 files changed, 387 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index 07c2d15..a4fab042 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -47,8 +47,6 @@
>  #define LEFT_MIXER 0
>  #define RIGHT_MIXER 1
>  
> -#define MISR_BUFF_SIZE   256
> -
>  static inline struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
>  {
>   struct msm_drm_private *priv;
> @@ -1272,8 +1270,6 @@ static void dpu_crtc_handle_power_event(u32 event_type, 
> void *arg)
>   struct drm_crtc *crtc = arg;
>   struct dpu_crtc *dpu_crtc;
>   struct drm_encoder *encoder;
> - struct dpu_crtc_mixer *m;
> - u32 i, misr_status;
>  
>   if (!crtc) {
>   DPU_ERROR("invalid crtc\n");
> @@ -1294,29 +1290,8 @@ static void dpu_crtc_handle_power_event(u32 
> event_type, void *arg)
>  
>   dpu_encoder_virt_restore(encoder);
>   }
> -
> - for (i = 0; i < dpu_crtc->num_mixers; ++i) {
> - m = _crtc->mixers[i];
> - if (!m->hw_lm || !m->hw_lm->ops.setup_misr ||
> - !dpu_crtc->misr_enable)
> - continue;
> -
> - m->hw_lm->ops.setup_misr(m->hw_lm, true,
> - dpu_crtc->misr_frame_count);
> - }
>   break;
>   case DPU_POWER_EVENT_PRE_DISABLE:

It looks like no one uses PRE_DISABLE now so it can be removed, ditto for
PRE_ENABLE. Since they're called at the same time anyways, lets just merge
PRE/POST_ENABLE/DISABLE into DPU_POWER_EVENT_ENABLE and DPU_POWER_EVENT_DISABLE.

In a separate patch, of course.

> - for (i = 0; i < dpu_crtc->num_mixers; ++i) {
> - m = _crtc->mixers[i];
> - if (!m->hw_lm || !m->hw_lm->ops.collect_misr ||
> - !dpu_crtc->misr_enable)
> - continue;
> -
> - misr_status = m->hw_lm->ops.collect_misr(m->hw_lm);
> - dpu_crtc->misr_data[i] = misr_status ? misr_status :
> - dpu_crtc->misr_data[i];
> - }
> - break;
>   case DPU_POWER_EVENT_POST_DISABLE:
>   /**
>* Nothing to do. All the planes on the CRTC will be
> @@ -1847,113 +1822,6 @@ static int _dpu_debugfs_status_open(struct inode 
> *inode, struct file *file)
>   return single_open(file, _dpu_debugfs_status_show, inode->i_private);
>  }
>  
> -static ssize_t _dpu_crtc_misr_setup(struct file *file,
> - const char __user *user_buf, size_t count, loff_t *ppos)
> -{
> - struct dpu_crtc *dpu_crtc;
> - struct dpu_crtc_mixer *m;
> - int i = 0, rc;
> - char buf[MISR_BUFF_SIZE + 1];
> - u32 frame_count, enable;
> - size_t buff_copy;
> -
> - if (!file || !file->private_data)
> - return -EINVAL;
> -
> - dpu_crtc = file->private_data;
> - buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
> - if (copy_from_user(buf, user_buf, buff_copy)) {
> - DPU_ERROR("buffer copy failed\n");
> - return -EINVAL;
> - }
> -
> - buf[buff_copy] = 0; /* end of string */
> -
> - if (sscanf(buf, "%u %u", , _count) != 2)
> - return -EINVAL;
> -
> - rc = _dpu_crtc_power_enable(dpu_crtc, true);
> - if (rc)
> - return rc;
> -
> - mutex_lock(_crtc->crtc_lock);
> - dpu_crtc->misr_enable = enable;
> - dpu_crtc->misr_frame_count = frame_count;
> - for (i = 0; i < dpu_crtc->num_mixers; ++i) {
> - 

Re: [Freedreno] [PATCH 0/3] use encoder type to identify display

2018-08-30 Thread Sean Paul
On Tue, Aug 28, 2018 at 04:02:15PM -0700, Jeykumar Sankaran wrote:
> DPU is broken with patch [1]. This patch cleans up few stale codes
> and fixes the DPU bug by using encoder type to identify displays.
> 
> [1] https://patchwork.kernel.org/patch/10568269/
> 
> Thanks.
> 
> Jeykumar Sankaran (3):
>   drm/msm/dpu: remove stale display port programming
>   drm/msm/dpu: remove unwanted encoder type mapping
>   drm/msm/dpu: use encoder type to identify display type

Entire series is

Reviewed-by: Sean Paul 

I've pushed them to dpu-staging/for-next 

Thanks,

Sean

> 
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 32 
> -
>  1 file changed, 9 insertions(+), 23 deletions(-)
> 
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH v16 3/5] iommu/arm-smmu: Add the device_link between masters and smmu

2018-08-30 Thread Vivek Gautam
From: Sricharan R 

Finally add the device link between the master device and
smmu, so that the smmu gets runtime enabled/disabled only when the
master needs it. This is done from add_device callback which gets
called once when the master is added to the smmu.

Signed-off-by: Sricharan R 
Signed-off-by: Vivek Gautam 
Reviewed-by: Tomasz Figa 
Tested-by: Srinivas Kandagatla 
---
 drivers/iommu/arm-smmu.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 1bf542010be7..166c8c6da24f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1461,6 +1461,9 @@ static int arm_smmu_add_device(struct device *dev)
 
iommu_device_link(>iommu, dev);
 
+   device_link_add(dev, smmu->dev,
+   DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER);
+
return 0;
 
 out_cfg_free:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH v16 5/5] iommu/arm-smmu: Add support for qcom, smmu-v2 variant

2018-08-30 Thread Vivek Gautam
qcom,smmu-v2 is an arm,smmu-v2 implementation with specific
clock and power requirements.
On msm8996, multiple cores, viz. mdss, video, etc. use this
smmu. On sdm845, this smmu is used with gpu.
Add bindings for the same.

Signed-off-by: Vivek Gautam 
Reviewed-by: Rob Herring 
Reviewed-by: Tomasz Figa 
Tested-by: Srinivas Kandagatla 
---
 drivers/iommu/arm-smmu.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 166c8c6da24f..411e5ac57c64 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -119,6 +119,7 @@ enum arm_smmu_implementation {
GENERIC_SMMU,
ARM_MMU500,
CAVIUM_SMMUV2,
+   QCOM_SMMUV2,
 };
 
 struct arm_smmu_s2cr {
@@ -1970,6 +1971,17 @@ ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, 
GENERIC_SMMU);
 ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500);
 ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2);
 
+static const char * const qcom_smmuv2_clks[] = {
+   "bus", "iface",
+};
+
+static const struct arm_smmu_match_data qcom_smmuv2 = {
+   .version = ARM_SMMU_V2,
+   .model = QCOM_SMMUV2,
+   .clks = qcom_smmuv2_clks,
+   .num_clks = ARRAY_SIZE(qcom_smmuv2_clks),
+};
+
 static const struct of_device_id arm_smmu_of_match[] = {
{ .compatible = "arm,smmu-v1", .data = _generic_v1 },
{ .compatible = "arm,smmu-v2", .data = _generic_v2 },
@@ -1977,6 +1989,7 @@ static const struct of_device_id arm_smmu_of_match[] = {
{ .compatible = "arm,mmu-401", .data = _mmu401 },
{ .compatible = "arm,mmu-500", .data = _mmu500 },
{ .compatible = "cavium,smmu-v2", .data = _smmuv2 },
+   { .compatible = "qcom,smmu-v2", .data = _smmuv2 },
{ },
 };
 MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH v16 4/5] dt-bindings: arm-smmu: Add bindings for qcom, smmu-v2

2018-08-30 Thread Vivek Gautam
Add bindings doc for Qcom's smmu-v2 implementation.

Signed-off-by: Vivek Gautam 
Reviewed-by: Tomasz Figa 
Tested-by: Srinivas Kandagatla 
---
 .../devicetree/bindings/iommu/arm,smmu.txt | 39 ++
 1 file changed, 39 insertions(+)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt 
b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 8a6ffce12af5..a6504b37cc21 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -17,10 +17,16 @@ conditions.
 "arm,mmu-401"
 "arm,mmu-500"
 "cavium,smmu-v2"
+"qcom,smmu-v2"
 
   depending on the particular implementation and/or the
   version of the architecture implemented.
 
+  Qcom SoCs must contain, as below, SoC-specific compatibles
+  along with "qcom,smmu-v2":
+  "qcom,msm8996-smmu-v2", "qcom,smmu-v2",
+  "qcom,sdm845-smmu-v2", "qcom,smmu-v2".
+
 - reg   : Base address and size of the SMMU.
 
 - #global-interrupts : The number of global interrupts exposed by the
@@ -71,6 +77,22 @@ conditions.
   or using stream matching with #iommu-cells = <2>, and
   may be ignored if present in such cases.
 
+- clock-names:List of the names of clocks input to the device. The
+  required list depends on particular implementation and
+  is as follows:
+  - for "qcom,smmu-v2":
+- "bus": clock required for downstream bus access and
+ for the smmu ptw,
+- "iface": clock required to access smmu's registers
+   through the TCU's programming interface.
+  - unspecified for other implementations.
+
+- clocks: Specifiers for all clocks listed in the clock-names property,
+  as per generic clock bindings.
+
+- power-domains:  Specifiers for power domains required to be powered on for
+  the SMMU to operate, as per generic power domain bindings.
+
 ** Deprecated properties:
 
 - mmu-masters (deprecated in favour of the generic "iommus" binding) :
@@ -137,3 +159,20 @@ conditions.
 iommu-map = <0  0 0x400>;
 ...
 };
+
+   /* Qcom's arm,smmu-v2 implementation */
+   smmu4: iommu@d0 {
+   compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+   reg = <0xd0 0x1>;
+
+   #global-interrupts = <1>;
+   interrupts = ,
+,
+;
+   #iommu-cells = <1>;
+   power-domains = < MDSS_GDSC>;
+
+   clocks = < SMMU_MDP_AXI_CLK>,
+< SMMU_MDP_AHB_CLK>;
+   clock-names = "bus", "iface";
+   };
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [PATCH v16 1/5] iommu/arm-smmu: Add pm_runtime/sleep ops

2018-08-30 Thread Vivek Gautam
From: Sricharan R 

The smmu needs to be functional only when the respective
master's using it are active. The device_link feature
helps to track such functional dependencies, so that the
iommu gets powered when the master device enables itself
using pm_runtime. So by adapting the smmu driver for
runtime pm, above said dependency can be addressed.

This patch adds the pm runtime/sleep callbacks to the
driver and also the functions to parse the smmu clocks
from DT and enable them in resume/suspend.

Also, while we enable the runtime pm add a pm sleep suspend
callback that pushes devices to low power state by turning
the clocks off in a system sleep.
Also add corresponding clock enable path in resume callback.

Signed-off-by: Sricharan R 
Signed-off-by: Archit Taneja 
[vivek: rework for clock and pm ops]
Signed-off-by: Vivek Gautam 
Reviewed-by: Tomasz Figa 
Tested-by: Srinivas Kandagatla 
---
 drivers/iommu/arm-smmu.c | 77 ++--
 1 file changed, 74 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index fd1b80ef9490..d900e007c3c9 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -48,6 +48,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -205,6 +206,8 @@ struct arm_smmu_device {
u32 num_global_irqs;
u32 num_context_irqs;
unsigned int*irqs;
+   struct clk_bulk_data*clks;
+   int num_clks;
 
u32 cavium_id_base; /* Specific to Cavium */
 
@@ -1896,10 +1899,12 @@ static int arm_smmu_device_cfg_probe(struct 
arm_smmu_device *smmu)
 struct arm_smmu_match_data {
enum arm_smmu_arch_version version;
enum arm_smmu_implementation model;
+   const char * const *clks;
+   int num_clks;
 };
 
 #define ARM_SMMU_MATCH_DATA(name, ver, imp)\
-static struct arm_smmu_match_data name = { .version = ver, .model = imp }
+static const struct arm_smmu_match_data name = { .version = ver, .model = imp }
 
 ARM_SMMU_MATCH_DATA(smmu_generic_v1, ARM_SMMU_V1, GENERIC_SMMU);
 ARM_SMMU_MATCH_DATA(smmu_generic_v2, ARM_SMMU_V2, GENERIC_SMMU);
@@ -1918,6 +1923,23 @@ static const struct of_device_id arm_smmu_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
 
+static void arm_smmu_fill_clk_data(struct arm_smmu_device *smmu,
+  const char * const *clks)
+{
+   int i;
+
+   if (smmu->num_clks < 1)
+   return;
+
+   smmu->clks = devm_kcalloc(smmu->dev, smmu->num_clks,
+ sizeof(*smmu->clks), GFP_KERNEL);
+   if (!smmu->clks)
+   return;
+
+   for (i = 0; i < smmu->num_clks; i++)
+   smmu->clks[i].id = clks[i];
+}
+
 #ifdef CONFIG_ACPI
 static int acpi_smmu_get_data(u32 model, struct arm_smmu_device *smmu)
 {
@@ -2000,6 +2022,9 @@ static int arm_smmu_device_dt_probe(struct 
platform_device *pdev,
data = of_device_get_match_data(dev);
smmu->version = data->version;
smmu->model = data->model;
+   smmu->num_clks = data->num_clks;
+
+   arm_smmu_fill_clk_data(smmu, data->clks);
 
parse_driver_options(smmu);
 
@@ -2098,6 +2123,14 @@ static int arm_smmu_device_probe(struct platform_device 
*pdev)
smmu->irqs[i] = irq;
}
 
+   err = devm_clk_bulk_get(smmu->dev, smmu->num_clks, smmu->clks);
+   if (err)
+   return err;
+
+   err = clk_bulk_prepare_enable(smmu->num_clks, smmu->clks);
+   if (err)
+   return err;
+
err = arm_smmu_device_cfg_probe(smmu);
if (err)
return err;
@@ -2184,6 +2217,9 @@ static int arm_smmu_device_remove(struct platform_device 
*pdev)
 
/* Turn the thing off */
writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
+
+   clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
+
return 0;
 }
 
@@ -2192,15 +2228,50 @@ static void arm_smmu_device_shutdown(struct 
platform_device *pdev)
arm_smmu_device_remove(pdev);
 }
 
-static int __maybe_unused arm_smmu_pm_resume(struct device *dev)
+static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
 {
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+   int ret;
+
+   ret = clk_bulk_enable(smmu->num_clks, smmu->clks);
+   if (ret)
+   return ret;
 
arm_smmu_device_reset(smmu);
+
return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(arm_smmu_pm_ops, NULL, arm_smmu_pm_resume);
+static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
+{
+   struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+
+   clk_bulk_disable(smmu->num_clks, smmu->clks);
+
+   return 0;
+}
+
+static int __maybe_unused arm_smmu_pm_resume(struct device *dev)
+{
+   if 

[Freedreno] [PATCH v16 2/5] iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device

2018-08-30 Thread Vivek Gautam
From: Sricharan R 

The smmu device probe/remove and add/remove master device callbacks
gets called when the smmu is not linked to its master, that is without
the context of the master device. So calling runtime apis in those places
separately.
Global locks are also initialized before enabling runtime pm as the
runtime_resume() calls device_reset() which does tlb_sync_global()
that ultimately requires locks to be initialized.

Signed-off-by: Sricharan R 
[vivek: Cleanup pm runtime calls]
Signed-off-by: Vivek Gautam 
Reviewed-by: Tomasz Figa 
Tested-by: Srinivas Kandagatla 
---
 drivers/iommu/arm-smmu.c | 89 +++-
 1 file changed, 81 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index d900e007c3c9..1bf542010be7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -268,6 +268,20 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
{ 0, NULL},
 };
 
+static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
+{
+   if (pm_runtime_enabled(smmu->dev))
+   return pm_runtime_get_sync(smmu->dev);
+
+   return 0;
+}
+
+static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
+{
+   if (pm_runtime_enabled(smmu->dev))
+   pm_runtime_put(smmu->dev);
+}
+
 static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 {
return container_of(dom, struct arm_smmu_domain, domain);
@@ -913,11 +927,15 @@ static void arm_smmu_destroy_domain_context(struct 
iommu_domain *domain)
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_device *smmu = smmu_domain->smmu;
struct arm_smmu_cfg *cfg = _domain->cfg;
-   int irq;
+   int ret, irq;
 
if (!smmu || domain->type == IOMMU_DOMAIN_IDENTITY)
return;
 
+   ret = arm_smmu_rpm_get(smmu);
+   if (ret < 0)
+   return;
+
/*
 * Disable the context bank and free the page tables before freeing
 * it.
@@ -932,6 +950,8 @@ static void arm_smmu_destroy_domain_context(struct 
iommu_domain *domain)
 
free_io_pgtable_ops(smmu_domain->pgtbl_ops);
__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
+
+   arm_smmu_rpm_put(smmu);
 }
 
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
@@ -1213,10 +1233,15 @@ static int arm_smmu_attach_dev(struct iommu_domain 
*domain, struct device *dev)
return -ENODEV;
 
smmu = fwspec_smmu(fwspec);
+
+   ret = arm_smmu_rpm_get(smmu);
+   if (ret < 0)
+   return ret;
+
/* Ensure that the domain is finalised */
ret = arm_smmu_init_domain_context(domain, smmu);
if (ret < 0)
-   return ret;
+   goto rpm_put;
 
/*
 * Sanity check the domain. We don't support domains across
@@ -1226,33 +1251,50 @@ static int arm_smmu_attach_dev(struct iommu_domain 
*domain, struct device *dev)
dev_err(dev,
"cannot attach to SMMU %s whilst already attached to 
domain on SMMU %s\n",
dev_name(smmu_domain->smmu->dev), dev_name(smmu->dev));
-   return -EINVAL;
+   ret = -EINVAL;
+   goto rpm_put;
}
 
/* Looks ok, so add the device to the domain */
-   return arm_smmu_domain_add_master(smmu_domain, fwspec);
+   ret = arm_smmu_domain_add_master(smmu_domain, fwspec);
+
+rpm_put:
+   arm_smmu_rpm_put(smmu);
+   return ret;
 }
 
 static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
 {
struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
+   struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+   int ret;
 
if (!ops)
return -ENODEV;
 
-   return ops->map(ops, iova, paddr, size, prot);
+   arm_smmu_rpm_get(smmu);
+   ret = ops->map(ops, iova, paddr, size, prot);
+   arm_smmu_rpm_put(smmu);
+
+   return ret;
 }
 
 static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
 size_t size)
 {
struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
+   struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+   size_t ret;
 
if (!ops)
return 0;
 
-   return ops->unmap(ops, iova, size);
+   arm_smmu_rpm_get(smmu);
+   ret = ops->unmap(ops, iova, size);
+   arm_smmu_rpm_put(smmu);
+
+   return ret;
 }
 
 static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
@@ -1407,7 +1449,13 @@ static int arm_smmu_add_device(struct device *dev)
while (i--)
cfg->smendx[i] = INVALID_SMENDX;
 
+   ret = arm_smmu_rpm_get(smmu);
+   if (ret < 0)
+   goto out_cfg_free;
+
ret = 

[Freedreno] [PATCH v16 0/5] iommu/arm-smmu: Add runtime pm/sleep support

2018-08-30 Thread Vivek Gautam
This series provides the support for turning on the arm-smmu's
clocks/power domains using runtime pm. This is done using
device links between smmu and client devices. The device link
framework keeps the two devices in correct order for power-cycling
across runtime PM or across system-wide PM.

With addition of a new device link flag DL_FLAG_AUTOREMOVE_SUPPLIER [7],
the device links created between arm-smmu and its clients will be
automatically purged when arm-smmu driver unbinds from its device.

As not all implementations support clock/power gating, we are checking
for a valid 'smmu->dev's pm_domain' to conditionally enable the runtime
power management for such smmu implementations that can support it.
Otherwise, the clocks are turned to be always on in .probe until .remove.
With conditional runtime pm now, we avoid touching dev->power.lock
in fastpaths for smmu implementations that don't need to do anything
useful with pm_runtime.
This lets us to use the much-argued pm_runtime_get_sync/put_sync()
calls in map/unmap callbacks so that the clients do not have to
worry about handling any of the arm-smmu's power.

This series also adds support for Qcom's arm-smmu-v2 variant that
has different clocks and power requirements.

Previous version of this patch series is @ [1].

Build tested the series based on 4.19-rc1.

[v16] 
   * Addressed review comments from Rob about soc specific compatibles.
   * Removed pm_runtime_get/put calls from arm_smmu_device_probe(), as
 doing a runtime_get() eventually calls arm_smmu_device_reset().
 arm_smmu_device_reset() should be called only after
 arm_smmu_device_cfg_probe().
 Enabling the clocks by default in the probe, and using
 pm_runtime_set_active() as suggested by Tomasz to disable the
 clocks when pm_runtime is enabled.

[v15]
   * Added a list of valid values of '' in "qcom,-smmu-v2"
 compatible string as pointed out by Robin, and Rob in the thread [8]:
   * Added Srini's Tested-by.
   * Separated out the dt-bindings change from driver change into a new
 patch as suggested by new checkpatch warning.

 Rob, I took the liberty of removing your Reviewed-by (for your
 comment on '') for the new dt-bindings patch 4/5.
 Please feel free to review it again. Thanks!

[v14]
   * Moved arm_smmu_device_reset() from arm_smmu_pm_resume() to
 arm_smmu_runtime_resume() so that the pm_resume callback calls
 only runtime_resume to resume the device.
 This should take care of restoring the state of smmu in systems
 in which smmu lose register state on power-domain collapse.

[v13]
   Addressing Rafael's comments:
   * Added .suspend pm callback to disable the clocks in system wide suspend.
   * Added corresponding clock enable in .resume pm callback.
   * Explicitly enabling/disabling the clocks now when runtime PM is disabled.
   * device_link_add() doesn't depend on pm_runtime_enabled() as we can
 use device links across system suspend/resume too.

   Addressing Robin's comments:
   * Making device_link_add failures as non-fatal.

   * Removed IOMMU_OF_DECLARE() declaration as we don't need this after Rob's
 patch that removed all of these declarations.

[v12]
   * Use new device link's flag introduced in [7] -
 DL_FLAG_AUTOREMOVE_SUPPLIER. With this devices links are automatically
 purged when arm-smmu driver unbinds.
   * Using pm_runtime_force_suspend() instead of pm_runtime_disable() to
 avoid following warning from arm_smmu_device_remove()

 [295711.537507] [ cut here ]
 [295711.544226] Unpreparing enabled smmu_mdp_ahb_clk
 [295711.549099] WARNING: CPU: 0 PID: 1 at ../drivers/clk/clk.c:697
 clk_core_unprepare+0xd8/0xe0
 ...
 [295711.674073] Call trace:
 [295711.679454]  clk_core_unprepare+0xd8/0xe0
 [295711.682059]  clk_unprepare+0x28/0x40
 [295711.685964]  clk_bulk_unprepare+0x28/0x40
 [295711.689701]  arm_smmu_device_remove+0x88/0xd8
 [295711.693692]  arm_smmu_device_shutdown+0xc/0x18
 [295711.698120]  platform_drv_shutdown+0x20/0x30

[v11]
   * Some more cleanups for device link. We don't need an explicit
 delete for device link from the driver, but just set the flag
 DL_FLAG_AUTOREMOVE.
 device_link_add() API description says -
 "If the DL_FLAG_AUTOREMOVE is set, the link will be removed
 automatically when the consumer device driver unbinds."
   * Addressed the comments for 'smmu' in arm_smmu_map/unmap().
   * Dropped the patch [6] that introduced device_link_del_dev() API. 

[v10]
   * Introduce device_link_del_dev() API to delete the link between
 given consumer and supplier devices. The users of device link
 do not need to store link pointer to delete the link later.
 They can straightaway use this API by passing consumer and
 supplier devices.
   * Made corresponding changes to arm-smmu driver patch handling the
 device links.
   * Dropped the patch [5] that was 

Re: [Freedreno] [Patch v15 2/5] iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device

2018-08-30 Thread Vivek Gautam
On Thu, Aug 30, 2018 at 3:04 PM Tomasz Figa  wrote:
>
> On Thu, Aug 30, 2018 at 6:22 PM Vivek Gautam
>  wrote:
> >
> > On Mon, Aug 27, 2018 at 4:27 PM Vivek Gautam
> >  wrote:
> > >
> > > From: Sricharan R 
> > >
> > > The smmu device probe/remove and add/remove master device callbacks
> > > gets called when the smmu is not linked to its master, that is without
> > > the context of the master device. So calling runtime apis in those places
> > > separately.
> > >
> > > Signed-off-by: Sricharan R 
> > > [vivek: Cleanup pm runtime calls]
> > > Signed-off-by: Vivek Gautam 
> > > Reviewed-by: Tomasz Figa 
> > > Tested-by: Srinivas Kandagatla 
> > > ---
> > >
> > > Changes since v14:
> > >  - none.
> > >
> > >  drivers/iommu/arm-smmu.c | 101 
> > > +++
> > >  1 file changed, 93 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> > > index a81224bc6637..23b4a60149b6 100644
> > > --- a/drivers/iommu/arm-smmu.c
> > > +++ b/drivers/iommu/arm-smmu.c
> >
> > [snip]
> >
> > > @@ -2131,6 +2188,26 @@ static int arm_smmu_device_probe(struct 
> > > platform_device *pdev)
> > > if (err)
> > > return err;
> > >
> > > +   /*
> > > +* We want to avoid touching dev->power.lock in fastpaths unless
> > > +* it's really going to do something useful - pm_runtime_enabled()
> > > +* can serve as an ideal proxy for that decision. So, 
> > > conditionally
> > > +* enable pm_runtime.
> > > +*/
> > > +   if (dev->pm_domain)
> > > +   pm_runtime_enable(dev);
> > > +
> > > +   err = arm_smmu_rpm_get(smmu);
> >
> > We shouldn't be doing a runtime_get() yet, as this eventually calls
> > arm_smmu_device_reset().
> > arm_smmu_device_reset() should be called only after 
> > arm_smmu_device_cfg_probe().
> > So, I plan to replace the pm_runtime_get/put() calls in probe() with
> > simple clk_bulk_enable()
> > to let the driver initialize smmu, and at the end of the probe we can
> > disable the clocks and
> > enable runtime pm over the device to let it take care of the device 
> > further-on.
> >
>
> We can avoid the explicit clock disable by just calling
> pm_runtime_set_active() before pm_runtime_enable(), assuming that what
> probe does is symmetrical with the suspend callback, which would be
> called after the latter.

Sure, that sounds reasonable. Will use pm_runtime_set_active() instead
of explicitly disabling the clocks.Thanks.

Best regards
Vivek

>
> Best regards,
> Tomasz
> ___
> iommu mailing list
> io...@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu



-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


Re: [Freedreno] [Patch v15 2/5] iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device

2018-08-30 Thread Tomasz Figa
On Thu, Aug 30, 2018 at 6:22 PM Vivek Gautam
 wrote:
>
> On Mon, Aug 27, 2018 at 4:27 PM Vivek Gautam
>  wrote:
> >
> > From: Sricharan R 
> >
> > The smmu device probe/remove and add/remove master device callbacks
> > gets called when the smmu is not linked to its master, that is without
> > the context of the master device. So calling runtime apis in those places
> > separately.
> >
> > Signed-off-by: Sricharan R 
> > [vivek: Cleanup pm runtime calls]
> > Signed-off-by: Vivek Gautam 
> > Reviewed-by: Tomasz Figa 
> > Tested-by: Srinivas Kandagatla 
> > ---
> >
> > Changes since v14:
> >  - none.
> >
> >  drivers/iommu/arm-smmu.c | 101 
> > +++
> >  1 file changed, 93 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> > index a81224bc6637..23b4a60149b6 100644
> > --- a/drivers/iommu/arm-smmu.c
> > +++ b/drivers/iommu/arm-smmu.c
>
> [snip]
>
> > @@ -2131,6 +2188,26 @@ static int arm_smmu_device_probe(struct 
> > platform_device *pdev)
> > if (err)
> > return err;
> >
> > +   /*
> > +* We want to avoid touching dev->power.lock in fastpaths unless
> > +* it's really going to do something useful - pm_runtime_enabled()
> > +* can serve as an ideal proxy for that decision. So, conditionally
> > +* enable pm_runtime.
> > +*/
> > +   if (dev->pm_domain)
> > +   pm_runtime_enable(dev);
> > +
> > +   err = arm_smmu_rpm_get(smmu);
>
> We shouldn't be doing a runtime_get() yet, as this eventually calls
> arm_smmu_device_reset().
> arm_smmu_device_reset() should be called only after 
> arm_smmu_device_cfg_probe().
> So, I plan to replace the pm_runtime_get/put() calls in probe() with
> simple clk_bulk_enable()
> to let the driver initialize smmu, and at the end of the probe we can
> disable the clocks and
> enable runtime pm over the device to let it take care of the device 
> further-on.
>

We can avoid the explicit clock disable by just calling
pm_runtime_set_active() before pm_runtime_enable(), assuming that what
probe does is symmetrical with the suspend callback, which would be
called after the latter.

Best regards,
Tomasz
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


Re: [Freedreno] [Patch v15 2/5] iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device

2018-08-30 Thread Vivek Gautam
On Mon, Aug 27, 2018 at 4:27 PM Vivek Gautam
 wrote:
>
> From: Sricharan R 
>
> The smmu device probe/remove and add/remove master device callbacks
> gets called when the smmu is not linked to its master, that is without
> the context of the master device. So calling runtime apis in those places
> separately.
>
> Signed-off-by: Sricharan R 
> [vivek: Cleanup pm runtime calls]
> Signed-off-by: Vivek Gautam 
> Reviewed-by: Tomasz Figa 
> Tested-by: Srinivas Kandagatla 
> ---
>
> Changes since v14:
>  - none.
>
>  drivers/iommu/arm-smmu.c | 101 
> +++
>  1 file changed, 93 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index a81224bc6637..23b4a60149b6 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c

[snip]

> @@ -2131,6 +2188,26 @@ static int arm_smmu_device_probe(struct 
> platform_device *pdev)
> if (err)
> return err;
>
> +   /*
> +* We want to avoid touching dev->power.lock in fastpaths unless
> +* it's really going to do something useful - pm_runtime_enabled()
> +* can serve as an ideal proxy for that decision. So, conditionally
> +* enable pm_runtime.
> +*/
> +   if (dev->pm_domain)
> +   pm_runtime_enable(dev);
> +
> +   err = arm_smmu_rpm_get(smmu);

We shouldn't be doing a runtime_get() yet, as this eventually calls
arm_smmu_device_reset().
arm_smmu_device_reset() should be called only after arm_smmu_device_cfg_probe().
So, I plan to replace the pm_runtime_get/put() calls in probe() with
simple clk_bulk_enable()
to let the driver initialize smmu, and at the end of the probe we can
disable the clocks and
enable runtime pm over the device to let it take care of the device further-on.

> +   if (err < 0)
> +   return err;
> +
> +   /* Enable clocks explicitly if runtime PM is disabled */
> +   if (!pm_runtime_enabled(dev)) {
> +   err = clk_bulk_enable(smmu->num_clks, smmu->clks);
> +   if (err)
> +   return err;
> +   }
> +
> err = arm_smmu_device_cfg_probe(smmu);
> if (err)
> return err;

[snip]

Best regards
Vivek
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno