2014-04-25 09:33:07

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 0/7] rtc-cmos: private locking and MMIO support

The original PC-style CMOS RTC driver is so weird and full of hacks
that it has reached the status of a major piece of art.

Despite noticeable efforts to carry on with the spirit of tainting
every architecture under the sun, this patch series tries to make the
rtc-cmos driver a slightly better citizen by allowing architecture
code *not* to provide an exported lock when it is not strictly
required, and to allow for MMIO accessors on architectures that don't
have IO ports.

Please have a bucket ready.

The actual goal of the exercise is to allow the use of the RTC
emulation provided by kvmtool in KVM/ARM guests. This series has also
been tested on x86.

Marc Zyngier (7):
rtc-cmos: abstract IO accessors
rtc-cmos: abstract locking primitives
rtc-cmos: allow MMIO to be used when initialized from FDT
rtc-cmos: allow strictly MMIO based configurations
rtc-cmos: implement driver private locking
ARM: rtc: update CMOS RTC to support MMIO and private lock
arm64: rtc: plug the PC CMOS RTC using MMIO accessors

arch/arm/kernel/time.c | 7 --
arch/arm64/include/asm/mc146818rtc.h | 10 ++
drivers/rtc/Kconfig | 15 ++-
drivers/rtc/rtc-cmos.c | 217 +++++++++++++++++++++++++----------
include/asm-generic/rtc.h | 92 ++++++++++-----
5 files changed, 240 insertions(+), 101 deletions(-)
create mode 100644 arch/arm64/include/asm/mc146818rtc.h

--
1.8.3.4


2014-04-25 09:31:29

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 5/7] rtc-cmos: implement driver private locking

A number of architecture happen to share a lock between the rtc-cmos
driver and the core architectural code for good reasons (or at least,
reasons that matter to the architecture).

Other architectures don't do that, but still have to define a lock
that is only used by the RTC driver. How annoying!

Implement a set of driver private locking primitives, and expose
a config option allowing the architecture to select it if it doesn't
require to share the lock with the RTC driver.

Signed-off-by: Marc Zyngier <[email protected]>
---
drivers/rtc/Kconfig | 3 +++
drivers/rtc/rtc-cmos.c | 16 ++++++++++++++++
include/asm-generic/rtc.h | 5 +++++
3 files changed, 24 insertions(+)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 10974f7..12bc27d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -684,6 +684,9 @@ config RTC_DRV_CMOS_MMIO_STRICT
select RTC_DRV_CMOS_MMIO
bool

+config RTC_DRV_CMOS_PRIV_LOCK
+ bool
+
config RTC_DRV_ALPHA
bool "Alpha PC-style CMOS"
depends on ALPHA
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index e2d1338..eb5d05c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -107,6 +107,22 @@ static inline void rtc_cmos_set_base(void __iomem *base)
static void rtc_cmos_set_base(void __iomem *base) {}
#endif

+#ifdef CONFIG_RTC_DRV_CMOS_PRIV_LOCK
+static DEFINE_SPINLOCK(rtc_private_lock);
+
+static unsigned long rtc_cmos_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&rtc_private_lock, flags);
+ return flags;
+}
+
+static void rtc_cmos_unlock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&rtc_private_lock, flags);
+}
+#endif
+
/* The RTC_INTR register may have e.g. RTC_PF set even if RTC_PIE is clear;
* always mask it against the irq enable bits in RTC_CONTROL. Bit values
* are the same: PF==PIE, AF=AIE, UF=UIE; so RTC_IRQMASK works with both.
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index 236693b..1d21408 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -43,6 +43,10 @@ static inline void do_cmos_write(u8 val, u8 reg)
}
#endif

+#ifdef CONFIG_RTC_DRV_CMOS_PRIV_LOCK
+static unsigned long rtc_cmos_lock(void);
+static void rtc_cmos_unlock(unsigned long flags);
+#else
static inline unsigned long rtc_cmos_lock(void)
{
unsigned long flags;
@@ -54,6 +58,7 @@ static inline void rtc_cmos_unlock(unsigned long flags)
{
spin_unlock_irqrestore(&rtc_lock, flags);
}
+#endif

/*
* Returns true if a clock update is in progress
--
1.8.3.4

2014-04-25 09:31:27

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 3/7] rtc-cmos: allow MMIO to be used when initialized from FDT

Currently, rtc-cmos mandates the use of an I/O port. If the
resource obtained from the device tree is instead a memory mapped
range, the probing will fail.

Let the cmos_of_init function try to ioremap the range obtained
from FDT. Should this fail, fallback to the normal I/O port.

Tested on KVM/ARM with kvmtools as the backend for RTC emulation.

Signed-off-by: Marc Zyngier <[email protected]>
---
drivers/rtc/Kconfig | 3 +++
drivers/rtc/rtc-cmos.c | 67 ++++++++++++++++++++++++++++++++++++++++++-----
include/asm-generic/rtc.h | 5 ++++
3 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2e565f8..7e88866 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -677,6 +677,9 @@ config RTC_DRV_CMOS
This driver can also be built as a module. If so, the module
will be called rtc-cmos.

+config RTC_DRV_CMOS_MMIO
+ bool
+
config RTC_DRV_ALPHA
bool "Alpha PC-style CMOS"
depends on ALPHA
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index be2dd17..d535e72 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -37,6 +37,7 @@
#include <linux/log2.h>
#include <linux/pm.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/dmi.h>

@@ -66,6 +67,41 @@ struct cmos_rtc {

static const char driver_name[] = "rtc_cmos";

+#ifdef CONFIG_RTC_DRV_CMOS_MMIO
+static void __iomem *rtc_cmos_base;
+
+static u8 do_cmos_read(u8 reg)
+{
+ u8 val;
+
+ if (rtc_cmos_base) {
+ writeb(reg, rtc_cmos_base);
+ val = readb(rtc_cmos_base + 1);
+ } else {
+ val = CMOS_READ(reg);
+ }
+
+ return val;
+}
+
+static void do_cmos_write(u8 val, u8 reg)
+{
+ if (rtc_cmos_base) {
+ writeb(reg, rtc_cmos_base);
+ writeb(val, rtc_cmos_base + 1);
+ } else {
+ CMOS_WRITE(val, reg);
+ }
+}
+
+static inline void rtc_cmos_set_base(void __iomem *base)
+{
+ rtc_cmos_base = base;
+}
+#else
+static void rtc_cmos_set_base(void __iomem *base) {}
+#endif
+
/* The RTC_INTR register may have e.g. RTC_PF set even if RTC_PIE is clear;
* always mask it against the irq enable bits in RTC_CONTROL. Bit values
* are the same: PF==PIE, AF=AIE, UF=UIE; so RTC_IRQMASK works with both.
@@ -663,13 +699,23 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
return -ENODEV;

/* Claim I/O ports ASAP, minimizing conflict with legacy driver.
- *
- * REVISIT non-x86 systems may instead use memory space resources
- * (needing ioremap etc), not i/o space resources like this ...
+ * MMIO gets requested the same way, not that it matters much.
*/
- ports = request_region(ports->start,
- resource_size(ports),
- driver_name);
+ switch(resource_type(ports)) {
+ case IORESOURCE_IO:
+ ports = request_region(ports->start,
+ resource_size(ports),
+ driver_name);
+ break;
+ case IORESOURCE_MEM:
+ ports = request_mem_region(ports->start,
+ resource_size(ports),
+ driver_name);
+ break;
+ default: /* Martian I/O??? */
+ ports = NULL;
+ }
+
if (!ports) {
dev_dbg(dev, "i/o registers already in use\n");
return -EBUSY;
@@ -1160,10 +1206,17 @@ static inline void cmos_of_init(struct platform_device *pdev) {}

static int __init cmos_platform_probe(struct platform_device *pdev)
{
+ struct resource *ports;
+
cmos_of_init(pdev);
+
+ ports = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!ports)
+ ports = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
cmos_wake_setup(&pdev->dev);
return cmos_do_probe(&pdev->dev,
- platform_get_resource(pdev, IORESOURCE_IO, 0),
+ ports,
platform_get_irq(pdev, 0));
}

diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index 1ad3e78..236693b 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -28,6 +28,10 @@
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */

+#ifdef CONFIG_RTC_DRV_CMOS_MMIO
+static u8 do_cmos_read(u8 reg);
+static void do_cmos_write(u8 val, u8 reg);
+#else
static inline u8 do_cmos_read(u8 reg)
{
return CMOS_READ(reg);
@@ -37,6 +41,7 @@ static inline void do_cmos_write(u8 val, u8 reg)
{
CMOS_WRITE(val, reg);
}
+#endif

static inline unsigned long rtc_cmos_lock(void)
{
--
1.8.3.4

2014-04-25 09:31:26

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 4/7] rtc-cmos: allow strictly MMIO based configurations

For those new fancy architectures lacking any kind of I/O ports,
and unwilling to emulate them, introduce the new config symbol
RTC_DRV_CMOS_MMIO_STRICT, which provides default (and explosive)
legacy I/O port accessors.

Signed-off-by: Marc Zyngier <[email protected]>
---
drivers/rtc/Kconfig | 4 ++++
drivers/rtc/rtc-cmos.c | 5 +++++
2 files changed, 9 insertions(+)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 7e88866..10974f7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -680,6 +680,10 @@ config RTC_DRV_CMOS
config RTC_DRV_CMOS_MMIO
bool

+config RTC_DRV_CMOS_MMIO_STRICT
+ select RTC_DRV_CMOS_MMIO
+ bool
+
config RTC_DRV_ALPHA
bool "Alpha PC-style CMOS"
depends on ALPHA
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index d535e72..e2d1338 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -70,6 +70,11 @@ static const char driver_name[] = "rtc_cmos";
#ifdef CONFIG_RTC_DRV_CMOS_MMIO
static void __iomem *rtc_cmos_base;

+#ifdef CONFIG_RTC_DRV_CMOS_MMIO_STRICT
+#define CMOS_READ(reg) ({BUG(); 0;})
+#define CMOS_WRITE(val,reg) BUG();
+#endif
+
static u8 do_cmos_read(u8 reg)
{
u8 val;
--
1.8.3.4

2014-04-25 09:36:00

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 2/7] rtc-cmos: abstract locking primitives

In order to be able to allow some architecture not to provide
the dreaded rtc_lock, define a couple of wrappers for taking/releasing
the lock.

Signed-off-by: Marc Zyngier <[email protected]>
---
drivers/rtc/rtc-cmos.c | 55 ++++++++++++++++++++++++++++-------------------
include/asm-generic/rtc.h | 27 +++++++++++++++++------
2 files changed, 53 insertions(+), 29 deletions(-)

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index ae895e8..be2dd17 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -209,6 +209,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char rtc_control;
+ unsigned long flags;

if (!is_valid_irq(cmos->irq))
return -EIO;
@@ -220,7 +221,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->time.tm_mday = -1;
t->time.tm_mon = -1;

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
t->time.tm_sec = do_cmos_read(RTC_SECONDS_ALARM);
t->time.tm_min = do_cmos_read(RTC_MINUTES_ALARM);
t->time.tm_hour = do_cmos_read(RTC_HOURS_ALARM);
@@ -239,7 +240,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
}

rtc_control = do_cmos_read(RTC_CONTROL);
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
if (((unsigned)t->time.tm_sec) < 0x60)
@@ -327,6 +328,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char mon, mday, hrs, min, sec, rtc_control;
+ unsigned long flags;

if (!is_valid_irq(cmos->irq))
return -EIO;
@@ -347,7 +349,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
sec = (sec < 60) ? bin2bcd(sec) : 0xff;
}

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();

/* next rtc irq must not be from previous alarm setting */
cmos_irq_disable(cmos, RTC_AIE);
@@ -372,7 +374,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (t->enabled)
cmos_irq_enable(cmos, RTC_AIE);

- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

return 0;
}
@@ -433,14 +435,14 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
if (alarm_disable_quirk)
return 0;

- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();

if (enabled)
cmos_irq_enable(cmos, RTC_AIE);
else
cmos_irq_disable(cmos, RTC_AIE);

- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);
return 0;
}

@@ -450,11 +452,12 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char rtc_control, valid;
+ unsigned long flags;

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
rtc_control = do_cmos_read(RTC_CONTROL);
valid = do_cmos_read(RTC_VALID);
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

/* NOTE: at least ICH6 reports battery status using a different
* (non-RTC) bit; and SQWE is ignored on many current systems.
@@ -507,6 +510,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
int retval;
+ unsigned long flags;

if (unlikely(off >= attr->size))
return 0;
@@ -516,7 +520,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
count = attr->size - off;

off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
for (retval = 0; count; count--, off++, retval++) {
if (off < 128)
*buf++ = do_cmos_read(off);
@@ -525,7 +529,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
else
break;
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

return retval;
}
@@ -537,6 +541,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
{
struct cmos_rtc *cmos;
int retval;
+ unsigned long flags;

cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
if (unlikely(off >= attr->size))
@@ -552,7 +557,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
* NVRAM to update, updating checksums is also part of its job.
*/
off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
for (retval = 0; count; count--, off++, retval++) {
/* don't trash RTC registers */
if (off == cmos->day_alrm
@@ -566,7 +571,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
else
break;
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

return retval;
}
@@ -590,8 +595,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
{
u8 irqstat;
u8 rtc_control;
+ unsigned long flags;

- spin_lock(&rtc_lock);
+ flags = rtc_cmos_lock();

/* When the HPET interrupt handler calls us, the interrupt
* status is passed as arg1 instead of the irq number. But
@@ -624,7 +630,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
hpet_mask_rtc_irq_bit(RTC_AIE);
do_cmos_read(RTC_INTR_FLAGS);
}
- spin_unlock(&rtc_lock);
+ rtc_cmos_unlock(flags);

if (is_intr(irqstat)) {
rtc_update_irq(p, 1, irqstat);
@@ -647,6 +653,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
int retval = 0;
unsigned char rtc_control;
unsigned address_space;
+ unsigned long flags;

/* there can be only one ... */
if (cmos_rtc.dev)
@@ -724,7 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)

rename_region(ports, dev_name(&cmos_rtc.rtc->dev));

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();

/* force periodic irq to CMOS reset default of 1024Hz;
*
@@ -741,7 +748,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)

rtc_control = do_cmos_read(RTC_CONTROL);

- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

/* FIXME:
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
@@ -808,9 +815,11 @@ cleanup0:

static void cmos_do_shutdown(void)
{
- spin_lock_irq(&rtc_lock);
+ unsigned long flags;
+
+ flags = rtc_cmos_lock();
cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);
}

static void __exit cmos_do_remove(struct device *dev)
@@ -843,9 +852,10 @@ static int cmos_suspend(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char tmp;
+ unsigned long flags;

/* only the alarm might be a wakeup event source */
- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
cmos->suspend_ctrl = tmp = do_cmos_read(RTC_CONTROL);
if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
unsigned char mask;
@@ -860,7 +870,7 @@ static int cmos_suspend(struct device *dev)

cmos_checkintr(cmos, tmp);
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

if (tmp & RTC_AIE) {
cmos->enabled_wake = 1;
@@ -892,6 +902,7 @@ static int cmos_resume(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char tmp;
+ unsigned long flags;

if (cmos->enabled_wake) {
if (cmos->wake_off)
@@ -901,7 +912,7 @@ static int cmos_resume(struct device *dev)
cmos->enabled_wake = 0;
}

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
tmp = cmos->suspend_ctrl;
cmos->suspend_ctrl = 0;
/* re-enable any irqs previously active */
@@ -928,7 +939,7 @@ static int cmos_resume(struct device *dev)
hpet_mask_rtc_irq_bit(RTC_AIE);
} while (mask & RTC_AIE);
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

dev_dbg(dev, "resume, ctrl %02x\n", tmp);

diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index 313438a..1ad3e78 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -37,6 +37,19 @@ static inline void do_cmos_write(u8 val, u8 reg)
{
CMOS_WRITE(val, reg);
}
+
+static inline unsigned long rtc_cmos_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&rtc_lock, flags);
+ return flags;
+}
+
+static inline void rtc_cmos_unlock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&rtc_lock, flags);
+}
+
/*
* Returns true if a clock update is in progress
*/
@@ -45,9 +58,9 @@ static inline unsigned char rtc_is_updating(void)
unsigned char uip;
unsigned long flags;

- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();
uip = (do_cmos_read(RTC_FREQ_SELECT) & RTC_UIP);
- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);
return uip;
}

@@ -78,7 +91,7 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
* by the RTC when initially set to a non-zero value.
*/
- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();
time->tm_sec = do_cmos_read(RTC_SECONDS);
time->tm_min = do_cmos_read(RTC_MINUTES);
time->tm_hour = do_cmos_read(RTC_HOURS);
@@ -89,7 +102,7 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
real_year = do_cmos_read(RTC_DEC_YEAR);
#endif
ctrl = do_cmos_read(RTC_CONTROL);
- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);

if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
@@ -142,7 +155,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
if (yrs > 255) /* They are unsigned */
return -EINVAL;

- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();
#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
@@ -163,7 +176,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
* whether the chip is in binary mode or not.
*/
if (yrs > 169) {
- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);
return -EINVAL;
}

@@ -198,7 +211,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
do_cmos_write(save_control, RTC_CONTROL);
do_cmos_write(save_freq_select, RTC_FREQ_SELECT);

- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);

return 0;
}
--
1.8.3.4

2014-04-25 09:35:57

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 7/7] arm64: rtc: plug the PC CMOS RTC using MMIO accessors

Add the now minimal gunk to enable the PC-style CMOS RTC.

Signed-off-by: Marc Zyngier <[email protected]>
---
arch/arm64/include/asm/mc146818rtc.h | 10 ++++++++++
drivers/rtc/Kconfig | 5 +++--
drivers/rtc/rtc-cmos.c | 2 +-
3 files changed, 14 insertions(+), 3 deletions(-)
create mode 100644 arch/arm64/include/asm/mc146818rtc.h

diff --git a/arch/arm64/include/asm/mc146818rtc.h b/arch/arm64/include/asm/mc146818rtc.h
new file mode 100644
index 0000000..79cc1f3
--- /dev/null
+++ b/arch/arm64/include/asm/mc146818rtc.h
@@ -0,0 +1,10 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ * In the arm64 case, pretty much nothing.
+ */
+#ifndef __ARM64_MC146818RTC_H__
+#define __ARM64_MC146818RTC_H__
+
+#define RTC_ALWAYS_BCD 0
+
+#endif /* __ARM64_MC146818RTC_H__ */
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index b2a512e..5944c92 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -660,10 +660,11 @@ comment "Platform RTC drivers"

config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
- depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
+ depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 || ARM64
default y if X86
select RTC_DRV_CMOS_MMIO if ARM
- select RTC_DRV_CMOS_PRIV_LOCK if ARM
+ select RTC_DRV_CMOS_MMIO_STRICT if ARM64
+ select RTC_DRV_CMOS_PRIV_LOCK if (ARM || ARM64)
help
Say "yes" here to get direct support for the real time clock
found in every PC or ACPI-based system, and some other boards.
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index eb5d05c..d84e3a5 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -754,7 +754,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
address_space = 64;
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
|| defined(__sparc__) || defined(__mips__) \
- || defined(__powerpc__)
+ || defined(__powerpc__) || defined(CONFIG_ARM64)
address_space = 128;
#else
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
--
1.8.3.4

2014-04-25 09:37:15

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 1/7] rtc-cmos: abstract IO accessors

Currently, rtc-cmos mandates the use of an I/O port, defined in an
architecture dependant way. This prevents the easy integration of
a platform that doesn't have the simple notion of an IO port.

Add wrappers around the CMOS_READ/CMOS_WRITE accessors, in order
to isolate the driver code from the vintage macros.

No feature is added.

Signed-off-by: Marc Zyngier <[email protected]>
---
drivers/rtc/rtc-cmos.c | 72 +++++++++++++++++++++++++----------------------
include/asm-generic/rtc.h | 57 +++++++++++++++++++++----------------
2 files changed, 72 insertions(+), 57 deletions(-)

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 0963c93..ae895e8 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -221,24 +221,24 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->time.tm_mon = -1;

spin_lock_irq(&rtc_lock);
- t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
- t->time.tm_min = CMOS_READ(RTC_MINUTES_ALARM);
- t->time.tm_hour = CMOS_READ(RTC_HOURS_ALARM);
+ t->time.tm_sec = do_cmos_read(RTC_SECONDS_ALARM);
+ t->time.tm_min = do_cmos_read(RTC_MINUTES_ALARM);
+ t->time.tm_hour = do_cmos_read(RTC_HOURS_ALARM);

if (cmos->day_alrm) {
/* ignore upper bits on readback per ACPI spec */
- t->time.tm_mday = CMOS_READ(cmos->day_alrm) & 0x3f;
+ t->time.tm_mday = do_cmos_read(cmos->day_alrm) & 0x3f;
if (!t->time.tm_mday)
t->time.tm_mday = -1;

if (cmos->mon_alrm) {
- t->time.tm_mon = CMOS_READ(cmos->mon_alrm);
+ t->time.tm_mon = do_cmos_read(cmos->mon_alrm);
if (!t->time.tm_mon)
t->time.tm_mon = -1;
}
}

- rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control = do_cmos_read(RTC_CONTROL);
spin_unlock_irq(&rtc_lock);

if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@@ -284,7 +284,7 @@ static void cmos_checkintr(struct cmos_rtc *cmos, unsigned char rtc_control)
/* NOTE after changing RTC_xIE bits we always read INTR_FLAGS;
* allegedly some older rtcs need that to handle irqs properly
*/
- rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+ rtc_intr = do_cmos_read(RTC_INTR_FLAGS);

if (is_hpet_enabled())
return;
@@ -301,11 +301,11 @@ static void cmos_irq_enable(struct cmos_rtc *cmos, unsigned char mask)
/* flush any pending IRQ status, notably for update irqs,
* before we enable new IRQs
*/
- rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control = do_cmos_read(RTC_CONTROL);
cmos_checkintr(cmos, rtc_control);

rtc_control |= mask;
- CMOS_WRITE(rtc_control, RTC_CONTROL);
+ do_cmos_write(rtc_control, RTC_CONTROL);
hpet_set_rtc_irq_bit(mask);

cmos_checkintr(cmos, rtc_control);
@@ -315,9 +315,9 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
{
unsigned char rtc_control;

- rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control = do_cmos_read(RTC_CONTROL);
rtc_control &= ~mask;
- CMOS_WRITE(rtc_control, RTC_CONTROL);
+ do_cmos_write(rtc_control, RTC_CONTROL);
hpet_mask_rtc_irq_bit(mask);

cmos_checkintr(cmos, rtc_control);
@@ -337,7 +337,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
min = t->time.tm_min;
sec = t->time.tm_sec;

- rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control = do_cmos_read(RTC_CONTROL);
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
/* Writing 0xff means "don't care" or "match all". */
mon = (mon <= 12) ? bin2bcd(mon) : 0xff;
@@ -353,15 +353,15 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
cmos_irq_disable(cmos, RTC_AIE);

/* update alarm */
- CMOS_WRITE(hrs, RTC_HOURS_ALARM);
- CMOS_WRITE(min, RTC_MINUTES_ALARM);
- CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+ do_cmos_write(hrs, RTC_HOURS_ALARM);
+ do_cmos_write(min, RTC_MINUTES_ALARM);
+ do_cmos_write(sec, RTC_SECONDS_ALARM);

/* the system may support an "enhanced" alarm */
if (cmos->day_alrm) {
- CMOS_WRITE(mday, cmos->day_alrm);
+ do_cmos_write(mday, cmos->day_alrm);
if (cmos->mon_alrm)
- CMOS_WRITE(mon, cmos->mon_alrm);
+ do_cmos_write(mon, cmos->mon_alrm);
}

/* FIXME the HPET alarm glue currently ignores day_alrm
@@ -452,8 +452,8 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
unsigned char rtc_control, valid;

spin_lock_irq(&rtc_lock);
- rtc_control = CMOS_READ(RTC_CONTROL);
- valid = CMOS_READ(RTC_VALID);
+ rtc_control = do_cmos_read(RTC_CONTROL);
+ valid = do_cmos_read(RTC_VALID);
spin_unlock_irq(&rtc_lock);

/* NOTE: at least ICH6 reports battery status using a different
@@ -519,7 +519,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
spin_lock_irq(&rtc_lock);
for (retval = 0; count; count--, off++, retval++) {
if (off < 128)
- *buf++ = CMOS_READ(off);
+ *buf++ = do_cmos_read(off);
else if (can_bank2)
*buf++ = cmos_read_bank2(off);
else
@@ -560,7 +560,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
|| off == cmos->century)
buf++;
else if (off < 128)
- CMOS_WRITE(*buf++, off);
+ do_cmos_write(*buf++, off);
else if (can_bank2)
cmos_write_bank2(*buf++, off);
else
@@ -600,8 +600,8 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
* Note that HPET and RTC are almost certainly out of phase,
* giving different IRQ status ...
*/
- irqstat = CMOS_READ(RTC_INTR_FLAGS);
- rtc_control = CMOS_READ(RTC_CONTROL);
+ irqstat = do_cmos_read(RTC_INTR_FLAGS);
+ rtc_control = do_cmos_read(RTC_CONTROL);
if (is_hpet_enabled())
irqstat = (unsigned long)irq & 0xF0;

@@ -620,9 +620,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
if (irqstat & RTC_AIE) {
cmos_rtc.suspend_ctrl &= ~RTC_AIE;
rtc_control &= ~RTC_AIE;
- CMOS_WRITE(rtc_control, RTC_CONTROL);
+ do_cmos_write(rtc_control, RTC_CONTROL);
hpet_mask_rtc_irq_bit(RTC_AIE);
- CMOS_READ(RTC_INTR_FLAGS);
+ do_cmos_read(RTC_INTR_FLAGS);
}
spin_unlock(&rtc_lock);

@@ -734,12 +734,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
*/
cmos_rtc.rtc->irq_freq = 1024;
hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+ do_cmos_write(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);

/* disable irqs */
cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);

- rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control = do_cmos_read(RTC_CONTROL);

spin_unlock_irq(&rtc_lock);

@@ -846,7 +846,7 @@ static int cmos_suspend(struct device *dev)

/* only the alarm might be a wakeup event source */
spin_lock_irq(&rtc_lock);
- cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL);
+ cmos->suspend_ctrl = tmp = do_cmos_read(RTC_CONTROL);
if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
unsigned char mask;

@@ -855,7 +855,7 @@ static int cmos_suspend(struct device *dev)
else
mask = RTC_IRQMASK;
tmp &= ~mask;
- CMOS_WRITE(tmp, RTC_CONTROL);
+ do_cmos_write(tmp, RTC_CONTROL);
hpet_mask_rtc_irq_bit(mask);

cmos_checkintr(cmos, tmp);
@@ -912,10 +912,10 @@ static int cmos_resume(struct device *dev)
hpet_rtc_timer_init();

do {
- CMOS_WRITE(tmp, RTC_CONTROL);
+ do_cmos_write(tmp, RTC_CONTROL);
hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK);

- mask = CMOS_READ(RTC_INTR_FLAGS);
+ mask = do_cmos_read(RTC_INTR_FLAGS);
mask &= (tmp & RTC_IRQMASK) | RTC_IRQF;
if (!is_hpet_enabled() || !is_intr(mask))
break;
@@ -1114,13 +1114,19 @@ static __init void cmos_of_init(struct platform_device *pdev)
if (!node)
return;

+ /*
+ * Try to map an MMIO region first. If it fails, we'll
+ * fallback on I/O access.
+ */
+ rtc_cmos_set_base(of_iomap(node, 0));
+
val = of_get_property(node, "ctrl-reg", NULL);
if (val)
- CMOS_WRITE(be32_to_cpup(val), RTC_CONTROL);
+ do_cmos_write(be32_to_cpup(val), RTC_CONTROL);

val = of_get_property(node, "freq-reg", NULL);
if (val)
- CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT);
+ do_cmos_write(be32_to_cpup(val), RTC_FREQ_SELECT);

get_rtc_time(&time);
ret = rtc_valid_tm(&time);
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index fa86f24..313438a 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -28,6 +28,15 @@
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */

+static inline u8 do_cmos_read(u8 reg)
+{
+ return CMOS_READ(reg);
+}
+
+static inline void do_cmos_write(u8 val, u8 reg)
+{
+ CMOS_WRITE(val, reg);
+}
/*
* Returns true if a clock update is in progress
*/
@@ -37,7 +46,7 @@ static inline unsigned char rtc_is_updating(void)
unsigned long flags;

spin_lock_irqsave(&rtc_lock, flags);
- uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+ uip = (do_cmos_read(RTC_FREQ_SELECT) & RTC_UIP);
spin_unlock_irqrestore(&rtc_lock, flags);
return uip;
}
@@ -70,16 +79,16 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
* by the RTC when initially set to a non-zero value.
*/
spin_lock_irqsave(&rtc_lock, flags);
- time->tm_sec = CMOS_READ(RTC_SECONDS);
- time->tm_min = CMOS_READ(RTC_MINUTES);
- time->tm_hour = CMOS_READ(RTC_HOURS);
- time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
- time->tm_mon = CMOS_READ(RTC_MONTH);
- time->tm_year = CMOS_READ(RTC_YEAR);
+ time->tm_sec = do_cmos_read(RTC_SECONDS);
+ time->tm_min = do_cmos_read(RTC_MINUTES);
+ time->tm_hour = do_cmos_read(RTC_HOURS);
+ time->tm_mday = do_cmos_read(RTC_DAY_OF_MONTH);
+ time->tm_mon = do_cmos_read(RTC_MONTH);
+ time->tm_year = do_cmos_read(RTC_YEAR);
#ifdef CONFIG_MACH_DECSTATION
- real_year = CMOS_READ(RTC_DEC_YEAR);
+ real_year = do_cmos_read(RTC_DEC_YEAR);
#endif
- ctrl = CMOS_READ(RTC_CONTROL);
+ ctrl = do_cmos_read(RTC_CONTROL);
spin_unlock_irqrestore(&rtc_lock, flags);

if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
@@ -161,7 +170,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
if (yrs >= 100)
yrs -= 100;

- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+ if (!(do_cmos_read(RTC_CONTROL) & RTC_DM_BINARY)
|| RTC_ALWAYS_BCD) {
sec = bin2bcd(sec);
min = bin2bcd(min);
@@ -171,23 +180,23 @@ static inline int __set_rtc_time(struct rtc_time *time)
yrs = bin2bcd(yrs);
}

- save_control = CMOS_READ(RTC_CONTROL);
- CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
- CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+ save_control = do_cmos_read(RTC_CONTROL);
+ do_cmos_write((save_control|RTC_SET), RTC_CONTROL);
+ save_freq_select = do_cmos_read(RTC_FREQ_SELECT);
+ do_cmos_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);

#ifdef CONFIG_MACH_DECSTATION
- CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
+ do_cmos_write(real_yrs, RTC_DEC_YEAR);
#endif
- CMOS_WRITE(yrs, RTC_YEAR);
- CMOS_WRITE(mon, RTC_MONTH);
- CMOS_WRITE(day, RTC_DAY_OF_MONTH);
- CMOS_WRITE(hrs, RTC_HOURS);
- CMOS_WRITE(min, RTC_MINUTES);
- CMOS_WRITE(sec, RTC_SECONDS);
-
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ do_cmos_write(yrs, RTC_YEAR);
+ do_cmos_write(mon, RTC_MONTH);
+ do_cmos_write(day, RTC_DAY_OF_MONTH);
+ do_cmos_write(hrs, RTC_HOURS);
+ do_cmos_write(min, RTC_MINUTES);
+ do_cmos_write(sec, RTC_SECONDS);
+
+ do_cmos_write(save_control, RTC_CONTROL);
+ do_cmos_write(save_freq_select, RTC_FREQ_SELECT);

spin_unlock_irqrestore(&rtc_lock, flags);

--
1.8.3.4

2014-04-25 09:37:11

by Marc Zyngier

[permalink] [raw]
Subject: [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock

So far, the CMOS RTC (PC-style mc146818) has always been used
through an ISA I/O port of some sort, with each platform configuring
the address in a static way.

Some platforms (KVM with kvmtools, for example) offer a MMIO version
of the CMOS RTC, which requires a different access method.

This patch select the RTC_DRV_CMOS_MMIO configuration in order to
support MMIO accesses as well as the older IO port method.

While we're at it, switch to RTC_DRV_CMOS_PRIV_LOCK and remove the
ancient rtc_lock.

Tested on Cortex-A7 with KVM and kvmtools.

Signed-off-by: Marc Zyngier <[email protected]>
---
arch/arm/kernel/time.c | 7 -------
drivers/rtc/Kconfig | 2 ++
2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 829a96d..38c8718 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -32,13 +32,6 @@
#include <asm/stacktrace.h>
#include <asm/thread_info.h>

-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \
- defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE)
-/* this needs a better home */
-DEFINE_SPINLOCK(rtc_lock);
-EXPORT_SYMBOL(rtc_lock);
-#endif /* pc-style 'CMOS' RTC support */
-
/* change this if you have some constant time drift */
#define USECS_PER_JIFFY (1000000/HZ)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 12bc27d..b2a512e 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -662,6 +662,8 @@ config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
default y if X86
+ select RTC_DRV_CMOS_MMIO if ARM
+ select RTC_DRV_CMOS_PRIV_LOCK if ARM
help
Say "yes" here to get direct support for the real time clock
found in every PC or ACPI-based system, and some other boards.
--
1.8.3.4

2014-04-25 10:28:28

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock

On Fri, Apr 25, 2014 at 10:31:14AM +0100, Marc Zyngier wrote:
> So far, the CMOS RTC (PC-style mc146818) has always been used
> through an ISA I/O port of some sort, with each platform configuring
> the address in a static way.
>
> Some platforms (KVM with kvmtools, for example) offer a MMIO version
> of the CMOS RTC, which requires a different access method.
>
> This patch select the RTC_DRV_CMOS_MMIO configuration in order to
> support MMIO accesses as well as the older IO port method.
>
> While we're at it, switch to RTC_DRV_CMOS_PRIV_LOCK and remove the
> ancient rtc_lock.

rtc_lock is there so that if you build the RTC driver and nvram driver
in, and load them, they will both want to access the RTC via its
indexed registers, and they need to share the lock to avoid trampling
on each others toes.

Yes, it should be handled in a more modern way, but I don't think you
can simply get rid of this in this manner. We can have both these
drivers loaded on ARM platforms.

--
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

2014-04-25 12:33:11

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock

Hi Russell,

On 25/04/14 11:27, Russell King - ARM Linux wrote:
> On Fri, Apr 25, 2014 at 10:31:14AM +0100, Marc Zyngier wrote:
>> So far, the CMOS RTC (PC-style mc146818) has always been used
>> through an ISA I/O port of some sort, with each platform configuring
>> the address in a static way.
>>
>> Some platforms (KVM with kvmtools, for example) offer a MMIO version
>> of the CMOS RTC, which requires a different access method.
>>
>> This patch select the RTC_DRV_CMOS_MMIO configuration in order to
>> support MMIO accesses as well as the older IO port method.
>>
>> While we're at it, switch to RTC_DRV_CMOS_PRIV_LOCK and remove the
>> ancient rtc_lock.
>
> rtc_lock is there so that if you build the RTC driver and nvram driver
> in, and load them, they will both want to access the RTC via its
> indexed registers, and they need to share the lock to avoid trampling
> on each others toes.

Ah, I completely missed that one. Note to self: never look at that kind
of code just after lunch...

> Yes, it should be handled in a more modern way, but I don't think you
> can simply get rid of this in this manner. We can have both these
> drivers loaded on ARM platforms.

Agreed. I suppose that would have to be handled by some kind of module
dependency, but it is starting to look even uglier than I initially thought.

Back to the drawing board...

Thanks,

M.
--
Jazz is not dead. It just smells funny...