[RFC PATCH 2/2] ARM: CSR: add PM sleep entry for SiRFprimaII
Arnd Bergmann
arnd at arndb.de
Fri Aug 12 09:54:11 EDT 2011
On Friday 05 August 2011, Barry Song wrote:
> From: Rongjun Ying <rongjun.ying at csr.com>
>
> Signed-off-by: Rongjun Ying <rongjun.ying at csr.com>
> Signed-off-by: Barry Song <baohua.song at csr.com>
Hi Barry and Rongjun,
My impression of this code is that you just add hooks into
a number of places, while this should really be a proper device
driver.
> diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
> index 83e5d21..894e361 100644
> --- a/arch/arm/mach-prima2/common.h
> +++ b/arch/arm/mach-prima2/common.h
> @@ -16,6 +16,7 @@ extern struct sys_timer sirfsoc_timer;
>
> extern void __init sirfsoc_of_irq_init(void);
> extern void __init sirfsoc_of_clk_init(void);
> +extern void sirfsoc_l2x_init(void);
>
> #ifndef CONFIG_DEBUG_LL
> static inline void sirfsoc_map_lluart(void) {}
You now call the sirfsoc_l2x_init function from two different places,
which is very confusing. Better make sure that the idle code is
only inialized after all the other subsystems it relies on have been
activated.
> diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c
> index 9cda205..adc9840 100644
> --- a/arch/arm/mach-prima2/l2x0.c
> +++ b/arch/arm/mach-prima2/l2x0.c
> @@ -18,25 +18,14 @@
> #define L2X0_ADDR_FILTERING_START 0xC00
> #define L2X0_ADDR_FILTERING_END 0xC04
>
> +void __iomem *sirfsoc_l2x_base;
> +
> static struct of_device_id l2x_ids[] = {
> { .compatible = "arm,pl310-cache" },
> };
Exporting the base address registers from one driver into another
is a layering violation, don't do that. There are global functions
that are used for managing the cache, so you should be calling those,
or extend them to do what you need if necessary.
> diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c
> new file mode 100644
> index 0000000..bae7241
> --- /dev/null
> +++ b/arch/arm/mach-prima2/pm.c
> @@ -0,0 +1,139 @@
> +/*
> + * power management entry for CSR SiRFprimaII
> + *
> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2 or later.
> + */
> +
> +#include <linux/suspend.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +#include <linux/rtc/sirfsoc_rtciobrg.h>
> +
> +#include "common.h"
> +#include "pm.h"
> +
> +static u32 sirfsoc_pwrc_base;
> +void __iomem *sirfsoc_memc_base;
> +
> +static void sirfsoc_set_wakeup_source(void)
> +{
> + u32 pwr_trigger_en_reg;
> + pwr_trigger_en_reg = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base +
> + SIRFSOC_PWRC_TRIGGER_EN);
> +#define X_ON_KEY_B (1 << 0)
> + sirfsoc_rtc_iobrg_writel(pwr_trigger_en_reg | X_ON_KEY_B,
> + sirfsoc_pwrc_base + SIRFSOC_PWRC_TRIGGER_EN);
> +}
> +
> +static void sirfsoc_set_sleep_mode(u32 mode)
> +{
> + u32 sleep_mode = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base +
> + SIRFSOC_PWRC_PDN_CTRL);
> + sleep_mode &= ~(SIRFSOC_SLEEP_MODE_MASK << 1);
> + sleep_mode |= ((mode << 1));
> + sirfsoc_rtc_iobrg_writel(sleep_mode, sirfsoc_pwrc_base +
> + SIRFSOC_PWRC_PDN_CTRL);
> +}
This again looks like a bad abstraction, and it gets the locking wrong,
since you need a spinlock around both the read and write of the register
to make the update atomic.
These functions therefore belong into the rtc_iobrg driver.
> +static struct of_device_id pwrc_ids[] = {
> + { .compatible = "sirf,prima2-pwrc" },
> +};
> +
> +static void __init sirfsoc_of_pwrc_init(void)
> +{
> + struct device_node *np;
> + const __be32 *addrp;
> +
> + np = of_find_matching_node(NULL, pwrc_ids);
> + if (!np)
> + panic("unable to find compatible pwrc node in dtb\n");
Don't use of_find_matching_node to look for stuff that is really more
a device that you want to talk to. Instead, register a platform
driver with that match_table and load a proper device driver for
it.
> +
> + addrp = of_get_property(np, "reg", NULL);
> + if (!addrp)
> + panic("unable to find base address of pwrc node in dtb\n");
> +
> + sirfsoc_pwrc_base = be32_to_cpup(addrp);
> +
> + of_node_put(np);
> +}
Why do you store the physical base address here, instead doing an of_iomap?
> +static struct of_device_id memc_ids[] = {
> + { .compatible = "sirf,prima2-memc" },
> +};
>
> +static void __init sirfsoc_of_memc_map(void)
> +{
> + struct device_node *np;
> +
> + np = of_find_matching_node(NULL, memc_ids);
> + if (!np)
> + panic("unable to find compatible memc node in dtb\n");
> +
> + sirfsoc_memc_base = of_iomap(np, 0);
> + if (!np)
> + panic("unable to map compatible memc node in dtb\n");
> +
> + of_node_put(np);
> +}
Same as for the other one, I think this should be another device
driver.
> +#include <linux/linkage.h>
> +#include <asm/ptrace.h>
> +#include <asm/assembler.h>
> +#include <asm/hardware/cache-l2x0.h>
> +
> +#include "pm.h"
> +
> +#define DENALI_CTL_22_OFF 0x58
> +#define DENALI_CTL_112_OFF 0x1c0
> +
> +ENTRY(sirfsoc_get_wakeup_pointer)
> + stmfd sp!, {lr} @ save registers on stack
> + adr r0, sirfsoc_wakeup
> + ldmfd sp!, {pc} @ restore regs and return
> +
> +ENTRY(sirfsoc_sleep)
> +sirfsoc_sleep:
> + stmdb sp!, {r0-r12, lr} @ Push SVC state onto our stack
> +
> + mrc p15, 0, r2, c1, c0, 1 @ cp15 c1 auxiliary Control register
> + mrc p15, 0, r3, c1, c0, 2 @ cp15 c1 coprocessor access control register
> + mrc p15, 0, r4, c2, c0, 0 @ cp15 c2_r0 translation table base resigter 0
> + mrc p15, 0, r5, c2, c0, 1 @ cp15 c2_r1 translation table base resigter 1
> +
> + mrc p15, 0, r6, c2, c0, 2 @ cp15 c2_r2 translation table base control resigter
> +
> + mrc p15, 0, r7, c3, c0, 0 @ load r2 with domain access control.
> + mrc p15, 0, r8, c1, c0, 0 @ MMU Control
> + mrc p15, 0, r9, c10,c2, 0 @ cp15 PRRR register
> + mrc p15, 0, r10, c10,c2, 1 @ cp15 NMRR register
> + mov r11, sp
> + ldr r0, =save_context
> + add r0, r0, #124
> + stmdb r0!, {r2-r11} @ Save CP15 and the SP to stack
It's not really clear why this code needs to be assembly. Would it be
possible to write the same in C, with just a few inline assembly statements?
Arnd
More information about the linux-arm-kernel
mailing list