Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1faef96 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'secure-exynos-for-v3.10' of...

Merge tag 'secure-exynos-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/firmware

From Kukjin Kim <kgene.kim@samsung.com>:

add support secure firmware for exynos

* tag 'secure-exynos-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung

:
  ARM: EXYNOS: Add secure firmware support to secondary CPU bring-up
  ARM: EXYNOS: Add IO mapping for non-secure SYSRAM.
  ARM: EXYNOS: Add support for Exynos secure firmware
  ARM: EXYNOS: Add support for secure monitor calls
  ARM: Add interface for registering and calling firmware-specific operations

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents cb63c029 beddf63f
Loading
Loading
Loading
Loading
+88 −0
Original line number Diff line number Diff line
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);
+10 −0
Original line number Diff line number Diff line
@@ -6,3 +6,13 @@ Required root node properties:
    - compatible = should be one or more of the following.
        (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board.
        (b) "samsung,exynos4210"  - for boards based on Exynos4210 SoC.

Optional:
    - firmware node, specifying presence and type of secure firmware:
        - compatible: only "samsung,secure-firmware" is currently supported
        - reg: address of non-secure SYSRAM used for communication with firmware

	firmware@0203F000 {
		compatible = "samsung,secure-firmware";
		reg = <0x0203F000 0x1000>;
	};
+2 −0
Original line number Diff line number Diff line
@@ -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
+18 −0
Original line number Diff line number Diff line
/*
 * 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 −0
Original line number Diff line number Diff line
/*
 * 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
Loading