Commit 1bd23153 authored by Andy Shevchenko's avatar Andy Shevchenko

pinctrl: intel: Allow to request locked pads

Some firmwares would like to protect pads 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 pad and may not change its state.
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Acked-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent bf5ab1bd
...@@ -220,47 +220,71 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin) ...@@ -220,47 +220,71 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
return !(readl(hostown) & BIT(gpp_offset)); return !(readl(hostown) & BIT(gpp_offset));
} }
static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin) /**
* enum - Locking variants of the pad configuration
*
* @PAD_UNLOCKED: pad is fully controlled by the configuration registers
* @PAD_LOCKED: pad configuration registers, except TX state, are locked
* @PAD_LOCKED_TX: pad configuration TX state is locked
* @PAD_LOCKED_FULL: pad configuration registers are locked completely
*
* Locking is considered as read-only mode for corresponding registers and
* their respective fields. That said, TX state bit is locked separately from
* the main locking scheme.
*/
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; struct intel_community *community;
const struct intel_padgroup *padgrp; const struct intel_padgroup *padgrp;
unsigned int offset, gpp_offset; unsigned int offset, gpp_offset;
u32 value; u32 value;
int ret = PAD_UNLOCKED;
community = intel_get_community(pctrl, pin); community = intel_get_community(pctrl, pin);
if (!community) if (!community)
return true; return PAD_LOCKED_FULL;
if (!community->padcfglock_offset) if (!community->padcfglock_offset)
return false; return PAD_UNLOCKED;
padgrp = intel_community_get_padgroup(community, pin); padgrp = intel_community_get_padgroup(community, pin);
if (!padgrp) if (!padgrp)
return true; return PAD_LOCKED_FULL;
gpp_offset = padgroup_offset(padgrp, pin); gpp_offset = padgroup_offset(padgrp, pin);
/* /*
* If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad, * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad,
* the pad is considered unlocked. Any other case means that it is * the pad is considered unlocked. Any other case means that it is
* either fully or partially locked and we don't touch it. * either fully or partially locked.
*/ */
offset = community->padcfglock_offset + padgrp->reg_num * 8; offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8;
value = readl(community->regs + offset); value = readl(community->regs + offset);
if (value & BIT(gpp_offset)) if (value & BIT(gpp_offset))
return true; ret |= PAD_LOCKED;
offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8; offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8;
value = readl(community->regs + offset); value = readl(community->regs + offset);
if (value & BIT(gpp_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) static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin)
{ {
return intel_pad_owned_by_host(pctrl, pin) && return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin);
!intel_pad_locked(pctrl, pin);
} }
static int intel_get_groups_count(struct pinctrl_dev *pctldev) static int intel_get_groups_count(struct pinctrl_dev *pctldev)
...@@ -294,7 +318,8 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, ...@@ -294,7 +318,8 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg; void __iomem *padcfg;
u32 cfg0, cfg1, mode; u32 cfg0, cfg1, mode;
bool locked, acpi; int locked;
bool acpi;
if (!intel_pad_owned_by_host(pctrl, pin)) { if (!intel_pad_owned_by_host(pctrl, pin)) {
seq_puts(s, "not available"); seq_puts(s, "not available");
...@@ -322,11 +347,16 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, ...@@ -322,11 +347,16 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
if (locked || acpi) { if (locked || acpi) {
seq_puts(s, " ["); seq_puts(s, " [");
if (locked) { if (locked)
seq_puts(s, "LOCKED"); seq_puts(s, "LOCKED");
if (acpi) 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, ", "); seq_puts(s, ", ");
}
if (acpi) if (acpi)
seq_puts(s, "ACPI"); seq_puts(s, "ACPI");
seq_puts(s, "]"); seq_puts(s, "]");
...@@ -448,11 +478,16 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, ...@@ -448,11 +478,16 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
raw_spin_lock_irqsave(&pctrl->lock, flags); 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); raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return -EBUSY; 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); padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
intel_gpio_set_gpio_mode(padcfg0); intel_gpio_set_gpio_mode(padcfg0);
/* Disable TX buffer and enable RX (this will be input) */ /* Disable TX buffer and enable RX (this will be input) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment