xref: /arm-trusted-firmware/plat/nvidia/tegra/drivers/bpmp/bpmp.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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