Patchwork [2/5] ARM: Add interface for registering and calling firmware-specific operations

login
register
mail settings
Submitter Tomasz Figa
Date Sept. 13, 2012, 8:13 a.m.
Message ID <1347524018-19301-3-git-send-email-t.figa@samsung.com>
Download mbox | patch
Permalink /patch/183548/
State New
Headers show

Comments

Tomasz Figa - Sept. 13, 2012, 8:13 a.m.
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@samsung.com>
Signed-off-by: Tomasz Figa <t.figa@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
Tomasz Figa - Sept. 13, 2012, 8:25 a.m.
On Thursday 13 of September 2012 10:13:35 Tomasz Figa wrote:
> 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);

Typo, s/do_/call_/ .

Best regards,
Olof Johansson - Sept. 22, 2012, 5:50 a.m.
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@samsung.com>
> Signed-off-by: Tomasz Figa <t.figa@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@samsung.com>
> + * Tomasz Figa <t.figa@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@samsung.com>
> + * Tomasz Figa <t.figa@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.


-Olof
Kyungmin Park - Sept. 22, 2012, 6:01 a.m.
On 9/22/12, Olof Johansson <olof@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@samsung.com>
>> Signed-off-by: Tomasz Figa <t.figa@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@samsung.com>
>> + * Tomasz Figa <t.figa@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@samsung.com>
>> + * Tomasz Figa <t.figa@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.

Thank you,
Kyungmin Park
>
>
> -Olof
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc"
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Olof Johansson - Sept. 22, 2012, 6:23 a.m.
On Sat, Sep 22, 2012 at 03:01:56PM +0900, Kyungmin Park wrote:
> On 9/22/12, Olof Johansson <olof@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@samsung.com>
> >> Signed-off-by: Tomasz Figa <t.figa@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@samsung.com>
> >> + * Tomasz Figa <t.figa@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@samsung.com>
> >> + * Tomasz Figa <t.figa@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;
Tomasz Figa - Sept. 22, 2012, 1:17 p.m.
Hi Olof, Kyungmin,

On Friday 21 of September 2012 23:23:22 Olof Johansson wrote:
> On Sat, Sep 22, 2012 at 03:01:56PM +0900, Kyungmin Park wrote:
> > On 9/22/12, Olof Johansson <olof@lixom.net> wrote:
> > > On Thu, Sep 13, 2012 at 10:13:35AM +0200, Tomasz Figa wrote:
> > >> +#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,
> }

Thanks for pointing this out. I will address it in next version of the 
series.

Also it might be useful to be able to check if an operation was provided, 
so maybe an unimplemented operation should return an error value (which one 
would be the most appropriate? -ENOSYS?)? What do you think?

Best regards,
Tomasz Figa
Russell King - ARM Linux - Sept. 22, 2012, 1:22 p.m.
On Fri, Sep 21, 2012 at 11:23:22PM -0700, Olof Johansson wrote:
> static void __iomem *default_cpu_boot_reg(int cpu)
> {
> 	return (void __iomem *)0;
> }

NULL is perfectly acceptable here.

Patch

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@samsung.com>
+ * Tomasz Figa <t.figa@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@samsung.com>
+ * Tomasz Figa <t.figa@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)
+
+static inline void register_firmware_ops(const struct firmware_ops *ops)
+{
+	firmware_ops = ops;
+}
+
+#endif