Message ID | 20231208074527.50840-4-jaewon02.kim@samsung.com |
---|---|
State | New |
Headers | show |
Series | [v3,1/4] arm64: dts: exynos: add initial support for exynosautov920 SoC | expand |
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
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
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
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 > >
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;
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(-)