intel-pinctrl for v5.17-3

* Intel Baytrail and Cherryview IRQ related fixes
 
 The following is an automated git shortlog grouped by driver:
 
 baytrail:
  -  Set IRQCHIP_SET_TYPE_MASKED flag on the irqchip
 
 cherryview:
  -  Use temporary variable for struct device
  -  Do not allow the same interrupt line to be used by 2 pins
  -  Don't use selection 0 to mark an interrupt line as unused
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEqaflIX74DDDzMJJtb7wzTHR8rCgFAmG6DMEACgkQb7wzTHR8
 rCjNaw/+MnE7sIpBZ1143N+T7qidGSLZkOW13OQOnreSIhjUVRrxFGAj5Iy6kRJA
 dIsZn/ALXiAlfM1iFar9vhVLznoA9uzfWRu3mfTmCfmgiv+N2XDMg+bVrwoHf5s3
 FLrTuNJKL34MAXAuTgIaGWEcpAwfrYUwY0saka3fgsj70lE8/+WWG7ZxU57E3ra4
 /q+2QGM/3oyqe1R2n9TJbrsWUS2aXZE3EMWzyiAmWJcsC9cbYjKBz75mpuyysBAH
 chikafxJ9aovhQhtus6Hbnq2IsD3G0FpOinhZRsArZoIntEgXO/GDNDvulY9qB8Z
 anJHRjCD8rPv8dJk9XK+ad/uqkPZct1IpbtWSnl9s1T4Gf+SJGrEd61Kyc7Pau9h
 4IMINIlCTqmPKyw7qEIsbGlQfTtvhAhNT3uRbQDjKyde+HhVtYEngwcPWGyFAPNx
 rj39KYkekcENZ+IQzhKmLJ3/LxFwiiU3lYtOU9oa1Xulfa/BHtdaBCbUIjuenXF6
 FKJkBfqHtwE3xOIH42F9ETA9zv8alVMp6kOt4JMTY7DNyKCzaHRM4KPWT9m1NaDa
 JF8djmjVIQzl102MQKJxjE4y3RWyHH3e/V+itFBE/142t8CR4XTJdUgkZzGqo6V3
 aGvr4oyia66b4sKureuvYLnEHnHFH2lxbgyg4YuSczwEKCvyBFo=
 =8Crg
 -----END PGP SIGNATURE-----

Merge tag 'intel-pinctrl-v5.17-3' of gitolite.kernel.org:pub/scm/linux/kernel/git/pinctrl/intel into devel

intel-pinctrl for v5.17-3

* Intel Baytrail and Cherryview IRQ related fixes

The following is an automated git shortlog grouped by driver:

baytrail:
 -  Set IRQCHIP_SET_TYPE_MASKED flag on the irqchip

cherryview:
 -  Use temporary variable for struct device
 -  Do not allow the same interrupt line to be used by 2 pins
 -  Don't use selection 0 to mark an interrupt line as unused
This commit is contained in:
Linus Walleij 2021-12-16 04:20:06 +01:00
commit f9b94d2426
2 changed files with 100 additions and 32 deletions

View File

@ -1577,7 +1577,7 @@ static int byt_gpio_probe(struct intel_pinctrl *vg)
vg->irqchip.irq_mask = byt_irq_mask,
vg->irqchip.irq_unmask = byt_irq_unmask,
vg->irqchip.irq_set_type = byt_irq_type,
vg->irqchip.flags = IRQCHIP_SKIP_SET_WAKE,
vg->irqchip.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED,
girq = &gc->irq;
girq->chip = &vg->irqchip;

View File

@ -73,6 +73,8 @@ struct intel_pad_context {
u32 padctrl1;
};
#define CHV_INVALID_HWIRQ ((unsigned int)INVALID_HWIRQ)
/**
* struct intel_community_context - community context for Cherryview
* @intr_lines: Mapping between 16 HW interrupt wires and GPIO offset (in GPIO number space)
@ -709,6 +711,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int function, unsigned int group)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
struct device *dev = pctrl->dev;
const struct intel_pingroup *grp;
unsigned long flags;
int i;
@ -720,9 +723,8 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
/* Check first that the pad is not locked */
for (i = 0; i < grp->npins; i++) {
if (chv_pad_locked(pctrl, grp->pins[i])) {
dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n",
grp->pins[i]);
raw_spin_unlock_irqrestore(&chv_lock, flags);
dev_warn(dev, "unable to set mode for locked pin %u\n", grp->pins[i]);
return -EBUSY;
}
}
@ -757,8 +759,8 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
value |= CHV_PADCTRL1_INVRXTX_TXENABLE;
chv_writel(pctrl, pin, CHV_PADCTRL1, value);
dev_dbg(pctrl->dev, "configured pin %u mode %u OE %sinverted\n",
pin, mode, invert_oe ? "" : "not ");
dev_dbg(dev, "configured pin %u mode %u OE %sinverted\n", pin, mode,
invert_oe ? "" : "not ");
}
raw_spin_unlock_irqrestore(&chv_lock, flags);
@ -812,7 +814,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
/* Reset the interrupt mapping */
for (i = 0; i < ARRAY_SIZE(cctx->intr_lines); i++) {
if (cctx->intr_lines[i] == offset) {
cctx->intr_lines[i] = 0;
cctx->intr_lines[i] = CHV_INVALID_HWIRQ;
break;
}
}
@ -1058,6 +1060,7 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, unsigned int nconfigs)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
struct device *dev = pctrl->dev;
enum pin_config_param param;
int i, ret;
u32 arg;
@ -1094,8 +1097,7 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
return -ENOTSUPP;
}
dev_dbg(pctrl->dev, "pin %d set config %d arg %u\n", pin,
param, arg);
dev_dbg(dev, "pin %d set config %d arg %u\n", pin, param, arg);
}
return 0;
@ -1302,6 +1304,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
struct device *dev = pctrl->dev;
struct intel_community_context *cctx = &pctrl->context.communities[0];
unsigned int pin = irqd_to_hwirq(d);
irq_flow_handler_t handler;
@ -1319,8 +1322,10 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
else
handler = handle_edge_irq;
if (!cctx->intr_lines[intsel]) {
if (cctx->intr_lines[intsel] == CHV_INVALID_HWIRQ) {
irq_set_handler_locked(d, handler);
dev_dbg(dev, "using interrupt line %u for IRQ_TYPE_NONE on pin %u\n",
intsel, pin);
cctx->intr_lines[intsel] = pin;
}
raw_spin_unlock_irqrestore(&chv_lock, flags);
@ -1330,17 +1335,74 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
return 0;
}
static int chv_gpio_set_intr_line(struct intel_pinctrl *pctrl, unsigned int pin)
{
struct device *dev = pctrl->dev;
struct intel_community_context *cctx = &pctrl->context.communities[0];
const struct intel_community *community = &pctrl->communities[0];
u32 value, intsel;
int i;
value = chv_readl(pctrl, pin, CHV_PADCTRL0);
intsel = (value & CHV_PADCTRL0_INTSEL_MASK) >> CHV_PADCTRL0_INTSEL_SHIFT;
if (cctx->intr_lines[intsel] == pin)
return 0;
if (cctx->intr_lines[intsel] == CHV_INVALID_HWIRQ) {
dev_dbg(dev, "using interrupt line %u for pin %u\n", intsel, pin);
cctx->intr_lines[intsel] = pin;
return 0;
}
/*
* The interrupt line selected by the BIOS is already in use by
* another pin, this is a known BIOS bug found on several models.
* But this may also be caused by Linux deciding to use a pin as
* IRQ which was not expected to be used as such by the BIOS authors,
* so log this at info level only.
*/
dev_info(dev, "interrupt line %u is used by both pin %u and pin %u\n", intsel,
cctx->intr_lines[intsel], pin);
if (chv_pad_locked(pctrl, pin))
return -EBUSY;
/*
* The BIOS fills the interrupt lines from 0 counting up, start at
* the other end to find a free interrupt line to workaround this.
*/
for (i = community->nirqs - 1; i >= 0; i--) {
if (cctx->intr_lines[i] == CHV_INVALID_HWIRQ)
break;
}
if (i < 0)
return -EBUSY;
dev_info(dev, "changing the interrupt line for pin %u to %d\n", pin, i);
value = (value & ~CHV_PADCTRL0_INTSEL_MASK) | (i << CHV_PADCTRL0_INTSEL_SHIFT);
chv_writel(pctrl, pin, CHV_PADCTRL0, value);
cctx->intr_lines[i] = pin;
return 0;
}
static int chv_gpio_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
struct intel_community_context *cctx = &pctrl->context.communities[0];
unsigned int pin = irqd_to_hwirq(d);
unsigned long flags;
u32 value;
int ret;
raw_spin_lock_irqsave(&chv_lock, flags);
ret = chv_gpio_set_intr_line(pctrl, pin);
if (ret)
goto out_unlock;
/*
* Pins which can be used as shared interrupt are configured in
* BIOS. Driver trusts BIOS configurations and assigns different
@ -1375,26 +1437,22 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned int type)
chv_writel(pctrl, pin, CHV_PADCTRL1, value);
}
value = chv_readl(pctrl, pin, CHV_PADCTRL0);
value &= CHV_PADCTRL0_INTSEL_MASK;
value >>= CHV_PADCTRL0_INTSEL_SHIFT;
cctx->intr_lines[value] = pin;
if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
else if (type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(d, handle_level_irq);
out_unlock:
raw_spin_unlock_irqrestore(&chv_lock, flags);
return 0;
return ret;
}
static void chv_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
struct device *dev = pctrl->dev;
const struct intel_community *community = &pctrl->communities[0];
struct intel_community_context *cctx = &pctrl->context.communities[0];
struct irq_chip *chip = irq_desc_get_chip(desc);
@ -1412,6 +1470,11 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
unsigned int offset;
offset = cctx->intr_lines[intr_line];
if (offset == CHV_INVALID_HWIRQ) {
dev_err(dev, "interrupt on unused interrupt line %u\n", intr_line);
continue;
}
generic_handle_domain_irq(gc->irq.domain, offset);
}
@ -1512,17 +1575,16 @@ static int chv_gpio_irq_init_hw(struct gpio_chip *chip)
static int chv_gpio_add_pin_ranges(struct gpio_chip *chip)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
struct device *dev = pctrl->dev;
const struct intel_community *community = &pctrl->communities[0];
const struct intel_padgroup *gpp;
int ret, i;
for (i = 0; i < community->ngpps; i++) {
gpp = &community->gpps[i];
ret = gpiochip_add_pin_range(chip, dev_name(pctrl->dev),
gpp->base, gpp->base,
gpp->size);
ret = gpiochip_add_pin_range(chip, dev_name(dev), gpp->base, gpp->base, gpp->size);
if (ret) {
dev_err(pctrl->dev, "failed to add GPIO pin range\n");
dev_err(dev, "failed to add GPIO pin range\n");
return ret;
}
}
@ -1535,15 +1597,16 @@ static int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq)
const struct intel_community *community = &pctrl->communities[0];
const struct intel_padgroup *gpp;
struct gpio_chip *chip = &pctrl->chip;
struct device *dev = pctrl->dev;
bool need_valid_mask = !dmi_check_system(chv_no_valid_mask);
int ret, i, irq_base;
*chip = chv_gpio_chip;
chip->ngpio = pctrl->soc->pins[pctrl->soc->npins - 1].number + 1;
chip->label = dev_name(pctrl->dev);
chip->label = dev_name(dev);
chip->add_pin_ranges = chv_gpio_add_pin_ranges;
chip->parent = pctrl->dev;
chip->parent = dev;
chip->base = -1;
pctrl->irq = irq;
@ -1565,17 +1628,16 @@ static int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq)
if (need_valid_mask) {
chip->irq.init_valid_mask = chv_init_irq_valid_mask;
} else {
irq_base = devm_irq_alloc_descs(pctrl->dev, -1, 0,
pctrl->soc->npins, NUMA_NO_NODE);
irq_base = devm_irq_alloc_descs(dev, -1, 0, pctrl->soc->npins, NUMA_NO_NODE);
if (irq_base < 0) {
dev_err(pctrl->dev, "Failed to allocate IRQ numbers\n");
dev_err(dev, "Failed to allocate IRQ numbers\n");
return irq_base;
}
}
ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
ret = devm_gpiochip_add_data(dev, chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "Failed to register gpiochip\n");
dev_err(dev, "Failed to register gpiochip\n");
return ret;
}
@ -1617,11 +1679,13 @@ static acpi_status chv_pinctrl_mmio_access_handler(u32 function,
static int chv_pinctrl_probe(struct platform_device *pdev)
{
const struct intel_pinctrl_soc_data *soc_data;
struct intel_community_context *cctx;
struct intel_community *community;
struct device *dev = &pdev->dev;
struct acpi_device *adev = ACPI_COMPANION(dev);
struct intel_pinctrl *pctrl;
acpi_status status;
unsigned int i;
int ret, irq;
soc_data = intel_pinctrl_get_soc_data(pdev);
@ -1663,6 +1727,10 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
if (!pctrl->context.communities)
return -ENOMEM;
cctx = &pctrl->context.communities[0];
for (i = 0; i < ARRAY_SIZE(cctx->intr_lines); i++)
cctx->intr_lines[i] = CHV_INVALID_HWIRQ;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@ -1767,15 +1835,15 @@ static int chv_pinctrl_resume_noirq(struct device *dev)
val &= ~CHV_PADCTRL0_GPIORXSTATE;
if (ctx->padctrl0 != val) {
chv_writel(pctrl, desc->number, CHV_PADCTRL0, ctx->padctrl0);
dev_dbg(pctrl->dev, "restored pin %2u ctrl0 0x%08x\n",
desc->number, chv_readl(pctrl, desc->number, CHV_PADCTRL0));
dev_dbg(dev, "restored pin %2u ctrl0 0x%08x\n", desc->number,
chv_readl(pctrl, desc->number, CHV_PADCTRL0));
}
val = chv_readl(pctrl, desc->number, CHV_PADCTRL1);
if (ctx->padctrl1 != val) {
chv_writel(pctrl, desc->number, CHV_PADCTRL1, ctx->padctrl1);
dev_dbg(pctrl->dev, "restored pin %2u ctrl1 0x%08x\n",
desc->number, chv_readl(pctrl, desc->number, CHV_PADCTRL1));
dev_dbg(dev, "restored pin %2u ctrl1 0x%08x\n", desc->number,
chv_readl(pctrl, desc->number, CHV_PADCTRL1));
}
}