New ExynosAuto series GPIO have a different register structure.
In the existing Exynos series, EINT control register enumerated after
a specific offset (e.g EXYNOS_GPIO_ECON_OFFSET, EXYNOS_GPIO_EMASK_OFFSET).
However, from ExynosAutov920 SoC, the register that controls EINT belongs
to each GPIO bank, and each GPIO bank has 0x1000 align.
This is a structure to protect the GPIO bank using S2MPU in VM environment,
and will only be applied in ExynosAuto series SoCs.
-------------------------------------------------
| original | ExynosAutov920 |
|-----------------------------------------------|
| 0x0 GPIO_CON | 0x0 GPIO_CON |
| 0x4 GPIO_DAT | 0x4 GPIO_DAT |
| 0x8 GPIO_PUD | 0x8 GPIO_PUD |
| 0xc GPIO_DRV | 0xc GPIO_DRV |
| 0x10 GPIO_CONPDN | 0x10 GPIO_CONPDN |
| 0x14 GPIO_PUDPDN | 0x14 GPIO_PUDPDN |
| 0x700 EINT_CON | 0x18 EINT_CON |
| 0x800 EINT_FLTCON | 0x1c EINT_FLTCON0 |
| 0x900 EINT_MASK | 0x20 EINT_FLTCON1 |
| 0xa00 EINT_PEND | 0x24 EINT_MASK |
| | 0x28 EINT_PEND |
-------------------------------------------------
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
---
drivers/pinctrl/samsung/pinctrl-exynos.c | 81 +++++++++++++++++++++--
drivers/pinctrl/samsung/pinctrl-exynos.h | 1 +
drivers/pinctrl/samsung/pinctrl-samsung.c | 3 +
drivers/pinctrl/samsung/pinctrl-samsung.h | 12 ++++
4 files changed, 90 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 6b58ec84e34b..f798f64b1122 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -56,6 +56,9 @@ static void exynos_irq_mask(struct irq_data *irqd)
unsigned int mask;
unsigned long flags;
+ if (bank->eint_mask_offset)
+ reg_mask = bank->pctl_offset + bank->eint_mask_offset;
+
raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask);
@@ -72,6 +75,9 @@ static void exynos_irq_ack(struct irq_data *irqd)
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
unsigned long reg_pend = our_chip->eint_pend + bank->eint_offset;
+ if (bank->eint_pend_offset)
+ reg_pend = bank->pctl_offset + bank->eint_pend_offset;
+
writel(1 << irqd->hwirq, bank->eint_base + reg_pend);
}
@@ -95,6 +101,9 @@ static void exynos_irq_unmask(struct irq_data *irqd)
if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
exynos_irq_ack(irqd);
+ if (bank->eint_mask_offset)
+ reg_mask = bank->pctl_offset + bank->eint_mask_offset;
+
raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask);
@@ -139,6 +148,9 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
else
irq_set_handler_locked(irqd, handle_level_irq);
+ if (bank->eint_con_offset)
+ reg_con = bank->pctl_offset + bank->eint_con_offset;
+
con = readl(bank->eint_base + reg_con);
con &= ~(EXYNOS_EINT_CON_MASK << shift);
con |= trig_type << shift;
@@ -221,6 +233,18 @@ static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
/* eint_wake_mask_value not used */
};
+static const struct exynos_irq_chip exynosauto_gpio_irq_chip __initconst = {
+ .chip = {
+ .name = "exynosauto_gpio_irq_chip",
+ .irq_unmask = exynos_irq_unmask,
+ .irq_mask = exynos_irq_mask,
+ .irq_ack = exynos_irq_ack,
+ .irq_set_type = exynos_irq_set_type,
+ .irq_request_resources = exynos_irq_request_resources,
+ .irq_release_resources = exynos_irq_release_resources,
+ },
+};
+
static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
@@ -247,7 +271,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
unsigned int svc, group, pin;
int ret;
- svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
+ if (bank->eint_con_offset)
+ svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET);
+ else
+ svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
group = EXYNOS_SVC_GROUP(svc);
pin = svc & EXYNOS_SVC_NUM_MASK;
@@ -297,8 +324,12 @@ __init int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
if (bank->eint_type != EINT_TYPE_GPIO)
continue;
- bank->irq_chip = devm_kmemdup(dev, &exynos_gpio_irq_chip,
- sizeof(*bank->irq_chip), GFP_KERNEL);
+ if (bank->eint_con_offset)
+ bank->irq_chip = devm_kmemdup(dev, &exynosauto_gpio_irq_chip,
+ sizeof(*bank->irq_chip), GFP_KERNEL);
+ else
+ bank->irq_chip = devm_kmemdup(dev, &exynos_gpio_irq_chip,
+ sizeof(*bank->irq_chip), GFP_KERNEL);
if (!bank->irq_chip) {
ret = -ENOMEM;
goto err_domains;
@@ -655,6 +686,19 @@ static void exynos_pinctrl_suspend_bank(
pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
}
+static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drvdata,
+ struct samsung_pin_bank *bank)
+{
+ struct exynos_eint_gpio_save *save = bank->soc_priv;
+ void __iomem *regs = bank->eint_base;
+
+ save->eint_con = readl(regs + bank->pctl_offset + bank->eint_con_offset);
+ save->eint_mask = readl(regs + bank->pctl_offset + bank->eint_mask_offset);
+
+ pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
+ pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
+}
+
void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
{
struct samsung_pin_bank *bank = drvdata->pin_banks;
@@ -662,8 +706,12 @@ void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
int i;
for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
- if (bank->eint_type == EINT_TYPE_GPIO)
- exynos_pinctrl_suspend_bank(drvdata, bank);
+ if (bank->eint_type == EINT_TYPE_GPIO) {
+ if (bank->eint_con_offset)
+ exynosauto_pinctrl_suspend_bank(drvdata, bank);
+ else
+ exynos_pinctrl_suspend_bank(drvdata, bank);
+ }
else if (bank->eint_type == EINT_TYPE_WKUP) {
if (!irq_chip) {
irq_chip = bank->irq_chip;
@@ -704,14 +752,33 @@ static void exynos_pinctrl_resume_bank(
+ bank->eint_offset);
}
+static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata,
+ struct samsung_pin_bank *bank)
+{
+ struct exynos_eint_gpio_save *save = bank->soc_priv;
+ void __iomem *regs = bank->eint_base;
+
+ pr_debug("%s: con %#010x => %#010x\n", bank->name,
+ readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con);
+ pr_debug("%s: mask %#010x => %#010x\n", bank->name,
+ readl(regs + bank->pctl_offset + bank->eint_mask_offset), save->eint_mask);
+
+ writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset);
+ writel(save->eint_mask, regs + bank->pctl_offset + bank->eint_mask_offset);
+}
+
void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
{
struct samsung_pin_bank *bank = drvdata->pin_banks;
int i;
for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
- if (bank->eint_type == EINT_TYPE_GPIO)
- exynos_pinctrl_resume_bank(drvdata, bank);
+ if (bank->eint_type == EINT_TYPE_GPIO) {
+ if (bank->eint_con_offset)
+ exynosauto_pinctrl_resume_bank(drvdata, bank);
+ else
+ exynos_pinctrl_resume_bank(drvdata, bank);
+ }
}
static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata)
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
index 3ac52c2cf998..5049c170e958 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.h
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
@@ -31,6 +31,7 @@
#define EXYNOS7_WKUP_EMASK_OFFSET 0x900
#define EXYNOS7_WKUP_EPEND_OFFSET 0xA00
#define EXYNOS_SVC_OFFSET 0xB08
+#define EXYNOSAUTO_SVC_OFFSET 0xF008
/* helpers to access interrupt service register */
#define EXYNOS_SVC_GROUP_SHIFT 3
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 79babbb39ced..362e99566919 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -1106,6 +1106,9 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
bank->eint_type = bdata->eint_type;
bank->eint_mask = bdata->eint_mask;
bank->eint_offset = bdata->eint_offset;
+ bank->eint_con_offset = bdata->eint_con_offset;
+ bank->eint_mask_offset = bdata->eint_mask_offset;
+ bank->eint_pend_offset = bdata->eint_pend_offset;
bank->name = bdata->name;
raw_spin_lock_init(&bank->slock);
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index 9b3db50adef3..789358bcd9c5 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -122,6 +122,9 @@ struct samsung_pin_bank_type {
* @eint_type: type of the external interrupt supported by the bank.
* @eint_mask: bit mask of pins which support EINT function.
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
+ * @eint_con_offset: ExynosAuto SoC-specific EINT control register offset of bank.
+ * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
+ * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
* @name: name to be prefixed for each pin in this pin bank.
*/
struct samsung_pin_bank_data {
@@ -133,6 +136,9 @@ struct samsung_pin_bank_data {
enum eint_type eint_type;
u32 eint_mask;
u32 eint_offset;
+ u32 eint_con_offset;
+ u32 eint_mask_offset;
+ u32 eint_pend_offset;
const char *name;
};
@@ -147,6 +153,9 @@ struct samsung_pin_bank_data {
* @eint_type: type of the external interrupt supported by the bank.
* @eint_mask: bit mask of pins which support EINT function.
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
+ * @eint_con_offset: ExynosAuto SoC-specific EINT register or interrupt offset of bank.
+ * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
+ * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
* @name: name to be prefixed for each pin in this pin bank.
* @id: id of the bank, propagated to the pin range.
* @pin_base: starting pin number of the bank.
@@ -170,6 +179,9 @@ struct samsung_pin_bank {
enum eint_type eint_type;
u32 eint_mask;
u32 eint_offset;
+ u32 eint_con_offset;
+ u32 eint_mask_offset;
+ u32 eint_pend_offset;
const char *name;
u32 id;
--
2.43.0
On 08/12/2023 08:45, Jaewon Kim wrote: > New ExynosAuto series GPIO have a different register structure. > In the existing Exynos series, EINT control register enumerated after Missing verb... or enumerated is past tense? I just don't get entire sentence. > a specific offset (e.g EXYNOS_GPIO_ECON_OFFSET, EXYNOS_GPIO_EMASK_OFFSET). > However, from ExynosAutov920 SoC, the register that controls EINT belongs > to each GPIO bank, and each GPIO bank has 0x1000 align. > > This is a structure to protect the GPIO bank using S2MPU in VM environment, > and will only be applied in ExynosAuto series SoCs. > > ------------------------------------------------- > | original | ExynosAutov920 | > |-----------------------------------------------| > | 0x0 GPIO_CON | 0x0 GPIO_CON | > | 0x4 GPIO_DAT | 0x4 GPIO_DAT | > | 0x8 GPIO_PUD | 0x8 GPIO_PUD | > | 0xc GPIO_DRV | 0xc GPIO_DRV | > | 0x10 GPIO_CONPDN | 0x10 GPIO_CONPDN | > | 0x14 GPIO_PUDPDN | 0x14 GPIO_PUDPDN | > | 0x700 EINT_CON | 0x18 EINT_CON | This suggests there is EINT_CON per bank in old and new register layout. I don't think it's true, so probably this could look like: | --- | 0x18 EINT_CON (per_bank) | | --- | 0x18 EINT_FLTCON0 (per_bank) | | --- | 0x18 EINT_FLTCON1 (per_bank) | | --- | 0x18 EINT_MASK (per_bank) | | 0x700 EINT_CON (global) | 0x18 EINT_CON | etc.. Also, please use spaces for alignment in the table. Best regards, Krzysztof
On 23. 12. 10. 22:23, Krzysztof Kozlowski wrote: > On 08/12/2023 08:45, Jaewon Kim wrote: >> New ExynosAuto series GPIO have a different register structure. >> In the existing Exynos series, EINT control register enumerated after > Missing verb... or enumerated is past tense? I just don't get entire > sentence. Sorry, I will add 'is' like below. In the existing Exynos series, the EINT control register is enumerated after a specific offset. > >> a specific offset (e.g EXYNOS_GPIO_ECON_OFFSET, EXYNOS_GPIO_EMASK_OFFSET). >> However, from ExynosAutov920 SoC, the register that controls EINT belongs >> to each GPIO bank, and each GPIO bank has 0x1000 align. >> >> This is a structure to protect the GPIO bank using S2MPU in VM environment, >> and will only be applied in ExynosAuto series SoCs. >> >> ------------------------------------------------- >> | original | ExynosAutov920 | >> |-----------------------------------------------| >> | 0x0 GPIO_CON | 0x0 GPIO_CON | >> | 0x4 GPIO_DAT | 0x4 GPIO_DAT | >> | 0x8 GPIO_PUD | 0x8 GPIO_PUD | >> | 0xc GPIO_DRV | 0xc GPIO_DRV | >> | 0x10 GPIO_CONPDN | 0x10 GPIO_CONPDN | >> | 0x14 GPIO_PUDPDN | 0x14 GPIO_PUDPDN | >> | 0x700 EINT_CON | 0x18 EINT_CON | > This suggests there is EINT_CON per bank in old and new register layout. > I don't think it's true, so probably this could look like: > > | --- | 0x18 EINT_CON (per_bank) | > | --- | 0x18 EINT_FLTCON0 (per_bank) | > | --- | 0x18 EINT_FLTCON1 (per_bank) | > | --- | 0x18 EINT_MASK (per_bank) | > | 0x700 EINT_CON (global) | 0x18 EINT_CON | > > etc.. > > Also, please use spaces for alignment in the table. > Thanks you for your review. I will add (global), (per_bank) for clearer expression. And, I will use space instead of tab in v4. > > Best regards, > Krzysztof > >
On 08/12/2023 08:45, Jaewon Kim wrote:
> New ExynosAuto series GPIO have a different register structure.
> In the existing Exynos series, EINT control register enumerated after
> a specific offset (e.g EXYNOS_GPIO_ECON_OFFSET, EXYNOS_GPIO_EMASK_OFFSET).
> However, from ExynosAutov920 SoC, the register that controls EINT belongs
> to each GPIO bank, and each GPIO bank has 0x1000 align.
>
> This is a structure to protect the GPIO bank using S2MPU in VM environment,
> and will only be applied in ExynosAuto series SoCs.
>
> -------------------------------------------------
> | original | ExynosAutov920 |
> |-----------------------------------------------|
> | 0x0 GPIO_CON | 0x0 GPIO_CON |
> | 0x4 GPIO_DAT | 0x4 GPIO_DAT |
> | 0x8 GPIO_PUD | 0x8 GPIO_PUD |
> | 0xc GPIO_DRV | 0xc GPIO_DRV |
> | 0x10 GPIO_CONPDN | 0x10 GPIO_CONPDN |
> | 0x14 GPIO_PUDPDN | 0x14 GPIO_PUDPDN |
> | 0x700 EINT_CON | 0x18 EINT_CON |
> | 0x800 EINT_FLTCON | 0x1c EINT_FLTCON0 |
> | 0x900 EINT_MASK | 0x20 EINT_FLTCON1 |
> | 0xa00 EINT_PEND | 0x24 EINT_MASK |
> | | 0x28 EINT_PEND |
> -------------------------------------------------
>
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> ---
> drivers/pinctrl/samsung/pinctrl-exynos.c | 81 +++++++++++++++++++++--
> drivers/pinctrl/samsung/pinctrl-exynos.h | 1 +
> drivers/pinctrl/samsung/pinctrl-samsung.c | 3 +
> drivers/pinctrl/samsung/pinctrl-samsung.h | 12 ++++
> 4 files changed, 90 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
> index 6b58ec84e34b..f798f64b1122 100644
> --- a/drivers/pinctrl/samsung/pinctrl-exynos.c
> +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
> @@ -56,6 +56,9 @@ static void exynos_irq_mask(struct irq_data *irqd)
> unsigned int mask;
> unsigned long flags;
>
> + if (bank->eint_mask_offset)
> + reg_mask = bank->pctl_offset + bank->eint_mask_offset;
Drop the initialization of reg_mask so:
else:
reg_mask = ...
> +
> raw_spin_lock_irqsave(&bank->slock, flags);
>
> mask = readl(bank->eint_base + reg_mask);
> @@ -72,6 +75,9 @@ static void exynos_irq_ack(struct irq_data *irqd)
> struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
> unsigned long reg_pend = our_chip->eint_pend + bank->eint_offset;
>
> + if (bank->eint_pend_offset)
> + reg_pend = bank->pctl_offset + bank->eint_pend_offset;
> +
> writel(1 << irqd->hwirq, bank->eint_base + reg_pend);
> }
>
> @@ -95,6 +101,9 @@ static void exynos_irq_unmask(struct irq_data *irqd)
> if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
> exynos_irq_ack(irqd);
>
Ditto
> + if (bank->eint_mask_offset)
> + reg_mask = bank->pctl_offset + bank->eint_mask_offset;
> +
> raw_spin_lock_irqsave(&bank->slock, flags);
>
> mask = readl(bank->eint_base + reg_mask);
> @@ -139,6 +148,9 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
> else
> irq_set_handler_locked(irqd, handle_level_irq);
>
Ditto
> + if (bank->eint_con_offset)
> + reg_con = bank->pctl_offset + bank->eint_con_offset;
> +
> con = readl(bank->eint_base + reg_con);
> con &= ~(EXYNOS_EINT_CON_MASK << shift);
> con |= trig_type << shift;
> @@ -221,6 +233,18 @@ static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
> /* eint_wake_mask_value not used */
> };
>
> +static const struct exynos_irq_chip exynosauto_gpio_irq_chip __initconst = {
No related to this patch.
> + .chip = {
> + .name = "exynosauto_gpio_irq_chip",
> + .irq_unmask = exynos_irq_unmask,
> + .irq_mask = exynos_irq_mask,
> + .irq_ack = exynos_irq_ack,
> + .irq_set_type = exynos_irq_set_type,
> + .irq_request_resources = exynos_irq_request_resources,
> + .irq_release_resources = exynos_irq_release_resources,
> + },
> +};
> +
> static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
> irq_hw_number_t hw)
> {
> @@ -247,7 +271,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
> unsigned int svc, group, pin;
> int ret;
>
> - svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
> + if (bank->eint_con_offset)
> + svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET);
This belongs to the second patch. The point of this patch is only to
customize the offsets. There should be nothing autov920 here.
> + else
> + svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
> group = EXYNOS_SVC_GROUP(svc);
> pin = svc & EXYNOS_SVC_NUM_MASK;
>
> @@ -297,8 +324,12 @@ __init int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
> if (bank->eint_type != EINT_TYPE_GPIO)
> continue;
>
> - bank->irq_chip = devm_kmemdup(dev, &exynos_gpio_irq_chip,
> - sizeof(*bank->irq_chip), GFP_KERNEL);
> + if (bank->eint_con_offset)
> + bank->irq_chip = devm_kmemdup(dev, &exynosauto_gpio_irq_chip,
> + sizeof(*bank->irq_chip), GFP_KERNEL);
> + else
> + bank->irq_chip = devm_kmemdup(dev, &exynos_gpio_irq_chip,
> + sizeof(*bank->irq_chip), GFP_KERNEL);
> if (!bank->irq_chip) {
> ret = -ENOMEM;
> goto err_domains;
> @@ -655,6 +686,19 @@ static void exynos_pinctrl_suspend_bank(
> pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
> }
>
> +static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drvdata,
> + struct samsung_pin_bank *bank)
> +{
> + struct exynos_eint_gpio_save *save = bank->soc_priv;
> + void __iomem *regs = bank->eint_base;
> +
> + save->eint_con = readl(regs + bank->pctl_offset + bank->eint_con_offset);
> + save->eint_mask = readl(regs + bank->pctl_offset + bank->eint_mask_offset);
> +
> + pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
> + pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
> +}
> +
> void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
> {
> struct samsung_pin_bank *bank = drvdata->pin_banks;
> @@ -662,8 +706,12 @@ void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
> int i;
>
> for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
> - if (bank->eint_type == EINT_TYPE_GPIO)
> - exynos_pinctrl_suspend_bank(drvdata, bank);
> + if (bank->eint_type == EINT_TYPE_GPIO) {
> + if (bank->eint_con_offset)
> + exynosauto_pinctrl_suspend_bank(drvdata, bank);
> + else
> + exynos_pinctrl_suspend_bank(drvdata, bank);
> + }
> else if (bank->eint_type == EINT_TYPE_WKUP) {
> if (!irq_chip) {
> irq_chip = bank->irq_chip;
> @@ -704,14 +752,33 @@ static void exynos_pinctrl_resume_bank(
> + bank->eint_offset);
> }
>
> +static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata,
> + struct samsung_pin_bank *bank)
> +{
> + struct exynos_eint_gpio_save *save = bank->soc_priv;
> + void __iomem *regs = bank->eint_base;
> +
> + pr_debug("%s: con %#010x => %#010x\n", bank->name,
> + readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con);
> + pr_debug("%s: mask %#010x => %#010x\n", bank->name,
> + readl(regs + bank->pctl_offset + bank->eint_mask_offset), save->eint_mask);
> +
> + writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset);
> + writel(save->eint_mask, regs + bank->pctl_offset + bank->eint_mask_offset);
> +}
> +
> void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
> {
> struct samsung_pin_bank *bank = drvdata->pin_banks;
> int i;
>
> for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
> - if (bank->eint_type == EINT_TYPE_GPIO)
> - exynos_pinctrl_resume_bank(drvdata, bank);
> + if (bank->eint_type == EINT_TYPE_GPIO) {
> + if (bank->eint_con_offset)
> + exynosauto_pinctrl_resume_bank(drvdata, bank);
> + else
> + exynos_pinctrl_resume_bank(drvdata, bank);
> + }
> }
>
> static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata)
> diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
> index 3ac52c2cf998..5049c170e958 100644
> --- a/drivers/pinctrl/samsung/pinctrl-exynos.h
> +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
> @@ -31,6 +31,7 @@
> #define EXYNOS7_WKUP_EMASK_OFFSET 0x900
> #define EXYNOS7_WKUP_EPEND_OFFSET 0xA00
> #define EXYNOS_SVC_OFFSET 0xB08
> +#define EXYNOSAUTO_SVC_OFFSET 0xF008
As well not related to this patch.
Best regards,
Krzysztof
Hello Krzysztof,
Thanks to review.
On 23. 12. 10. 22:00, Krzysztof Kozlowski wrote:
> On 08/12/2023 08:45, Jaewon Kim wrote:
>> New ExynosAuto series GPIO have a different register structure.
>> In the existing Exynos series, EINT control register enumerated after
>> a specific offset (e.g EXYNOS_GPIO_ECON_OFFSET, EXYNOS_GPIO_EMASK_OFFSET).
>> However, from ExynosAutov920 SoC, the register that controls EINT belongs
>> to each GPIO bank, and each GPIO bank has 0x1000 align.
>>
>> This is a structure to protect the GPIO bank using S2MPU in VM environment,
>> and will only be applied in ExynosAuto series SoCs.
>>
>> -------------------------------------------------
>> | original | ExynosAutov920 |
>> |-----------------------------------------------|
>> | 0x0 GPIO_CON | 0x0 GPIO_CON |
>> | 0x4 GPIO_DAT | 0x4 GPIO_DAT |
>> | 0x8 GPIO_PUD | 0x8 GPIO_PUD |
>> | 0xc GPIO_DRV | 0xc GPIO_DRV |
>> | 0x10 GPIO_CONPDN | 0x10 GPIO_CONPDN |
>> | 0x14 GPIO_PUDPDN | 0x14 GPIO_PUDPDN |
>> | 0x700 EINT_CON | 0x18 EINT_CON |
>> | 0x800 EINT_FLTCON | 0x1c EINT_FLTCON0 |
>> | 0x900 EINT_MASK | 0x20 EINT_FLTCON1 |
>> | 0xa00 EINT_PEND | 0x24 EINT_MASK |
>> | | 0x28 EINT_PEND |
>> -------------------------------------------------
>>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>> drivers/pinctrl/samsung/pinctrl-exynos.c | 81 +++++++++++++++++++++--
>> drivers/pinctrl/samsung/pinctrl-exynos.h | 1 +
>> drivers/pinctrl/samsung/pinctrl-samsung.c | 3 +
>> drivers/pinctrl/samsung/pinctrl-samsung.h | 12 ++++
>> 4 files changed, 90 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
>> index 6b58ec84e34b..f798f64b1122 100644
>> --- a/drivers/pinctrl/samsung/pinctrl-exynos.c
>> +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
>> @@ -56,6 +56,9 @@ static void exynos_irq_mask(struct irq_data *irqd)
>> unsigned int mask;
>> unsigned long flags;
>>
>> + if (bank->eint_mask_offset)
>> + reg_mask = bank->pctl_offset + bank->eint_mask_offset;
> Drop the initialization of reg_mask so:
>
> else:
> reg_mask = ...
Okay, I will fix it in v4.
>
>> +
>> raw_spin_lock_irqsave(&bank->slock, flags);
>>
>> mask = readl(bank->eint_base + reg_mask);
>> @@ -72,6 +75,9 @@ static void exynos_irq_ack(struct irq_data *irqd)
>> struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
>> unsigned long reg_pend = our_chip->eint_pend + bank->eint_offset;
>>
>> + if (bank->eint_pend_offset)
>> + reg_pend = bank->pctl_offset + bank->eint_pend_offset;
>> +
>> writel(1 << irqd->hwirq, bank->eint_base + reg_pend);
>> }
>>
>> @@ -95,6 +101,9 @@ static void exynos_irq_unmask(struct irq_data *irqd)
>> if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
>> exynos_irq_ack(irqd);
>>
> Ditto
I will fix it also.
>
>> + if (bank->eint_mask_offset)
>> + reg_mask = bank->pctl_offset + bank->eint_mask_offset;
>> +
>> raw_spin_lock_irqsave(&bank->slock, flags);
>>
>> mask = readl(bank->eint_base + reg_mask);
>> @@ -139,6 +148,9 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
>> else
>> irq_set_handler_locked(irqd, handle_level_irq);
>>
>
> Ditto
I will fix it also.
>
>> + if (bank->eint_con_offset)
>> + reg_con = bank->pctl_offset + bank->eint_con_offset;
>> +
>> con = readl(bank->eint_base + reg_con);
>> con &= ~(EXYNOS_EINT_CON_MASK << shift);
>> con |= trig_type << shift;
>> @@ -221,6 +233,18 @@ static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
>> /* eint_wake_mask_value not used */
>> };
>>
>> +static const struct exynos_irq_chip exynosauto_gpio_irq_chip __initconst = {
> No related to this patch.
>
>> + .chip = {
>> + .name = "exynosauto_gpio_irq_chip",
>> + .irq_unmask = exynos_irq_unmask,
>> + .irq_mask = exynos_irq_mask,
>> + .irq_ack = exynos_irq_ack,
>> + .irq_set_type = exynos_irq_set_type,
>> + .irq_request_resources = exynos_irq_request_resources,
>> + .irq_release_resources = exynos_irq_release_resources,
>> + },
>> +};
>> +
>> static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
>> irq_hw_number_t hw)
>> {
>> @@ -247,7 +271,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
>> unsigned int svc, group, pin;
>> int ret;
>>
>> - svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
>> + if (bank->eint_con_offset)
>> + svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET);
> This belongs to the second patch. The point of this patch is only to
> customize the offsets. There should be nothing autov920 here.
Okay, I will put the irq-related changes in the v920 patch.
>
>
>> + else
>> + svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
>> group = EXYNOS_SVC_GROUP(svc);
>> pin = svc & EXYNOS_SVC_NUM_MASK;
>>
>> @@ -297,8 +324,12 @@ __init int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
>> if (bank->eint_type != EINT_TYPE_GPIO)
>> continue;
>>
>> - bank->irq_chip = devm_kmemdup(dev, &exynos_gpio_irq_chip,
>> - sizeof(*bank->irq_chip), GFP_KERNEL);
>> + if (bank->eint_con_offset)
>> + bank->irq_chip = devm_kmemdup(dev, &exynosauto_gpio_irq_chip,
>> + sizeof(*bank->irq_chip), GFP_KERNEL);
>> + else
>> + bank->irq_chip = devm_kmemdup(dev, &exynos_gpio_irq_chip,
>> + sizeof(*bank->irq_chip), GFP_KERNEL);
>> if (!bank->irq_chip) {
>> ret = -ENOMEM;
>> goto err_domains;
>> @@ -655,6 +686,19 @@ static void exynos_pinctrl_suspend_bank(
>> pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
>> }
>>
>> +static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drvdata,
>> + struct samsung_pin_bank *bank)
>> +{
>> + struct exynos_eint_gpio_save *save = bank->soc_priv;
>> + void __iomem *regs = bank->eint_base;
>> +
>> + save->eint_con = readl(regs + bank->pctl_offset + bank->eint_con_offset);
>> + save->eint_mask = readl(regs + bank->pctl_offset + bank->eint_mask_offset);
>> +
>> + pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
>> + pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
>> +}
>> +
>> void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
>> {
>> struct samsung_pin_bank *bank = drvdata->pin_banks;
>> @@ -662,8 +706,12 @@ void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
>> int i;
>>
>> for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
>> - if (bank->eint_type == EINT_TYPE_GPIO)
>> - exynos_pinctrl_suspend_bank(drvdata, bank);
>> + if (bank->eint_type == EINT_TYPE_GPIO) {
>> + if (bank->eint_con_offset)
>> + exynosauto_pinctrl_suspend_bank(drvdata, bank);
>> + else
>> + exynos_pinctrl_suspend_bank(drvdata, bank);
>> + }
>> else if (bank->eint_type == EINT_TYPE_WKUP) {
>> if (!irq_chip) {
>> irq_chip = bank->irq_chip;
>> @@ -704,14 +752,33 @@ static void exynos_pinctrl_resume_bank(
>> + bank->eint_offset);
>> }
>>
>> +static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata,
>> + struct samsung_pin_bank *bank)
>> +{
>> + struct exynos_eint_gpio_save *save = bank->soc_priv;
>> + void __iomem *regs = bank->eint_base;
>> +
>> + pr_debug("%s: con %#010x => %#010x\n", bank->name,
>> + readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con);
>> + pr_debug("%s: mask %#010x => %#010x\n", bank->name,
>> + readl(regs + bank->pctl_offset + bank->eint_mask_offset), save->eint_mask);
>> +
>> + writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset);
>> + writel(save->eint_mask, regs + bank->pctl_offset + bank->eint_mask_offset);
>> +}
>> +
>> void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
>> {
>> struct samsung_pin_bank *bank = drvdata->pin_banks;
>> int i;
>>
>> for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
>> - if (bank->eint_type == EINT_TYPE_GPIO)
>> - exynos_pinctrl_resume_bank(drvdata, bank);
>> + if (bank->eint_type == EINT_TYPE_GPIO) {
>> + if (bank->eint_con_offset)
>> + exynosauto_pinctrl_resume_bank(drvdata, bank);
>> + else
>> + exynos_pinctrl_resume_bank(drvdata, bank);
>> + }
>> }
>>
>> static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata)
>> diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
>> index 3ac52c2cf998..5049c170e958 100644
>> --- a/drivers/pinctrl/samsung/pinctrl-exynos.h
>> +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
>> @@ -31,6 +31,7 @@
>> #define EXYNOS7_WKUP_EMASK_OFFSET 0x900
>> #define EXYNOS7_WKUP_EPEND_OFFSET 0xA00
>> #define EXYNOS_SVC_OFFSET 0xB08
>> +#define EXYNOSAUTO_SVC_OFFSET 0xF008
> As well not related to this patch.
>
> Best regards,
> Krzysztof
>
>
Thanks
Jaewon Kim
© 2016 - 2025 Red Hat, Inc.