Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 372659
b: refs/heads/master
c: 7366b92
h: refs/heads/master
i:
  372657: eae5c59
  372655: 1b18a56
v: v3
  • Loading branch information
Tomasz Figa authored and Kukjin Kim committed Apr 8, 2013
1 parent e625f21 commit fcdeda0
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cb63c0290c3914a0f1ef6e2ff5bf1a1724097d80
refs/heads/master: 7366b92a77fc00357294819bb495896d7482f30c
88 changes: 88 additions & 0 deletions trunk/Documentation/arm/firmware.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
Interface for registering and calling firmware-specific operations for ARM.
----
Written by Tomasz Figa <t.figa@samsung.com>

Some boards are running with secure firmware running in TrustZone secure
world, which changes the way some things have to be initialized. This makes
a need to provide an interface for such platforms to specify available firmware
operations and call them when needed.

Firmware operations can be specified using struct firmware_ops

struct firmware_ops {
/*
* Enters CPU idle mode
*/
int (*do_idle)(void);
/*
* Sets boot address of specified physical CPU
*/
int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr);
/*
* Boots specified physical CPU
*/
int (*cpu_boot)(int cpu);
/*
* Initializes L2 cache
*/
int (*l2x0_init)(void);
};

and then registered with register_firmware_ops function

void register_firmware_ops(const struct firmware_ops *ops)

the ops pointer must be non-NULL.

There is a default, empty set of operations provided, so there is no need to
set anything if platform does not require firmware operations.

To call a firmware operation, a helper macro is provided

#define call_firmware_op(op, ...) \
((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))

the macro checks if the operation is provided and calls it or otherwise returns
-ENOSYS to signal that given operation is not available (for example, to allow
fallback to legacy operation).

Example of registering firmware operations:

/* board file */

static int platformX_do_idle(void)
{
/* tell platformX firmware to enter idle */
return 0;
}

static int platformX_cpu_boot(int i)
{
/* tell platformX firmware to boot CPU i */
return 0;
}

static const struct firmware_ops platformX_firmware_ops = {
.do_idle = exynos_do_idle,
.cpu_boot = exynos_cpu_boot,
/* other operations not available on platformX */
};

/* init_early callback of machine descriptor */
static void __init board_init_early(void)
{
register_firmware_ops(&platformX_firmware_ops);
}

Example of using a firmware operation:

/* some platform code, e.g. SMP initialization */

__raw_writel(virt_to_phys(exynos4_secondary_startup),
CPU1_BOOT_REG);

/* Call Exynos specific smc call */
if (call_firmware_op(cpu_boot, cpu) == -ENOSYS)
cpu_boot_legacy(...); /* Try legacy way */

gic_raise_softirq(cpumask_of(cpu), 1);
2 changes: 2 additions & 0 deletions trunk/arch/arm/common/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Makefile for the linux kernel.
#

obj-y += firmware.o

obj-$(CONFIG_ICST) += icst.o
obj-$(CONFIG_SA1111) += sa1111.o
obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o
Expand Down
18 changes: 18 additions & 0 deletions trunk/arch/arm/common/firmware.c
Original file line number Diff line number Diff line change
@@ -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;
66 changes: 66 additions & 0 deletions trunk/arch/arm/include/asm/firmware.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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

#include <linux/bug.h>

/*
* struct firmware_ops
*
* A structure to specify available firmware operations.
*
* A filled up structure can be registered with register_firmware_ops().
*/
struct firmware_ops {
/*
* Enters CPU idle mode
*/
int (*do_idle)(void);
/*
* Sets boot address of specified physical CPU
*/
int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr);
/*
* Boots specified physical CPU
*/
int (*cpu_boot)(int cpu);
/*
* Initializes L2 cache
*/
int (*l2x0_init)(void);
};

/* Global pointer for current firmware_ops structure, can't be NULL. */
extern const struct firmware_ops *firmware_ops;

/*
* call_firmware_op(op, ...)
*
* Checks if firmware operation is present and calls it,
* otherwise returns -ENOSYS
*/
#define call_firmware_op(op, ...) \
((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))

/*
* register_firmware_ops(ops)
*
* A function to register platform firmware_ops struct.
*/
static inline void register_firmware_ops(const struct firmware_ops *ops)
{
BUG_ON(!ops);

firmware_ops = ops;
}

#endif

0 comments on commit fcdeda0

Please sign in to comment.