drivers: tegra: EMC floor control for userland
Sai Gurrappadi [Wed, 8 Apr 2015 17:33:51 +0000 (10:33 -0700)]
EMC freq floor can now be set via pmqos by doing:

echo "<emc_freq_khz>" > /dev/emc_freq_min

This change is a straight port of the equivalent T124 change:
d3626864ae9aca28b4f999ce3b35deb4c7a82ac5

Bug 1631192

Change-Id: Idd558602e9d6386970981290d14e660ba00c090e
Signed-off-by: Sai Gurrappadi <sgurrappadi@nvidia.com>
Reviewed-on: http://git-master/r/729927
(cherry picked from commit b945e1e46895c4262e8df8812f5b334cee5b0b4a)
Reviewed-on: http://git-master/r/825152
Tested-by: Michael I Gold <gold@nvidia.com>
Reviewed-by: David Dastous St Hilaire <ddastoussthi@nvidia.com>
Reviewed-by: Michael I Gold <gold@nvidia.com>

drivers/platform/tegra/tegra21_clocks.c
drivers/platform/tegra/tegra21_dvfs.c

index 3fa5b45..9ae33d2 100644 (file)
@@ -9640,12 +9640,13 @@ static struct clk tegra_list_clks[] = {
        SHARED_EMC_CLK("camera.emc", "tegra_camera_ctrl",       "emc",  &tegra_clk_emc, NULL, 0, SHARED_BW, 0, TEGRA210_CLK_ID_EMC_CAMERA_USER),
        SHARED_EMC_CLK("camera_iso.emc", "tegra_camera_ctrl",   "iso.emc",      &tegra_clk_emc, NULL, 0, SHARED_ISO_BW, 0, TEGRA210_CLK_ID_EMC_CAMERA_ISO_USER),
        SHARED_EMC_CLK("iso.emc",       "iso",          "emc",  &tegra_clk_emc, NULL, 0, 0, 0, TEGRA210_CLK_ID_EMC_ISO_USER),
-       SHARED_EMC_CLK("floor.emc",     "floor.emc",    NULL,   &tegra_clk_emc, NULL, 0, 0, 0, 0),
        SHARED_EMC_CLK("override.emc", "override.emc",  NULL,   &tegra_clk_emc, NULL, 0, SHARED_OVERRIDE, 0, 0),
        SHARED_EMC_CLK("vic.emc",       "tegra_vic03",  "emc",  &tegra_clk_emc, NULL, 0, 0, 0, TEGRA210_CLK_ID_EMC_VIC_USER),
        SHARED_EMC_CLK("vic_shared.emc",        "tegra_vic03",  "emc_shared",  &tegra_clk_emc, NULL, 0, SHARED_BW, 0, TEGRA210_CLK_ID_EMC_VIC_SHARED_USER),
        SHARED_EMC_CLK("battery.emc",   "battery_edp",  "emc",  &tegra_clk_emc, NULL, 0, SHARED_CEILING, 0, 0),
        SHARED_EMC_CLK("ape.emc", "ape", "emc",  &tegra_clk_emc, NULL, 0, 0, 0, TEGRA210_CLK_ID_EMC_APE_USER),
+       SHARED_EMC_CLK("floor.emc",     "floor.emc",    NULL,   &tegra_clk_emc, NULL, 0, 0, 0, 0),
+       SHARED_EMC_CLK("floor.profile.emc", "profile.emc", "floor", &tegra_clk_emc, NULL,  0, 0, 0, 0),
        SHARED_EMC_CLK("pcie.emc", "tegra_pcie", "emc",  &tegra_clk_emc, NULL, 0, 0, 0, TEGRA210_CLK_ID_EMC_PCIE_USER),
 
        DUAL_CBUS_CLK("vic03.cbus",     "tegra_vic03",          "vic03", &tegra_clk_c2bus, "vic03", 0, 0, TEGRA210_CLK_ID_CXBUS_VIC_USER),
index 1a9e526..e612fe2 100644 (file)
@@ -2098,6 +2098,7 @@ int tegra_dvfs_rail_post_enable(struct dvfs_rail *rail)
 /* Core voltage and bus cap object and tables */
 static struct kobject *cap_kobj;
 static struct kobject *gpu_kobj;
+static struct kobject *emc_kobj;
 
 static struct core_dvfs_cap_table tegra21_core_cap_table[] = {
        { .cap_name = "cap.vcore.c2bus" },
@@ -2134,6 +2135,20 @@ static struct core_bus_rates_table tegra21_gpu_rates_sysfs = {
                .attr = {.name = "gpu_time_at_user_rate", .mode = 0444} },
 };
 
+static struct core_bus_limit_table tegra21_emc_floor_sysfs = {
+       .limit_clk_name = "floor.profile.emc",
+       .refcnt_attr = {.attr = {.name = "emc_floor_state", .mode = 0644} },
+       .level_attr  = {.attr = {.name = "emc_floor_rate", .mode = 0644} },
+       .pm_qos_class = PM_QOS_EMC_FREQ_MIN,
+};
+
+static struct core_bus_rates_table tegra21_emc_rates_sysfs = {
+       .bus_clk_name = "emc",
+       .rate_attr = {.attr = {.name = "emc_rate", .mode = 0444} },
+       .available_rates_attr = {
+               .attr = {.name = "emc_available_rates", .mode = 0444} },
+};
+
 /*
  * Core Vmax cooling device registration:
  * - Use VDD_CORE capping method provided by DVFS
@@ -2223,7 +2238,31 @@ static int __init tegra21_dvfs_init_core_cap(void)
                return 0;
        }
 
-       pr_info("tegra dvfs: tegra sysfs gpu interface is initialized\n");
+       emc_kobj = kobject_create_and_add("tegra_emc", kernel_kobj);
+       if (!emc_kobj) {
+               pr_err("tegra21_dvfs: failed to create sysfs emc object\n");
+               return 0;
+       }
+
+       ret = tegra_init_sysfs_shared_bus_rate(&tegra21_emc_rates_sysfs,
+                                              1, emc_kobj);
+       if (ret) {
+               pr_err("tegra21_dvfs: failed to init emc rates interface (%d)\n",
+                      ret);
+               kobject_del(emc_kobj);
+               return 0;
+       }
+
+       ret = tegra_init_shared_bus_floor(&tegra21_emc_floor_sysfs,
+                                         1, emc_kobj);
+       if (ret) {
+               pr_err("tegra21_dvfs: failed to init emc floor interface (%d)\n",
+                      ret);
+               kobject_del(emc_kobj);
+               return 0;
+       }
+
+       pr_info("tegra dvfs: tegra sysfs gpu & emc interface is initialized\n");
 
        return 0;
 }