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