tegra: adsp: add clock values in devicetree
Puneet Saxena [Thu, 30 Apr 2015 11:35:42 +0000 (16:35 +0530)]
It adds support to initialize adsp, ape and emc freq from
dt.

Bug 1637308

Change-Id: Id66e7404674349b77a96650e90805bc9c1346a3d
Signed-off-by: Puneet Saxena <puneets@nvidia.com>
Reviewed-on: http://git-master/r/737683
Signed-off-by: Ajay Nandakumar <anandakumarm@nvidia.com>
Reviewed-on: http://git-master/r/754352
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Nitin Kumbhar <nkumbhar@nvidia.com>

Documentation/devicetree/bindings/sound/tegra-adsp.txt
drivers/platform/tegra/nvadsp/adsp_dfs.c
drivers/platform/tegra/nvadsp/dev.c
drivers/platform/tegra/nvadsp/dev.h
drivers/platform/tegra/nvadsp/os.c

index 2925f8e..ee747dd 100644 (file)
@@ -13,6 +13,12 @@ Required properties:
                                contain the DEASSERT value. The ASSERT is ignored if the
                                value is equal to 0.
 
+Optional properties:
+ - nvidia,adsp_freq: should contain adsp boot up freq, multiple of 51.2 MHz
+ - nvidia,ape_freq: should contain ape boot up freq, half of adsp_freq
+ - nvidia,ape_emc_freq:        should contain appropriate emc freq w.r.t above
+                       adsp and ape freq
+
 Example:
        adsp {
             compatible = "nvidia,tegra210-adsp";
@@ -25,4 +31,8 @@ Example:
             nvidia,adsp_mem = <0x80300000 0x01000000>, /* ADSP OS */
                               <0x80B00000 0x00800000>; /* ADSP APP */
             nvidia,adsp_unit_fpga_reset = <0x0 0x00000040>;
+            nvidia,adsp_mem = <0x80300000 0x1000>;
+            nvidia,adsp_freq = <819000>; /* in KHz */
+            nvidia,ape_freq = <409500>; /* in KHz */
+            nvidia,ape_emc_freq = <102000>; /* in KHz */
        };
index e11245c..6786050 100644 (file)
@@ -146,28 +146,6 @@ static unsigned long adsp_get_target_freq(unsigned long tfreq, int *index)
        return 0;
 }
 
-/*
- * Static adsp freq to emc freq lookup table
- *
- * arg:
- *     adspfreq - adsp freq in KHz
- * return:
- *     0 - min emc freq
- *     > 0 - expected emc freq at this adsp freq
- */
-static u32 adsp_to_emc_freq(u32 adspfreq)
-{
-       /*
-        * Vote on memory bus frequency based on adsp frequency
-        * cpu rate is in kHz, emc rate is in Hz
-        */
-       if (adspfreq >= 204800)
-               return 102000;  /* adsp >= 204.8 MHz, emc 102 MHz */
-       else
-               return 0;               /* emc min */
-
-}
-
 static void adspfreq_stats_update(void)
 {
        unsigned long long cur_time;
@@ -673,7 +651,7 @@ int adsp_dfs_core_init(struct platform_device *pdev)
                goto end;
        }
 
-       policy->max = policy->cpu_max = drv->max_adsp_freq / 1000;
+       policy->max = policy->cpu_max = drv->adsp_freq / 1000;
 
        policy->min = policy->cpu_min = adsp_cpu_freq_table[0] / 1000;
 
index 9a184d9..69669a4 100644 (file)
@@ -171,6 +171,13 @@ static void nvadsp_clocks_disable(struct platform_device *pdev)
                drv_data->ape_clk = NULL;
        }
 
+       if (drv_data->ape_emc_clk) {
+               clk_disable_unprepare(drv_data->ape_emc_clk);
+               dev_dbg(dev, "ape.emc clock disabled\n");
+               drv_data->ape_emc_clk = NULL;
+       }
+
+
        if (drv_data->ahub_clk) {
                clk_disable_unprepare(drv_data->ahub_clk);
                dev_dbg(dev, "ahub clock disabled\n");
@@ -236,6 +243,20 @@ static int nvadsp_clocks_enable(struct platform_device *pdev)
        }
        dev_dbg(dev, "adsp cpu clock enabled\n");
 
+       drv_data->ape_emc_clk = clk_get_sys("ape", "emc");
+       if (IS_ERR_OR_NULL(drv_data->ape_emc_clk)) {
+               dev_err(dev, "unable to find ape.emc clock\n");
+               ret = PTR_ERR(drv_data->ape_emc_clk);
+               goto end;
+       }
+
+       ret = clk_prepare_enable(drv_data->ape_emc_clk);
+       if (ret) {
+               dev_err(dev, "unable to enable ape.emc clock\n");
+               goto end;
+       }
+       dev_dbg(dev, "ape.emc is enabled\n");
+
        drv_data->uartape_clk = clk_get_sys("uartape", NULL);
        if (IS_ERR_OR_NULL(drv_data->uartape_clk)) {
                dev_err(dev, "unable to find uart ape clk\n");
@@ -361,6 +382,30 @@ read_again:
 }
 EXPORT_SYMBOL(nvadsp_get_timestamp_counter);
 
+static void __init nvadsp_parse_clk_entries(struct platform_device *pdev)
+{
+       struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+       u32 val32 = 0;
+
+
+       /* Optional properties, should come from platform dt files */
+       if (of_property_read_u32(dev->of_node, "nvidia,adsp_freq", &val32))
+               dev_dbg(dev, "adsp_freq dt not found\n");
+       else
+               drv_data->adsp_freq = val32;
+
+       if (of_property_read_u32(dev->of_node, "nvidia,ape_freq", &val32))
+               dev_dbg(dev, "ape_freq dt not found\n");
+       else
+               drv_data->ape_freq = val32;
+
+       if (of_property_read_u32(dev->of_node, "nvidia,ape_emc_freq", &val32))
+               dev_dbg(dev, "ape_emc_freq dt not found\n");
+       else
+               drv_data->ape_emc_freq = val32;
+}
+
 static int __init nvadsp_parse_dt(struct platform_device *pdev)
 {
        struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
@@ -394,6 +439,7 @@ static int __init nvadsp_parse_dt(struct platform_device *pdev)
                        }
                }
        }
+       nvadsp_parse_clk_entries(pdev);
 
        return 0;
 }
index 2d58493..fa19511 100644 (file)
@@ -108,9 +108,12 @@ struct nvadsp_drv_data {
        struct clk *ape_clk;
        struct clk *adsp_clk;
        struct clk *adsp_cpu_clk;
+       struct clk *ape_emc_clk;
        struct clk *uartape_clk;
        struct clk *ahub_clk;
-       long max_adsp_freq;
+       unsigned long adsp_freq; /* in KHz*/
+       unsigned long ape_freq; /* in KHz*/
+       unsigned long ape_emc_freq; /* in KHz*/
 
        struct nvadsp_pm_state state;
        bool adsp_os_running;
@@ -140,6 +143,7 @@ status_t nvadsp_amc_init(struct platform_device *pdev);
 void adsp_cpu_set_rate(unsigned long freq);
 int adsp_dfs_core_init(struct platform_device *pdev);
 int adsp_dfs_core_exit(struct platform_device *pdev);
+u32 adsp_to_emc_freq(u32 adspfreq);
 #endif
 
 #ifdef CONFIG_TEGRA_ADSP_ACTMON
index c0e9646..ac72567 100644 (file)
@@ -714,6 +714,121 @@ end:
 }
 EXPORT_SYMBOL(nvadsp_os_load);
 
+/*
+ * Static adsp freq to emc freq lookup table
+ *
+ * arg:
+ *     adspfreq - adsp freq in KHz
+ * return:
+ *     0 - min emc freq
+ *     > 0 - expected emc freq at this adsp freq
+ */
+u32 adsp_to_emc_freq(u32 adspfreq)
+{
+       /*
+        * Vote on memory bus frequency based on adsp frequency
+        * cpu rate is in kHz, emc rate is in Hz
+        */
+       if (adspfreq >= 204800)
+               return 102000;  /* adsp >= 204.8 MHz, emc 102 MHz */
+       else
+               return 0;               /* emc min */
+}
+
+static int nvadsp_set_ape_emc_freq(struct nvadsp_drv_data *drv_data)
+{
+       unsigned long ape_emc_freq = drv_data->ape_emc_freq * 1000; /* in Hz */
+       struct device *dev = &priv.pdev->dev;
+       int ret;
+
+#ifdef CONFIG_TEGRA_ADSP_DFS
+        /* pass adsp freq in KHz. adsp_emc_freq in Hz */
+       ape_emc_freq = adsp_to_emc_freq(drv_data->adsp_freq / 1000) * 1000;
+#endif
+       dev_dbg(dev, "requested adsp cpu freq %luKHz",
+               drv_data->adsp_freq / 1000);
+       dev_dbg(dev, "ape.emc freq %luHz\n", ape_emc_freq / 1000);
+
+       ret = clk_set_rate(drv_data->ape_emc_clk, ape_emc_freq);
+
+       dev_info(dev, "ape.emc freq %luKHz\n",
+               clk_get_rate(drv_data->ape_emc_clk) / 1000);
+       return ret;
+}
+
+static int nvadsp_set_ape_freq(struct nvadsp_drv_data *drv_data)
+{
+       unsigned long ape_freq = drv_data->ape_freq * 1000; /* in Hz*/
+       struct device *dev = &priv.pdev->dev;
+       int ret;
+
+#ifdef CONFIG_TEGRA_ADSP_ACTMON
+       ape_freq = drv_data->adsp_freq / ADSP_TO_APE_CLK_RATIO;
+#endif
+       dev_dbg(dev, "ape freq %luKHz", ape_freq / 1000);
+
+       ret = clk_set_rate(drv_data->ape_clk, ape_freq);
+
+       dev_info(dev, "ape freq %luKHz\n",
+               clk_get_rate(drv_data->ape_clk) / 1000);
+       return ret;
+}
+
+static int set_adsp_clks_and_timer_prescalar(struct nvadsp_drv_data *drv_data)
+{
+       struct nvadsp_shared_mem *shared_mem = drv_data->shared_adsp_os_data;
+       struct nvadsp_os_args *os_args = &shared_mem->os_args;
+       struct device *dev = &priv.pdev->dev;
+       unsigned long max_adsp_freq;
+       unsigned long adsp_freq;
+       u32 max_index;
+       u32 cur_index;
+       int ret = 0;
+
+       adsp_freq = drv_data->adsp_freq * 1000; /* in Hz*/
+
+       max_adsp_freq = clk_round_rate(drv_data->adsp_cpu_clk,
+                               ULONG_MAX);
+       max_index = max_adsp_freq / MIN_ADSP_FREQ;
+       cur_index = adsp_freq / MIN_ADSP_FREQ;
+
+
+       if (!adsp_freq)
+               /* Set max adsp boot freq */
+               cur_index = max_index;
+
+       if (adsp_freq % MIN_ADSP_FREQ) {
+               if (cur_index >= max_index)
+                       cur_index = max_index;
+               else
+                       cur_index++;
+       } else if (cur_index >= max_index)
+               cur_index = max_index;
+
+       /*
+        * timer interval = (prescalar + 1) * (count + 1) / periph_freq
+        * therefore for 0 count,
+        * 1 / TIMER_CLK_HZ =  (prescalar + 1) / periph_freq
+        * Hence, prescalar = periph_freq / TIMER_CLK_HZ - 1
+        */
+       os_args->timer_prescalar = cur_index - 1;
+
+       adsp_freq = cur_index * MIN_ADSP_FREQ;
+
+       ret = clk_set_rate(drv_data->adsp_cpu_clk, adsp_freq);
+       if (ret)
+               goto end;
+
+       drv_data->adsp_freq = adsp_freq / 1000; /* adsp_freq in KHz*/
+
+end:
+       dev_info(dev, "adsp cpu freq %luKHz\n",
+               clk_get_rate(drv_data->adsp_cpu_clk) / 1000);
+       dev_dbg(dev, "timer prescalar %x\n", os_args->timer_prescalar);
+
+       return ret;
+}
+
 static int deassert_adsp(struct nvadsp_drv_data *drv_data)
 {
        struct device *dev = &priv.pdev->dev;
@@ -757,39 +872,36 @@ static int assert_adsp(struct nvadsp_drv_data *drv_data)
        return -EINVAL;
 }
 
-static int set_adsp_clks_and_timer_prescalar(struct nvadsp_drv_data *drv_data)
+static int nvadsp_set_boot_freqs(struct nvadsp_drv_data *drv_data)
 {
-       struct nvadsp_shared_mem *shared_mem = drv_data->shared_adsp_os_data;
-       struct nvadsp_os_args *os_args = &shared_mem->os_args;
-       struct device *dev = &priv.pdev->dev;
-       long max_adsp_freq;
-       int ret = -EINVAL;
+       int ret;
 
        /* on Unit-FPGA do not set clocks, return Sucess */
        if (drv_data->adsp_unit_fpga)
                return 0;
 
        if (drv_data->adsp_cpu_clk) {
-               max_adsp_freq = clk_round_rate(drv_data->adsp_cpu_clk,
-                               ULONG_MAX);
-               os_args->timer_prescalar = max_adsp_freq / MIN_ADSP_FREQ;
-               max_adsp_freq = MIN_ADSP_FREQ * os_args->timer_prescalar;
-               /*
-                * timer interval = (prescalar + 1) * (count + 1) / periph_freq
-                * therefore for 0 count,
-                * 1 / TIMER_CLK_HZ =  (prescalar + 1) / periph_freq
-                * Hence, prescalar = periph_freq / TIMER_CLK_HZ - 1
-                */
-               os_args->timer_prescalar--;
-               drv_data->max_adsp_freq = max_adsp_freq;
-               ret = clk_set_rate(drv_data->adsp_cpu_clk, max_adsp_freq);
+               ret = set_adsp_clks_and_timer_prescalar(drv_data);
+               if (ret)
+                       goto end;
+       } else {
+               ret = -EINVAL;
+               goto end;
+       }
 
-               dev_dbg(dev, "adsp cpu frequncy %lu and timer prescalar %x\n",
-                       clk_get_rate(drv_data->adsp_cpu_clk),
-                       os_args->timer_prescalar);
+       if (drv_data->ape_clk) {
+               ret = nvadsp_set_ape_freq(drv_data);
+               if (ret)
+                       goto end;
+       }
 
+       if (drv_data->ape_emc_clk) {
+               ret = nvadsp_set_ape_emc_freq(drv_data);
+               if (ret)
+                       goto end;
        }
 
+end:
        return ret;
 }
 
@@ -813,7 +925,7 @@ static int __nvadsp_os_start(void)
                     drv_data->state.evp,
                     AMC_EVP_SIZE);
 
-       ret = set_adsp_clks_and_timer_prescalar(drv_data);
+       ret = nvadsp_set_boot_freqs(drv_data);
        if (ret)
                goto end;
        ret = deassert_adsp(drv_data);