From patchwork Thu Nov 22 15:51:14 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tomasz Figa X-Patchwork-Id: 1783921 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id BB18DDF24C for ; Thu, 22 Nov 2012 15:54:48 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TbZ47-0001Qd-Jc; Thu, 22 Nov 2012 15:51:47 +0000 Received: from mailout3.samsung.com ([203.254.224.33]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TbZ3u-0001N9-GU for linux-arm-kernel@lists.infradead.org; Thu, 22 Nov 2012 15:51:37 +0000 MIME-version: 1.0 Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MDW00HQTC1SOCT0@mailout3.samsung.com> for linux-arm-kernel@lists.infradead.org; Fri, 23 Nov 2012 00:51:33 +0900 (KST) X-AuditID: cbfee61b-b7f616d00000319b-12-50ae4a05b6d9 Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 8C.F6.12699.50A4EA05; Fri, 23 Nov 2012 00:51:33 +0900 (KST) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MDW0039YC1LP780@mmp2.samsung.com> for linux-arm-kernel@lists.infradead.org; Fri, 23 Nov 2012 00:51:33 +0900 (KST) From: Tomasz Figa To: linux-samsung-soc@vger.kernel.org Subject: [PATCH v4 1/5] ARM: Add interface for registering and calling firmware-specific operations Date: Thu, 22 Nov 2012 16:51:14 +0100 Message-id: <1353599478-24617-2-git-send-email-t.figa@samsung.com> X-Mailer: git-send-email 1.7.10 In-reply-to: <1353599478-24617-1-git-send-email-t.figa@samsung.com> References: <1353599478-24617-1-git-send-email-t.figa@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrBLMWRmVeSWpSXmKPExsVy+t9jQV1Wr3UBBrMvyltsenyN1YHRY/OS +gDGKC6blNSczLLUIn27BK6M/f1cBe+tKiY/2MbWwPhAv4uRk0NCwETi1oenTBC2mMSFe+vZ uhi5OIQEpjNK3H2/nw0kwSsgKPFj8j2WLkYODmYBeYkjl7JBwswC6hKT5i1ihqjfzCSxaPoj ZpAEm4CaxOeGR2C9IgKqEp/bFrCDFDEL3GKUOHzzLyNIQlggVeLR9LUsIDYLUNGvLw+ZIJY5 SXSsmw91kbzE0/t9YIM4BZwlZnV/ZgexhYBqFu7/wzyBUWAWkvtmIdw3C8l9CxiZVzGKphYk FxQnpeca6RUn5haX5qXrJefnbmIEh98z6R2MqxosDjEKcDAq8fBmGKwNEGJNLCuuzD3EKMHB rCTCm6O/LkCINyWxsiq1KD++qDQntfgQozQHi5I4b7NHSoCQQHpiSWp2ampBahFMlomDU6qB cckEbS/P0y45To3bHt1nF6t9pq0ndElqgVG26I6TWl9mMexpd2le7qv5+c0v042P3I+wrN62 8e1t33fn1NZN2rF3vWDMqgPnrCYU3d5+x8TkGJOlrUKe2+eHN9q5G/Jf7uEqXhozOeziNOZf 6eHrO5ZWRsy4evbJUX+lJKWn65UfTYw/5ZM63UKJpTgj0VCLuag4EQAl8lNjOwIAAA== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121122_105135_209274_7ACF5C7D X-CRM114-Status: GOOD ( 20.01 ) X-Spam-Score: -7.6 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [203.254.224.33 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: kgene.kim@samsung.com, linux@arm.linux.org.uk, arnd@arndb.de, t.figa@samsung.com, tomasz.figa@gmail.com, kyungmin.park@samsung.com, olof@lixom.net, linux-arm-kernel@lists.infradead.org, m.szyprowski@samsung.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 -ENOSYS to allow fallback to legacy operation.. By default no operations are provided. Example of use: In code using firmware ops: __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); In board-/platform-specific code: 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 */ }; static void __init board_init_early(void) {         register_firmware_ops(&platformX_firmware_ops); } Signed-off-by: Kyungmin Park Signed-off-by: Tomasz Figa --- Documentation/arm/firmware.txt | 88 +++++++++++++++++++++++++++++++++++++++++ arch/arm/common/Makefile | 2 + arch/arm/common/firmware.c | 18 +++++++++ arch/arm/include/asm/firmware.h | 66 +++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 Documentation/arm/firmware.txt create mode 100644 arch/arm/common/firmware.c create mode 100644 arch/arm/include/asm/firmware.h diff --git a/Documentation/arm/firmware.txt b/Documentation/arm/firmware.txt new file mode 100644 index 0000000..c2e468f --- /dev/null +++ b/Documentation/arm/firmware.txt @@ -0,0 +1,88 @@ +Interface for registering and calling firmware-specific operations for ARM. +---- +Written by Tomasz Figa + +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); 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 + * Tomasz Figa + * + * 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 +#include + +#include + +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..1563130 --- /dev/null +++ b/arch/arm/include/asm/firmware.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 Samsung Electronics. + * Kyungmin Park + * Tomasz Figa + * + * 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 + +/* + * 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