aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0258-drm-amd-add-pm-domain-for-ACP-IP-sub-blocks.patch
diff options
context:
space:
mode:
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.patch311
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
-