xref: /rk3399_ARM-atf/plat/nvidia/tegra/drivers/bpmp/bpmp.c (revision 01096cac3a052487f5efc1a68b2a4b989e4d9797)
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 
channel_field(unsigned int ch)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 
master_free(unsigned int ch)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 
master_acked(unsigned int ch)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 
signal_slave(unsigned int ch)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 
free_master(unsigned int ch)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 */
tegra_bpmp_send_receive_atomic(int mrq,const void * ob_data,int ob_sz,void * ib_data,int ib_sz)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 
tegra_bpmp_init(void)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 
tegra_bpmp_suspend(void)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 
tegra_bpmp_resume(void)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