[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