* [PATCH 2/2] Alchemy: timer: support multiple SYS_BASE addresses
2009-08-22 16:10 ` [PATCH 1/2] Alchemy: simple cpu subtype detector Manuel Lauss
@ 2009-08-22 16:10 ` Manuel Lauss
2009-08-27 11:47 ` Ralf Baechle
2009-08-27 11:46 ` [PATCH 1/2] Alchemy: simple cpu subtype detector Ralf Baechle
1 sibling, 1 reply; 9+ messages in thread
From: Manuel Lauss @ 2009-08-22 16:10 UTC (permalink / raw)
To: Linux-MIPS, Ralf Baechle; +Cc: Manuel Lauss
The Au1300 has SYS_BASE moved to another bus which has the base address
of all timer-related bits changed. Add support for runtime detection
of proper timer base address and irq.
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
arch/mips/alchemy/common/time.c | 137 ++++++++++++++++++++--------
arch/mips/alchemy/devboards/pm.c | 58 +++++++-----
arch/mips/include/asm/mach-au1x00/au1000.h | 32 +++++--
3 files changed, 157 insertions(+), 70 deletions(-)
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index 9fc0d44..5ae771e 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -43,28 +43,47 @@
/* 32kHz clock enabled and detected */
#define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
+struct alchemy_clocksource {
+ struct clocksource cs;
+ void __iomem *sys_base;
+};
+
+struct alchemy_clkevdev {
+ struct clock_event_device cd;
+ void __iomem *sys_base;
+};
+
static cycle_t au1x_counter1_read(struct clocksource *cs)
{
- return au_readl(SYS_RTCREAD);
+ struct alchemy_clocksource *acs =
+ container_of(cs, struct alchemy_clocksource, cs);
+
+ return __raw_readl(acs->sys_base + SYS_RTCREAD_OFS);
}
-static struct clocksource au1x_counter1_clocksource = {
- .name = "alchemy-counter1",
- .read = au1x_counter1_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .rating = 100,
+static struct alchemy_clocksource au1x_counter1_clocksource = {
+ .cs = {
+ .name = "alchemy-counter1",
+ .read = au1x_counter1_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .rating = 100,
+ },
};
static int au1x_rtcmatch2_set_next_event(unsigned long delta,
- struct clock_event_device *cd)
+ struct clock_event_device *ced)
{
- delta += au_readl(SYS_RTCREAD);
+ struct alchemy_clkevdev *aced =
+ container_of(ced, struct alchemy_clkevdev, cd);
+ void __iomem *b = aced->sys_base;
+
+ delta += __raw_readl(b + SYS_RTCREAD_OFS);
/* wait for register access */
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M21)
+ while (__raw_readl(b + SYS_COUNTER_CNTRL_OFS) & SYS_CNTRL_M21)
;
- au_writel(delta, SYS_RTCMATCH2);
- au_sync();
+ __raw_writel(delta, b + SYS_RTCMATCH2_OFS);
+ mmiowb();
return 0;
}
@@ -81,28 +100,33 @@ static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct clock_event_device au1x_rtcmatch2_clockdev = {
- .name = "rtcmatch2",
- .features = CLOCK_EVT_FEAT_ONESHOT,
- .rating = 100,
- .irq = AU1000_RTC_MATCH2_INT,
- .set_next_event = au1x_rtcmatch2_set_next_event,
- .set_mode = au1x_rtcmatch2_set_mode,
- .cpumask = CPU_MASK_ALL_PTR,
+
+static struct alchemy_clkevdev au1x_rtcmatch2_clockdev = {
+ .cd = {
+ .name = "rtcmatch2",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 100,
+ .set_next_event = au1x_rtcmatch2_set_next_event,
+ .set_mode = au1x_rtcmatch2_set_mode,
+ .cpumask = CPU_MASK_ALL_PTR,
+ },
};
static struct irqaction au1x_rtcmatch2_irqaction = {
.handler = au1x_rtcmatch2_irq,
.flags = IRQF_DISABLED | IRQF_TIMER,
.name = "timer",
- .dev_id = &au1x_rtcmatch2_clockdev,
+ .dev_id = &au1x_rtcmatch2_clockdev.cd,
};
-void __init plat_time_init(void)
+static int __init alchemy_time_init(void __iomem *sys_base, int cntr_irq)
{
- struct clock_event_device *cd = &au1x_rtcmatch2_clockdev;
+ struct clock_event_device *cd = &au1x_rtcmatch2_clockdev.cd;
unsigned long t;
+ au1x_counter1_clocksource.sys_base = sys_base;
+ au1x_rtcmatch2_clockdev.sys_base = sys_base;
+
/* Check if firmware (YAMON, ...) has enabled 32kHz and clock
* has been detected. If so install the rtcmatch2 clocksource,
* otherwise don't bother. Note that both bits being set is by
@@ -110,51 +134,55 @@ void __init plat_time_init(void)
* (the 32S bit seems to be stuck set to 1 once a single clock-
* edge is detected, hence the timeouts).
*/
- if (CNTR_OK != (au_readl(SYS_COUNTER_CNTRL) & CNTR_OK))
- goto cntr_err;
+ if (CNTR_OK != (__raw_readl(sys_base + SYS_COUNTER_CNTRL_OFS) & CNTR_OK))
+ return -ENODEV;
/*
* setup counter 1 (RTC) to tick at full speed
*/
t = 0xffffff;
- while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S) && --t)
+ while ((__raw_readl(sys_base + SYS_COUNTER_CNTRL_OFS) & SYS_CNTRL_T1S) && --t)
asm volatile ("nop");
if (!t)
- goto cntr_err;
+ return -ENODEV;
- au_writel(0, SYS_RTCTRIM); /* 32.768 kHz */
- au_sync();
+ __raw_writel(0, sys_base + SYS_RTCTRIM_OFS); /* 32.768 kHz */
+ mmiowb();
t = 0xffffff;
- while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t)
+ while ((__raw_readl(sys_base + SYS_COUNTER_CNTRL_OFS) & SYS_CNTRL_C1S) && --t)
asm volatile ("nop");
if (!t)
- goto cntr_err;
- au_writel(0, SYS_RTCWRITE);
- au_sync();
+ return -ENODEV;
+
+ __raw_writel(0, sys_base + SYS_RTCWRITE_OFS);
+ mmiowb();
t = 0xffffff;
- while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t)
+ while ((__raw_readl(sys_base + SYS_COUNTER_CNTRL_OFS) & SYS_CNTRL_C1S) && --t)
asm volatile ("nop");
if (!t)
- goto cntr_err;
+ return -ENODEV;
/* register counter1 clocksource and event device */
- clocksource_set_clock(&au1x_counter1_clocksource, 32768);
- clocksource_register(&au1x_counter1_clocksource);
+ clocksource_set_clock(&au1x_counter1_clocksource.cs, 32768);
+ clocksource_register(&au1x_counter1_clocksource.cs);
+ cd->irq = cntr_irq;
cd->shift = 32;
cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd);
cd->min_delta_ns = clockevent_delta2ns(8, cd); /* ~0.25ms */
clockevents_register_device(cd);
- setup_irq(AU1000_RTC_MATCH2_INT, &au1x_rtcmatch2_irqaction);
+ setup_irq(cntr_irq, &au1x_rtcmatch2_irqaction);
printk(KERN_INFO "Alchemy clocksource installed\n");
- return;
+ return 0;
+}
-cntr_err:
+static void alchemy_use_c0_cntr(void)
+{
/* MIPS kernel assigns 'au1k_wait' to 'cpu_wait' before this
* function is called. Because the Alchemy counters are unusable
* the C0 timekeeping code is installed and use of the 'wait'
@@ -165,3 +193,32 @@ cntr_err:
r4k_clockevent_init();
init_r4k_clocksource();
}
+
+void __init plat_time_init(void)
+{
+ void __iomem *io = NULL;
+ int irq, ret;
+
+ switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1100:
+ case ALCHEMY_CPU_AU1550:
+ case ALCHEMY_CPU_AU1200:
+ io = (void __iomem *)KSEG1ADDR(SYS_PHYS_ADDR);
+ irq = AU1000_RTC_MATCH2_INT;
+ break;
+/* case ALCHEMY_CPU_AU1300:
+ io = (void __iomem *)KSEG1ADDR(AU1300_SYS_PHYS_ADDR);
+ irq = AU1300_RTC_MATCH2_INT;
+ break;
+*/
+ default:
+ goto c0cntr;
+ }
+
+ ret = alchemy_time_init(io, irq);
+ if (ret)
+c0cntr:
+ alchemy_use_c0_cntr();
+}
diff --git a/arch/mips/alchemy/devboards/pm.c b/arch/mips/alchemy/devboards/pm.c
index 632f986..06b4bfb 100644
--- a/arch/mips/alchemy/devboards/pm.c
+++ b/arch/mips/alchemy/devboards/pm.c
@@ -23,6 +23,7 @@
static unsigned long db1x_pm_sleep_secs;
static unsigned long db1x_pm_wakemsk;
static unsigned long db1x_pm_last_wakesrc;
+static void __iomem *sys_base;
static int db1x_pm_enter(suspend_state_t state)
{
@@ -30,23 +31,24 @@ static int db1x_pm_enter(suspend_state_t state)
alchemy_gpio1_input_enable();
/* clear and setup wake cause and source */
- au_writel(0, SYS_WAKEMSK);
- au_sync();
- au_writel(0, SYS_WAKESRC);
- au_sync();
+ __raw_writel(0, sys_base + SYS_WAKEMSK_OFS);
+ mmiowb();
+ __raw_writel(0, sys_base + SYS_WAKESRC_OFS);
+ mmiowb();
- au_writel(db1x_pm_wakemsk, SYS_WAKEMSK);
- au_sync();
+ __raw_writel(db1x_pm_wakemsk, sys_base + SYS_WAKEMSK_OFS);
+ mmiowb();
/* setup 1Hz-timer-based wakeup: wait for reg access */
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20)
+ while (__raw_readl(sys_base + SYS_COUNTER_CNTRL_OFS) & SYS_CNTRL_M20)
asm volatile ("nop");
- au_writel(au_readl(SYS_TOYREAD) + db1x_pm_sleep_secs, SYS_TOYMATCH2);
- au_sync();
+ __raw_writel(__raw_readl(sys_base + SYS_TOYREAD_OFS) + db1x_pm_sleep_secs,
+ sys_base + SYS_TOYMATCH2_OFS);
+ mmiowb();
/* wait for value to really hit the register */
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20)
+ while (__raw_readl(sys_base + SYS_COUNTER_CNTRL_OFS) & SYS_CNTRL_M20)
asm volatile ("nop");
/* ...and now the sandman can come! */
@@ -70,12 +72,12 @@ static void db1x_pm_end(void)
/* read and store wakeup source, the clear the register. To
* be able to clear it, WAKEMSK must be cleared first.
*/
- db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC);
-
- au_writel(0, SYS_WAKEMSK);
- au_writel(0, SYS_WAKESRC);
- au_sync();
+ db1x_pm_last_wakesrc = __raw_readl(sys_base + SYS_WAKESRC_OFS);
+ __raw_writel(0, sys_base + SYS_WAKEMSK_OFS);
+ mmiowb();
+ __raw_writel(0, sys_base + SYS_WAKESRC_OFS);
+ mmiowb();
}
static struct platform_suspend_ops db1x_pm_ops = {
@@ -206,21 +208,31 @@ static struct attribute_group db1x_pmattr_group = {
*/
static int __init pm_init(void)
{
+ switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1100:
+ case ALCHEMY_CPU_AU1550:
+ case ALCHEMY_CPU_AU1200:
+ sys_base = (void __iomem *)KSEG1ADDR(SYS_PHYS_ADDR);
+ break;
+ }
+
/* init TOY to tick at 1Hz if not already done. No need to wait
* for confirmation since there's plenty of time from here to
* the next suspend cycle.
*/
- if (au_readl(SYS_TOYTRIM) != 32767) {
- au_writel(32767, SYS_TOYTRIM);
- au_sync();
+ if (__raw_readl(sys_base + SYS_TOYTRIM_OFS) != 32767) {
+ __raw_writel(32767, sys_base + SYS_TOYTRIM_OFS);
+ mmiowb();
}
- db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC);
+ db1x_pm_last_wakesrc = __raw_readl(sys_base + SYS_WAKESRC_OFS);
- au_writel(0, SYS_WAKESRC);
- au_sync();
- au_writel(0, SYS_WAKEMSK);
- au_sync();
+ __raw_writel(0, sys_base + SYS_WAKEMSK_OFS);
+ mmiowb();
+ __raw_writel(0, sys_base + SYS_WAKESRC_OFS);
+ mmiowb();
suspend_set_ops(&db1x_pm_ops);
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 85713f8..6aa0bab 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -1020,7 +1020,8 @@ enum soc_au1200_ints {
/* Programmable Counters 0 and 1 */
#define SYS_BASE 0xB1900000
-#define SYS_COUNTER_CNTRL (SYS_BASE + 0x14)
+#define SYS_COUNTER_CNTRL_OFS 0x14
+#define SYS_COUNTER_CNTRL (SYS_BASE + SYS_COUNTER_CNTRL_OFS)
# define SYS_CNTRL_E1S (1 << 23)
# define SYS_CNTRL_T1S (1 << 20)
# define SYS_CNTRL_M21 (1 << 19)
@@ -1049,13 +1050,20 @@ enum soc_au1200_ints {
#define SYS_TOYMATCH2 (SYS_BASE + 0x10)
#define SYS_TOYREAD (SYS_BASE + 0x40)
+#define SYS_TOYTRIM_OFS 0
+#define SYS_TOYWRITE_OFS 4
+#define SYS_TOYMATCH0_OFS 8
+#define SYS_TOYMATCH1_OFS 0xC
+#define SYS_TOYMATCH2_OFS 0x10
+#define SYS_TOYREAD_OFS 0x40
+
/* Programmable Counter 1 Registers */
-#define SYS_RTCTRIM (SYS_BASE + 0x44)
-#define SYS_RTCWRITE (SYS_BASE + 0x48)
-#define SYS_RTCMATCH0 (SYS_BASE + 0x4C)
-#define SYS_RTCMATCH1 (SYS_BASE + 0x50)
-#define SYS_RTCMATCH2 (SYS_BASE + 0x54)
-#define SYS_RTCREAD (SYS_BASE + 0x58)
+#define SYS_RTCTRIM_OFS 0x44
+#define SYS_RTCWRITE_OFS 0x48
+#define SYS_RTCMATCH0_OFS 0x4C
+#define SYS_RTCMATCH1_OFS 0x50
+#define SYS_RTCMATCH2_OFS 0x54
+#define SYS_RTCREAD_OFS 0x58
/* I2S Controller */
#define I2S_DATA 0xB1000000
@@ -1594,6 +1602,16 @@ enum soc_au1200_ints {
#define SYS_SLPPWR 0xB1900078
#define SYS_SLEEP 0xB190007C
+#define SYS_SCRATCH0_OFS 0x18
+#define SYS_SCRATCH1_OFS 0x1C
+#define SYS_WAKEMSK_OFS 0x34
+#define SYS_ENDIAN_OFS 0x38
+#define SYS_POWERCTRL_OFS 0x3C
+#define SYS_WAKESRC_OFS 0x5C
+#define SYS_SLPPWR_OFS 0x78
+#define SYS_SLEEP_OFS 0x7C
+
+
#define SYS_WAKEMSK_D2 (1 << 9)
#define SYS_WAKEMSK_M2 (1 << 8)
#define SYS_WAKEMSK_GPIO(x) (1 << (x))
--
1.6.4
^ permalink raw reply related [flat|nested] 9+ messages in thread