1*4882a593Smuzhiyun========================================================================== 2*4882a593SmuzhiyunInterface for registering and calling firmware-specific operations for ARM 3*4882a593Smuzhiyun========================================================================== 4*4882a593Smuzhiyun 5*4882a593SmuzhiyunWritten by Tomasz Figa <t.figa@samsung.com> 6*4882a593Smuzhiyun 7*4882a593SmuzhiyunSome boards are running with secure firmware running in TrustZone secure 8*4882a593Smuzhiyunworld, which changes the way some things have to be initialized. This makes 9*4882a593Smuzhiyuna need to provide an interface for such platforms to specify available firmware 10*4882a593Smuzhiyunoperations and call them when needed. 11*4882a593Smuzhiyun 12*4882a593SmuzhiyunFirmware operations can be specified by filling in a struct firmware_ops 13*4882a593Smuzhiyunwith appropriate callbacks and then registering it with register_firmware_ops() 14*4882a593Smuzhiyunfunction:: 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun void register_firmware_ops(const struct firmware_ops *ops) 17*4882a593Smuzhiyun 18*4882a593SmuzhiyunThe ops pointer must be non-NULL. More information about struct firmware_ops 19*4882a593Smuzhiyunand its members can be found in arch/arm/include/asm/firmware.h header. 20*4882a593Smuzhiyun 21*4882a593SmuzhiyunThere is a default, empty set of operations provided, so there is no need to 22*4882a593Smuzhiyunset anything if platform does not require firmware operations. 23*4882a593Smuzhiyun 24*4882a593SmuzhiyunTo call a firmware operation, a helper macro is provided:: 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun #define call_firmware_op(op, ...) \ 27*4882a593Smuzhiyun ((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS)) 28*4882a593Smuzhiyun 29*4882a593Smuzhiyunthe macro checks if the operation is provided and calls it or otherwise returns 30*4882a593Smuzhiyun-ENOSYS to signal that given operation is not available (for example, to allow 31*4882a593Smuzhiyunfallback to legacy operation). 32*4882a593Smuzhiyun 33*4882a593SmuzhiyunExample of registering firmware operations:: 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun /* board file */ 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun static int platformX_do_idle(void) 38*4882a593Smuzhiyun { 39*4882a593Smuzhiyun /* tell platformX firmware to enter idle */ 40*4882a593Smuzhiyun return 0; 41*4882a593Smuzhiyun } 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun static int platformX_cpu_boot(int i) 44*4882a593Smuzhiyun { 45*4882a593Smuzhiyun /* tell platformX firmware to boot CPU i */ 46*4882a593Smuzhiyun return 0; 47*4882a593Smuzhiyun } 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun static const struct firmware_ops platformX_firmware_ops = { 50*4882a593Smuzhiyun .do_idle = exynos_do_idle, 51*4882a593Smuzhiyun .cpu_boot = exynos_cpu_boot, 52*4882a593Smuzhiyun /* other operations not available on platformX */ 53*4882a593Smuzhiyun }; 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun /* init_early callback of machine descriptor */ 56*4882a593Smuzhiyun static void __init board_init_early(void) 57*4882a593Smuzhiyun { 58*4882a593Smuzhiyun register_firmware_ops(&platformX_firmware_ops); 59*4882a593Smuzhiyun } 60*4882a593Smuzhiyun 61*4882a593SmuzhiyunExample of using a firmware operation:: 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun /* some platform code, e.g. SMP initialization */ 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun __raw_writel(__pa_symbol(exynos4_secondary_startup), 66*4882a593Smuzhiyun CPU1_BOOT_REG); 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun /* Call Exynos specific smc call */ 69*4882a593Smuzhiyun if (call_firmware_op(cpu_boot, cpu) == -ENOSYS) 70*4882a593Smuzhiyun cpu_boot_legacy(...); /* Try legacy way */ 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun gic_raise_softirq(cpumask_of(cpu), 1); 73