* [RFC PATCH 1/7] Alchemy: remove cpu_table.
2008-06-24 20:08 [RFC PATCH 0/7] Alchemy updates Manuel Lauss
@ 2008-06-24 20:09 ` Manuel Lauss
2008-06-24 21:04 ` Sergei Shtylyov
2008-06-24 20:09 ` [RFC PATCH 2/7] Alchemy: remove get/set_au1x00_lcd_clock() Manuel Lauss
` (5 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 20:09 UTC (permalink / raw)
To: linux-mips
From: Manuel Lauss <mano@roarinelk.homelinux.net>
Remove the cpu_table:
- move detection of config[od] necessity to au1000 header.
- ditto for detection of write-only sys_cpupll register,
- remove the BCLK switching code. Activation of this features should be
left to the individual boards since it also affects external devices
tied to BCLK and only the board designers know whether it is safe to
enable.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/Makefile | 2 +-
arch/mips/au1000/common/cputable.c | 52 -----------------------------
arch/mips/au1000/common/setup.c | 40 ++++++-----------------
arch/mips/au1000/common/sleeper.S | 4 ++-
arch/mips/au1000/common/time.c | 4 +-
arch/mips/mm/c-r4k.c | 41 ++++-------------------
include/asm-mips/mach-au1x00/au1000.h | 58 +++++++++++++++++++++-----------
7 files changed, 61 insertions(+), 140 deletions(-)
delete mode 100644 arch/mips/au1000/common/cputable.c
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
index dd0e19d..850de08 100644
--- a/arch/mips/au1000/common/Makefile
+++ b/arch/mips/au1000/common/Makefile
@@ -7,7 +7,7 @@
obj-y += prom.o irq.o puts.o time.o reset.o \
au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
- sleeper.o cputable.o dma.o dbdma.o gpio.o
+ sleeper.o dma.o dbdma.o gpio.o
obj-$(CONFIG_KGDB) += dbg_io.o
obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c
deleted file mode 100644
index ba6430b..0000000
--- a/arch/mips/au1000/common/cputable.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * arch/mips/au1000/common/cputable.c
- *
- * Copyright (C) 2004 Dan Malek (dan@embeddededge.com)
- * Copied from PowerPC and updated for Alchemy Au1xxx processors.
- *
- * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/mach-au1x00/au1000.h>
-
-struct cpu_spec *cur_cpu_spec[NR_CPUS];
-
-/* With some thought, we can probably use the mask to reduce the
- * size of the table.
- */
-struct cpu_spec cpu_specs[] = {
- { 0xffffffff, 0x00030100, "Au1000 DA", 1, 0, 1 },
- { 0xffffffff, 0x00030201, "Au1000 HA", 1, 0, 1 },
- { 0xffffffff, 0x00030202, "Au1000 HB", 1, 0, 1 },
- { 0xffffffff, 0x00030203, "Au1000 HC", 1, 1, 0 },
- { 0xffffffff, 0x00030204, "Au1000 HD", 1, 1, 0 },
- { 0xffffffff, 0x01030200, "Au1500 AB", 1, 1, 0 },
- { 0xffffffff, 0x01030201, "Au1500 AC", 0, 1, 0 },
- { 0xffffffff, 0x01030202, "Au1500 AD", 0, 1, 0 },
- { 0xffffffff, 0x02030200, "Au1100 AB", 1, 1, 0 },
- { 0xffffffff, 0x02030201, "Au1100 BA", 1, 1, 0 },
- { 0xffffffff, 0x02030202, "Au1100 BC", 1, 1, 0 },
- { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1, 0 },
- { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1, 0 },
- { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1, 0 },
- { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0, 0 },
- { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0, 0 },
- { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0, 0 }
-};
-
-void set_cpuspec(void)
-{
- struct cpu_spec *sp;
- u32 prid;
-
- prid = read_c0_prid();
- sp = cpu_specs;
- while ((prid & sp->prid_mask) != sp->prid_value)
- sp++;
- cur_cpu_spec[0] = sp;
-}
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 1ac6b06..0d78f50 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -41,43 +41,23 @@ extern void __init board_setup(void);
extern void au1000_restart(char *);
extern void au1000_halt(void);
extern void au1000_power_off(void);
-extern void set_cpuspec(void);
+
+/* setting CONFIG[OD] fixes various errata on many Au1xxx processors */
+void au1x00_fixup_config_od(void)
+{
+ if (au1xxx_cpu_needs_config_od())
+ set_c0_config(1 << 19);
+ else
+ clear_c0_config(1 << 19);
+}
void __init plat_mem_setup(void)
{
- struct cpu_spec *sp;
char *argptr;
- unsigned long prid, cpufreq, bclk;
-
- set_cpuspec();
- sp = cur_cpu_spec[0];
board_setup(); /* board specific setup */
- prid = read_c0_prid();
- if (sp->cpu_pll_wo)
-#ifdef CONFIG_SOC_AU1000_FREQUENCY
- cpufreq = CONFIG_SOC_AU1000_FREQUENCY / 1000000;
-#else
- cpufreq = 396;
-#endif
- else
- cpufreq = (au_readl(SYS_CPUPLL) & 0x3F) * 12;
- printk(KERN_INFO "(PRID %08lx) @ %ld MHz\n", prid, cpufreq);
-
- if (sp->cpu_bclk) {
- /* Enable BCLK switching */
- bclk = au_readl(SYS_POWERCTRL);
- au_writel(bclk | 0x60, SYS_POWERCTRL);
- printk(KERN_INFO "BCLK switching enabled!\n");
- }
-
- if (sp->cpu_od)
- /* Various early Au1xx0 errata corrected by this */
- set_c0_config(1 << 19); /* Set Config[OD] */
- else
- /* Clear to obtain best system bus performance */
- clear_c0_config(1 << 19); /* Clear Config[OD] */
+ au1x00_fixup_config_od();
argptr = prom_getcmdline();
diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S
index 4b3cf02..8039aca 100644
--- a/arch/mips/au1000/common/sleeper.S
+++ b/arch/mips/au1000/common/sleeper.S
@@ -113,10 +113,11 @@ sdsleep:
lw k0, 0x14(sp)
mtc0 k0, CP0_CONFIG
- /* We need to catch the ealry Alchemy SOCs with
+ /* We need to catch the early Alchemy SOCs with
* the write-only Config[OD] bit and set it back to one...
*/
jal au1x00_fixup_config_od
+ nop
lw $1, PT_R1(sp)
lw $2, PT_R2(sp)
lw $3, PT_R3(sp)
@@ -151,4 +152,5 @@ sdsleep:
addiu sp, PT_SIZE
jr ra
+ nop
END(save_and_sleep)
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index 563d939..f9dc939 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -198,7 +198,7 @@ unsigned long calc_clock(void)
* silicon versions of Au1000 are not sold by AMD, we don't bend
* over backwards trying to determine the frequency.
*/
- if (cur_cpu_spec[0]->cpu_pll_wo)
+ if (au1xxx_cpu_has_pll_wo())
#ifdef CONFIG_SOC_AU1000_FREQUENCY
cpu_speed = CONFIG_SOC_AU1000_FREQUENCY;
#else
@@ -221,7 +221,7 @@ void __init plat_time_init(void)
est_freq += 5000; /* round */
est_freq -= est_freq%10000;
- printk(KERN_INFO "CPU frequency %u.%02u MHz\n",
+ printk(KERN_INFO "(PRId %08x) @ %u.%02u MHz\n", read_c0_prid(),
est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000);
set_au1x00_speed(est_freq);
set_au1x00_lcd_clock(); /* program the LCD clock */
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 2709675..bb22649 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1204,31 +1204,6 @@ static void __cpuinit setup_scache(void)
c->options |= MIPS_CPU_INCLUSIVE_CACHES;
}
-void au1x00_fixup_config_od(void)
-{
- /*
- * c0_config.od (bit 19) was write only (and read as 0)
- * on the early revisions of Alchemy SOCs. It disables the bus
- * transaction overlapping and needs to be set to fix various errata.
- */
- switch (read_c0_prid()) {
- case 0x00030100: /* Au1000 DA */
- case 0x00030201: /* Au1000 HA */
- case 0x00030202: /* Au1000 HB */
- case 0x01030200: /* Au1500 AB */
- /*
- * Au1100 errata actually keeps silence about this bit, so we set it
- * just in case for those revisions that require it to be set according
- * to arch/mips/au1000/common/cputable.c
- */
- case 0x02030200: /* Au1100 AB */
- case 0x02030201: /* Au1100 BA */
- case 0x02030202: /* Au1100 BC */
- set_c0_config(1 << 19);
- break;
- }
-}
-
/* CP0 hazard avoidance. */
#define NXP_BARRIER() \
__asm__ __volatile__( \
@@ -1287,20 +1262,18 @@ static void __cpuinit coherency_setup(void)
case CPU_R4400MC:
clear_c0_config(CONF_CU);
break;
- /*
- * We need to catch the early Alchemy SOCs with
- * the write-only co_config.od bit and set it back to one...
- */
- case CPU_AU1000: /* rev. DA, HA, HB */
- case CPU_AU1100: /* rev. AB, BA, BC ?? */
- case CPU_AU1500: /* rev. AB */
- au1x00_fixup_config_od();
- break;
case PRID_IMP_PR4450:
nxp_pr4450_fixup_config();
break;
}
+
+#ifdef CONFIG_MACH_ALCHEMY
+ {
+ extern void au1x00_fixup_config_od(void);
+ au1x00_fixup_config_od();
+ }
+#endif
}
#if defined(CONFIG_DMA_NONCOHERENT)
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 0d302ba..2a60969 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -91,6 +91,44 @@ static inline u32 au_readl(unsigned long reg)
return *(volatile u32 *)reg;
}
+/* Early Au1000 have a write-only SYS_CPUPLL register. */
+static inline int au1xxx_cpu_has_pll_wo(void)
+{
+ switch (read_c0_prid()) {
+ case 0x00030100: /* Au1000 DA */
+ case 0x00030201: /* Au1000 HA */
+ case 0x00030202: /* Au1000 HB */
+ return 1;
+ }
+ return 0;
+}
+
+/* does CPU need CONFIG[OD] set to fix tons of errata? */
+static inline int au1xxx_cpu_needs_config_od(void)
+{
+ /*
+ * c0_config.od (bit 19) was write only (and read as 0) on the
+ * early revisions of Alchemy SOCs. It disables the bus trans-
+ * action overlapping and needs to be set to fix various errata.
+ */
+ switch (read_c0_prid()) {
+ case 0x00030100: /* Au1000 DA */
+ case 0x00030201: /* Au1000 HA */
+ case 0x00030202: /* Au1000 HB */
+ case 0x01030200: /* Au1500 AB */
+ /*
+ * Au1100/Au1200 errata actually keep silence about this bit,
+ * so we set it just in case for those revisions that require
+ * it to be set according to the (now gone) cpu_table.
+ */
+ case 0x02030200: /* Au1100 AB */
+ case 0x02030201: /* Au1100 BA */
+ case 0x02030202: /* Au1100 BC */
+ case 0x04030201: /* Au1200 AC */
+ return 1;
+ }
+ return 0;
+}
/* arch/mips/au1000/common/clocks.c */
extern void set_au1x00_speed(unsigned int new_freq);
@@ -1749,24 +1787,4 @@ static AU1X00_SYS * const sys = (AU1X00_SYS *)SYS_BASE;
#endif
-/*
- * Processor information based on PRID.
- * Copied from PowerPC.
- */
-#ifndef _LANGUAGE_ASSEMBLY
-struct cpu_spec {
- /* CPU is matched via (PRID & prid_mask) == prid_value */
- unsigned int prid_mask;
- unsigned int prid_value;
-
- char *cpu_name;
- unsigned char cpu_od; /* Set Config[OD] */
- unsigned char cpu_bclk; /* Enable BCLK switching */
- unsigned char cpu_pll_wo; /* sys_cpupll reg. write-only */
-};
-
-extern struct cpu_spec cpu_specs[];
-extern struct cpu_spec *cur_cpu_spec[];
-#endif
-
#endif
--
1.5.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [RFC PATCH 1/7] Alchemy: remove cpu_table.
2008-06-24 20:09 ` [RFC PATCH 1/7] Alchemy: remove cpu_table Manuel Lauss
@ 2008-06-24 21:04 ` Sergei Shtylyov
2008-06-24 21:26 ` Manuel Lauss
0 siblings, 1 reply; 12+ messages in thread
From: Sergei Shtylyov @ 2008-06-24 21:04 UTC (permalink / raw)
To: Manuel Lauss; +Cc: linux-mips
Hello.
Manuel Lauss wrote:
> Remove the cpu_table:
> - move detection of config[od] necessity to au1000 header.
> - ditto for detection of write-only sys_cpupll register,
> - remove the BCLK switching code. Activation of this features should be
> left to the individual boards since it also affects external devices
> tied to BCLK and only the board designers know whether it is safe to
> enable.
>
>
Good point...
> Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
>
[...]
> diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S
> index 4b3cf02..8039aca 100644
> --- a/arch/mips/au1000/common/sleeper.S
> +++ b/arch/mips/au1000/common/sleeper.S
> @@ -113,10 +113,11 @@ sdsleep:
> lw k0, 0x14(sp)
> mtc0 k0, CP0_CONFIG
>
> - /* We need to catch the ealry Alchemy SOCs with
> + /* We need to catch the early Alchemy SOCs with
> * the write-only Config[OD] bit and set it back to one...
> */
> jal au1x00_fixup_config_od
> + nop
> lw $1, PT_R1(sp)
> lw $2, PT_R2(sp)
> lw $3, PT_R3(sp)
> @@ -151,4 +152,5 @@ sdsleep:
> addiu sp, PT_SIZE
>
> jr ra
> + nop
> END(save_and_sleep)
>
Don't bother doing this if there's no ".set noreorder" around.
Assembler should do a better job at filling up the delay slot in this case.
> diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
> index 2709675..bb22649 100644
> --- a/arch/mips/mm/c-r4k.c
> +++ b/arch/mips/mm/c-r4k.c
>
[...]
> @@ -1287,20 +1262,18 @@ static void __cpuinit coherency_setup(void)
> case CPU_R4400MC:
> clear_c0_config(CONF_CU);
> break;
> - /*
> - * We need to catch the early Alchemy SOCs with
> - * the write-only co_config.od bit and set it back to one...
> - */
> - case CPU_AU1000: /* rev. DA, HA, HB */
> - case CPU_AU1100: /* rev. AB, BA, BC ?? */
> - case CPU_AU1500: /* rev. AB */
> - au1x00_fixup_config_od();
> - break;
>
> case PRID_IMP_PR4450:
> nxp_pr4450_fixup_config();
> break;
> }
> +
> +#ifdef CONFIG_MACH_ALCHEMY
> + {
> + extern void au1x00_fixup_config_od(void);
> + au1x00_fixup_config_od();
> + }
> +#endif
> }
>
I've been thru this before. Ralf will hardly accept #ifdef'ery and
extern in this file. That's why we have what we have now. :-)
WBR. Sergei
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [RFC PATCH 1/7] Alchemy: remove cpu_table.
2008-06-24 21:04 ` Sergei Shtylyov
@ 2008-06-24 21:26 ` Manuel Lauss
2008-06-24 21:37 ` Sergei Shtylyov
0 siblings, 1 reply; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 21:26 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: linux-mips
Good Evening,
>> --- a/arch/mips/au1000/common/sleeper.S
>> +++ b/arch/mips/au1000/common/sleeper.S
>> @@ -113,10 +113,11 @@ sdsleep:
>> lw k0, 0x14(sp)
>> mtc0 k0, CP0_CONFIG
>> - /* We need to catch the ealry Alchemy SOCs with
>> + /* We need to catch the early Alchemy SOCs with
>> * the write-only Config[OD] bit and set it back to one...
>> */
>> jal au1x00_fixup_config_od
>> + nop
>> lw $1, PT_R1(sp)
>> lw $2, PT_R2(sp)
>> lw $3, PT_R3(sp)
>> @@ -151,4 +152,5 @@ sdsleep:
>> addiu sp, PT_SIZE
>> jr ra
>> + nop
>> END(save_and_sleep)
>>
> Don't bother doing this if there's no ".set noreorder" around. Assembler
> should do a better job at filling up the delay slot in this case.
heh, my mips assembler skills are extremely rusty :-)
>> diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
>> index 2709675..bb22649 100644
>> --- a/arch/mips/mm/c-r4k.c
>> +++ b/arch/mips/mm/c-r4k.c
>>
>
> [...]
>
>> @@ -1287,20 +1262,18 @@ static void __cpuinit coherency_setup(void)
>> case CPU_R4400MC:
>> clear_c0_config(CONF_CU);
>> break;
>> - /*
>> - * We need to catch the early Alchemy SOCs with
>> - * the write-only co_config.od bit and set it back to one...
>> - */
>> - case CPU_AU1000: /* rev. DA, HA, HB */
>> - case CPU_AU1100: /* rev. AB, BA, BC ?? */
>> - case CPU_AU1500: /* rev. AB */
>> - au1x00_fixup_config_od();
>> - break;
>> case PRID_IMP_PR4450:
>> nxp_pr4450_fixup_config();
>> break;
>> }
>> +
>> +#ifdef CONFIG_MACH_ALCHEMY
>> + {
>> + extern void au1x00_fixup_config_od(void);
>> + au1x00_fixup_config_od();
>> + }
>> +#endif
>> }
>>
>
> I've been thru this before. Ralf will hardly accept #ifdef'ery and extern
> in this file. That's why we have what we have now. :-)
I believe it can be removed entirely from c-r4k.c, the Alchemy
plat_mem_setup and resume code run it too (and earlier).
Thanks for having a look!
Manuel Lauss
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [RFC PATCH 1/7] Alchemy: remove cpu_table.
2008-06-24 21:26 ` Manuel Lauss
@ 2008-06-24 21:37 ` Sergei Shtylyov
2008-06-24 21:42 ` Manuel Lauss
0 siblings, 1 reply; 12+ messages in thread
From: Sergei Shtylyov @ 2008-06-24 21:37 UTC (permalink / raw)
To: Manuel Lauss; +Cc: linux-mips
Hello.
Manuel Lauss wrote:
>>> diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
>>> index 2709675..bb22649 100644
>>> --- a/arch/mips/mm/c-r4k.c
>>> +++ b/arch/mips/mm/c-r4k.c
>>>
>>>
>> [...]
>>
>>
>>> @@ -1287,20 +1262,18 @@ static void __cpuinit coherency_setup(void)
>>> case CPU_R4400MC:
>>> clear_c0_config(CONF_CU);
>>> break;
>>> - /*
>>> - * We need to catch the early Alchemy SOCs with
>>> - * the write-only co_config.od bit and set it back to one...
>>> - */
>>> - case CPU_AU1000: /* rev. DA, HA, HB */
>>> - case CPU_AU1100: /* rev. AB, BA, BC ?? */
>>> - case CPU_AU1500: /* rev. AB */
>>> - au1x00_fixup_config_od();
>>> - break;
>>> case PRID_IMP_PR4450:
>>> nxp_pr4450_fixup_config();
>>> break;
>>> }
>>> +
>>> +#ifdef CONFIG_MACH_ALCHEMY
>>> + {
>>> + extern void au1x00_fixup_config_od(void);
>>> + au1x00_fixup_config_od();
>>> + }
>>> +#endif
>>> }
>>>
>>>
>> I've been thru this before. Ralf will hardly accept #ifdef'ery and extern
>> in this file. That's why we have what we have now. :-)
>>
>
> I believe it can be removed entirely from c-r4k.c, the Alchemy
> plat_mem_setup and resume code run it too (and earlier).
>
You cleraly didn't get it. ;-)
It's here because what is written earlier was *discarded* while doing
the coherency setup (remember, the OD bit is write only, so you can't
just RMW the Config reg).
That lead to some crap with USB on Au1500 in particular, IIRC.
> Thanks for having a look!
> Manuel Lauss
>
WBR, Sergei
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [RFC PATCH 1/7] Alchemy: remove cpu_table.
2008-06-24 21:37 ` Sergei Shtylyov
@ 2008-06-24 21:42 ` Manuel Lauss
0 siblings, 0 replies; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 21:42 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: linux-mips
Hello.
> Manuel Lauss wrote:
>
>>>> diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
>>>> index 2709675..bb22649 100644
>>>> --- a/arch/mips/mm/c-r4k.c
>>>> +++ b/arch/mips/mm/c-r4k.c
>>>>
>>> [...]
>>>
>>>
>>>> @@ -1287,20 +1262,18 @@ static void __cpuinit coherency_setup(void)
>>>> case CPU_R4400MC:
>>>> clear_c0_config(CONF_CU);
>>>> break;
>>>> - /*
>>>> - * We need to catch the early Alchemy SOCs with
>>>> - * the write-only co_config.od bit and set it back to one...
>>>> - */
>>>> - case CPU_AU1000: /* rev. DA, HA, HB */
>>>> - case CPU_AU1100: /* rev. AB, BA, BC ?? */
>>>> - case CPU_AU1500: /* rev. AB */
>>>> - au1x00_fixup_config_od();
>>>> - break;
>>>> case PRID_IMP_PR4450:
>>>> nxp_pr4450_fixup_config();
>>>> break;
>>>> }
>>>> +
>>>> +#ifdef CONFIG_MACH_ALCHEMY
>>>> + {
>>>> + extern void au1x00_fixup_config_od(void);
>>>> + au1x00_fixup_config_od();
>>>> + }
>>>> +#endif
>>>> }
>>>>
>>> I've been thru this before. Ralf will hardly accept #ifdef'ery and
>>> extern in this file. That's why we have what we have now. :-)
>>>
>>
>> I believe it can be removed entirely from c-r4k.c, the Alchemy
>> plat_mem_setup and resume code run it too (and earlier).
>>
>
> You cleraly didn't get it. ;-)
> It's here because what is written earlier was *discarded* while doing the
> coherency setup (remember, the OD bit is write only, so you can't just RMW
> the Config reg).
> That lead to some crap with USB on Au1500 in particular, IIRC.
Ah ok. I'll leave c-r4k untouched then. Thanks.
Manuel Lauss
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 2/7] Alchemy: remove get/set_au1x00_lcd_clock().
2008-06-24 20:08 [RFC PATCH 0/7] Alchemy updates Manuel Lauss
2008-06-24 20:09 ` [RFC PATCH 1/7] Alchemy: remove cpu_table Manuel Lauss
@ 2008-06-24 20:09 ` Manuel Lauss
2008-06-24 20:10 ` [RFC PATCH 3/7] MIPS: make r4k clocksource/clockevent usable as fallbacks Manuel Lauss
` (4 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 20:09 UTC (permalink / raw)
To: linux-mips
From: Manuel Lauss <mano@roarinelk.homelinux.net>
There are no in-tree users, so remove them.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/clocks.c | 31 -------------------------------
arch/mips/au1000/common/time.c | 1 -
include/asm-mips/mach-au1x00/au1000.h | 2 --
3 files changed, 0 insertions(+), 34 deletions(-)
diff --git a/arch/mips/au1000/common/clocks.c b/arch/mips/au1000/common/clocks.c
index 043429d..a8170fd 100644
--- a/arch/mips/au1000/common/clocks.c
+++ b/arch/mips/au1000/common/clocks.c
@@ -30,7 +30,6 @@
#include <asm/mach-au1x00/au1000.h>
static unsigned int au1x00_clock; /* Hz */
-static unsigned int lcd_clock; /* KHz */
static unsigned long uart_baud_base;
/*
@@ -61,33 +60,3 @@ void set_au1x00_uart_baud_base(unsigned long new_baud_base)
{
uart_baud_base = new_baud_base;
}
-
-/*
- * Calculate the Au1x00's LCD clock based on the current
- * cpu clock and the system bus clock, and try to keep it
- * below 40 MHz (the Pb1000 board can lock-up if the LCD
- * clock is over 40 MHz).
- */
-void set_au1x00_lcd_clock(void)
-{
- unsigned int static_cfg0;
- unsigned int sys_busclk = (get_au1x00_speed() / 1000) /
- ((int)(au_readl(SYS_POWERCTRL) & 0x03) + 2);
-
- static_cfg0 = au_readl(MEM_STCFG0);
-
- if (static_cfg0 & (1 << 11))
- lcd_clock = sys_busclk / 5; /* note: BCLK switching fails with D5 */
- else
- lcd_clock = sys_busclk / 4;
-
- if (lcd_clock > 50000) /* Epson MAX */
- printk(KERN_WARNING "warning: LCD clock too high (%u KHz)\n",
- lcd_clock);
-}
-
-unsigned int get_au1x00_lcd_clock(void)
-{
- return lcd_clock;
-}
-EXPORT_SYMBOL(get_au1x00_lcd_clock);
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index f9dc939..1518570 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -224,7 +224,6 @@ void __init plat_time_init(void)
printk(KERN_INFO "(PRId %08x) @ %u.%02u MHz\n", read_c0_prid(),
est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000);
set_au1x00_speed(est_freq);
- set_au1x00_lcd_clock(); /* program the LCD clock */
#ifdef CONFIG_PM
/*
diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h
index 2a60969..7245960 100644
--- a/include/asm-mips/mach-au1x00/au1000.h
+++ b/include/asm-mips/mach-au1x00/au1000.h
@@ -135,8 +135,6 @@ extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void);
extern void set_au1x00_uart_baud_base(unsigned long new_baud_base);
extern unsigned long get_au1x00_uart_baud_base(void);
-extern void set_au1x00_lcd_clock(void);
-extern unsigned int get_au1x00_lcd_clock(void);
/*
* Every board describes its IRQ mapping with this table.
--
1.5.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [RFC PATCH 3/7] MIPS: make r4k clocksource/clockevent usable as fallbacks.
2008-06-24 20:08 [RFC PATCH 0/7] Alchemy updates Manuel Lauss
2008-06-24 20:09 ` [RFC PATCH 1/7] Alchemy: remove cpu_table Manuel Lauss
2008-06-24 20:09 ` [RFC PATCH 2/7] Alchemy: remove get/set_au1x00_lcd_clock() Manuel Lauss
@ 2008-06-24 20:10 ` Manuel Lauss
2008-06-24 20:11 ` [RFC PATCH 4/7] Alchemy: TOY counter clocksource / clockevent support Manuel Lauss
` (3 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 20:10 UTC (permalink / raw)
To: linux-mips
From: Manuel Lauss <mano@roarinelk.homelinux.net>
Make r4k counter clocksource/clockevent code usable as fallbacks in case
other core-specific methods don't work.
Existing behaviour is not changed in any way.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/Kconfig | 8 ++++++++
arch/mips/kernel/Makefile | 4 ++--
arch/mips/kernel/cevt-r4k.c | 2 +-
arch/mips/kernel/csrc-r4k.c | 2 +-
include/asm-mips/time.h | 24 ++++++++++++++++--------
5 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e5a7c5d..58168c7 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -777,7 +777,11 @@ config CEVT_DS1287
config CEVT_GT641XX
bool
+config CEVT_R4K_LIB
+ bool
+
config CEVT_R4K
+ select CEVT_R4K_LIB
bool
config CEVT_SB1250
@@ -792,7 +796,11 @@ config CSRC_BCM1480
config CSRC_IOASIC
bool
+config CSRC_R4K_LIB
+ bool
+
config CSRC_R4K
+ select CSRC_R4K_LIB
bool
config CSRC_SB1250
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 65e46a6..bfa7dca 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -9,14 +9,14 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
time.o topology.o traps.o unaligned.o
obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o
-obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o
+obj-$(CONFIG_CEVT_R4K_LIB) += cevt-r4k.o
obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o
obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o
obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o
obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o
-obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o
+obj-$(CONFIG_CSRC_R4K_LIB) += csrc-r4k.o
obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 24a2d90..70f6343 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -219,7 +219,7 @@ static int c0_compare_int_usable(void)
return 1;
}
-int __cpuinit mips_clockevent_init(void)
+int __cpuinit r4k_clockevent_init(void)
{
uint64_t mips_freq = mips_hpt_frequency;
unsigned int cpu = smp_processor_id();
diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c
index 86e026f..8dc1235 100644
--- a/arch/mips/kernel/csrc-r4k.c
+++ b/arch/mips/kernel/csrc-r4k.c
@@ -22,7 +22,7 @@ static struct clocksource clocksource_mips = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-int __init init_mips_clocksource(void)
+int __init init_r4k_clocksource(void)
{
if (!cpu_has_counter || !mips_hpt_frequency)
return -ENXIO;
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index d3bd5c5..01a4c93 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -50,27 +50,35 @@ extern int (*perf_irq)(void);
/*
* Initialize the calling CPU's compare interrupt as clockevent device
*/
-#ifdef CONFIG_CEVT_R4K
-extern int mips_clockevent_init(void);
+#ifdef CONFIG_CEVT_R4K_LIB
extern unsigned int __weak get_c0_compare_int(void);
-#else
+extern int r4k_clockevent_init(void);
+#endif
+
static inline int mips_clockevent_init(void)
{
+#ifdef CONFIG_CEVT_R4K
+ return r4k_clockevent_init();
+#else
return -ENXIO;
-}
#endif
+}
/*
* Initialize the count register as a clocksource
*/
-#ifdef CONFIG_CEVT_R4K
-extern int init_mips_clocksource(void);
-#else
+#ifdef CONFIG_CSRC_R4K_LIB
+extern int init_r4k_clocksource(void);
+#endif
+
static inline int init_mips_clocksource(void)
{
+#ifdef CONFIG_CSRC_R4K
+ return init_r4k_clocksource(void);
+#else
return 0;
-}
#endif
+}
extern void clocksource_set_clock(struct clocksource *cs, unsigned int clock);
extern void clockevent_set_clock(struct clock_event_device *cd,
--
1.5.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [RFC PATCH 4/7] Alchemy: TOY counter clocksource / clockevent support.
2008-06-24 20:08 [RFC PATCH 0/7] Alchemy updates Manuel Lauss
` (2 preceding siblings ...)
2008-06-24 20:10 ` [RFC PATCH 3/7] MIPS: make r4k clocksource/clockevent usable as fallbacks Manuel Lauss
@ 2008-06-24 20:11 ` Manuel Lauss
2008-06-24 20:12 ` [RFC PATCH 5/7] Alchemy: I hate au1000/common/platform.c Manuel Lauss
` (2 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 20:11 UTC (permalink / raw)
To: linux-mips
From: Manuel Lauss <mano@roarinelk.homelinux.net>
Add support for the TOY (32kHz) counter as clocksource / clockevent
device to enable use of the 'wait' instruction.
If the 32kHz clock supply is unstable/stopped during init, the CP0 counter
clocksource/event will be used instead.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/Kconfig | 4 +-
arch/mips/au1000/common/power.c | 7 +-
arch/mips/au1000/common/setup.c | 6 -
arch/mips/au1000/common/time.c | 333 +++++++++++++++++++--------------------
4 files changed, 170 insertions(+), 180 deletions(-)
diff --git a/arch/mips/au1000/Kconfig b/arch/mips/au1000/Kconfig
index 1fe97cc..c689cd6 100644
--- a/arch/mips/au1000/Kconfig
+++ b/arch/mips/au1000/Kconfig
@@ -128,8 +128,8 @@ config SOC_AU1200
config SOC_AU1X00
bool
select 64BIT_PHYS_ADDR
- select CEVT_R4K
- select CSRC_R4K
+ select CEVT_R4K_LIB
+ select CSRC_R4K_LIB
select IRQ_CPU
select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index 2166b9e..751b4b3 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -87,7 +87,11 @@ static unsigned int sleep_static_memctlr[4][3];
#define SLEEP_TEST_TIMEOUT 1
#ifdef SLEEP_TEST_TIMEOUT
static int sleep_ticks;
-void wakeup_counter0_set(int ticks);
+static void wakeup_counter0_set(int ticks)
+{
+ au_writel(au_readl(SYS_TOYREAD) + ticks, SYS_TOYMATCH2);
+ au_sync();
+}
#endif
static void save_core_regs(void)
@@ -185,7 +189,6 @@ static void restore_core_regs(void)
}
restore_au1xxx_intctl();
- wakeup_counter0_adjust();
}
unsigned long suspend_mode;
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 0d78f50..66f4fd6 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -93,12 +93,6 @@ void __init plat_mem_setup(void)
ioport_resource.end = IOPORT_RESOURCE_END;
iomem_resource.start = IOMEM_RESOURCE_START;
iomem_resource.end = IOMEM_RESOURCE_END;
-
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
- au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
- au_sync();
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
- au_writel(0, SYS_TOYTRIM);
}
#if defined(CONFIG_64BIT_PHYS_ADDR)
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index 1518570..b6c7833 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -23,131 +23,29 @@
*
* ########################################################################
*
- * Setting up the clock on the MIPS boards.
+ * Clocksource/event using the Au1000 TOY counter.
+ * compared to the C0 timer, the TOY is a very lousy clocksource and
+ * hrtimers are definitely unusable with it. But it enables the use
+ * of the 'wait' instructions for some power-savings during idle times.
*
- * We provide the clock interrupt processing and the timer offset compute
- * functions. If CONFIG_PM is selected, we also ensure the 32KHz timer is
- * available. -- Dan
+ * If the TOY is unusable, the CP0 counter will be installed instead,
+ * and use of 'wait' prohibited.
*/
-#include <linux/types.h>
+#include <linux/clocksource.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/types.h>
#include <asm/mipsregs.h>
#include <asm/time.h>
#include <asm/mach-au1x00/au1000.h>
-static int no_au1xxx_32khz;
extern int allow_au1k_wait; /* default off for CP0 Counter */
-#ifdef CONFIG_PM
-#if HZ < 100 || HZ > 1000
-#error "unsupported HZ value! Must be in [100,1000]"
-#endif
-#define MATCH20_INC (328 * 100 / HZ) /* magic number 328 is for HZ=100... */
-static unsigned long last_pc0, last_match20;
-#endif
-
static DEFINE_SPINLOCK(time_lock);
-unsigned long wtimer;
-
-#ifdef CONFIG_PM
-static irqreturn_t counter0_irq(int irq, void *dev_id)
-{
- unsigned long pc0;
- int time_elapsed;
- static int jiffie_drift;
-
- if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
- /* should never happen! */
- printk(KERN_WARNING "counter 0 w status error\n");
- return IRQ_NONE;
- }
-
- pc0 = au_readl(SYS_TOYREAD);
- if (pc0 < last_match20)
- /* counter overflowed */
- time_elapsed = (0xffffffff - last_match20) + pc0;
- else
- time_elapsed = pc0 - last_match20;
-
- while (time_elapsed > 0) {
- do_timer(1);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(get_irq_regs()));
-#endif
- time_elapsed -= MATCH20_INC;
- last_match20 += MATCH20_INC;
- jiffie_drift++;
- }
-
- last_pc0 = pc0;
- au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
- au_sync();
-
- /*
- * Our counter ticks at 10.009765625 ms/tick, we we're running
- * almost 10 uS too slow per tick.
- */
-
- if (jiffie_drift >= 999) {
- jiffie_drift -= 999;
- do_timer(1); /* increment jiffies by one */
-#ifndef CONFIG_SMP
- update_process_times(user_mode(get_irq_regs()));
-#endif
- }
-
- return IRQ_HANDLED;
-}
-
-struct irqaction counter0_action = {
- .handler = counter0_irq,
- .flags = IRQF_DISABLED,
- .name = "alchemy-toy",
- .dev_id = NULL,
-};
-
-/* When we wakeup from sleep, we have to "catch up" on all of the
- * timer ticks we have missed.
- */
-void wakeup_counter0_adjust(void)
-{
- unsigned long pc0;
- int time_elapsed;
-
- pc0 = au_readl(SYS_TOYREAD);
- if (pc0 < last_match20)
- /* counter overflowed */
- time_elapsed = (0xffffffff - last_match20) + pc0;
- else
- time_elapsed = pc0 - last_match20;
-
- while (time_elapsed > 0) {
- time_elapsed -= MATCH20_INC;
- last_match20 += MATCH20_INC;
- }
-
- last_pc0 = pc0;
- au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
- au_sync();
-
-}
-
-/* This is just for debugging to set the timer for a sleep delay. */
-void wakeup_counter0_set(int ticks)
-{
- unsigned long pc0;
-
- pc0 = au_readl(SYS_TOYREAD);
- last_pc0 = pc0;
- au_writel(last_match20 + (MATCH20_INC * ticks), SYS_TOYMATCH2);
- au_sync();
-}
-#endif
-
/*
* I haven't found anyone that doesn't use a 12 MHz source clock,
* but just in case.....
@@ -162,37 +60,15 @@ void wakeup_counter0_set(int ticks)
* this advertised speed will introduce error and sometimes not work
* properly. This function is futher convoluted to still allow configurations
* to do that in case they have really, really old silicon with a
- * write-only PLL register, that we need the 32 KHz when power management
- * "wait" is enabled, and we need to detect if the 32 KHz isn't present
- * but requested......got it? :-) -- Dan
+ * write-only PLL register. -- Dan
*/
unsigned long calc_clock(void)
{
unsigned long cpu_speed;
unsigned long flags;
- unsigned long counter;
spin_lock_irqsave(&time_lock, flags);
- /* Power management cares if we don't have a 32 KHz counter. */
- no_au1xxx_32khz = 0;
- counter = au_readl(SYS_COUNTER_CNTRL);
- if (counter & SYS_CNTRL_E0) {
- int trim_divide = 16;
-
- au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);
-
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
- /* RTC now ticks at 32.768/16 kHz */
- au_writel(trim_divide - 1, SYS_RTCTRIM);
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
-
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
- au_writel(0, SYS_TOYWRITE);
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
- } else
- no_au1xxx_32khz = 1;
-
/*
* On early Au1000, sys_cpupll was write-only. Since these
* silicon versions of Au1000 are not sold by AMD, we don't bend
@@ -206,60 +82,177 @@ unsigned long calc_clock(void)
#endif
else
cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
+
/* On Alchemy CPU:counter ratio is 1:1 */
mips_hpt_frequency = cpu_speed;
/* Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) */
set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)
& 0x03) + 2) * 16));
+
spin_unlock_irqrestore(&time_lock, flags);
+
return cpu_speed;
}
+/* Test and initialize TOY/RTC counters. It is assumed bootloader
+ * and/or platform init code have already configured the 32kHz input
+ * sources for each (GPIO or dedicated crystal input).
+ */
+static int au1x_init_toy(void)
+{
+ unsigned long i, j;
+
+ /* enable 32kHz input */
+ i = au_readl(SYS_COUNTER_CNTRL);
+ au_writel(i | SYS_CNTRL_E0, SYS_COUNTER_CNTRL);
+ au_sync();
+
+ /* wait a bit for clock to stabilize throughout TOY unit */
+ for (j = 0x000fffff; j; j--)
+ asm volatile ("nop");
+
+ /* check 32S flag: clock detected? */
+ if (!(au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_32S))
+ goto out_err;
+
+ /* The 32S bit is unrealiable -- it stays set even when clock
+ * is stopped. Instead, read the TOY counter, it _should_ not
+ * increased without some sort of clock.
+ */
+ i = au_readl(SYS_TOYREAD);
+ for (j = 0x7ffff; j; j--)
+ asm volatile ("nop");
+ j = au_readl(SYS_TOYREAD);
+ if (i == j)
+ goto out_err;
+
+ /* setup counter 0 (TOY) */
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S)
+ asm volatile ("nop");
+ au_writel(0, SYS_TOYTRIM); /* keep ticking at 32kHz */
+ au_sync();
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S)
+ asm volatile ("nop");
+
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S)
+ asm volatile ("nop");
+ au_writel(0, SYS_TOYWRITE);
+ au_sync();
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S)
+ asm volatile ("nop");
+
+ /* setup counter 1 (RTC) too */
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S)
+ asm volatile ("nop");
+ /* RTC now ticks at 32.768/16 kHz */
+ au_writel(15, SYS_RTCTRIM);
+ au_sync();
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S)
+ asm volatile ("nop");
+
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S)
+ asm volatile ("nop");
+ au_writel(0, SYS_RTCWRITE);
+ au_sync();
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S)
+ asm volatile ("nop");
+
+ return 0;
+
+out_err:
+ /* no fun in TOY land */
+ au_writel(i & ~SYS_CNTRL_E0, SYS_COUNTER_CNTRL);
+ au_sync();
+ return -ENXIO;
+}
+
+static cycle_t au1x_toy_read(void)
+{
+ return au_readl(SYS_TOYREAD);
+}
+
+static struct clocksource clocksource_toy = {
+ .name = "Au1000-TOY",
+ .read = au1x_toy_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int toymatch2_set_next_event(unsigned long delta,
+ struct clock_event_device *cd)
+{
+ au_writel(au_readl(SYS_TOYREAD) + delta, SYS_TOYMATCH2);
+ au_sync();
+ return 0;
+}
+
+static void toymatch2_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *cd)
+{
+}
+
+static irqreturn_t toymatch2_irq(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+ cd->event_handler(cd);
+ return IRQ_HANDLED;
+}
+
+static struct clock_event_device ced_toy_match2 = {
+ .name = "Au1000-TOY2",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 100,
+ .irq = AU1000_TOY_MATCH2_INT,
+ .set_next_event = toymatch2_set_next_event,
+ .set_mode = toymatch2_set_mode,
+ .cpumask = CPU_MASK_ALL,
+};
+
+struct irqaction toymatch2_action = {
+ .handler = toymatch2_irq,
+ .flags = IRQF_DISABLED,
+ .name = "toymatch2",
+ .dev_id = &ced_toy_match2,
+};
+
+static void toymatch2_clockevent_init(void)
+{
+ struct clock_event_device *cd = &ced_toy_match2;
+
+ cd->mult = div_sc(32768, NSEC_PER_SEC, 32);
+ cd->shift = 32;
+ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+
+ /* 0x140 -- boots AND BogoMIPS detection is pretty accurate too */
+ cd->min_delta_ns = clockevent_delta2ns(0x140, cd);
+ clockevents_register_device(cd);
+ setup_irq(AU1000_TOY_MATCH2_INT, &toymatch2_action);
+}
+
void __init plat_time_init(void)
{
unsigned int est_freq = calc_clock();
est_freq += 5000; /* round */
- est_freq -= est_freq%10000;
+ est_freq -= est_freq % 10000;
printk(KERN_INFO "(PRId %08x) @ %u.%02u MHz\n", read_c0_prid(),
est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000);
set_au1x00_speed(est_freq);
-#ifdef CONFIG_PM
- /*
- * setup counter 0, since it keeps ticking after a
- * 'wait' instruction has been executed. The CP0 timer and
- * counter 1 do NOT continue running after 'wait'
- *
- * It's too early to call request_irq() here, so we handle
- * counter 0 interrupt as a special irq and it doesn't show
- * up under /proc/interrupts.
- *
- * Check to ensure we really have a 32 KHz oscillator before
- * we do this.
- */
- if (no_au1xxx_32khz)
- printk(KERN_WARNING "WARNING: no 32KHz clock found.\n");
- else {
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
- au_writel(0, SYS_TOYWRITE);
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
-
- au_writel(au_readl(SYS_WAKEMSK) | (1 << 8), SYS_WAKEMSK);
- au_writel(~0, SYS_WAKESRC);
- au_sync();
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
-
- /* Setup match20 to interrupt once every HZ */
- last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
- au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
- au_sync();
- while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
- setup_irq(AU1000_TOY_MATCH2_INT, &counter0_action);
-
- /* We can use the real 'wait' instruction. */
+ if (au1x_init_toy()) {
+ r4k_clockevent_init();
+ init_r4k_clocksource();
+
+ /* 'wait' stops the CP0 counter */
+ allow_au1k_wait = 0;
+ } else {
+ toymatch2_clockevent_init();
+
+ clocksource_toy.rating = 100;
+ clocksource_set_clock(&clocksource_toy, 32768);
+ clocksource_register(&clocksource_toy);
+ printk(KERN_INFO "Au1000 TOY clocksource installed\n");
+
allow_au1k_wait = 1;
}
-
-#endif
}
--
1.5.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [RFC PATCH 5/7] Alchemy: I hate au1000/common/platform.c ...
2008-06-24 20:08 [RFC PATCH 0/7] Alchemy updates Manuel Lauss
` (3 preceding siblings ...)
2008-06-24 20:11 ` [RFC PATCH 4/7] Alchemy: TOY counter clocksource / clockevent support Manuel Lauss
@ 2008-06-24 20:12 ` Manuel Lauss
2008-06-24 20:12 ` [RFC PATCH 6/7] Alchemy: PM: split sysctl code from more useful code Manuel Lauss
2008-06-24 20:14 ` [RFC PATCH 7/7] Alchemy: Fix PM code for Au1200/Au1550 Manuel Lauss
6 siblings, 0 replies; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 20:12 UTC (permalink / raw)
To: linux-mips
From: Manuel Lauss <mano@roarinelk.homelinux.net>
... so only compile it in if boards actually want it.
It registers stuff my board does not want/need, and
with this change I can use it as a dumping ground for
other demoboard-specific stuff spread around in the
au1000/common/ directory (PM code mainly).
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/Makefile | 2 +-
arch/mips/au1000/common/platform.c | 7 ++++++-
arch/mips/au1000/db1x00/Makefile | 1 +
arch/mips/au1000/mtx-1/Makefile | 2 +-
arch/mips/au1000/pb1000/Makefile | 1 +
arch/mips/au1000/pb1100/Makefile | 1 +
arch/mips/au1000/pb1200/Makefile | 2 +-
arch/mips/au1000/pb1500/Makefile | 1 +
arch/mips/au1000/pb1550/Makefile | 1 +
arch/mips/au1000/xxs1500/Makefile | 1 +
10 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
index 850de08..aefb2b8 100644
--- a/arch/mips/au1000/common/Makefile
+++ b/arch/mips/au1000/common/Makefile
@@ -6,7 +6,7 @@
#
obj-y += prom.o irq.o puts.o time.o reset.o \
- au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
+ au1xxx_irqmap.o clocks.o power.o setup.o \
sleeper.o dma.o dbdma.o gpio.o
obj-$(CONFIG_KGDB) += dbg_io.o
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index 74d6d4a..a147c2d 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -1,5 +1,5 @@
/*
- * Platform device support for Au1x00 SoCs.
+ * Common device support for Au1x00 demoboards.
*
* Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
*
@@ -9,6 +9,11 @@
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
+ *
+ * This file is intended to be included by all db1xxx/pb1xxx demoboards.
+ * It is currently used by all in-tree au1x-based boards. If your
+ * board does not want/need all the stuff registered in here (like mine)
+ * then simply don't include it in your board's Makefile ;-) --mlau
*/
#include <linux/platform_device.h>
diff --git a/arch/mips/au1000/db1x00/Makefile b/arch/mips/au1000/db1x00/Makefile
index 274db3b..3bfec10 100644
--- a/arch/mips/au1000/db1x00/Makefile
+++ b/arch/mips/au1000/db1x00/Makefile
@@ -6,3 +6,4 @@
#
lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/mtx-1/Makefile b/arch/mips/au1000/mtx-1/Makefile
index 7c67b3d..ef98975 100644
--- a/arch/mips/au1000/mtx-1/Makefile
+++ b/arch/mips/au1000/mtx-1/Makefile
@@ -7,6 +7,6 @@
#
lib-y := init.o board_setup.o irqmap.o
-obj-y := platform.o
+obj-y := platform.o ../common/platform.o
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/au1000/pb1000/Makefile b/arch/mips/au1000/pb1000/Makefile
index 99bbec0..41a09be 100644
--- a/arch/mips/au1000/pb1000/Makefile
+++ b/arch/mips/au1000/pb1000/Makefile
@@ -6,3 +6,4 @@
#
lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/pb1100/Makefile b/arch/mips/au1000/pb1100/Makefile
index 793e97c..1a8cd71 100644
--- a/arch/mips/au1000/pb1100/Makefile
+++ b/arch/mips/au1000/pb1100/Makefile
@@ -6,3 +6,4 @@
#
lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/au1000/pb1200/Makefile
index d678adf..7b9f2f5 100644
--- a/arch/mips/au1000/pb1200/Makefile
+++ b/arch/mips/au1000/pb1200/Makefile
@@ -3,6 +3,6 @@
#
lib-y := init.o board_setup.o irqmap.o
-obj-y += platform.o
+obj-y += platform.o ../common/platform.o
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/au1000/pb1500/Makefile b/arch/mips/au1000/pb1500/Makefile
index 602f38d..c12e1bd 100644
--- a/arch/mips/au1000/pb1500/Makefile
+++ b/arch/mips/au1000/pb1500/Makefile
@@ -6,3 +6,4 @@
#
lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/pb1550/Makefile b/arch/mips/au1000/pb1550/Makefile
index 7d8beca..8df0890 100644
--- a/arch/mips/au1000/pb1550/Makefile
+++ b/arch/mips/au1000/pb1550/Makefile
@@ -6,3 +6,4 @@
#
lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
diff --git a/arch/mips/au1000/xxs1500/Makefile b/arch/mips/au1000/xxs1500/Makefile
index db3c526..86db0f7 100644
--- a/arch/mips/au1000/xxs1500/Makefile
+++ b/arch/mips/au1000/xxs1500/Makefile
@@ -6,3 +6,4 @@
#
lib-y := init.o board_setup.o irqmap.o
+obj-y := ../common/platform.o
--
1.5.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [RFC PATCH 6/7] Alchemy: PM: split sysctl code from more useful code.
2008-06-24 20:08 [RFC PATCH 0/7] Alchemy updates Manuel Lauss
` (4 preceding siblings ...)
2008-06-24 20:12 ` [RFC PATCH 5/7] Alchemy: I hate au1000/common/platform.c Manuel Lauss
@ 2008-06-24 20:12 ` Manuel Lauss
2008-06-24 20:14 ` [RFC PATCH 7/7] Alchemy: Fix PM code for Au1200/Au1550 Manuel Lauss
6 siblings, 0 replies; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 20:12 UTC (permalink / raw)
To: linux-mips
From: Manuel Lauss <mano@roarinelk.homelinux.net>
Split the custom Alchemy pm sysctl code away from the more
useful parts (the actual suspend/resume work code).
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/platform.c | 295 ++++++++++++++++++++++++++++++++++-
arch/mips/au1000/common/power.c | 306 +-----------------------------------
2 files changed, 296 insertions(+), 305 deletions(-)
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index a147c2d..bf3bcbf 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -18,8 +18,13 @@
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
-#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
+#include <asm/uaccess.h>
#include <asm/mach-au1x00/au1xxx.h>
#define PORT(_base, _irq) \
@@ -321,3 +326,291 @@ static int __init au1xxx_platform_init(void)
}
arch_initcall(au1xxx_platform_init);
+
+
+/*********************************************************************/
+
+
+#ifdef CONFIG_PM
+
+static DEFINE_SPINLOCK(pm_lock);
+
+extern unsigned long save_local_and_disable(int controller);
+extern void restore_local_and_enable(int controller, unsigned long mask);
+extern void local_enable_irq(unsigned int irq_nr);
+extern void au_sleep(void);
+
+/*
+ * Define this to cause the value you write to /proc/sys/pm/sleep to
+ * set the TOY timer for the amount of time you want to sleep.
+ * This is done mainly for testing, but may be useful in other cases.
+ * The value is number of 32KHz ticks to sleep.
+ */
+#define SLEEP_TEST_TIMEOUT 1
+#ifdef SLEEP_TEST_TIMEOUT
+static int sleep_ticks;
+static void wakeup_counter0_set(int ticks)
+{
+ au_writel(au_readl(SYS_TOYREAD) + ticks, SYS_TOYMATCH2);
+ au_sync();
+}
+#endif
+
+static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
+ void __user *buffer, size_t *len, loff_t *ppos)
+{
+ unsigned long wakeup, flags;
+#ifdef SLEEP_TEST_TIMEOUT
+#define TMPBUFLEN2 16
+ char buf[TMPBUFLEN2], *p;
+#endif
+
+ spin_lock_irqsave(&pm_lock, flags);
+
+ if (!write) {
+ *len = 0;
+ spin_unlock_irqrestore(&pm_lock, flags);
+ return 0;
+ }
+
+#ifdef SLEEP_TEST_TIMEOUT
+ if (*len > TMPBUFLEN2 - 1)
+ return -EFAULT;
+ if (copy_from_user(buf, buffer, *len))
+ return -EFAULT;
+ buf[*len] = 0;
+ p = buf;
+ sleep_ticks = simple_strtoul(p, &p, 0);
+#endif
+
+ /**
+ ** The code below is all system dependent and we should probably
+ ** have a function call out of here to set this up. You need
+ ** to configure the GPIO or timer interrupts that will bring
+ ** you out of sleep.
+ ** For testing, the TOY counter wakeup is useful.
+ **/
+#if 0
+ au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
+
+ /* GPIO 6 can cause a wake up event */
+ wakeup = au_readl(SYS_WAKEMSK);
+ wakeup &= ~(1 << 8); /* turn off match20 wakeup */
+ wakeup |= 1 << 6; /* turn on GPIO 6 wakeup */
+#else
+ /* For testing, allow match20 to wake us up. */
+#ifdef SLEEP_TEST_TIMEOUT
+ wakeup_counter0_set(sleep_ticks);
+#endif
+ wakeup = 1 << 8; /* turn on match20 wakeup */
+ wakeup = 0;
+#endif
+ au_writel(1, SYS_WAKESRC); /* clear cause */
+ au_sync();
+ au_writel(wakeup, SYS_WAKEMSK);
+ au_sync();
+
+ au_sleep();
+
+ spin_unlock_irqrestore(&pm_lock, flags);
+
+ return 0;
+}
+
+/*
+ * This is the number of bits of precision for the loops_per_jiffy.
+ * Each bit takes on average 1.5/HZ seconds. This (like the original)
+ * is a little better than 1%.
+ */
+#define LPS_PREC 8
+
+static void au1000_calibrate_delay(void)
+{
+ unsigned long ticks, loopbit;
+ int lps_precision = LPS_PREC;
+
+ loops_per_jiffy = 1 << 12;
+
+ while (loops_per_jiffy <<= 1) {
+ /* Wait for "start of" clock tick */
+ ticks = jiffies;
+ while (ticks == jiffies)
+ /* nothing */ ;
+ /* Go ... */
+ ticks = jiffies;
+ __delay(loops_per_jiffy);
+ ticks = jiffies - ticks;
+ if (ticks)
+ break;
+ }
+
+ /*
+ * Do a binary approximation to get loops_per_jiffy set to be equal
+ * one clock (up to lps_precision bits)
+ */
+ loops_per_jiffy >>= 1;
+ loopbit = loops_per_jiffy;
+ while (lps_precision-- && (loopbit >>= 1)) {
+ loops_per_jiffy |= loopbit;
+ ticks = jiffies;
+ while (ticks == jiffies);
+ ticks = jiffies;
+ __delay(loops_per_jiffy);
+ if (jiffies != ticks) /* longer than 1 tick */
+ loops_per_jiffy &= ~loopbit;
+ }
+}
+
+static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
+ void __user *buffer, size_t *len, loff_t *ppos)
+{
+ int retval = 0, i;
+ unsigned long val, pll;
+#define TMPBUFLEN 64
+#define MAX_CPU_FREQ 396
+ char buf[TMPBUFLEN], *p;
+ unsigned long flags, intc0_mask, intc1_mask;
+ unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh;
+ unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
+ unsigned long baud_rate;
+
+ spin_lock_irqsave(&pm_lock, flags);
+ if (!write)
+ *len = 0;
+ else {
+ /* Parse the new frequency */
+ if (*len > TMPBUFLEN - 1) {
+ spin_unlock_irqrestore(&pm_lock, flags);
+ return -EFAULT;
+ }
+ if (copy_from_user(buf, buffer, *len)) {
+ spin_unlock_irqrestore(&pm_lock, flags);
+ return -EFAULT;
+ }
+ buf[*len] = 0;
+ p = buf;
+ val = simple_strtoul(p, &p, 0);
+ if (val > MAX_CPU_FREQ) {
+ spin_unlock_irqrestore(&pm_lock, flags);
+ return -EFAULT;
+ }
+
+ pll = val / 12;
+ if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
+ /* Revisit this for higher speed CPUs */
+ spin_unlock_irqrestore(&pm_lock, flags);
+ return -EFAULT;
+ }
+
+ old_baud_base = get_au1x00_uart_baud_base();
+ old_cpu_freq = get_au1x00_speed();
+
+ new_cpu_freq = pll * 12 * 1000000;
+ new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)
+ & 0x03) + 2) * 16));
+ set_au1x00_speed(new_cpu_freq);
+ set_au1x00_uart_baud_base(new_baud_base);
+
+ old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
+ new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) |
+ (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
+
+ au_writel(pll, SYS_CPUPLL);
+ au_sync_delay(1);
+ au_writel(new_refresh, MEM_SDREFCFG);
+ au_sync_delay(1);
+
+ for (i = 0; i < 4; i++)
+ if (au_readl(UART_BASE + UART_MOD_CNTRL +
+ i * 0x00100000) == 3) {
+ old_clk = au_readl(UART_BASE + UART_CLK +
+ i * 0x00100000);
+ baud_rate = old_baud_base / old_clk;
+ /*
+ * We won't get an exact baud rate and the error
+ * could be significant enough that our new
+ * calculation will result in a clock that will
+ * give us a baud rate that's too far off from
+ * what we really want.
+ */
+ if (baud_rate > 100000)
+ baud_rate = 115200;
+ else if (baud_rate > 50000)
+ baud_rate = 57600;
+ else if (baud_rate > 30000)
+ baud_rate = 38400;
+ else if (baud_rate > 17000)
+ baud_rate = 19200;
+ else
+ baud_rate = 9600;
+ new_clk = new_baud_base / baud_rate;
+ au_writel(new_clk, UART_BASE + UART_CLK +
+ i * 0x00100000);
+ au_sync_delay(10);
+ }
+ }
+
+ /*
+ * We don't want _any_ interrupts other than match20. Otherwise our
+ * au1000_calibrate_delay() calculation will be off, potentially a lot.
+ */
+ intc0_mask = save_local_and_disable(0);
+ intc1_mask = save_local_and_disable(1);
+ local_enable_irq(AU1000_TOY_MATCH2_INT);
+ spin_unlock_irqrestore(&pm_lock, flags);
+ au1000_calibrate_delay();
+ restore_local_and_enable(0, intc0_mask);
+ restore_local_and_enable(1, intc1_mask);
+
+ return retval;
+}
+
+
+static struct ctl_table pm_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "sleep",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0600,
+ .proc_handler = &pm_do_sleep
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "freq",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0600,
+ .proc_handler = &pm_do_freq
+ },
+ {}
+};
+
+static struct ctl_table pm_dir_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "pm",
+ .mode = 0555,
+ .child = pm_table
+ },
+ {}
+};
+
+/*
+ * Initialize power interface
+ */
+static int __init pm_init(void)
+{
+ au_writel(0, SYS_WAKESRC);
+ au_sync();
+ au_writel(0, SYS_WAKEMSK);
+ au_sync();
+
+ register_sysctl_table(pm_dir_table);
+
+ return 0;
+}
+
+__initcall(pm_init);
+
+#endif /* CONFIG_PM */
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index 751b4b3..7feb21a 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -30,31 +30,12 @@
*/
#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/pm_legacy.h>
-#include <linux/sysctl.h>
-#include <linux/jiffies.h>
-
-#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_PM
-#define DEBUG 1
-#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-static void au1000_calibrate_delay(void);
-
-extern unsigned long save_local_and_disable(int controller);
-extern void restore_local_and_enable(int controller, unsigned long mask);
-extern void local_enable_irq(unsigned int irq_nr);
-
-static DEFINE_SPINLOCK(pm_lock);
+extern void save_and_sleep(void);
/*
* We need to save/restore a bunch of core registers that are
@@ -78,22 +59,6 @@ static unsigned int sleep_usbhost_enable;
static unsigned int sleep_usbdev_enable;
static unsigned int sleep_static_memctlr[4][3];
-/*
- * Define this to cause the value you write to /proc/sys/pm/sleep to
- * set the TOY timer for the amount of time you want to sleep.
- * This is done mainly for testing, but may be useful in other cases.
- * The value is number of 32KHz ticks to sleep.
- */
-#define SLEEP_TEST_TIMEOUT 1
-#ifdef SLEEP_TEST_TIMEOUT
-static int sleep_ticks;
-static void wakeup_counter0_set(int ticks)
-{
- au_writel(au_readl(SYS_TOYREAD) + ticks, SYS_TOYMATCH2);
- au_sync();
-}
-#endif
-
static void save_core_regs(void)
{
extern void save_au1xxx_intctl(void);
@@ -191,279 +156,12 @@ static void restore_core_regs(void)
restore_au1xxx_intctl();
}
-unsigned long suspend_mode;
-
-void wakeup_from_suspend(void)
+void au_sleep(void)
{
- suspend_mode = 0;
-}
-
-int au_sleep(void)
-{
- unsigned long wakeup, flags;
- extern void save_and_sleep(void);
-
- spin_lock_irqsave(&pm_lock, flags);
-
save_core_regs();
-
flush_cache_all();
-
- /**
- ** The code below is all system dependent and we should probably
- ** have a function call out of here to set this up. You need
- ** to configure the GPIO or timer interrupts that will bring
- ** you out of sleep.
- ** For testing, the TOY counter wakeup is useful.
- **/
-#if 0
- au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
-
- /* GPIO 6 can cause a wake up event */
- wakeup = au_readl(SYS_WAKEMSK);
- wakeup &= ~(1 << 8); /* turn off match20 wakeup */
- wakeup |= 1 << 6; /* turn on GPIO 6 wakeup */
-#else
- /* For testing, allow match20 to wake us up. */
-#ifdef SLEEP_TEST_TIMEOUT
- wakeup_counter0_set(sleep_ticks);
-#endif
- wakeup = 1 << 8; /* turn on match20 wakeup */
- wakeup = 0;
-#endif
- au_writel(1, SYS_WAKESRC); /* clear cause */
- au_sync();
- au_writel(wakeup, SYS_WAKEMSK);
- au_sync();
-
save_and_sleep();
-
- /*
- * After a wakeup, the cpu vectors back to 0x1fc00000, so
- * it's up to the boot code to get us back here.
- */
restore_core_regs();
- spin_unlock_irqrestore(&pm_lock, flags);
- return 0;
}
-static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
- void __user *buffer, size_t *len, loff_t *ppos)
-{
-#ifdef SLEEP_TEST_TIMEOUT
-#define TMPBUFLEN2 16
- char buf[TMPBUFLEN2], *p;
-#endif
-
- if (!write)
- *len = 0;
- else {
-#ifdef SLEEP_TEST_TIMEOUT
- if (*len > TMPBUFLEN2 - 1)
- return -EFAULT;
- if (copy_from_user(buf, buffer, *len))
- return -EFAULT;
- buf[*len] = 0;
- p = buf;
- sleep_ticks = simple_strtoul(p, &p, 0);
#endif
-
- au_sleep();
- }
- return 0;
-}
-
-static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
- void __user *buffer, size_t *len, loff_t *ppos)
-{
- int retval = 0, i;
- unsigned long val, pll;
-#define TMPBUFLEN 64
-#define MAX_CPU_FREQ 396
- char buf[TMPBUFLEN], *p;
- unsigned long flags, intc0_mask, intc1_mask;
- unsigned long old_baud_base, old_cpu_freq, old_clk, old_refresh;
- unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
- unsigned long baud_rate;
-
- spin_lock_irqsave(&pm_lock, flags);
- if (!write)
- *len = 0;
- else {
- /* Parse the new frequency */
- if (*len > TMPBUFLEN - 1) {
- spin_unlock_irqrestore(&pm_lock, flags);
- return -EFAULT;
- }
- if (copy_from_user(buf, buffer, *len)) {
- spin_unlock_irqrestore(&pm_lock, flags);
- return -EFAULT;
- }
- buf[*len] = 0;
- p = buf;
- val = simple_strtoul(p, &p, 0);
- if (val > MAX_CPU_FREQ) {
- spin_unlock_irqrestore(&pm_lock, flags);
- return -EFAULT;
- }
-
- pll = val / 12;
- if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
- /* Revisit this for higher speed CPUs */
- spin_unlock_irqrestore(&pm_lock, flags);
- return -EFAULT;
- }
-
- old_baud_base = get_au1x00_uart_baud_base();
- old_cpu_freq = get_au1x00_speed();
-
- new_cpu_freq = pll * 12 * 1000000;
- new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)
- & 0x03) + 2) * 16));
- set_au1x00_speed(new_cpu_freq);
- set_au1x00_uart_baud_base(new_baud_base);
-
- old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
- new_refresh = ((old_refresh * new_cpu_freq) / old_cpu_freq) |
- (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
-
- au_writel(pll, SYS_CPUPLL);
- au_sync_delay(1);
- au_writel(new_refresh, MEM_SDREFCFG);
- au_sync_delay(1);
-
- for (i = 0; i < 4; i++)
- if (au_readl(UART_BASE + UART_MOD_CNTRL +
- i * 0x00100000) == 3) {
- old_clk = au_readl(UART_BASE + UART_CLK +
- i * 0x00100000);
- baud_rate = old_baud_base / old_clk;
- /*
- * We won't get an exact baud rate and the error
- * could be significant enough that our new
- * calculation will result in a clock that will
- * give us a baud rate that's too far off from
- * what we really want.
- */
- if (baud_rate > 100000)
- baud_rate = 115200;
- else if (baud_rate > 50000)
- baud_rate = 57600;
- else if (baud_rate > 30000)
- baud_rate = 38400;
- else if (baud_rate > 17000)
- baud_rate = 19200;
- else
- baud_rate = 9600;
- new_clk = new_baud_base / baud_rate;
- au_writel(new_clk, UART_BASE + UART_CLK +
- i * 0x00100000);
- au_sync_delay(10);
- }
- }
-
- /*
- * We don't want _any_ interrupts other than match20. Otherwise our
- * au1000_calibrate_delay() calculation will be off, potentially a lot.
- */
- intc0_mask = save_local_and_disable(0);
- intc1_mask = save_local_and_disable(1);
- local_enable_irq(AU1000_TOY_MATCH2_INT);
- spin_unlock_irqrestore(&pm_lock, flags);
- au1000_calibrate_delay();
- restore_local_and_enable(0, intc0_mask);
- restore_local_and_enable(1, intc1_mask);
-
- return retval;
-}
-
-
-static struct ctl_table pm_table[] = {
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "sleep",
- .data = NULL,
- .maxlen = 0,
- .mode = 0600,
- .proc_handler = &pm_do_sleep
- },
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "freq",
- .data = NULL,
- .maxlen = 0,
- .mode = 0600,
- .proc_handler = &pm_do_freq
- },
- {}
-};
-
-static struct ctl_table pm_dir_table[] = {
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "pm",
- .mode = 0555,
- .child = pm_table
- },
- {}
-};
-
-/*
- * Initialize power interface
- */
-static int __init pm_init(void)
-{
- register_sysctl_table(pm_dir_table);
- return 0;
-}
-
-__initcall(pm_init);
-
-/*
- * This is right out of init/main.c
- */
-
-/*
- * This is the number of bits of precision for the loops_per_jiffy.
- * Each bit takes on average 1.5/HZ seconds. This (like the original)
- * is a little better than 1%.
- */
-#define LPS_PREC 8
-
-static void au1000_calibrate_delay(void)
-{
- unsigned long ticks, loopbit;
- int lps_precision = LPS_PREC;
-
- loops_per_jiffy = 1 << 12;
-
- while (loops_per_jiffy <<= 1) {
- /* Wait for "start of" clock tick */
- ticks = jiffies;
- while (ticks == jiffies)
- /* nothing */ ;
- /* Go ... */
- ticks = jiffies;
- __delay(loops_per_jiffy);
- ticks = jiffies - ticks;
- if (ticks)
- break;
- }
-
- /*
- * Do a binary approximation to get loops_per_jiffy set to be equal
- * one clock (up to lps_precision bits)
- */
- loops_per_jiffy >>= 1;
- loopbit = loops_per_jiffy;
- while (lps_precision-- && (loopbit >>= 1)) {
- loops_per_jiffy |= loopbit;
- ticks = jiffies;
- while (ticks == jiffies);
- ticks = jiffies;
- __delay(loops_per_jiffy);
- if (jiffies != ticks) /* longer than 1 tick */
- loops_per_jiffy &= ~loopbit;
- }
-}
-#endif /* CONFIG_PM */
--
1.5.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [RFC PATCH 7/7] Alchemy: Fix PM code for Au1200/Au1550.
2008-06-24 20:08 [RFC PATCH 0/7] Alchemy updates Manuel Lauss
` (5 preceding siblings ...)
2008-06-24 20:12 ` [RFC PATCH 6/7] Alchemy: PM: split sysctl code from more useful code Manuel Lauss
@ 2008-06-24 20:14 ` Manuel Lauss
6 siblings, 0 replies; 12+ messages in thread
From: Manuel Lauss @ 2008-06-24 20:14 UTC (permalink / raw)
To: linux-mips
From: Manuel Lauss <mano@roarinelk.homelinux.net>
- Make PM code compile on Au1200.
- sleep code for Au1200/Au1550.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
---
arch/mips/au1000/common/platform.c | 5 +-
arch/mips/au1000/common/power.c | 125 ++++++++++++++++++++++--------------
arch/mips/au1000/common/sleeper.S | 119 +++++++++++++++++++++-------------
3 files changed, 152 insertions(+), 97 deletions(-)
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index bf3bcbf..02d237a 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -417,6 +417,7 @@ static int pm_do_sleep(ctl_table *ctl, int write, struct file *file,
return 0;
}
+#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
/*
* This is the number of bits of precision for the loops_per_jiffy.
* Each bit takes on average 1.5/HZ seconds. This (like the original)
@@ -564,7 +565,7 @@ static int pm_do_freq(ctl_table *ctl, int write, struct file *file,
return retval;
}
-
+#endif
static struct ctl_table pm_table[] = {
{
@@ -575,6 +576,7 @@ static struct ctl_table pm_table[] = {
.mode = 0600,
.proc_handler = &pm_do_sleep
},
+#if !defined(CONFIG_SOC_AU1200) && !defined(CONFIG_SOC_AU1550)
{
.ctl_name = CTL_UNNUMBERED,
.procname = "freq",
@@ -583,6 +585,7 @@ static struct ctl_table pm_table[] = {
.mode = 0600,
.proc_handler = &pm_do_freq
},
+#endif
{}
};
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index 7feb21a..c539c0f 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -1,13 +1,10 @@
/*
* BRIEF MODULE DESCRIPTION
- * Au1xx0 Power Management routines.
+ * Au1xxx suspend/resume routines.
*
* Copyright 2001, 2008 MontaVista Software Inc.
* Author: MontaVista Software, Inc. <source@mvista.com>
*
- * Some of the routines are right out of init/main.c, whose
- * copyrights apply here.
- *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
@@ -29,13 +26,13 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/init.h>
-#include <asm/cacheflush.h>
-#include <asm/mach-au1x00/au1000.h>
-
#ifdef CONFIG_PM
+#include <asm/mach-au1x00/au1000.h>
+
extern void save_and_sleep(void);
+extern void save_au1xxx_intctl(void);
+extern void restore_au1xxx_intctl(void);
/*
* We need to save/restore a bunch of core registers that are
@@ -47,59 +44,68 @@ extern void save_and_sleep(void);
* We only have to save/restore registers that aren't otherwise
* done as part of a driver pm_* function.
*/
-static unsigned int sleep_aux_pll_cntrl;
-static unsigned int sleep_cpu_pll_cntrl;
-static unsigned int sleep_pin_function;
-static unsigned int sleep_uart0_inten;
-static unsigned int sleep_uart0_fifoctl;
-static unsigned int sleep_uart0_linectl;
-static unsigned int sleep_uart0_clkdiv;
-static unsigned int sleep_uart0_enable;
-static unsigned int sleep_usbhost_enable;
-static unsigned int sleep_usbdev_enable;
-static unsigned int sleep_static_memctlr[4][3];
+static unsigned int sleep_uart0_inten;
+static unsigned int sleep_uart0_fifoctl;
+static unsigned int sleep_uart0_linectl;
+static unsigned int sleep_uart0_clkdiv;
+static unsigned int sleep_uart0_enable;
+static unsigned int sleep_usb[2];
+static unsigned int sleep_sys_clocks[5];
+static unsigned int sleep_sys_pinfunc;
+static unsigned int sleep_static_memctlr[4][3];
static void save_core_regs(void)
{
- extern void save_au1xxx_intctl(void);
- extern void pm_eth0_shutdown(void);
-
- /*
- * Do the serial ports.....these really should be a pm_*
- * registered function by the driver......but of course the
- * standard serial driver doesn't understand our Au1xxx
- * unique registers.
- */
+ /* Do the serial ports.....these really should be a pm_*
+ * registered function by the driver......but of course the
+ * standard serial driver doesn't understand our Au1xxx
+ * unique registers.
+ */
sleep_uart0_inten = au_readl(UART0_ADDR + UART_IER);
sleep_uart0_fifoctl = au_readl(UART0_ADDR + UART_FCR);
sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR);
sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK);
sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL);
+ au_writel(0, UART0_ADDR + UART_MOD_CNTRL);
+ au_sync();
+#ifndef CONFIG_SOC_AU1200
/* Shutdown USB host/device. */
- sleep_usbhost_enable = au_readl(USB_HOST_CONFIG);
+ sleep_usb[0] = au_readl(USB_HOST_CONFIG);
/* There appears to be some undocumented reset register.... */
- au_writel(0, 0xb0100004); au_sync();
- au_writel(0, USB_HOST_CONFIG); au_sync();
+ au_writel(0, 0xb0100004);
+ au_sync();
+ au_writel(0, USB_HOST_CONFIG);
+ au_sync();
+
+ sleep_usb[1] = au_readl(USBD_ENABLE);
+ au_writel(0, USBD_ENABLE);
+ au_sync();
- sleep_usbdev_enable = au_readl(USBD_ENABLE);
- au_writel(0, USBD_ENABLE); au_sync();
+#else /* AU1200 */
+
+ /* enable access to OTG mmio so we can save OTG CAP/MUX.
+ * FIXME: write an OTG driver and move this stuff there!
+ */
+ au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4);
+ au_sync();
+ sleep_usb[0] = au_readl(0xb4020020); /* OTG_CAP */
+ sleep_usb[1] = au_readl(0xb4020024); /* OTG_MUX */
+#endif
/* Save interrupt controller state. */
save_au1xxx_intctl();
/* Clocks and PLLs. */
- sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL);
+ sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0);
+ sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1);
+ sleep_sys_clocks[2] = au_readl(SYS_CLKSRC);
+ sleep_sys_clocks[3] = au_readl(SYS_CPUPLL);
+ sleep_sys_clocks[4] = au_readl(SYS_AUXPLL);
- /*
- * We don't really need to do this one, but unless we
- * write it again it won't have a valid value if we
- * happen to read it.
- */
- sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL);
-
- sleep_pin_function = au_readl(SYS_PINFUNC);
+ /* pin mux config */
+ sleep_sys_pinfunc = au_readl(SYS_PINFUNC);
/* Save the static memory controller configuration. */
sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0);
@@ -118,12 +124,34 @@ static void save_core_regs(void)
static void restore_core_regs(void)
{
- extern void restore_au1xxx_intctl(void);
- extern void wakeup_counter0_adjust(void);
-
- au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync();
- au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync();
- au_writel(sleep_pin_function, SYS_PINFUNC); au_sync();
+ /* restore clock configuration. Writing CPUPLL last will
+ * stall a bit and stabilize other clocks.
+ */
+ au_writel(sleep_sys_clocks[0], SYS_FREQCTRL0);
+ au_writel(sleep_sys_clocks[1], SYS_FREQCTRL1);
+ au_writel(sleep_sys_clocks[2], SYS_CLKSRC);
+ au_writel(sleep_sys_clocks[4], SYS_AUXPLL);
+ au_writel(sleep_sys_clocks[3], SYS_CPUPLL);
+ au_sync();
+
+ au_writel(sleep_sys_pinfunc, SYS_PINFUNC);
+ au_sync();
+
+#ifndef CONFIG_SOC_AU1200
+ au_writel(sleep_usb[0], USB_HOST_CONFIG);
+ au_writel(sleep_usb[1], USBD_ENABLE);
+ au_sync();
+#else
+ /* enable accces to OTG memory */
+ au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4);
+ au_sync();
+
+ /* restore OTG caps and port mux. */
+ au_writel(sleep_usb[0], 0xb4020020 + 0); /* OTG_CAP */
+ au_sync();
+ au_writel(sleep_usb[1], 0xb4020020 + 4); /* OTG_MUX */
+ au_sync();
+#endif
/* Restore the static memory controller configuration. */
au_writel(sleep_static_memctlr[0][0], MEM_STCFG0);
@@ -159,7 +187,6 @@ static void restore_core_regs(void)
void au_sleep(void)
{
save_core_regs();
- flush_cache_all();
save_and_sleep();
restore_core_regs();
}
diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S
index 8039aca..9d1af54 100644
--- a/arch/mips/au1000/common/sleeper.S
+++ b/arch/mips/au1000/common/sleeper.S
@@ -15,9 +15,11 @@
#include <asm/regdef.h>
#include <asm/stackframe.h>
+ .extern __flush_cache_all
+
.text
- .set macro
- .set noat
+ .set noreorder
+ .set noat
.align 5
/* Save all of the processor general registers and go to sleep.
@@ -33,14 +35,6 @@ LEAF(save_and_sleep)
sw $5, PT_R5(sp)
sw $6, PT_R6(sp)
sw $7, PT_R7(sp)
- sw $8, PT_R8(sp)
- sw $9, PT_R9(sp)
- sw $10, PT_R10(sp)
- sw $11, PT_R11(sp)
- sw $12, PT_R12(sp)
- sw $13, PT_R13(sp)
- sw $14, PT_R14(sp)
- sw $15, PT_R15(sp)
sw $16, PT_R16(sp)
sw $17, PT_R17(sp)
sw $18, PT_R18(sp)
@@ -49,12 +43,9 @@ LEAF(save_and_sleep)
sw $21, PT_R21(sp)
sw $22, PT_R22(sp)
sw $23, PT_R23(sp)
- sw $24, PT_R24(sp)
- sw $25, PT_R25(sp)
sw $26, PT_R26(sp)
sw $27, PT_R27(sp)
sw $28, PT_R28(sp)
- sw $29, PT_R29(sp)
sw $30, PT_R30(sp)
sw $31, PT_R31(sp)
mfc0 k0, CP0_STATUS
@@ -66,44 +57,89 @@ LEAF(save_and_sleep)
mfc0 k0, CP0_CONFIG
sw k0, 0x14(sp)
+ /* flush caches to make sure context is in memory */
+ la t1, __flush_cache_all
+ lw t0, 0(t1)
+ jal t0
+ nop
+
/* Now set up the scratch registers so the boot rom will
* return to this point upon wakeup.
+ * sys_scratch0 : SP
+ * sys_scratch1 : RA
*/
- la k0, 1f
- lui k1, 0xb190
- ori k1, 0x18
- sw sp, 0(k1)
- ori k1, 0x1c
- sw k0, 0(k1)
-
-/* Put SDRAM into self refresh. Preload instructions into cache,
- * issue a precharge, then auto refresh, then sleep commands to it.
- */
- la t0, sdsleep
+ li t3, 0xb1900000 /* sys_xxx */
+ sw sp, 0x0018(t3)
+ la k0, resume_from_sleep
+ sw k0, 0x001c(t3)
+
+ /* Put SDRAM into self refresh. Preload instructions into cache,
+ * issue a precharge, then auto refresh, then sleep commands to it.
+ */
+ la t0, sdsleep
.set mips3
- cache 0x14, 0(t0)
- cache 0x14, 32(t0)
- cache 0x14, 64(t0)
- cache 0x14, 96(t0)
+ cache 0x14, 0(t0)
+ cache 0x14, 32(t0)
+ cache 0x14, 64(t0)
+ cache 0x14, 96(t0)
.set mips0
sdsleep:
- lui k0, 0xb400
- sw zero, 0x001c(k0) /* Precharge */
- sw zero, 0x0020(k0) /* Auto refresh */
- sw zero, 0x0030(k0) /* SDRAM sleep */
+ li a0, 0xb4000000 /* mem_xxx */
+#if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100) || \
+ defined(CONFIG_SOC_AU1500)
+ sw zero, 0x001c(a0) /* Precharge */
+ sync
+ sw zero, 0x0020(a0) /* Auto Refresh */
+ sync
+ sw zero, 0x0030(a0) /* Sleep */
sync
+#endif
- lui k1, 0xb190
- sw zero, 0x0078(k1) /* get ready to sleep */
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+ sw zero, 0x08c0(a0) /* Precharge */
sync
- sw zero, 0x007c(k1) /* Put processor to sleep */
+ sw zero, 0x08d0(a0) /* Self Refresh */
sync
+ /* wait for sdram to enter self-refresh mode */
+ li t0, 0x01000000
+sref_wait_loop:
+ lw t1, 0x0850(a0) /* mem_sdstat */
+ and t2, t1, t0
+ beq t2, zero, sref_wait_loop
+ nop
+
+ /* Disable SDRAM clocks */
+ li t0, ~0x30000000
+ lw t1, 0x0840(a0) /* mem_sdconfiga */
+ and t1, t0, t1 /* clear CE[1:0] to 00 */
+ sw t1, 0x0840(a0) /* mem_sdconfiga */
+ sync
+#endif
+
+ /* put power supply and processor to sleep */
+ sw zero, 0x0078(t3) /* sys_slppwr */
+ sync
+ sw zero, 0x007c(t3) /* sys_sleep */
+ sync
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
/* This is where we return upon wakeup.
* Reload all of the registers and return.
*/
-1: nop
+resume_from_sleep:
+ nop
+ .set nomacro
+ .set noat
+
lw k0, 0x20(sp)
mtc0 k0, CP0_STATUS
lw k0, 0x1c(sp)
@@ -125,14 +161,6 @@ sdsleep:
lw $5, PT_R5(sp)
lw $6, PT_R6(sp)
lw $7, PT_R7(sp)
- lw $8, PT_R8(sp)
- lw $9, PT_R9(sp)
- lw $10, PT_R10(sp)
- lw $11, PT_R11(sp)
- lw $12, PT_R12(sp)
- lw $13, PT_R13(sp)
- lw $14, PT_R14(sp)
- lw $15, PT_R15(sp)
lw $16, PT_R16(sp)
lw $17, PT_R17(sp)
lw $18, PT_R18(sp)
@@ -141,12 +169,9 @@ sdsleep:
lw $21, PT_R21(sp)
lw $22, PT_R22(sp)
lw $23, PT_R23(sp)
- lw $24, PT_R24(sp)
- lw $25, PT_R25(sp)
lw $26, PT_R26(sp)
lw $27, PT_R27(sp)
lw $28, PT_R28(sp)
- lw $29, PT_R29(sp)
lw $30, PT_R30(sp)
lw $31, PT_R31(sp)
addiu sp, PT_SIZE
--
1.5.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread