* Re: [PATCH v7 03/20] clk: tegra: divider: Save and restore divider rate
From: Dmitry Osipenko @ 2019-07-31 10:49 UTC (permalink / raw)
To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
marc.zyngier, linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
robh+dt, devicetree
In-Reply-To: <1564532424-10449-4-git-send-email-skomatineni@nvidia.com>
31.07.2019 3:20, Sowjanya Komatineni пишет:
> This patch implements context restore for clock divider.
>
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
>
> So on resume, clock dividers are restored back for normal operation.
>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
> drivers/clk/tegra/clk-divider.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
> index e76731fb7d69..ca0de5f11f84 100644
> --- a/drivers/clk/tegra/clk-divider.c
> +++ b/drivers/clk/tegra/clk-divider.c
> @@ -109,10 +109,21 @@ static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate,
> return 0;
> }
>
> +static void clk_divider_restore_context(struct clk_hw *hw)
> +{
> + struct clk_hw *parent = clk_hw_get_parent(hw);
> + unsigned long parent_rate = clk_hw_get_rate(parent);
> + unsigned long rate = clk_hw_get_rate(hw);
> +
> + if (clk_frac_div_set_rate(hw, rate, parent_rate) < 0)
> + WARN_ON(1);
> +}
> +
> const struct clk_ops tegra_clk_frac_div_ops = {
> .recalc_rate = clk_frac_div_recalc_rate,
> .set_rate = clk_frac_div_set_rate,
> .round_rate = clk_frac_div_round_rate,
> + .restore_context = clk_divider_restore_context,
> };
>
> struct clk *tegra_clk_register_divider(const char *name,
>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
^ permalink raw reply
* Re: [PATCH v7 07/20] clk: tegra: clk-periph: Add save and restore support
From: Dmitry Osipenko @ 2019-07-31 10:44 UTC (permalink / raw)
To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
marc.zyngier, linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
robh+dt, devicetree
In-Reply-To: <f90cf34d-c294-b23d-38e3-6de9a8fca7d6@gmail.com>
31.07.2019 12:50, Dmitry Osipenko пишет:
> 31.07.2019 3:20, Sowjanya Komatineni пишет:
>> This patch implements save and restore context for peripheral fixed
>> clock ops, peripheral gate clock ops, sdmmc mux clock ops, and
>> peripheral clock ops.
>>
>> During system suspend, core power goes off and looses the settings
>> of the Tegra CAR controller registers.
>>
>> So during suspend entry clock and reset state of peripherals is saved
>> and on resume they are restored to have clocks back to same rate and
>> state as before suspend.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
>> drivers/clk/tegra/clk-periph-fixed.c | 33 ++++++++++++++++++++++++++++++++
>> drivers/clk/tegra/clk-periph-gate.c | 34 +++++++++++++++++++++++++++++++++
>> drivers/clk/tegra/clk-periph.c | 37 ++++++++++++++++++++++++++++++++++++
>> drivers/clk/tegra/clk-sdmmc-mux.c | 28 +++++++++++++++++++++++++++
>> drivers/clk/tegra/clk.h | 6 ++++++
>> 5 files changed, 138 insertions(+)
>>
>> diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c
>> index c088e7a280df..21b24530fa00 100644
>> --- a/drivers/clk/tegra/clk-periph-fixed.c
>> +++ b/drivers/clk/tegra/clk-periph-fixed.c
>> @@ -60,11 +60,44 @@ tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
>> return (unsigned long)rate;
>> }
>>
>> +static int tegra_clk_periph_fixed_save_context(struct clk_hw *hw)
>> +{
>> + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
>> + u32 mask = 1 << (fixed->num % 32);
>> +
>> + fixed->enb_ctx = readl_relaxed(fixed->base + fixed->regs->enb_reg) &
>> + mask;
>> + fixed->rst_ctx = readl_relaxed(fixed->base + fixed->regs->rst_reg) &
>> + mask;
>> +
>> + return 0;
>> +}
>> +
>> +static void tegra_clk_periph_fixed_restore_context(struct clk_hw *hw)
>> +{
>> + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
>> + u32 mask = 1 << (fixed->num % 32);
>> +
>> + if (fixed->enb_ctx)
>> + writel_relaxed(mask, fixed->base + fixed->regs->enb_set_reg);
>> + else
>> + writel_relaxed(mask, fixed->base + fixed->regs->enb_clr_reg);
>> +
>> + udelay(2);
>> +
>> + if (!fixed->rst_ctx) {
>> + udelay(5); /* reset propogation delay */
>> + writel_relaxed(mask, fixed->base + fixed->regs->rst_reg);
>> + }
>> +}
>> +
>> static const struct clk_ops tegra_clk_periph_fixed_ops = {
>> .is_enabled = tegra_clk_periph_fixed_is_enabled,
>> .enable = tegra_clk_periph_fixed_enable,
>> .disable = tegra_clk_periph_fixed_disable,
>> .recalc_rate = tegra_clk_periph_fixed_recalc_rate,
>> + .save_context = tegra_clk_periph_fixed_save_context,
>> + .restore_context = tegra_clk_periph_fixed_restore_context,
>> };
>>
>> struct clk *tegra_clk_register_periph_fixed(const char *name,
>> diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
>> index 4b31beefc9fc..6ba5b08e0787 100644
>> --- a/drivers/clk/tegra/clk-periph-gate.c
>> +++ b/drivers/clk/tegra/clk-periph-gate.c
>> @@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(periph_ref_lock);
>>
>> #define read_rst(gate) \
>> readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
>> +#define write_rst_set(val, gate) \
>> + writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
>> #define write_rst_clr(val, gate) \
>> writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
>>
>> @@ -110,10 +112,42 @@ static void clk_periph_disable(struct clk_hw *hw)
>> spin_unlock_irqrestore(&periph_ref_lock, flags);
>> }
>>
>> +static int clk_periph_gate_save_context(struct clk_hw *hw)
>> +{
>> + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
>> +
>> + gate->clk_state_ctx = read_enb(gate) & periph_clk_to_bit(gate);
>> + gate->rst_state_ctx = read_rst(gate) & periph_clk_to_bit(gate);
>> +
>> + return 0;
>> +}
>> +
>> +static void clk_periph_gate_restore_context(struct clk_hw *hw)
>> +{
>> + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
>> +
>> + if (gate->clk_state_ctx)
>> + write_enb_set(periph_clk_to_bit(gate), gate);
>> + else
>> + write_enb_clr(periph_clk_to_bit(gate), gate);
>> +
>> + udelay(5);
>> +
>> + if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
>> + !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
>> + if (gate->rst_state_ctx)
>> + write_rst_set(periph_clk_to_bit(gate), gate);
>> + else
>> + write_rst_clr(periph_clk_to_bit(gate), gate);
>> + }
>> +}
>> +
>> const struct clk_ops tegra_clk_periph_gate_ops = {
>> .is_enabled = clk_periph_is_enabled,
>> .enable = clk_periph_enable,
>> .disable = clk_periph_disable,
>> + .save_context = clk_periph_gate_save_context,
>> + .restore_context = clk_periph_gate_restore_context,
>> };
>>
>> struct clk *tegra_clk_register_periph_gate(const char *name,
>> diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
>> index 58437da25156..06fb62955768 100644
>> --- a/drivers/clk/tegra/clk-periph.c
>> +++ b/drivers/clk/tegra/clk-periph.c
>> @@ -99,6 +99,37 @@ static void clk_periph_disable(struct clk_hw *hw)
>> gate_ops->disable(gate_hw);
>> }
>>
>> +static int clk_periph_save_context(struct clk_hw *hw)
>> +{
>> + struct tegra_clk_periph *periph = to_clk_periph(hw);
>> + const struct clk_ops *gate_ops = periph->gate_ops;
>> + struct clk_hw *gate_hw = &periph->gate.hw;
>> +
>> + if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
>> + gate_ops->save_context(gate_hw);
>> +
>> + periph->parent_ctx = clk_periph_get_parent(hw);
>> +
>> + return 0;
>> +}
>> +
>> +static void clk_periph_restore_context(struct clk_hw *hw)
>> +{
>> + struct tegra_clk_periph *periph = to_clk_periph(hw);
>> + const struct clk_ops *gate_ops = periph->gate_ops;
>> + struct clk_hw *gate_hw = &periph->gate.hw;
>> + const struct clk_ops *div_ops = periph->div_ops;
>> + struct clk_hw *div_hw = &periph->divider.hw;
>> +
>> + clk_periph_set_parent(hw, periph->parent_ctx);
>> +
>> + if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
>> + div_ops->restore_context(div_hw);
>
> Could you please point to where the divider's save_context() happens?
> Because I can't see it.
Ah, I now see that there is no need to save the dividers context because
clk itself has enough info that is needed for the context's restoring
(like I pointed in the review to v6).
Looks like you could also implement a new clk_hw_get_parent_index()
generic helper to get the index instead of storing it manually.
^ permalink raw reply
* Re: [PATCH v7 11/20] cpufreq: tegra124: Add suspend and resume support
From: Dmitry Osipenko @ 2019-07-31 10:23 UTC (permalink / raw)
To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
marc.zyngier, linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
robh+dt, devicetree
In-Reply-To: <1564532424-10449-12-git-send-email-skomatineni@nvidia.com>
31.07.2019 3:20, Sowjanya Komatineni пишет:
> This patch adds suspend and resume pm ops for cpufreq driver.
>
> PLLP is the safe clock source for CPU during system suspend and
> resume as PLLP rate is below the CPU Fmax at Vmin.
>
> CPUFreq driver suspend switches the CPU clock source to PLLP and
> disables the DFLL clock.
>
> During system resume, warmboot code powers up the CPU with PLLP
> clock source. So CPUFreq driver resume enabled DFLL clock and
> switches CPU back to DFLL clock source.
>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
> drivers/cpufreq/tegra124-cpufreq.c | 60 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 60 insertions(+)
>
> diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
> index 4f0c637b3b49..e979a3370988 100644
> --- a/drivers/cpufreq/tegra124-cpufreq.c
> +++ b/drivers/cpufreq/tegra124-cpufreq.c
> @@ -6,6 +6,7 @@
> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>
> #include <linux/clk.h>
> +#include <linux/cpufreq.h>
> #include <linux/err.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> @@ -128,8 +129,67 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
> return ret;
> }
>
> +static int __maybe_unused tegra124_cpufreq_suspend(struct device *dev)
> +{
> + struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
> + int err;
> +
> + /*
> + * PLLP rate 408Mhz is below the CPU Fmax at Vmin and is safe to
> + * use during suspend and resume. So, switch the CPU clock source
> + * to PLLP and disable DFLL.
> + */
> + err = clk_set_parent(priv->cpu_clk, priv->pllp_clk);
> + if (err < 0) {
> + dev_err(dev, "failed to reparent to PLLP: %d\n", err);
> + return err;
> + }
> +
> + /* disable DFLL clock */
> + clk_disable_unprepare(priv->dfll_clk);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused tegra124_cpufreq_resume(struct device *dev)
> +{
> + struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
> + int err;
> +
> + /*
> + * Warmboot code powers up the CPU with PLLP clock source.
> + * Enable DFLL clock and switch CPU clock source back to DFLL.
> + */
> + err = clk_prepare_enable(priv->dfll_clk);
> + if (err < 0) {
> + dev_err(dev, "failed to enable DFLL clock for CPU: %d\n", err);
> + goto disable_cpufreq;
> + }
> +
> + err = clk_set_parent(priv->cpu_clk, priv->dfll_clk);
> + if (err < 0) {
> + dev_err(dev, "failed to reparent to DFLL clock: %d\n", err);
> + goto disable_dfll;
> + }
> +
> + return 0;
> +
> +disable_dfll:
> + clk_disable_unprepare(priv->dfll_clk);
> +disable_cpufreq:
> + disable_cpufreq();
> +
> + return err;
> +}
> +
> +static const struct dev_pm_ops tegra124_cpufreq_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(tegra124_cpufreq_suspend,
> + tegra124_cpufreq_resume)
> +};
> +
> static struct platform_driver tegra124_cpufreq_platdrv = {
> .driver.name = "cpufreq-tegra124",
> + .driver.pm = &tegra124_cpufreq_pm_ops,
> .probe = tegra124_cpufreq_probe,
> };
>
>
Looks good,
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
^ permalink raw reply
* [PATCH v2 5/5] drivers: xhci: Add quirk to reset xHCI port PHY
From: Srinath Mannam @ 2019-07-31 10:19 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman, Rob Herring,
Kishon Vijay Abraham I, Mark Rutland
Cc: linux-usb, devicetree, linux-kernel, bcm-kernel-feedback-list,
Srinath Mannam
In-Reply-To: <1564568395-9980-1-git-send-email-srinath.mannam@broadcom.com>
Stingray USB HS PHY has an issue, that USB High Speed device detects
at Full Speed if the same port was connected to Full speed device.
This problem can be resolved by resetting that port's PHY on disconnect.
Add a quirk to reset xHCI port PHY on port disconnect event.
XHCI_RESET_PHY_ON_DISCONNECT quirk is introduced with xhci_plat_brcm_sr
platform data. New quirks parameter added in xhci_plat_priv structure to
assign platform specific quirks.
Signed-off-by: Srinath Mannam <srinath.mannam@broadcom.com>
---
drivers/usb/core/hcd.c | 6 ++++++
drivers/usb/core/phy.c | 19 +++++++++++++++++++
drivers/usb/core/phy.h | 1 +
drivers/usb/host/xhci-plat.c | 10 ++++++++++
drivers/usb/host/xhci-plat.h | 1 +
drivers/usb/host/xhci-ring.c | 9 ++++++---
drivers/usb/host/xhci.h | 1 +
include/linux/usb/hcd.h | 1 +
8 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 94d2255..a23441b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2675,6 +2675,12 @@ int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
return hcd->driver->find_raw_port_number(hcd, port1);
}
+int usb_hcd_phy_port_reset(struct usb_hcd *hcd, int port)
+{
+ return usb_phy_roothub_port_reset(hcd->phy_roothub, port);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_phy_port_reset);
+
static int usb_hcd_request_irqs(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags)
{
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c
index 7580493..4d1ac31 100644
--- a/drivers/usb/core/phy.c
+++ b/drivers/usb/core/phy.c
@@ -190,6 +190,25 @@ void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
}
EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
+int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int port)
+{
+ struct usb_phy_roothub *roothub_entry;
+ struct list_head *head;
+
+ if (!phy_roothub)
+ return -EINVAL;
+
+ head = &phy_roothub->list;
+
+ list_for_each_entry(roothub_entry, head, list) {
+ if (phy_get_phy_ports(roothub_entry->phy) & BIT(port))
+ return phy_reset(roothub_entry->phy);
+ }
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_port_reset);
+
int usb_phy_roothub_suspend(struct device *controller_dev,
struct usb_phy_roothub *phy_roothub)
{
diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h
index dad564e..3f682e8 100644
--- a/drivers/usb/core/phy.h
+++ b/drivers/usb/core/phy.h
@@ -20,6 +20,7 @@ int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
enum phy_mode mode);
int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub);
void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub);
+int usb_phy_roothub_port_reset(struct usb_phy_roothub *phy_roothub, int port);
int usb_phy_roothub_suspend(struct device *controller_dev,
struct usb_phy_roothub *phy_roothub);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 998241f..af23e92 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -47,6 +47,9 @@ static void xhci_priv_plat_start(struct usb_hcd *hcd)
static int xhci_priv_init_quirk(struct usb_hcd *hcd)
{
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ xhci->quirks |= priv->quirks;
if (!priv->init_quirk)
return 0;
@@ -116,6 +119,10 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
.resume_quirk = xhci_rcar_resume_quirk,
};
+static const struct xhci_plat_priv xhci_plat_brcm_sr = {
+ .quirks = XHCI_RESET_PHY_ON_DISCONNECT,
+};
+
static const struct of_device_id usb_xhci_of_match[] = {
{
.compatible = "generic-xhci",
@@ -151,6 +158,9 @@ static const struct of_device_id usb_xhci_of_match[] = {
}, {
.compatible = "renesas,rcar-gen3-xhci",
.data = &xhci_plat_renesas_rcar_gen3,
+ }, {
+ .compatible = "brcm,sr-xhci",
+ .data = &xhci_plat_brcm_sr,
},
{},
};
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index ae29f22..0cd61c6 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -15,6 +15,7 @@ struct xhci_plat_priv {
void (*plat_start)(struct usb_hcd *);
int (*init_quirk)(struct usb_hcd *);
int (*resume_quirk)(struct usb_hcd *);
+ unsigned long long quirks;
};
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index feffceb..77e94e8 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1696,9 +1696,12 @@ static void handle_port_status(struct xhci_hcd *xhci,
if (hcd->speed < HCD_USB3) {
xhci_test_and_clear_bit(xhci, port, PORT_PLC);
- if ((xhci->quirks & XHCI_RESET_PLL_ON_DISCONNECT) &&
- (portsc & PORT_CSC) && !(portsc & PORT_CONNECT))
- xhci_cavium_reset_phy_quirk(xhci);
+ if ((portsc & PORT_CSC) && !(portsc & PORT_CONNECT)) {
+ if (xhci->quirks & XHCI_RESET_PLL_ON_DISCONNECT)
+ xhci_cavium_reset_phy_quirk(xhci);
+ else if (xhci->quirks & XHCI_RESET_PHY_ON_DISCONNECT)
+ usb_hcd_phy_port_reset(hcd, port_id - 1);
+ }
}
cleanup:
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 7f8b950..f3b336b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1856,6 +1856,7 @@ struct xhci_hcd {
#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
+#define XHCI_RESET_PHY_ON_DISCONNECT BIT_ULL(36)
unsigned int num_active_eps;
unsigned int limit_active_eps;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index bb57b5a..2590666 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -461,6 +461,7 @@ extern int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags);
extern void usb_remove_hcd(struct usb_hcd *hcd);
extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
+extern int usb_hcd_phy_port_reset(struct usb_hcd *hcd, int port);
struct platform_device;
extern void usb_hcd_platform_shutdown(struct platform_device *dev);
--
2.7.4
^ permalink raw reply related
* [PATCH v2 4/5] dt-bindings: usb-xhci: Add platform specific compatible for Stingray xHCI
From: Srinath Mannam @ 2019-07-31 10:19 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman, Rob Herring,
Kishon Vijay Abraham I, Mark Rutland
Cc: linux-usb, devicetree, linux-kernel, bcm-kernel-feedback-list,
Srinath Mannam
In-Reply-To: <1564568395-9980-1-git-send-email-srinath.mannam@broadcom.com>
Add Platform specific compatible, because xHCI of this SoC has an issue
with HS port which has to reset on disconnect event.
Signed-off-by: Srinath Mannam <srinath.mannam@broadcom.com>
---
Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
index 97400e8..ee1f051 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
@@ -22,6 +22,7 @@ Required properties:
device
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 or RZ/G2 compatible
device
+ - "brcm,sr-xhci" for Stingray SoC
- "xhci-platform" (deprecated)
When compatible with the generic version, nodes must list the
--
2.7.4
^ permalink raw reply related
* [PATCH v2 3/5] phy: sr-usb: Set phy ports
From: Srinath Mannam @ 2019-07-31 10:19 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman, Rob Herring,
Kishon Vijay Abraham I, Mark Rutland
Cc: linux-usb, devicetree, linux-kernel, bcm-kernel-feedback-list,
Srinath Mannam
In-Reply-To: <1564568395-9980-1-git-send-email-srinath.mannam@broadcom.com>
set phy ports value in xlate handler which is taken from second argument
of PHY phandle.
Signed-off-by: Srinath Mannam <srinath.mannam@broadcom.com>
---
drivers/phy/broadcom/phy-bcm-sr-usb.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/broadcom/phy-bcm-sr-usb.c b/drivers/phy/broadcom/phy-bcm-sr-usb.c
index fe6c589..5274e45 100644
--- a/drivers/phy/broadcom/phy-bcm-sr-usb.c
+++ b/drivers/phy/broadcom/phy-bcm-sr-usb.c
@@ -278,9 +278,16 @@ static struct phy *bcm_usb_phy_xlate(struct device *dev,
if (WARN_ON(phy_idx > 1))
return ERR_PTR(-ENODEV);
+ if (args->args[1])
+ phy_set_phy_ports(phy_cfg[phy_idx].phy, args->args[1]);
+
return phy_cfg[phy_idx].phy;
- } else
+ } else {
+ if (args->args[0])
+ phy_set_phy_ports(phy_cfg->phy, args->args[0]);
+
return phy_cfg->phy;
+ }
}
static int bcm_usb_phy_create(struct device *dev, struct device_node *node,
--
2.7.4
^ permalink raw reply related
* [PATCH v2 2/5] dt-bindings: phy: Modify Stingray USB PHY #phy-cells
From: Srinath Mannam @ 2019-07-31 10:19 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman, Rob Herring,
Kishon Vijay Abraham I, Mark Rutland
Cc: linux-usb, devicetree, linux-kernel, bcm-kernel-feedback-list,
Srinath Mannam
In-Reply-To: <1564568395-9980-1-git-send-email-srinath.mannam@broadcom.com>
Increase #phy-cells from 1 to 2 to have bitmask of PHY enabled ports.
Signed-off-by: Srinath Mannam <srinath.mannam@broadcom.com>
---
.../devicetree/bindings/phy/brcm,stingray-usb-phy.txt | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt
index 4ba2989..aeb0568 100644
--- a/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt
+++ b/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt
@@ -6,9 +6,11 @@ Required properties:
- "brcm,sr-usb-hs-phy" is a single HS PHY.
- reg: offset and length of the PHY blocks registers
- #phy-cells:
- - Must be 1 for brcm,sr-usb-combo-phy as it expects one argument to indicate
- the PHY number of two PHYs. 0 for HS PHY and 1 for SS PHY.
- - Must be 0 for brcm,sr-usb-hs-phy.
+ - Must be 2 for brcm,sr-usb-combo-phy.
+ - Cell 1 - PHY Number, 0 for HS PHY and 1 for SS PHY.
+ - Cell 2 - Bitmask of enabled ports connected to USB Host controller.
+ - Must be 1 for brcm,sr-usb-hs-phy to indicate Bit mask of ports connected
+ to USB Host controller.
Refer to phy/phy-bindings.txt for the generic PHY binding properties
@@ -16,17 +18,17 @@ Example:
usbphy0: usb-phy@0 {
compatible = "brcm,sr-usb-combo-phy";
reg = <0x00000000 0x100>;
- #phy-cells = <1>;
+ #phy-cells = <2>;
};
usbphy1: usb-phy@10000 {
compatible = "brcm,sr-usb-combo-phy";
reg = <0x00010000 0x100>,
- #phy-cells = <1>;
+ #phy-cells = <2>;
};
usbphy2: usb-phy@20000 {
compatible = "brcm,sr-usb-hs-phy";
reg = <0x00020000 0x100>,
- #phy-cells = <0>;
+ #phy-cells = <1>;
};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 1/5] phy: Add phy ports in attrs
From: Srinath Mannam @ 2019-07-31 10:19 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman, Rob Herring,
Kishon Vijay Abraham I, Mark Rutland
Cc: linux-usb, devicetree, linux-kernel, bcm-kernel-feedback-list,
Srinath Mannam
In-Reply-To: <1564568395-9980-1-git-send-email-srinath.mannam@broadcom.com>
Add phy ports bitmask to contain enabled PHY ports.
set and get APIs added to set and get phy ports value.
Signed-off-by: Srinath Mannam <srinath.mannam@broadcom.com>
---
include/linux/phy/phy.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 15032f14..b8bca1d 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -109,10 +109,12 @@ struct phy_ops {
/**
* struct phy_attrs - represents phy attributes
* @bus_width: Data path width implemented by PHY
+ * @phy_ports: Bitmask of enabled ports
* @mode: PHY mode
*/
struct phy_attrs {
u32 bus_width;
+ u32 phy_ports;
enum phy_mode mode;
};
@@ -225,6 +227,14 @@ static inline void phy_set_bus_width(struct phy *phy, int bus_width)
{
phy->attrs.bus_width = bus_width;
}
+static inline int phy_get_phy_ports(struct phy *phy)
+{
+ return phy->attrs.phy_ports;
+}
+static inline void phy_set_phy_ports(struct phy *phy, int phy_ports)
+{
+ phy->attrs.phy_ports |= phy_ports;
+}
struct phy *phy_get(struct device *dev, const char *string);
struct phy *phy_optional_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
--
2.7.4
^ permalink raw reply related
* [PATCH v2 0/4] Reset xHCI port PHY on disconnect
From: Srinath Mannam @ 2019-07-31 10:19 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman, Rob Herring,
Kishon Vijay Abraham I, Mark Rutland
Cc: linux-usb, devicetree, linux-kernel, bcm-kernel-feedback-list,
Srinath Mannam
This patch set adds a quirk in xHCI driver to reset PHY of xHCI port on
its disconnect event.
This patch set is based on Linux-5.2-rc4.
Changes from v1:
- Addressed Mathias's comments
- Modified mapping of HC ports and their corresponding PHYs
- Addressed Rob's comments
- Removed usb-phy-port-reset DT property.
- Added quirk in platform data using HCI compatible string.
- Add phy ports in phy attr structure to have enabled ports bitmask.
- Modified #phy-cells of sr-phy to pass phy ports bitmask.
Srinath Mannam (4):
phy: Add phy ports in attrs
dt-bindings: phy: Modify Stingray USB PHY #phy-cells
phy: sr-usb: Set phy ports
dt-bindings: usb-xhci: Add platform specific compatible for Stingray
xHCI
drivers: xhci: Add quirk to reset xHCI port PHY
.../devicetree/bindings/phy/brcm,stingray-usb-phy.txt | 14 ++++++++------
Documentation/devicetree/bindings/usb/usb-xhci.txt | 1 +
drivers/phy/broadcom/phy-bcm-sr-usb.c | 9 ++++++++-
drivers/usb/core/hcd.c | 6 ++++++
drivers/usb/core/phy.c | 19 +++++++++++++++++++
drivers/usb/core/phy.h | 1 +
drivers/usb/host/xhci-plat.c | 10 ++++++++++
drivers/usb/host/xhci-plat.h | 1 +
drivers/usb/host/xhci-ring.c | 9 ++++++---
drivers/usb/host/xhci.h | 1 +
include/linux/phy/phy.h | 10 ++++++++++
include/linux/usb/hcd.h | 1 +
12 files changed, 72 insertions(+), 10 deletions(-)
--
2.7.4
^ permalink raw reply
* Re: [PATCH v7 08/20] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
From: Dmitry Osipenko @ 2019-07-31 10:14 UTC (permalink / raw)
To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
marc.zyngier, linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
robh+dt, devicetree
In-Reply-To: <1564532424-10449-9-git-send-email-skomatineni@nvidia.com>
31.07.2019 3:20, Sowjanya Komatineni пишет:
> This patch has a fix to enable PLLP branches to CPU before changing
> the CPU clusters clock source to PLLP for Gen5 Super clock and
> disables PLLP branches to CPU when not in use.
>
> During system suspend entry and exit, CPU source will be switched
> to PLLP and this needs PLLP branches to be enabled to CPU prior to
> the switch.
>
> On system resume, warmboot code enables PLLP branches to CPU and
> powers up the CPU with PLLP clock source.
>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
> drivers/clk/tegra/clk-super.c | 14 ++++++++++++++
> drivers/clk/tegra/clk-tegra-super-gen4.c | 2 +-
> drivers/clk/tegra/clk.c | 14 ++++++++++++++
> drivers/clk/tegra/clk.h | 5 +++++
> 4 files changed, 34 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
> index 39ef31b46df5..e2a1e95a8db7 100644
> --- a/drivers/clk/tegra/clk-super.c
> +++ b/drivers/clk/tegra/clk-super.c
> @@ -28,6 +28,9 @@
> #define super_state_to_src_shift(m, s) ((m->width * s))
> #define super_state_to_src_mask(m) (((1 << m->width) - 1))
>
> +#define CCLK_SRC_PLLP_OUT0 4
> +#define CCLK_SRC_PLLP_OUT4 5
> +
> static u8 clk_super_get_parent(struct clk_hw *hw)
> {
> struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
> @@ -97,12 +100,23 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
> if (index == mux->div2_index)
> index = mux->pllx_index;
> }
> +
> + /* enable PLLP branches to CPU before selecting PLLP source */
> + if ((mux->flags & TEGRA210_CPU_CLK) &&
> + (index == CCLK_SRC_PLLP_OUT0 || index == CCLK_SRC_PLLP_OUT4))
> + tegra_clk_set_pllp_out_cpu(true);
> +
> val &= ~((super_state_to_src_mask(mux)) << shift);
> val |= (index & (super_state_to_src_mask(mux))) << shift;
>
> writel_relaxed(val, mux->reg);
> udelay(2);
>
> + /* disable PLLP branches to CPU if not used */
> + if ((mux->flags & TEGRA210_CPU_CLK) &&
> + index != CCLK_SRC_PLLP_OUT0 && index != CCLK_SRC_PLLP_OUT4)
> + tegra_clk_set_pllp_out_cpu(false);
> +
> out:
> if (mux->lock)
> spin_unlock_irqrestore(mux->lock, flags);
> diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
> index cdfe7c9697e1..888d76b01c75 100644
> --- a/drivers/clk/tegra/clk-tegra-super-gen4.c
> +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
> @@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
> gen_info->num_cclk_g_parents,
> CLK_SET_RATE_PARENT,
> clk_base + CCLKG_BURST_POLICY,
> - 0, 4, 8, 0, NULL);
> + TEGRA210_CPU_CLK, 4, 8, 0, NULL);
Don't we want a clarifying comment for cclk_lp telling why it doesn't
have the TEGRA210_CPU_CLK flag?
> } else {
> clk = tegra_clk_register_super_mux("cclk_g",
> gen_info->cclk_g_parents,
> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
> index 573e3c967ae1..eb08047fd02f 100644
> --- a/drivers/clk/tegra/clk.c
> +++ b/drivers/clk/tegra/clk.c
> @@ -23,6 +23,7 @@
> #define CLK_OUT_ENB_W 0x364
> #define CLK_OUT_ENB_X 0x280
> #define CLK_OUT_ENB_Y 0x298
> +#define CLK_ENB_PLLP_OUT_CPU BIT(31)
> #define CLK_OUT_ENB_SET_L 0x320
> #define CLK_OUT_ENB_CLR_L 0x324
> #define CLK_OUT_ENB_SET_H 0x328
> @@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
> }
> }
>
> +void tegra_clk_set_pllp_out_cpu(bool enable)
> +{
> + u32 val;
> +
> + val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
> + if (enable)
> + val |= CLK_ENB_PLLP_OUT_CPU;
> + else
> + val &= ~CLK_ENB_PLLP_OUT_CPU;
> +
> + writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
> +}
> +
> struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
> {
> clk_base = regs;
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index d61e61eebf4a..f8de447f505b 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -687,6 +687,9 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
> * Flags:
> * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
> * that this is LP cluster clock.
> + * TEGRA210_CPU_CLK - This flag indicates this is CPU cluster clock. To use
> + * PLLP for CPU clock source, need to enable PLLP branches to CPU by setting
> + * additional bit PLLP_OUT_CPU for gen5 super clock.
> */
> struct tegra_clk_super_mux {
> struct clk_hw hw;
> @@ -703,6 +706,7 @@ struct tegra_clk_super_mux {
> #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
>
> #define TEGRA_DIVIDER_2 BIT(0)
> +#define TEGRA210_CPU_CLK BIT(1)
>
> extern const struct clk_ops tegra_clk_super_ops;
> struct clk *tegra_clk_register_super_mux(const char *name,
> @@ -849,6 +853,7 @@ int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
> int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
> u8 frac_width, u8 flags);
> void tegra_clk_osc_resume(void __iomem *clk_base);
> +void tegra_clk_set_pllp_out_cpu(bool enable);
>
>
> /* Combined read fence with delay */
>
^ permalink raw reply
* Re: [PATCH v7 10/20] clk: tegra: clk-dfll: Add suspend and resume support
From: Dmitry Osipenko @ 2019-07-31 10:12 UTC (permalink / raw)
To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
marc.zyngier, linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
robh+dt, devicetree
In-Reply-To: <1564532424-10449-11-git-send-email-skomatineni@nvidia.com>
31.07.2019 3:20, Sowjanya Komatineni пишет:
> This patch implements DFLL suspend and resume operation.
>
> During system suspend entry, CPU clock will switch CPU to safe
> clock source of PLLP and disables DFLL clock output.
>
> DFLL driver suspend confirms DFLL disable state and errors out on
> being active.
>
> DFLL is re-initialized during the DFLL driver resume as it goes
> through complete reset during suspend entry.
>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
> drivers/clk/tegra/clk-dfll.c | 56 ++++++++++++++++++++++++++++++
> drivers/clk/tegra/clk-dfll.h | 2 ++
> drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 1 +
> 3 files changed, 59 insertions(+)
>
> diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
> index f8688c2ddf1a..9900097ec2aa 100644
> --- a/drivers/clk/tegra/clk-dfll.c
> +++ b/drivers/clk/tegra/clk-dfll.c
> @@ -1513,6 +1513,62 @@ static int dfll_init(struct tegra_dfll *td)
> return ret;
> }
>
> +/**
> + * tegra_dfll_suspend - check DFLL is disabled
> + * @dev: DFLL device *
> + *
> + * DFLL clock should be disabled by the CPUFreq driver. So, make
> + * sure it is disabled and disable all clocks needed by the DFLL.
> + */
> +int tegra_dfll_suspend(struct device *dev)
> +{
> + struct tegra_dfll *td = dev_get_drvdata(dev);
> +
> + if (dfll_is_running(td)) {
> + dev_err(td->dev, "dfll is enabled while shouldn't be\n");
> + return -EBUSY;
> + }
> +
> + reset_control_assert(td->dvco_rst);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(tegra_dfll_suspend);
> +
> +/**
> + * tegra_dfll_resume - reinitialize DFLL on resume
> + * @dev: DFLL instance
> + *
> + * DFLL is disabled and reset during suspend and resume.
> + * So, reinitialize the DFLL IP block back for use.
> + * DFLL clock is enabled later in closed loop mode by CPUFreq
> + * driver before switching its clock source to DFLL output.
> + */
> +int tegra_dfll_resume(struct device *dev)
> +{
> + struct tegra_dfll *td = dev_get_drvdata(dev);
> +
> + reset_control_deassert(td->dvco_rst);
> +
> + pm_runtime_irq_safe(td->dev);
1. Interrupts are allowed here.
2. It's enough to invoke that function once during probe.
3. That function bumps runtime-enable count of the parent, which
immediately should raise some questions.
Corollary: you should remove pm_runtime_irq_safe() because it is not needed.
> + pm_runtime_get_sync(td->dev);
> +
> + dfll_set_mode(td, DFLL_DISABLED);
> + dfll_set_default_params(td);
> +
> + if (td->soc->init_clock_trimmers)
> + td->soc->init_clock_trimmers();
> +
> + dfll_set_open_loop_config(td);
> +
> + dfll_init_out_if(td);
> +
> + pm_runtime_put_sync(td->dev);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(tegra_dfll_resume);
> +
> /*
> * DT data fetch
> */
> diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
> index 1b14ebe7268b..fb209eb5f365 100644
> --- a/drivers/clk/tegra/clk-dfll.h
> +++ b/drivers/clk/tegra/clk-dfll.h
> @@ -42,5 +42,7 @@ int tegra_dfll_register(struct platform_device *pdev,
> struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
> int tegra_dfll_runtime_suspend(struct device *dev);
> int tegra_dfll_runtime_resume(struct device *dev);
> +int tegra_dfll_suspend(struct device *dev);
> +int tegra_dfll_resume(struct device *dev);
>
> #endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
> diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
> index e84b6d52cbbd..2ac2679d696d 100644
> --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
> +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
> @@ -631,6 +631,7 @@ static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
> static const struct dev_pm_ops tegra124_dfll_pm_ops = {
> SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,
> tegra_dfll_runtime_resume, NULL)
> + SET_SYSTEM_SLEEP_PM_OPS(tegra_dfll_suspend, tegra_dfll_resume)
> };
>
> static struct platform_driver tegra124_dfll_fcpu_driver = {
>
^ permalink raw reply
* Re: [PATCH v7 07/20] clk: tegra: clk-periph: Add save and restore support
From: Dmitry Osipenko @ 2019-07-31 9:50 UTC (permalink / raw)
To: Sowjanya Komatineni, thierry.reding, jonathanh, tglx, jason,
marc.zyngier, linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, linux-tegra, linux-kernel, mperttunen, spatra,
robh+dt, devicetree
In-Reply-To: <1564532424-10449-8-git-send-email-skomatineni@nvidia.com>
31.07.2019 3:20, Sowjanya Komatineni пишет:
> This patch implements save and restore context for peripheral fixed
> clock ops, peripheral gate clock ops, sdmmc mux clock ops, and
> peripheral clock ops.
>
> During system suspend, core power goes off and looses the settings
> of the Tegra CAR controller registers.
>
> So during suspend entry clock and reset state of peripherals is saved
> and on resume they are restored to have clocks back to same rate and
> state as before suspend.
>
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
> drivers/clk/tegra/clk-periph-fixed.c | 33 ++++++++++++++++++++++++++++++++
> drivers/clk/tegra/clk-periph-gate.c | 34 +++++++++++++++++++++++++++++++++
> drivers/clk/tegra/clk-periph.c | 37 ++++++++++++++++++++++++++++++++++++
> drivers/clk/tegra/clk-sdmmc-mux.c | 28 +++++++++++++++++++++++++++
> drivers/clk/tegra/clk.h | 6 ++++++
> 5 files changed, 138 insertions(+)
>
> diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c
> index c088e7a280df..21b24530fa00 100644
> --- a/drivers/clk/tegra/clk-periph-fixed.c
> +++ b/drivers/clk/tegra/clk-periph-fixed.c
> @@ -60,11 +60,44 @@ tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
> return (unsigned long)rate;
> }
>
> +static int tegra_clk_periph_fixed_save_context(struct clk_hw *hw)
> +{
> + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
> + u32 mask = 1 << (fixed->num % 32);
> +
> + fixed->enb_ctx = readl_relaxed(fixed->base + fixed->regs->enb_reg) &
> + mask;
> + fixed->rst_ctx = readl_relaxed(fixed->base + fixed->regs->rst_reg) &
> + mask;
> +
> + return 0;
> +}
> +
> +static void tegra_clk_periph_fixed_restore_context(struct clk_hw *hw)
> +{
> + struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
> + u32 mask = 1 << (fixed->num % 32);
> +
> + if (fixed->enb_ctx)
> + writel_relaxed(mask, fixed->base + fixed->regs->enb_set_reg);
> + else
> + writel_relaxed(mask, fixed->base + fixed->regs->enb_clr_reg);
> +
> + udelay(2);
> +
> + if (!fixed->rst_ctx) {
> + udelay(5); /* reset propogation delay */
> + writel_relaxed(mask, fixed->base + fixed->regs->rst_reg);
> + }
> +}
> +
> static const struct clk_ops tegra_clk_periph_fixed_ops = {
> .is_enabled = tegra_clk_periph_fixed_is_enabled,
> .enable = tegra_clk_periph_fixed_enable,
> .disable = tegra_clk_periph_fixed_disable,
> .recalc_rate = tegra_clk_periph_fixed_recalc_rate,
> + .save_context = tegra_clk_periph_fixed_save_context,
> + .restore_context = tegra_clk_periph_fixed_restore_context,
> };
>
> struct clk *tegra_clk_register_periph_fixed(const char *name,
> diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
> index 4b31beefc9fc..6ba5b08e0787 100644
> --- a/drivers/clk/tegra/clk-periph-gate.c
> +++ b/drivers/clk/tegra/clk-periph-gate.c
> @@ -25,6 +25,8 @@ static DEFINE_SPINLOCK(periph_ref_lock);
>
> #define read_rst(gate) \
> readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
> +#define write_rst_set(val, gate) \
> + writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
> #define write_rst_clr(val, gate) \
> writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
>
> @@ -110,10 +112,42 @@ static void clk_periph_disable(struct clk_hw *hw)
> spin_unlock_irqrestore(&periph_ref_lock, flags);
> }
>
> +static int clk_periph_gate_save_context(struct clk_hw *hw)
> +{
> + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
> +
> + gate->clk_state_ctx = read_enb(gate) & periph_clk_to_bit(gate);
> + gate->rst_state_ctx = read_rst(gate) & periph_clk_to_bit(gate);
> +
> + return 0;
> +}
> +
> +static void clk_periph_gate_restore_context(struct clk_hw *hw)
> +{
> + struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
> +
> + if (gate->clk_state_ctx)
> + write_enb_set(periph_clk_to_bit(gate), gate);
> + else
> + write_enb_clr(periph_clk_to_bit(gate), gate);
> +
> + udelay(5);
> +
> + if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
> + !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
> + if (gate->rst_state_ctx)
> + write_rst_set(periph_clk_to_bit(gate), gate);
> + else
> + write_rst_clr(periph_clk_to_bit(gate), gate);
> + }
> +}
> +
> const struct clk_ops tegra_clk_periph_gate_ops = {
> .is_enabled = clk_periph_is_enabled,
> .enable = clk_periph_enable,
> .disable = clk_periph_disable,
> + .save_context = clk_periph_gate_save_context,
> + .restore_context = clk_periph_gate_restore_context,
> };
>
> struct clk *tegra_clk_register_periph_gate(const char *name,
> diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
> index 58437da25156..06fb62955768 100644
> --- a/drivers/clk/tegra/clk-periph.c
> +++ b/drivers/clk/tegra/clk-periph.c
> @@ -99,6 +99,37 @@ static void clk_periph_disable(struct clk_hw *hw)
> gate_ops->disable(gate_hw);
> }
>
> +static int clk_periph_save_context(struct clk_hw *hw)
> +{
> + struct tegra_clk_periph *periph = to_clk_periph(hw);
> + const struct clk_ops *gate_ops = periph->gate_ops;
> + struct clk_hw *gate_hw = &periph->gate.hw;
> +
> + if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
> + gate_ops->save_context(gate_hw);
> +
> + periph->parent_ctx = clk_periph_get_parent(hw);
> +
> + return 0;
> +}
> +
> +static void clk_periph_restore_context(struct clk_hw *hw)
> +{
> + struct tegra_clk_periph *periph = to_clk_periph(hw);
> + const struct clk_ops *gate_ops = periph->gate_ops;
> + struct clk_hw *gate_hw = &periph->gate.hw;
> + const struct clk_ops *div_ops = periph->div_ops;
> + struct clk_hw *div_hw = &periph->divider.hw;
> +
> + clk_periph_set_parent(hw, periph->parent_ctx);
> +
> + if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
> + div_ops->restore_context(div_hw);
Could you please point to where the divider's save_context() happens?
Because I can't see it.
> + if (!(periph->gate.flags & TEGRA_PERIPH_NO_GATE))
> + gate_ops->restore_context(gate_hw);
> +}
> +
> const struct clk_ops tegra_clk_periph_ops = {
> .get_parent = clk_periph_get_parent,
> .set_parent = clk_periph_set_parent,
> @@ -108,6 +139,8 @@ const struct clk_ops tegra_clk_periph_ops = {
> .is_enabled = clk_periph_is_enabled,
> .enable = clk_periph_enable,
> .disable = clk_periph_disable,
> + .save_context = clk_periph_save_context,
> + .restore_context = clk_periph_restore_context,
> };
>
> static const struct clk_ops tegra_clk_periph_nodiv_ops = {
> @@ -116,6 +149,8 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
> .is_enabled = clk_periph_is_enabled,
> .enable = clk_periph_enable,
> .disable = clk_periph_disable,
> + .save_context = clk_periph_save_context,
> + .restore_context = clk_periph_restore_context,
> };
>
> static const struct clk_ops tegra_clk_periph_no_gate_ops = {
> @@ -124,6 +159,8 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = {
> .recalc_rate = clk_periph_recalc_rate,
> .round_rate = clk_periph_round_rate,
> .set_rate = clk_periph_set_rate,
> + .save_context = clk_periph_save_context,
> + .restore_context = clk_periph_restore_context,
> };
>
> static struct clk *_tegra_clk_register_periph(const char *name,
> diff --git a/drivers/clk/tegra/clk-sdmmc-mux.c b/drivers/clk/tegra/clk-sdmmc-mux.c
> index a5cd3e31dbae..48da9d7fea80 100644
> --- a/drivers/clk/tegra/clk-sdmmc-mux.c
> +++ b/drivers/clk/tegra/clk-sdmmc-mux.c
> @@ -194,6 +194,32 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw)
> gate_ops->disable(gate_hw);
> }
>
> +static int clk_sdmmc_mux_save_context(struct clk_hw *hw)
> +{
> + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw);
> + const struct clk_ops *gate_ops = sdmmc_mux->gate_ops;
> + struct clk_hw *gate_hw = &sdmmc_mux->gate.hw;
> +
> + sdmmc_mux->parent_ctx = clk_sdmmc_mux_get_parent(hw);
> + gate_ops->save_context(gate_hw);
> +
> + return 0;
> +}
> +
> +static void clk_sdmmc_mux_restore_context(struct clk_hw *hw)
> +{
> + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw);
> + const struct clk_ops *gate_ops = sdmmc_mux->gate_ops;
> + struct clk_hw *gate_hw = &sdmmc_mux->gate.hw;
> + struct clk_hw *parent = clk_hw_get_parent(hw);
> + unsigned long parent_rate = clk_hw_get_rate(parent);
> + unsigned long rate = clk_hw_get_rate(hw);
> +
> + clk_sdmmc_mux_set_parent(hw, sdmmc_mux->parent_ctx);
> + clk_sdmmc_mux_set_rate(hw, rate, parent_rate);
> + gate_ops->restore_context(gate_hw);
> +}
> +
> static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
> .get_parent = clk_sdmmc_mux_get_parent,
> .set_parent = clk_sdmmc_mux_set_parent,
> @@ -203,6 +229,8 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
> .is_enabled = clk_sdmmc_mux_is_enabled,
> .enable = clk_sdmmc_mux_enable,
> .disable = clk_sdmmc_mux_disable,
> + .save_context = clk_sdmmc_mux_save_context,
> + .restore_context = clk_sdmmc_mux_restore_context,
> };
>
> struct clk *tegra_clk_register_sdmmc_mux_div(const char *name,
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> index abba6d8a04cd..d61e61eebf4a 100644
> --- a/drivers/clk/tegra/clk.h
> +++ b/drivers/clk/tegra/clk.h
> @@ -517,6 +517,8 @@ struct tegra_clk_periph_gate {
> int clk_num;
> int *enable_refcnt;
> const struct tegra_clk_periph_regs *regs;
> + bool clk_state_ctx;
> + bool rst_state_ctx;
> };
>
> #define to_clk_periph_gate(_hw) \
> @@ -543,6 +545,8 @@ struct tegra_clk_periph_fixed {
> unsigned int mul;
> unsigned int div;
> unsigned int num;
> + bool enb_ctx;
> + bool rst_ctx;
> };
>
> struct clk *tegra_clk_register_periph_fixed(const char *name,
> @@ -575,6 +579,7 @@ struct tegra_clk_periph {
> const struct clk_ops *mux_ops;
> const struct clk_ops *div_ops;
> const struct clk_ops *gate_ops;
> + u8 parent_ctx;
> };
>
> #define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw)
> @@ -726,6 +731,7 @@ struct tegra_sdmmc_mux {
> const struct clk_ops *gate_ops;
> struct tegra_clk_periph_gate gate;
> u8 div_flags;
> + u8 parent_ctx;
> };
>
> #define to_clk_sdmmc_mux(_hw) container_of(_hw, struct tegra_sdmmc_mux, hw)
>
^ permalink raw reply
* [RFC PATCH 2/2] net: macb: Add SGMII poll thread
From: Harini Katakam @ 2019-07-31 9:40 UTC (permalink / raw)
To: nicolas.ferre, davem, claudiu.beznea, robh+dt, mark.rutland
Cc: netdev, linux-kernel, michal.simek, harinikatakamlinux,
harini.katakam, devicetree
In-Reply-To: <1564566033-676-1-git-send-email-harini.katakam@xilinx.com>
The internal SGMII mode in PS GEM on ZynqMP can be used without any
external PHY on board. In this case, the phy framework doesn't kick
in to monitor the link status. Hence do the same in macb driver.
Signed-off-by: Harini Katakam <harini.katakam@xilinx.com>
Signed-off-by: Kester Aernoudt <kester.aernoudt@xilinx.com>
---
drivers/net/ethernet/cadence/macb.h | 8 ++++
drivers/net/ethernet/cadence/macb_main.c | 65 ++++++++++++++++++++++++++++++--
2 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 03983bd..b07284a 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -155,6 +155,7 @@
#define GEM_PEFTN 0x01f4 /* PTP Peer Event Frame Tx Ns */
#define GEM_PEFRSL 0x01f8 /* PTP Peer Event Frame Rx Sec Low */
#define GEM_PEFRN 0x01fc /* PTP Peer Event Frame Rx Ns */
+#define GEM_PCSSTATUS 0x0204 /* PCS Status */
#define GEM_DCFG1 0x0280 /* Design Config 1 */
#define GEM_DCFG2 0x0284 /* Design Config 2 */
#define GEM_DCFG3 0x0288 /* Design Config 3 */
@@ -455,6 +456,10 @@
#define MACB_REV_OFFSET 0
#define MACB_REV_SIZE 16
+/* Bitfields in PCSSTATUS */
+#define GEM_PCSLINK_OFFSET 2
+#define GEM_PCSLINK_SIZE 1
+
/* Bitfields in DCFG1. */
#define GEM_IRQCOR_OFFSET 23
#define GEM_IRQCOR_SIZE 1
@@ -1232,6 +1237,9 @@ struct macb {
u32 rx_intr_mask;
struct macb_pm_data pm_data;
+
+ int internal_pcspma;
+ struct task_struct *sgmii_poll_task;
};
#ifdef CONFIG_MACB_USE_HWSTAMP
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 5ca17e6..ae1f18d 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -36,6 +36,7 @@
#include <linux/tcp.h>
#include <linux/iopoll.h>
#include <linux/pm_runtime.h>
+#include <linux/kthread.h>
#include "macb.h"
/* This structure is only used for MACB on SiFive FU540 devices */
@@ -2418,8 +2419,10 @@ static int macb_open(struct net_device *dev)
/* carrier starts down */
netif_carrier_off(dev);
- /* if the phy is not yet register, retry later*/
- if (!dev->phydev) {
+ /* if the phy is not yet registered and internal SGMII is not used,
+ * retry later
+ */
+ if (!bp->internal_pcspma && !dev->phydev) {
err = -EAGAIN;
goto pm_exit;
}
@@ -2441,7 +2444,8 @@ static int macb_open(struct net_device *dev)
macb_init_hw(bp);
/* schedule a link state check */
- phy_start(dev->phydev);
+ if (!bp->internal_pcspma)
+ phy_start(dev->phydev);
netif_tx_start_all_queues(dev);
@@ -2468,7 +2472,7 @@ static int macb_close(struct net_device *dev)
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
napi_disable(&queue->napi);
- if (dev->phydev)
+ if (!bp->internal_pcspma && dev->phydev)
phy_stop(dev->phydev);
spin_lock_irqsave(&bp->lock, flags);
@@ -3187,6 +3191,49 @@ static const struct ethtool_ops gem_ethtool_ops = {
.set_rxnfc = gem_set_rxnfc,
};
+int gem_sgmii_status_poll(void *data)
+{
+ struct net_device *dev = data;
+ struct macb *bp = netdev_priv(dev);
+ int status, prev_status = 0;
+ u32 reg;
+
+ while (!kthread_should_stop()) {
+ status = gem_readl(bp, PCSSTATUS) & GEM_BIT(PCSLINK);
+ reg = macb_readl(bp, NCR);
+ if (!(reg & MACB_BIT(RE)) || !(reg & MACB_BIT(TE)) ||
+ (!netif_carrier_ok(dev) && prev_status))
+ status = 0;
+
+ if (status != prev_status) {
+ if (status) {
+ reg = macb_readl(bp, NCFGR);
+ reg |= MACB_BIT(FD);
+ reg |= GEM_BIT(GBE);
+
+ macb_or_gem_writel(bp, NCFGR, reg);
+
+ bp->speed = SPEED_1000;
+ bp->duplex = DUPLEX_FULL;
+ bp->link = 1;
+ macb_set_tx_clk(bp->tx_clk, SPEED_1000, dev);
+
+ netif_carrier_on(dev);
+ netdev_info(dev, "link up (%d/%s)\n",
+ SPEED_1000, "Full");
+ } else {
+ netif_carrier_off(dev);
+ netdev_info(dev, "link down\n");
+ }
+
+ prev_status = status;
+ }
+ schedule_timeout_uninterruptible(HZ);
+ }
+
+ return 0;
+}
+
static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct phy_device *phydev = dev->phydev;
@@ -4344,6 +4391,12 @@ static int macb_probe(struct platform_device *pdev)
macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
dev->base_addr, dev->irq, dev->dev_addr);
+ bp->internal_pcspma = of_property_read_bool(np, "is-internal-pcspma");
+
+ if (bp->internal_pcspma)
+ bp->sgmii_poll_task = kthread_run(gem_sgmii_status_poll, dev,
+ "gem_sgmii_status_poll");
+
pm_runtime_mark_last_busy(&bp->pdev->dev);
pm_runtime_put_autosuspend(&bp->pdev->dev);
@@ -4384,6 +4437,10 @@ static int macb_remove(struct platform_device *pdev)
if (dev) {
bp = netdev_priv(dev);
+
+ if (bp->internal_pcspma)
+ kthread_stop(bp->sgmii_poll_task);
+
if (dev->phydev)
phy_disconnect(dev->phydev);
mdiobus_unregister(bp->mii_bus);
--
2.7.4
^ permalink raw reply related
* [RFC PATCH 1/2] dt-bindings: net: macb: Add new property for PS SGMII only
From: Harini Katakam @ 2019-07-31 9:40 UTC (permalink / raw)
To: nicolas.ferre, davem, claudiu.beznea, robh+dt, mark.rutland
Cc: netdev, linux-kernel, michal.simek, harinikatakamlinux,
harini.katakam, devicetree
In-Reply-To: <1564566033-676-1-git-send-email-harini.katakam@xilinx.com>
Add a new property to indicate when PS SGMII is used with NO
external PHY on board.
Signed-off-by: Harini Katakam <harini.katakam@xilinx.com>
---
Documentation/devicetree/bindings/net/macb.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt
index 63c73fa..ae1b109 100644
--- a/Documentation/devicetree/bindings/net/macb.txt
+++ b/Documentation/devicetree/bindings/net/macb.txt
@@ -38,6 +38,10 @@ Optional properties for PHY child node:
up via magic packet.
- phy-handle : see ethernet.txt file in the same directory
+Optional properties:
+- is-internal-pcspma: Add when GEM's internal SGMII support is used without
+ any external SGMII PHY.
+
Examples:
macb0: ethernet@fffc4000 {
--
2.7.4
^ permalink raw reply related
* [RFC PATCH 0/2] Macb SGMII status poll thread
From: Harini Katakam @ 2019-07-31 9:40 UTC (permalink / raw)
To: nicolas.ferre, davem, claudiu.beznea, robh+dt, mark.rutland
Cc: netdev, linux-kernel, michal.simek, harinikatakamlinux,
harini.katakam, devicetree
When PS GEM is used with SGMII mode without an external PHY
on board, add a link status reporting mechanism.
Harini Katakam (2):
dt-bindings: net: macb: Add new property for PS SGMII only
net: macb: Add SGMII poll thread
Documentation/devicetree/bindings/net/macb.txt | 4 ++
drivers/net/ethernet/cadence/macb.h | 8 ++++
drivers/net/ethernet/cadence/macb_main.c | 65 ++++++++++++++++++++++++--
3 files changed, 73 insertions(+), 4 deletions(-)
--
2.7.4
^ permalink raw reply
* [v2,3/3] arm: dts: ls1021a: add ftm_alarm0 DT node
From: Biwen Li @ 2019-07-31 9:38 UTC (permalink / raw)
To: robh+dt, mark.rutland, leoyang.li; +Cc: devicetree, linux-kernel, Biwen Li
In-Reply-To: <20190731093826.49046-1-biwen.li@nxp.com>
The patch add ftm_alarm0 DT node
- add rcpm node
- add ftm_alarm0 node
- aliases ftm_alarm0 as rtc1
Signed-off-by: Biwen Li <biwen.li@nxp.com>
---
Change in v2:
- delete reg-name property
- correct fsl,rcpm-wakeup property
arch/arm/boot/dts/ls1021a.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 464df4290ffc..30bd6bc1f49a 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -66,6 +66,7 @@
serial4 = &lpuart4;
serial5 = &lpuart5;
sysclk = &sysclk;
+ rtc1 = &ftm_alarm0;
};
cpus {
@@ -985,5 +986,18 @@
big-endian;
};
+ rcpm: rcpm@1ee2140 {
+ compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1+";
+ reg = <0x0 0x1ee2140 0x0 0x8>;
+ #fsl,rcpm-wakeup-cells = <2>;
+ };
+
+ ftm_alarm0: timer0@29d0000 {
+ compatible = "fsl,ls1021a-ftm-alarm";
+ reg = <0x0 0x29d0000 0x0 0x10000>;
+ fsl,rcpm-wakeup = <&rcpm 0x0 0x20000000>;
+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+ big-endian;
+ };
};
};
--
2.17.1
^ permalink raw reply related
* [v2,2/3] arm64: dts: ls1012a/ls1043a/ls1046a/ls1088a/ls208xa: add ftm_alarm0 node
From: Biwen Li @ 2019-07-31 9:38 UTC (permalink / raw)
To: robh+dt, mark.rutland, leoyang.li; +Cc: devicetree, linux-kernel, Biwen Li
In-Reply-To: <20190731093826.49046-1-biwen.li@nxp.com>
The patch adds ftm_alarm0 DT node
- add new rcpm node
- add ftm_alarm0 node
- aliases ftm_alarm0 as rtc1
Signed-off-by: Biwen Li <biwen.li@nxp.com>
---
Change in v2:
- None
arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 15 +++++++++++++++
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 14 ++++++++++++++
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 15 +++++++++++++++
arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 14 ++++++++++++++
arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 14 ++++++++++++++
5 files changed, 72 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
index ec6257a5b251..401210e3afd2 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
@@ -22,6 +22,7 @@
rtic-c = &rtic_c;
rtic-d = &rtic_d;
sec-mon = &sec_mon;
+ rtc1 = &ftm_alarm0;
};
cpus {
@@ -500,6 +501,20 @@
<0000 0 0 4 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
+
+ rcpm: rcpm@1ee2140 {
+ compatible = "fsl,ls1012a-rcpm", "fsl,qoriq-rcpm-2.1+";
+ reg = <0x0 0x1ee2140 0x0 0x4>;
+ #fsl,rcpm-wakeup-cells = <1>;
+ };
+
+ ftm_alarm0: timer@29d0000 {
+ compatible = "fsl,ls1012a-ftm-alarm";
+ reg = <0x0 0x29d0000 0x0 0x10000>;
+ fsl,rcpm-wakeup = <&rcpm 0x20000>;
+ interrupts = <0 86 0x4>;
+ big-endian;
+ };
};
firmware {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index 71d9ed9ff985..9ff5dd32e87d 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -27,6 +27,7 @@
ethernet4 = &enet4;
ethernet5 = &enet5;
ethernet6 = &enet6;
+ rtc1 = &ftm_alarm0;
};
cpus {
@@ -767,6 +768,19 @@
big-endian;
};
+ rcpm: rcpm@1ee2140 {
+ compatible = "fsl,ls1043a-rcpm", "fsl,qoriq-rcpm-2.1+";
+ reg = <0x0 0x1ee2140 0x0 0x4>;
+ #fsl,rcpm-wakeup-cells = <1>;
+ };
+
+ ftm_alarm0: timer@29d0000 {
+ compatible = "fsl,ls1043a-ftm-alarm";
+ reg = <0x0 0x29d0000 0x0 0x10000>;
+ fsl,rcpm-wakeup = <&rcpm 0x20000>;
+ interrupts = <0 86 0x4>;
+ big-endian;
+ };
};
firmware {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index b0ef08b090dd..d216375b174f 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -28,6 +28,7 @@
ethernet5 = &enet5;
ethernet6 = &enet6;
ethernet7 = &enet7;
+ rtc1 = &ftm_alarm0;
};
cpus {
@@ -771,6 +772,20 @@
queue-sizes = <64 64>;
big-endian;
};
+
+ rcpm: rcpm@1ee208c {
+ compatible = "fsl,ls1046a-rcpm", "fsl,qoriq-rcpm-2.1+";
+ reg = <0x0 0x1ee208c 0x0 0x4>;
+ #fsl,rcpm-wakeup-cells = <1>;
+ };
+
+ ftm_alarm0: timer@29d0000 {
+ compatible = "fsl,ls1046a-ftm-alarm";
+ reg = <0x0 0x29d0000 0x0 0x10000>;
+ fsl,rcpm-wakeup = <&rcpm 0x20000>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ big-endian;
+ };
};
reserved-memory {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
index dacd8cf03a7f..61cb897b940a 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
@@ -18,6 +18,7 @@
aliases {
crypto = &crypto;
+ rtc1 = &ftm_alarm0;
};
cpus {
@@ -745,6 +746,19 @@
};
};
};
+
+ rcpm: rcpm@1e34040 {
+ compatible = "fsl,ls1088a-rcpm", "fsl,qoriq-rcpm-2.1+";
+ reg = <0x0 0x1e34040 0x0 0x18>;
+ #fsl,rcpm-wakeup-cells = <6>;
+ };
+
+ ftm_alarm0: timer@2800000 {
+ compatible = "fsl,ls1088a-ftm-alarm";
+ reg = <0x0 0x2800000 0x0 0x10000>;
+ fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0>;
+ interrupts = <0 44 4>;
+ };
};
firmware {
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
index 3ace91945b72..908386042c5b 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
@@ -24,6 +24,7 @@
serial1 = &serial1;
serial2 = &serial2;
serial3 = &serial3;
+ rtc1 = &ftm_alarm0;
};
cpu: cpus {
@@ -758,6 +759,19 @@
reg = <0x0 0x04000000 0x0 0x01000000>;
interrupts = <0 12 4>;
};
+
+ rcpm: rcpm@1e34040 {
+ compatible = "fsl,ls208xa-rcpm", "fsl,qoriq-rcpm-2.1+";
+ reg = <0x0 0x1e34040 0x0 0x18>;
+ #fsl,rcpm-wakeup-cells = <6>;
+ };
+
+ ftm_alarm0: timer@2800000 {
+ compatible = "fsl,ls208xa-ftm-alarm";
+ reg = <0x0 0x2800000 0x0 0x10000>;
+ fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0>;
+ interrupts = <0 44 4>;
+ };
};
ddr1: memory-controller@1080000 {
--
2.17.1
^ permalink raw reply related
* [v2,1/3] arm64: dts: ls1028a: Add ftm_alarm0 DT node
From: Biwen Li @ 2019-07-31 9:38 UTC (permalink / raw)
To: robh+dt, mark.rutland, leoyang.li; +Cc: devicetree, linux-kernel, Biwen Li
The patch adds ftm_alarm0 DT node for LS1028ARDB board
FlexTimer1 module is used to wakeup the system
Signed-off-by: Biwen Li <biwen.li@nxp.com>
---
Change in v2:
- None
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
index 7975519b4f56..3c66d1e1d196 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
@@ -17,6 +17,10 @@
#address-cells = <2>;
#size-cells = <2>;
+ aliases {
+ rtc1 = &ftm_alarm0;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -543,6 +547,19 @@
little-endian;
};
};
+
+ rcpm: rcpm@1e34040 {
+ compatible = "fsl,ls1028a-rcpm", "fsl,qoriq-rcpm-2.1+";
+ reg = <0x0 0x1e34040 0x0 0x1c>;
+ #fsl,rcpm-wakeup-cells = <7>;
+ };
+
+ ftm_alarm0: timer@2800000 {
+ compatible = "fsl,ls1028a-ftm-alarm";
+ reg = <0x0 0x2800000 0x0 0x10000>;
+ fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0 0x0>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ };
};
malidp0: display@f080000 {
--
2.17.1
^ permalink raw reply related
* RE: [PATCH 2/6] hwspinlock: allow sharing of hwspinlocks
From: Loic PALLARDY @ 2019-07-31 9:22 UTC (permalink / raw)
To: Ohad Ben-Cohen, Bjorn Andersson, Rob Herring, Mark Rutland,
Maxime Coquelin, Alexandre TORGUE, Jonathan Corbet,
linux-remoteproc@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org
Cc: Benjamin GAIGNARD, Fabien DESSENNE
In-Reply-To: <1552492237-28810-3-git-send-email-fabien.dessenne@st.com>
> -----Original Message-----
> From: linux-remoteproc-owner@vger.kernel.org <linux-remoteproc-
> owner@vger.kernel.org> On Behalf Of Fabien Dessenne
> Sent: mercredi 13 mars 2019 16:51
> To: Ohad Ben-Cohen <ohad@wizery.com>; Bjorn Andersson
> <bjorn.andersson@linaro.org>; Rob Herring <robh+dt@kernel.org>; Mark
> Rutland <mark.rutland@arm.com>; Maxime Coquelin
> <mcoquelin.stm32@gmail.com>; Alexandre TORGUE
> <alexandre.torgue@st.com>; Jonathan Corbet <corbet@lwn.net>; linux-
> remoteproc@vger.kernel.org; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-stm32@st-md-mailman.stormreply.com;
> linux-arm-kernel@lists.infradead.org; linux-doc@vger.kernel.org
> Cc: Fabien DESSENNE <fabien.dessenne@st.com>; Benjamin GAIGNARD
> <benjamin.gaignard@st.com>
> Subject: [PATCH 2/6] hwspinlock: allow sharing of hwspinlocks
>
> The current implementation does not allow different devices to use a
> common hwspinlock. Offer the possibility to use the same hwspinlock by
> several users.
> If a device registers to the framework with #hwlock-cells = 2, then
> the second parameter of the 'hwlocks' DeviceTree property defines
> whether an hwlock is requested for an exclusive or a shared usage.
> If a device registers with #hwlock-cells = 1, then all the hwlocks are
> for an exclusive usage.
>
> Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com>
Looks good for me.
Acked-by: Loic Pallardy <loic.pallardy@st.com>
Regards,
Loic
> ---
> Documentation/hwspinlock.txt | 10 ++--
> drivers/hwspinlock/hwspinlock_core.c | 82
> +++++++++++++++++++++++++-------
> drivers/hwspinlock/hwspinlock_internal.h | 2 +
> 3 files changed, 73 insertions(+), 21 deletions(-)
>
> diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt
> index ed640a2..e6ce2dd 100644
> --- a/Documentation/hwspinlock.txt
> +++ b/Documentation/hwspinlock.txt
> @@ -54,9 +54,11 @@ Should be called from a process context (might sleep).
> struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
>
> Assign a specific hwspinlock id and return its address, or NULL
> -if that hwspinlock is already in use. Usually board code will
> -be calling this function in order to reserve specific hwspinlock
> -ids for predefined purposes.
> +if that hwspinlock is already in use and not shared. If that specific
> +hwspinlock is declared as shared, it can be requested and used by
> +several users.
> +Usually board code will be calling this function in order to reserve
> +specific hwspinlock ids for predefined purposes.
>
> Should be called from a process context (might sleep).
>
> @@ -368,11 +370,13 @@ of which represents a single hardware lock::
> * struct hwspinlock - this struct represents a single hwspinlock
> instance
> * @bank: the hwspinlock_device structure which owns this lock
> * @lock: initialized and used by hwspinlock core
> + * @refcount: number of users (when shared)
> * @priv: private data, owned by the underlying platform-specific
> hwspinlock drv
> */
> struct hwspinlock {
> struct hwspinlock_device *bank;
> spinlock_t lock;
> + unsigned int refcount;
> void *priv;
> };
>
> diff --git a/drivers/hwspinlock/hwspinlock_core.c
> b/drivers/hwspinlock/hwspinlock_core.c
> index 2bad40d..53afdeb 100644
> --- a/drivers/hwspinlock/hwspinlock_core.c
> +++ b/drivers/hwspinlock/hwspinlock_core.c
> @@ -25,6 +25,8 @@
>
> /* radix tree tags */
> #define HWSPINLOCK_UNUSED (0) /* tags an hwspinlock as unused
> */
> +#define HWSPINLOCK_EXCLUSIVE (1) /* tags an hwspinlock as exclusive
> */
> +#define HWSPINLOCK_SHARED (2) /* tags an hwspinlock as shared */
>
> /*
> * A radix tree is used to maintain the available hwspinlock instances.
> @@ -291,7 +293,7 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock);
> * @hwlock_spec: hwlock specifier as found in the device tree
> *
> * This is a simple translation function, suitable for hwspinlock platform
> - * drivers that only has a lock specifier length of 1.
> + * drivers that only has a lock specifier length of 1 or 2.
> *
> * Returns a relative index of the lock within a specified bank on success,
> * or -EINVAL on invalid specifier cell count.
> @@ -299,7 +301,8 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock);
> static inline int
> of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
> {
> - if (WARN_ON(hwlock_spec->args_count != 1))
> + if (WARN_ON(hwlock_spec->args_count != 1 &&
> + hwlock_spec->args_count != 2))
> return -EINVAL;
>
> return hwlock_spec->args[0];
> @@ -322,11 +325,12 @@ of_hwspin_lock_simple_xlate(const struct
> of_phandle_args *hwlock_spec)
> int of_hwspin_lock_get_id(struct device_node *np, int index)
> {
> struct of_phandle_args args;
> - struct hwspinlock *hwlock;
> + struct hwspinlock *hwlock, *tmp;
> struct radix_tree_iter iter;
> void **slot;
> int id;
> int ret;
> + unsigned int tag;
>
> ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells",
> index,
> &args);
> @@ -361,6 +365,37 @@ int of_hwspin_lock_get_id(struct device_node *np,
> int index)
> }
> id += hwlock->bank->base_id;
>
> + /* Set the EXCLUSIVE / SHARED tag */
> + if (args.args_count == 2 && args.args[1]) {
> + /* Tag SHARED unless already tagged EXCLUSIVE */
> + if (radix_tree_tag_get(&hwspinlock_tree, id,
> + HWSPINLOCK_EXCLUSIVE)) {
> + ret = -EINVAL;
> + goto out;
> + }
> + tag = HWSPINLOCK_SHARED;
> + } else {
> + /* Tag EXCLUSIVE unless already tagged SHARED */
> + if (radix_tree_tag_get(&hwspinlock_tree, id,
> + HWSPINLOCK_SHARED)) {
> + ret = -EINVAL;
> + goto out;
> + }
> + tag = HWSPINLOCK_EXCLUSIVE;
> + }
> +
> + /* mark this hwspinlock */
> + hwlock = radix_tree_lookup(&hwspinlock_tree, id);
> + if (!hwlock) {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + tmp = radix_tree_tag_set(&hwspinlock_tree, id, tag);
> +
> + /* self-sanity check which should never fail */
> + WARN_ON(tmp != hwlock);
> +
> out:
> of_node_put(args.np);
> return ret ? ret : id;
> @@ -483,6 +518,7 @@ int hwspin_lock_register(struct hwspinlock_device
> *bank, struct device *dev,
>
> spin_lock_init(&hwlock->lock);
> hwlock->bank = bank;
> + hwlock->refcount = 0;
>
> ret = hwspin_lock_register_single(hwlock, base_id + i);
> if (ret)
> @@ -625,7 +661,7 @@ static int __hwspin_lock_request(struct hwspinlock
> *hwlock)
> {
> struct device *dev = hwlock->bank->dev;
> struct hwspinlock *tmp;
> - int ret;
> + int ret, id;
>
> /* prevent underlying implementation from being removed */
> if (!try_module_get(dev->driver->owner)) {
> @@ -642,13 +678,18 @@ static int __hwspin_lock_request(struct hwspinlock
> *hwlock)
> return ret;
> }
>
> + /* update shareable refcount */
> + id = hwlock_to_id(hwlock);
> + if (radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED)
> &&
> + hwlock->refcount++)
> + goto out;
> +
> /* mark hwspinlock as used, should not fail */
> - tmp = radix_tree_tag_clear(&hwspinlock_tree,
> hwlock_to_id(hwlock),
> -
> HWSPINLOCK_UNUSED);
> + tmp = radix_tree_tag_clear(&hwspinlock_tree, id,
> HWSPINLOCK_UNUSED);
>
> /* self-sanity check that should never fail */
> WARN_ON(tmp != hwlock);
> -
> +out:
> return ret;
> }
>
> @@ -742,9 +783,9 @@ struct hwspinlock
> *hwspin_lock_request_specific(unsigned int id)
> /* sanity check (this shouldn't happen) */
> WARN_ON(hwlock_to_id(hwlock) != id);
>
> - /* make sure this hwspinlock is unused */
> - ret = radix_tree_tag_get(&hwspinlock_tree, id,
> HWSPINLOCK_UNUSED);
> - if (ret == 0) {
> + /* make sure this hwspinlock is unused or shareable */
> + if (!radix_tree_tag_get(&hwspinlock_tree, id,
> HWSPINLOCK_SHARED) &&
> + !radix_tree_tag_get(&hwspinlock_tree, id,
> HWSPINLOCK_UNUSED)) {
> pr_warn("hwspinlock %u is already in use\n", id);
> hwlock = NULL;
> goto out;
> @@ -777,7 +818,7 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
> {
> struct device *dev;
> struct hwspinlock *tmp;
> - int ret;
> + int ret, id;
>
> if (!hwlock) {
> pr_err("invalid hwlock\n");
> @@ -788,30 +829,35 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
> mutex_lock(&hwspinlock_tree_lock);
>
> /* make sure the hwspinlock is used */
> - ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock),
> -
> HWSPINLOCK_UNUSED);
> + id = hwlock_to_id(hwlock);
> + ret = radix_tree_tag_get(&hwspinlock_tree, id,
> HWSPINLOCK_UNUSED);
> if (ret == 1) {
> dev_err(dev, "%s: hwlock is already free\n", __func__);
> dump_stack();
> ret = -EINVAL;
> - goto out;
> + goto unlock;
> }
>
> /* notify the underlying device that power is not needed */
> ret = pm_runtime_put(dev);
> if (ret < 0)
> - goto out;
> + goto unlock;
> +
> + /* update shareable refcount */
> + if (radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_SHARED)
> &&
> + --hwlock->refcount)
> + goto put;
>
> /* mark this hwspinlock as available */
> - tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock),
> -
> HWSPINLOCK_UNUSED);
> + tmp = radix_tree_tag_set(&hwspinlock_tree, id,
> HWSPINLOCK_UNUSED);
>
> /* sanity check (this shouldn't happen) */
> WARN_ON(tmp != hwlock);
>
> +put:
> module_put(dev->driver->owner);
>
> -out:
> +unlock:
> mutex_unlock(&hwspinlock_tree_lock);
> return ret;
> }
> diff --git a/drivers/hwspinlock/hwspinlock_internal.h
> b/drivers/hwspinlock/hwspinlock_internal.h
> index 9eb6bd0..c808e11 100644
> --- a/drivers/hwspinlock/hwspinlock_internal.h
> +++ b/drivers/hwspinlock/hwspinlock_internal.h
> @@ -35,11 +35,13 @@ struct hwspinlock_ops {
> * struct hwspinlock - this struct represents a single hwspinlock instance
> * @bank: the hwspinlock_device structure which owns this lock
> * @lock: initialized and used by hwspinlock core
> + * @refcount: number of users (when shared)
> * @priv: private data, owned by the underlying platform-specific hwspinlock
> drv
> */
> struct hwspinlock {
> struct hwspinlock_device *bank;
> spinlock_t lock;
> + unsigned int refcount;
> void *priv;
> };
>
> --
> 2.7.4
^ permalink raw reply
* Re: [alsa-devel] [PATCH v2 2/3] ASoC: Add codec driver for ST TDA7802
From: Thomas Preston @ 2019-07-31 8:57 UTC (permalink / raw)
To: Marco Felsch
Cc: Mark Rutland, devicetree, alsa-devel, Charles Keepax,
Kuninori Morimoto, Kirill Marinushkin, linux-kernel, Takashi Iwai,
Annaliese McDermond, Liam Girdwood, Paul Cercueil, Rob Herring,
Vinod Koul, Mark Brown, Srinivas Kandagatla, Patrick Glaser,
Rob Duncan, Jerome Brunet, Nate Case, Cheng-Yi Chiang
In-Reply-To: <20190731060644.yrewu2kvrlootyyl@pengutronix.de>
On 31/07/2019 07:06, Marco Felsch wrote:
> Hi Thomas,
>
> again sorry for jumping in..
>
Np!
> On 19-07-30 18:26, Thomas Preston wrote:
>> On 30/07/2019 15:58, Mark Brown wrote:
>>> On Tue, Jul 30, 2019 at 01:09:36PM +0100, Thomas Preston wrote:
>>>> + case SND_SOC_BIAS_STANDBY:
>>>> + err = regulator_enable(tda7802->enable_reg);
>>>> + if (err < 0) {
>>>> + dev_err(component->dev, "Could not enable.\n");
>>>> + return err;
>>>> + }
>>>> + dev_dbg(component->dev, "Regulator enabled\n");
>>>> + msleep(ENABLE_DELAY_MS);
>>>
>>> Is this delay needed by the device or is it for the regulator to ramp?
>>> If it's for the regulator to ramp then the regulator should be doing it.
>>>
>>
>> According to the datasheet the device itself takes 10ms to rise from 0V
>> after PLLen is enabled. There are additional rise times but they are
>> negligible with default capacitor configuration (which we have).
>>
>> Good to know about the regulator rising configuration though. Thanks.
>
> Isn't it the regulator we mentioned to not use that because it is a
> GPIO?
>
Yeah it is - I intend to switch PLLen to gpio API.
^ permalink raw reply
* Re: [PATCH] arm64: dts: renesas: r8a77995: draak: Fix backlight regulator name
From: Geert Uytterhoeven @ 2019-07-31 8:32 UTC (permalink / raw)
To: Laurent Pinchart
Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Laurent Pinchart, Geert Uytterhoeven, Rob Herring, Mark Brown,
Magnus Damm, Johan Hovold, Linux-Renesas, Simon Horman, Linux ARM,
Marek Vasut
In-Reply-To: <20190731081209.GA5080@pendragon.ideasonboard.com>
Hi Laurent,
On Wed, Jul 31, 2019 at 10:12 AM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Wed, Jul 31, 2019 at 09:48:01AM +0200, Geert Uytterhoeven wrote:
> > Currently there are two nodes named "regulator1" in the Draak DTS: a
> > 3.3V regulator for the eMMC and the LVDS decoder, and a 12V regulator
> > for the backlight. This causes the former to be overwritten by the
> > latter.
> >
> > Fix this by renaming all regulators with numerical suffixes to use named
> > suffixes, which are less likely to conflict.
>
> Aren't DT node names supposed to describe the device type, not a
> particular instance of the device ? This is something that has bothered
> me too, but I believe the naming scheme should be decided globally, not
> per board. Is there precedent for using this scheme that has been
> explicitly approved by the DT maintainers ?
The example in Documentation/devicetree/bindings/regulator/regulator.yaml
uses "regulator@0", which of course works only if #address-cells = 1, which
is usually not the case for discrete regulators.
BTW, the example lacks a "reg" property...
So some other suffix has to be added to distinguish individual "regulator"
nodes.
The example in Documentation/devicetree/bindings/regulator/fixed-regulator.yaml
uses "regulator-1v8" since commit b735f41dcb06ae06 ("dt-bindings: regulator:
update fixed-regulator example"), which received a Reviewed-by from Rob
after it was committed.
https://lore.kernel.org/lkml/CAL_Jsq+rRYazOqtjNms0cTK0HpkxCkmZ4JXoLM7ZaPivATEO8A@mail.gmail.com/
Looks good enough to me ;-)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH v2 4/4] firmware: meson_sm: Rework driver as a proper platform driver
From: Carlo Caione @ 2019-07-31 8:23 UTC (permalink / raw)
To: srinivas.kandagatla, khilman, narmstrong, robh+dt, tglx, jbrunet,
linux-arm-kernel, linux-amlogic, devicetree
Cc: Carlo Caione
In-Reply-To: <20190731082339.20163-1-ccaione@baylibre.com>
The secure monitor driver is currently a frankenstein driver which is
registered as a platform driver but its functionality goes through a
global struct accessed by the consumer drivers using exported helper
functions.
Try to tidy up the driver moving the firmware struct into the driver
data and make the consumer drivers referencing the secure-monitor using
a new property in the DT.
Currently only the nvmem driver is using this API so we can fix it in
the same commit.
Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Carlo Caione <ccaione@baylibre.com>
---
drivers/firmware/meson/meson_sm.c | 94 +++++++++++++++++--------
drivers/nvmem/meson-efuse.c | 24 ++++++-
include/linux/firmware/meson/meson_sm.h | 15 ++--
3 files changed, 94 insertions(+), 39 deletions(-)
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
index 772ca6726e7b..2e36a2aa274c 100644
--- a/drivers/firmware/meson/meson_sm.c
+++ b/drivers/firmware/meson/meson_sm.c
@@ -54,8 +54,6 @@ struct meson_sm_firmware {
void __iomem *sm_shmem_out_base;
};
-static struct meson_sm_firmware fw;
-
static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip,
unsigned int cmd_index)
{
@@ -90,6 +88,7 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
/**
* meson_sm_call - generic SMC32 call to the secure-monitor
*
+ * @fw: Pointer to secure-monitor firmware
* @cmd_index: Index of the SMC32 function ID
* @ret: Returned value
* @arg0: SMC32 Argument 0
@@ -100,15 +99,15 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
*
* Return: 0 on success, a negative value on error
*/
-int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0,
- u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index,
+ u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 cmd, lret;
- if (!fw.chip)
+ if (!fw->chip)
return -ENOENT;
- cmd = meson_sm_get_cmd(fw.chip, cmd_index);
+ cmd = meson_sm_get_cmd(fw->chip, cmd_index);
if (!cmd)
return -EINVAL;
@@ -124,6 +123,7 @@ EXPORT_SYMBOL(meson_sm_call);
/**
* meson_sm_call_read - retrieve data from secure-monitor
*
+ * @fw: Pointer to secure-monitor firmware
* @buffer: Buffer to store the retrieved data
* @bsize: Size of the buffer
* @cmd_index: Index of the SMC32 function ID
@@ -137,22 +137,23 @@ EXPORT_SYMBOL(meson_sm_call);
* When 0 is returned there is no guarantee about the amount of
* data read and bsize bytes are copied in buffer.
*/
-int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
+ unsigned int bsize, unsigned int cmd_index, u32 arg0,
+ u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 size;
int ret;
- if (!fw.chip)
+ if (!fw->chip)
return -ENOENT;
- if (!fw.chip->cmd_shmem_out_base)
+ if (!fw->chip->cmd_shmem_out_base)
return -EINVAL;
- if (bsize > fw.chip->shmem_size)
+ if (bsize > fw->chip->shmem_size)
return -EINVAL;
- if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
+ if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
return -EINVAL;
if (size > bsize)
@@ -164,7 +165,7 @@ int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
size = bsize;
if (buffer)
- memcpy(buffer, fw.sm_shmem_out_base, size);
+ memcpy(buffer, fw->sm_shmem_out_base, size);
return ret;
}
@@ -173,6 +174,7 @@ EXPORT_SYMBOL(meson_sm_call_read);
/**
* meson_sm_call_write - send data to secure-monitor
*
+ * @fw: Pointer to secure-monitor firmware
* @buffer: Buffer containing data to send
* @size: Size of the data to send
* @cmd_index: Index of the SMC32 function ID
@@ -184,23 +186,24 @@ EXPORT_SYMBOL(meson_sm_call_read);
*
* Return: size of sent data on success, a negative value on error
*/
-int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
+int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
+ unsigned int size, unsigned int cmd_index, u32 arg0,
+ u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 written;
- if (!fw.chip)
+ if (!fw->chip)
return -ENOENT;
- if (size > fw.chip->shmem_size)
+ if (size > fw->chip->shmem_size)
return -EINVAL;
- if (!fw.chip->cmd_shmem_in_base)
+ if (!fw->chip->cmd_shmem_in_base)
return -EINVAL;
- memcpy(fw.sm_shmem_in_base, buffer, size);
+ memcpy(fw->sm_shmem_in_base, buffer, size);
- if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
+ if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
return -EINVAL;
if (!written)
@@ -210,6 +213,24 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
}
EXPORT_SYMBOL(meson_sm_call_write);
+/**
+ * meson_sm_get - get pointer to meson_sm_firmware structure.
+ *
+ * @sm_node: Pointer to the secure-monitor Device Tree node.
+ *
+ * Return: NULL is the secure-monitor device is not ready.
+ */
+struct meson_sm_firmware *meson_sm_get(struct device_node *sm_node)
+{
+ struct platform_device *pdev = of_find_device_by_node(sm_node);
+
+ if (!pdev)
+ return NULL;
+
+ return platform_get_drvdata(pdev);
+}
+EXPORT_SYMBOL_GPL(meson_sm_get);
+
#define SM_CHIP_ID_LENGTH 119
#define SM_CHIP_ID_OFFSET 4
#define SM_CHIP_ID_SIZE 12
@@ -217,14 +238,18 @@ EXPORT_SYMBOL(meson_sm_call_write);
static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct meson_sm_firmware *fw;
uint8_t *id_buf;
int ret;
+ fw = platform_get_drvdata(pdev);
+
id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL);
if (!id_buf)
return -ENOMEM;
- ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
+ ret = meson_sm_call_read(fw, id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
0, 0, 0, 0, 0);
if (ret < 0) {
kfree(id_buf);
@@ -268,25 +293,34 @@ static const struct of_device_id meson_sm_ids[] = {
static int __init meson_sm_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
const struct meson_sm_chip *chip;
+ struct meson_sm_firmware *fw;
+
+ fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
- chip = of_match_device(meson_sm_ids, &pdev->dev)->data;
+ chip = of_match_device(meson_sm_ids, dev)->data;
if (chip->cmd_shmem_in_base) {
- fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
- chip->shmem_size);
- if (WARN_ON(!fw.sm_shmem_in_base))
+ fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
+ chip->shmem_size);
+ if (WARN_ON(!fw->sm_shmem_in_base))
goto out;
}
if (chip->cmd_shmem_out_base) {
- fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
- chip->shmem_size);
- if (WARN_ON(!fw.sm_shmem_out_base))
+ fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
+ chip->shmem_size);
+ if (WARN_ON(!fw->sm_shmem_out_base))
goto out_in_base;
}
- fw.chip = chip;
+ fw->chip = chip;
+
+ platform_set_drvdata(pdev, fw);
+
pr_info("secure-monitor enabled\n");
if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
@@ -295,7 +329,7 @@ static int __init meson_sm_probe(struct platform_device *pdev)
return 0;
out_in_base:
- iounmap(fw.sm_shmem_in_base);
+ iounmap(fw->sm_shmem_in_base);
out:
return -EINVAL;
}
diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c
index 39bd76306033..d6b533497ce1 100644
--- a/drivers/nvmem/meson-efuse.c
+++ b/drivers/nvmem/meson-efuse.c
@@ -17,14 +17,18 @@
static int meson_efuse_read(void *context, unsigned int offset,
void *val, size_t bytes)
{
- return meson_sm_call_read((u8 *)val, bytes, SM_EFUSE_READ, offset,
+ struct meson_sm_firmware *fw = context;
+
+ return meson_sm_call_read(fw, (u8 *)val, bytes, SM_EFUSE_READ, offset,
bytes, 0, 0, 0);
}
static int meson_efuse_write(void *context, unsigned int offset,
void *val, size_t bytes)
{
- return meson_sm_call_write((u8 *)val, bytes, SM_EFUSE_WRITE, offset,
+ struct meson_sm_firmware *fw = context;
+
+ return meson_sm_call_write(fw, (u8 *)val, bytes, SM_EFUSE_WRITE, offset,
bytes, 0, 0, 0);
}
@@ -37,12 +41,25 @@ MODULE_DEVICE_TABLE(of, meson_efuse_match);
static int meson_efuse_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct meson_sm_firmware *fw;
+ struct device_node *sm_np;
struct nvmem_device *nvmem;
struct nvmem_config *econfig;
struct clk *clk;
unsigned int size;
int ret;
+ sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
+ if (!sm_np) {
+ dev_err(&pdev->dev, "no secure-monitor node\n");
+ return -ENODEV;
+ }
+
+ fw = meson_sm_get(sm_np);
+ of_node_put(sm_np);
+ if (!fw)
+ return -EPROBE_DEFER;
+
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -65,7 +82,7 @@ static int meson_efuse_probe(struct platform_device *pdev)
return ret;
}
- if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
+ if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
dev_err(dev, "failed to get max user");
return -EINVAL;
}
@@ -81,6 +98,7 @@ static int meson_efuse_probe(struct platform_device *pdev)
econfig->reg_read = meson_efuse_read;
econfig->reg_write = meson_efuse_write;
econfig->size = size;
+ econfig->priv = fw;
nvmem = devm_nvmem_register(&pdev->dev, econfig);
diff --git a/include/linux/firmware/meson/meson_sm.h b/include/linux/firmware/meson/meson_sm.h
index 7613bf7c9442..6669e2a1d5fd 100644
--- a/include/linux/firmware/meson/meson_sm.h
+++ b/include/linux/firmware/meson/meson_sm.h
@@ -16,11 +16,14 @@ enum {
struct meson_sm_firmware;
-int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, u32 arg1,
- u32 arg2, u32 arg3, u32 arg4);
-int meson_sm_call_write(void *buffer, unsigned int b_size, unsigned int cmd_index,
- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
-int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index,
+ u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
+ unsigned int b_size, unsigned int cmd_index, u32 arg0,
+ u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
+ unsigned int bsize, unsigned int cmd_index, u32 arg0,
+ u32 arg1, u32 arg2, u32 arg3, u32 arg4);
+struct meson_sm_firmware *meson_sm_get(struct device_node *firmware_node);
#endif /* _MESON_SM_FW_H_ */
--
2.20.1
^ permalink raw reply related
* [PATCH v2 3/4] arm64: dts: meson: Link nvmem and secure-monitor nodes
From: Carlo Caione @ 2019-07-31 8:23 UTC (permalink / raw)
To: srinivas.kandagatla, khilman, narmstrong, robh+dt, tglx, jbrunet,
linux-arm-kernel, linux-amlogic, devicetree
Cc: Carlo Caione
In-Reply-To: <20190731082339.20163-1-ccaione@baylibre.com>
The former is going to use the latter to retrieve the efuses data.
Signed-off-by: Carlo Caione <ccaione@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 1 +
arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 1 +
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 1 +
3 files changed, 3 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
index 6219337033a0..b8244efb85fa 100644
--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
@@ -117,6 +117,7 @@
#address-cells = <1>;
#size-cells = <1>;
read-only;
+ secure-monitor = <&sm>;
};
psci {
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
index f8d43e3dcf20..2b07752e034f 100644
--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi
@@ -100,6 +100,7 @@
#address-cells = <1>;
#size-cells = <1>;
read-only;
+ secure-monitor = <&sm>;
};
psci {
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 74d03fc706be..d244d9783718 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -161,6 +161,7 @@
#address-cells = <1>;
#size-cells = <1>;
read-only;
+ secure-monitor = <&sm>;
sn: sn@14 {
reg = <0x14 0x10>;
--
2.20.1
^ permalink raw reply related
* [PATCH v2 2/4] nvmem: meson-efuse: bindings: Add secure-monitor phandle
From: Carlo Caione @ 2019-07-31 8:23 UTC (permalink / raw)
To: srinivas.kandagatla, khilman, narmstrong, robh+dt, tglx, jbrunet,
linux-arm-kernel, linux-amlogic, devicetree
Cc: Carlo Caione
In-Reply-To: <20190731082339.20163-1-ccaione@baylibre.com>
Add a new property to link the nvmem driver to the secure-monitor. The
nvmem driver needs to access the secure-monitor to be able to access the
fuses.
Signed-off-by: Carlo Caione <ccaione@baylibre.com>
---
Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt b/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt
index 2e0723ab3384..f7b3ed74db54 100644
--- a/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt
+++ b/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt
@@ -4,6 +4,7 @@ Required properties:
- compatible: should be "amlogic,meson-gxbb-efuse"
- clocks: phandle to the efuse peripheral clock provided by the
clock controller.
+- secure-monitor: phandle to the secure-monitor node
= Data cells =
Are child nodes of eFuse, bindings of which as described in
@@ -16,6 +17,7 @@ Example:
clocks = <&clkc CLKID_EFUSE>;
#address-cells = <1>;
#size-cells = <1>;
+ secure-monitor = <&sm>;
sn: sn@14 {
reg = <0x14 0x10>;
@@ -30,6 +32,10 @@ Example:
};
};
+ sm: secure-monitor {
+ compatible = "amlogic,meson-gxbb-sm";
+ };
+
= Data consumers =
Are device nodes which consume nvmem data cells.
--
2.20.1
^ permalink raw reply related
* [PATCH v2 1/4] firmware: meson_sm: Mark chip struct as static const
From: Carlo Caione @ 2019-07-31 8:23 UTC (permalink / raw)
To: srinivas.kandagatla, khilman, narmstrong, robh+dt, tglx, jbrunet,
linux-arm-kernel, linux-amlogic, devicetree
Cc: Carlo Caione
In-Reply-To: <20190731082339.20163-1-ccaione@baylibre.com>
No need to be a global struct.
Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Carlo Caione <ccaione@baylibre.com>
---
drivers/firmware/meson/meson_sm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
index 8d908a8e0d20..772ca6726e7b 100644
--- a/drivers/firmware/meson/meson_sm.c
+++ b/drivers/firmware/meson/meson_sm.c
@@ -35,7 +35,7 @@ struct meson_sm_chip {
struct meson_sm_cmd cmd[];
};
-struct meson_sm_chip gxbb_chip = {
+static const struct meson_sm_chip gxbb_chip = {
.shmem_size = SZ_4K,
.cmd_shmem_in_base = 0x82000020,
.cmd_shmem_out_base = 0x82000021,
--
2.20.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox