1*9a40c0fbSSheetal Tigadoli /* 2*9a40c0fbSSheetal Tigadoli * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. 3*9a40c0fbSSheetal Tigadoli * 4*9a40c0fbSSheetal Tigadoli * SPDX-License-Identifier: BSD-3-Clause 5*9a40c0fbSSheetal Tigadoli */ 6*9a40c0fbSSheetal Tigadoli 7*9a40c0fbSSheetal Tigadoli #include <assert.h> 8*9a40c0fbSSheetal Tigadoli 9*9a40c0fbSSheetal Tigadoli #include <arch_helpers.h> 10*9a40c0fbSSheetal Tigadoli #include <drivers/delay_timer.h> 11*9a40c0fbSSheetal Tigadoli #include <lib/bakery_lock.h> 12*9a40c0fbSSheetal Tigadoli 13*9a40c0fbSSheetal Tigadoli #include <brcm_mhu.h> 14*9a40c0fbSSheetal Tigadoli #include <platform_def.h> 15*9a40c0fbSSheetal Tigadoli 16*9a40c0fbSSheetal Tigadoli #include "m0_ipc.h" 17*9a40c0fbSSheetal Tigadoli 18*9a40c0fbSSheetal Tigadoli #define PLAT_MHU_INTR_REG AP_TO_SCP_MAILBOX1 19*9a40c0fbSSheetal Tigadoli 20*9a40c0fbSSheetal Tigadoli /* SCP MHU secure channel registers */ 21*9a40c0fbSSheetal Tigadoli #define SCP_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG11 22*9a40c0fbSSheetal Tigadoli #define SCP_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG11 23*9a40c0fbSSheetal Tigadoli #define SCP_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG11 24*9a40c0fbSSheetal Tigadoli 25*9a40c0fbSSheetal Tigadoli /* CPU MHU secure channel registers */ 26*9a40c0fbSSheetal Tigadoli #define CPU_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG10 27*9a40c0fbSSheetal Tigadoli #define CPU_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG10 28*9a40c0fbSSheetal Tigadoli #define CPU_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG10 29*9a40c0fbSSheetal Tigadoli 30*9a40c0fbSSheetal Tigadoli static DEFINE_BAKERY_LOCK(bcm_lock); 31*9a40c0fbSSheetal Tigadoli 32*9a40c0fbSSheetal Tigadoli /* 33*9a40c0fbSSheetal Tigadoli * Slot 31 is reserved because the MHU hardware uses this register bit to 34*9a40c0fbSSheetal Tigadoli * indicate a non-secure access attempt. The total number of available slots is 35*9a40c0fbSSheetal Tigadoli * therefore 31 [30:0]. 36*9a40c0fbSSheetal Tigadoli */ 37*9a40c0fbSSheetal Tigadoli #define MHU_MAX_SLOT_ID 30 38*9a40c0fbSSheetal Tigadoli 39*9a40c0fbSSheetal Tigadoli void mhu_secure_message_start(unsigned int slot_id) 40*9a40c0fbSSheetal Tigadoli { 41*9a40c0fbSSheetal Tigadoli int iter = 1000000; 42*9a40c0fbSSheetal Tigadoli 43*9a40c0fbSSheetal Tigadoli assert(slot_id <= MHU_MAX_SLOT_ID); 44*9a40c0fbSSheetal Tigadoli 45*9a40c0fbSSheetal Tigadoli bakery_lock_get(&bcm_lock); 46*9a40c0fbSSheetal Tigadoli /* Make sure any previous command has finished */ 47*9a40c0fbSSheetal Tigadoli do { 48*9a40c0fbSSheetal Tigadoli if (!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) & 49*9a40c0fbSSheetal Tigadoli (1 << slot_id))) 50*9a40c0fbSSheetal Tigadoli break; 51*9a40c0fbSSheetal Tigadoli 52*9a40c0fbSSheetal Tigadoli udelay(1); 53*9a40c0fbSSheetal Tigadoli 54*9a40c0fbSSheetal Tigadoli } while (--iter); 55*9a40c0fbSSheetal Tigadoli 56*9a40c0fbSSheetal Tigadoli assert(iter != 0); 57*9a40c0fbSSheetal Tigadoli } 58*9a40c0fbSSheetal Tigadoli 59*9a40c0fbSSheetal Tigadoli void mhu_secure_message_send(unsigned int slot_id) 60*9a40c0fbSSheetal Tigadoli { 61*9a40c0fbSSheetal Tigadoli uint32_t response, iter = 1000000; 62*9a40c0fbSSheetal Tigadoli 63*9a40c0fbSSheetal Tigadoli assert(slot_id <= MHU_MAX_SLOT_ID); 64*9a40c0fbSSheetal Tigadoli assert(!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) & 65*9a40c0fbSSheetal Tigadoli (1 << slot_id))); 66*9a40c0fbSSheetal Tigadoli 67*9a40c0fbSSheetal Tigadoli /* Send command to SCP */ 68*9a40c0fbSSheetal Tigadoli mmio_setbits_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id); 69*9a40c0fbSSheetal Tigadoli mmio_write_32(CRMU_MAIL_BOX0, MCU_IPC_MCU_CMD_SCPI); 70*9a40c0fbSSheetal Tigadoli mmio_write_32(PLAT_BRCM_MHU_BASE + PLAT_MHU_INTR_REG, 0x1); 71*9a40c0fbSSheetal Tigadoli 72*9a40c0fbSSheetal Tigadoli /* Wait until IPC transport acknowledges reception of SCP command */ 73*9a40c0fbSSheetal Tigadoli do { 74*9a40c0fbSSheetal Tigadoli response = mmio_read_32(CRMU_MAIL_BOX0); 75*9a40c0fbSSheetal Tigadoli if ((response & ~MCU_IPC_CMD_REPLY_MASK) == 76*9a40c0fbSSheetal Tigadoli (MCU_IPC_CMD_DONE_MASK | MCU_IPC_MCU_CMD_SCPI)) 77*9a40c0fbSSheetal Tigadoli break; 78*9a40c0fbSSheetal Tigadoli 79*9a40c0fbSSheetal Tigadoli udelay(1); 80*9a40c0fbSSheetal Tigadoli 81*9a40c0fbSSheetal Tigadoli } while (--iter); 82*9a40c0fbSSheetal Tigadoli 83*9a40c0fbSSheetal Tigadoli assert(iter != 0); 84*9a40c0fbSSheetal Tigadoli } 85*9a40c0fbSSheetal Tigadoli 86*9a40c0fbSSheetal Tigadoli uint32_t mhu_secure_message_wait(void) 87*9a40c0fbSSheetal Tigadoli { 88*9a40c0fbSSheetal Tigadoli /* Wait for response from SCP */ 89*9a40c0fbSSheetal Tigadoli uint32_t response, iter = 1000000; 90*9a40c0fbSSheetal Tigadoli 91*9a40c0fbSSheetal Tigadoli do { 92*9a40c0fbSSheetal Tigadoli response = mmio_read_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT); 93*9a40c0fbSSheetal Tigadoli if (!response) 94*9a40c0fbSSheetal Tigadoli break; 95*9a40c0fbSSheetal Tigadoli 96*9a40c0fbSSheetal Tigadoli udelay(1); 97*9a40c0fbSSheetal Tigadoli } while (--iter); 98*9a40c0fbSSheetal Tigadoli assert(iter != 0); 99*9a40c0fbSSheetal Tigadoli 100*9a40c0fbSSheetal Tigadoli return response; 101*9a40c0fbSSheetal Tigadoli } 102*9a40c0fbSSheetal Tigadoli 103*9a40c0fbSSheetal Tigadoli void mhu_secure_message_end(unsigned int slot_id) 104*9a40c0fbSSheetal Tigadoli { 105*9a40c0fbSSheetal Tigadoli assert(slot_id <= MHU_MAX_SLOT_ID); 106*9a40c0fbSSheetal Tigadoli 107*9a40c0fbSSheetal Tigadoli /* 108*9a40c0fbSSheetal Tigadoli * Clear any response we got by writing one in the relevant slot bit to 109*9a40c0fbSSheetal Tigadoli * the CLEAR register 110*9a40c0fbSSheetal Tigadoli */ 111*9a40c0fbSSheetal Tigadoli mmio_clrbits_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id); 112*9a40c0fbSSheetal Tigadoli bakery_lock_release(&bcm_lock); 113*9a40c0fbSSheetal Tigadoli } 114*9a40c0fbSSheetal Tigadoli 115*9a40c0fbSSheetal Tigadoli void mhu_secure_init(void) 116*9a40c0fbSSheetal Tigadoli { 117*9a40c0fbSSheetal Tigadoli bakery_lock_init(&bcm_lock); 118*9a40c0fbSSheetal Tigadoli 119*9a40c0fbSSheetal Tigadoli /* 120*9a40c0fbSSheetal Tigadoli * The STAT register resets to zero. Ensure it is in the expected state, 121*9a40c0fbSSheetal Tigadoli * as a stale or garbage value would make us think it's a message we've 122*9a40c0fbSSheetal Tigadoli * already sent. 123*9a40c0fbSSheetal Tigadoli */ 124*9a40c0fbSSheetal Tigadoli mmio_write_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT, 0); 125*9a40c0fbSSheetal Tigadoli mmio_write_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT, 0); 126*9a40c0fbSSheetal Tigadoli } 127*9a40c0fbSSheetal Tigadoli 128*9a40c0fbSSheetal Tigadoli void plat_brcm_pwrc_setup(void) 129*9a40c0fbSSheetal Tigadoli { 130*9a40c0fbSSheetal Tigadoli mhu_secure_init(); 131*9a40c0fbSSheetal Tigadoli } 132