rtc: s3c-rtc: Avoid using broken ALMYEAR register

Message ID 20181113113250.15527-1-m.szyprowski@samsung.com
State New
Headers show
Series
  • rtc: s3c-rtc: Avoid using broken ALMYEAR register
Related show

Commit Message

Marek Szyprowski Nov. 13, 2018, 11:32 a.m.
(RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD
characters. s3c-rtc driver uses only 2 lower of them and supports years
from 2000..2099 range. The third BCD value is typically set to 0, but it
looks that handling of it is broken in the hardware. It sometimes
defaults to a random (even non-BCD) value. This is not an issue
for handling RTCYEAR register, because bcd2bin() properly handles only
8bit values (2 BCD characters, the third one is skipped). The problem
is however with ALMYEAR register and proper RTC alarm operation. When
YEAREN bit is set for the configured alarm, RTC hardware triggers alarm
only when ALMYEAR and RTCYEAR matches. This usually doesn't happen
because of the random noise on the third BCD character.

Fix this by simply skipping setting ALMYEAR register in alarm
configuration. This workaround fixes broken alarm operation on Exynos
built-in rtc device. My tests revealed that the issue happens on the
following Exynos series: 3250, 4210, 4412, 5250 and 5410.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

---
 drivers/rtc/rtc-s3c.c | 6 ------
 1 file changed, 6 deletions(-)

-- 
2.17.1

Comments

Alexandre Belloni Nov. 13, 2018, 11:39 a.m. | #1
Hello Marek,

On 13/11/2018 12:32:50+0100, Marek Szyprowski wrote:
> (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD

> characters. s3c-rtc driver uses only 2 lower of them and supports years

> from 2000..2099 range. The third BCD value is typically set to 0, but it

> looks that handling of it is broken in the hardware. It sometimes

> defaults to a random (even non-BCD) value. This is not an issue

> for handling RTCYEAR register, because bcd2bin() properly handles only

> 8bit values (2 BCD characters, the third one is skipped). The problem

> is however with ALMYEAR register and proper RTC alarm operation. When

> YEAREN bit is set for the configured alarm, RTC hardware triggers alarm

> only when ALMYEAR and RTCYEAR matches. This usually doesn't happen

> because of the random noise on the third BCD character.

> 


I'm probably missing something but can't you set that third BCD value to
0 in ALMYEAR?

> Fix this by simply skipping setting ALMYEAR register in alarm

> configuration. This workaround fixes broken alarm operation on Exynos

> built-in rtc device. My tests revealed that the issue happens on the

> following Exynos series: 3250, 4210, 4412, 5250 and 5410.

> 

> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---

>  drivers/rtc/rtc-s3c.c | 6 ------

>  1 file changed, 6 deletions(-)

> 

> diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c

> index 75c8c5033e08..58e03ac3578b 100644

> --- a/drivers/rtc/rtc-s3c.c

> +++ b/drivers/rtc/rtc-s3c.c

> @@ -327,7 +327,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)

>  	struct rtc_time *tm = &alrm->time;

>  	unsigned int alrm_en;

>  	int ret;

> -	int year = tm->tm_year - 100;

>  

>  	dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",

>  		alrm->enabled,

> @@ -356,11 +355,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)

>  		writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);

>  	}

>  

> -	if (year < 100 && year >= 0) {

> -		alrm_en |= S3C2410_RTCALM_YEAREN;

> -		writeb(bin2bcd(year), info->base + S3C2410_ALMYEAR);

> -	}

> -

>  	if (tm->tm_mon < 12 && tm->tm_mon >= 0) {

>  		alrm_en |= S3C2410_RTCALM_MONEN;

>  		writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);

> -- 

> 2.17.1

> 


-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Krzysztof Kozlowski Nov. 13, 2018, 11:50 a.m. | #2
On Tue, 13 Nov 2018 at 12:33, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>

> (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD

> characters. s3c-rtc driver uses only 2 lower of them and supports years

> from 2000..2099 range. The third BCD value is typically set to 0, but it

> looks that handling of it is broken in the hardware. It sometimes

> defaults to a random (even non-BCD) value. This is not an issue

> for handling RTCYEAR register, because bcd2bin() properly handles only

> 8bit values (2 BCD characters, the third one is skipped). The problem

> is however with ALMYEAR register and proper RTC alarm operation. When

> YEAREN bit is set for the configured alarm, RTC hardware triggers alarm

> only when ALMYEAR and RTCYEAR matches. This usually doesn't happen

> because of the random noise on the third BCD character.

>

> Fix this by simply skipping setting ALMYEAR register in alarm

> configuration. This workaround fixes broken alarm operation on Exynos

> built-in rtc device. My tests revealed that the issue happens on the

> following Exynos series: 3250, 4210, 4412, 5250 and 5410.


Does it mean that alarm set for 20.11.2019 will be triggered also this
year on 20.11.2018 (and any other year as well)?

Best regards,
Krzysztof

> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---

>  drivers/rtc/rtc-s3c.c | 6 ------

>  1 file changed, 6 deletions(-)

>

> diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c

> index 75c8c5033e08..58e03ac3578b 100644

> --- a/drivers/rtc/rtc-s3c.c

> +++ b/drivers/rtc/rtc-s3c.c

> @@ -327,7 +327,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)

>         struct rtc_time *tm = &alrm->time;

>         unsigned int alrm_en;

>         int ret;

> -       int year = tm->tm_year - 100;

>

>         dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",

>                 alrm->enabled,

> @@ -356,11 +355,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)

>                 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);

>         }

>

> -       if (year < 100 && year >= 0) {

> -               alrm_en |= S3C2410_RTCALM_YEAREN;

> -               writeb(bin2bcd(year), info->base + S3C2410_ALMYEAR);

> -       }

> -

>         if (tm->tm_mon < 12 && tm->tm_mon >= 0) {

>                 alrm_en |= S3C2410_RTCALM_MONEN;

>                 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);

> --

> 2.17.1

>
Marek Szyprowski Nov. 13, 2018, 11:52 a.m. | #3
Hi Alexandre,

On 2018-11-13 12:39, Alexandre Belloni wrote:
> On 13/11/2018 12:32:50+0100, Marek Szyprowski wrote:

>> (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD

>> characters. s3c-rtc driver uses only 2 lower of them and supports years

>> from 2000..2099 range. The third BCD value is typically set to 0, but it

>> looks that handling of it is broken in the hardware. It sometimes

>> defaults to a random (even non-BCD) value. This is not an issue

>> for handling RTCYEAR register, because bcd2bin() properly handles only

>> 8bit values (2 BCD characters, the third one is skipped). The problem

>> is however with ALMYEAR register and proper RTC alarm operation. When

>> YEAREN bit is set for the configured alarm, RTC hardware triggers alarm

>> only when ALMYEAR and RTCYEAR matches. This usually doesn't happen

>> because of the random noise on the third BCD character.

>>

> I'm probably missing something but can't you set that third BCD value to

> 0 in ALMYEAR?



s3c-rtc code sets it to 0 already, both for ALMYEAR and RTCYEAR registers
(bin2bcd returns 2 BCD characters, which are written to the register as u32,
with leading zeros). However I've observed that both mentioned registers
after such operation can still contain random noise on the third BCD
character, what make the alarm completely unreliable.

> ...



Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland
Marek Szyprowski Nov. 13, 2018, 12:15 p.m. | #4
Hi Krzysztof,

On 2018-11-13 12:50, Krzysztof Kozlowski wrote:
> On Tue, 13 Nov 2018 at 12:33, Marek Szyprowski <m.szyprowski@samsung.com> wrote:

>> (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD

>> characters. s3c-rtc driver uses only 2 lower of them and supports years

>> from 2000..2099 range. The third BCD value is typically set to 0, but it

>> looks that handling of it is broken in the hardware. It sometimes

>> defaults to a random (even non-BCD) value. This is not an issue

>> for handling RTCYEAR register, because bcd2bin() properly handles only

>> 8bit values (2 BCD characters, the third one is skipped). The problem

>> is however with ALMYEAR register and proper RTC alarm operation. When

>> YEAREN bit is set for the configured alarm, RTC hardware triggers alarm

>> only when ALMYEAR and RTCYEAR matches. This usually doesn't happen

>> because of the random noise on the third BCD character.

>>

>> Fix this by simply skipping setting ALMYEAR register in alarm

>> configuration. This workaround fixes broken alarm operation on Exynos

>> built-in rtc device. My tests revealed that the issue happens on the

>> following Exynos series: 3250, 4210, 4412, 5250 and 5410.

> Does it mean that alarm set for 20.11.2019 will be triggered also this

> year on 20.11.2018 (and any other year as well)?

Yes, this will trigger one year earlier.
The question is if this is really and issue in typical use cases...

The only other workaround I see is to store the requested alarm time in
the driver context and check each time when it triggers interrupt if the
year matches requested value.

> ...


Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland
Alexandre Belloni Nov. 13, 2018, 12:33 p.m. | #5
On 13/11/2018 13:15:33+0100, Marek Szyprowski wrote:
> Hi Krzysztof,

> 

> On 2018-11-13 12:50, Krzysztof Kozlowski wrote:

> > On Tue, 13 Nov 2018 at 12:33, Marek Szyprowski <m.szyprowski@samsung.com> wrote:

> >> (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD

> >> characters. s3c-rtc driver uses only 2 lower of them and supports years

> >> from 2000..2099 range. The third BCD value is typically set to 0, but it

> >> looks that handling of it is broken in the hardware. It sometimes

> >> defaults to a random (even non-BCD) value. This is not an issue

> >> for handling RTCYEAR register, because bcd2bin() properly handles only

> >> 8bit values (2 BCD characters, the third one is skipped). The problem

> >> is however with ALMYEAR register and proper RTC alarm operation. When

> >> YEAREN bit is set for the configured alarm, RTC hardware triggers alarm

> >> only when ALMYEAR and RTCYEAR matches. This usually doesn't happen

> >> because of the random noise on the third BCD character.

> >>

> >> Fix this by simply skipping setting ALMYEAR register in alarm

> >> configuration. This workaround fixes broken alarm operation on Exynos

> >> built-in rtc device. My tests revealed that the issue happens on the

> >> following Exynos series: 3250, 4210, 4412, 5250 and 5410.

> > Does it mean that alarm set for 20.11.2019 will be triggered also this

> > year on 20.11.2018 (and any other year as well)?

> Yes, this will trigger one year earlier.

> The question is if this is really and issue in typical use cases...

> 


Note that the core will already set the alarm again if it fired too
early. So this is way better than not firing at all.

-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
Alexandre Belloni Nov. 14, 2018, 9:59 a.m. | #6
On 13/11/2018 12:32:50+0100, Marek Szyprowski wrote:
> (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD

> characters. s3c-rtc driver uses only 2 lower of them and supports years

> from 2000..2099 range. The third BCD value is typically set to 0, but it

> looks that handling of it is broken in the hardware. It sometimes

> defaults to a random (even non-BCD) value. This is not an issue

> for handling RTCYEAR register, because bcd2bin() properly handles only

> 8bit values (2 BCD characters, the third one is skipped). The problem

> is however with ALMYEAR register and proper RTC alarm operation. When

> YEAREN bit is set for the configured alarm, RTC hardware triggers alarm

> only when ALMYEAR and RTCYEAR matches. This usually doesn't happen

> because of the random noise on the third BCD character.

> 

> Fix this by simply skipping setting ALMYEAR register in alarm

> configuration. This workaround fixes broken alarm operation on Exynos

> built-in rtc device. My tests revealed that the issue happens on the

> following Exynos series: 3250, 4210, 4412, 5250 and 5410.

> 

> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---

>  drivers/rtc/rtc-s3c.c | 6 ------

>  1 file changed, 6 deletions(-)

> 

Applied, thanks.

-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

Patch

diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 75c8c5033e08..58e03ac3578b 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -327,7 +327,6 @@  static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 	struct rtc_time *tm = &alrm->time;
 	unsigned int alrm_en;
 	int ret;
-	int year = tm->tm_year - 100;
 
 	dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
 		alrm->enabled,
@@ -356,11 +355,6 @@  static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 		writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
 	}
 
-	if (year < 100 && year >= 0) {
-		alrm_en |= S3C2410_RTCALM_YEAREN;
-		writeb(bin2bcd(year), info->base + S3C2410_ALMYEAR);
-	}
-
 	if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
 		alrm_en |= S3C2410_RTCALM_MONEN;
 		writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);