17.12.2019 23:03, Sowjanya Komatineni пишет: > Tegra PMC has blink control to output 32 Khz clock out to Tegra > blink pin. Blink pad DPD state and enable controls are part of > Tegra PMC register space. > > Currently Tegra clock driver registers blink control by passing > PMC address and register offset to clk_register_gate which performs > direct PMC access during clk_ops and with this when PMC is in secure > mode, any access from non-secure world does not go through. > > This patch adds blink control registration to the Tegra PMC driver > using PMC specific clock gate operations that use tegra_pmc_readl > and tegra_pmc_writel to support both secure mode and non-secure > mode PMC register access. > > Signed-off-by: Sowjanya Komatineni <skomatineni@xxxxxxxxxx> > --- > drivers/soc/tegra/pmc.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 107 insertions(+) > > diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c > index 6d65194a6e71..19996c21c60d 100644 > --- a/drivers/soc/tegra/pmc.c > +++ b/drivers/soc/tegra/pmc.c > @@ -61,12 +61,15 @@ > #define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ > #define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ > #define PMC_CNTRL_PWRREQ_POLARITY BIT(8) > +#define PMC_CNTRL_BLINK_EN 7 > #define PMC_CNTRL_MAIN_RST BIT(4) > > #define PMC_WAKE_MASK 0x0c > #define PMC_WAKE_LEVEL 0x10 > #define PMC_WAKE_STATUS 0x14 > #define PMC_SW_WAKE_STATUS 0x18 > +#define PMC_DPD_PADS_ORIDE 0x1c > +#define PMC_DPD_PADS_ORIDE_BLINK 20 > > #define DPD_SAMPLE 0x020 > #define DPD_SAMPLE_ENABLE BIT(0) > @@ -79,6 +82,7 @@ > > #define PWRGATE_STATUS 0x38 > > +#define PMC_BLINK_TIMER 0x40 > #define PMC_IMPL_E_33V_PWR 0x40 > > #define PMC_PWR_DET 0x48 > @@ -170,6 +174,14 @@ struct pmc_clk { > > #define to_pmc_clk(_hw) container_of(_hw, struct pmc_clk, hw) > > +struct pmc_clk_gate { > + struct clk_hw hw; > + unsigned long offs; > + u32 shift; > +}; > + > +#define to_pmc_clk_gate(_hw) container_of(_hw, struct pmc_clk_gate, hw) > + > struct pmc_clk_init_data { > char *name; > const char *const *parents; > @@ -320,6 +332,7 @@ struct tegra_pmc_soc { > > const struct pmc_clk_init_data *pmc_clks_data; > unsigned int num_pmc_clks; > + bool has_blink_output; > }; > > static const char * const tegra186_reset_sources[] = { > @@ -2330,6 +2343,60 @@ tegra_pmc_clk_out_register(const struct pmc_clk_init_data *data, > return clk_register(NULL, &pmc_clk->hw); > } > > +static int pmc_clk_gate_is_enabled(struct clk_hw *hw) > +{ > + struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); > + > + return tegra_pmc_readl(pmc, gate->offs) & BIT(gate->shift) ? 1 : 0; > +} > + > +static int pmc_clk_gate_enable(struct clk_hw *hw) > +{ > + struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); > + > + pmc_clk_set_state(gate->offs, gate->shift, 1); > + > + return 0; > +} > + > +static void pmc_clk_gate_disable(struct clk_hw *hw) > +{ > + struct pmc_clk_gate *gate = to_pmc_clk_gate(hw); > + > + pmc_clk_set_state(gate->offs, gate->shift, 0); > +} > + > +static const struct clk_ops pmc_clk_gate_ops = { > + .is_enabled = pmc_clk_gate_is_enabled, > + .enable = pmc_clk_gate_enable, > + .disable = pmc_clk_gate_disable, > +}; > + > +static struct clk * > +tegra_pmc_clk_gate_register(const char *name, const char *parent_name, > + unsigned long flags, unsigned long offset, > + u32 shift) > +{ > + struct clk_init_data init; > + struct pmc_clk_gate *gate; > + > + gate = kzalloc(sizeof(*gate), GFP_KERNEL); > + if (!gate) > + return ERR_PTR(-ENOMEM); > + > + init.name = name; > + init.ops = &pmc_clk_gate_ops; > + init.parent_names = &parent_name; > + init.num_parents = 1; > + init.flags = flags; What about "init.flags = 0"? > + gate->hw.init = &init; > + gate->offs = offset; > + gate->shift = shift; > + > + return clk_register(NULL, &gate->hw); > +} > + > static void tegra_pmc_clock_register(struct tegra_pmc *pmc, > struct device_node *np) > { > @@ -2339,6 +2406,8 @@ static void tegra_pmc_clock_register(struct tegra_pmc *pmc, > int i, err = -ENOMEM; > > num_clks = pmc->soc->num_pmc_clks; > + if (pmc->soc->has_blink_output) > + num_clks += 1; > > if (!num_clks) > return; > @@ -2380,6 +2449,37 @@ static void tegra_pmc_clock_register(struct tegra_pmc *pmc, > } > } > > + if (pmc->soc->has_blink_output) { > + tegra_pmc_writel(pmc, 0x0, PMC_BLINK_TIMER); > + clk = tegra_pmc_clk_gate_register("blink_override", > + "clk_32k", 0, > + PMC_DPD_PADS_ORIDE, > + PMC_DPD_PADS_ORIDE_BLINK); > + if (IS_ERR(clk)) { > + dev_err(pmc->dev, "unable to register blink_override\n"); > + err = PTR_ERR(clk); > + goto free_clks; > + } > + > + clk = tegra_pmc_clk_gate_register("blink", > + "blink_override", 0, > + PMC_CNTRL, > + PMC_CNTRL_BLINK_EN); > + if (IS_ERR(clk)) { > + dev_err(pmc->dev, "unable to register blink\n"); > + err = PTR_ERR(clk); > + goto free_clks; > + } > + > + clk_data->clks[TEGRA_PMC_CLK_BLINK] = clk; > + err = clk_register_clkdev(clk, "blink", NULL); > + if (err) { > + dev_err(pmc->dev, > + "unable to register blink clock lookup\n"); > + goto free_clks; > + } > + } > + > err = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); > if (err) { > dev_err(pmc->dev, "failed to add pmc clk provider\n"); > @@ -2658,6 +2758,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { > .num_reset_levels = 0, > .pmc_clks_data = NULL, > .num_pmc_clks = 0, > + .has_blink_output = true, > }; > > static const char * const tegra30_powergates[] = { > @@ -2707,6 +2808,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { > .num_reset_levels = 0, > .pmc_clks_data = tegra_pmc_clks_data, > .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), > + .has_blink_output = true, > }; > > static const char * const tegra114_powergates[] = { > @@ -2760,6 +2862,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { > .num_reset_levels = 0, > .pmc_clks_data = tegra_pmc_clks_data, > .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), > + .has_blink_output = true, > }; > > static const char * const tegra124_powergates[] = { > @@ -2873,6 +2976,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { > .num_reset_levels = 0, > .pmc_clks_data = tegra_pmc_clks_data, > .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), > + .has_blink_output = true, > }; > > static const char * const tegra210_powergates[] = { > @@ -2989,6 +3093,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { > .wake_events = tegra210_wake_events, > .pmc_clks_data = tegra_pmc_clks_data, > .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), > + .has_blink_output = true, > }; > > #define TEGRA186_IO_PAD_TABLE(_pad) \ > @@ -3120,6 +3225,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { > .wake_events = tegra186_wake_events, > .pmc_clks_data = NULL, > .num_pmc_clks = 0, > + .has_blink_output = false, > }; > > static const struct tegra_io_pad_soc tegra194_io_pads[] = { > @@ -3239,6 +3345,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { > .wake_events = tegra194_wake_events, > .pmc_clks_data = NULL, > .num_pmc_clks = 0, > + .has_blink_output = false, > }; > > static const struct of_device_id tegra_pmc_match[] = { >