Merge branches 'clk-nvidia', 'clk-rockchip', 'clk-at91' and 'clk-vc5' into clk-next
authorStephen Boyd <sboyd@kernel.org>
Wed, 1 Sep 2021 22:26:58 +0000 (15:26 -0700)
committerStephen Boyd <sboyd@kernel.org>
Wed, 1 Sep 2021 22:26:58 +0000 (15:26 -0700)
 - Support the SD/OE pin on IDT VersaClock 5 and 6 clock generators

* clk-nvidia:
  clk: tegra: fix old-style declaration
  clk: tegra: Remove CLK_IS_CRITICAL flag from fuse clock
  soc/tegra: fuse: Enable fuse clock on suspend for Tegra124
  soc/tegra: fuse: Add runtime PM support
  soc/tegra: fuse: Clear fuse->clk on driver probe failure
  soc/tegra: pmc: Prevent racing with cpuilde driver
  soc/tegra: bpmp: Remove unused including <linux/version.h>

* clk-rockchip:
  clk: rockchip: make rk3308 ddrphy4x clock critical
  clk: rockchip: drop GRF dependency for rk3328/rk3036 pll types
  dt-bindings: clk: Convert rockchip,rk3399-cru to DT schema
  clk: rockchip: Add support for hclk_sfc on rk3036
  clk: rockchip: rk3036: fix up the sclk_sfc parent error
  clk: rockchip: add dt-binding clkid for hclk_sfc on rk3036

* clk-at91:
  clk: at91: clk-generated: Limit the requested rate to our range

* clk-vc5:
  clk: vc5: Add properties for configuring SD/OE behavior
  clk: vc5: Use dev_err_probe
  dt-bindings: clk: vc5: Add properties for configuring the SD/OE pin

21 files changed:
Documentation/devicetree/bindings/clock/idt,versaclock5.yaml
Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt [deleted file]
Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.yaml [new file with mode: 0644]
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/pm.h
arch/arm/mach-tegra/tegra.c
drivers/clk/at91/clk-generated.c
drivers/clk/clk-versaclock5.c
drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/clk-rk3036.c
drivers/clk/rockchip/clk-rk3308.c
drivers/clk/tegra/clk-dfll.c
drivers/clk/tegra/clk-tegra-periph.c
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/soc/tegra/fuse/fuse-tegra20.c
drivers/soc/tegra/fuse/fuse-tegra30.c
drivers/soc/tegra/fuse/fuse.h
drivers/soc/tegra/pmc.c
drivers/soc/tegra/powergate-bpmp.c
include/dt-bindings/clock/rk3036-cru.h
include/soc/tegra/pm.h

index 26ed040..ffd6ae0 100644 (file)
@@ -30,6 +30,20 @@ description: |
     3 -- OUT3
     4 -- OUT4
 
+  The idt,shutdown and idt,output-enable-active properties control the
+  SH (en_global_shutdown) and SP bits of the Primary Source and Shutdown
+  Register, respectively. Their behavior is summarized by the following
+  table:
+
+  SH SP Output when the SD/OE pin is Low/High
+  == == =====================================
+   0  0 Active/Inactive
+   0  1 Inactive/Active
+   1  0 Active/Shutdown
+   1  1 Inactive/Shutdown
+
+  The case where SH and SP are both 1 is likely not very interesting.
+
 maintainers:
   - Luca Ceresoli <luca@lucaceresoli.net>
 
@@ -64,6 +78,26 @@ properties:
     maximum: 22760
     description: Optional load capacitor for XTAL1 and XTAL2
 
+  idt,shutdown:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1]
+    description: |
+      If 1, this enables the shutdown functionality: the chip will be
+      shut down if the SD/OE pin is driven high. If 0, this disables the
+      shutdown functionality: the chip will never be shut down based on
+      the value of the SD/OE pin. This property corresponds to the SH
+      bit of the Primary Source and Shutdown Register.
+
+  idt,output-enable-active:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1]
+    description: |
+      If 1, this enables output when the SD/OE pin is high, and disables
+      output when the SD/OE pin is low. If 0, this disables output when
+      the SD/OE pin is high, and enables output when the SD/OE pin is
+      low. This corresponds to the SP bit of the Primary Source and
+      Shutdown Register.
+
 patternProperties:
   "^OUT[1-4]$":
     type: object
@@ -90,6 +124,8 @@ required:
   - compatible
   - reg
   - '#clock-cells'
+  - idt,shutdown
+  - idt,output-enable-active
 
 allOf:
   - if:
@@ -139,6 +175,10 @@ examples:
             clocks = <&ref25m>;
             clock-names = "xin";
 
+            /* Set the SD/OE pin's settings */
+            idt,shutdown = <0>;
+            idt,output-enable-active = <0>;
+
             OUT1 {
                 idt,mode = <VC5_CMOSD>;
                 idt,voltage-microvolt = <1800000>;
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt
deleted file mode 100644 (file)
index 3bc56fa..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-* Rockchip RK3399 Clock and Reset Unit
-
-The RK3399 clock controller generates and supplies clock to various
-controllers within the SoC and also implements a reset controller for SoC
-peripherals.
-
-Required Properties:
-
-- compatible: PMU for CRU should be "rockchip,rk3399-pmucru"
-- compatible: CRU should be "rockchip,rk3399-cru"
-- reg: physical base address of the controller and length of memory mapped
-  region.
-- #clock-cells: should be 1.
-- #reset-cells: should be 1.
-
-Optional Properties:
-
-- rockchip,grf: phandle to the syscon managing the "general register files".
-  It is used for GRF muxes, if missing any muxes present in the GRF will not
-  be available.
-
-Each clock is assigned an identifier and client nodes can use this identifier
-to specify the clock which they consume. All available clocks are defined as
-preprocessor macros in the dt-bindings/clock/rk3399-cru.h headers and can be
-used in device tree sources. Similar macros exist for the reset sources in
-these files.
-
-External clocks:
-
-There are several clocks that are generated outside the SoC. It is expected
-that they are defined using standard clock bindings with following
-clock-output-names:
- - "xin24m" - crystal input - required,
- - "xin32k" - rtc clock - optional,
- - "clkin_gmac" - external GMAC clock - optional,
- - "clkin_i2s" - external I2S clock - optional,
- - "pclkin_cif" - external ISP clock - optional,
- - "clk_usbphy0_480m" - output clock of the pll in the usbphy0
- - "clk_usbphy1_480m" - output clock of the pll in the usbphy1
-
-Example: Clock controller node:
-
-       pmucru: pmu-clock-controller@ff750000 {
-               compatible = "rockchip,rk3399-pmucru";
-               reg = <0x0 0xff750000 0x0 0x1000>;
-               #clock-cells = <1>;
-               #reset-cells = <1>;
-       };
-
-       cru: clock-controller@ff760000 {
-               compatible = "rockchip,rk3399-cru";
-               reg = <0x0 0xff760000 0x0 0x1000>;
-               #clock-cells = <1>;
-               #reset-cells = <1>;
-       };
-
-Example: UART controller node that consumes the clock generated by the clock
-  controller:
-
-       uart0: serial@ff1a0000 {
-               compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
-               reg = <0x0 0xff180000 0x0 0x100>;
-               clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
-               clock-names = "baudclk", "apb_pclk";
-               interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
-               reg-shift = <2>;
-               reg-io-width = <4>;
-       };
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.yaml b/Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.yaml
new file mode 100644 (file)
index 0000000..72b286a
--- /dev/null
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/rockchip,rk3399-cru.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip RK3399 Clock and Reset Unit
+
+maintainers:
+  - Xing Zheng <zhengxing@rock-chips.com>
+  - Heiko Stuebner <heiko@sntech.de>
+
+description: |
+  The RK3399 clock controller generates and supplies clock to various
+  controllers within the SoC and also implements a reset controller for SoC
+  peripherals.
+  Each clock is assigned an identifier and client nodes can use this identifier
+  to specify the clock which they consume. All available clocks are defined as
+  preprocessor macros in the dt-bindings/clock/rk3399-cru.h headers and can be
+  used in device tree sources. Similar macros exist for the reset sources in
+  these files.
+  There are several clocks that are generated outside the SoC. It is expected
+  that they are defined using standard clock bindings with following
+  clock-output-names:
+    - "xin24m" - crystal input - required,
+    - "xin32k" - rtc clock - optional,
+    - "clkin_gmac" - external GMAC clock - optional,
+    - "clkin_i2s" - external I2S clock - optional,
+    - "pclkin_cif" - external ISP clock - optional,
+    - "clk_usbphy0_480m" - output clock of the pll in the usbphy0
+    - "clk_usbphy1_480m" - output clock of the pll in the usbphy1
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk3399-pmucru
+      - rockchip,rk3399-cru
+
+  reg:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 1
+
+  "#reset-cells":
+    const: 1
+
+  clocks:
+    minItems: 1
+
+  assigned-clocks:
+    minItems: 1
+    maxItems: 64
+
+  assigned-clock-parents:
+    minItems: 1
+    maxItems: 64
+
+  assigned-clock-rates:
+    minItems: 1
+    maxItems: 64
+
+  rockchip,grf:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: >
+      phandle to the syscon managing the "general register files". It is used
+      for GRF muxes, if missing any muxes present in the GRF will not be
+      available.
+
+required:
+  - compatible
+  - reg
+  - "#clock-cells"
+  - "#reset-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    pmucru: pmu-clock-controller@ff750000 {
+      compatible = "rockchip,rk3399-pmucru";
+      reg = <0xff750000 0x1000>;
+      #clock-cells = <1>;
+      #reset-cells = <1>;
+    };
+  - |
+    cru: clock-controller@ff760000 {
+      compatible = "rockchip,rk3399-cru";
+      reg = <0xff760000 0x1000>;
+      #clock-cells = <1>;
+      #reset-cells = <1>;
+    };
index 6452ebf..b21f51b 100644 (file)
@@ -403,7 +403,7 @@ static const struct platform_suspend_ops tegra_suspend_ops = {
        .enter          = tegra_suspend_enter,
 };
 
-void __init tegra_init_suspend(void)
+void tegra_pm_init_suspend(void)
 {
        enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
 
index 81525f5..e63f96d 100644 (file)
@@ -25,10 +25,4 @@ void tegra30_sleep_core_init(void);
 
 extern void (*tegra_tear_down_cpu)(void);
 
-#ifdef CONFIG_PM_SLEEP
-void tegra_init_suspend(void);
-#else
-static inline void tegra_init_suspend(void) {}
-#endif
-
 #endif /* _MACH_TEGRA_PM_H_ */
index c011359..ab5008f 100644 (file)
@@ -84,8 +84,6 @@ static void __init tegra_dt_init(void)
 
 static void __init tegra_dt_init_late(void)
 {
-       tegra_init_suspend();
-
        if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
            of_machine_is_compatible("compal,paz00"))
                tegra_paz00_wifikill_init();
index b4fc8d7..b656d25 100644 (file)
@@ -128,6 +128,12 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
        int i;
        u32 div;
 
+       /* do not look for a rate that is outside of our range */
+       if (gck->range.max && req->rate > gck->range.max)
+               req->rate = gck->range.max;
+       if (gck->range.min && req->rate < gck->range.min)
+               req->rate = gck->range.min;
+
        for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
                if (gck->chg_pid == i)
                        continue;
index 3c73774..c6d3b1a 100644 (file)
@@ -907,6 +907,7 @@ static const struct of_device_id clk_vc5_of_match[];
 
 static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
+       unsigned int oe, sd, src_mask = 0, src_val = 0;
        struct vc5_driver_data *vc5;
        struct clk_init_data init;
        const char *parent_names[2];
@@ -930,11 +931,33 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -EPROBE_DEFER;
 
        vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config);
-       if (IS_ERR(vc5->regmap)) {
-               dev_err(&client->dev, "failed to allocate register map\n");
-               return PTR_ERR(vc5->regmap);
+       if (IS_ERR(vc5->regmap))
+               return dev_err_probe(&client->dev, PTR_ERR(vc5->regmap),
+                                    "failed to allocate register map\n");
+
+       ret = of_property_read_u32(client->dev.of_node, "idt,shutdown", &sd);
+       if (!ret) {
+               src_mask |= VC5_PRIM_SRC_SHDN_EN_GBL_SHDN;
+               if (sd)
+                       src_val |= VC5_PRIM_SRC_SHDN_EN_GBL_SHDN;
+       } else if (ret != -EINVAL) {
+               return dev_err_probe(&client->dev, ret,
+                                    "could not read idt,shutdown\n");
        }
 
+       ret = of_property_read_u32(client->dev.of_node,
+                                  "idt,output-enable-active", &oe);
+       if (!ret) {
+               src_mask |= VC5_PRIM_SRC_SHDN_SP;
+               if (oe)
+                       src_val |= VC5_PRIM_SRC_SHDN_SP;
+       } else if (ret != -EINVAL) {
+               return dev_err_probe(&client->dev, ret,
+                                    "could not read idt,output-enable-active\n");
+       }
+
+       regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, src_mask, src_val);
+
        /* Register clock input mux */
        memset(&init, 0, sizeof(init));
 
@@ -957,10 +980,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
                    __clk_get_name(vc5->pin_clkin);
        }
 
-       if (!init.num_parents) {
-               dev_err(&client->dev, "no input clock specified!\n");
-               return -EINVAL;
-       }
+       if (!init.num_parents)
+               return dev_err_probe(&client->dev, -EINVAL,
+                                    "no input clock specified!\n");
 
        /* Configure Optional Loading Capacitance for external XTAL */
        if (!(vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)) {
@@ -1099,14 +1121,16 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
        if (ret) {
-               dev_err(&client->dev, "unable to add clk provider\n");
+               dev_err_probe(&client->dev, ret,
+                             "unable to add clk provider\n");
                goto err_clk;
        }
 
        return 0;
 
 err_clk_register:
-       dev_err(&client->dev, "unable to register %s\n", init.name);
+       dev_err_probe(&client->dev, ret,
+                     "unable to register %s\n", init.name);
        kfree(init.name); /* clock framework made a copy of the name */
 err_clk:
        if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
index fe937bc..f7827b3 100644 (file)
@@ -940,7 +940,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
        switch (pll_type) {
        case pll_rk3036:
        case pll_rk3328:
-               if (!pll->rate_table || IS_ERR(ctx->grf))
+               if (!pll->rate_table)
                        init.ops = &rockchip_rk3036_pll_clk_norate_ops;
                else
                        init.ops = &rockchip_rk3036_pll_clk_ops;
index 614845c..d644bc1 100644 (file)
@@ -121,6 +121,7 @@ PNAME(mux_pll_src_3plls_p)  = { "apll", "dpll", "gpll" };
 PNAME(mux_timer_p)             = { "xin24m", "pclk_peri_src" };
 
 PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p)    = { "apll", "dpll", "gpll", "usb480m" };
+PNAME(mux_pll_src_dmyapll_dpll_gpll_xin24_p)   = { "dummy_apll", "dpll", "gpll", "xin24m" };
 
 PNAME(mux_mmc_src_p)   = { "apll", "dpll", "gpll", "xin24m" };
 PNAME(mux_i2s_pre_p)   = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
@@ -340,7 +341,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
                        RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS,
                        RK2928_CLKGATE_CON(10), 4, GFLAGS),
 
-       COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
+       COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_dmyapll_dpll_gpll_xin24_p, 0,
                        RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS,
                        RK2928_CLKGATE_CON(10), 5, GFLAGS),
 
@@ -403,7 +404,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
        GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS),
        GATE(HCLK_OTG1, "hclk_otg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 3, GFLAGS),
        GATE(HCLK_I2S, "hclk_i2s", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
-       GATE(0, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS),
+       GATE(HCLK_SFC, "hclk_sfc", "hclk_peri", 0, RK2928_CLKGATE_CON(3), 14, GFLAGS),
        GATE(HCLK_MAC, "hclk_mac", "hclk_peri", 0, RK2928_CLKGATE_CON(3), 5, GFLAGS),
 
        /* pclk_peri gates */
index 2c3bd0c..db3396c 100644 (file)
@@ -911,6 +911,7 @@ static const char *const rk3308_critical_clocks[] __initconst = {
        "hclk_audio",
        "pclk_audio",
        "sclk_ddrc",
+       "clk_ddrphy4x",
 };
 
 static void __init rk3308_clk_init(struct device_node *np)
index a5f526b..6144447 100644 (file)
@@ -1377,7 +1377,7 @@ static void dfll_debug_init(struct tegra_dfll *td)
 }
 
 #else
-static void inline dfll_debug_init(struct tegra_dfll *td) { }
+static inline void dfll_debug_init(struct tegra_dfll *td) { }
 #endif /* CONFIG_DEBUG_FS */
 
 /*
index 292d626..4dcf7f7 100644 (file)
@@ -777,11 +777,7 @@ static struct tegra_periph_init_data gate_clks[] = {
        GATE("ahbdma", "hclk", 33, 0, tegra_clk_ahbdma, 0),
        GATE("apbdma", "pclk", 34, 0, tegra_clk_apbdma, 0),
        GATE("kbc", "clk_32k", 36, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_kbc, 0),
-       /*
-        * Critical for RAM re-repair operation, which must occur on resume
-        * from LP1 system suspend and as part of CCPLEX cluster switching.
-        */
-       GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, CLK_IS_CRITICAL),
+       GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, 0),
        GATE("fuse_burn", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse_burn, 0),
        GATE("kfuse", "clk_m", 40, TEGRA_PERIPH_ON_APB, tegra_clk_kfuse, 0),
        GATE("apbif", "clk_m", 107, TEGRA_PERIPH_ON_APB, tegra_clk_apbif, 0),
index 3d9da3d..f215181 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 
@@ -210,6 +211,8 @@ static int tegra_fuse_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, fuse);
        fuse->dev = &pdev->dev;
 
+       pm_runtime_enable(&pdev->dev);
+
        if (fuse->soc->probe) {
                err = fuse->soc->probe(fuse);
                if (err < 0)
@@ -246,14 +249,71 @@ static int tegra_fuse_probe(struct platform_device *pdev)
        return 0;
 
 restore:
+       fuse->clk = NULL;
        fuse->base = base;
+       pm_runtime_disable(&pdev->dev);
        return err;
 }
 
+static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev)
+{
+       int err;
+
+       err = clk_prepare_enable(fuse->clk);
+       if (err < 0) {
+               dev_err(dev, "failed to enable FUSE clock: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused tegra_fuse_runtime_suspend(struct device *dev)
+{
+       clk_disable_unprepare(fuse->clk);
+
+       return 0;
+}
+
+static int __maybe_unused tegra_fuse_suspend(struct device *dev)
+{
+       int ret;
+
+       /*
+        * Critical for RAM re-repair operation, which must occur on resume
+        * from LP1 system suspend and as part of CCPLEX cluster switching.
+        */
+       if (fuse->soc->clk_suspend_on)
+               ret = pm_runtime_resume_and_get(dev);
+       else
+               ret = pm_runtime_force_suspend(dev);
+
+       return ret;
+}
+
+static int __maybe_unused tegra_fuse_resume(struct device *dev)
+{
+       int ret = 0;
+
+       if (fuse->soc->clk_suspend_on)
+               pm_runtime_put(dev);
+       else
+               ret = pm_runtime_force_resume(dev);
+
+       return ret;
+}
+
+static const struct dev_pm_ops tegra_fuse_pm = {
+       SET_RUNTIME_PM_OPS(tegra_fuse_runtime_suspend, tegra_fuse_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra_fuse_suspend, tegra_fuse_resume)
+};
+
 static struct platform_driver tegra_fuse_driver = {
        .driver = {
                .name = "tegra-fuse",
                .of_match_table = tegra_fuse_match,
+               .pm = &tegra_fuse_pm,
                .suppress_bind_attrs = true,
        },
        .probe = tegra_fuse_probe,
index 16aaa28..8ec9fc5 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kobject.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/random.h>
 
 #include <soc/tegra/fuse.h>
@@ -46,6 +47,10 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
        u32 value = 0;
        int err;
 
+       err = pm_runtime_resume_and_get(fuse->dev);
+       if (err)
+               return err;
+
        mutex_lock(&fuse->apbdma.lock);
 
        fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset;
@@ -66,8 +71,6 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
 
        reinit_completion(&fuse->apbdma.wait);
 
-       clk_prepare_enable(fuse->clk);
-
        dmaengine_submit(dma_desc);
        dma_async_issue_pending(fuse->apbdma.chan);
        time_left = wait_for_completion_timeout(&fuse->apbdma.wait,
@@ -78,10 +81,9 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
        else
                value = *fuse->apbdma.virt;
 
-       clk_disable_unprepare(fuse->clk);
-
 out:
        mutex_unlock(&fuse->apbdma.lock);
+       pm_runtime_put(fuse->dev);
        return value;
 }
 
@@ -165,4 +167,5 @@ const struct tegra_fuse_soc tegra20_fuse_soc = {
        .probe = tegra20_fuse_probe,
        .info = &tegra20_fuse_info,
        .soc_attr_group = &tegra_soc_attr_group,
+       .clk_suspend_on = false,
 };
index c1aa781..b071d43 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/random.h>
 
 #include <soc/tegra/fuse.h>
@@ -52,15 +53,13 @@ static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
        u32 value;
        int err;
 
-       err = clk_prepare_enable(fuse->clk);
-       if (err < 0) {
-               dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err);
+       err = pm_runtime_resume_and_get(fuse->dev);
+       if (err)
                return 0;
-       }
 
        value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
 
-       clk_disable_unprepare(fuse->clk);
+       pm_runtime_put(fuse->dev);
 
        return value;
 }
@@ -113,6 +112,7 @@ const struct tegra_fuse_soc tegra30_fuse_soc = {
        .speedo_init = tegra30_init_speedo_data,
        .info = &tegra30_fuse_info,
        .soc_attr_group = &tegra_soc_attr_group,
+       .clk_suspend_on = false,
 };
 #endif
 
@@ -128,6 +128,7 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
        .speedo_init = tegra114_init_speedo_data,
        .info = &tegra114_fuse_info,
        .soc_attr_group = &tegra_soc_attr_group,
+       .clk_suspend_on = false,
 };
 #endif
 
@@ -209,6 +210,7 @@ const struct tegra_fuse_soc tegra124_fuse_soc = {
        .lookups = tegra124_fuse_lookups,
        .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
        .soc_attr_group = &tegra_soc_attr_group,
+       .clk_suspend_on = true,
 };
 #endif
 
@@ -295,6 +297,7 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
        .lookups = tegra210_fuse_lookups,
        .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
        .soc_attr_group = &tegra_soc_attr_group,
+       .clk_suspend_on = false,
 };
 #endif
 
@@ -325,6 +328,7 @@ const struct tegra_fuse_soc tegra186_fuse_soc = {
        .lookups = tegra186_fuse_lookups,
        .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
        .soc_attr_group = &tegra_soc_attr_group,
+       .clk_suspend_on = false,
 };
 #endif
 
@@ -355,6 +359,7 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
        .lookups = tegra194_fuse_lookups,
        .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
        .soc_attr_group = &tegra194_soc_attr_group,
+       .clk_suspend_on = false,
 };
 #endif
 
@@ -385,5 +390,6 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
        .lookups = tegra234_fuse_lookups,
        .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
        .soc_attr_group = &tegra194_soc_attr_group,
+       .clk_suspend_on = false,
 };
 #endif
index e057a58..de58feb 100644 (file)
@@ -34,6 +34,8 @@ struct tegra_fuse_soc {
        unsigned int num_lookups;
 
        const struct attribute_group *soc_attr_group;
+
+       bool clk_suspend_on;
 };
 
 struct tegra_fuse {
index ea62f84..50091c4 100644 (file)
@@ -436,7 +436,7 @@ struct tegra_pmc {
 
 static struct tegra_pmc *pmc = &(struct tegra_pmc) {
        .base = NULL,
-       .suspend_mode = TEGRA_SUSPEND_NONE,
+       .suspend_mode = TEGRA_SUSPEND_NOT_READY,
 };
 
 static inline struct tegra_powergate *
@@ -1812,6 +1812,7 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
        u32 value, values[2];
 
        if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) {
+               pmc->suspend_mode = TEGRA_SUSPEND_NONE;
        } else {
                switch (value) {
                case 0:
@@ -2785,6 +2786,11 @@ static int tegra_pmc_regmap_init(struct tegra_pmc *pmc)
        return 0;
 }
 
+static void tegra_pmc_reset_suspend_mode(void *data)
+{
+       pmc->suspend_mode = TEGRA_SUSPEND_NOT_READY;
+}
+
 static int tegra_pmc_probe(struct platform_device *pdev)
 {
        void __iomem *base;
@@ -2803,6 +2809,11 @@ static int tegra_pmc_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
+       err = devm_add_action_or_reset(&pdev->dev, tegra_pmc_reset_suspend_mode,
+                                      NULL);
+       if (err)
+               return err;
+
        /* take over the memory region from the early initialization */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
@@ -2909,6 +2920,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
        tegra_pmc_clock_register(pmc, pdev->dev.of_node);
        platform_set_drvdata(pdev, pmc);
+       tegra_pm_init_suspend();
 
        return 0;
 
index 06c792b..8eaf50d 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 
 #include <soc/tegra/bpmp.h>
 #include <soc/tegra/bpmp-abi.h>
index 35a5a01..a96a987 100644 (file)
@@ -81,6 +81,7 @@
 #define HCLK_OTG0              449
 #define HCLK_OTG1              450
 #define HCLK_NANDC             453
+#define HCLK_SFC               454
 #define HCLK_SDMMC             456
 #define HCLK_SDIO              457
 #define HCLK_EMMC              459
index 08477d7..4338789 100644 (file)
@@ -14,6 +14,7 @@ enum tegra_suspend_mode {
        TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
        TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
        TEGRA_MAX_SUSPEND_MODE,
+       TEGRA_SUSPEND_NOT_READY,
 };
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
@@ -28,6 +29,7 @@ void tegra_pm_clear_cpu_in_lp2(void);
 void tegra_pm_set_cpu_in_lp2(void);
 int tegra_pm_enter_lp2(void);
 int tegra_pm_park_secondary_cpu(unsigned long cpu);
+void tegra_pm_init_suspend(void);
 #else
 static inline enum tegra_suspend_mode
 tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode)
@@ -61,6 +63,10 @@ static inline int tegra_pm_park_secondary_cpu(unsigned long cpu)
 {
        return -ENOTSUPP;
 }
+
+static inline void tegra_pm_init_suspend(void)
+{
+}
 #endif /* CONFIG_PM_SLEEP */
 
 #endif /* __SOC_TEGRA_PM_H__ */