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