diff options
Diffstat (limited to 'common/recipes-kernel/linux/files/0258-drm-amd-add-pm-domain-for-ACP-IP-sub-blocks.patch')
-rw-r--r-- | common/recipes-kernel/linux/files/0258-drm-amd-add-pm-domain-for-ACP-IP-sub-blocks.patch | 311 |
1 files changed, 0 insertions, 311 deletions
diff --git a/common/recipes-kernel/linux/files/0258-drm-amd-add-pm-domain-for-ACP-IP-sub-blocks.patch b/common/recipes-kernel/linux/files/0258-drm-amd-add-pm-domain-for-ACP-IP-sub-blocks.patch deleted file mode 100644 index 2c43d4be..00000000 --- a/common/recipes-kernel/linux/files/0258-drm-amd-add-pm-domain-for-ACP-IP-sub-blocks.patch +++ /dev/null @@ -1,311 +0,0 @@ -From c4179391cc0a3321b45cda7fcc0431d71421e58d Mon Sep 17 00:00:00 2001 -From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu@amd.com> -Date: Mon, 23 Nov 2015 21:07:30 +0530 -Subject: [PATCH 0258/1110] drm/amd: add pm domain for ACP IP sub blocks - -ACP IP have internal DMA controller, DW I2S controller and DSPs -as separate power tiles. DMA and I2S devices are added to generic -pm domain, so that entire IP can be powered off/on at appropriate -times. Unused DSPs are made to be powered off though they are powered -on during ACP pm domain power on sequence. - -Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com> -Reviewed-by: Alex Deucher <alexander.deucher@amd.com> -Signed-off-by: Alex Deucher <alexander.deucher@amd.com> ---- - drivers/gpu/drm/amd/acp/Kconfig | 1 + - drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 206 +++++++++++++++++++++++++++++++- - drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h | 1 + - 3 files changed, 207 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/amd/acp/Kconfig b/drivers/gpu/drm/amd/acp/Kconfig -index 28b5e70..2b07813 100644 ---- a/drivers/gpu/drm/amd/acp/Kconfig -+++ b/drivers/gpu/drm/amd/acp/Kconfig -@@ -4,6 +4,7 @@ config DRM_AMD_ACP - bool "Enable ACP IP support" - default y - select MFD_CORE -+ select PM_GENERIC_DOMAINS if PM - help - Choose this option to enable ACP IP support for AMD SOCs. - -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c -index 71f26e9..9f8cfaa 100644 ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c -@@ -24,6 +24,7 @@ - */ - - #include <linux/irqdomain.h> -+#include <linux/pm_domain.h> - #include <linux/platform_device.h> - #include <sound/designware_i2s.h> - #include <sound/pcm.h> -@@ -102,6 +103,155 @@ static int acp_sw_fini(void *handle) - return 0; - } - -+/* power off a tile/block within ACP */ -+static int acp_suspend_tile(void *cgs_dev, 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 = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); -+ val &= ACP_TILE_ON_MASK; -+ -+ if (val == 0x0) { -+ val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); -+ val = val | (1 << tile); -+ cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); -+ cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG, -+ 0x500 + tile); -+ -+ count = ACP_TIMEOUT_LOOP; -+ while (true) { -+ val = cgs_read_register(cgs_dev, 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 = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); -+ -+ val |= ACP_TILE_OFF_RETAIN_REG_MASK; -+ cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); -+ } -+ return 0; -+} -+ -+/* power on a tile/block within ACP */ -+static int acp_resume_tile(void *cgs_dev, 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 = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); -+ val = val & ACP_TILE_ON_MASK; -+ -+ if (val != 0x0) { -+ cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG, -+ 0x600 + tile); -+ count = ACP_TIMEOUT_LOOP; -+ while (true) { -+ val = cgs_read_register(cgs_dev, 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 = cgs_read_register(cgs_dev, 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); -+ -+ cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); -+ } -+ return 0; -+} -+ -+struct acp_pm_domain { -+ void *cgs_dev; -+ struct generic_pm_domain gpd; -+}; -+ -+static int acp_poweroff(struct generic_pm_domain *genpd) -+{ -+ int i, ret; -+ struct acp_pm_domain *apd; -+ -+ apd = container_of(genpd, struct acp_pm_domain, gpd); -+ if (apd != NULL) { -+ /* Donot return abruptly if any of power tile fails to suspend. -+ * Log it and continue powering off other tile -+ */ -+ for (i = 4; i >= 0 ; i--) { -+ ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i); -+ if (ret) -+ pr_err("ACP tile %d tile suspend failed\n", i); -+ } -+ } -+ return 0; -+} -+ -+static int acp_poweron(struct generic_pm_domain *genpd) -+{ -+ int i, ret; -+ struct acp_pm_domain *apd; -+ -+ apd = container_of(genpd, struct acp_pm_domain, gpd); -+ if (apd != NULL) { -+ for (i = 0; i < 2; i++) { -+ ret = acp_resume_tile(apd->cgs_dev, ACP_TILE_P1 + i); -+ if (ret) { -+ pr_err("ACP tile %d resume failed\n", i); -+ break; -+ } -+ } -+ -+ /* Disable DSPs which are not going to be used */ -+ for (i = 0; i < 3; i++) { -+ ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_DSP0 + i); -+ /* Continue suspending other DSP, even if one fails */ -+ if (ret) -+ pr_err("ACP DSP %d suspend failed\n", i); -+ } -+ } -+ return 0; -+} -+ -+static struct device *get_mfd_cell_dev(const char *device_name, int r) -+{ -+ char auto_dev_name[25]; -+ char buf[8]; -+ struct device *dev; -+ -+ sprintf(buf, ".%d.auto", r); -+ strcpy(auto_dev_name, device_name); -+ strcat(auto_dev_name, buf); -+ dev = bus_find_device_by_name(&platform_bus_type, NULL, auto_dev_name); -+ dev_info(dev, "device %s added to pm domain\n", auto_dev_name); -+ -+ return dev; -+} -+ - /** - * acp_hw_init - start and test ACP block - * -@@ -110,8 +260,9 @@ static int acp_sw_fini(void *handle) - */ - static int acp_hw_init(void *handle) - { -- int r; -+ int r, i; - uint64_t acp_base; -+ struct device *dev; - struct i2s_platform_data *i2s_pdata; - - struct amdgpu_device *adev = (struct amdgpu_device *)handle; -@@ -137,6 +288,19 @@ static int acp_hw_init(void *handle) - else if (r) - return r; - -+ adev->acp.acp_genpd = kzalloc(sizeof(struct acp_pm_domain), GFP_KERNEL); -+ if (adev->acp.acp_genpd == NULL) -+ return -ENOMEM; -+ -+ adev->acp.acp_genpd->gpd.name = "ACP_AUDIO"; -+ adev->acp.acp_genpd->gpd.power_off = acp_poweroff; -+ adev->acp.acp_genpd->gpd.power_on = acp_poweron; -+ -+ -+ adev->acp.acp_genpd->cgs_dev = adev->acp.cgs_device; -+ -+ pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false); -+ - adev->acp.acp_cell = kzalloc(sizeof(struct mfd_cell) * ACP_DEVS, - GFP_KERNEL); - -@@ -211,6 +375,15 @@ static int acp_hw_init(void *handle) - if (r) - return r; - -+ for (i = 0; i < ACP_DEVS ; i++) { -+ dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); -+ r = pm_genpd_add_device(&adev->acp.acp_genpd->gpd, dev); -+ if (r) { -+ dev_err(dev, "Failed to add dev to genpd\n"); -+ return r; -+ } -+ } -+ - return 0; - } - -@@ -222,10 +395,22 @@ static int acp_hw_init(void *handle) - */ - static int acp_hw_fini(void *handle) - { -+ int i, ret; -+ struct device *dev; -+ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - -+ for (i = 0; i < ACP_DEVS ; i++) { -+ dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); -+ ret = pm_genpd_remove_device(&adev->acp.acp_genpd->gpd, dev); -+ /* If removal fails, dont giveup and try rest */ -+ if (ret) -+ dev_err(dev, "remove dev from genpd failed\n"); -+ } -+ - mfd_remove_devices(adev->acp.parent); - kfree(adev->acp.acp_res); -+ kfree(adev->acp.acp_genpd); - kfree(adev->acp.acp_cell); - - return 0; -@@ -238,6 +423,25 @@ static int acp_suspend(void *handle) - - static int acp_resume(void *handle) - { -+ int i, ret; -+ struct acp_pm_domain *apd; -+ struct amdgpu_device *adev = (struct amdgpu_device *)handle; -+ -+ /* SMU block will power on ACP irrespective of ACP runtime status. -+ * Power off explicitly based on genpd ACP runtime status so that ACP -+ * hw and ACP-genpd status are in sync. -+ * 'suspend_power_off' represents "Power status before system suspend" -+ */ -+ if (adev->acp.acp_genpd->gpd.suspend_power_off == true) { -+ apd = container_of(&adev->acp.acp_genpd->gpd, -+ struct acp_pm_domain, gpd); -+ -+ for (i = 4; i >= 0 ; i--) { -+ ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i); -+ if (ret) -+ pr_err("ACP tile %d tile 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 24952ed..f6e32a6 100644 ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.h -@@ -34,6 +34,7 @@ struct amdgpu_acp { - struct amd_acp_private *private; - struct mfd_cell *acp_cell; - struct resource *acp_res; -+ struct acp_pm_domain *acp_genpd; - }; - - extern const struct amd_ip_funcs acp_ip_funcs; --- -2.7.4 - |