[PATCH] drm/amdgpu/acp: Power on/off acp tiles within driver

Alex Deucher alexdeucher at gmail.com
Fri Aug 3 15:03:19 UTC 2018


On Fri, Aug 3, 2018 at 4:41 AM, Rex Zhu <Rex.Zhu at amd.com> wrote:
> Different from ordinary stoney,For Stoney Fanless,
> smu firmware do not poweron/off acp tiles, so need to
> poweron/off acp in driver.
>
> Partially revert
> 'commit f766dd23e5ce ("drm/amdgpu/acp: Powrgate acp via smu")'
>
> Signed-off-by: Rex Zhu <Rex.Zhu at amd.com>

Acked-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 118 +++++++++++++++++++++++++++++---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h |   4 ++
>  2 files changed, 114 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
> index 8bf3a98..f673c99 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
> @@ -91,6 +91,8 @@ enum {
>         ACP_TILE_DSP1,
>         ACP_TILE_DSP2,
>  };
> +static int acp_set_powergating_state(void *handle,
> +                                    enum amd_powergating_state state);
>
>  static int acp_sw_init(void *handle)
>  {
> @@ -135,8 +137,7 @@ static int acp_poweroff(struct generic_pm_domain *genpd)
>          * 2. power off the acp tiles
>          * 3. check and enter ulv state
>          */
> -               if (adev->powerplay.pp_funcs->set_powergating_by_smu)
> -                       amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
> +               acp_set_powergating_state(adev, AMD_PG_STATE_GATE);
>         }
>         return 0;
>  }
> @@ -155,8 +156,7 @@ static int acp_poweron(struct generic_pm_domain *genpd)
>          * 2. turn on acp clock
>          * 3. power on acp tiles
>          */
> -               if (adev->powerplay.pp_funcs->set_powergating_by_smu)
> -                       amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
> +               acp_set_powergating_state(adev, AMD_PG_STATE_UNGATE);
>         }
>         return 0;
>  }
> @@ -201,7 +201,7 @@ static int acp_hw_init(void *handle)
>                             ip_block->version->major, ip_block->version->minor);
>         /* -ENODEV means board uses AZ rather than ACP */
>         if (r == -ENODEV) {
> -               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
> +               acp_set_powergating_state(adev, AMD_PG_STATE_GATE);
>                 return 0;
>         } else if (r) {
>                 return r;
> @@ -407,7 +407,7 @@ static int acp_hw_fini(void *handle)
>
>         /* return early if no ACP */
>         if (!adev->acp.acp_genpd) {
> -               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
> +               acp_set_powergating_state(adev, AMD_PG_STATE_UNGATE);
>                 return 0;
>         }
>
> @@ -469,7 +469,7 @@ static int acp_suspend(void *handle)
>
>         /* power up on suspend */
>         if (!adev->acp.acp_cell)
> -               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
> +               acp_set_powergating_state(adev, AMD_PG_STATE_UNGATE);
>         return 0;
>  }
>
> @@ -479,7 +479,7 @@ static int acp_resume(void *handle)
>
>         /* power down again on resume */
>         if (!adev->acp.acp_cell)
> -               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
> +               acp_set_powergating_state(adev, AMD_PG_STATE_GATE);
>         return 0;
>  }
>
> @@ -509,15 +509,117 @@ static int acp_set_clockgating_state(void *handle,
>         return 0;
>  }
>
> +/* power off a tile/block within ACP */
> +static int acp_suspend_tile(struct amdgpu_device *adev, int tile)
> +{
> +       u32 val = 0;
> +       u32 count = 0;
> +
> +       if ((tile  < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) {
> +               pr_err("Invalid ACP tile : %d to suspend\n", tile);
> +               return -1;
> +       }
> +
> +       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
> +       val &= ACP_TILE_ON_MASK;
> +
> +       if (val == 0x0) {
> +               val = RREG32(mmACP_PGFSM_RETAIN_REG);
> +               val = val | (1 << tile);
> +               WREG32(mmACP_PGFSM_RETAIN_REG, val);
> +               WREG32(mmACP_PGFSM_CONFIG_REG,
> +                                       0x500 + tile);
> +
> +               count = ACP_TIMEOUT_LOOP;
> +               while (true) {
> +                       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
> +                       val = val & ACP_TILE_ON_MASK;
> +                       if (val == ACP_TILE_OFF_MASK)
> +                               break;
> +                       if (--count == 0) {
> +                               pr_err("Timeout reading ACP PGFSM status\n");
> +                               return -ETIMEDOUT;
> +                       }
> +                       udelay(100);
> +               }
> +
> +               val = RREG32(mmACP_PGFSM_RETAIN_REG);
> +
> +               val |= ACP_TILE_OFF_RETAIN_REG_MASK;
> +               WREG32(mmACP_PGFSM_RETAIN_REG, val);
> +       }
> +       return 0;
> +}
> +
> +/* power on a tile/block within ACP */
> +static int acp_resume_tile(struct amdgpu_device *adev, int tile)
> +{
> +       u32 val = 0;
> +       u32 count = 0;
> +
> +       if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) {
> +               pr_err("Invalid ACP tile to resume\n");
> +               return -1;
> +       }
> +
> +       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
> +       val = val & ACP_TILE_ON_MASK;
> +
> +       if (val != 0x0) {
> +               WREG32(mmACP_PGFSM_CONFIG_REG,
> +                                       0x600 + tile);
> +               count = ACP_TIMEOUT_LOOP;
> +               while (true) {
> +                       val = RREG32(mmACP_PGFSM_READ_REG_0 + tile);
> +                       val = val & ACP_TILE_ON_MASK;
> +                       if (val == 0x0)
> +                               break;
> +                       if (--count == 0) {
> +                               pr_err("Timeout reading ACP PGFSM status\n");
> +                               return -ETIMEDOUT;
> +                       }
> +                       udelay(100);
> +               }
> +               val = RREG32(mmACP_PGFSM_RETAIN_REG);
> +               if (tile == ACP_TILE_P1)
> +                       val = val & (ACP_TILE_P1_MASK);
> +               else if (tile == ACP_TILE_P2)
> +                       val = val & (ACP_TILE_P2_MASK);
> +
> +               WREG32(mmACP_PGFSM_RETAIN_REG, val);
> +       }
> +       return 0;
> +}
> +
>  static int acp_set_powergating_state(void *handle,
>                                      enum amd_powergating_state state)
>  {
>         struct amdgpu_device *adev = (struct amdgpu_device *)handle;
>         bool enable = state == AMD_PG_STATE_GATE ? true : false;
> +       int i, ret;
> +
> +       if (!enable && IS_ST_KICKER(adev)) {
> +               for (i = 0; i < 2; i++) {
> +                       /* do not power up DSPs which are not going to be used */
> +                       ret = acp_resume_tile(adev, ACP_TILE_P1 + i);
> +                       if (ret) {
> +                               pr_err("ACP tile %d resume failed\n", i);
> +                               break;
> +                       }
> +               }
> +       }
>
>         if (adev->powerplay.pp_funcs->set_powergating_by_smu)
>                 amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable);
>
> +       if (enable && IS_ST_KICKER(adev)) {
> +               for (i = 0; i < 5; i++) {
> +                       ret = acp_suspend_tile(adev, ACP_TILE_P1 + i);
> +                       if (ret)
> +                               pr_err("ACP tile %d suspend failed\n", i);
> +               }
> +       }
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h
> index a288ce2..fcb2e7d 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h
> @@ -39,4 +39,8 @@ struct amdgpu_acp {
>
>  extern const struct amdgpu_ip_block_version acp_ip_block;
>
> +#define IS_ST_KICKER(dev)  ((dev)->asic_type == CHIP_STONEY && \
> +                          (((dev)->pm.fw_version & 0xff00) == 0x2100 || \
> +                           ((dev)->pm.fw_version & 0xff00) == 0x1A00))
> +
>  #endif /* __AMDGPU_ACP_H__ */
> --
> 1.9.1
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx


More information about the amd-gfx mailing list