* [PATCH v2 1/3] pinctrl: amd: Centralize per-pin register access
2026-09-21 5:27 [PATCH v2 0/3] pinctrl: amd: Add Remote GPIO (RGPIO) bank support Basavaraj Natikar
@ 2026-09-21 5:27 ` Basavaraj Natikar
2026-09-21 5:27 ` [PATCH v2 2/3] pinctrl: amd: Factor out optional named resource lookup Basavaraj Natikar
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Basavaraj Natikar @ 2026-09-21 5:27 UTC (permalink / raw)
To: linusw
Cc: Shyam-sundar.S-k, Matt.Devillier, Guruvendra.Punugupati,
linux-gpio, Basavaraj Natikar
Add a helper to translate a pin into its per-pin register address and
use it at every per-pin access, so a second GPIO bank added later can
be addressed from a single place. No functional change.
Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
---
drivers/pinctrl/pinctrl-amd.c | 85 ++++++++++++++++++-----------------
1 file changed, 44 insertions(+), 41 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 65728b590999..543733c2aae0 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -40,6 +40,11 @@
static struct amd_gpio *pinctrl_dev;
#endif
+static inline void __iomem *amd_gpio_pin_reg(struct amd_gpio *gpio_dev, unsigned int pin)
+{
+ return gpio_dev->base + pin * 4;
+}
+
static int amd_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
{
unsigned long flags;
@@ -47,7 +52,7 @@ static int amd_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + offset * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, offset));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
if (pin_reg & BIT(OUTPUT_ENABLE_OFF))
@@ -63,9 +68,9 @@ static int amd_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + offset * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, offset));
pin_reg &= ~BIT(OUTPUT_ENABLE_OFF);
- writel(pin_reg, gpio_dev->base + offset * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, offset));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
return 0;
@@ -79,13 +84,13 @@ static int amd_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + offset * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, offset));
pin_reg |= BIT(OUTPUT_ENABLE_OFF);
if (value)
pin_reg |= BIT(OUTPUT_VALUE_OFF);
else
pin_reg &= ~BIT(OUTPUT_VALUE_OFF);
- writel(pin_reg, gpio_dev->base + offset * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, offset));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
return 0;
@@ -98,7 +103,7 @@ static int amd_gpio_get_value(struct gpio_chip *gc, unsigned offset)
struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + offset * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, offset));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
return !!(pin_reg & BIT(PIN_STS_OFF));
@@ -112,12 +117,12 @@ static int amd_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + offset * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, offset));
if (value)
pin_reg |= BIT(OUTPUT_VALUE_OFF);
else
pin_reg &= ~BIT(OUTPUT_VALUE_OFF);
- writel(pin_reg, gpio_dev->base + offset * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, offset));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
return 0;
@@ -137,7 +142,7 @@ static int amd_gpio_set_debounce(struct amd_gpio *gpio_dev, unsigned int offset,
debounce = 0;
}
- pin_reg = readl(gpio_dev->base + offset * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, offset));
if (debounce) {
pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF;
@@ -186,7 +191,7 @@ static int amd_gpio_set_debounce(struct amd_gpio *gpio_dev, unsigned int offset,
pin_reg &= ~DB_TMR_OUT_MASK;
pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF);
}
- writel(pin_reg, gpio_dev->base + offset * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, offset));
return ret;
}
@@ -248,7 +253,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
for (; i < pin_num; i++) {
seq_printf(s, "#%d\t", i);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + i * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, i));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) {
@@ -387,10 +392,10 @@ static void amd_gpio_irq_enable(struct irq_data *d)
gpiochip_enable_irq(gc, hwirq);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + hwirq * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, hwirq));
pin_reg |= BIT(INTERRUPT_ENABLE_OFF);
pin_reg |= BIT(INTERRUPT_MASK_OFF);
- writel(pin_reg, gpio_dev->base + hwirq * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, hwirq));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
@@ -403,10 +408,10 @@ static void amd_gpio_irq_disable(struct irq_data *d)
irq_hw_number_t hwirq = irqd_to_hwirq(d);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + hwirq * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, hwirq));
pin_reg &= ~BIT(INTERRUPT_ENABLE_OFF);
pin_reg &= ~BIT(INTERRUPT_MASK_OFF);
- writel(pin_reg, gpio_dev->base + hwirq * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, hwirq));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
gpiochip_disable_irq(gc, hwirq);
@@ -421,9 +426,9 @@ static void amd_gpio_irq_mask(struct irq_data *d)
irq_hw_number_t hwirq = irqd_to_hwirq(d);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + hwirq * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, hwirq));
pin_reg &= ~BIT(INTERRUPT_MASK_OFF);
- writel(pin_reg, gpio_dev->base + hwirq * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, hwirq));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
@@ -436,9 +441,9 @@ static void amd_gpio_irq_unmask(struct irq_data *d)
irq_hw_number_t hwirq = irqd_to_hwirq(d);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + hwirq * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, hwirq));
pin_reg |= BIT(INTERRUPT_MASK_OFF);
- writel(pin_reg, gpio_dev->base + hwirq * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, hwirq));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
@@ -456,14 +461,14 @@ static int amd_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
hwirq, str_enable_disable(on));
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + hwirq * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, hwirq));
if (on)
pin_reg |= wake_mask;
else
pin_reg &= ~wake_mask;
- writel(pin_reg, gpio_dev->base + hwirq * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, hwirq));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
if (on)
@@ -502,7 +507,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type)
irq_hw_number_t hwirq = irqd_to_hwirq(d);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + hwirq * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, hwirq));
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING:
@@ -568,11 +573,11 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type)
pin_reg_irq_en = pin_reg;
pin_reg_irq_en |= mask;
pin_reg_irq_en &= ~BIT(INTERRUPT_MASK_OFF);
- writel(pin_reg_irq_en, gpio_dev->base + hwirq * 4);
- if (readl_poll_timeout_atomic(gpio_dev->base + hwirq * 4, reg,
+ writel(pin_reg_irq_en, amd_gpio_pin_reg(gpio_dev, hwirq));
+ if (readl_poll_timeout_atomic(amd_gpio_pin_reg(gpio_dev, hwirq), reg,
(reg & mask) == mask, 1, 1000))
ret = -ETIMEDOUT;
- writel(pin_reg, gpio_dev->base + hwirq * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, hwirq));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
return ret;
@@ -615,7 +620,6 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
struct gpio_chip *gc = &gpio_dev->gc;
unsigned int i, irqnr;
unsigned long flags;
- u32 __iomem *regs;
bool ret = false;
u32 regval;
u64 status, mask;
@@ -629,15 +633,14 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
/* Bit 0-45 contain the relevant status bits */
status &= (1ULL << 46) - 1;
- regs = gpio_dev->base;
- for (mask = 1, irqnr = 0; status; mask <<= 1, regs += 4, irqnr += 4) {
+ for (mask = 1, irqnr = 0; status; mask <<= 1, irqnr += 4) {
if (!(status & mask))
continue;
status &= ~mask;
/* Each status bit covers four pins */
for (i = 0; i < 4; i++) {
- regval = readl(regs + i);
+ regval = readl(amd_gpio_pin_reg(gpio_dev, irqnr + i));
if (regval & PIN_IRQ_PENDING)
pm_pr_dbg("GPIO %d is active: 0x%x",
@@ -660,7 +663,7 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
* avoid a system hang caused by an interrupt storm.
*/
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- regval = readl(regs + i);
+ regval = readl(amd_gpio_pin_reg(gpio_dev, irqnr + i));
if (!gpiochip_line_is_irq(gc, irqnr + i)) {
regval &= ~BIT(INTERRUPT_MASK_OFF);
dev_dbg(&gpio_dev->pdev->dev,
@@ -669,7 +672,7 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
} else {
ret = true;
}
- writel(regval, regs + i);
+ writel(regval, amd_gpio_pin_reg(gpio_dev, irqnr + i));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
}
@@ -745,7 +748,7 @@ static int amd_pinconf_get(struct pinctrl_dev *pctldev,
enum pin_config_param param = pinconf_to_config_param(*config);
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + pin*4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, pin));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
switch (param) {
case PIN_CONFIG_INPUT_DEBOUNCE:
@@ -790,7 +793,7 @@ static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
- pin_reg = readl(gpio_dev->base + pin*4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, pin));
switch (param) {
case PIN_CONFIG_INPUT_DEBOUNCE:
@@ -820,7 +823,7 @@ static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
ret = -ENOTSUPP;
}
- writel(pin_reg, gpio_dev->base + pin*4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, pin));
}
out_unlock:
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
@@ -897,9 +900,9 @@ static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- pin_reg = readl(gpio_dev->base + pin * 4);
+ pin_reg = readl(amd_gpio_pin_reg(gpio_dev, pin));
pin_reg &= ~mask;
- writel(pin_reg, gpio_dev->base + pin * 4);
+ writel(pin_reg, amd_gpio_pin_reg(gpio_dev, pin));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
@@ -919,7 +922,7 @@ static void amd_gpio_check_pending(void)
int pin = desc->pins[i].number;
u32 tmp;
- tmp = readl(gpio_dev->base + pin * 4);
+ tmp = readl(amd_gpio_pin_reg(gpio_dev, pin));
if (tmp & PIN_IRQ_PENDING)
pm_pr_dbg("%s: GPIO %d is active: 0x%x.\n", __func__, pin, tmp);
}
@@ -977,12 +980,12 @@ static int amd_gpio_suspend_hibernate_common(struct device *dev, bool is_suspend
continue;
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin * 4) & ~PIN_IRQ_PENDING;
+ gpio_dev->saved_regs[i] = readl(amd_gpio_pin_reg(gpio_dev, pin)) & ~PIN_IRQ_PENDING;
/* mask any interrupts not intended to be a wake source */
if (!(gpio_dev->saved_regs[i] & wake_mask)) {
writel(gpio_dev->saved_regs[i] & ~BIT(INTERRUPT_MASK_OFF),
- gpio_dev->base + pin * 4);
+ amd_gpio_pin_reg(gpio_dev, pin));
pm_pr_dbg("Disabling GPIO #%d interrupt for %s.\n",
pin, is_suspend ? "suspend" : "hibernate");
}
@@ -1031,8 +1034,8 @@ static int amd_gpio_resume(struct device *dev)
continue;
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
- gpio_dev->saved_regs[i] |= readl(gpio_dev->base + pin * 4) & PIN_IRQ_PENDING;
- writel(gpio_dev->saved_regs[i], gpio_dev->base + pin * 4);
+ gpio_dev->saved_regs[i] |= readl(amd_gpio_pin_reg(gpio_dev, pin)) & PIN_IRQ_PENDING;
+ writel(gpio_dev->saved_regs[i], amd_gpio_pin_reg(gpio_dev, pin));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 3/3] pinctrl: amd: Add support for the Remote GPIO (RGPIO) bank
2026-09-21 5:27 [PATCH v2 0/3] pinctrl: amd: Add Remote GPIO (RGPIO) bank support Basavaraj Natikar
2026-09-21 5:27 ` [PATCH v2 1/3] pinctrl: amd: Centralize per-pin register access Basavaraj Natikar
2026-09-21 5:27 ` [PATCH v2 2/3] pinctrl: amd: Factor out optional named resource lookup Basavaraj Natikar
@ 2026-09-21 5:27 ` Basavaraj Natikar
2026-10-01 6:48 ` [PATCH v2 0/3] pinctrl: amd: Add Remote GPIO (RGPIO) bank support Linus Walleij
3 siblings, 0 replies; 6+ messages in thread
From: Basavaraj Natikar @ 2026-09-21 5:27 UTC (permalink / raw)
To: linusw
Cc: Shyam-sundar.S-k, Matt.Devillier, Guruvendra.Punugupati,
linux-gpio, Basavaraj Natikar
Some AMD platforms expose a second GPIO bank, Remote GPIO (RGPIO),
covering pins 256-271 through a separate register region advertised by
name. Add support for these pins, including their interrupts, when the
region is advertised and the main bank spans the expected number of
registers, so they are usable like the main bank pins. The RGPIO pins
stay inactive on platforms that do not expose the region.
Co-developed-by: Matt DeVillier <Matt.Devillier@amd.com>
Signed-off-by: Matt DeVillier <Matt.Devillier@amd.com>
Co-developed-by: Guruvendra Punugupati <Guruvendra.Punugupati@amd.com>
Signed-off-by: Guruvendra Punugupati <Guruvendra.Punugupati@amd.com>
Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
---
drivers/pinctrl/pinctrl-amd.c | 121 ++++++++++++++++++++++-
drivers/pinctrl/pinctrl-amd.h | 174 ++++++++++++++++++++++++++++++++++
2 files changed, 292 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 18fce75fe86c..e8b9a8e57149 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -42,6 +42,8 @@ static struct amd_gpio *pinctrl_dev;
static inline void __iomem *amd_gpio_pin_reg(struct amd_gpio *gpio_dev, unsigned int pin)
{
+ if (gpio_dev->base_rgpio && pin >= AMD_GPIO_RGPIO_PIN_BASE)
+ return gpio_dev->base_rgpio + (pin - AMD_GPIO_RGPIO_PIN_BASE) * 4;
return gpio_dev->base + pin * 4;
}
@@ -244,6 +246,10 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
i = 192;
pin_num = AMD_GPIO_PINS_BANK3 + i;
break;
+ case 4:
+ i = AMD_GPIO_RGPIO_PIN_BASE;
+ pin_num = AMD_GPIO_PINS_BANK4 + i;
+ break;
default:
/* Illegal bank number, ignore */
continue;
@@ -676,6 +682,58 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id)
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
}
+
+ /*
+ * Unlike WAKE_INT_STATUS_REG0/1, where each status bit covers four
+ * pins, the RGPIO status register uses one bit per pin. As with the
+ * main bank status registers, a bit is cleared by acknowledging the
+ * pending interrupt on its pin below (clearing PIN_IRQ_PENDING); no
+ * separate write to the RGPIO status register is required.
+ */
+ if (gpio_dev->base_rgpio) {
+ u32 status_rgpio;
+
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+ status_rgpio = readl(gpio_dev->base_rgpio + WAKE_INT_STATUS_REG_RGPIO);
+ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
+
+ status_rgpio &= GENMASK(AMD_GPIO_PINS_BANK4 - 1, 0);
+
+ for (i = 0; i < AMD_GPIO_PINS_BANK4; i++) {
+ unsigned int pin = AMD_GPIO_RGPIO_PIN_BASE + i;
+
+ if (!(status_rgpio & BIT(i)))
+ continue;
+
+ regval = readl(amd_gpio_pin_reg(gpio_dev, pin));
+
+ if (regval & PIN_IRQ_PENDING)
+ pm_pr_dbg("GPIO %d is active: 0x%x", pin, regval);
+
+ /* caused wake on resume context for shared IRQ */
+ if (irq < 0 && (regval & BIT(WAKE_STS_OFF)))
+ return true;
+
+ if (!(regval & PIN_IRQ_PENDING) ||
+ !(regval & BIT(INTERRUPT_MASK_OFF)))
+ continue;
+ generic_handle_domain_irq_safe(gc->irq.domain, pin);
+
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+ regval = readl(amd_gpio_pin_reg(gpio_dev, pin));
+ if (!gpiochip_line_is_irq(gc, pin)) {
+ regval &= ~BIT(INTERRUPT_MASK_OFF);
+ dev_dbg(&gpio_dev->pdev->dev,
+ "Disabling spurious GPIO IRQ %d\n",
+ pin);
+ } else {
+ ret = true;
+ }
+ writel(regval, amd_gpio_pin_reg(gpio_dev, pin));
+ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
+ }
+ }
+
/* did not cause wake on resume context for shared IRQ */
if (irq < 0)
return false;
@@ -747,6 +805,9 @@ static int amd_pinconf_get(struct pinctrl_dev *pctldev,
struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
+ if (pin >= AMD_GPIO_RGPIO_PIN_BASE && !gpio_dev->base_rgpio)
+ return -EOPNOTSUPP;
+
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(amd_gpio_pin_reg(gpio_dev, pin));
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
@@ -789,6 +850,9 @@ static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
enum pin_config_param param;
struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev);
+ if (pin >= AMD_GPIO_RGPIO_PIN_BASE && !gpio_dev->base_rgpio)
+ return -EOPNOTSUPP;
+
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
@@ -898,6 +962,9 @@ static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
if (!pd)
continue;
+ if (pin >= AMD_GPIO_RGPIO_PIN_BASE && !gpio_dev->base_rgpio)
+ continue;
+
raw_spin_lock_irqsave(&gpio_dev->lock, flags);
pin_reg = readl(amd_gpio_pin_reg(gpio_dev, pin));
@@ -922,6 +989,9 @@ static void amd_gpio_check_pending(void)
int pin = desc->pins[i].number;
u32 tmp;
+ if (pin >= AMD_GPIO_RGPIO_PIN_BASE && !gpio_dev->base_rgpio)
+ continue;
+
tmp = readl(amd_gpio_pin_reg(gpio_dev, pin));
if (tmp & PIN_IRQ_PENDING)
pm_pr_dbg("%s: GPIO %d is active: 0x%x.\n", __func__, pin, tmp);
@@ -1068,7 +1138,8 @@ static int amd_get_groups(struct pinctrl_dev *pctrldev, unsigned int selector,
{
struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctrldev);
- if (!gpio_dev->iomux_base) {
+ if (!gpio_dev->iomux_base &&
+ pmx_functions[selector].index < AMD_GPIO_RGPIO_PIN_BASE) {
dev_err(&gpio_dev->pdev->dev, "iomux function %d group not supported\n", selector);
return -EINVAL;
}
@@ -1084,6 +1155,34 @@ static int amd_set_mux(struct pinctrl_dev *pctrldev, unsigned int function, unsi
struct device *dev = &gpio_dev->pdev->dev;
struct pin_desc *pd;
int ind, index;
+ unsigned int pin = gpio_dev->groups[group].pins[0];
+
+ if (pin >= AMD_GPIO_RGPIO_PIN_BASE) {
+ if (!gpio_dev->base_rgpio)
+ return -EINVAL;
+
+ for (index = 0; index < NSELECTS; index++)
+ if (!strcmp(gpio_dev->groups[group].name,
+ pmx_functions[function].groups[index]))
+ break;
+ if (index >= NSELECTS)
+ return -EINVAL;
+
+ writeb(index, gpio_dev->base_rgpio + AMD_GPIO_RGPIO_MUX_OFFSET +
+ (pin - AMD_GPIO_RGPIO_PIN_BASE));
+
+ if (index != (readb(gpio_dev->base_rgpio + AMD_GPIO_RGPIO_MUX_OFFSET +
+ (pin - AMD_GPIO_RGPIO_PIN_BASE)) & FUNCTION_MASK)) {
+ dev_err(dev, "RGPIO_GPIO %u mux not present or supported\n", pin);
+ return -EINVAL;
+ }
+
+ for (ind = 0; ind < gpio_dev->groups[group].npins; ind++) {
+ pd = pin_desc_get(gpio_dev->pctrl, gpio_dev->groups[group].pins[ind]);
+ pd->mux_owner = gpio_dev->groups[group].name;
+ }
+ return 0;
+ }
if (!gpio_dev->iomux_base)
return -EINVAL;
@@ -1184,6 +1283,19 @@ static int amd_gpio_probe(struct platform_device *pdev)
return PTR_ERR(gpio_dev->base);
}
+ gpio_dev->base_rgpio = amd_get_named_res(&pdev->dev, pdev, "rgpio",
+ WAKE_INT_STATUS_REG_RGPIO + sizeof(u32));
+ /*
+ * RGPIO pins are numbered from AMD_GPIO_RGPIO_PIN_BASE, so the main
+ * bank must span exactly that many register slots for the RGPIO pin
+ * numbering to line up. Disable RGPIO if the main bank is a different
+ * size.
+ */
+ if (gpio_dev->base_rgpio && resource_size(res) / 4 != AMD_GPIO_RGPIO_PIN_BASE) {
+ dev_err(&pdev->dev, "unexpected GPIO bank size, disabling RGPIO\n");
+ gpio_dev->base_rgpio = NULL;
+ }
+
gpio_dev->irq = platform_get_irq(pdev, 0);
if (gpio_dev->irq < 0)
return gpio_dev->irq;
@@ -1210,14 +1322,17 @@ static int amd_gpio_probe(struct platform_device *pdev)
gpio_dev->gc.owner = THIS_MODULE;
gpio_dev->gc.parent = &pdev->dev;
gpio_dev->gc.ngpio = resource_size(res) / 4;
-
gpio_dev->hwbank_num = gpio_dev->gc.ngpio / 64;
+ if (gpio_dev->base_rgpio) {
+ gpio_dev->gc.ngpio += AMD_GPIO_PINS_BANK4;
+ gpio_dev->hwbank_num++;
+ }
gpio_dev->groups = kerncz_groups;
gpio_dev->ngroups = ARRAY_SIZE(kerncz_groups);
amd_pinctrl_desc.name = dev_name(&pdev->dev);
gpio_dev->iomux_base = amd_get_named_res(&pdev->dev, pdev, "iomux", 0);
- if (!gpio_dev->iomux_base)
+ if (!gpio_dev->iomux_base && !gpio_dev->base_rgpio)
amd_pinctrl_desc.pmxops = NULL;
gpio_dev->pctrl = devm_pinctrl_register(&pdev->dev, &amd_pinctrl_desc,
gpio_dev);
diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h
index 3a1e5bffaf6e..c602c4b648bd 100644
--- a/drivers/pinctrl/pinctrl-amd.h
+++ b/drivers/pinctrl/pinctrl-amd.h
@@ -15,6 +15,18 @@
#define AMD_GPIO_PINS_BANK1 64
#define AMD_GPIO_PINS_BANK2 56
#define AMD_GPIO_PINS_BANK3 32
+#define AMD_GPIO_PINS_BANK4 16
+
+/*
+ * Remote GPIO (RGPIO) is a second GPIO bank on some AMD platforms. Firmware
+ * advertises its register region as an optional resource named "rgpio" (via
+ * the pinctrl-resource-names _DSD property). Relative to that region's base,
+ * RGPIO pin AMD_GPIO_RGPIO_PIN_BASE + n uses a per-pin control register at
+ * n * 4, a pinmux selector byte at AMD_GPIO_RGPIO_MUX_OFFSET + n, and one
+ * interrupt status bit (bit n) in WAKE_INT_STATUS_REG_RGPIO.
+ */
+#define AMD_GPIO_RGPIO_PIN_BASE 256
+#define AMD_GPIO_RGPIO_MUX_OFFSET 0xC0
#define WAKE_INT_MASTER_REG 0xfc
#define INTERNAL_GPIO0_DEBOUNCE (1 << 15)
@@ -22,6 +34,7 @@
#define WAKE_INT_STATUS_REG0 0x2f8
#define WAKE_INT_STATUS_REG1 0x2fc
+#define WAKE_INT_STATUS_REG_RGPIO 0x0F4
#define DB_TMR_OUT_OFF 0
#define DB_TMR_OUT_UNIT_OFF 4
@@ -94,6 +107,7 @@ struct amd_function {
struct amd_gpio {
raw_spinlock_t lock;
void __iomem *base;
+ void __iomem *base_rgpio;
void __iomem *iomux_base;
const struct pingroup *groups;
@@ -292,6 +306,22 @@ static const struct pinctrl_pin_desc kerncz_pins[] = {
PINCTRL_PIN(181, "GPIO_181"),
PINCTRL_PIN(182, "GPIO_182"),
PINCTRL_PIN(183, "GPIO_183"),
+ PINCTRL_PIN(256, "GPIO_256"),
+ PINCTRL_PIN(257, "GPIO_257"),
+ PINCTRL_PIN(258, "GPIO_258"),
+ PINCTRL_PIN(259, "GPIO_259"),
+ PINCTRL_PIN(260, "GPIO_260"),
+ PINCTRL_PIN(261, "GPIO_261"),
+ PINCTRL_PIN(262, "GPIO_262"),
+ PINCTRL_PIN(263, "GPIO_263"),
+ PINCTRL_PIN(264, "GPIO_264"),
+ PINCTRL_PIN(265, "GPIO_265"),
+ PINCTRL_PIN(266, "GPIO_266"),
+ PINCTRL_PIN(267, "GPIO_267"),
+ PINCTRL_PIN(268, "GPIO_268"),
+ PINCTRL_PIN(269, "GPIO_269"),
+ PINCTRL_PIN(270, "GPIO_270"),
+ PINCTRL_PIN(271, "GPIO_271"),
};
#define AMD_PINS(...) (const unsigned int []){__VA_ARGS__}
@@ -873,6 +903,70 @@ enum amd_functions {
IMX_F1_GPIO144,
IMX_F2_GPIO144,
IMX_F3_GPIO144,
+ IMX_F0_GPIO256,
+ IMX_F1_GPIO256,
+ IMX_F2_GPIO256,
+ IMX_F3_GPIO256,
+ IMX_F0_GPIO257,
+ IMX_F1_GPIO257,
+ IMX_F2_GPIO257,
+ IMX_F3_GPIO257,
+ IMX_F0_GPIO258,
+ IMX_F1_GPIO258,
+ IMX_F2_GPIO258,
+ IMX_F3_GPIO258,
+ IMX_F0_GPIO259,
+ IMX_F1_GPIO259,
+ IMX_F2_GPIO259,
+ IMX_F3_GPIO259,
+ IMX_F0_GPIO260,
+ IMX_F1_GPIO260,
+ IMX_F2_GPIO260,
+ IMX_F3_GPIO260,
+ IMX_F0_GPIO261,
+ IMX_F1_GPIO261,
+ IMX_F2_GPIO261,
+ IMX_F3_GPIO261,
+ IMX_F0_GPIO262,
+ IMX_F1_GPIO262,
+ IMX_F2_GPIO262,
+ IMX_F3_GPIO262,
+ IMX_F0_GPIO263,
+ IMX_F1_GPIO263,
+ IMX_F2_GPIO263,
+ IMX_F3_GPIO263,
+ IMX_F0_GPIO264,
+ IMX_F1_GPIO264,
+ IMX_F2_GPIO264,
+ IMX_F3_GPIO264,
+ IMX_F0_GPIO265,
+ IMX_F1_GPIO265,
+ IMX_F2_GPIO265,
+ IMX_F3_GPIO265,
+ IMX_F0_GPIO266,
+ IMX_F1_GPIO266,
+ IMX_F2_GPIO266,
+ IMX_F3_GPIO266,
+ IMX_F0_GPIO267,
+ IMX_F1_GPIO267,
+ IMX_F2_GPIO267,
+ IMX_F3_GPIO267,
+ IMX_F0_GPIO268,
+ IMX_F1_GPIO268,
+ IMX_F2_GPIO268,
+ IMX_F3_GPIO268,
+ IMX_F0_GPIO269,
+ IMX_F1_GPIO269,
+ IMX_F2_GPIO269,
+ IMX_F3_GPIO269,
+ IMX_F0_GPIO270,
+ IMX_F1_GPIO270,
+ IMX_F2_GPIO270,
+ IMX_F3_GPIO270,
+ IMX_F0_GPIO271,
+ IMX_F1_GPIO271,
+ IMX_F2_GPIO271,
+ IMX_F3_GPIO271,
};
#define AMD_PINCTRL_FUNC_GRP(_number, _func) \
@@ -1456,6 +1550,70 @@ static const struct pingroup kerncz_groups[] = {
AMD_PINCTRL_FUNC_GRP(144, 1),
AMD_PINCTRL_FUNC_GRP(144, 2),
AMD_PINCTRL_FUNC_GRP(144, 3),
+ AMD_PINCTRL_FUNC_GRP(256, 0),
+ AMD_PINCTRL_FUNC_GRP(256, 1),
+ AMD_PINCTRL_FUNC_GRP(256, 2),
+ AMD_PINCTRL_FUNC_GRP(256, 3),
+ AMD_PINCTRL_FUNC_GRP(257, 0),
+ AMD_PINCTRL_FUNC_GRP(257, 1),
+ AMD_PINCTRL_FUNC_GRP(257, 2),
+ AMD_PINCTRL_FUNC_GRP(257, 3),
+ AMD_PINCTRL_FUNC_GRP(258, 0),
+ AMD_PINCTRL_FUNC_GRP(258, 1),
+ AMD_PINCTRL_FUNC_GRP(258, 2),
+ AMD_PINCTRL_FUNC_GRP(258, 3),
+ AMD_PINCTRL_FUNC_GRP(259, 0),
+ AMD_PINCTRL_FUNC_GRP(259, 1),
+ AMD_PINCTRL_FUNC_GRP(259, 2),
+ AMD_PINCTRL_FUNC_GRP(259, 3),
+ AMD_PINCTRL_FUNC_GRP(260, 0),
+ AMD_PINCTRL_FUNC_GRP(260, 1),
+ AMD_PINCTRL_FUNC_GRP(260, 2),
+ AMD_PINCTRL_FUNC_GRP(260, 3),
+ AMD_PINCTRL_FUNC_GRP(261, 0),
+ AMD_PINCTRL_FUNC_GRP(261, 1),
+ AMD_PINCTRL_FUNC_GRP(261, 2),
+ AMD_PINCTRL_FUNC_GRP(261, 3),
+ AMD_PINCTRL_FUNC_GRP(262, 0),
+ AMD_PINCTRL_FUNC_GRP(262, 1),
+ AMD_PINCTRL_FUNC_GRP(262, 2),
+ AMD_PINCTRL_FUNC_GRP(262, 3),
+ AMD_PINCTRL_FUNC_GRP(263, 0),
+ AMD_PINCTRL_FUNC_GRP(263, 1),
+ AMD_PINCTRL_FUNC_GRP(263, 2),
+ AMD_PINCTRL_FUNC_GRP(263, 3),
+ AMD_PINCTRL_FUNC_GRP(264, 0),
+ AMD_PINCTRL_FUNC_GRP(264, 1),
+ AMD_PINCTRL_FUNC_GRP(264, 2),
+ AMD_PINCTRL_FUNC_GRP(264, 3),
+ AMD_PINCTRL_FUNC_GRP(265, 0),
+ AMD_PINCTRL_FUNC_GRP(265, 1),
+ AMD_PINCTRL_FUNC_GRP(265, 2),
+ AMD_PINCTRL_FUNC_GRP(265, 3),
+ AMD_PINCTRL_FUNC_GRP(266, 0),
+ AMD_PINCTRL_FUNC_GRP(266, 1),
+ AMD_PINCTRL_FUNC_GRP(266, 2),
+ AMD_PINCTRL_FUNC_GRP(266, 3),
+ AMD_PINCTRL_FUNC_GRP(267, 0),
+ AMD_PINCTRL_FUNC_GRP(267, 1),
+ AMD_PINCTRL_FUNC_GRP(267, 2),
+ AMD_PINCTRL_FUNC_GRP(267, 3),
+ AMD_PINCTRL_FUNC_GRP(268, 0),
+ AMD_PINCTRL_FUNC_GRP(268, 1),
+ AMD_PINCTRL_FUNC_GRP(268, 2),
+ AMD_PINCTRL_FUNC_GRP(268, 3),
+ AMD_PINCTRL_FUNC_GRP(269, 0),
+ AMD_PINCTRL_FUNC_GRP(269, 1),
+ AMD_PINCTRL_FUNC_GRP(269, 2),
+ AMD_PINCTRL_FUNC_GRP(269, 3),
+ AMD_PINCTRL_FUNC_GRP(270, 0),
+ AMD_PINCTRL_FUNC_GRP(270, 1),
+ AMD_PINCTRL_FUNC_GRP(270, 2),
+ AMD_PINCTRL_FUNC_GRP(270, 3),
+ AMD_PINCTRL_FUNC_GRP(271, 0),
+ AMD_PINCTRL_FUNC_GRP(271, 1),
+ AMD_PINCTRL_FUNC_GRP(271, 2),
+ AMD_PINCTRL_FUNC_GRP(271, 3),
PINCTRL_PINGROUP("i2c0", AMD_PINS(145, 146), 2),
PINCTRL_PINGROUP("i2c1", AMD_PINS(147, 148), 2),
@@ -1620,6 +1778,22 @@ static const struct amd_function pmx_functions[] = {
AMD_PMUX_FUNC(142),
AMD_PMUX_FUNC(143),
AMD_PMUX_FUNC(144),
+ AMD_PMUX_FUNC(256),
+ AMD_PMUX_FUNC(257),
+ AMD_PMUX_FUNC(258),
+ AMD_PMUX_FUNC(259),
+ AMD_PMUX_FUNC(260),
+ AMD_PMUX_FUNC(261),
+ AMD_PMUX_FUNC(262),
+ AMD_PMUX_FUNC(263),
+ AMD_PMUX_FUNC(264),
+ AMD_PMUX_FUNC(265),
+ AMD_PMUX_FUNC(266),
+ AMD_PMUX_FUNC(267),
+ AMD_PMUX_FUNC(268),
+ AMD_PMUX_FUNC(269),
+ AMD_PMUX_FUNC(270),
+ AMD_PMUX_FUNC(271),
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread