Merge branches 'clk-nvidia', 'clk-rockchip', 'clk-at91' and 'clk-vc5' into clk-next

- 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
This commit is contained in:
Stephen Boyd 2021-09-01 15:26:58 -07:00
Коммит 8fb59ce15c
21 изменённых файлов: 279 добавлений и 106 удалений

Просмотреть файл

@ -30,6 +30,20 @@ description: |
3 -- OUT3 3 -- OUT3
4 -- OUT4 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: maintainers:
- Luca Ceresoli <luca@lucaceresoli.net> - Luca Ceresoli <luca@lucaceresoli.net>
@ -64,6 +78,26 @@ properties:
maximum: 22760 maximum: 22760
description: Optional load capacitor for XTAL1 and XTAL2 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: patternProperties:
"^OUT[1-4]$": "^OUT[1-4]$":
type: object type: object
@ -90,6 +124,8 @@ required:
- compatible - compatible
- reg - reg
- '#clock-cells' - '#clock-cells'
- idt,shutdown
- idt,output-enable-active
allOf: allOf:
- if: - if:
@ -139,6 +175,10 @@ examples:
clocks = <&ref25m>; clocks = <&ref25m>;
clock-names = "xin"; clock-names = "xin";
/* Set the SD/OE pin's settings */
idt,shutdown = <0>;
idt,output-enable-active = <0>;
OUT1 { OUT1 {
idt,mode = <VC5_CMOSD>; idt,mode = <VC5_CMOSD>;
idt,voltage-microvolt = <1800000>; idt,voltage-microvolt = <1800000>;

Просмотреть файл

@ -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>;
};

Просмотреть файл

@ -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>;
};

Просмотреть файл

@ -403,7 +403,7 @@ static const struct platform_suspend_ops tegra_suspend_ops = {
.enter = tegra_suspend_enter, .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(); enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();

Просмотреть файл

@ -25,10 +25,4 @@ void tegra30_sleep_core_init(void);
extern void (*tegra_tear_down_cpu)(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_ */ #endif /* _MACH_TEGRA_PM_H_ */

Просмотреть файл

@ -84,8 +84,6 @@ static void __init tegra_dt_init(void)
static void __init tegra_dt_init_late(void) static void __init tegra_dt_init_late(void)
{ {
tegra_init_suspend();
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
of_machine_is_compatible("compal,paz00")) of_machine_is_compatible("compal,paz00"))
tegra_paz00_wifikill_init(); tegra_paz00_wifikill_init();

Просмотреть файл

@ -128,6 +128,12 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
int i; int i;
u32 div; 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++) { for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
if (gck->chg_pid == i) if (gck->chg_pid == i)
continue; continue;

Просмотреть файл

@ -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) 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 vc5_driver_data *vc5;
struct clk_init_data init; struct clk_init_data init;
const char *parent_names[2]; 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; return -EPROBE_DEFER;
vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config); vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config);
if (IS_ERR(vc5->regmap)) { if (IS_ERR(vc5->regmap))
dev_err(&client->dev, "failed to allocate register map\n"); return dev_err_probe(&client->dev, PTR_ERR(vc5->regmap),
return 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 */ /* Register clock input mux */
memset(&init, 0, sizeof(init)); 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); __clk_get_name(vc5->pin_clkin);
} }
if (!init.num_parents) { if (!init.num_parents)
dev_err(&client->dev, "no input clock specified!\n"); return dev_err_probe(&client->dev, -EINVAL,
return -EINVAL; "no input clock specified!\n");
}
/* Configure Optional Loading Capacitance for external XTAL */ /* Configure Optional Loading Capacitance for external XTAL */
if (!(vc5->chip_info->flags & VC5_HAS_INTERNAL_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); ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
if (ret) { 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; goto err_clk;
} }
return 0; return 0;
err_clk_register: 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 */ kfree(init.name); /* clock framework made a copy of the name */
err_clk: err_clk:
if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)

Просмотреть файл

@ -940,7 +940,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
switch (pll_type) { switch (pll_type) {
case pll_rk3036: case pll_rk3036:
case pll_rk3328: case pll_rk3328:
if (!pll->rate_table || IS_ERR(ctx->grf)) if (!pll->rate_table)
init.ops = &rockchip_rk3036_pll_clk_norate_ops; init.ops = &rockchip_rk3036_pll_clk_norate_ops;
else else
init.ops = &rockchip_rk3036_pll_clk_ops; init.ops = &rockchip_rk3036_pll_clk_ops;

Просмотреть файл

@ -121,6 +121,7 @@ PNAME(mux_pll_src_3plls_p) = { "apll", "dpll", "gpll" };
PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" }; 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_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_mmc_src_p) = { "apll", "dpll", "gpll", "xin24m" };
PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; 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_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS,
RK2928_CLKGATE_CON(10), 4, GFLAGS), 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_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS,
RK2928_CLKGATE_CON(10), 5, GFLAGS), 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_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_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(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), GATE(HCLK_MAC, "hclk_mac", "hclk_peri", 0, RK2928_CLKGATE_CON(3), 5, GFLAGS),
/* pclk_peri gates */ /* pclk_peri gates */

Просмотреть файл

@ -911,6 +911,7 @@ static const char *const rk3308_critical_clocks[] __initconst = {
"hclk_audio", "hclk_audio",
"pclk_audio", "pclk_audio",
"sclk_ddrc", "sclk_ddrc",
"clk_ddrphy4x",
}; };
static void __init rk3308_clk_init(struct device_node *np) static void __init rk3308_clk_init(struct device_node *np)

Просмотреть файл

@ -1377,7 +1377,7 @@ static void dfll_debug_init(struct tegra_dfll *td)
} }
#else #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 */ #endif /* CONFIG_DEBUG_FS */
/* /*

Просмотреть файл

@ -777,11 +777,7 @@ static struct tegra_periph_init_data gate_clks[] = {
GATE("ahbdma", "hclk", 33, 0, tegra_clk_ahbdma, 0), GATE("ahbdma", "hclk", 33, 0, tegra_clk_ahbdma, 0),
GATE("apbdma", "pclk", 34, 0, tegra_clk_apbdma, 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), GATE("kbc", "clk_32k", 36, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_kbc, 0),
/* GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, 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_burn", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse_burn, 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("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), GATE("apbif", "clk_m", 107, TEGRA_PERIPH_ON_APB, tegra_clk_apbif, 0),

Просмотреть файл

@ -13,6 +13,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
@ -210,6 +211,8 @@ static int tegra_fuse_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fuse); platform_set_drvdata(pdev, fuse);
fuse->dev = &pdev->dev; fuse->dev = &pdev->dev;
pm_runtime_enable(&pdev->dev);
if (fuse->soc->probe) { if (fuse->soc->probe) {
err = fuse->soc->probe(fuse); err = fuse->soc->probe(fuse);
if (err < 0) if (err < 0)
@ -246,14 +249,71 @@ static int tegra_fuse_probe(struct platform_device *pdev)
return 0; return 0;
restore: restore:
fuse->clk = NULL;
fuse->base = base; fuse->base = base;
pm_runtime_disable(&pdev->dev);
return err; 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 = { static struct platform_driver tegra_fuse_driver = {
.driver = { .driver = {
.name = "tegra-fuse", .name = "tegra-fuse",
.of_match_table = tegra_fuse_match, .of_match_table = tegra_fuse_match,
.pm = &tegra_fuse_pm,
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
}, },
.probe = tegra_fuse_probe, .probe = tegra_fuse_probe,

Просмотреть файл

@ -16,6 +16,7 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/random.h> #include <linux/random.h>
#include <soc/tegra/fuse.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; u32 value = 0;
int err; int err;
err = pm_runtime_resume_and_get(fuse->dev);
if (err)
return err;
mutex_lock(&fuse->apbdma.lock); mutex_lock(&fuse->apbdma.lock);
fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset; 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); reinit_completion(&fuse->apbdma.wait);
clk_prepare_enable(fuse->clk);
dmaengine_submit(dma_desc); dmaengine_submit(dma_desc);
dma_async_issue_pending(fuse->apbdma.chan); dma_async_issue_pending(fuse->apbdma.chan);
time_left = wait_for_completion_timeout(&fuse->apbdma.wait, 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 else
value = *fuse->apbdma.virt; value = *fuse->apbdma.virt;
clk_disable_unprepare(fuse->clk);
out: out:
mutex_unlock(&fuse->apbdma.lock); mutex_unlock(&fuse->apbdma.lock);
pm_runtime_put(fuse->dev);
return value; return value;
} }
@ -165,4 +167,5 @@ const struct tegra_fuse_soc tegra20_fuse_soc = {
.probe = tegra20_fuse_probe, .probe = tegra20_fuse_probe,
.info = &tegra20_fuse_info, .info = &tegra20_fuse_info,
.soc_attr_group = &tegra_soc_attr_group, .soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
}; };

Просмотреть файл

@ -12,6 +12,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/random.h> #include <linux/random.h>
#include <soc/tegra/fuse.h> #include <soc/tegra/fuse.h>
@ -52,15 +53,13 @@ static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
u32 value; u32 value;
int err; int err;
err = clk_prepare_enable(fuse->clk); err = pm_runtime_resume_and_get(fuse->dev);
if (err < 0) { if (err)
dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err);
return 0; return 0;
}
value = readl_relaxed(fuse->base + FUSE_BEGIN + offset); value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
clk_disable_unprepare(fuse->clk); pm_runtime_put(fuse->dev);
return value; return value;
} }
@ -113,6 +112,7 @@ const struct tegra_fuse_soc tegra30_fuse_soc = {
.speedo_init = tegra30_init_speedo_data, .speedo_init = tegra30_init_speedo_data,
.info = &tegra30_fuse_info, .info = &tegra30_fuse_info,
.soc_attr_group = &tegra_soc_attr_group, .soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
}; };
#endif #endif
@ -128,6 +128,7 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
.speedo_init = tegra114_init_speedo_data, .speedo_init = tegra114_init_speedo_data,
.info = &tegra114_fuse_info, .info = &tegra114_fuse_info,
.soc_attr_group = &tegra_soc_attr_group, .soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
}; };
#endif #endif
@ -209,6 +210,7 @@ const struct tegra_fuse_soc tegra124_fuse_soc = {
.lookups = tegra124_fuse_lookups, .lookups = tegra124_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups), .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
.soc_attr_group = &tegra_soc_attr_group, .soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = true,
}; };
#endif #endif
@ -295,6 +297,7 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
.lookups = tegra210_fuse_lookups, .lookups = tegra210_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups), .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
.soc_attr_group = &tegra_soc_attr_group, .soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
}; };
#endif #endif
@ -325,6 +328,7 @@ const struct tegra_fuse_soc tegra186_fuse_soc = {
.lookups = tegra186_fuse_lookups, .lookups = tegra186_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups), .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
.soc_attr_group = &tegra_soc_attr_group, .soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
}; };
#endif #endif
@ -355,6 +359,7 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
.lookups = tegra194_fuse_lookups, .lookups = tegra194_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra194_fuse_lookups), .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
.soc_attr_group = &tegra194_soc_attr_group, .soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
}; };
#endif #endif
@ -385,5 +390,6 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
.lookups = tegra234_fuse_lookups, .lookups = tegra234_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra234_fuse_lookups), .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
.soc_attr_group = &tegra194_soc_attr_group, .soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
}; };
#endif #endif

Просмотреть файл

@ -34,6 +34,8 @@ struct tegra_fuse_soc {
unsigned int num_lookups; unsigned int num_lookups;
const struct attribute_group *soc_attr_group; const struct attribute_group *soc_attr_group;
bool clk_suspend_on;
}; };
struct tegra_fuse { struct tegra_fuse {

Просмотреть файл

@ -436,7 +436,7 @@ struct tegra_pmc {
static struct tegra_pmc *pmc = &(struct tegra_pmc) { static struct tegra_pmc *pmc = &(struct tegra_pmc) {
.base = NULL, .base = NULL,
.suspend_mode = TEGRA_SUSPEND_NONE, .suspend_mode = TEGRA_SUSPEND_NOT_READY,
}; };
static inline struct tegra_powergate * 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]; u32 value, values[2];
if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) { if (of_property_read_u32(np, "nvidia,suspend-mode", &value)) {
pmc->suspend_mode = TEGRA_SUSPEND_NONE;
} else { } else {
switch (value) { switch (value) {
case 0: case 0:
@ -2785,6 +2786,11 @@ static int tegra_pmc_regmap_init(struct tegra_pmc *pmc)
return 0; 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) static int tegra_pmc_probe(struct platform_device *pdev)
{ {
void __iomem *base; void __iomem *base;
@ -2803,6 +2809,11 @@ static int tegra_pmc_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
return err; 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 */ /* take over the memory region from the early initialization */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res); 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); tegra_pmc_clock_register(pmc, pdev->dev.of_node);
platform_set_drvdata(pdev, pmc); platform_set_drvdata(pdev, pmc);
tegra_pm_init_suspend();
return 0; return 0;

Просмотреть файл

@ -7,7 +7,6 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/version.h>
#include <soc/tegra/bpmp.h> #include <soc/tegra/bpmp.h>
#include <soc/tegra/bpmp-abi.h> #include <soc/tegra/bpmp-abi.h>

Просмотреть файл

@ -81,6 +81,7 @@
#define HCLK_OTG0 449 #define HCLK_OTG0 449
#define HCLK_OTG1 450 #define HCLK_OTG1 450
#define HCLK_NANDC 453 #define HCLK_NANDC 453
#define HCLK_SFC 454
#define HCLK_SDMMC 456 #define HCLK_SDMMC 456
#define HCLK_SDIO 457 #define HCLK_SDIO 457
#define HCLK_EMMC 459 #define HCLK_EMMC 459

Просмотреть файл

@ -14,6 +14,7 @@ enum tegra_suspend_mode {
TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */ TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */ TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
TEGRA_MAX_SUSPEND_MODE, TEGRA_MAX_SUSPEND_MODE,
TEGRA_SUSPEND_NOT_READY,
}; };
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) #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); void tegra_pm_set_cpu_in_lp2(void);
int tegra_pm_enter_lp2(void); int tegra_pm_enter_lp2(void);
int tegra_pm_park_secondary_cpu(unsigned long cpu); int tegra_pm_park_secondary_cpu(unsigned long cpu);
void tegra_pm_init_suspend(void);
#else #else
static inline enum tegra_suspend_mode static inline enum tegra_suspend_mode
tegra_pm_validate_suspend_mode(enum tegra_suspend_mode 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; return -ENOTSUPP;
} }
static inline void tegra_pm_init_suspend(void)
{
}
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
#endif /* __SOC_TEGRA_PM_H__ */ #endif /* __SOC_TEGRA_PM_H__ */