diff mbox series

[v1] pinctrl: intel: Allow to request locked pins

Message ID 20190726200830.52728-1-andriy.shevchenko@linux.intel.com
State New
Headers show
Series [v1] pinctrl: intel: Allow to request locked pins | expand

Commit Message

Andy Shevchenko July 26, 2019, 8:08 p.m. UTC
Some firmwares would like to protect pins from being modified by OS
and at the same time provide them to OS as a resource. So, the driver
in such circumstances may request pin and may not change its state.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/pinctrl/intel/pinctrl-intel.c | 55 +++++++++++++++++++--------
 1 file changed, 39 insertions(+), 16 deletions(-)

Comments

Mika Westerberg Aug. 6, 2019, 11:01 a.m. UTC | #1
On Fri, Jul 26, 2019 at 11:08:30PM +0300, Andy Shevchenko wrote:
> Some firmwares would like to protect pins from being modified by OS
> and at the same time provide them to OS as a resource. So, the driver
> in such circumstances may request pin and may not change its state.

This is definitely good idea.

> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/pinctrl/intel/pinctrl-intel.c | 55 +++++++++++++++++++--------
>  1 file changed, 39 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
> index 3a945997b8eb..567fe43b238f 100644
> --- a/drivers/pinctrl/intel/pinctrl-intel.c
> +++ b/drivers/pinctrl/intel/pinctrl-intel.c
> @@ -220,22 +220,30 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
>  	return !(readl(hostown) & BIT(gpp_offset));
>  }
>  
> -static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
> +enum {
> +	PAD_UNLOCKED	= 0,
> +	PAD_LOCKED	= 1,
> +	PAD_LOCKED_TX	= 2,
> +	PAD_LOCKED_FULL	= PAD_LOCKED | PAD_LOCKED_TX,
> +};
> +
> +static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
>  {
>  	struct intel_community *community;
>  	const struct intel_padgroup *padgrp;
>  	unsigned int offset, gpp_offset;
>  	u32 value;
> +	int ret = PAD_UNLOCKED;
>  
>  	community = intel_get_community(pctrl, pin);
>  	if (!community)
> -		return true;
> +		return PAD_LOCKED_FULL;
>  	if (!community->padcfglock_offset)
> -		return false;
> +		return PAD_UNLOCKED;
>  
>  	padgrp = intel_community_get_padgroup(community, pin);
>  	if (!padgrp)
> -		return true;
> +		return PAD_LOCKED_FULL;
>  
>  	gpp_offset = padgroup_offset(padgrp, pin);
>  
> @@ -244,23 +252,27 @@ static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
>  	 * the pad is considered unlocked. Any other case means that it is
>  	 * either fully or partially locked and we don't touch it.

I think you should update the above comment as well.

>  	 */
> -	offset = community->padcfglock_offset + padgrp->reg_num * 8;
> +	offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8;
>  	value = readl(community->regs + offset);
>  	if (value & BIT(gpp_offset))
> -		return true;
> +		ret |= PAD_LOCKED;
>  
>  	offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8;
>  	value = readl(community->regs + offset);
>  	if (value & BIT(gpp_offset))
> -		return true;
> +		ret |= PAD_LOCKED_TX;
>  
> -	return false;
> +	return ret;
> +}
> +
> +static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin)
> +{
> +	return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED;
>  }
>  
>  static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin)
>  {
> -	return intel_pad_owned_by_host(pctrl, pin) &&
> -		!intel_pad_locked(pctrl, pin);
> +	return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin);
>  }
>  
>  static int intel_get_groups_count(struct pinctrl_dev *pctldev)
> @@ -294,7 +306,8 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
>  	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
>  	void __iomem *padcfg;
>  	u32 cfg0, cfg1, mode;
> -	bool locked, acpi;
> +	int locked;
> +	bool acpi;
>  
>  	if (!intel_pad_owned_by_host(pctrl, pin)) {
>  		seq_puts(s, "not available");
> @@ -322,11 +335,16 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
>  
>  	if (locked || acpi) {
>  		seq_puts(s, " [");
> -		if (locked) {
> +		if (locked)
>  			seq_puts(s, "LOCKED");
> -			if (acpi)
> -				seq_puts(s, ", ");
> -		}
> +		if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX)
> +			seq_puts(s, " TX");
> +		else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL)
> +			seq_puts(s, " FULL");
> +
> +		if (locked && acpi)
> +			seq_puts(s, ", ");
> +
>  		if (acpi)
>  			seq_puts(s, "ACPI");
>  		seq_puts(s, "]");
> @@ -448,11 +466,16 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
>  
>  	raw_spin_lock_irqsave(&pctrl->lock, flags);
>  
> -	if (!intel_pad_usable(pctrl, pin)) {
> +	if (!intel_pad_owned_by_host(pctrl, pin)) {
>  		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>  		return -EBUSY;
>  	}
>  
> +	if (!intel_pad_is_unlocked(pctrl, pin)) {
> +		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
> +		return 0;

Hmm, if I'm reading this right it still does not allow requesting locked
pins. What I'm missing here?

> +	}
> +
>  	padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
>  	intel_gpio_set_gpio_mode(padcfg0);
>  	/* Disable TX buffer and enable RX (this will be input) */
> -- 
> 2.20.1
Andy Shevchenko Aug. 6, 2019, 11:45 a.m. UTC | #2
On Tue, Aug 06, 2019 at 02:01:26PM +0300, Mika Westerberg wrote:
> On Fri, Jul 26, 2019 at 11:08:30PM +0300, Andy Shevchenko wrote:
> > Some firmwares would like to protect pins from being modified by OS
> > and at the same time provide them to OS as a resource. So, the driver
> > in such circumstances may request pin and may not change its state.
> 
> This is definitely good idea.

Thanks for review, my answers below.

> >  	 * the pad is considered unlocked. Any other case means that it is
> >  	 * either fully or partially locked and we don't touch it.
> 
> I think you should update the above comment as well.

Will do for v2.

> >  	raw_spin_lock_irqsave(&pctrl->lock, flags);
> >  
> > -	if (!intel_pad_usable(pctrl, pin)) {
> > +	if (!intel_pad_owned_by_host(pctrl, pin)) {
> >  		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
> >  		return -EBUSY;
> >  	}
> >  
> > +	if (!intel_pad_is_unlocked(pctrl, pin)) {
> > +		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
> > +		return 0;
> 
> Hmm, if I'm reading this right it still does not allow requesting locked
> pins. What I'm missing here?

We do not return an error code here, so pin is left requested but pad
configuration register untouched.

> > +	}
> > +
> >  	padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
> >  	intel_gpio_set_gpio_mode(padcfg0);
Mika Westerberg Aug. 6, 2019, 11:47 a.m. UTC | #3
On Tue, Aug 06, 2019 at 02:45:17PM +0300, Andy Shevchenko wrote:
> On Tue, Aug 06, 2019 at 02:01:26PM +0300, Mika Westerberg wrote:
> > On Fri, Jul 26, 2019 at 11:08:30PM +0300, Andy Shevchenko wrote:
> > > Some firmwares would like to protect pins from being modified by OS
> > > and at the same time provide them to OS as a resource. So, the driver
> > > in such circumstances may request pin and may not change its state.
> > 
> > This is definitely good idea.
> 
> Thanks for review, my answers below.
> 
> > >  	 * the pad is considered unlocked. Any other case means that it is
> > >  	 * either fully or partially locked and we don't touch it.
> > 
> > I think you should update the above comment as well.
> 
> Will do for v2.
> 
> > >  	raw_spin_lock_irqsave(&pctrl->lock, flags);
> > >  
> > > -	if (!intel_pad_usable(pctrl, pin)) {
> > > +	if (!intel_pad_owned_by_host(pctrl, pin)) {
> > >  		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
> > >  		return -EBUSY;
> > >  	}
> > >  
> > > +	if (!intel_pad_is_unlocked(pctrl, pin)) {
> > > +		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
> > > +		return 0;
> > 
> > Hmm, if I'm reading this right it still does not allow requesting locked
> > pins. What I'm missing here?
> 
> We do not return an error code here, so pin is left requested but pad
> configuration register untouched.

Indeed, now it is clear. Thanks for explaining :)
Linus Walleij Aug. 6, 2019, 2:27 p.m. UTC | #4
Hi Andy,

On Fri, Jul 26, 2019 at 10:08 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:

> Some firmwares would like to protect pins from being modified by OS
> and at the same time provide them to OS as a resource. So, the driver
> in such circumstances may request pin and may not change its state.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Interesting patch!

> +enum {
> +       PAD_UNLOCKED    = 0,
> +       PAD_LOCKED      = 1,
> +       PAD_LOCKED_TX   = 2,
> +       PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX,
> +};

Please add some kerneldoc explaining what these different lock
states are. My head is spinning. Locked? Locked TX? Locked full?

Yours,
Linus Walleij
diff mbox series

Patch

diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 3a945997b8eb..567fe43b238f 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -220,22 +220,30 @@  static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
 	return !(readl(hostown) & BIT(gpp_offset));
 }
 
-static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
+enum {
+	PAD_UNLOCKED	= 0,
+	PAD_LOCKED	= 1,
+	PAD_LOCKED_TX	= 2,
+	PAD_LOCKED_FULL	= PAD_LOCKED | PAD_LOCKED_TX,
+};
+
+static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
 {
 	struct intel_community *community;
 	const struct intel_padgroup *padgrp;
 	unsigned int offset, gpp_offset;
 	u32 value;
+	int ret = PAD_UNLOCKED;
 
 	community = intel_get_community(pctrl, pin);
 	if (!community)
-		return true;
+		return PAD_LOCKED_FULL;
 	if (!community->padcfglock_offset)
-		return false;
+		return PAD_UNLOCKED;
 
 	padgrp = intel_community_get_padgroup(community, pin);
 	if (!padgrp)
-		return true;
+		return PAD_LOCKED_FULL;
 
 	gpp_offset = padgroup_offset(padgrp, pin);
 
@@ -244,23 +252,27 @@  static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
 	 * the pad is considered unlocked. Any other case means that it is
 	 * either fully or partially locked and we don't touch it.
 	 */
-	offset = community->padcfglock_offset + padgrp->reg_num * 8;
+	offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8;
 	value = readl(community->regs + offset);
 	if (value & BIT(gpp_offset))
-		return true;
+		ret |= PAD_LOCKED;
 
 	offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8;
 	value = readl(community->regs + offset);
 	if (value & BIT(gpp_offset))
-		return true;
+		ret |= PAD_LOCKED_TX;
 
-	return false;
+	return ret;
+}
+
+static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin)
+{
+	return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED;
 }
 
 static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin)
 {
-	return intel_pad_owned_by_host(pctrl, pin) &&
-		!intel_pad_locked(pctrl, pin);
+	return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin);
 }
 
 static int intel_get_groups_count(struct pinctrl_dev *pctldev)
@@ -294,7 +306,8 @@  static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
 	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
 	void __iomem *padcfg;
 	u32 cfg0, cfg1, mode;
-	bool locked, acpi;
+	int locked;
+	bool acpi;
 
 	if (!intel_pad_owned_by_host(pctrl, pin)) {
 		seq_puts(s, "not available");
@@ -322,11 +335,16 @@  static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
 
 	if (locked || acpi) {
 		seq_puts(s, " [");
-		if (locked) {
+		if (locked)
 			seq_puts(s, "LOCKED");
-			if (acpi)
-				seq_puts(s, ", ");
-		}
+		if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX)
+			seq_puts(s, " TX");
+		else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL)
+			seq_puts(s, " FULL");
+
+		if (locked && acpi)
+			seq_puts(s, ", ");
+
 		if (acpi)
 			seq_puts(s, "ACPI");
 		seq_puts(s, "]");
@@ -448,11 +466,16 @@  static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
 
 	raw_spin_lock_irqsave(&pctrl->lock, flags);
 
-	if (!intel_pad_usable(pctrl, pin)) {
+	if (!intel_pad_owned_by_host(pctrl, pin)) {
 		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 		return -EBUSY;
 	}
 
+	if (!intel_pad_is_unlocked(pctrl, pin)) {
+		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+		return 0;
+	}
+
 	padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
 	intel_gpio_set_gpio_mode(padcfg0);
 	/* Disable TX buffer and enable RX (this will be input) */