asoc: abox: check abox power domain status before resuming
authorHyunwoong Kim <khw0178.kim@samsung.com>
Wed, 20 Nov 2019 05:57:22 +0000 (14:57 +0900)
committerlingsen1 <lingsen1@lenovo.com>
Fri, 22 Nov 2019 05:43:59 +0000 (13:43 +0800)
ITMON error detected when abox driver accessed SFR of abox
in the step of resuming abox
The state of abox power domain was not off state at that time.
This patch check if abox power domain is off before abox driver
starts resuming abox H/W.

Change-Id: I6afd0d27540705cf6d140ffda94f6f24a567f27d
Signed-off-by: Hyunwoong Kim <khw0178.kim@samsung.com>
arch/arm64/boot/dts/exynos/exynos9610.dtsi
sound/soc/samsung/abox/abox.c
sound/soc/samsung/abox/abox.h

index 672ee462360abb6ce2b922f3a9c862106e6e39c4..000a2b074f441d37d03607ed1f9907b9654a020c 100644 (file)
                iommus = <&sysmmu_abox>;
                pm_qos_int = <0 0 0 0 0>;
                pm_qos_aud = <1180000 800000 590000 394000 0>;
+               pd_name = "pd-dispaud";
 
                abox_rdma_0: abox_rdma@0x14A51000 {
                        compatible = "samsung,abox-rdma";
index bde066184814c838b4efef37814bb1dc6b427d0d..460bbf31e3112939f647f70f2bab3401f474be71 100644 (file)
@@ -5591,6 +5591,7 @@ static int abox_pm_notifier(struct notifier_block *nb,
 {
        struct abox_data *data = container_of(nb, struct abox_data, pm_nb);
        struct device *dev = &data->pdev->dev;
+       int pd_status, retry = 0;
        int ret;
 
        dev_dbg(dev, "%s(%lu)\n", __func__, action);
@@ -5650,6 +5651,24 @@ static int abox_pm_notifier(struct notifier_block *nb,
                        dev_info(dev, "(%d)r suspend_state: %d\n", __LINE__,
                                        atomic_read(&data->suspend_state));
                        if (atomic_read(&data->suspend_state) == 1) {
+                               if (data->abox_pm_domain) {
+                                       do {
+                                               pd_status = exynos_pd_status(data->abox_pm_domain);
+                                               if (pd_status == 0) {
+                                                       dev_info(dev, "%s is off, go to ABOX initial sequence\n",
+                                                                       data->abox_pm_domain->name);
+                                                       break;
+                                               } else if (pd_status > 0) {
+                                                       dev_info(dev, "%s is still on, wait for 10ms\n",
+                                                                       data->abox_pm_domain->name);
+                                                       mdelay(10);
+                                               } else if (pd_status < 0) {
+                                                       dev_info(dev, "%s is in abnormal state\n",
+                                                                       data->abox_pm_domain->name);
+                                                       break;
+                                               }
+                                       } while (retry++ < 10);
+                               }
                                pm_runtime_get_sync(&data->pdev->dev);
                                atomic_set(&data->suspend_state, 0);
                        }
@@ -5788,6 +5807,7 @@ static int samsung_abox_probe(struct platform_device *pdev)
        struct platform_device *pdev_tmp;
        struct abox_data *data;
        phys_addr_t paddr;
+       const char *pd_name;
        int ret, i;
 
        dev_info(dev, "%s\n", __func__);
@@ -5975,6 +5995,14 @@ static int samsung_abox_probe(struct platform_device *pdev)
                }
        }
 
+       if (of_property_read_string(np, "pd_name", &pd_name)) {
+               dev_warn(dev, "no power domain\n");
+               data->abox_pm_domain = NULL;
+       } else {
+               dev_info(dev, "power domain: %s\n", pd_name);
+               data->abox_pm_domain = exynos_pd_lookup_name(pd_name);
+
+       }
        np_tmp = of_parse_phandle(np, "abox_gic", 0);
        if (!np_tmp) {
                dev_err(dev, "Failed to get abox_gic device node\n");
index e6461a98326b73e5ce4c42a35ab585163055c50d..a61b229cdb1bdcd31a191290e674114de349fda5 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/pm_wakeup.h>
 #include <sound/samsung/abox.h>
+#include <soc/samsung/exynos-pd.h>
 
 #define ABOX_MASK(name) (GENMASK(ABOX_##name##_H, ABOX_##name##_L))
 #define ABOX_MASK_ARG(name, x) (GENMASK(ABOX_##name##_H(x), ABOX_##name##_L(x)))
@@ -576,6 +577,7 @@ struct abox_data {
        void *dump_base;
        phys_addr_t dump_base_phys;
        struct iommu_domain *iommu_domain;
+       struct exynos_pm_domain *abox_pm_domain;
        unsigned int ipc_tx_offset;
        unsigned int ipc_rx_offset;
        unsigned int ipc_tx_ack_offset;