[Freedreno] [PATCH 09/16] drm/msm: gpu Add new gpu register read/write functions
Rob Clark
robdclark at gmail.com
Mon Nov 7 19:17:57 UTC 2016
On Fri, Nov 4, 2016 at 6:44 PM, Jordan Crouse <jcrouse at codeaurora.org> wrote:
> Add some new functions to manipulate GPU registers. gpu_read64 and
> gpu_write64 can read/write a 64 bit value to two 32 bit registers.
> For 4XX and older these are normally perfcounter registers, but
> future targets will use 64 bit addressing so there will be many
> more spots where a 64 bit read and write are needed.
>
> gpu_rmw() does a read/modify/write on a 32 bit register given a mask
> and bits to OR in.
>
> Signed-off-by: Jordan Crouse <jcrouse at codeaurora.org>
> ---
> drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 12 ++---------
> drivers/gpu/drm/msm/msm_gpu.h | 39 +++++++++++++++++++++++++++++++++++
> 2 files changed, 41 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
> index f39e082..f2f9c91 100644
> --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
> @@ -515,16 +515,8 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) {
>
> static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
> {
> - uint32_t hi, lo, tmp;
> -
> - tmp = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_HI);
> - do {
> - hi = tmp;
> - lo = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
> - tmp = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_HI);
> - } while (tmp != hi);
> -
> - *value = (((uint64_t)hi) << 32) | lo;
> + *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO,
> + REG_A4XX_RBBM_PERFCTR_CP_0_HI);
probably other places are ok to use gpu_read64, but I kinda think the
timestamp counters should stay with the loop while(tmp!=hi)..
I guess if we were reading perfctrs in enough places, a special
read_perfctr type fxn would be in order.
BR,
-R
> return 0;
> }
> diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
> index 161cd2f..bec3735 100644
> --- a/drivers/gpu/drm/msm/msm_gpu.h
> +++ b/drivers/gpu/drm/msm/msm_gpu.h
> @@ -154,6 +154,45 @@ static inline u32 gpu_read(struct msm_gpu *gpu, u32 reg)
> return msm_readl(gpu->mmio + (reg << 2));
> }
>
> +static inline void gpu_rmw(struct msm_gpu *gpu, u32 reg, u32 mask, u32 or)
> +{
> + uint32_t val = gpu_read(gpu, reg);
> +
> + val &= ~mask;
> + gpu_write(gpu, reg, val | or);
> +}
> +
> +static inline u64 gpu_read64(struct msm_gpu *gpu, u32 lo, u32 hi)
> +{
> + u64 val;
> +
> + /*
> + * Why not a readq here? Two reasons: 1) many of the LO registers are
> + * not quad word aligned and 2) the GPU hardware designers have a bit
> + * of a history of putting registers where they fit, especially in
> + * spins. The longer a GPU family goes the higher the chance that
> + * we'll get burned. We could do a series of validity checks if we
> + * wanted to, but really is a readq() that much better? Nah.
> + */
> +
> + /*
> + * For some lo/hi registers (like perfcounters), the hi value is latched
> + * when the lo is read, so make sure to read the lo first to trigger
> + * that
> + */
> + val = (u64) msm_readl(gpu->mmio + (lo << 2));
> + val |= ((u64) msm_readl(gpu->mmio + (hi << 2)) << 32);
> +
> + return val;
> +}
> +
> +static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)
> +{
> + /* Why not a writeq here? Read the screed above */
> + msm_writel(lower_32_bits(val), gpu->mmio + (lo << 2));
> + msm_writel(upper_32_bits(val), gpu->mmio + (hi << 2));
> +}
> +
> int msm_gpu_pm_suspend(struct msm_gpu *gpu);
> int msm_gpu_pm_resume(struct msm_gpu *gpu);
>
> --
> 1.9.1
>
> _______________________________________________
> Freedreno mailing list
> Freedreno at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/freedreno
More information about the Freedreno
mailing list