[PATCH 2/5] ARM: Add interface for registering and calling firmware-specific operations
Olof Johansson
olof at lixom.net
Sat Sep 22 02:23:22 EDT 2012
On Sat, Sep 22, 2012 at 03:01:56PM +0900, Kyungmin Park wrote:
> On 9/22/12, Olof Johansson <olof at lixom.net> wrote:
> > On Thu, Sep 13, 2012 at 10:13:35AM +0200, Tomasz Figa wrote:
> >> Some boards are running with secure firmware running in TrustZone secure
> >> world, which changes the way some things have to be initialized.
> >>
> >> This patch adds an interface for platforms to specify available firmware
> >> operations and call them.
> >>
> >> A wrapper macro, call_firmware_op(), checks if the operation is provided
> >> and calls it if so, otherwise returns 0.
> >>
> >> By default no operations are provided.
> >>
> >> This is a follow-up on the patch by Kyungmin Park:
> >> [PATCH v5 1/2] ARM: Make a compile firmware conditionally
> >> http://thread.gmane.org/gmane.linux.ports.arm.kernel/183607/focus=183988
> >>
> >> Example of use:
> >>
> >> In code using firmware ops:
> >>
> >> __raw_writel(virt_to_phys(exynos4_secondary_startup),
> >> CPU1_BOOT_REG);
> >>
> >> /* Call Exynos specific smc call */
> >> do_firmware_op(cpu_boot, cpu);
> >>
> >> gic_raise_softirq(cpumask_of(cpu), 1);
> >>
> >> In board-/platform-specific code:
> >>
> >> static int platformX_do_idle(void)
> >> {
> >> /* tell platformX firmware to enter idle */
> >> return 0;
> >> }
> >>
> >> static void platformX_cpu_boot(int i)
> >> {
> >> /* tell platformX firmware to boot CPU i */
> >> }
> >>
> >> static const struct firmware_ops platformX_firmware_ops __initdata = {
> >> .do_idle = exynos_do_idle,
> >> .cpu_boot = exynos_cpu_boot,
> >> /* cpu_boot_reg not available on platformX */
> >> };
> >>
> >> static void __init board_init_early(void)
> >> {
> >> register_firmware_ops(&platformX_firmware_ops);
> >> }
> >>
> >> Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
> >> Signed-off-by: Tomasz Figa <t.figa at samsung.com>
> >> ---
> >> arch/arm/common/Makefile | 2 ++
> >> arch/arm/common/firmware.c | 18 ++++++++++++++++++
> >> arch/arm/include/asm/firmware.h | 30 ++++++++++++++++++++++++++++++
> >> 3 files changed, 50 insertions(+)
> >> create mode 100644 arch/arm/common/firmware.c
> >> create mode 100644 arch/arm/include/asm/firmware.h
> >>
> >> diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
> >> index e8a4e58..55d4182 100644
> >> --- a/arch/arm/common/Makefile
> >> +++ b/arch/arm/common/Makefile
> >> @@ -2,6 +2,8 @@
> >> # Makefile for the linux kernel.
> >> #
> >>
> >> +obj-y += firmware.o
> >> +
> >> obj-$(CONFIG_ARM_GIC) += gic.o
> >> obj-$(CONFIG_ARM_VIC) += vic.o
> >> obj-$(CONFIG_ICST) += icst.o
> >> diff --git a/arch/arm/common/firmware.c b/arch/arm/common/firmware.c
> >> new file mode 100644
> >> index 0000000..27ddccb
> >> --- /dev/null
> >> +++ b/arch/arm/common/firmware.c
> >> @@ -0,0 +1,18 @@
> >> +/*
> >> + * Copyright (C) 2012 Samsung Electronics.
> >> + * Kyungmin Park <kyungmin.park at samsung.com>
> >> + * Tomasz Figa <t.figa at samsung.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + */
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/suspend.h>
> >> +
> >> +#include <asm/firmware.h>
> >> +
> >> +static const struct firmware_ops default_firmware_ops;
> >> +
> >> +const struct firmware_ops *firmware_ops = &default_firmware_ops;
> >> diff --git a/arch/arm/include/asm/firmware.h
> >> b/arch/arm/include/asm/firmware.h
> >> new file mode 100644
> >> index 0000000..ed51b02
> >> --- /dev/null
> >> +++ b/arch/arm/include/asm/firmware.h
> >> @@ -0,0 +1,30 @@
> >> +/*
> >> + * Copyright (C) 2012 Samsung Electronics.
> >> + * Kyungmin Park <kyungmin.park at samsung.com>
> >> + * Tomasz Figa <t.figa at samsung.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + */
> >> +
> >> +#ifndef __ASM_ARM_FIRMWARE_H
> >> +#define __ASM_ARM_FIRMWARE_H
> >> +
> >> +struct firmware_ops {
> >> + int (*do_idle)(void);
> >> + void (*cpu_boot)(int cpu);
> >> + void __iomem *(*cpu_boot_reg)(int cpu);
> >> +};
> >> +
> >> +extern const struct firmware_ops *firmware_ops;
> >> +
> >> +#define call_firmware_op(op, ...) \
> >> + ((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : 0)
> >
> > I think this will cause sparse warnings for call_firmware_op(cpu_boot_reg)
> > if there are no ops defined, since the '0' isn't annotated as __iomem. And
> > you can't annotate it since the other function pointers don't need it.
> >
> > I think you might be better off with stub functions as fallbacks instead of
> > allowing and checking for NULL here.
> do you mean like this?
>
> #Ifdef CONFIG_ARM_FIRMWARE
> #define call_firmware_op(op, ...) ((firmware_ops->op) ?
> firmware_ops->op(__VA_ARGS__) : 0)
> #else
> #define call_firmware_op(op, ...) do { } while (0)
> #endif
>
> No problem to modify it.
To get the types and return values right you still need to do something
like:
#define call_firmware_op(op, ...) (firmware_ops->op(__VA_ARGS))
And then, in firmware.c:
static int default_do_idle(void)
{
return 0;
}
static default_cpu_boot(int cpu)
{
return;
}
static void __iomem *default_cpu_boot_reg(int cpu)
{
return (void __iomem *)0;
}
static const struct firmware_ops default_firmware_ops = {
.do_idle = default_do_idle,
.cpu_boot = default_cpu_boot,
.cpu_boot_reg = default_cpu_boot_reg,
}
const struct firmware_ops *firmware_ops = &default_firmware_ops;
More information about the linux-arm-kernel
mailing list