From: Alice Guo (OSS) <hidden> Date: 2022-08-25 08:32:57
From: Anson Huang <redacted>
The i.MX7ULP's watchdog is enabled by default when out of reset, so the
resume callback which is to disable watchdog should be called earlier
to avoid unexpected timeout, move suspend/resume callback to noirq phase.
Signed-off-by: Anson Huang <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Tested-by: Peter Chen <redacted>
Tested-by: Li Jun <redacted>
---
Changes for v2:
- none
drivers/watchdog/imx7ulp_wdt.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
From: Alice Guo (OSS) <hidden> Date: 2022-08-25 08:33:08
From: Jacky Bai <ping.bai@nxp.com>
When reconfiguring the WDOG Timer of i.MX7ULP, there is a certain
probability causes it to reset. The reason is that the CMD32EN of the
WDOG Timer of i.MX7ULP is disabled in bootloader. The unlock sequence
are two 16-bit writes to the CNT register within 16 bus clocks. Adding
mb() is to guarantee that two 16-bit writes are finished within 16 bus
clocks. Memory barriers cannot be added between these two 16-bit writes
so that writel_relaxed is used.
Suggested-by: Ye Li <redacted>
Signed-off-by: Jacky Bai <ping.bai@nxp.com>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Ye Li <redacted>
---
Changes for v2:
- add the reason why memory barriers are added for unlock sequence in commit log
drivers/watchdog/imx7ulp_wdt.c | 4 ++++
1 file changed, 4 insertions(+)
@@ -179,9 +179,13 @@ static int imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)intret;local_irq_disable();++mb();/* unlock the wdog for reconfiguration */writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);+mb();+ret=imx7ulp_wdt_wait(base,WDOG_CS_ULK);if(ret)gotoinit_out;
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alice Guo (OSS) <hidden> Date: 2022-08-25 08:33:15
From: Ye Li <redacted>
When bootloader has enabled the CMD32EN bit, switch to use 32bits
unlock command to unlock the CS register. Using 32bits command will
help on avoiding 16 bus cycle window violation for two 16 bits
commands.
Signed-off-by: Ye Li <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Acked-by: Jason Liu <redacted>
---
Changes for v2:
- none
drivers/watchdog/imx7ulp_wdt.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
@@ -180,11 +180,16 @@ static int imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)local_irq_disable();-mb();-/* unlock the wdog for reconfiguration */-writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);-writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);-mb();+val=readl(base+WDOG_CS);+if(val&WDOG_CS_CMD32EN){+writel(UNLOCK,base+WDOG_CNT);+}else{+mb();+/* unlock the wdog for reconfiguration */+writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);+writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);+mb();+}ret=imx7ulp_wdt_wait(base,WDOG_CS_ULK);if(ret)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alice Guo (OSS) <hidden> Date: 2022-08-25 08:33:30
From: Ye Li <redacted>
According to measure on i.MX7ULP and i.MX8ULP, the RCS done needs
about 3400us and 6700us respectively. So current 20us timeout is
not enough. When reconfiguring is on-going, unlock and configure CS
will lead to unknown result.
Increase the wait timeout value to 10ms and check the return value
of RCS wait to fix the issue
Signed-off-by: Ye Li <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Acked-by: Jason Liu <redacted>
---
Changes for v2:
- none
drivers/watchdog/imx7ulp_wdt.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
From: Alice Guo (OSS) <hidden> Date: 2022-08-25 08:33:35
From: Ye Li <redacted>
Current driver may meet reconfigure failure caused by below reasons:
1. The wdog on iMX7ULP has different behavior after RCS valid. It needs
to wait more than 2.5 wdog clock for clock sync before next
reconfiguration, while imx8ulp wdog does not need such delay.
2. After unlock, there is 128 bus clock window opened for reconfiguration,
but on iMX8ULP, the HW can't guarantee the latency. So it is possible
the window is closed before the writing arrives to wdog.
3. If the PRES is enabled, the RCS valid time becomes x256 to the time
of PRES disabled. It is about 1715ms on iMX8ULP. So We have to increase
the RCS timeout and can't wait it in IRQ disabled.
The patch updates the driver to handle failures
1. Using different wait for unlock and RCS. Unlock valid time is very short
and only related to bus clock. It must be in IRQ disabled to avoid
being interrupted in 128 clock window. But for RCS time, it is longer
and ok for IRQ enabled.
2. Add retry for any reconfigure failure with default 5 times.
3. Add "fsl,imx8ulp-wdt" compatile string for iMX8ULP and afterwards
platform which don't need more 2.5 wdog clock after RCS valid.
For imx7ulp, add post delay of 2.5 clock after RCS valid.
Signed-off-by: Ye Li <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
---
Changes for v2:
- the wait timeout value of the RCS is 10ms, so use the sleep_us of
readl_poll_timeout in imx7ulp_wdt_wait_rcs to avoid a 10ms hot wait
drivers/watchdog/imx7ulp_wdt.c | 163 ++++++++++++++++++++++++++-------
1 file changed, 129 insertions(+), 34 deletions(-)
@@ -114,28 +162,44 @@ static int imx7ulp_wdt_stop(struct watchdog_device *wdog)returnimx7ulp_wdt_enable(wdog,false);}-staticintimx7ulp_wdt_set_timeout(structwatchdog_device*wdog,-unsignedinttimeout)+staticint_imx7ulp_wdt_set_timeout(structimx7ulp_wdt_device*wdt,+unsignedinttoval){-structimx7ulp_wdt_device*wdt=watchdog_get_drvdata(wdog);-u32val=WDOG_CLOCK_RATE*timeout;intret;local_irq_disable();writel(UNLOCK,wdt->base+WDOG_CNT);-ret=imx7ulp_wdt_wait(wdt->base,WDOG_CS_ULK);+ret=imx7ulp_wdt_wait_ulk(wdt->base);if(ret)gototimeout_out;-writel(val,wdt->base+WDOG_TOVAL);-ret=imx7ulp_wdt_wait(wdt->base,WDOG_CS_RCS);-if(ret)-gototimeout_out;--wdog->timeout=timeout;+writel(toval,wdt->base+WDOG_TOVAL);+local_irq_enable();+ret=imx7ulp_wdt_wait_rcs(wdt);+returnret;timeout_out:local_irq_enable();+returnret;+}+staticintimx7ulp_wdt_set_timeout(structwatchdog_device*wdog,+unsignedinttimeout)+{+structimx7ulp_wdt_device*wdt=watchdog_get_drvdata(wdog);+u32toval=WDOG_CLOCK_RATE*timeout;+u32val;+intret;+u32loop=RETRY_MAX;++do{+ret=_imx7ulp_wdt_set_timeout(wdt,toval);+val=readl(wdt->base+WDOG_TOVAL);+}while(--loop>0&&(val!=toval||ret));++if(loop==0)+return-EBUSY;++wdog->timeout=timeout;returnret;}
@@ -175,38 +239,59 @@ static const struct watchdog_info imx7ulp_wdt_info = {WDIOF_MAGICCLOSE,};-staticintimx7ulp_wdt_init(void__iomem*base,unsignedinttimeout)+staticint_imx7ulp_wdt_init(structimx7ulp_wdt_device*wdt,unsignedinttimeout,unsignedintcs){u32val;intret;local_irq_disable();-val=readl(base+WDOG_CS);+val=readl(wdt->base+WDOG_CS);if(val&WDOG_CS_CMD32EN){-writel(UNLOCK,base+WDOG_CNT);+writel(UNLOCK,wdt->base+WDOG_CNT);}else{mb();/* unlock the wdog for reconfiguration */-writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);-writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);+writel_relaxed(UNLOCK_SEQ0,wdt->base+WDOG_CNT);+writel_relaxed(UNLOCK_SEQ1,wdt->base+WDOG_CNT);mb();}-ret=imx7ulp_wdt_wait(base,WDOG_CS_ULK);+ret=imx7ulp_wdt_wait_ulk(wdt->base);if(ret)gotoinit_out;/* set an initial timeout value in TOVAL */-writel(timeout,base+WDOG_TOVAL);-/* enable 32bit command sequence and reconfigure */-val=WDOG_CS_CMD32EN|WDOG_CS_CLK|WDOG_CS_UPDATE|-WDOG_CS_WAIT|WDOG_CS_STOP;-writel(val,base+WDOG_CS);-imx7ulp_wdt_wait(base,WDOG_CS_RCS);+writel(timeout,wdt->base+WDOG_TOVAL);+writel(cs,wdt->base+WDOG_CS);+local_irq_enable();+ret=imx7ulp_wdt_wait_rcs(wdt);++returnret;init_out:local_irq_enable();+returnret;+}++staticintimx7ulp_wdt_init(structimx7ulp_wdt_device*wdt,unsignedinttimeout)+{+/* enable 32bit command sequence and reconfigure */+u32val=WDOG_CS_CMD32EN|WDOG_CS_CLK|WDOG_CS_UPDATE|+WDOG_CS_WAIT|WDOG_CS_STOP;+u32cs,toval;+intret;+u32loop=RETRY_MAX;++do{+ret=_imx7ulp_wdt_init(wdt,timeout,val);+toval=readl(wdt->base+WDOG_TOVAL);+cs=readl(wdt->base+WDOG_CS);+cs&=~(WDOG_CS_FLG|WDOG_CS_ULK|WDOG_CS_RCS);+}while(--loop>0&&(cs!=val||toval!=timeout||ret));++if(loop==0)+return-EBUSY;returnret;}
From: Alice Guo (OSS) <hidden> Date: 2022-08-25 08:33:43
From: Jason Liu <redacted>
Paired with suspend, we can only init wdog again when it was active
and ping it once to avoid the watchdog timeout after it resumed.
Signed-off-by: Jason Liu <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Ye Li <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Tested-by: Jacky Bai <ping.bai@nxp.com>
---
Changes for v2:
- none
drivers/watchdog/imx7ulp_wdt.c | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
From: Alice Guo (OSS) <hidden> Date: 2022-08-25 08:34:00
From: Alice Guo <redacted>
The WDOG clocks are sourced from lpo_clk, and lpo_clk is the fixed
32KHz. TOVAL contains the 16-bit value used to set the timeout period of
the watchdog. When the timeout period exceeds 2 seconds, the value
written to the TOVAL register is larger than 16-bit can represent.
Enabling watchdog prescaler can solve this problem.
Two points need to be aware of:
1. watchdog prescaler enables a fixed 256 pre-scaling of watchdog
counter reference clock
2. reconfiguration takes about 55ms on imx93
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Signed-off-by: Alice Guo <redacted>
---
Changes for v2:
- none
drivers/watchdog/imx7ulp_wdt.c | 33 ++++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
@@ -52,11 +53,17 @@ module_param(nowayout, bool, 0000);MODULE_PARM_DESC(nowayout,"Watchdog cannot be stopped once started (default="__MODULE_STRING(WATCHDOG_NOWAYOUT)")");+structimx_wdt_hw_feature{+boolprescaler_enable;+u32wdog_clock_rate;+};+structimx7ulp_wdt_device{structwatchdog_devicewdd;void__iomem*base;structclk*clk;boolpost_rcs_wait;+conststructimx_wdt_hw_feature*hw;};staticintimx7ulp_wdt_wait_ulk(void__iomem*base)
@@ -179,7 +186,7 @@ static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog,unsignedinttimeout){structimx7ulp_wdt_device*wdt=watchdog_get_drvdata(wdog);-u32toval=WDOG_CLOCK_RATE*timeout;+u32toval=wdt->hw->wdog_clock_rate*timeout;u32val;intret;u32loop=RETRY_MAX;
@@ -276,6 +283,9 @@ static int imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeoutintret;u32loop=RETRY_MAX;+if(wdt->hw->prescaler_enable)+val|=WDOG_CS_PRES;+do{ret=_imx7ulp_wdt_init(wdt,timeout,val);toval=readl(wdt->base+WDOG_TOVAL);
@@ -346,7 +356,9 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)watchdog_stop_on_reboot(wdog);watchdog_stop_on_unregister(wdog);watchdog_set_drvdata(wdog,imx7ulp_wdt);-ret=imx7ulp_wdt_init(imx7ulp_wdt,wdog->timeout*WDOG_CLOCK_RATE);++imx7ulp_wdt->hw=of_device_get_match_data(dev);+ret=imx7ulp_wdt_init(imx7ulp_wdt,wdog->timeout*imx7ulp_wdt->hw->wdog_clock_rate);if(ret)returnret;
@@ -368,7 +380,7 @@ static int __maybe_unused imx7ulp_wdt_suspend_noirq(struct device *dev)staticint__maybe_unusedimx7ulp_wdt_resume_noirq(structdevice*dev){structimx7ulp_wdt_device*imx7ulp_wdt=dev_get_drvdata(dev);-u32timeout=imx7ulp_wdt->wdd.timeout*WDOG_CLOCK_RATE;+u32timeout=imx7ulp_wdt->wdd.timeout*imx7ulp_wdt->hw->wdog_clock_rate;intret;ret=clk_prepare_enable(imx7ulp_wdt->clk);
On Thu, Aug 25, 2022 at 04:32:50PM +0800, Alice Guo (OSS) wrote:
From: Anson Huang <redacted>
The i.MX7ULP's watchdog is enabled by default when out of reset, so the
resume callback which is to disable watchdog should be called earlier
to avoid unexpected timeout, move suspend/resume callback to noirq phase.
Signed-off-by: Anson Huang <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Tested-by: Peter Chen <redacted>
Tested-by: Li Jun <redacted>
On Thu, Aug 25, 2022 at 04:32:51PM +0800, Alice Guo (OSS) wrote:
From: Jacky Bai <ping.bai@nxp.com>
When reconfiguring the WDOG Timer of i.MX7ULP, there is a certain
probability causes it to reset. The reason is that the CMD32EN of the
WDOG Timer of i.MX7ULP is disabled in bootloader. The unlock sequence
are two 16-bit writes to the CNT register within 16 bus clocks. Adding
mb() is to guarantee that two 16-bit writes are finished within 16 bus
clocks. Memory barriers cannot be added between these two 16-bit writes
so that writel_relaxed is used.
Suggested-by: Ye Li <redacted>
Signed-off-by: Jacky Bai <ping.bai@nxp.com>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Ye Li <redacted>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
quoted hunk
---
Changes for v2:
- add the reason why memory barriers are added for unlock sequence in commit log
drivers/watchdog/imx7ulp_wdt.c | 4 ++++
1 file changed, 4 insertions(+)
@@ -179,9 +179,13 @@ static int imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)intret;local_irq_disable();++mb();/* unlock the wdog for reconfiguration */writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);+mb();+ret=imx7ulp_wdt_wait(base,WDOG_CS_ULK);if(ret)gotoinit_out;
On Thu, Aug 25, 2022 at 04:32:52PM +0800, Alice Guo (OSS) wrote:
From: Ye Li <redacted>
When bootloader has enabled the CMD32EN bit, switch to use 32bits
unlock command to unlock the CS register. Using 32bits command will
help on avoiding 16 bus cycle window violation for two 16 bits
commands.
Signed-off-by: Ye Li <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Acked-by: Jason Liu <redacted>
@@ -180,11 +180,16 @@ static int imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)local_irq_disable();-mb();-/* unlock the wdog for reconfiguration */-writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);-writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);-mb();+val=readl(base+WDOG_CS);+if(val&WDOG_CS_CMD32EN){+writel(UNLOCK,base+WDOG_CNT);+}else{+mb();+/* unlock the wdog for reconfiguration */+writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);+writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);+mb();+}ret=imx7ulp_wdt_wait(base,WDOG_CS_ULK);if(ret)
On Thu, Aug 25, 2022 at 04:32:53PM +0800, Alice Guo (OSS) wrote:
From: Ye Li <redacted>
According to measure on i.MX7ULP and i.MX8ULP, the RCS done needs
about 3400us and 6700us respectively. So current 20us timeout is
not enough. When reconfiguring is on-going, unlock and configure CS
will lead to unknown result.
Increase the wait timeout value to 10ms and check the return value
of RCS wait to fix the issue
Signed-off-by: Ye Li <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Acked-by: Jason Liu <redacted>
On Thu, Aug 25, 2022 at 04:32:54PM +0800, Alice Guo (OSS) wrote:
From: Ye Li <redacted>
Current driver may meet reconfigure failure caused by below reasons:
1. The wdog on iMX7ULP has different behavior after RCS valid. It needs
to wait more than 2.5 wdog clock for clock sync before next
reconfiguration, while imx8ulp wdog does not need such delay.
2. After unlock, there is 128 bus clock window opened for reconfiguration,
but on iMX8ULP, the HW can't guarantee the latency. So it is possible
the window is closed before the writing arrives to wdog.
3. If the PRES is enabled, the RCS valid time becomes x256 to the time
of PRES disabled. It is about 1715ms on iMX8ULP. So We have to increase
the RCS timeout and can't wait it in IRQ disabled.
The patch updates the driver to handle failures
1. Using different wait for unlock and RCS. Unlock valid time is very short
and only related to bus clock. It must be in IRQ disabled to avoid
being interrupted in 128 clock window. But for RCS time, it is longer
and ok for IRQ enabled.
2. Add retry for any reconfigure failure with default 5 times.
3. Add "fsl,imx8ulp-wdt" compatile string for iMX8ULP and afterwards
platform which don't need more 2.5 wdog clock after RCS valid.
For imx7ulp, add post delay of 2.5 clock after RCS valid.
Signed-off-by: Ye Li <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
quoted hunk
---
Changes for v2:
- the wait timeout value of the RCS is 10ms, so use the sleep_us of
readl_poll_timeout in imx7ulp_wdt_wait_rcs to avoid a 10ms hot wait
drivers/watchdog/imx7ulp_wdt.c | 163 ++++++++++++++++++++++++++-------
1 file changed, 129 insertions(+), 34 deletions(-)
@@ -114,28 +162,44 @@ static int imx7ulp_wdt_stop(struct watchdog_device *wdog)returnimx7ulp_wdt_enable(wdog,false);}-staticintimx7ulp_wdt_set_timeout(structwatchdog_device*wdog,-unsignedinttimeout)+staticint_imx7ulp_wdt_set_timeout(structimx7ulp_wdt_device*wdt,+unsignedinttoval){-structimx7ulp_wdt_device*wdt=watchdog_get_drvdata(wdog);-u32val=WDOG_CLOCK_RATE*timeout;intret;local_irq_disable();writel(UNLOCK,wdt->base+WDOG_CNT);-ret=imx7ulp_wdt_wait(wdt->base,WDOG_CS_ULK);+ret=imx7ulp_wdt_wait_ulk(wdt->base);if(ret)gototimeout_out;-writel(val,wdt->base+WDOG_TOVAL);-ret=imx7ulp_wdt_wait(wdt->base,WDOG_CS_RCS);-if(ret)-gototimeout_out;--wdog->timeout=timeout;+writel(toval,wdt->base+WDOG_TOVAL);+local_irq_enable();+ret=imx7ulp_wdt_wait_rcs(wdt);+returnret;timeout_out:local_irq_enable();+returnret;+}+staticintimx7ulp_wdt_set_timeout(structwatchdog_device*wdog,+unsignedinttimeout)+{+structimx7ulp_wdt_device*wdt=watchdog_get_drvdata(wdog);+u32toval=WDOG_CLOCK_RATE*timeout;+u32val;+intret;+u32loop=RETRY_MAX;++do{+ret=_imx7ulp_wdt_set_timeout(wdt,toval);+val=readl(wdt->base+WDOG_TOVAL);+}while(--loop>0&&(val!=toval||ret));++if(loop==0)+return-EBUSY;++wdog->timeout=timeout;returnret;}
@@ -175,38 +239,59 @@ static const struct watchdog_info imx7ulp_wdt_info = {WDIOF_MAGICCLOSE,};-staticintimx7ulp_wdt_init(void__iomem*base,unsignedinttimeout)+staticint_imx7ulp_wdt_init(structimx7ulp_wdt_device*wdt,unsignedinttimeout,unsignedintcs){u32val;intret;local_irq_disable();-val=readl(base+WDOG_CS);+val=readl(wdt->base+WDOG_CS);if(val&WDOG_CS_CMD32EN){-writel(UNLOCK,base+WDOG_CNT);+writel(UNLOCK,wdt->base+WDOG_CNT);}else{mb();/* unlock the wdog for reconfiguration */-writel_relaxed(UNLOCK_SEQ0,base+WDOG_CNT);-writel_relaxed(UNLOCK_SEQ1,base+WDOG_CNT);+writel_relaxed(UNLOCK_SEQ0,wdt->base+WDOG_CNT);+writel_relaxed(UNLOCK_SEQ1,wdt->base+WDOG_CNT);mb();}-ret=imx7ulp_wdt_wait(base,WDOG_CS_ULK);+ret=imx7ulp_wdt_wait_ulk(wdt->base);if(ret)gotoinit_out;/* set an initial timeout value in TOVAL */-writel(timeout,base+WDOG_TOVAL);-/* enable 32bit command sequence and reconfigure */-val=WDOG_CS_CMD32EN|WDOG_CS_CLK|WDOG_CS_UPDATE|-WDOG_CS_WAIT|WDOG_CS_STOP;-writel(val,base+WDOG_CS);-imx7ulp_wdt_wait(base,WDOG_CS_RCS);+writel(timeout,wdt->base+WDOG_TOVAL);+writel(cs,wdt->base+WDOG_CS);+local_irq_enable();+ret=imx7ulp_wdt_wait_rcs(wdt);++returnret;init_out:local_irq_enable();+returnret;+}++staticintimx7ulp_wdt_init(structimx7ulp_wdt_device*wdt,unsignedinttimeout)+{+/* enable 32bit command sequence and reconfigure */+u32val=WDOG_CS_CMD32EN|WDOG_CS_CLK|WDOG_CS_UPDATE|+WDOG_CS_WAIT|WDOG_CS_STOP;+u32cs,toval;+intret;+u32loop=RETRY_MAX;++do{+ret=_imx7ulp_wdt_init(wdt,timeout,val);+toval=readl(wdt->base+WDOG_TOVAL);+cs=readl(wdt->base+WDOG_CS);+cs&=~(WDOG_CS_FLG|WDOG_CS_ULK|WDOG_CS_RCS);+}while(--loop>0&&(cs!=val||toval!=timeout||ret));++if(loop==0)+return-EBUSY;returnret;}
On Thu, Aug 25, 2022 at 04:32:55PM +0800, Alice Guo (OSS) wrote:
From: Jason Liu <redacted>
Paired with suspend, we can only init wdog again when it was active
and ping it once to avoid the watchdog timeout after it resumed.
Signed-off-by: Jason Liu <redacted>
Signed-off-by: Alice Guo <redacted>
Reviewed-by: Ye Li <redacted>
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Tested-by: Jacky Bai <ping.bai@nxp.com>
On Thu, Aug 25, 2022 at 04:32:56PM +0800, Alice Guo (OSS) wrote:
From: Alice Guo <redacted>
The WDOG clocks are sourced from lpo_clk, and lpo_clk is the fixed
32KHz. TOVAL contains the 16-bit value used to set the timeout period of
the watchdog. When the timeout period exceeds 2 seconds, the value
written to the TOVAL register is larger than 16-bit can represent.
Enabling watchdog prescaler can solve this problem.
Two points need to be aware of:
1. watchdog prescaler enables a fixed 256 pre-scaling of watchdog
counter reference clock
2. reconfiguration takes about 55ms on imx93
Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Signed-off-by: Alice Guo <redacted>
@@ -52,11 +53,17 @@ module_param(nowayout, bool, 0000);MODULE_PARM_DESC(nowayout,"Watchdog cannot be stopped once started (default="__MODULE_STRING(WATCHDOG_NOWAYOUT)")");+structimx_wdt_hw_feature{+boolprescaler_enable;+u32wdog_clock_rate;+};+structimx7ulp_wdt_device{structwatchdog_devicewdd;void__iomem*base;structclk*clk;boolpost_rcs_wait;+conststructimx_wdt_hw_feature*hw;};staticintimx7ulp_wdt_wait_ulk(void__iomem*base)
@@ -179,7 +186,7 @@ static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog,unsignedinttimeout){structimx7ulp_wdt_device*wdt=watchdog_get_drvdata(wdog);-u32toval=WDOG_CLOCK_RATE*timeout;+u32toval=wdt->hw->wdog_clock_rate*timeout;u32val;intret;u32loop=RETRY_MAX;
@@ -276,6 +283,9 @@ static int imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeoutintret;u32loop=RETRY_MAX;+if(wdt->hw->prescaler_enable)+val|=WDOG_CS_PRES;+do{ret=_imx7ulp_wdt_init(wdt,timeout,val);toval=readl(wdt->base+WDOG_TOVAL);
@@ -346,7 +356,9 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)watchdog_stop_on_reboot(wdog);watchdog_stop_on_unregister(wdog);watchdog_set_drvdata(wdog,imx7ulp_wdt);-ret=imx7ulp_wdt_init(imx7ulp_wdt,wdog->timeout*WDOG_CLOCK_RATE);++imx7ulp_wdt->hw=of_device_get_match_data(dev);+ret=imx7ulp_wdt_init(imx7ulp_wdt,wdog->timeout*imx7ulp_wdt->hw->wdog_clock_rate);if(ret)returnret;
@@ -368,7 +380,7 @@ static int __maybe_unused imx7ulp_wdt_suspend_noirq(struct device *dev)staticint__maybe_unusedimx7ulp_wdt_resume_noirq(structdevice*dev){structimx7ulp_wdt_device*imx7ulp_wdt=dev_get_drvdata(dev);-u32timeout=imx7ulp_wdt->wdd.timeout*WDOG_CLOCK_RATE;+u32timeout=imx7ulp_wdt->wdd.timeout*imx7ulp_wdt->hw->wdog_clock_rate;intret;ret=clk_prepare_enable(imx7ulp_wdt->clk);