Re: [PATCH 1/2] rtc: m48t59: Accommodate chips that lack a century bit

From: Finn Thain
Date: Sat Oct 05 2024 - 00:23:37 EST



On Thu, 3 Oct 2024, Alexandre Belloni wrote:

>
> ... while you are it, can you use m48t59->rtc->start_secs and
> m48t59->rtc->set_start_time in probe instead of offsetting tm_year in
> read_time/set_time so we can later use device tree or any other
> mechanism to extend the range?
>

That didn't work out as I'd hoped. I booted a patched kernel (diff below)
under qemu-system-sparc64:

~ # for yyyy in 1970 1971 1999 2000 2024 2025 2068 2069 ; do
date 01010101$yyyy ; hwclock --systohc --utc && hwclock --utc ; echo ; done
Thu Jan 1 01:01:00 UTC 1970
Thu Jan 1 01:01:00 1970 0.000000 seconds

Fri Jan 1 01:01:00 UTC 1971
Tue Nov 24 18:32:44 1998 0.000000 seconds

Fri Jan 1 01:01:00 UTC 1999
Tue Nov 24 18:32:44 2026 0.000000 seconds

Sat Jan 1 01:01:00 UTC 2000
Sun Jan 2 23:29:16 2000 0.000000 seconds

Mon Jan 1 01:01:00 UTC 2024
Tue Jan 2 23:29:16 2024 0.000000 seconds

Wed Jan 1 01:01:00 UTC 2025
Thu Jan 2 23:29:16 2025 0.000000 seconds

Sun Jan 1 01:01:00 UTC 2068
hwclock: RTC_SET_TIME: Numerical result out of range

Tue Jan 1 01:01:00 UTC 2069
hwclock: RTC_SET_TIME: Numerical result out of range

~ #

Here's the result from an unpatched kernel (v6.11):

~ # for yyyy in 1970 1971 1999 2000 2024 2025 2068 2069 ; do
date 01010101$yyyy ; hwclock --systohc --utc && hwclock --utc ; echo ; done
Thu Jan 1 01:01:00 UTC 1970
Thu Jan 1 01:01:00 1970 0.000000 seconds

Fri Jan 1 01:01:00 UTC 1971
Fri Jan 1 01:01:00 1971 0.000000 seconds

Fri Jan 1 01:01:00 UTC 1999
Fri Jan 1 01:01:01 1999 0.000000 seconds

Sat Jan 1 01:01:00 UTC 2000
Sat Jan 1 01:01:00 2000 0.000000 seconds

Mon Jan 1 01:01:00 UTC 2024
Mon Jan 1 01:01:00 2024 0.000000 seconds

Wed Jan 1 01:01:00 UTC 2025
Wed Jan 1 01:01:00 2025 0.000000 seconds

Sun Jan 1 01:01:00 UTC 2068
hwclock: RTC_RD_TIME: Invalid argument

Tue Jan 1 01:01:00 UTC 2069
hwclock: RTC_RD_TIME: Invalid argument

~ #


I'm afraid I don't see how we might avoid adding/subtracting in
read_time/set_time given that we must avoid messing up the present date
when users boot into an upgraded kernel.


diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index 08bbdc458596..41ae3d1aa12e 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -255,6 +255,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
static struct m48t59_plat_data m48t59_data = {
.read_byte = mostek_read_byte,
.write_byte = mostek_write_byte,
+ .start_year = 1968,
};

/* resource is set at runtime */
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index 60f1c8cc5363..eceb3fadb71a 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -544,6 +544,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
static struct m48t59_plat_data m48t59_data = {
.read_byte = mostek_read_byte,
.write_byte = mostek_write_byte,
+ .start_year = 1968,
};

static struct platform_device m48t59_rtc = {
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index f0f6b9b6daec..d7e1f79cd52b 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -82,10 +82,6 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
dev_dbg(dev, "Century bit is enabled\n");
tm->tm_year += 100; /* one century */
}
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- tm->tm_year += 68;
-#endif

tm->tm_wday = bcd2bin(val & 0x07);
tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F);
@@ -108,11 +104,6 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 val = 0;
int year = tm->tm_year;

-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- year -= 68;
-#endif
-
dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n",
year + 1900, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -163,10 +154,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);

tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- tm->tm_year += 68;
-#endif
+
/* tm_mon is 0-11 */
tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;

@@ -199,11 +187,6 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
unsigned long flags;
int year = tm->tm_year;

-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- year -= 68;
-#endif
-
/* If no irq, we don't support ALARM */
if (m48t59->irq == NO_IRQ)
return -EIO;
@@ -458,6 +441,10 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, m48t59);

m48t59->rtc->ops = &m48t59_rtc_ops;
+ m48t59->rtc->range_min = mktime64(1900, 1, 1, 0, 0, 0);
+ m48t59->rtc->range_max = mktime64(1999, 12, 31, 23, 59, 59);
+ m48t59->rtc->start_secs = mktime64(pdata->start_year, 1, 1, 0, 0, 0);
+ m48t59->rtc->set_start_time = true;

nvmem_cfg.size = pdata->offset;
ret = devm_rtc_nvmem_register(m48t59->rtc, &nvmem_cfg);
diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h
index 9465d5405fe2..b01c514d7079 100644
--- a/include/linux/rtc/m48t59.h
+++ b/include/linux/rtc/m48t59.h
@@ -56,6 +56,9 @@ struct m48t59_plat_data {
void __iomem *ioaddr;
/* offset to RTC registers, automatically set according to the type */
unsigned int offset;
+
+ /* value to be used to initialize rtc->start_secs */
+ time64_t start_year;
};

#endif /* _LINUX_RTC_M48T59_H_ */