diff mbox series

[2/3] gpio: tegra186: Program interrupt route mapping

Message ID 20191108153353.3149078-2-thierry.reding@gmail.com
State Accepted
Headers show
Series [1/3] gpio: tegra186: Derive register offsets from bank/port | expand

Commit Message

Thierry Reding Nov. 8, 2019, 3:33 p.m. UTC
From: Thierry Reding <treding@nvidia.com>

The controls for the GG port on Tegra194 resides in the power partition
of the C5 PCIe controller and its interrupt route mapping can therefore
not be programmed by early boot firmware along with that of the other
ports.

Detect this generically by looking at which controls have already been
locked down using the security registers and fill in default values for
controls that are unlocked.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpio-tegra186.c | 46 ++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

Comments

Bartosz Golaszewski Nov. 12, 2019, 10:11 a.m. UTC | #1
pt., 8 lis 2019 o 16:34 Thierry Reding <thierry.reding@gmail.com> napisał(a):
>
> From: Thierry Reding <treding@nvidia.com>
>
> The controls for the GG port on Tegra194 resides in the power partition
> of the C5 PCIe controller and its interrupt route mapping can therefore
> not be programmed by early boot firmware along with that of the other
> ports.
>
> Detect this generically by looking at which controls have already been
> locked down using the security registers and fill in default values for
> controls that are unlocked.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
>  drivers/gpio/gpio-tegra186.c | 46 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
>
> diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
> index 32714cefdfde..404ebb82bfa2 100644
> --- a/drivers/gpio/gpio-tegra186.c
> +++ b/drivers/gpio/gpio-tegra186.c
> @@ -15,6 +15,14 @@
>  #include <dt-bindings/gpio/tegra186-gpio.h>
>  #include <dt-bindings/gpio/tegra194-gpio.h>
>
> +/* security registers */
> +#define TEGRA186_GPIO_CTL_SCR 0x0c
> +#define  TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28)
> +#define  TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27)
> +
> +#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4)
> +
> +/* control registers */
>  #define TEGRA186_GPIO_ENABLE_CONFIG 0x00
>  #define  TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
>  #define  TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
> @@ -64,6 +72,7 @@ struct tegra_gpio {
>
>         const struct tegra_gpio_soc *soc;
>
> +       void __iomem *secure;
>         void __iomem *base;
>  };
>
> @@ -449,6 +458,37 @@ static const struct of_device_id tegra186_pmc_of_match[] = {
>         { /* sentinel */ }
>  };
>
> +static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
> +{
> +       unsigned int i, j;
> +       u32 value;
> +
> +       for (i = 0; i < gpio->soc->num_ports; i++) {
> +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> +               unsigned int offset, p = port->port;
> +               void __iomem *base;
> +
> +               base = gpio->secure + port->bank * 0x1000 + 0x800;
> +
> +               value = readl(base + TEGRA186_GPIO_CTL_SCR);
> +
> +               /*
> +                * For controllers that haven't been locked down yet, make
> +                * sure to program the default interrupt route mapping.
> +                */
> +               if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 &&
> +                   (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) {
> +                       for (j = 0; j < 8; j++) {
> +                               offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
> +
> +                               value = readl(base + offset);
> +                               value = BIT(port->pins) - 1;
> +                               writel(value, base + offset);
> +                       }
> +               }
> +       }
> +}
> +
>  static int tegra186_gpio_probe(struct platform_device *pdev)
>  {
>         unsigned int i, j, offset;
> @@ -464,6 +504,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
>
>         gpio->soc = of_device_get_match_data(&pdev->dev);
>
> +       gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
> +       if (IS_ERR(gpio->secure))
> +               return PTR_ERR(gpio->secure);
> +
>         gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
>         if (IS_ERR(gpio->base))
>                 return PTR_ERR(gpio->base);
> @@ -558,6 +602,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
>                         return -EPROBE_DEFER;
>         }
>
> +       tegra186_gpio_init_route_mapping(gpio);
> +
>         irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
>                                 sizeof(*irq->map), GFP_KERNEL);
>         if (!irq->map)
> --
> 2.23.0
>

This doesn't apply without a patch that went through Greg's driver-core tree.

Greg: can you provide us with an immutable branch which we can merge
into the gpio for-next tree?

Bart
Greg KH Nov. 12, 2019, 2:10 p.m. UTC | #2
On Tue, Nov 12, 2019 at 11:11:35AM +0100, Bartosz Golaszewski wrote:
> pt., 8 lis 2019 o 16:34 Thierry Reding <thierry.reding@gmail.com> napisał(a):
> >
> > From: Thierry Reding <treding@nvidia.com>
> >
> > The controls for the GG port on Tegra194 resides in the power partition
> > of the C5 PCIe controller and its interrupt route mapping can therefore
> > not be programmed by early boot firmware along with that of the other
> > ports.
> >
> > Detect this generically by looking at which controls have already been
> > locked down using the security registers and fill in default values for
> > controls that are unlocked.
> >
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > ---
> >  drivers/gpio/gpio-tegra186.c | 46 ++++++++++++++++++++++++++++++++++++
> >  1 file changed, 46 insertions(+)
> >
> > diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
> > index 32714cefdfde..404ebb82bfa2 100644
> > --- a/drivers/gpio/gpio-tegra186.c
> > +++ b/drivers/gpio/gpio-tegra186.c
> > @@ -15,6 +15,14 @@
> >  #include <dt-bindings/gpio/tegra186-gpio.h>
> >  #include <dt-bindings/gpio/tegra194-gpio.h>
> >
> > +/* security registers */
> > +#define TEGRA186_GPIO_CTL_SCR 0x0c
> > +#define  TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28)
> > +#define  TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27)
> > +
> > +#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4)
> > +
> > +/* control registers */
> >  #define TEGRA186_GPIO_ENABLE_CONFIG 0x00
> >  #define  TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
> >  #define  TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
> > @@ -64,6 +72,7 @@ struct tegra_gpio {
> >
> >         const struct tegra_gpio_soc *soc;
> >
> > +       void __iomem *secure;
> >         void __iomem *base;
> >  };
> >
> > @@ -449,6 +458,37 @@ static const struct of_device_id tegra186_pmc_of_match[] = {
> >         { /* sentinel */ }
> >  };
> >
> > +static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
> > +{
> > +       unsigned int i, j;
> > +       u32 value;
> > +
> > +       for (i = 0; i < gpio->soc->num_ports; i++) {
> > +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> > +               unsigned int offset, p = port->port;
> > +               void __iomem *base;
> > +
> > +               base = gpio->secure + port->bank * 0x1000 + 0x800;
> > +
> > +               value = readl(base + TEGRA186_GPIO_CTL_SCR);
> > +
> > +               /*
> > +                * For controllers that haven't been locked down yet, make
> > +                * sure to program the default interrupt route mapping.
> > +                */
> > +               if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 &&
> > +                   (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) {
> > +                       for (j = 0; j < 8; j++) {
> > +                               offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
> > +
> > +                               value = readl(base + offset);
> > +                               value = BIT(port->pins) - 1;
> > +                               writel(value, base + offset);
> > +                       }
> > +               }
> > +       }
> > +}
> > +
> >  static int tegra186_gpio_probe(struct platform_device *pdev)
> >  {
> >         unsigned int i, j, offset;
> > @@ -464,6 +504,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
> >
> >         gpio->soc = of_device_get_match_data(&pdev->dev);
> >
> > +       gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
> > +       if (IS_ERR(gpio->secure))
> > +               return PTR_ERR(gpio->secure);
> > +
> >         gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
> >         if (IS_ERR(gpio->base))
> >                 return PTR_ERR(gpio->base);
> > @@ -558,6 +602,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
> >                         return -EPROBE_DEFER;
> >         }
> >
> > +       tegra186_gpio_init_route_mapping(gpio);
> > +
> >         irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
> >                                 sizeof(*irq->map), GFP_KERNEL);
> >         if (!irq->map)
> > --
> > 2.23.0
> >
> 
> This doesn't apply without a patch that went through Greg's driver-core tree.
> 
> Greg: can you provide us with an immutable branch which we can merge
> into the gpio for-next tree?

A branch for/called what?

You can always pull from my driver-core-next branch, I never rebase it.

thanks,

greg k-h
Bartosz Golaszewski Nov. 12, 2019, 3:33 p.m. UTC | #3
wt., 12 lis 2019 o 15:10 Greg KH <gregkh@linuxfoundation.org> napisał(a):
>
> On Tue, Nov 12, 2019 at 11:11:35AM +0100, Bartosz Golaszewski wrote:
> > pt., 8 lis 2019 o 16:34 Thierry Reding <thierry.reding@gmail.com> napisał(a):
> > >
> > > From: Thierry Reding <treding@nvidia.com>
> > >
> > > The controls for the GG port on Tegra194 resides in the power partition
> > > of the C5 PCIe controller and its interrupt route mapping can therefore
> > > not be programmed by early boot firmware along with that of the other
> > > ports.
> > >
> > > Detect this generically by looking at which controls have already been
> > > locked down using the security registers and fill in default values for
> > > controls that are unlocked.
> > >
> > > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > > ---
> > >  drivers/gpio/gpio-tegra186.c | 46 ++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 46 insertions(+)
> > >
> > > diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
> > > index 32714cefdfde..404ebb82bfa2 100644
> > > --- a/drivers/gpio/gpio-tegra186.c
> > > +++ b/drivers/gpio/gpio-tegra186.c
> > > @@ -15,6 +15,14 @@
> > >  #include <dt-bindings/gpio/tegra186-gpio.h>
> > >  #include <dt-bindings/gpio/tegra194-gpio.h>
> > >
> > > +/* security registers */
> > > +#define TEGRA186_GPIO_CTL_SCR 0x0c
> > > +#define  TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28)
> > > +#define  TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27)
> > > +
> > > +#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4)
> > > +
> > > +/* control registers */
> > >  #define TEGRA186_GPIO_ENABLE_CONFIG 0x00
> > >  #define  TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
> > >  #define  TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
> > > @@ -64,6 +72,7 @@ struct tegra_gpio {
> > >
> > >         const struct tegra_gpio_soc *soc;
> > >
> > > +       void __iomem *secure;
> > >         void __iomem *base;
> > >  };
> > >
> > > @@ -449,6 +458,37 @@ static const struct of_device_id tegra186_pmc_of_match[] = {
> > >         { /* sentinel */ }
> > >  };
> > >
> > > +static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
> > > +{
> > > +       unsigned int i, j;
> > > +       u32 value;
> > > +
> > > +       for (i = 0; i < gpio->soc->num_ports; i++) {
> > > +               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
> > > +               unsigned int offset, p = port->port;
> > > +               void __iomem *base;
> > > +
> > > +               base = gpio->secure + port->bank * 0x1000 + 0x800;
> > > +
> > > +               value = readl(base + TEGRA186_GPIO_CTL_SCR);
> > > +
> > > +               /*
> > > +                * For controllers that haven't been locked down yet, make
> > > +                * sure to program the default interrupt route mapping.
> > > +                */
> > > +               if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 &&
> > > +                   (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) {
> > > +                       for (j = 0; j < 8; j++) {
> > > +                               offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
> > > +
> > > +                               value = readl(base + offset);
> > > +                               value = BIT(port->pins) - 1;
> > > +                               writel(value, base + offset);
> > > +                       }
> > > +               }
> > > +       }
> > > +}
> > > +
> > >  static int tegra186_gpio_probe(struct platform_device *pdev)
> > >  {
> > >         unsigned int i, j, offset;
> > > @@ -464,6 +504,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
> > >
> > >         gpio->soc = of_device_get_match_data(&pdev->dev);
> > >
> > > +       gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
> > > +       if (IS_ERR(gpio->secure))
> > > +               return PTR_ERR(gpio->secure);
> > > +
> > >         gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
> > >         if (IS_ERR(gpio->base))
> > >                 return PTR_ERR(gpio->base);
> > > @@ -558,6 +602,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
> > >                         return -EPROBE_DEFER;
> > >         }
> > >
> > > +       tegra186_gpio_init_route_mapping(gpio);
> > > +
> > >         irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
> > >                                 sizeof(*irq->map), GFP_KERNEL);
> > >         if (!irq->map)
> > > --
> > > 2.23.0
> > >
> >
> > This doesn't apply without a patch that went through Greg's driver-core tree.
> >
> > Greg: can you provide us with an immutable branch which we can merge
> > into the gpio for-next tree?
>
> A branch for/called what?
>
> You can always pull from my driver-core-next branch, I never rebase it.
>

That works for me - thanks!

Bart

> thanks,
>
> greg k-h
diff mbox series

Patch

diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 32714cefdfde..404ebb82bfa2 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -15,6 +15,14 @@ 
 #include <dt-bindings/gpio/tegra186-gpio.h>
 #include <dt-bindings/gpio/tegra194-gpio.h>
 
+/* security registers */
+#define TEGRA186_GPIO_CTL_SCR 0x0c
+#define  TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28)
+#define  TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27)
+
+#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4)
+
+/* control registers */
 #define TEGRA186_GPIO_ENABLE_CONFIG 0x00
 #define  TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
 #define  TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
@@ -64,6 +72,7 @@  struct tegra_gpio {
 
 	const struct tegra_gpio_soc *soc;
 
+	void __iomem *secure;
 	void __iomem *base;
 };
 
@@ -449,6 +458,37 @@  static const struct of_device_id tegra186_pmc_of_match[] = {
 	{ /* sentinel */ }
 };
 
+static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
+{
+	unsigned int i, j;
+	u32 value;
+
+	for (i = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+		unsigned int offset, p = port->port;
+		void __iomem *base;
+
+		base = gpio->secure + port->bank * 0x1000 + 0x800;
+
+		value = readl(base + TEGRA186_GPIO_CTL_SCR);
+
+		/*
+		 * For controllers that haven't been locked down yet, make
+		 * sure to program the default interrupt route mapping.
+		 */
+		if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 &&
+		    (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) {
+			for (j = 0; j < 8; j++) {
+				offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
+
+				value = readl(base + offset);
+				value = BIT(port->pins) - 1;
+				writel(value, base + offset);
+			}
+		}
+	}
+}
+
 static int tegra186_gpio_probe(struct platform_device *pdev)
 {
 	unsigned int i, j, offset;
@@ -464,6 +504,10 @@  static int tegra186_gpio_probe(struct platform_device *pdev)
 
 	gpio->soc = of_device_get_match_data(&pdev->dev);
 
+	gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
+	if (IS_ERR(gpio->secure))
+		return PTR_ERR(gpio->secure);
+
 	gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
 	if (IS_ERR(gpio->base))
 		return PTR_ERR(gpio->base);
@@ -558,6 +602,8 @@  static int tegra186_gpio_probe(struct platform_device *pdev)
 			return -EPROBE_DEFER;
 	}
 
+	tegra186_gpio_init_route_mapping(gpio);
+
 	irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
 				sizeof(*irq->map), GFP_KERNEL);
 	if (!irq->map)