1*e2469d82SVarun Wadekar /* 2*e2469d82SVarun Wadekar * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3*e2469d82SVarun Wadekar * 4*e2469d82SVarun Wadekar * SPDX-License-Identifier: BSD-3-Clause 5*e2469d82SVarun Wadekar */ 6*e2469d82SVarun Wadekar 7*e2469d82SVarun Wadekar #include <arch_helpers.h> 8*e2469d82SVarun Wadekar #include <assert.h> 9*e2469d82SVarun Wadekar #include <bpmp.h> 10*e2469d82SVarun Wadekar #include <common/debug.h> 11*e2469d82SVarun Wadekar #include <drivers/delay_timer.h> 12*e2469d82SVarun Wadekar #include <errno.h> 13*e2469d82SVarun Wadekar #include <lib/mmio.h> 14*e2469d82SVarun Wadekar #include <plat/common/platform.h> 15*e2469d82SVarun Wadekar #include <stdbool.h> 16*e2469d82SVarun Wadekar #include <string.h> 17*e2469d82SVarun Wadekar #include <tegra_def.h> 18*e2469d82SVarun Wadekar 19*e2469d82SVarun Wadekar #define BPMP_TIMEOUT 500 /* 500ms */ 20*e2469d82SVarun Wadekar 21*e2469d82SVarun Wadekar static uint32_t channel_base[NR_CHANNELS]; 22*e2469d82SVarun Wadekar static uint32_t bpmp_init_state = BPMP_INIT_PENDING; 23*e2469d82SVarun Wadekar 24*e2469d82SVarun Wadekar static uint32_t channel_field(unsigned int ch) 25*e2469d82SVarun Wadekar { 26*e2469d82SVarun Wadekar return mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET) & CH_MASK(ch); 27*e2469d82SVarun Wadekar } 28*e2469d82SVarun Wadekar 29*e2469d82SVarun Wadekar static bool master_free(unsigned int ch) 30*e2469d82SVarun Wadekar { 31*e2469d82SVarun Wadekar return channel_field(ch) == MA_FREE(ch); 32*e2469d82SVarun Wadekar } 33*e2469d82SVarun Wadekar 34*e2469d82SVarun Wadekar static bool master_acked(unsigned int ch) 35*e2469d82SVarun Wadekar { 36*e2469d82SVarun Wadekar return channel_field(ch) == MA_ACKD(ch); 37*e2469d82SVarun Wadekar } 38*e2469d82SVarun Wadekar 39*e2469d82SVarun Wadekar static void signal_slave(unsigned int ch) 40*e2469d82SVarun Wadekar { 41*e2469d82SVarun Wadekar mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, CH_MASK(ch)); 42*e2469d82SVarun Wadekar } 43*e2469d82SVarun Wadekar 44*e2469d82SVarun Wadekar static void free_master(unsigned int ch) 45*e2469d82SVarun Wadekar { 46*e2469d82SVarun Wadekar mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, 47*e2469d82SVarun Wadekar MA_ACKD(ch) ^ MA_FREE(ch)); 48*e2469d82SVarun Wadekar } 49*e2469d82SVarun Wadekar 50*e2469d82SVarun Wadekar /* should be called with local irqs disabled */ 51*e2469d82SVarun Wadekar int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz, 52*e2469d82SVarun Wadekar void *ib_data, int ib_sz) 53*e2469d82SVarun Wadekar { 54*e2469d82SVarun Wadekar unsigned int ch = (unsigned int)plat_my_core_pos(); 55*e2469d82SVarun Wadekar mb_data_t *p = (mb_data_t *)(uintptr_t)channel_base[ch]; 56*e2469d82SVarun Wadekar int32_t ret = -ETIMEDOUT, timeout = 0; 57*e2469d82SVarun Wadekar 58*e2469d82SVarun Wadekar if (bpmp_init_state == BPMP_INIT_COMPLETE) { 59*e2469d82SVarun Wadekar 60*e2469d82SVarun Wadekar /* loop until BPMP is free */ 61*e2469d82SVarun Wadekar for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) { 62*e2469d82SVarun Wadekar if (master_free(ch) == true) { 63*e2469d82SVarun Wadekar break; 64*e2469d82SVarun Wadekar } 65*e2469d82SVarun Wadekar 66*e2469d82SVarun Wadekar mdelay(1); 67*e2469d82SVarun Wadekar } 68*e2469d82SVarun Wadekar 69*e2469d82SVarun Wadekar if (timeout != BPMP_TIMEOUT) { 70*e2469d82SVarun Wadekar 71*e2469d82SVarun Wadekar /* generate the command struct */ 72*e2469d82SVarun Wadekar p->code = mrq; 73*e2469d82SVarun Wadekar p->flags = DO_ACK; 74*e2469d82SVarun Wadekar (void)memcpy((void *)p->data, ob_data, (size_t)ob_sz); 75*e2469d82SVarun Wadekar 76*e2469d82SVarun Wadekar /* signal command ready to the BPMP */ 77*e2469d82SVarun Wadekar signal_slave(ch); 78*e2469d82SVarun Wadekar mmio_write_32(TEGRA_PRI_ICTLR_BASE + CPU_IEP_FIR_SET, 79*e2469d82SVarun Wadekar (1U << INT_SHR_SEM_OUTBOX_FULL)); 80*e2469d82SVarun Wadekar 81*e2469d82SVarun Wadekar /* loop until the command is executed */ 82*e2469d82SVarun Wadekar for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) { 83*e2469d82SVarun Wadekar if (master_acked(ch) == true) { 84*e2469d82SVarun Wadekar break; 85*e2469d82SVarun Wadekar } 86*e2469d82SVarun Wadekar 87*e2469d82SVarun Wadekar mdelay(1); 88*e2469d82SVarun Wadekar } 89*e2469d82SVarun Wadekar 90*e2469d82SVarun Wadekar if (timeout != BPMP_TIMEOUT) { 91*e2469d82SVarun Wadekar 92*e2469d82SVarun Wadekar /* get the command response */ 93*e2469d82SVarun Wadekar (void)memcpy(ib_data, (const void *)p->data, 94*e2469d82SVarun Wadekar (size_t)ib_sz); 95*e2469d82SVarun Wadekar 96*e2469d82SVarun Wadekar /* return error code */ 97*e2469d82SVarun Wadekar ret = p->code; 98*e2469d82SVarun Wadekar 99*e2469d82SVarun Wadekar /* free this channel */ 100*e2469d82SVarun Wadekar free_master(ch); 101*e2469d82SVarun Wadekar } 102*e2469d82SVarun Wadekar } 103*e2469d82SVarun Wadekar 104*e2469d82SVarun Wadekar } else { 105*e2469d82SVarun Wadekar /* return error code */ 106*e2469d82SVarun Wadekar ret = -EINVAL; 107*e2469d82SVarun Wadekar } 108*e2469d82SVarun Wadekar 109*e2469d82SVarun Wadekar if (timeout == BPMP_TIMEOUT) { 110*e2469d82SVarun Wadekar ERROR("Timed out waiting for bpmp's response\n"); 111*e2469d82SVarun Wadekar } 112*e2469d82SVarun Wadekar 113*e2469d82SVarun Wadekar return ret; 114*e2469d82SVarun Wadekar } 115*e2469d82SVarun Wadekar 116*e2469d82SVarun Wadekar int tegra_bpmp_init(void) 117*e2469d82SVarun Wadekar { 118*e2469d82SVarun Wadekar uint32_t val, base, timeout = BPMP_TIMEOUT; 119*e2469d82SVarun Wadekar unsigned int ch; 120*e2469d82SVarun Wadekar int ret = 0; 121*e2469d82SVarun Wadekar 122*e2469d82SVarun Wadekar if (bpmp_init_state == BPMP_INIT_PENDING) { 123*e2469d82SVarun Wadekar 124*e2469d82SVarun Wadekar /* check if the bpmp processor is alive. */ 125*e2469d82SVarun Wadekar do { 126*e2469d82SVarun Wadekar val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); 127*e2469d82SVarun Wadekar if (val != SIGN_OF_LIFE) { 128*e2469d82SVarun Wadekar mdelay(1); 129*e2469d82SVarun Wadekar timeout--; 130*e2469d82SVarun Wadekar } 131*e2469d82SVarun Wadekar 132*e2469d82SVarun Wadekar } while ((val != SIGN_OF_LIFE) && (timeout > 0U)); 133*e2469d82SVarun Wadekar 134*e2469d82SVarun Wadekar if (val == SIGN_OF_LIFE) { 135*e2469d82SVarun Wadekar 136*e2469d82SVarun Wadekar /* check if clock for the atomics block is enabled */ 137*e2469d82SVarun Wadekar val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V); 138*e2469d82SVarun Wadekar if ((val & CAR_ENABLE_ATOMICS) == 0) { 139*e2469d82SVarun Wadekar ERROR("Clock to the atomics block is disabled\n"); 140*e2469d82SVarun Wadekar } 141*e2469d82SVarun Wadekar 142*e2469d82SVarun Wadekar /* check if the atomics block is out of reset */ 143*e2469d82SVarun Wadekar val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V); 144*e2469d82SVarun Wadekar if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) { 145*e2469d82SVarun Wadekar ERROR("Reset to the atomics block is asserted\n"); 146*e2469d82SVarun Wadekar } 147*e2469d82SVarun Wadekar 148*e2469d82SVarun Wadekar /* base address to get the result from Atomics */ 149*e2469d82SVarun Wadekar base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET; 150*e2469d82SVarun Wadekar 151*e2469d82SVarun Wadekar /* channel area is setup by BPMP before signaling handshake */ 152*e2469d82SVarun Wadekar for (ch = 0; ch < NR_CHANNELS; ch++) { 153*e2469d82SVarun Wadekar 154*e2469d82SVarun Wadekar /* issue command to get the channel base address */ 155*e2469d82SVarun Wadekar mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) | 156*e2469d82SVarun Wadekar ATOMIC_CMD_GET); 157*e2469d82SVarun Wadekar 158*e2469d82SVarun Wadekar /* get the base address for the channel */ 159*e2469d82SVarun Wadekar channel_base[ch] = mmio_read_32(base); 160*e2469d82SVarun Wadekar 161*e2469d82SVarun Wadekar /* increment result register offset */ 162*e2469d82SVarun Wadekar base += 4U; 163*e2469d82SVarun Wadekar } 164*e2469d82SVarun Wadekar 165*e2469d82SVarun Wadekar /* mark state as "initialized" */ 166*e2469d82SVarun Wadekar bpmp_init_state = BPMP_INIT_COMPLETE; 167*e2469d82SVarun Wadekar 168*e2469d82SVarun Wadekar /* the channel values have to be visible across all cpus */ 169*e2469d82SVarun Wadekar flush_dcache_range((uint64_t)channel_base, 170*e2469d82SVarun Wadekar sizeof(channel_base)); 171*e2469d82SVarun Wadekar flush_dcache_range((uint64_t)&bpmp_init_state, 172*e2469d82SVarun Wadekar sizeof(bpmp_init_state)); 173*e2469d82SVarun Wadekar 174*e2469d82SVarun Wadekar INFO("%s: done\n", __func__); 175*e2469d82SVarun Wadekar 176*e2469d82SVarun Wadekar } else { 177*e2469d82SVarun Wadekar ERROR("BPMP not powered on\n"); 178*e2469d82SVarun Wadekar 179*e2469d82SVarun Wadekar /* bpmp is not present in the system */ 180*e2469d82SVarun Wadekar bpmp_init_state = BPMP_NOT_PRESENT; 181*e2469d82SVarun Wadekar 182*e2469d82SVarun Wadekar /* communication timed out */ 183*e2469d82SVarun Wadekar ret = -ETIMEDOUT; 184*e2469d82SVarun Wadekar } 185*e2469d82SVarun Wadekar } 186*e2469d82SVarun Wadekar 187*e2469d82SVarun Wadekar return ret; 188*e2469d82SVarun Wadekar } 189*e2469d82SVarun Wadekar 190*e2469d82SVarun Wadekar void tegra_bpmp_suspend(void) 191*e2469d82SVarun Wadekar { 192*e2469d82SVarun Wadekar /* freeze the interface */ 193*e2469d82SVarun Wadekar if (bpmp_init_state == BPMP_INIT_COMPLETE) { 194*e2469d82SVarun Wadekar bpmp_init_state = BPMP_SUSPEND_ENTRY; 195*e2469d82SVarun Wadekar flush_dcache_range((uint64_t)&bpmp_init_state, 196*e2469d82SVarun Wadekar sizeof(bpmp_init_state)); 197*e2469d82SVarun Wadekar } 198*e2469d82SVarun Wadekar } 199*e2469d82SVarun Wadekar 200*e2469d82SVarun Wadekar void tegra_bpmp_resume(void) 201*e2469d82SVarun Wadekar { 202*e2469d82SVarun Wadekar uint32_t val, timeout = 0; 203*e2469d82SVarun Wadekar 204*e2469d82SVarun Wadekar if (bpmp_init_state == BPMP_SUSPEND_ENTRY) { 205*e2469d82SVarun Wadekar 206*e2469d82SVarun Wadekar /* check if the bpmp processor is alive. */ 207*e2469d82SVarun Wadekar do { 208*e2469d82SVarun Wadekar 209*e2469d82SVarun Wadekar val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); 210*e2469d82SVarun Wadekar if (val != SIGN_OF_LIFE) { 211*e2469d82SVarun Wadekar mdelay(1); 212*e2469d82SVarun Wadekar timeout++; 213*e2469d82SVarun Wadekar } 214*e2469d82SVarun Wadekar 215*e2469d82SVarun Wadekar } while ((val != SIGN_OF_LIFE) && (timeout < BPMP_TIMEOUT)); 216*e2469d82SVarun Wadekar 217*e2469d82SVarun Wadekar if (val == SIGN_OF_LIFE) { 218*e2469d82SVarun Wadekar 219*e2469d82SVarun Wadekar INFO("%s: BPMP took %d ms to resume\n", __func__, timeout); 220*e2469d82SVarun Wadekar 221*e2469d82SVarun Wadekar /* mark state as "initialized" */ 222*e2469d82SVarun Wadekar bpmp_init_state = BPMP_INIT_COMPLETE; 223*e2469d82SVarun Wadekar 224*e2469d82SVarun Wadekar /* state has to be visible across all cpus */ 225*e2469d82SVarun Wadekar flush_dcache_range((uint64_t)&bpmp_init_state, 226*e2469d82SVarun Wadekar sizeof(bpmp_init_state)); 227*e2469d82SVarun Wadekar } else { 228*e2469d82SVarun Wadekar ERROR("BPMP not powered on\n"); 229*e2469d82SVarun Wadekar } 230*e2469d82SVarun Wadekar } 231*e2469d82SVarun Wadekar } 232