xref: /arm-trusted-firmware/drivers/marvell/gwin.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (C) 2018 Marvell International Ltd.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier:     BSD-3-Clause
5*91f16700Schasinglulu  * https://spdx.org/licenses
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu /* GWIN unit device driver for Marvell AP810 SoC */
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <inttypes.h>
11*91f16700Schasinglulu #include <stdint.h>
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <common/debug.h>
14*91f16700Schasinglulu #include <drivers/marvell/gwin.h>
15*91f16700Schasinglulu #include <lib/mmio.h>
16*91f16700Schasinglulu 
17*91f16700Schasinglulu #include <armada_common.h>
18*91f16700Schasinglulu #include <mvebu.h>
19*91f16700Schasinglulu #include <mvebu_def.h>
20*91f16700Schasinglulu 
21*91f16700Schasinglulu #if LOG_LEVEL >= LOG_LEVEL_INFO
22*91f16700Schasinglulu #define DEBUG_ADDR_MAP
23*91f16700Schasinglulu #endif
24*91f16700Schasinglulu 
25*91f16700Schasinglulu /* common defines */
26*91f16700Schasinglulu #define WIN_ENABLE_BIT			(0x1)
27*91f16700Schasinglulu #define WIN_TARGET_MASK			(0xF)
28*91f16700Schasinglulu #define WIN_TARGET_SHIFT		(0x8)
29*91f16700Schasinglulu #define WIN_TARGET(tgt)			(((tgt) & WIN_TARGET_MASK) \
30*91f16700Schasinglulu 					<< WIN_TARGET_SHIFT)
31*91f16700Schasinglulu 
32*91f16700Schasinglulu /* Bits[43:26] of the physical address are the window base,
33*91f16700Schasinglulu  * which is aligned to 64MB
34*91f16700Schasinglulu  */
35*91f16700Schasinglulu #define ADDRESS_RSHIFT			(26)
36*91f16700Schasinglulu #define ADDRESS_LSHIFT			(10)
37*91f16700Schasinglulu #define GWIN_ALIGNMENT_64M		(0x4000000)
38*91f16700Schasinglulu 
39*91f16700Schasinglulu /* AP registers */
40*91f16700Schasinglulu #define GWIN_CR_OFFSET(ap, win)		(MVEBU_GWIN_BASE(ap) + 0x0 + \
41*91f16700Schasinglulu 						(0x10 * (win)))
42*91f16700Schasinglulu #define GWIN_ALR_OFFSET(ap, win)	(MVEBU_GWIN_BASE(ap) + 0x8 + \
43*91f16700Schasinglulu 						(0x10 * (win)))
44*91f16700Schasinglulu #define GWIN_AHR_OFFSET(ap, win)	(MVEBU_GWIN_BASE(ap) + 0xc + \
45*91f16700Schasinglulu 						(0x10 * (win)))
46*91f16700Schasinglulu 
47*91f16700Schasinglulu #define CCU_GRU_CR_OFFSET(ap)		(MVEBU_CCU_GRU_BASE(ap))
48*91f16700Schasinglulu #define CCR_GRU_CR_GWIN_MBYPASS		(1 << 1)
49*91f16700Schasinglulu 
50*91f16700Schasinglulu static void gwin_check(struct addr_map_win *win)
51*91f16700Schasinglulu {
52*91f16700Schasinglulu 	/* The base is always 64M aligned */
53*91f16700Schasinglulu 	if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) {
54*91f16700Schasinglulu 		win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1);
55*91f16700Schasinglulu 		NOTICE("%s: Align the base address to 0x%" PRIx64 "\n",
56*91f16700Schasinglulu 		       __func__, win->base_addr);
57*91f16700Schasinglulu 	}
58*91f16700Schasinglulu 
59*91f16700Schasinglulu 	/* size parameter validity check */
60*91f16700Schasinglulu 	if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) {
61*91f16700Schasinglulu 		win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M);
62*91f16700Schasinglulu 		NOTICE("%s: Aligning window size to 0x%" PRIx64 "\n",
63*91f16700Schasinglulu 		       __func__, win->win_size);
64*91f16700Schasinglulu 	}
65*91f16700Schasinglulu }
66*91f16700Schasinglulu 
67*91f16700Schasinglulu static void gwin_enable_window(int ap_index, struct addr_map_win *win,
68*91f16700Schasinglulu 			       uint32_t win_num)
69*91f16700Schasinglulu {
70*91f16700Schasinglulu 	uint32_t alr, ahr;
71*91f16700Schasinglulu 	uint64_t end_addr;
72*91f16700Schasinglulu 
73*91f16700Schasinglulu 	if ((win->target_id & WIN_TARGET_MASK) != win->target_id) {
74*91f16700Schasinglulu 		ERROR("target ID = %d, is invalid\n", win->target_id);
75*91f16700Schasinglulu 		return;
76*91f16700Schasinglulu 	}
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 	/* calculate 64bit end-address */
79*91f16700Schasinglulu 	end_addr = (win->base_addr + win->win_size - 1);
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	alr = (uint32_t)((win->base_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
82*91f16700Schasinglulu 	ahr = (uint32_t)((end_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	/* write start address and end address for GWIN */
85*91f16700Schasinglulu 	mmio_write_32(GWIN_ALR_OFFSET(ap_index, win_num), alr);
86*91f16700Schasinglulu 	mmio_write_32(GWIN_AHR_OFFSET(ap_index, win_num), ahr);
87*91f16700Schasinglulu 
88*91f16700Schasinglulu 	/* write the target ID and enable the window */
89*91f16700Schasinglulu 	mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num),
90*91f16700Schasinglulu 		      WIN_TARGET(win->target_id) | WIN_ENABLE_BIT);
91*91f16700Schasinglulu }
92*91f16700Schasinglulu 
93*91f16700Schasinglulu static void gwin_disable_window(int ap_index, uint32_t win_num)
94*91f16700Schasinglulu {
95*91f16700Schasinglulu 	uint32_t win_reg;
96*91f16700Schasinglulu 
97*91f16700Schasinglulu 	win_reg = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
98*91f16700Schasinglulu 	win_reg &= ~WIN_ENABLE_BIT;
99*91f16700Schasinglulu 	mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), win_reg);
100*91f16700Schasinglulu }
101*91f16700Schasinglulu 
102*91f16700Schasinglulu /* Insert/Remove temporary window for using the out-of reset default
103*91f16700Schasinglulu  * CPx base address to access the CP configuration space prior to
104*91f16700Schasinglulu  * the further base address update in accordance with address mapping
105*91f16700Schasinglulu  * design.
106*91f16700Schasinglulu  *
107*91f16700Schasinglulu  * NOTE: Use the same window array for insertion and removal of
108*91f16700Schasinglulu  *       temporary windows.
109*91f16700Schasinglulu  */
110*91f16700Schasinglulu void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
111*91f16700Schasinglulu {
112*91f16700Schasinglulu 	uint32_t win_id;
113*91f16700Schasinglulu 
114*91f16700Schasinglulu 	for (int i = 0; i < size; i++) {
115*91f16700Schasinglulu 		win_id = MVEBU_GWIN_MAX_WINS - i - 1;
116*91f16700Schasinglulu 		gwin_check(win);
117*91f16700Schasinglulu 		gwin_enable_window(ap_index, win, win_id);
118*91f16700Schasinglulu 		win++;
119*91f16700Schasinglulu 	}
120*91f16700Schasinglulu }
121*91f16700Schasinglulu 
122*91f16700Schasinglulu /*
123*91f16700Schasinglulu  * NOTE: Use the same window array for insertion and removal of
124*91f16700Schasinglulu  *       temporary windows.
125*91f16700Schasinglulu  */
126*91f16700Schasinglulu void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
127*91f16700Schasinglulu {
128*91f16700Schasinglulu 	uint32_t win_id;
129*91f16700Schasinglulu 
130*91f16700Schasinglulu 	for (int i = 0; i < size; i++) {
131*91f16700Schasinglulu 		uint64_t base;
132*91f16700Schasinglulu 		uint32_t target;
133*91f16700Schasinglulu 
134*91f16700Schasinglulu 		win_id = MVEBU_GWIN_MAX_WINS - i - 1;
135*91f16700Schasinglulu 
136*91f16700Schasinglulu 		target = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_id));
137*91f16700Schasinglulu 		target >>= WIN_TARGET_SHIFT;
138*91f16700Schasinglulu 		target &= WIN_TARGET_MASK;
139*91f16700Schasinglulu 
140*91f16700Schasinglulu 		base = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_id));
141*91f16700Schasinglulu 		base >>= ADDRESS_LSHIFT;
142*91f16700Schasinglulu 		base <<= ADDRESS_RSHIFT;
143*91f16700Schasinglulu 
144*91f16700Schasinglulu 		if (win->target_id != target) {
145*91f16700Schasinglulu 			ERROR("%s: Trying to remove bad window-%d!\n",
146*91f16700Schasinglulu 			      __func__, win_id);
147*91f16700Schasinglulu 			continue;
148*91f16700Schasinglulu 		}
149*91f16700Schasinglulu 		gwin_disable_window(ap_index, win_id);
150*91f16700Schasinglulu 		win++;
151*91f16700Schasinglulu 	}
152*91f16700Schasinglulu }
153*91f16700Schasinglulu 
154*91f16700Schasinglulu #ifdef DEBUG_ADDR_MAP
155*91f16700Schasinglulu static void dump_gwin(int ap_index)
156*91f16700Schasinglulu {
157*91f16700Schasinglulu 	uint32_t win_num;
158*91f16700Schasinglulu 
159*91f16700Schasinglulu 	/* Dump all GWIN windows */
160*91f16700Schasinglulu 	printf("\tbank  target     start              end\n");
161*91f16700Schasinglulu 	printf("\t----------------------------------------------------\n");
162*91f16700Schasinglulu 	for (win_num = 0; win_num < MVEBU_GWIN_MAX_WINS; win_num++) {
163*91f16700Schasinglulu 		uint32_t cr;
164*91f16700Schasinglulu 		uint64_t alr, ahr;
165*91f16700Schasinglulu 
166*91f16700Schasinglulu 		cr  = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
167*91f16700Schasinglulu 		/* Window enabled */
168*91f16700Schasinglulu 		if (cr & WIN_ENABLE_BIT) {
169*91f16700Schasinglulu 			alr = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_num));
170*91f16700Schasinglulu 			alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
171*91f16700Schasinglulu 			ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num));
172*91f16700Schasinglulu 			ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
173*91f16700Schasinglulu 			printf("\tgwin   %d     0x%016" PRIx64 " 0x%016" PRIx64 "\n",
174*91f16700Schasinglulu 			       (cr >> 8) & 0xF, alr, ahr);
175*91f16700Schasinglulu 		}
176*91f16700Schasinglulu 	}
177*91f16700Schasinglulu }
178*91f16700Schasinglulu #endif
179*91f16700Schasinglulu 
180*91f16700Schasinglulu int init_gwin(int ap_index)
181*91f16700Schasinglulu {
182*91f16700Schasinglulu 	struct addr_map_win *win;
183*91f16700Schasinglulu 	uint32_t win_id;
184*91f16700Schasinglulu 	uint32_t win_count;
185*91f16700Schasinglulu 	uint32_t win_reg;
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	INFO("Initializing GWIN Address decoding\n");
188*91f16700Schasinglulu 
189*91f16700Schasinglulu 	/* Get the array of the windows and its size */
190*91f16700Schasinglulu 	marvell_get_gwin_memory_map(ap_index, &win, &win_count);
191*91f16700Schasinglulu 	if (win_count <= 0) {
192*91f16700Schasinglulu 		INFO("no windows configurations found\n");
193*91f16700Schasinglulu 		return 0;
194*91f16700Schasinglulu 	}
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	if (win_count > MVEBU_GWIN_MAX_WINS) {
197*91f16700Schasinglulu 		ERROR("number of windows is bigger than %d\n",
198*91f16700Schasinglulu 		      MVEBU_GWIN_MAX_WINS);
199*91f16700Schasinglulu 		return 0;
200*91f16700Schasinglulu 	}
201*91f16700Schasinglulu 
202*91f16700Schasinglulu 	/* disable all windows */
203*91f16700Schasinglulu 	for (win_id = 0; win_id < MVEBU_GWIN_MAX_WINS; win_id++)
204*91f16700Schasinglulu 		gwin_disable_window(ap_index, win_id);
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	/* enable relevant windows */
207*91f16700Schasinglulu 	for (win_id = 0; win_id < win_count; win_id++, win++) {
208*91f16700Schasinglulu 		gwin_check(win);
209*91f16700Schasinglulu 		gwin_enable_window(ap_index, win, win_id);
210*91f16700Schasinglulu 	}
211*91f16700Schasinglulu 
212*91f16700Schasinglulu 	/* GWIN Miss feature has not verified, therefore any access towards
213*91f16700Schasinglulu 	 * remote AP should be accompanied with proper configuration to
214*91f16700Schasinglulu 	 * GWIN registers group and therefore the GWIN Miss feature
215*91f16700Schasinglulu 	 * should be set into Bypass mode, need to make sure all GWIN regions
216*91f16700Schasinglulu 	 * are defined correctly that will assure no GWIN miss occurrence
217*91f16700Schasinglulu 	 * JIRA-AURORA2-1630
218*91f16700Schasinglulu 	 */
219*91f16700Schasinglulu 	INFO("Update GWIN miss bypass\n");
220*91f16700Schasinglulu 	win_reg = mmio_read_32(CCU_GRU_CR_OFFSET(ap_index));
221*91f16700Schasinglulu 	win_reg |= CCR_GRU_CR_GWIN_MBYPASS;
222*91f16700Schasinglulu 	mmio_write_32(CCU_GRU_CR_OFFSET(ap_index), win_reg);
223*91f16700Schasinglulu 
224*91f16700Schasinglulu #ifdef DEBUG_ADDR_MAP
225*91f16700Schasinglulu 	dump_gwin(ap_index);
226*91f16700Schasinglulu #endif
227*91f16700Schasinglulu 
228*91f16700Schasinglulu 	INFO("Done GWIN Address decoding Initializing\n");
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	return 0;
231*91f16700Schasinglulu }
232