]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'tegra-for-4.7-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra...
authorArnd Bergmann <arnd@arndb.de>
Mon, 25 Apr 2016 21:46:15 +0000 (23:46 +0200)
committerArnd Bergmann <arnd@arndb.de>
Mon, 25 Apr 2016 21:46:15 +0000 (23:46 +0200)
Merge "soc/tegra: Changes for v4.7-rc1" from Thierry Reding:

This contains a bunch of preparatory patches to the PMC driver which are
a prerequisite to moving the driver to generic power domains.

* tag 'tegra-for-4.7-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  dt-bindings: Update NVIDIA PMC for Tegra
  soc/tegra: pmc: Wait for powergate state to change
  soc/tegra: pmc: Ensure GPU partition can be toggled on/off by PMC
  soc/tegra: pmc: Remove additional check for a valid partition
  soc/tegra: pmc: Fix verification of valid partitions
  soc/tegra: pmc: Fix testing of powergate state
  soc/tegra: pmc: Change powergate and rail IDs to be an unsigned type
  soc/tegra: pmc: Protect public functions from potential race conditions
  soc/tegra: pmc: Restore base address on probe failure
  soc/tegra: pmc: Remove non-existing L2 partition for Tegra124
  soc/tegra: pmc: Remove non-existing power partitions for Tegra210
  soc/tegra: pmc: Remove debugfs entry on probe failure
  soc/tegra: pmc: Fix sparse warning for tegra_pmc_init_tsense_reset()
  soc/tegra: pmc: Add missing structure members to kernel-doc

Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
arch/arm/mach-tegra/platsmp.c
drivers/gpu/drm/tegra/drm.h
drivers/soc/tegra/pmc.c
include/soc/tegra/pmc.h

index 02c27004d4a866e2e5d8bd5b3e72f41bae26c57e..53aa5496c5cfac84711aa4382ade1606ddb6434f 100644 (file)
@@ -6,11 +6,13 @@ modes. It provides power-gating controllers for SoC and CPU power-islands.
 
 Required properties:
 - name : Should be pmc
-- compatible : For Tegra20, must contain "nvidia,tegra20-pmc".  For Tegra30,
-  must contain "nvidia,tegra30-pmc".  For Tegra114, must contain
-  "nvidia,tegra114-pmc".  For Tegra124, must contain "nvidia,tegra124-pmc".
-  Otherwise, must contain "nvidia,<chip>-pmc", plus at least one of the
-  above, where <chip> is tegra132.
+- compatible : Should contain one of the following:
+       For Tegra20 must contain "nvidia,tegra20-pmc".
+       For Tegra30 must contain "nvidia,tegra30-pmc".
+       For Tegra114 must contain "nvidia,tegra114-pmc"
+       For Tegra124 must contain "nvidia,tegra124-pmc"
+       For Tegra132 must contain "nvidia,tegra124-pmc"
+       For Tegra210 must contain "nvidia,tegra210-pmc"
 - reg : Offset and length of the register set for the device
 - clocks : Must contain an entry for each entry in clock-names.
   See ../clocks/clock-bindings.txt for details.
index f3f61dbbda97b8f4fd09b42c34fd79903955ad34..75620ae73913a18d92fd4521b7ae06aea397e1e1 100644 (file)
@@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
         * be un-gated by un-toggling the power gate register
         * manually.
         */
-       if (!tegra_pmc_cpu_is_powered(cpu)) {
-               ret = tegra_pmc_cpu_power_on(cpu);
-               if (ret)
-                       return ret;
-
-               /* Wait for the power to come up. */
-               timeout = jiffies + msecs_to_jiffies(100);
-               while (!tegra_pmc_cpu_is_powered(cpu)) {
-                       if (time_after(jiffies, timeout))
-                               return -ETIMEDOUT;
-                       udelay(10);
-               }
-       }
+       ret = tegra_pmc_cpu_power_on(cpu);
+       if (ret)
+               return ret;
 
 remove_clamps:
        /* CPU partition is powered. Enable the CPU clock. */
index 8a10f5b7d9dce926f41dc402a7feaa4826425d23..f52d6cb24ff524ce771dd9aeabaf121c19824202 100644 (file)
@@ -121,7 +121,7 @@ struct tegra_dc {
        spinlock_t lock;
 
        struct drm_crtc base;
-       int powergate;
+       unsigned int powergate;
        int pipe;
 
        struct clk *clk;
index bc34cf7482fb559c6fcfdece56a5b4d88c24266b..08966c26d65cb959c379162c8905667584c22e0c 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
@@ -113,8 +114,11 @@ struct tegra_pmc_soc {
 
 /**
  * struct tegra_pmc - NVIDIA Tegra PMC
+ * @dev: pointer to PMC device structure
  * @base: pointer to I/O remapped register region
  * @clk: pointer to pclk clock
+ * @soc: pointer to SoC data structure
+ * @debugfs: pointer to debugfs entry
  * @rate: currently configured rate of pclk
  * @suspend_mode: lowest suspend mode available
  * @cpu_good_time: CPU power good time (in microseconds)
@@ -134,6 +138,7 @@ struct tegra_pmc {
        struct device *dev;
        void __iomem *base;
        struct clk *clk;
+       struct dentry *debugfs;
 
        const struct tegra_pmc_soc *soc;
 
@@ -170,38 +175,56 @@ static void tegra_pmc_writel(u32 value, unsigned long offset)
        writel(value, pmc->base + offset);
 }
 
+static inline bool tegra_powergate_state(int id)
+{
+       if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps)
+               return (tegra_pmc_readl(GPU_RG_CNTRL) & 0x1) == 0;
+       else
+               return (tegra_pmc_readl(PWRGATE_STATUS) & BIT(id)) != 0;
+}
+
+static inline bool tegra_powergate_is_valid(int id)
+{
+       return (pmc->soc && pmc->soc->powergates[id]);
+}
+
 /**
  * tegra_powergate_set() - set the state of a partition
  * @id: partition ID
  * @new_state: new state of the partition
  */
-static int tegra_powergate_set(int id, bool new_state)
+static int tegra_powergate_set(unsigned int id, bool new_state)
 {
        bool status;
+       int err;
 
-       mutex_lock(&pmc->powergates_lock);
+       if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps)
+               return -EINVAL;
 
-       status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
+       mutex_lock(&pmc->powergates_lock);
 
-       if (status == new_state) {
+       if (tegra_powergate_state(id) == new_state) {
                mutex_unlock(&pmc->powergates_lock);
                return 0;
        }
 
        tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
 
+       err = readx_poll_timeout(tegra_powergate_state, id, status,
+                                status == new_state, 10, 100000);
+
        mutex_unlock(&pmc->powergates_lock);
 
-       return 0;
+       return err;
 }
 
 /**
  * tegra_powergate_power_on() - power on partition
  * @id: partition ID
  */
-int tegra_powergate_power_on(int id)
+int tegra_powergate_power_on(unsigned int id)
 {
-       if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+       if (!tegra_powergate_is_valid(id))
                return -EINVAL;
 
        return tegra_powergate_set(id, true);
@@ -211,9 +234,9 @@ int tegra_powergate_power_on(int id)
  * tegra_powergate_power_off() - power off partition
  * @id: partition ID
  */
-int tegra_powergate_power_off(int id)
+int tegra_powergate_power_off(unsigned int id)
 {
-       if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+       if (!tegra_powergate_is_valid(id))
                return -EINVAL;
 
        return tegra_powergate_set(id, false);
@@ -224,28 +247,33 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
  * tegra_powergate_is_powered() - check if partition is powered
  * @id: partition ID
  */
-int tegra_powergate_is_powered(int id)
+int tegra_powergate_is_powered(unsigned int id)
 {
-       u32 status;
+       int status;
 
-       if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+       if (!tegra_powergate_is_valid(id))
                return -EINVAL;
 
-       status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id);
-       return !!status;
+       mutex_lock(&pmc->powergates_lock);
+       status = tegra_powergate_state(id);
+       mutex_unlock(&pmc->powergates_lock);
+
+       return status;
 }
 
 /**
  * tegra_powergate_remove_clamping() - remove power clamps for partition
  * @id: partition ID
  */
-int tegra_powergate_remove_clamping(int id)
+int tegra_powergate_remove_clamping(unsigned int id)
 {
        u32 mask;
 
-       if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates)
+       if (!tegra_powergate_is_valid(id))
                return -EINVAL;
 
+       mutex_lock(&pmc->powergates_lock);
+
        /*
         * On Tegra124 and later, the clamps for the GPU are controlled by a
         * separate register (with different semantics).
@@ -253,7 +281,7 @@ int tegra_powergate_remove_clamping(int id)
        if (id == TEGRA_POWERGATE_3D) {
                if (pmc->soc->has_gpu_clamps) {
                        tegra_pmc_writel(0, GPU_RG_CNTRL);
-                       return 0;
+                       goto out;
                }
        }
 
@@ -270,6 +298,9 @@ int tegra_powergate_remove_clamping(int id)
 
        tegra_pmc_writel(mask, REMOVE_CLAMPING);
 
+out:
+       mutex_unlock(&pmc->powergates_lock);
+
        return 0;
 }
 EXPORT_SYMBOL(tegra_powergate_remove_clamping);
@@ -282,7 +313,7 @@ EXPORT_SYMBOL(tegra_powergate_remove_clamping);
  *
  * Must be called with clk disabled, and returns with clk enabled.
  */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk,
+int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
                                      struct reset_control *rst)
 {
        int ret;
@@ -325,9 +356,9 @@ EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
  * Returns the partition ID corresponding to the CPU partition ID or a
  * negative error code on failure.
  */
-static int tegra_get_cpu_powergate_id(int cpuid)
+static int tegra_get_cpu_powergate_id(unsigned int cpuid)
 {
-       if (pmc->soc && cpuid > 0 && cpuid < pmc->soc->num_cpu_powergates)
+       if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates)
                return pmc->soc->cpu_powergates[cpuid];
 
        return -EINVAL;
@@ -337,7 +368,7 @@ static int tegra_get_cpu_powergate_id(int cpuid)
  * tegra_pmc_cpu_is_powered() - check if CPU partition is powered
  * @cpuid: CPU partition ID
  */
-bool tegra_pmc_cpu_is_powered(int cpuid)
+bool tegra_pmc_cpu_is_powered(unsigned int cpuid)
 {
        int id;
 
@@ -352,7 +383,7 @@ bool tegra_pmc_cpu_is_powered(int cpuid)
  * tegra_pmc_cpu_power_on() - power on CPU partition
  * @cpuid: CPU partition ID
  */
-int tegra_pmc_cpu_power_on(int cpuid)
+int tegra_pmc_cpu_power_on(unsigned int cpuid)
 {
        int id;
 
@@ -367,7 +398,7 @@ int tegra_pmc_cpu_power_on(int cpuid)
  * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition
  * @cpuid: CPU partition ID
  */
-int tegra_pmc_cpu_remove_clamping(int cpuid)
+int tegra_pmc_cpu_remove_clamping(unsigned int cpuid)
 {
        int id;
 
@@ -416,16 +447,18 @@ static struct notifier_block tegra_pmc_restart_handler = {
 static int powergate_show(struct seq_file *s, void *data)
 {
        unsigned int i;
+       int status;
 
        seq_printf(s, " powergate powered\n");
        seq_printf(s, "------------------\n");
 
        for (i = 0; i < pmc->soc->num_powergates; i++) {
-               if (!pmc->soc->powergates[i])
+               status = tegra_powergate_is_powered(i);
+               if (status < 0)
                        continue;
 
                seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i],
-                          tegra_powergate_is_powered(i) ? "yes" : "no");
+                          status ? "yes" : "no");
        }
 
        return 0;
@@ -445,17 +478,15 @@ static const struct file_operations powergate_fops = {
 
 static int tegra_powergate_debugfs_init(void)
 {
-       struct dentry *d;
-
-       d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
-                               &powergate_fops);
-       if (!d)
+       pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
+                                          &powergate_fops);
+       if (!pmc->debugfs)
                return -ENOMEM;
 
        return 0;
 }
 
-static int tegra_io_rail_prepare(int id, unsigned long *request,
+static int tegra_io_rail_prepare(unsigned int id, unsigned long *request,
                                 unsigned long *status, unsigned int *bit)
 {
        unsigned long rate, value;
@@ -512,15 +543,17 @@ static void tegra_io_rail_unprepare(void)
        tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
 }
 
-int tegra_io_rail_power_on(int id)
+int tegra_io_rail_power_on(unsigned int id)
 {
        unsigned long request, status, value;
        unsigned int bit, mask;
        int err;
 
+       mutex_lock(&pmc->powergates_lock);
+
        err = tegra_io_rail_prepare(id, &request, &status, &bit);
-       if (err < 0)
-               return err;
+       if (err)
+               goto error;
 
        mask = 1 << bit;
 
@@ -531,27 +564,32 @@ int tegra_io_rail_power_on(int id)
        tegra_pmc_writel(value, request);
 
        err = tegra_io_rail_poll(status, mask, 0, 250);
-       if (err < 0) {
+       if (err) {
                pr_info("tegra_io_rail_poll() failed: %d\n", err);
-               return err;
+               goto error;
        }
 
        tegra_io_rail_unprepare();
 
-       return 0;
+error:
+       mutex_unlock(&pmc->powergates_lock);
+
+       return err;
 }
 EXPORT_SYMBOL(tegra_io_rail_power_on);
 
-int tegra_io_rail_power_off(int id)
+int tegra_io_rail_power_off(unsigned int id)
 {
        unsigned long request, status, value;
        unsigned int bit, mask;
        int err;
 
+       mutex_lock(&pmc->powergates_lock);
+
        err = tegra_io_rail_prepare(id, &request, &status, &bit);
-       if (err < 0) {
+       if (err) {
                pr_info("tegra_io_rail_prepare() failed: %d\n", err);
-               return err;
+               goto error;
        }
 
        mask = 1 << bit;
@@ -563,12 +601,15 @@ int tegra_io_rail_power_off(int id)
        tegra_pmc_writel(value, request);
 
        err = tegra_io_rail_poll(status, mask, mask, 250);
-       if (err < 0)
-               return err;
+       if (err)
+               goto error;
 
        tegra_io_rail_unprepare();
 
-       return 0;
+error:
+       mutex_unlock(&pmc->powergates_lock);
+
+       return err;
 }
 EXPORT_SYMBOL(tegra_io_rail_power_off);
 
@@ -727,7 +768,7 @@ static void tegra_pmc_init(struct tegra_pmc *pmc)
        tegra_pmc_writel(value, PMC_CNTRL);
 }
 
-void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
+static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
 {
        static const char disabled[] = "emergency thermal reset disabled";
        u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux;
@@ -805,7 +846,7 @@ out:
 
 static int tegra_pmc_probe(struct platform_device *pdev)
 {
-       void __iomem *base = pmc->base;
+       void __iomem *base;
        struct resource *res;
        int err;
 
@@ -815,11 +856,9 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
        /* take over the memory region from the early initialization */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pmc->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(pmc->base))
-               return PTR_ERR(pmc->base);
-
-       iounmap(base);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        pmc->clk = devm_clk_get(&pdev->dev, "pclk");
        if (IS_ERR(pmc->clk)) {
@@ -842,11 +881,17 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
        err = register_restart_handler(&tegra_pmc_restart_handler);
        if (err) {
+               debugfs_remove(pmc->debugfs);
                dev_err(&pdev->dev, "unable to register restart handler, %d\n",
                        err);
                return err;
        }
 
+       mutex_lock(&pmc->powergates_lock);
+       iounmap(pmc->base);
+       pmc->base = base;
+       mutex_unlock(&pmc->powergates_lock);
+
        return 0;
 }
 
@@ -964,7 +1009,6 @@ static const char * const tegra124_powergates[] = {
        [TEGRA_POWERGATE_VENC] = "venc",
        [TEGRA_POWERGATE_PCIE] = "pcie",
        [TEGRA_POWERGATE_VDEC] = "vdec",
-       [TEGRA_POWERGATE_L2] = "l2",
        [TEGRA_POWERGATE_MPE] = "mpe",
        [TEGRA_POWERGATE_HEG] = "heg",
        [TEGRA_POWERGATE_SATA] = "sata",
@@ -1006,17 +1050,13 @@ static const char * const tegra210_powergates[] = {
        [TEGRA_POWERGATE_3D] = "3d",
        [TEGRA_POWERGATE_VENC] = "venc",
        [TEGRA_POWERGATE_PCIE] = "pcie",
-       [TEGRA_POWERGATE_L2] = "l2",
        [TEGRA_POWERGATE_MPE] = "mpe",
-       [TEGRA_POWERGATE_HEG] = "heg",
        [TEGRA_POWERGATE_SATA] = "sata",
        [TEGRA_POWERGATE_CPU1] = "cpu1",
        [TEGRA_POWERGATE_CPU2] = "cpu2",
        [TEGRA_POWERGATE_CPU3] = "cpu3",
-       [TEGRA_POWERGATE_CELP] = "celp",
        [TEGRA_POWERGATE_CPU0] = "cpu0",
        [TEGRA_POWERGATE_C0NC] = "c0nc",
-       [TEGRA_POWERGATE_C1NC] = "c1nc",
        [TEGRA_POWERGATE_SOR] = "sor",
        [TEGRA_POWERGATE_DIS] = "dis",
        [TEGRA_POWERGATE_DISB] = "disb",
index d18efe402ff1261c09e48b369bc689e4a5c8238d..07e332dd44fb4d4418d1d31f961fc1f80560e3ff 100644 (file)
@@ -33,9 +33,9 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_SMP
-bool tegra_pmc_cpu_is_powered(int cpuid);
-int tegra_pmc_cpu_power_on(int cpuid);
-int tegra_pmc_cpu_remove_clamping(int cpuid);
+bool tegra_pmc_cpu_is_powered(unsigned int cpuid);
+int tegra_pmc_cpu_power_on(unsigned int cpuid);
+int tegra_pmc_cpu_remove_clamping(unsigned int cpuid);
 #endif /* CONFIG_SMP */
 
 /*
@@ -108,50 +108,51 @@ int tegra_pmc_cpu_remove_clamping(int cpuid);
 #define TEGRA_IO_RAIL_SYS_DDC  58
 
 #ifdef CONFIG_ARCH_TEGRA
-int tegra_powergate_is_powered(int id);
-int tegra_powergate_power_on(int id);
-int tegra_powergate_power_off(int id);
-int tegra_powergate_remove_clamping(int id);
+int tegra_powergate_is_powered(unsigned int id);
+int tegra_powergate_power_on(unsigned int id);
+int tegra_powergate_power_off(unsigned int id);
+int tegra_powergate_remove_clamping(unsigned int id);
 
 /* Must be called with clk disabled, and returns with clk enabled */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk,
+int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
                                      struct reset_control *rst);
 
-int tegra_io_rail_power_on(int id);
-int tegra_io_rail_power_off(int id);
+int tegra_io_rail_power_on(unsigned int id);
+int tegra_io_rail_power_off(unsigned int id);
 #else
-static inline int tegra_powergate_is_powered(int id)
+static inline int tegra_powergate_is_powered(unsigned int id)
 {
        return -ENOSYS;
 }
 
-static inline int tegra_powergate_power_on(int id)
+static inline int tegra_powergate_power_on(unsigned int id)
 {
        return -ENOSYS;
 }
 
-static inline int tegra_powergate_power_off(int id)
+static inline int tegra_powergate_power_off(unsigned int id)
 {
        return -ENOSYS;
 }
 
-static inline int tegra_powergate_remove_clamping(int id)
+static inline int tegra_powergate_remove_clamping(unsigned int id)
 {
        return -ENOSYS;
 }
 
-static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk,
+static inline int tegra_powergate_sequence_power_up(unsigned int id,
+                                                   struct clk *clk,
                                                    struct reset_control *rst)
 {
        return -ENOSYS;
 }
 
-static inline int tegra_io_rail_power_on(int id)
+static inline int tegra_io_rail_power_on(unsigned int id)
 {
        return -ENOSYS;
 }
 
-static inline int tegra_io_rail_power_off(int id)
+static inline int tegra_io_rail_power_off(unsigned int id)
 {
        return -ENOSYS;
 }