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