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