Commit 08a96e43 authored by Linus Walleij's avatar Linus Walleij

Merge tag 'intel-pinctrl-v5.5-1' of...

Merge tag 'intel-pinctrl-v5.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel into devel

intel-pinctrl for v5.5-1

* Intel Tigerlake pin controller support has been added.
* Miscellaneous fixes to the main and Cherryview drivers.
* Refactoring of the context restoring in the main driver.

The following is an automated git shortlog grouped by driver:

cherryview:
 -  Missed type change to unsigned int
 -  Allocate IRQ chip dynamic
 -  Fix spelling mistake in the comment
 -  Fix irq_valid_mask calculation

intel:
 -  Missed type change to unsigned int
 -  Add Intel Tiger Lake pin controller support
 -  Use helper to restore register values on ->resume()
 -  Drop level from warning to debug in intel_restore_hostown()
 -  Introduce intel_restore_intmask() helper
 -  Introduce intel_restore_hostown() helper
 -  Introduce intel_restore_padcfg() helper
 -  Avoid potential glitches if pin is in GPIO mode
parents 1566a6a3 8ae93b5e
......@@ -115,4 +115,11 @@ config PINCTRL_SUNRISEPOINT
provides an interface that allows configuring of PCH pins and
using them as GPIOs.
config PINCTRL_TIGERLAKE
tristate "Intel Tiger Lake pinctrl and GPIO driver"
depends on ACPI
select PINCTRL_INTEL
help
This pinctrl driver provides an interface that allows configuring
of Intel Tiger Lake PCH pins and using them as GPIOs.
endif
......@@ -13,3 +13,4 @@ obj-$(CONFIG_PINCTRL_GEMINILAKE) += pinctrl-geminilake.o
obj-$(CONFIG_PINCTRL_ICELAKE) += pinctrl-icelake.o
obj-$(CONFIG_PINCTRL_LEWISBURG) += pinctrl-lewisburg.o
obj-$(CONFIG_PINCTRL_SUNRISEPOINT) += pinctrl-sunrisepoint.o
obj-$(CONFIG_PINCTRL_TIGERLAKE) += pinctrl-tigerlake.o
......@@ -147,6 +147,7 @@ struct chv_pin_context {
* @pctldesc: Pin controller description
* @pctldev: Pointer to the pin controller device
* @chip: GPIO chip in this pin controller
* @irqchip: IRQ chip in this pin controller
* @regs: MMIO registers
* @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
* offset (in GPIO number space)
......@@ -162,8 +163,9 @@ struct chv_pinctrl {
struct pinctrl_desc pctldesc;
struct pinctrl_dev *pctldev;
struct gpio_chip chip;
struct irq_chip irqchip;
void __iomem *regs;
unsigned intr_lines[16];
unsigned int intr_lines[16];
const struct chv_community *community;
u32 saved_intmask;
struct chv_pin_context *saved_pin_context;
......@@ -377,7 +379,7 @@ static const struct chv_community southwest_community = {
.gpio_ranges = southwest_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(southwest_gpio_ranges),
/*
* Southwest community can benerate GPIO interrupts only for the
* Southwest community can generate GPIO interrupts only for the
* first 8 interrupts. The upper half (8-15) can only be used to
* trigger GPEs.
*/
......@@ -1466,16 +1468,6 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned int type)
return 0;
}
static struct irq_chip chv_gpio_irqchip = {
.name = "chv-gpio",
.irq_startup = chv_gpio_irq_startup,
.irq_ack = chv_gpio_irq_ack,
.irq_mask = chv_gpio_irq_mask,
.irq_unmask = chv_gpio_irq_unmask,
.irq_set_type = chv_gpio_irq_type,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
static void chv_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
......@@ -1488,7 +1480,7 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
pending = readl(pctrl->regs + CHV_INTSTAT);
for_each_set_bit(intr_line, &pending, pctrl->community->nirqs) {
unsigned irq, offset;
unsigned int irq, offset;
offset = pctrl->intr_lines[intr_line];
irq = irq_find_mapping(gc->irq.domain, offset);
......@@ -1559,7 +1551,7 @@ static void chv_init_irq_valid_mask(struct gpio_chip *chip,
intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
if (intsel >= community->nirqs)
clear_bit(i, valid_mask);
clear_bit(desc->number, valid_mask);
}
}
......@@ -1625,7 +1617,15 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
}
}
ret = gpiochip_irqchip_add(chip, &chv_gpio_irqchip, 0,
pctrl->irqchip.name = "chv-gpio";
pctrl->irqchip.irq_startup = chv_gpio_irq_startup;
pctrl->irqchip.irq_ack = chv_gpio_irq_ack;
pctrl->irqchip.irq_mask = chv_gpio_irq_mask;
pctrl->irqchip.irq_unmask = chv_gpio_irq_unmask;
pctrl->irqchip.irq_set_type = chv_gpio_irq_type;
pctrl->irqchip.flags = IRQCHIP_SKIP_SET_WAKE;
ret = gpiochip_irqchip_add(chip, &pctrl->irqchip, 0,
handle_bad_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(pctrl->dev, "failed to add IRQ chip\n");
......@@ -1642,7 +1642,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
}
}
gpiochip_set_chained_irqchip(chip, &chv_gpio_irqchip, irq,
gpiochip_set_chained_irqchip(chip, &pctrl->irqchip, irq,
chv_gpio_irq_handler);
return 0;
}
......
......@@ -52,6 +52,7 @@
#define PADCFG0_GPIROUTNMI BIT(17)
#define PADCFG0_PMODE_SHIFT 10
#define PADCFG0_PMODE_MASK GENMASK(13, 10)
#define PADCFG0_PMODE_GPIO 0
#define PADCFG0_GPIORXDIS BIT(9)
#define PADCFG0_GPIOTXDIS BIT(8)
#define PADCFG0_GPIORXSTATE BIT(1)
......@@ -332,7 +333,7 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1));
mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
if (!mode)
if (mode == PADCFG0_PMODE_GPIO)
seq_puts(s, "GPIO ");
else
seq_printf(s, "mode %d ", mode);
......@@ -458,6 +459,11 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
writel(value, padcfg0);
}
static int intel_gpio_get_gpio_mode(void __iomem *padcfg0)
{
return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
}
static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
{
u32 value;
......@@ -491,7 +497,20 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
}
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
/*
* If pin is already configured in GPIO mode, we assume that
* firmware provides correct settings. In such case we avoid
* potential glitches on the pin. Otherwise, for the pin in
* alternative mode, consumer has to supply respective flags.
*/
if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) {
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
intel_gpio_set_gpio_mode(padcfg0);
/* Disable TX buffer and enable RX (this will be input) */
__intel_gpio_set_direction(padcfg0, true);
......@@ -1112,7 +1131,7 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
pending &= enabled;
for_each_set_bit(gpp_offset, &pending, padgrp->size) {
unsigned irq;
unsigned int irq;
irq = irq_find_mapping(gc->irq.domain,
padgrp->gpio_base + gpp_offset);
......@@ -1162,7 +1181,7 @@ static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl,
return ret;
}
static unsigned intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
{
const struct intel_community *community;
unsigned int ngpio = 0;
......@@ -1576,16 +1595,65 @@ intel_gpio_is_requested(struct gpio_chip *chip, int base, unsigned int size)
return requested;
}
static u32
intel_gpio_update_pad_mode(void __iomem *hostown, u32 mask, u32 value)
static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
{
u32 curr, updated;
curr = readl(hostown);
curr = readl(reg);
updated = (curr & ~mask) | (value & mask);
writel(updated, hostown);
if (curr == updated)
return false;
writel(updated, reg);
return true;
}
static void intel_restore_hostown(struct intel_pinctrl *pctrl, unsigned int c,
void __iomem *base, unsigned int gpp, u32 saved)
{
const struct intel_community *community = &pctrl->communities[c];
const struct intel_padgroup *padgrp = &community->gpps[gpp];
struct device *dev = pctrl->dev;
u32 requested;
if (padgrp->gpio_base < 0)
return;
requested = intel_gpio_is_requested(&pctrl->chip, padgrp->gpio_base, padgrp->size);
if (!intel_gpio_update_reg(base + gpp * 4, requested, saved))
return;
dev_dbg(dev, "restored hostown %u/%u %#08x\n", c, gpp, readl(base + gpp * 4));
}
static void intel_restore_intmask(struct intel_pinctrl *pctrl, unsigned int c,
void __iomem *base, unsigned int gpp, u32 saved)
{
struct device *dev = pctrl->dev;
if (!intel_gpio_update_reg(base + gpp * 4, ~0U, saved))
return;
return curr;
dev_dbg(dev, "restored mask %u/%u %#08x\n", c, gpp, readl(base + gpp * 4));
}
static void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin,
unsigned int reg, u32 saved)
{
u32 mask = (reg == PADCFG0) ? PADCFG0_GPIORXSTATE : 0;
unsigned int n = reg / sizeof(u32);
struct device *dev = pctrl->dev;
void __iomem *padcfg;
padcfg = intel_get_padcfg(pctrl, pin, reg);
if (!padcfg)
return;
if (!intel_gpio_update_reg(padcfg, ~mask, saved))
return;
dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg));
}
int intel_pinctrl_resume_noirq(struct device *dev)
......@@ -1601,37 +1669,13 @@ int intel_pinctrl_resume_noirq(struct device *dev)
pads = pctrl->context.pads;
for (i = 0; i < pctrl->soc->npins; i++) {
const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
void __iomem *padcfg;
u32 val;
if (!intel_pinctrl_should_save(pctrl, desc->number))
continue;
padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0);
val = readl(padcfg) & ~PADCFG0_GPIORXSTATE;
if (val != pads[i].padcfg0) {
writel(pads[i].padcfg0, padcfg);
dev_dbg(dev, "restored pin %u padcfg0 %#08x\n",
desc->number, readl(padcfg));
}
padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG1);
val = readl(padcfg);
if (val != pads[i].padcfg1) {
writel(pads[i].padcfg1, padcfg);
dev_dbg(dev, "restored pin %u padcfg1 %#08x\n",
desc->number, readl(padcfg));
}
padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2);
if (padcfg) {
val = readl(padcfg);
if (val != pads[i].padcfg2) {
writel(pads[i].padcfg2, padcfg);
dev_dbg(dev, "restored pin %u padcfg2 %#08x\n",
desc->number, readl(padcfg));
}
}
intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0);
intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1);
intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2);
}
communities = pctrl->context.communities;
......@@ -1641,30 +1685,12 @@ int intel_pinctrl_resume_noirq(struct device *dev)
unsigned int gpp;
base = community->regs + community->ie_offset;
for (gpp = 0; gpp < community->ngpps; gpp++) {
writel(communities[i].intmask[gpp], base + gpp * 4);
dev_dbg(dev, "restored mask %d/%u %#08x\n", i, gpp,
readl(base + gpp * 4));
}
for (gpp = 0; gpp < community->ngpps; gpp++)
intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]);
base = community->regs + community->hostown_offset;
for (gpp = 0; gpp < community->ngpps; gpp++) {
const struct intel_padgroup *padgrp = &community->gpps[gpp];
u32 requested = 0, value = 0;
u32 saved = communities[i].hostown[gpp];
if (padgrp->gpio_base < 0)
continue;
requested = intel_gpio_is_requested(&pctrl->chip,
padgrp->gpio_base, padgrp->size);
value = intel_gpio_update_pad_mode(base + gpp * 4,
requested, saved);
if ((value ^ saved) & requested) {
dev_warn(dev, "restore hostown %d/%u %#8x->%#8x\n",
i, gpp, value, saved);
}
}
for (gpp = 0; gpp < community->ngpps; gpp++)
intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[gpp]);
}
return 0;
......
This diff is collapsed.
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