diff mbox series

[v3,3/4] pinctrl: samsung: support ExynosAuto GPIO structure

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

Commit Message

Jaewon Kim Dec. 8, 2023, 7:45 a.m. UTC
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(-)

Comments

Krzysztof Kozlowski Dec. 10, 2023, 1 p.m. UTC | #1
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
Krzysztof Kozlowski Dec. 10, 2023, 1:23 p.m. UTC | #2
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
Jaewon Kim Dec. 11, 2023, 2:38 a.m. UTC | #3
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
Jaewon Kim Dec. 11, 2023, 2:44 a.m. UTC | #4
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 mbox series

Patch

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;