* Re: [PATCH 04/14] serial: lpc32xx_hs: allow compile-testing
From: Greg Kroah-Hartman @ 2019-08-01 5:58 UTC (permalink / raw)
To: Arnd Bergmann
Cc: soc, linux-arm-kernel, Vladimir Zapolskiy, Sylvain Lemieux,
Russell King, Gregory Clement, Linus Walleij, Jiri Slaby,
Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, David S. Miller,
Alan Stern, Guenter Roeck, linux-gpio, netdev, linux-serial,
linux-usb, linux-watchdog, linux-kernel
In-Reply-To: <20190731195713.3150463-5-arnd@arndb.de>
On Wed, Jul 31, 2019 at 09:56:46PM +0200, Arnd Bergmann wrote:
> The only thing that prevents building this driver on other
> platforms is the mach/hardware.h include, which is not actually
> used here at all, so remove the line and allow CONFIG_COMPILE_TEST.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/tty/serial/Kconfig | 3 ++-
> drivers/tty/serial/lpc32xx_hs.c | 2 --
> 2 files changed, 2 insertions(+), 3 deletions(-)
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply
* Re: [PATCH 02/14] usb: udc: lpc32xx: allow compile-testing
From: Greg Kroah-Hartman @ 2019-08-01 5:58 UTC (permalink / raw)
To: Arnd Bergmann
Cc: soc, linux-arm-kernel, Vladimir Zapolskiy, Sylvain Lemieux,
Russell King, Gregory Clement, Linus Walleij, Felipe Balbi,
Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, David S. Miller,
Alan Stern, Guenter Roeck, linux-gpio, netdev, linux-serial,
linux-usb, linux-watchdog, Alexandre Belloni, linux-kernel
In-Reply-To: <20190731195713.3150463-3-arnd@arndb.de>
On Wed, Jul 31, 2019 at 09:56:44PM +0200, Arnd Bergmann wrote:
> The only thing that prevents building this driver on other
> platforms is the mach/hardware.h include, which is not actually
> used here at all, so remove the line and allow CONFIG_COMPILE_TEST.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/usb/gadget/udc/Kconfig | 3 ++-
> drivers/usb/gadget/udc/lpc32xx_udc.c | 2 --
> 2 files changed, 2 insertions(+), 3 deletions(-)
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply
* Re: [PATCH 01/14] usb: ohci-nxp: enable compile-testing
From: Greg Kroah-Hartman @ 2019-08-01 5:58 UTC (permalink / raw)
To: Arnd Bergmann
Cc: soc, linux-arm-kernel, Vladimir Zapolskiy, Sylvain Lemieux,
Russell King, Gregory Clement, Linus Walleij, Alan Stern,
Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, David S. Miller,
Guenter Roeck, linux-gpio, netdev, linux-serial, linux-usb,
linux-watchdog, linux-kernel
In-Reply-To: <20190731195713.3150463-2-arnd@arndb.de>
On Wed, Jul 31, 2019 at 09:56:43PM +0200, Arnd Bergmann wrote:
> The driver hardcodes a hardware I/O address the way one should
> generally not do, and this prevents both compile-testing, and
> moving the platform to CONFIG_ARCH_MULTIPLATFORM.
>
> Change the code to be independent of the machine headers
> to allow those two. Removing the hardcoded address would
> be hard and is not necessary, so leave that in place for now.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/usb/host/Kconfig | 3 ++-
> drivers/usb/host/ohci-nxp.c | 25 ++++++++++++++++++-------
> 2 files changed, 20 insertions(+), 8 deletions(-)
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply
* Re: [PATCH 0/3] ARM: dts: aspeed: Deprecate g[45]-style compatibles
From: Andrew Jeffery @ 2019-08-01 5:45 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-aspeed, Lee Jones, Rob Herring, Mark Rutland, Joel Stanley,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux ARM, linux-kernel@vger.kernel.org, open list:GPIO SUBSYSTEM
In-Reply-To: <9d0f2b20-e6f6-419c-a866-c4a0dd92aa63@www.fastmail.com>
On Tue, 30 Jul 2019, at 10:27, Andrew Jeffery wrote:
>
>
> On Tue, 30 Jul 2019, at 07:23, Linus Walleij wrote:
> > On Wed, Jul 24, 2019 at 10:13 AM Andrew Jeffery <andrew@aj.id.au> wrote:
> >
> > > It's probably best if we push the three patches all through one tree rather
> > > than fragmenting. Is everyone happy if Joel applies them to the aspeed tree?
> >
> > If you are sure it will not collide with parallell work in the
> > pinctrl tree, yes.
> > Acked-by: Linus Walleij <linus.walleij@linaro.org>
> >
> > (If it does collide I'd prefer to take the pinctrl patches and fix the
> > conflicts in my tree.)
>
> Fair enough, I don't know the answer so I'll poke around. I don't
> really mind
> where the series goes in, I just want to avoid landing only part of it
> if I split it up.
Okay, it currently conflicts with my cleanup-devicetree-warnings series.
Joel, do you mind if Linus takes this series through the pinctrl tree, given
the fix to the devicetrees is patch 1/3?
Andrew
^ permalink raw reply
* Re: [PATCH v7 11/20] cpufreq: tegra124: Add suspend and resume support
From: Viresh Kumar @ 2019-08-01 5:40 UTC (permalink / raw)
To: Sowjanya Komatineni
Cc: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland, pdeschrijver, pgaikwad,
sboyd, linux-clk, linux-gpio, jckuo, josephl, talho, linux-tegra,
linux-kernel, mperttunen, spatra, robh+dt, digetx, devicetree,
rjw, linux-pm
In-Reply-To: <1564607463-28802-12-git-send-email-skomatineni@nvidia.com>
On 31-07-19, 14:10, Sowjanya Komatineni wrote:
> 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(+)
Is there any hard dependency of this patch on the rest of the patches?
Can I apply it alone to cpufreq tree ?
--
viresh
^ permalink raw reply
* Re: [v7 2/2] gpio: aspeed: Add SGPIO driver
From: Andrew Jeffery @ 2019-08-01 2:59 UTC (permalink / raw)
To: Hongwei Zhang, Linus Walleij, linux-gpio
Cc: Joel Stanley, linux-aspeed, Bartosz Golaszewski, linux-kernel,
linux-arm-kernel
In-Reply-To: <1564603297-1391-3-git-send-email-hongweiz@ami.com>
On Thu, 1 Aug 2019, at 05:32, Hongwei Zhang wrote:
> Add SGPIO driver support for Aspeed AST2500 SoC.
>
> Signed-off-by: Hongwei Zhang <hongweiz@ami.com>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Adding my Reviewed-by tag is a bit keen, I only gave it for the bindings on v6.
However, having looked over the patch you've addressed all of the issues I've
found, so you can keep it.
Andrew
> ---
> drivers/gpio/sgpio-aspeed.c | 530 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 530 insertions(+)
> create mode 100644 drivers/gpio/sgpio-aspeed.c
>
> diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
> new file mode 100644
> index 0000000..752efea
> --- /dev/null
> +++ b/drivers/gpio/sgpio-aspeed.c
> @@ -0,0 +1,530 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright 2019 American Megatrends International LLC.
> + *
> + * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/hashtable.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/string.h>
> +
> +#define MAX_NR_SGPIO 80
> +
> +#define ASPEED_SGPIO_CTRL 0x54
> +
> +#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
> +#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
> +#define ASPEED_SGPIO_ENABLE BIT(0)
> +
> +struct aspeed_sgpio {
> + struct gpio_chip chip;
> + struct clk *pclk;
> + spinlock_t lock;
> + void __iomem *base;
> + uint32_t dir_in[3];
> + int irq;
> +};
> +
> +struct aspeed_sgpio_bank {
> + uint16_t val_regs;
> + uint16_t rdata_reg;
> + uint16_t irq_regs;
> + const char names[4][3];
> +};
> +
> +/*
> + * Note: The "value" register returns the input value when the GPIO is
> + * configured as an input.
> + *
> + * The "rdata" register returns the output value when the GPIO is
> + * configured as an output.
> + */
> +static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
> + {
> + .val_regs = 0x0000,
> + .rdata_reg = 0x0070,
> + .irq_regs = 0x0004,
> + .names = { "A", "B", "C", "D" },
> + },
> + {
> + .val_regs = 0x001C,
> + .rdata_reg = 0x0074,
> + .irq_regs = 0x0020,
> + .names = { "E", "F", "G", "H" },
> + },
> + {
> + .val_regs = 0x0038,
> + .rdata_reg = 0x0078,
> + .irq_regs = 0x003C,
> + .names = { "I", "J" },
> + },
> +};
> +
> +enum aspeed_sgpio_reg {
> + reg_val,
> + reg_rdata,
> + reg_irq_enable,
> + reg_irq_type0,
> + reg_irq_type1,
> + reg_irq_type2,
> + reg_irq_status,
> +};
> +
> +#define GPIO_VAL_VALUE 0x00
> +#define GPIO_IRQ_ENABLE 0x00
> +#define GPIO_IRQ_TYPE0 0x04
> +#define GPIO_IRQ_TYPE1 0x08
> +#define GPIO_IRQ_TYPE2 0x0C
> +#define GPIO_IRQ_STATUS 0x10
> +
> +static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
> + const struct aspeed_sgpio_bank *bank,
> + const enum aspeed_sgpio_reg reg)
> +{
> + switch (reg) {
> + case reg_val:
> + return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
> + case reg_rdata:
> + return gpio->base + bank->rdata_reg;
> + case reg_irq_enable:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
> + case reg_irq_type0:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
> + case reg_irq_type1:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
> + case reg_irq_type2:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
> + case reg_irq_status:
> + return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
> + default:
> + /* acturally if code runs to here, it's an error case */
> + BUG_ON(1);
> + }
> +}
> +
> +#define GPIO_BANK(x) ((x) >> 5)
> +#define GPIO_OFFSET(x) ((x) & 0x1f)
> +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
> +
> +static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
> +{
> + unsigned int bank = GPIO_BANK(offset);
> +
> + WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
> + return &aspeed_sgpio_banks[bank];
> +}
> +
> +static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + const struct aspeed_sgpio_bank *bank = to_bank(offset);
> + unsigned long flags;
> + enum aspeed_sgpio_reg reg;
> + bool is_input;
> + int rc = 0;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
> + reg = is_input ? reg_val : reg_rdata;
> + rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + return rc;
> +}
> +
> +static void __aspeed_sgpio_set(struct gpio_chip *gc, unsigned int
> offset, int val)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + const struct aspeed_sgpio_bank *bank = to_bank(offset);
> + void __iomem *addr;
> + u32 reg = 0;
> +
> + addr = bank_reg(gpio, bank, reg_val);
> + reg = ioread32(addr);
> +
> + if (val)
> + reg |= GPIO_BIT(offset);
> + else
> + reg &= ~GPIO_BIT(offset);
> +
> + iowrite32(reg, addr);
> +}
> +
> +static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int
> offset, int val)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + __aspeed_sgpio_set(gc, offset, val);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +}
> +
> +static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int
> offset)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> + gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + return 0;
> +}
> +
> +static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int
> offset, int val)
> +{
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
> + __aspeed_sgpio_set(gc, offset, val);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + return 0;
> +}
> +
> +static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned
> int offset)
> +{
> + int dir_status;
> + struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> + dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + return dir_status;
> +
> +}
> +
> +static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
> + struct aspeed_sgpio **gpio,
> + const struct aspeed_sgpio_bank **bank,
> + u32 *bit, int *offset)
> +{
> + struct aspeed_sgpio *internal;
> +
> + *offset = irqd_to_hwirq(d);
> + internal = irq_data_get_irq_chip_data(d);
> + WARN_ON(!internal);
> +
> + *gpio = internal;
> + *bank = to_bank(*offset);
> + *bit = GPIO_BIT(*offset);
> +}
> +
> +static void aspeed_sgpio_irq_ack(struct irq_data *d)
> +{
> + const struct aspeed_sgpio_bank *bank;
> + struct aspeed_sgpio *gpio;
> + unsigned long flags;
> + void __iomem *status_addr;
> + int offset;
> + u32 bit;
> +
> + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
> +
> + status_addr = bank_reg(gpio, bank, reg_irq_status);
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + iowrite32(bit, status_addr);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +}
> +
> +static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
> +{
> + const struct aspeed_sgpio_bank *bank;
> + struct aspeed_sgpio *gpio;
> + unsigned long flags;
> + u32 reg, bit;
> + void __iomem *addr;
> + int offset;
> +
> + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
> + addr = bank_reg(gpio, bank, reg_irq_enable);
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + reg = ioread32(addr);
> + if (set)
> + reg |= bit;
> + else
> + reg &= ~bit;
> +
> + iowrite32(reg, addr);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +}
> +
> +static void aspeed_sgpio_irq_mask(struct irq_data *d)
> +{
> + aspeed_sgpio_irq_set_mask(d, false);
> +}
> +
> +static void aspeed_sgpio_irq_unmask(struct irq_data *d)
> +{
> + aspeed_sgpio_irq_set_mask(d, true);
> +}
> +
> +static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
> +{
> + u32 type0 = 0;
> + u32 type1 = 0;
> + u32 type2 = 0;
> + u32 bit, reg;
> + const struct aspeed_sgpio_bank *bank;
> + irq_flow_handler_t handler;
> + struct aspeed_sgpio *gpio;
> + unsigned long flags;
> + void __iomem *addr;
> + int offset;
> +
> + irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
> +
> + switch (type & IRQ_TYPE_SENSE_MASK) {
> + case IRQ_TYPE_EDGE_BOTH:
> + type2 |= bit;
> + /* fall through */
> + case IRQ_TYPE_EDGE_RISING:
> + type0 |= bit;
> + /* fall through */
> + case IRQ_TYPE_EDGE_FALLING:
> + handler = handle_edge_irq;
> + break;
> + case IRQ_TYPE_LEVEL_HIGH:
> + type0 |= bit;
> + /* fall through */
> + case IRQ_TYPE_LEVEL_LOW:
> + type1 |= bit;
> + handler = handle_level_irq;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + spin_lock_irqsave(&gpio->lock, flags);
> +
> + addr = bank_reg(gpio, bank, reg_irq_type0);
> + reg = ioread32(addr);
> + reg = (reg & ~bit) | type0;
> + iowrite32(reg, addr);
> +
> + addr = bank_reg(gpio, bank, reg_irq_type1);
> + reg = ioread32(addr);
> + reg = (reg & ~bit) | type1;
> + iowrite32(reg, addr);
> +
> + addr = bank_reg(gpio, bank, reg_irq_type2);
> + reg = ioread32(addr);
> + reg = (reg & ~bit) | type2;
> + iowrite32(reg, addr);
> +
> + spin_unlock_irqrestore(&gpio->lock, flags);
> +
> + irq_set_handler_locked(d, handler);
> +
> + return 0;
> +}
> +
> +static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
> +{
> + struct gpio_chip *gc = irq_desc_get_handler_data(desc);
> + struct irq_chip *ic = irq_desc_get_chip(desc);
> + struct aspeed_sgpio *data = gpiochip_get_data(gc);
> + unsigned int i, p, girq;
> + unsigned long reg;
> +
> + chained_irq_enter(ic, desc);
> +
> + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
> + const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
> +
> + reg = ioread32(bank_reg(data, bank, reg_irq_status));
> +
> + for_each_set_bit(p, ®, 32) {
> + girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
> + generic_handle_irq(girq);
> + }
> +
> + }
> +
> + chained_irq_exit(ic, desc);
> +}
> +
> +static struct irq_chip aspeed_sgpio_irqchip = {
> + .name = "aspeed-sgpio",
> + .irq_ack = aspeed_sgpio_irq_ack,
> + .irq_mask = aspeed_sgpio_irq_mask,
> + .irq_unmask = aspeed_sgpio_irq_unmask,
> + .irq_set_type = aspeed_sgpio_set_type,
> +};
> +
> +static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
> + struct platform_device *pdev)
> +{
> + int rc, i;
> + const struct aspeed_sgpio_bank *bank;
> +
> + rc = platform_get_irq(pdev, 0);
> + if (rc < 0)
> + return rc;
> +
> + gpio->irq = rc;
> +
> + /* Disable IRQ and clear Interrupt status registers for all SPGIO
> Pins. */
> + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
> + bank = &aspeed_sgpio_banks[i];
> + /* disable irq enable bits */
> + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
> + /* clear status bits */
> + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
> + }
> +
> + rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_sgpio_irqchip,
> + 0, handle_bad_irq, IRQ_TYPE_NONE);
> + if (rc) {
> + dev_info(&pdev->dev, "Could not add irqchip\n");
> + return rc;
> + }
> +
> + gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_sgpio_irqchip,
> + gpio->irq, aspeed_sgpio_irq_handler);
> +
> + /* set IRQ settings and Enable Interrupt */
> + for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
> + bank = &aspeed_sgpio_banks[i];
> + /* set falling or level-low irq */
> + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
> + /* trigger type is edge */
> + iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
> + /* dual edge trigger mode. */
> + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
> + /* enable irq */
> + iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
> + }
> +
> + return 0;
> +}
> +
> +static const struct of_device_id aspeed_sgpio_of_table[] = {
> + { .compatible = "aspeed,ast2400-sgpio" },
> + { .compatible = "aspeed,ast2500-sgpio" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
> +
> +static int __init aspeed_sgpio_probe(struct platform_device *pdev)
> +{
> + struct aspeed_sgpio *gpio;
> + u32 nr_gpios, sgpio_freq, sgpio_clk_div;
> + int rc;
> + unsigned long apb_freq;
> +
> + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
> + if (!gpio)
> + return -ENOMEM;
> +
> + gpio->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(gpio->base))
> + return PTR_ERR(gpio->base);
> +
> + rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
> + if (rc < 0) {
> + dev_err(&pdev->dev, "Could not read ngpios property\n");
> + return -EINVAL;
> + } else if (nr_gpios > MAX_NR_SGPIO) {
> + dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d:
> %d\n",
> + MAX_NR_SGPIO, nr_gpios);
> + return -EINVAL;
> + }
> +
> + rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency",
> &sgpio_freq);
> + if (rc < 0) {
> + dev_err(&pdev->dev, "Could not read bus-frequency property\n");
> + return -EINVAL;
> + }
> +
> + gpio->pclk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(gpio->pclk)) {
> + dev_err(&pdev->dev, "devm_clk_get failed\n");
> + return PTR_ERR(gpio->pclk);
> + }
> +
> + apb_freq = clk_get_rate(gpio->pclk);
> +
> + /*
> + * From the datasheet,
> + * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
> + * period = 2 * (GPIO254[31:16] + 1) / PCLK
> + * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
> + * frequency = PCLK / (2 * (GPIO254[31:16] + 1))
> + * frequency * 2 * (GPIO254[31:16] + 1) = PCLK
> + * GPIO254[31:16] = PCLK / (frequency * 2) - 1
> + */
> + if (sgpio_freq == 0)
> + return -EINVAL;
> +
> + sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
> +
> + if (sgpio_clk_div > (1 << 16) - 1)
> + return -EINVAL;
> +
> + iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
> + FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
> + ASPEED_SGPIO_ENABLE,
> + gpio->base + ASPEED_SGPIO_CTRL);
> +
> + spin_lock_init(&gpio->lock);
> +
> + gpio->chip.parent = &pdev->dev;
> + gpio->chip.ngpio = nr_gpios;
> + gpio->chip.direction_input = aspeed_sgpio_dir_in;
> + gpio->chip.direction_output = aspeed_sgpio_dir_out;
> + gpio->chip.get_direction = aspeed_sgpio_get_direction;
> + gpio->chip.request = NULL;
> + gpio->chip.free = NULL;
> + gpio->chip.get = aspeed_sgpio_get;
> + gpio->chip.set = aspeed_sgpio_set;
> + gpio->chip.set_config = NULL;
> + gpio->chip.label = dev_name(&pdev->dev);
> + gpio->chip.base = -1;
> +
> + /* set all SGPIO pins as input (1). */
> + memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
> +
> + rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
> + if (rc < 0)
> + return rc;
> +
> + return aspeed_sgpio_setup_irqs(gpio, pdev);
> +}
> +
> +static struct platform_driver aspeed_sgpio_driver = {
> + .driver = {
> + .name = KBUILD_MODNAME,
> + .of_match_table = aspeed_sgpio_of_table,
> + },
> +};
> +
> +module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
> +MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
> +MODULE_LICENSE("GPL");
> --
> 2.7.4
>
>
^ permalink raw reply
* linusw/devel boot: 43 boots: 1 failed, 42 passed (v5.3-rc1-9-g8825e356f52f)
From: kernelci.org bot @ 2019-08-01 0:08 UTC (permalink / raw)
To: linux-gpio, fellows
linusw/devel boot: 43 boots: 1 failed, 42 passed (v5.3-rc1-9-g8825e356f52f)
Full Boot Summary: https://kernelci.org/boot/all/job/linusw/branch/devel/kernel/v5.3-rc1-9-g8825e356f52f/
Full Build Summary: https://kernelci.org/build/linusw/branch/devel/kernel/v5.3-rc1-9-g8825e356f52f/
Tree: linusw
Branch: devel
Git Describe: v5.3-rc1-9-g8825e356f52f
Git Commit: 8825e356f52f3af8b86e916e650a091a21fe25b5
Git URL: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git/
Tested: 29 unique boards, 15 SoC families, 3 builds out of 6
Boot Regressions Detected:
arm64:
defconfig:
gcc-8:
apq8016-sbc:
lab-mhart: failing since 1 day (last pass: v5.2-10808-g9637d517347e - first fail: v5.3-rc1-5-ga299726da44f)
Boot Failure Detected:
arm64:
defconfig:
gcc-8:
apq8016-sbc: 1 failed lab
---
For more info write to <info@kernelci.org>
^ permalink raw reply
* linusw/for-next boot: 44 boots: 1 failed, 43 passed (v5.3-rc1-14-gc058275cfa13)
From: kernelci.org bot @ 2019-08-01 0:08 UTC (permalink / raw)
To: linux-gpio, fellows
linusw/for-next boot: 44 boots: 1 failed, 43 passed (v5.3-rc1-14-gc058275cfa13)
Full Boot Summary: https://kernelci.org/boot/all/job/linusw/branch/for-next/kernel/v5.3-rc1-14-gc058275cfa13/
Full Build Summary: https://kernelci.org/build/linusw/branch/for-next/kernel/v5.3-rc1-14-gc058275cfa13/
Tree: linusw
Branch: for-next
Git Describe: v5.3-rc1-14-gc058275cfa13
Git Commit: c058275cfa138773636fb944dad64fa799d6d493
Git URL: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git/
Tested: 30 unique boards, 15 SoC families, 3 builds out of 6
Boot Regressions Detected:
arm64:
defconfig:
gcc-8:
apq8016-sbc:
lab-mhart: failing since 1 day (last pass: v5.2-10813-g88785b7fa74a - first fail: v5.3-rc1-10-gd2a561ae1961)
Boot Failure Detected:
arm64:
defconfig:
gcc-8:
apq8016-sbc: 1 failed lab
---
For more info write to <info@kernelci.org>
^ permalink raw reply
* linusw/devel build: 6 builds: 0 failed, 6 passed, 13 warnings (v5.3-rc1-9-g8825e356f52f)
From: kernelci.org bot @ 2019-07-31 23:24 UTC (permalink / raw)
To: linux-gpio, fellows
linusw/devel build: 6 builds: 0 failed, 6 passed, 13 warnings (v5.3-rc1-9-g8825e356f52f)
Full Build Summary: https://kernelci.org/build/linusw/branch/devel/kernel/v5.3-rc1-9-g8825e356f52f/
Tree: linusw
Branch: devel
Git Describe: v5.3-rc1-9-g8825e356f52f
Git Commit: 8825e356f52f3af8b86e916e650a091a21fe25b5
Git URL: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git/
Built: 6 unique architectures
Warnings Detected:
arc:
nsim_hs_defconfig (gcc-8): 2 warnings
arm64:
arm:
multi_v7_defconfig (gcc-8): 6 warnings
mips:
32r2el_defconfig (gcc-8): 3 warnings
riscv:
defconfig (gcc-8): 2 warnings
x86_64:
Warnings summary:
7 <stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dts:129.4-18: Warning (reg_format): /mdio-bus-mux/mdio@200:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #size-cells value
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #address-cells value
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
================================================================================
Detailed per-defconfig build reports:
--------------------------------------------------------------------------------
32r2el_defconfig (mips, gcc-8) — PASS, 0 errors, 3 warnings, 0 section mismatches
Warnings:
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
--------------------------------------------------------------------------------
defconfig (riscv, gcc-8) — PASS, 0 errors, 2 warnings, 0 section mismatches
Warnings:
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
--------------------------------------------------------------------------------
defconfig (arm64, gcc-8) — PASS, 0 errors, 0 warnings, 0 section mismatches
--------------------------------------------------------------------------------
multi_v7_defconfig (arm, gcc-8) — PASS, 0 errors, 6 warnings, 0 section mismatches
Warnings:
arch/arm/boot/dts/bcm47094-linksys-panamera.dts:129.4-18: Warning (reg_format): /mdio-bus-mux/mdio@200:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #address-cells value
arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #size-cells value
--------------------------------------------------------------------------------
nsim_hs_defconfig (arc, gcc-8) — PASS, 0 errors, 2 warnings, 0 section mismatches
Warnings:
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
--------------------------------------------------------------------------------
x86_64_defconfig (x86_64, gcc-8) — PASS, 0 errors, 0 warnings, 0 section mismatches
---
For more info write to <info@kernelci.org>
^ permalink raw reply
* linusw/for-next build: 6 builds: 0 failed, 6 passed, 13 warnings (v5.3-rc1-14-gc058275cfa13)
From: kernelci.org bot @ 2019-07-31 23:23 UTC (permalink / raw)
To: linux-gpio, fellows
linusw/for-next build: 6 builds: 0 failed, 6 passed, 13 warnings (v5.3-rc1-14-gc058275cfa13)
Full Build Summary: https://kernelci.org/build/linusw/branch/for-next/kernel/v5.3-rc1-14-gc058275cfa13/
Tree: linusw
Branch: for-next
Git Describe: v5.3-rc1-14-gc058275cfa13
Git Commit: c058275cfa138773636fb944dad64fa799d6d493
Git URL: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git/
Built: 6 unique architectures
Warnings Detected:
arc:
nsim_hs_defconfig (gcc-8): 2 warnings
arm64:
arm:
multi_v7_defconfig (gcc-8): 6 warnings
mips:
32r2el_defconfig (gcc-8): 3 warnings
riscv:
defconfig (gcc-8): 2 warnings
x86_64:
Warnings summary:
7 <stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dts:129.4-18: Warning (reg_format): /mdio-bus-mux/mdio@200:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #size-cells value
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #address-cells value
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
1 arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
================================================================================
Detailed per-defconfig build reports:
--------------------------------------------------------------------------------
32r2el_defconfig (mips, gcc-8) — PASS, 0 errors, 3 warnings, 0 section mismatches
Warnings:
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
--------------------------------------------------------------------------------
defconfig (riscv, gcc-8) — PASS, 0 errors, 2 warnings, 0 section mismatches
Warnings:
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
--------------------------------------------------------------------------------
defconfig (arm64, gcc-8) — PASS, 0 errors, 0 warnings, 0 section mismatches
--------------------------------------------------------------------------------
multi_v7_defconfig (arm, gcc-8) — PASS, 0 errors, 6 warnings, 0 section mismatches
Warnings:
arch/arm/boot/dts/bcm47094-linksys-panamera.dts:129.4-18: Warning (reg_format): /mdio-bus-mux/mdio@200:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
arch/arm/boot/dts/bcm47094-linksys-panamera.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #address-cells value
arch/arm/boot/dts/bcm47094-linksys-panamera.dts:128.22-132.5: Warning (avoid_default_addr_size): /mdio-bus-mux/mdio@200: Relying on default #size-cells value
--------------------------------------------------------------------------------
nsim_hs_defconfig (arc, gcc-8) — PASS, 0 errors, 2 warnings, 0 section mismatches
Warnings:
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
<stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp]
--------------------------------------------------------------------------------
x86_64_defconfig (x86_64, gcc-8) — PASS, 0 errors, 0 warnings, 0 section mismatches
---
For more info write to <info@kernelci.org>
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: ls1088a: Revise gpio registers to little-endian
From: Li Yang @ 2019-07-31 23:19 UTC (permalink / raw)
To: Chuanhua Han
Cc: Shawn Guo, Rob Herring, Mark Rutland, Linus Walleij,
Bartosz Golaszewski,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, lkml,
linux-gpio
In-Reply-To: <20190529083254.39581-3-chuanhua.han@nxp.com>
On Wed, May 29, 2019 at 3:32 AM Chuanhua Han <chuanhua.han@nxp.com> wrote:
>
> Since fsl-ls1088a Soc GPIO registers are used as little endian,
> the patch adds the little-endian attribute to each gpio node.
>
> Signed-off-by: Chuanhua Han <chuanhua.han@nxp.com>
Acked-by: Li Yang <leoyang.li@nxp.com>
> ---
> arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
> index 661137ffa319..3e6d20d065bd 100644
> --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi
> @@ -272,6 +272,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2300000 0x0 0x10000>;
> interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -282,6 +283,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2310000 0x0 0x10000>;
> interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -292,6 +294,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2320000 0x0 0x10000>;
> interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> @@ -302,6 +305,7 @@
> compatible = "fsl,qoriq-gpio";
> reg = <0x0 0x2330000 0x0 0x10000>;
> interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>;
> + little-endian;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> --
> 2.17.1
>
^ permalink raw reply
* Re: [PATCH 1/2] arm64: dts: ls1028a: Fix GPIO work fail.
From: Li Yang @ 2019-07-31 23:17 UTC (permalink / raw)
To: Hui Song
Cc: Shawn Guo, Rob Herring, Mark Rutland, Linus Walleij,
Bartosz Golaszewski,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, lkml,
linux-gpio
In-Reply-To: <20190718094902.15562-1-hui.song_1@nxp.com>
On Thu, Jul 18, 2019 at 4:59 AM Hui Song <hui.song_1@nxp.com> wrote:
>
Change the title to be something like:
arm64: dts: ls1028a: fix gpio nodes
> From: Song Hui <hui.song_1@nxp.com>
>
> Add ls1028a device specify compatible.
Please submit a separate patch to update the device tree binding too.
> Make gpio as little-endian deal.
"Update the nodes to include little-endian property to be consistent
with the hardware."
>
> Signed-off-by: Song Hui <hui.song_1@nxp.com>
> ---
> arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 9 ++++++---
> 1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
> index 7975519..488602b 100644
> --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
> +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
> @@ -277,33 +277,36 @@
> };
>
> gpio1: gpio@2300000 {
> - compatible = "fsl,qoriq-gpio";
> + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio";
> reg = <0x0 0x2300000 0x0 0x10000>;
> interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> #interrupt-cells = <2>;
> + little-endian;
> };
>
> gpio2: gpio@2310000 {
> - compatible = "fsl,qoriq-gpio";
> + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio";
> reg = <0x0 0x2310000 0x0 0x10000>;
> interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> #interrupt-cells = <2>;
> + little-endian;
> };
>
> gpio3: gpio@2320000 {
> - compatible = "fsl,qoriq-gpio";
> + compatible = "fsl,ls1028a-gpio","fsl,qoriq-gpio";
> reg = <0x0 0x2320000 0x0 0x10000>;
> interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> gpio-controller;
> #gpio-cells = <2>;
> interrupt-controller;
> #interrupt-cells = <2>;
> + little-endian;
> };
>
> usb0: usb@3100000 {
> --
> 2.9.5
>
^ permalink raw reply
* Re: [PATCH v7 07/20] clk: tegra: clk-periph: Add save and restore support
From: Sowjanya Komatineni @ 2019-07-31 23:09 UTC (permalink / raw)
To: Dmitry Osipenko, 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: <e796e26e-830c-b1be-e368-c7ff177a61dd@gmail.com>
On 7/31/19 3:44 AM, Dmitry Osipenko wrote:
> 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.
clk_periph_get_parent basically invokes existing clk_mux_ops
get_parent() which is then saved in tegra_clk_periph.
All existing drivers are using directly get_parent() from clk_mux which
actually gets index from the register read.
To have this more generic w.r.t save/restore context point of view,
probably instead of implementing new get_parent_index helper, I think
its better to implement save_context and restore_context to clk_mux_ops
along with creating parent_index field into clk_mux to cache index
during set_parent.
So we just need to invoke mux_ops save_context and restore_context.
^ permalink raw reply
* Re: [PATCH 00/14] ARM: move lpc32xx and dove to multiplatform
From: Russell King - ARM Linux admin @ 2019-07-31 22:53 UTC (permalink / raw)
To: Arnd Bergmann
Cc: soc, linux-arm-kernel, Vladimir Zapolskiy, Sylvain Lemieux,
Gregory Clement, Linus Walleij, Jason Cooper, Andrew Lunn,
Sebastian Hesselbarth, David S. Miller, Greg Kroah-Hartman,
Alan Stern, Guenter Roeck, linux-gpio, netdev, linux-serial,
linux-usb, linux-watchdog
In-Reply-To: <20190731195713.3150463-1-arnd@arndb.de>
On Wed, Jul 31, 2019 at 09:56:42PM +0200, Arnd Bergmann wrote:
> For dove, the patches are basically what I had proposed back in
> 2015 when all other ARMv6/ARMv7 machines became part of a single
> kernel build. I don't know what the state is mach-dove support is,
> compared to the DT based support in mach-mvebu for the same
> hardware. If they are functionally the same, we could also just
> remove mach-dove rather than applying my patches.
Well, the good news is that I'm down to a small board support file
for the Dove Cubox now - but the bad news is, that there's still a
board support file necessary to support everything the Dove SoC has
to offer.
Even for a DT based Dove Cubox, I'm still using mach-dove, but it
may be possible to drop most of mach-dove now. Without spending a
lot of time digging through it, it's impossible to really know.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
^ permalink raw reply
* Re: [PATCH] gpio: of: Fix hard-assigned valid_mask for OF case
From: Stephen Boyd @ 2019-07-31 22:51 UTC (permalink / raw)
To: Linus Walleij, linux-gpio
Cc: Bartosz Golaszewski, Mark Brown, Bjorn Andersson, Linus Walleij
In-Reply-To: <20190731224208.30429-1-linus.walleij@linaro.org>
Quoting Linus Walleij (2019-07-31 15:42:08)
> From: Stephen Boyd <swboyd@chromium.org>
>
> The recent refactoring to break out OF code to its own file
> contained a bug by yours truly letting the need_valid_mask
I'm not yours truly :)
> be overridden by the need of the device tree range check,
> and if there were no ranges, but device tree was active
> and the reserved GPIO used in another way, things likely
> crash.
>
> Cc: Mark Brown <broonie@kernel.org>
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
> Cc: Stephen Boyd <swboyd@chromium.org>
> Reported-by: Mark Brown <broonie@kernel.org>
> Suggested-by: Stephen Boyd <swboyd@chromium.org>
> Signed-off-by: Stephen Boyd <swboyd@chromium.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
Thanks for taking care of writing up the commit text for me.
^ permalink raw reply
* [PATCH] gpio: of: Fix hard-assigned valid_mask for OF case
From: Linus Walleij @ 2019-07-31 22:42 UTC (permalink / raw)
To: linux-gpio
Cc: Bartosz Golaszewski, Stephen Boyd, Mark Brown, Bjorn Andersson,
Linus Walleij
From: Stephen Boyd <swboyd@chromium.org>
The recent refactoring to break out OF code to its own file
contained a bug by yours truly letting the need_valid_mask
be overridden by the need of the device tree range check,
and if there were no ranges, but device tree was active
and the reserved GPIO used in another way, things likely
crash.
Cc: Mark Brown <broonie@kernel.org>
Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
Cc: Stephen Boyd <swboyd@chromium.org>
Reported-by: Mark Brown <broonie@kernel.org>
Suggested-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/gpio/gpiolib-of.c | 2 +-
drivers/gpio/gpiolib-of.h | 4 ++--
drivers/gpio/gpiolib.c | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index b10d04dd9296..e39b4290b80c 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -87,7 +87,7 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
* @dev: the device for the GPIO provider
* @return: true if the valid mask needs to be set
*/
-bool of_gpio_need_valid_mask(struct gpio_chip *gc)
+bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
{
int size;
struct device_node *np = gc->of_node;
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
index 34954921d96e..454d1658ee2d 100644
--- a/drivers/gpio/gpiolib-of.h
+++ b/drivers/gpio/gpiolib-of.h
@@ -16,7 +16,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
int of_gpiochip_add(struct gpio_chip *gc);
void of_gpiochip_remove(struct gpio_chip *gc);
int of_gpio_get_count(struct device *dev, const char *con_id);
-bool of_gpio_need_valid_mask(struct gpio_chip *gc);
+bool of_gpio_need_valid_mask(const struct gpio_chip *gc);
#else
static inline struct gpio_desc *of_find_gpio(struct device *dev,
const char *con_id,
@@ -36,7 +36,7 @@ static inline int of_gpio_get_count(struct device *dev, const char *con_id)
{
return 0;
}
-static inline bool of_gpio_need_valid_mask(struct gpio_chip *gc)
+static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
{
return false;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f83870a18ae7..20f13129cdaa 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -363,8 +363,8 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
{
- if (IS_ENABLED(CONFIG_OF_GPIO))
- gc->need_valid_mask = of_gpio_need_valid_mask(gc);
+ if (of_gpio_need_valid_mask(gc))
+ gc->need_valid_mask = true;
if (!gc->need_valid_mask)
return 0;
--
2.21.0
^ permalink raw reply related
* [PATCH v7 00/20] SC7 entry and exit support for Tegra210
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
This patch series includes Tegra210 deepsleep (SC7) support with RTC alarm
wake event.
This series also includes save and restore of PLLs, clocks, OSC contexts
for deepsleep exit to normal operation.
This patch series doesn't support 100% suspend/resume to allow fully
functional state upon resume and we are working on some more drivers suspend
and resume implementations.
[V7]: Changes between V6 & V7 are
- V6 feedback fixes
- Removed patch-0001 from V6 which keeps COP IRQ enabled. Looking
more into ATF FW, it loads SC7 entry FW into IRAM and sets the
COP reset vector to SC7 FW load address and resets COP. So, COP
IRQ can be cleared during suspend.
Note:
Below patch is also needed for SC7 support as GPIO restore need
to happen prior to pinctrl.
https://patchwork.kernel.org/patch/11012077/
[V6]: Changes between V5 & V6 are
- V5 feedback fixes
- DFLL suspend and resume moved to DFLL clock driver
- Add suspend and resume support for CPUFreq driver to explicitly
switch source to safe source of PLLP and disable DFLL clock.
- Fix to super clock driver to enable PLLP branch to CPU before
source switch to PLLP.
- Added save and restore support for super clock driver.
[V5]: Changes between V4 & V5 are
- V4 feedback fixes
[V4]: Changes between V3 & V4 are
- V3 feedback fixes
- Removed park bits clear for EMMC pads in pinctrl-tegra driver
function tegra_pinctrl_clear_parked_bits as based on V3 feedback
parked_bit is updated to parked_bitmask to use with DRV_PINGROUP
as well and thierry posted patch series for this.
- Implemented all peripheral clocks save and restore through their
corresponding clk_ops save_context and restore_context and removed
all direct registers store and restore in clk-tegra210 driver.
- Created separate patch for fence_delay update during PLLU init based
on V3 feedback.
- Added more comments in tegra210_clk_resume regarding dfll restore
sequence and its dependency on peripheral clocks restore.
[V3]: Changes between V2 & V3 are
- V2 feedback fixes
- GPIO restore should happen prior to Pinctrl restore to prevent
glitch on GPIO lines. So using resume_noirq for gpio tegra to allow
gpio resume prior to pinctrl resume.
- Implemented save_context and restore_context callbacks for clock
plls, pll outs and dividers in corresponding drivers.
Note: Peripheral clocks and clock enable and reset need to be in
Tegra210 clock suspend/resume as they need to be in proper sequence
w.r.t DFLL resume for restoring CPU clock.
- Removed gpio-tegra changes for hierarchical support to have PMC as
parent to GPIOs for GPIO wake event support. Thierry is working on
gpiolib for some cleanup before adding hierarchical support. So
holding on to GPIO wake support for now.
[V2] : V1 feedback fixes
Patch 0002: This version still using syscore. Thierry suggest not to
use syscore and waiting on suggestion from Linux Walleij for any better
way of storing current state of pins before suspend entry and restoring
them on resume at very early stage. So left this the same way as V1 and
will address once I get more feedback on this.
Also need to findout and implement proper way of forcing resume order
between pinctrl and gpio driver.
[V1]: Tegra210 SC7 entry and exit thru RTC wake and Power button GPIO wake
using hierarchical IRQ with PMC as parent to GPIO.
Sowjanya Komatineni (20):
pinctrl: tegra: Add suspend and resume support
pinctrl: tegra210: Add Tegra210 pinctrl pm ops
clk: tegra: divider: Save and restore divider rate
clk: tegra: pllout: Save and restore pllout context
clk: tegra: pll: Save and restore pll context
clk: tegra: Support for OSC context save and restore
clk: tegra: clk-periph: Add save and restore support
clk: tegra: clk-super: Fix to enable PLLP branches to CPU
clk: tegra: clk-super: Add save and restore support
clk: tegra: clk-dfll: Add suspend and resume support
cpufreq: tegra124: Add suspend and resume support
clk: tegra210: Use fence_udelay during PLLU init
clk: tegra210: Add suspend and resume support
soc/tegra: pmc: Allow to support more tegras wake
soc/tegra: pmc: Add pmc wake support for tegra210
arm64: tegra: Enable wake from deep sleep on RTC alarm
soc/tegra: pmc: Configure core power request polarity
soc/tegra: pmc: Configure deep sleep control settings
arm64: dts: tegra210-p2180: Jetson TX1 SC7 timings
arm64: dts: tegra210-p3450: Jetson Nano SC7 timings
arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi | 7 ++
arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 7 ++
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 5 +-
drivers/clk/tegra/clk-dfll.c | 56 +++++++++
drivers/clk/tegra/clk-dfll.h | 2 +
drivers/clk/tegra/clk-divider.c | 11 ++
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-pll-out.c | 26 +++++
drivers/clk/tegra/clk-pll.c | 112 +++++++++++++-----
drivers/clk/tegra/clk-sdmmc-mux.c | 28 +++++
drivers/clk/tegra/clk-super.c | 53 +++++++++
drivers/clk/tegra/clk-tegra-fixed.c | 15 +++
drivers/clk/tegra/clk-tegra-super-gen4.c | 2 +-
drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 1 +
drivers/clk/tegra/clk-tegra210.c | 86 ++++++++++++--
drivers/clk/tegra/clk.c | 14 +++
drivers/clk/tegra/clk.h | 26 +++++
drivers/cpufreq/tegra124-cpufreq.c | 60 ++++++++++
drivers/pinctrl/tegra/pinctrl-tegra.c | 59 ++++++++++
drivers/pinctrl/tegra/pinctrl-tegra.h | 3 +
drivers/pinctrl/tegra/pinctrl-tegra210.c | 1 +
drivers/soc/tegra/pmc.c | 129 ++++++++++++++++++++-
24 files changed, 759 insertions(+), 48 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH v7 03/20] clk: tegra: divider: Save and restore divider rate
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
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,
--
2.7.4
^ permalink raw reply related
* [PATCH v7 01/20] pinctrl: tegra: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
This patch adds support for Tegra pinctrl driver suspend and resume.
During suspend, context of all pinctrl registers are stored and
on resume they are all restored to have all the pinmux and pad
configuration for normal operation.
Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++++++++++++++
drivers/pinctrl/tegra/pinctrl-tegra.h | 3 ++
2 files changed, 62 insertions(+)
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 186ef98e7b2b..e3a237534281 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -631,6 +631,58 @@ static void tegra_pinctrl_clear_parked_bits(struct tegra_pmx *pmx)
}
}
+static size_t tegra_pinctrl_get_bank_size(struct device *dev,
+ unsigned int bank_id)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id);
+
+ return resource_size(res) / 4;
+}
+
+static int tegra_pinctrl_suspend(struct device *dev)
+{
+ struct tegra_pmx *pmx = dev_get_drvdata(dev);
+ u32 *backup_regs = pmx->backup_regs;
+ u32 *regs;
+ size_t bank_size;
+ unsigned int i, k;
+
+ for (i = 0; i < pmx->nbanks; i++) {
+ bank_size = tegra_pinctrl_get_bank_size(dev, i);
+ regs = pmx->regs[i];
+ for (k = 0; k < bank_size; k++)
+ *backup_regs++ = readl_relaxed(regs++);
+ }
+
+ return pinctrl_force_sleep(pmx->pctl);
+}
+
+static int tegra_pinctrl_resume(struct device *dev)
+{
+ struct tegra_pmx *pmx = dev_get_drvdata(dev);
+ u32 *backup_regs = pmx->backup_regs;
+ u32 *regs;
+ size_t bank_size;
+ unsigned int i, k;
+
+ for (i = 0; i < pmx->nbanks; i++) {
+ bank_size = tegra_pinctrl_get_bank_size(dev, i);
+ regs = pmx->regs[i];
+ for (k = 0; k < bank_size; k++)
+ writel_relaxed(*backup_regs++, regs++);
+ }
+
+ return 0;
+}
+
+const struct dev_pm_ops tegra_pinctrl_pm = {
+ .suspend = &tegra_pinctrl_suspend,
+ .resume = &tegra_pinctrl_resume
+};
+
static bool gpio_node_has_range(const char *compatible)
{
struct device_node *np;
@@ -655,6 +707,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
int i;
const char **group_pins;
int fn, gn, gfn;
+ unsigned long backup_regs_size = 0;
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx)
@@ -707,6 +760,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res)
break;
+ backup_regs_size += resource_size(res);
}
pmx->nbanks = i;
@@ -715,6 +769,11 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
if (!pmx->regs)
return -ENOMEM;
+ pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size,
+ GFP_KERNEL);
+ if (!pmx->backup_regs)
+ return -ENOMEM;
+
for (i = 0; i < pmx->nbanks; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index 105309774079..0fc82eea9cf1 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
@@ -17,6 +17,7 @@ struct tegra_pmx {
int nbanks;
void __iomem **regs;
+ u32 *backup_regs;
};
enum tegra_pinconf_param {
@@ -193,6 +194,8 @@ struct tegra_pinctrl_soc_data {
bool drvtype_in_mux;
};
+extern const struct dev_pm_ops tegra_pinctrl_pm;
+
int tegra_pinctrl_probe(struct platform_device *pdev,
const struct tegra_pinctrl_soc_data *soc_data);
#endif
--
2.7.4
^ permalink raw reply related
* [PATCH v7 08/20] clk: tegra: clk-super: Fix to enable PLLP branches to CPU
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
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);
} 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 */
--
2.7.4
^ permalink raw reply related
* [PATCH v7 05/20] clk: tegra: pll: Save and restore pll context
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
This patch implements save and restore of PLL context.
During system suspend, core power goes off and looses the settings
of the Tegra CAR controller registers.
So during suspend entry pll context is stored and on resume it is
restored back along with its state.
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-pll.c | 112 +++++++++++++++++++++++++++++++-------------
drivers/clk/tegra/clk.h | 4 ++
2 files changed, 84 insertions(+), 32 deletions(-)
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 1583f5fc992f..344605135a70 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -1008,6 +1008,50 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
return rate;
}
+static int tegra_clk_pll_save_context(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val = 0;
+
+ if (pll->params->flags & TEGRA_PLLMB)
+ val = pll_readl_base(pll);
+ else if (pll->params->flags & TEGRA_PLLRE)
+ val = pll_readl_base(pll) & divp_mask_shifted(pll);
+
+ pll->pllbase_ctx = val;
+ return 0;
+}
+
+static void tegra_clk_pll_restore_context(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(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);
+ u32 val;
+
+ if (clk_pll_is_enabled(hw))
+ return;
+
+ if (pll->params->flags & TEGRA_PLLMB) {
+ pll_writel_base(pll->pllbase_ctx, pll);
+ } else if (pll->params->flags & TEGRA_PLLRE) {
+ val = pll_readl_base(pll);
+ val &= ~(divp_mask_shifted(pll));
+ pll_writel_base(pll->pllbase_ctx | val, pll);
+ }
+
+ if (pll->params->set_defaults)
+ pll->params->set_defaults(pll);
+
+ clk_pll_set_rate(hw, rate, parent_rate);
+
+ if (!__clk_get_enable_count(hw->clk))
+ clk_pll_disable(hw);
+ else
+ clk_pll_enable(hw);
+}
+
const struct clk_ops tegra_clk_pll_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_enable,
@@ -1015,6 +1059,8 @@ const struct clk_ops tegra_clk_pll_ops = {
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_round_rate,
.set_rate = clk_pll_set_rate,
+ .save_context = tegra_clk_pll_save_context,
+ .restore_context = tegra_clk_pll_restore_context,
};
const struct clk_ops tegra_clk_plle_ops = {
@@ -1802,6 +1848,27 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
return ret;
}
+
+static void _clk_plle_tegra_init_parent(struct tegra_clk_pll *pll)
+{
+ u32 val, val_aux;
+
+ /* ensure parent is set to pll_ref */
+ val = pll_readl_base(pll);
+ val_aux = pll_readl(pll->params->aux_reg, pll);
+
+ if (val & PLL_BASE_ENABLE) {
+ if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
+ (val_aux & PLLE_AUX_PLLP_SEL))
+ WARN(1, "pll_e enabled with unsupported parent %s\n",
+ (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
+ "pll_re_vco");
+ } else {
+ val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
+ pll_writel(val_aux, pll->params->aux_reg, pll);
+ fence_udelay(1, pll->clk_base);
+ }
+}
#endif
static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
@@ -2214,27 +2281,12 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
{
struct tegra_clk_pll *pll;
struct clk *clk;
- u32 val, val_aux;
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
- /* ensure parent is set to pll_re_vco */
-
- val = pll_readl_base(pll);
- val_aux = pll_readl(pll_params->aux_reg, pll);
-
- if (val & PLL_BASE_ENABLE) {
- if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
- (val_aux & PLLE_AUX_PLLP_SEL))
- WARN(1, "pll_e enabled with unsupported parent %s\n",
- (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
- "pll_re_vco");
- } else {
- val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
- pll_writel(val_aux, pll_params->aux_reg, pll);
- }
+ _clk_plle_tegra_init_parent(pll);
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
&tegra_clk_plle_tegra114_ops);
@@ -2276,6 +2328,8 @@ static const struct clk_ops tegra_clk_pllss_ops = {
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_ramp_round_rate,
.set_rate = clk_pllxc_set_rate,
+ .save_context = tegra_clk_pll_save_context,
+ .restore_context = tegra_clk_pll_restore_context,
};
struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
@@ -2375,6 +2429,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name,
pll_params->vco_min = pll_params->adjust_vco(pll_params,
parent_rate);
+ pll_params->flags |= TEGRA_PLLRE;
pll = _tegra_init_pll(clk_base, pmc, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
@@ -2520,11 +2575,19 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw)
spin_unlock_irqrestore(pll->lock, flags);
}
+static void tegra_clk_plle_t210_restore_context(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+ _clk_plle_tegra_init_parent(pll);
+}
+
static const struct clk_ops tegra_clk_plle_tegra210_ops = {
.is_enabled = clk_plle_tegra210_is_enabled,
.enable = clk_plle_tegra210_enable,
.disable = clk_plle_tegra210_disable,
.recalc_rate = clk_pll_recalc_rate,
+ .restore_context = tegra_clk_plle_t210_restore_context,
};
struct clk *tegra_clk_register_plle_tegra210(const char *name,
@@ -2535,27 +2598,12 @@ struct clk *tegra_clk_register_plle_tegra210(const char *name,
{
struct tegra_clk_pll *pll;
struct clk *clk;
- u32 val, val_aux;
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
if (IS_ERR(pll))
return ERR_CAST(pll);
- /* ensure parent is set to pll_re_vco */
-
- val = pll_readl_base(pll);
- val_aux = pll_readl(pll_params->aux_reg, pll);
-
- if (val & PLLE_BASE_ENABLE) {
- if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
- (val_aux & PLLE_AUX_PLLP_SEL))
- WARN(1, "pll_e enabled with unsupported parent %s\n",
- (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
- "pll_re_vco");
- } else {
- val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
- pll_writel(val_aux, pll_params->aux_reg, pll);
- }
+ _clk_plle_tegra_init_parent(pll);
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
&tegra_clk_plle_tegra210_ops);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 230c05d8eef0..f1ef6ae8c979 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -233,6 +233,7 @@ struct tegra_clk_pll;
* TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This
* flag indicated that it is PLLMB.
* TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output
+ * TEGRA_PLLRE - Used to indicate that it is PLLRE
*/
struct tegra_clk_pll_params {
unsigned long input_min;
@@ -299,6 +300,7 @@ struct tegra_clk_pll_params {
#define TEGRA_MDIV_NEW BIT(11)
#define TEGRA_PLLMB BIT(12)
#define TEGRA_PLL_VCO_OUT BIT(13)
+#define TEGRA_PLLRE BIT(14)
/**
* struct tegra_clk_pll - Tegra PLL clock
@@ -308,6 +310,7 @@ struct tegra_clk_pll_params {
* @pmc: address of PMC, required to read override bits
* @lock: register lock
* @params: PLL parameters
+ * @pllbase_ctx: pll base register value during suspend and resume
*/
struct tegra_clk_pll {
struct clk_hw hw;
@@ -315,6 +318,7 @@ struct tegra_clk_pll {
void __iomem *pmc;
spinlock_t *lock;
struct tegra_clk_pll_params *params;
+ u32 pllbase_ctx;
};
#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
--
2.7.4
^ permalink raw reply related
* [PATCH v7 06/20] clk: tegra: Support for OSC context save and restore
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
This patch adds support for saving OSC clock frequency and the
drive-strength during OSC clock init and creates an API to restore
OSC control register value from the saved context.
This API is invoked by Tegra210 clock driver during system resume
to restore the OSC clock settings.
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-tegra-fixed.c | 15 +++++++++++++++
drivers/clk/tegra/clk.h | 1 +
2 files changed, 16 insertions(+)
diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c
index 8d91b2b191cf..7c6c8abfcde6 100644
--- a/drivers/clk/tegra/clk-tegra-fixed.c
+++ b/drivers/clk/tegra/clk-tegra-fixed.c
@@ -17,6 +17,10 @@
#define OSC_CTRL 0x50
#define OSC_CTRL_OSC_FREQ_SHIFT 28
#define OSC_CTRL_PLL_REF_DIV_SHIFT 26
+#define OSC_CTRL_MASK (0x3f2 | \
+ (0xf << OSC_CTRL_OSC_FREQ_SHIFT))
+
+static u32 osc_ctrl_ctx;
int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
unsigned long *input_freqs, unsigned int num,
@@ -29,6 +33,7 @@ int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
unsigned osc_idx;
val = readl_relaxed(clk_base + OSC_CTRL);
+ osc_ctrl_ctx = val & OSC_CTRL_MASK;
osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;
if (osc_idx < num)
@@ -96,3 +101,13 @@ void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks)
*dt_clk = clk;
}
}
+
+void tegra_clk_osc_resume(void __iomem *clk_base)
+{
+ u32 val;
+
+ val = readl_relaxed(clk_base + OSC_CTRL) & ~OSC_CTRL_MASK;
+ val |= osc_ctrl_ctx;
+ writel_relaxed(val, clk_base + OSC_CTRL);
+ fence_udelay(2, clk_base);
+}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index f1ef6ae8c979..abba6d8a04cd 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -842,6 +842,7 @@ u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);
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);
/* Combined read fence with delay */
--
2.7.4
^ permalink raw reply related
* [PATCH v7 11/20] cpufreq: tegra124: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
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,
};
--
2.7.4
^ permalink raw reply related
* [PATCH v7 13/20] clk: tegra210: Add suspend and resume support
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
This patch adds support for clk: tegra210: suspend-resume.
All the CAR controller settings are lost on suspend when core
power goes off.
This patch has implementation for saving and restoring all PLLs
and clocks context during system suspend and resume to have the
clocks back to same state for normal operation.
Clock driver suspend and resume are registered as syscore_ops as clocks
restore need to happen before the other drivers resume to have all their
clocks back to the same state as before suspend.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/clk/tegra/clk-tegra210.c | 75 +++++++++++++++++++++++++++++++++++++---
1 file changed, 71 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 998bf60b219a..14ea9f373a84 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -9,13 +9,13 @@
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/clk/tegra.h>
#include <dt-bindings/clock/tegra210-car.h>
#include <dt-bindings/reset/tegra210-car.h>
-#include <linux/iopoll.h>
#include <linux/sizes.h>
#include <soc/tegra/pmc.h>
@@ -220,11 +220,15 @@
#define CLK_M_DIVISOR_SHIFT 2
#define CLK_M_DIVISOR_MASK 0x3
+#define CLK_MASK_ARM 0x44
+#define MISC_CLK_ENB 0x48
+
#define RST_DFLL_DVCO 0x2f4
#define DVFS_DFLL_RESET_SHIFT 0
#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
+#define CPU_SOFTRST_CTRL 0x380
#define LVL2_CLK_GATE_OVRA 0xf8
#define LVL2_CLK_GATE_OVRC 0x3a0
@@ -2825,6 +2829,7 @@ static int tegra210_enable_pllu(void)
struct tegra_clk_pll_freq_table *fentry;
struct tegra_clk_pll pllu;
u32 reg;
+ int ret;
for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) {
if (fentry->input_rate == pll_ref_freq)
@@ -2853,9 +2858,14 @@ static int tegra210_enable_pllu(void)
reg |= PLL_ENABLE;
writel(reg, clk_base + PLLU_BASE);
- readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg,
- reg & PLL_BASE_LOCK, 2, 1000);
- if (!(reg & PLL_BASE_LOCK)) {
+ /*
+ * During clock resume syscore operation, same PLLU init and enable
+ * routines gets invoked. So, readx_poll_timeout_atomic can't be used
+ * here as it uses ktime_get() and timekeeping resume doesn't happen
+ * by that time. So, using tegra210_wait_for_mask for PLL LOCK.
+ */
+ ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK);
+ if (ret) {
pr_err("Timed out waiting for PLL_U to lock\n");
return -ETIMEDOUT;
}
@@ -3288,6 +3298,56 @@ static void tegra210_disable_cpu_clock(u32 cpu)
}
#ifdef CONFIG_PM_SLEEP
+#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4))
+#define car_writel(_val, _base, _off) \
+ writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
+
+static u32 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
+static u32 cpu_softrst_ctx[3];
+
+static int tegra210_clk_suspend(void)
+{
+ unsigned int i;
+
+ clk_save_context();
+
+ /*
+ * Save the bootloader configured clock registers SPARE_REG0,
+ * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL.
+ */
+ spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0);
+ misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB);
+ clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM);
+
+ for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+ cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i);
+
+ return 0;
+}
+
+static void tegra210_clk_resume(void)
+{
+ unsigned int i;
+
+ tegra_clk_osc_resume(clk_base);
+
+ /*
+ * Restore the bootloader configured clock registers SPARE_REG0,
+ * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
+ */
+ writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0);
+ writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB);
+ writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM);
+
+ for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++)
+ car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i);
+
+ fence_udelay(5, clk_base);
+
+ tegra210_init_pllu();
+ clk_restore_context();
+}
+
static void tegra210_cpu_clock_suspend(void)
{
/* switch coresite to clk_m, save off original source */
@@ -3303,6 +3363,11 @@ static void tegra210_cpu_clock_resume(void)
}
#endif
+static struct syscore_ops tegra_clk_syscore_ops = {
+ .suspend = tegra210_clk_suspend,
+ .resume = tegra210_clk_resume,
+};
+
static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
.wait_for_reset = tegra210_wait_cpu_in_reset,
.disable_clock = tegra210_disable_cpu_clock,
@@ -3587,5 +3652,7 @@ static void __init tegra210_clock_init(struct device_node *np)
tegra210_mbist_clk_init();
tegra_cpu_car_ops = &tegra210_cpu_car_ops;
+
+ register_syscore_ops(&tegra_clk_syscore_ops);
}
CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
--
2.7.4
^ permalink raw reply related
* [PATCH v7 14/20] soc/tegra: pmc: Allow to support more tegras wake
From: Sowjanya Komatineni @ 2019-07-31 21:10 UTC (permalink / raw)
To: thierry.reding, jonathanh, tglx, jason, marc.zyngier,
linus.walleij, stefan, mark.rutland
Cc: pdeschrijver, pgaikwad, sboyd, linux-clk, linux-gpio, jckuo,
josephl, talho, skomatineni, linux-tegra, linux-kernel,
mperttunen, spatra, robh+dt, digetx, devicetree, rjw,
viresh.kumar, linux-pm
In-Reply-To: <1564607463-28802-1-git-send-email-skomatineni@nvidia.com>
This patch allows to create separate irq_set_wake and irq_set_type
implementations for different tegra designs PMC that has different
wake models which require difference wake registers and different
programming sequence.
AOWAKE model support is available for Tegra186 and Tegra194 only
and it resides within PMC and supports tiered wake architecture.
Tegra210 and prior tegra designs uses PMC directly to receive wake
events and coordinate the wake sequence.
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
drivers/soc/tegra/pmc.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 9f9c1c677cf4..91c84d0e66ae 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -226,6 +226,8 @@ struct tegra_pmc_soc {
void (*setup_irq_polarity)(struct tegra_pmc *pmc,
struct device_node *np,
bool invert);
+ int (*irq_set_wake)(struct irq_data *data, unsigned int on);
+ int (*irq_set_type)(struct irq_data *data, unsigned int type);
const char * const *reset_sources;
unsigned int num_reset_sources;
@@ -1920,7 +1922,7 @@ static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
.alloc = tegra_pmc_irq_alloc,
};
-static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
+static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
unsigned int offset, bit;
@@ -1952,7 +1954,7 @@ static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
return 0;
}
-static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type)
+static int tegra186_pmc_irq_set_type(struct irq_data *data, unsigned int type)
{
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
u32 value;
@@ -2006,8 +2008,8 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
pmc->irq.irq_unmask = irq_chip_unmask_parent;
pmc->irq.irq_eoi = irq_chip_eoi_parent;
pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent;
- pmc->irq.irq_set_type = tegra_pmc_irq_set_type;
- pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake;
+ pmc->irq.irq_set_type = pmc->soc->irq_set_type;
+ pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
&tegra_pmc_irq_domain_ops, pmc);
@@ -2680,6 +2682,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.regs = &tegra186_pmc_regs,
.init = NULL,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .irq_set_wake = tegra186_pmc_irq_set_wake,
+ .irq_set_type = tegra186_pmc_irq_set_type,
.reset_sources = tegra186_reset_sources,
.num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
.reset_levels = tegra186_reset_levels,
--
2.7.4
^ 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