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 ...@@ -115,4 +115,11 @@ config PINCTRL_SUNRISEPOINT
provides an interface that allows configuring of PCH pins and provides an interface that allows configuring of PCH pins and
using them as GPIOs. 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 endif
...@@ -13,3 +13,4 @@ obj-$(CONFIG_PINCTRL_GEMINILAKE) += pinctrl-geminilake.o ...@@ -13,3 +13,4 @@ obj-$(CONFIG_PINCTRL_GEMINILAKE) += pinctrl-geminilake.o
obj-$(CONFIG_PINCTRL_ICELAKE) += pinctrl-icelake.o obj-$(CONFIG_PINCTRL_ICELAKE) += pinctrl-icelake.o
obj-$(CONFIG_PINCTRL_LEWISBURG) += pinctrl-lewisburg.o obj-$(CONFIG_PINCTRL_LEWISBURG) += pinctrl-lewisburg.o
obj-$(CONFIG_PINCTRL_SUNRISEPOINT) += pinctrl-sunrisepoint.o obj-$(CONFIG_PINCTRL_SUNRISEPOINT) += pinctrl-sunrisepoint.o
obj-$(CONFIG_PINCTRL_TIGERLAKE) += pinctrl-tigerlake.o
...@@ -147,6 +147,7 @@ struct chv_pin_context { ...@@ -147,6 +147,7 @@ struct chv_pin_context {
* @pctldesc: Pin controller description * @pctldesc: Pin controller description
* @pctldev: Pointer to the pin controller device * @pctldev: Pointer to the pin controller device
* @chip: GPIO chip in this pin controller * @chip: GPIO chip in this pin controller
* @irqchip: IRQ chip in this pin controller
* @regs: MMIO registers * @regs: MMIO registers
* @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
* offset (in GPIO number space) * offset (in GPIO number space)
...@@ -162,8 +163,9 @@ struct chv_pinctrl { ...@@ -162,8 +163,9 @@ struct chv_pinctrl {
struct pinctrl_desc pctldesc; struct pinctrl_desc pctldesc;
struct pinctrl_dev *pctldev; struct pinctrl_dev *pctldev;
struct gpio_chip chip; struct gpio_chip chip;
struct irq_chip irqchip;
void __iomem *regs; void __iomem *regs;
unsigned intr_lines[16]; unsigned int intr_lines[16];
const struct chv_community *community; const struct chv_community *community;
u32 saved_intmask; u32 saved_intmask;
struct chv_pin_context *saved_pin_context; struct chv_pin_context *saved_pin_context;
...@@ -377,7 +379,7 @@ static const struct chv_community southwest_community = { ...@@ -377,7 +379,7 @@ static const struct chv_community southwest_community = {
.gpio_ranges = southwest_gpio_ranges, .gpio_ranges = southwest_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(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 * first 8 interrupts. The upper half (8-15) can only be used to
* trigger GPEs. * trigger GPEs.
*/ */
...@@ -1466,16 +1468,6 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned int type) ...@@ -1466,16 +1468,6 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned int type)
return 0; 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) static void chv_gpio_irq_handler(struct irq_desc *desc)
{ {
struct gpio_chip *gc = irq_desc_get_handler_data(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) ...@@ -1488,7 +1480,7 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
pending = readl(pctrl->regs + CHV_INTSTAT); pending = readl(pctrl->regs + CHV_INTSTAT);
for_each_set_bit(intr_line, &pending, pctrl->community->nirqs) { for_each_set_bit(intr_line, &pending, pctrl->community->nirqs) {
unsigned irq, offset; unsigned int irq, offset;
offset = pctrl->intr_lines[intr_line]; offset = pctrl->intr_lines[intr_line];
irq = irq_find_mapping(gc->irq.domain, offset); irq = irq_find_mapping(gc->irq.domain, offset);
...@@ -1559,7 +1551,7 @@ static void chv_init_irq_valid_mask(struct gpio_chip *chip, ...@@ -1559,7 +1551,7 @@ static void chv_init_irq_valid_mask(struct gpio_chip *chip,
intsel >>= CHV_PADCTRL0_INTSEL_SHIFT; intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
if (intsel >= community->nirqs) 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) ...@@ -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); handle_bad_irq, IRQ_TYPE_NONE);
if (ret) { if (ret) {
dev_err(pctrl->dev, "failed to add IRQ chip\n"); 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) ...@@ -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); chv_gpio_irq_handler);
return 0; return 0;
} }
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#define PADCFG0_GPIROUTNMI BIT(17) #define PADCFG0_GPIROUTNMI BIT(17)
#define PADCFG0_PMODE_SHIFT 10 #define PADCFG0_PMODE_SHIFT 10
#define PADCFG0_PMODE_MASK GENMASK(13, 10) #define PADCFG0_PMODE_MASK GENMASK(13, 10)
#define PADCFG0_PMODE_GPIO 0
#define PADCFG0_GPIORXDIS BIT(9) #define PADCFG0_GPIORXDIS BIT(9)
#define PADCFG0_GPIOTXDIS BIT(8) #define PADCFG0_GPIOTXDIS BIT(8)
#define PADCFG0_GPIORXSTATE BIT(1) #define PADCFG0_GPIORXSTATE BIT(1)
...@@ -332,7 +333,7 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, ...@@ -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)); cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1));
mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
if (!mode) if (mode == PADCFG0_PMODE_GPIO)
seq_puts(s, "GPIO "); seq_puts(s, "GPIO ");
else else
seq_printf(s, "mode %d ", mode); seq_printf(s, "mode %d ", mode);
...@@ -458,6 +459,11 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) ...@@ -458,6 +459,11 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
writel(value, padcfg0); 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) static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
{ {
u32 value; u32 value;
...@@ -491,7 +497,20 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, ...@@ -491,7 +497,20 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
} }
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); 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); 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) */
__intel_gpio_set_direction(padcfg0, true); __intel_gpio_set_direction(padcfg0, true);
...@@ -1112,7 +1131,7 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, ...@@ -1112,7 +1131,7 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
pending &= enabled; pending &= enabled;
for_each_set_bit(gpp_offset, &pending, padgrp->size) { for_each_set_bit(gpp_offset, &pending, padgrp->size) {
unsigned irq; unsigned int irq;
irq = irq_find_mapping(gc->irq.domain, irq = irq_find_mapping(gc->irq.domain,
padgrp->gpio_base + gpp_offset); padgrp->gpio_base + gpp_offset);
...@@ -1162,7 +1181,7 @@ static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl, ...@@ -1162,7 +1181,7 @@ static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl,
return ret; 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; const struct intel_community *community;
unsigned int ngpio = 0; unsigned int ngpio = 0;
...@@ -1576,16 +1595,65 @@ intel_gpio_is_requested(struct gpio_chip *chip, int base, unsigned int size) ...@@ -1576,16 +1595,65 @@ intel_gpio_is_requested(struct gpio_chip *chip, int base, unsigned int size)
return requested; return requested;
} }
static u32 static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
intel_gpio_update_pad_mode(void __iomem *hostown, u32 mask, u32 value)
{ {
u32 curr, updated; u32 curr, updated;
curr = readl(hostown); curr = readl(reg);
updated = (curr & ~mask) | (value & mask); 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) int intel_pinctrl_resume_noirq(struct device *dev)
...@@ -1601,37 +1669,13 @@ int intel_pinctrl_resume_noirq(struct device *dev) ...@@ -1601,37 +1669,13 @@ int intel_pinctrl_resume_noirq(struct device *dev)
pads = pctrl->context.pads; pads = pctrl->context.pads;
for (i = 0; i < pctrl->soc->npins; i++) { for (i = 0; i < pctrl->soc->npins; i++) {
const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i]; const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
void __iomem *padcfg;
u32 val;
if (!intel_pinctrl_should_save(pctrl, desc->number)) if (!intel_pinctrl_should_save(pctrl, desc->number))
continue; continue;
padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0); intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0);
val = readl(padcfg) & ~PADCFG0_GPIORXSTATE; intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1);
if (val != pads[i].padcfg0) { intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2);
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));
}
}
} }
communities = pctrl->context.communities; communities = pctrl->context.communities;
...@@ -1641,30 +1685,12 @@ int intel_pinctrl_resume_noirq(struct device *dev) ...@@ -1641,30 +1685,12 @@ int intel_pinctrl_resume_noirq(struct device *dev)
unsigned int gpp; unsigned int gpp;
base = community->regs + community->ie_offset; base = community->regs + community->ie_offset;
for (gpp = 0; gpp < community->ngpps; gpp++) { for (gpp = 0; gpp < community->ngpps; gpp++)
writel(communities[i].intmask[gpp], base + gpp * 4); intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]);
dev_dbg(dev, "restored mask %d/%u %#08x\n", i, gpp,
readl(base + gpp * 4));
}
base = community->regs + community->hostown_offset; base = community->regs + community->hostown_offset;
for (gpp = 0; gpp < community->ngpps; gpp++) { for (gpp = 0; gpp < community->ngpps; gpp++)
const struct intel_padgroup *padgrp = &community->gpps[gpp]; intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[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);
}
}
} }
return 0; 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