1 /*
2 * Utility routines for configuring different memories in Broadcom chips.
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions
16 * of the license of that module. An independent module is a module which is
17 * not derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: $
28 */
29
30 #include <typedefs.h>
31 #include <sbchipc.h>
32 #include <hndsoc.h>
33 #include <bcmdevs.h>
34 #include <osl.h>
35 #include <sbgci.h>
36 #include <siutils.h>
37 #include <bcmutils.h>
38 #include <hndmem.h>
39
40 #define IS_MEMTYPE_VALID(mem) ((mem >= MEM_SOCRAM) && (mem < MEM_MAX))
41 #define IS_MEMCONFIG_VALID(cfg) \
42 ((cfg >= PDA_CONFIG_CLEAR) && (cfg < PDA_CONFIG_MAX))
43
44 /* Returns the number of banks in a given memory */
hndmem_num_banks(si_t * sih,int mem)45 int hndmem_num_banks(si_t *sih, int mem)
46 {
47 uint32 savecore, mem_info;
48 int num_banks = 0;
49 gciregs_t *gciregs;
50 osl_t *osh = si_osh(sih);
51
52 if (!IS_MEMTYPE_VALID(mem)) {
53 goto exit;
54 }
55
56 savecore = si_coreidx(sih);
57
58 /* Check whether SOCRAM core is present or not. If not, bail out */
59 /* In future we need to add code for TCM based chips as well */
60 if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
61 goto exit;
62 }
63
64 if (sih->gcirev >= 0x9) {
65 gciregs = si_setcore(sih, GCI_CORE_ID, 0);
66
67 mem_info = R_REG(osh, &gciregs->wlan_mem_info);
68
69 switch (mem) {
70 case MEM_SOCRAM:
71 num_banks =
72 (mem_info & WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_MASK) >>
73 WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_SHIFT;
74 break;
75 case MEM_BM:
76 num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACBM_MASK) >>
77 WLAN_MEM_INFO_REG_NUMD11MACBM_SHIFT;
78 break;
79 case MEM_UCM:
80 num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACUCM_MASK) >>
81 WLAN_MEM_INFO_REG_NUMD11MACUCM_SHIFT;
82 break;
83 case MEM_SHM:
84 num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACSHM_MASK) >>
85 WLAN_MEM_INFO_REG_NUMD11MACSHM_SHIFT;
86 break;
87 default:
88 ASSERT(0);
89 break;
90 }
91 } else {
92 /* Figure out bank information using SOCRAM registers */
93 }
94
95 si_setcoreidx(sih, savecore);
96 exit:
97 return num_banks;
98 }
99
100 /* Returns the size of a give bank in a given memory */
hndmem_bank_size(si_t * sih,hndmem_type_t mem,int bank_num)101 int hndmem_bank_size(si_t *sih, hndmem_type_t mem, int bank_num)
102 {
103 uint32 savecore, bank_info, reg_data;
104 int bank_sz = 0;
105 gciregs_t *gciregs;
106 osl_t *osh = si_osh(sih);
107
108 if (!IS_MEMTYPE_VALID(mem)) {
109 goto exit;
110 }
111
112 savecore = si_coreidx(sih);
113
114 /* Check whether SOCRAM core is present or not. If not, bail out */
115 /* In future we need to add code for TCM based chips as well */
116 if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
117 goto exit;
118 }
119
120 if (sih->gcirev >= 0x9) {
121 gciregs = si_setcore(sih, GCI_CORE_ID, 0);
122
123 reg_data = ((mem & GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK)
124 << GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) |
125 ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK)
126 << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT);
127 W_REG(osh, &gciregs->gci_indirect_addr, reg_data);
128
129 bank_info = R_REG(osh, &gciregs->wlan_bankxinfo);
130 bank_sz = (bank_info & WLAN_BANKXINFO_BANK_SIZE_MASK) >>
131 WLAN_BANKXINFO_BANK_SIZE_SHIFT;
132 } else {
133 /* Figure out bank size using SOCRAM registers */
134 }
135
136 si_setcoreidx(sih, savecore);
137 exit:
138 return bank_sz;
139 }
140
141 /* Returns the start address of given memory */
hndmem_mem_base(si_t * sih,hndmem_type_t mem)142 uint32 hndmem_mem_base(si_t *sih, hndmem_type_t mem)
143 {
144 uint32 savecore, base_addr = 0;
145
146 /* Currently only support of SOCRAM is available in hardware */
147 if (mem != MEM_SOCRAM) {
148 goto exit;
149 }
150
151 savecore = si_coreidx(sih);
152
153 if (si_setcore(sih, SOCRAM_CORE_ID, 0)) {
154 base_addr = si_get_slaveport_addr(sih, CORE_SLAVE_PORT_1,
155 CORE_BASE_ADDR_0, SOCRAM_CORE_ID, 0);
156 } else {
157 /* Add code to get the base address of TCM */
158 base_addr = 0;
159 }
160
161 si_setcoreidx(sih, savecore);
162
163 exit:
164 return base_addr;
165 }
166
167 #ifdef BCMDEBUG
168 char *hndmem_type_str[] = {
169 "SOCRAM", /* 0 */
170 "BM", /* 1 */
171 "UCM", /* 2 */
172 "SHM", /* 3 */
173 };
174
175 /* Dumps the complete memory information */
hndmem_dump_meminfo_all(si_t * sih)176 void hndmem_dump_meminfo_all(si_t *sih)
177 {
178 int mem, bank, bank_cnt, bank_sz;
179
180 for (mem = MEM_SOCRAM; mem < MEM_MAX; mem++) {
181 bank_cnt = hndmem_num_banks(sih, mem);
182
183 printf("\nMemtype: %s\n", hndmem_type_str[mem]);
184 for (bank = 0; bank < bank_cnt; bank++) {
185 bank_sz = hndmem_bank_size(sih, mem, bank);
186 printf("Bank-%d: %d KB\n", bank, bank_sz);
187 }
188 }
189 }
190 #endif /* BCMDEBUG */
191
192 /* Configures the Sleep PDA for a particular bank for a given memory type */
hndmem_sleeppda_bank_config(si_t * sih,hndmem_type_t mem,int bank_num,hndmem_config_t config,uint32 pda)193 int hndmem_sleeppda_bank_config(si_t *sih, hndmem_type_t mem, int bank_num,
194 hndmem_config_t config, uint32 pda)
195 {
196 uint32 savecore, reg_data;
197 gciregs_t *gciregs;
198 int err = BCME_OK;
199 osl_t *osh = si_osh(sih);
200
201 /* Check whether SOCRAM core is present or not. If not, bail out */
202 /* In future we need to add code for TCM based chips as well */
203 if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
204 err = BCME_UNSUPPORTED;
205 goto exit;
206 }
207
208 /* Sleep PDA is supported only by GCI rev >= 9 */
209 if (sih->gcirev < 9) {
210 err = BCME_UNSUPPORTED;
211 goto exit;
212 }
213
214 if (!IS_MEMTYPE_VALID(mem)) {
215 err = BCME_BADOPTION;
216 goto exit;
217 }
218
219 if (!IS_MEMCONFIG_VALID(config)) {
220 err = BCME_BADOPTION;
221 goto exit;
222 }
223
224 savecore = si_coreidx(sih);
225 gciregs = si_setcore(sih, GCI_CORE_ID, 0);
226
227 reg_data = ((mem & GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK)
228 << GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) |
229 ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK)
230 << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT);
231
232 W_REG(osh, &gciregs->gci_indirect_addr, reg_data);
233
234 if (config == PDA_CONFIG_SET_PARTIAL) {
235 W_REG(osh, &gciregs->wlan_bankxsleeppda, pda);
236 W_REG(osh, &gciregs->wlan_bankxkill, 0);
237 } else if (config == PDA_CONFIG_SET_FULL) {
238 W_REG(osh, &gciregs->wlan_bankxsleeppda,
239 WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK);
240 W_REG(osh, &gciregs->wlan_bankxkill,
241 WLAN_BANKX_PKILL_REG_SLEEPPDA_MASK);
242 } else {
243 W_REG(osh, &gciregs->wlan_bankxsleeppda, 0);
244 W_REG(osh, &gciregs->wlan_bankxkill, 0);
245 }
246
247 si_setcoreidx(sih, savecore);
248
249 exit:
250 return err;
251 }
252
253 /* Configures the Active PDA for a particular bank for a given memory type */
hndmem_activepda_bank_config(si_t * sih,hndmem_type_t mem,int bank_num,hndmem_config_t config,uint32 pda)254 int hndmem_activepda_bank_config(si_t *sih, hndmem_type_t mem, int bank_num,
255 hndmem_config_t config, uint32 pda)
256 {
257 uint32 savecore, reg_data;
258 gciregs_t *gciregs;
259 int err = BCME_OK;
260 osl_t *osh = si_osh(sih);
261
262 if (!IS_MEMTYPE_VALID(mem)) {
263 err = BCME_BADOPTION;
264 goto exit;
265 }
266
267 if (!IS_MEMCONFIG_VALID(config)) {
268 err = BCME_BADOPTION;
269 goto exit;
270 }
271
272 savecore = si_coreidx(sih);
273
274 /* Check whether SOCRAM core is present or not. If not, bail out */
275 /* In future we need to add code for TCM based chips as well */
276 if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
277 err = BCME_UNSUPPORTED;
278 goto exit;
279 }
280
281 if (sih->gcirev >= 0x9) {
282 gciregs = si_setcore(sih, GCI_CORE_ID, 0);
283
284 reg_data = ((mem & GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK)
285 << GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) |
286 ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK)
287 << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT);
288
289 W_REG(osh, &gciregs->gci_indirect_addr, reg_data);
290
291 if (config == PDA_CONFIG_SET_PARTIAL) {
292 W_REG(osh, &gciregs->wlan_bankxactivepda, pda);
293 } else if (config == PDA_CONFIG_SET_FULL) {
294 W_REG(osh, &gciregs->wlan_bankxactivepda,
295 WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK);
296 } else {
297 W_REG(osh, &gciregs->wlan_bankxactivepda, 0);
298 }
299 } else {
300 /* Configure SOCRAM PDA using SOCRAM registers */
301 err = BCME_UNSUPPORTED;
302 }
303
304 si_setcoreidx(sih, savecore);
305
306 exit:
307 return err;
308 }
309
310 /* Configures the Sleep PDA for all the banks for a given memory type */
hndmem_sleeppda_config(si_t * sih,hndmem_type_t mem,hndmem_config_t config)311 int hndmem_sleeppda_config(si_t *sih, hndmem_type_t mem, hndmem_config_t config)
312 {
313 int bank;
314 int num_banks = hndmem_num_banks(sih, mem);
315 int err = BCME_OK;
316
317 /* Sleep PDA is supported only by GCI rev >= 9 */
318 if (sih->gcirev < 9) {
319 err = BCME_UNSUPPORTED;
320 goto exit;
321 }
322
323 if (!IS_MEMTYPE_VALID(mem)) {
324 err = BCME_BADOPTION;
325 goto exit;
326 }
327
328 if (!IS_MEMCONFIG_VALID(config)) {
329 err = BCME_BADOPTION;
330 goto exit;
331 }
332
333 for (bank = 0; bank < num_banks; bank++) {
334 err = hndmem_sleeppda_bank_config(sih, mem, bank, config, 0);
335 }
336
337 exit:
338 return err;
339 }
340
341 /* Configures the Active PDA for all the banks for a given memory type */
hndmem_activepda_config(si_t * sih,hndmem_type_t mem,hndmem_config_t config)342 int hndmem_activepda_config(si_t *sih, hndmem_type_t mem,
343 hndmem_config_t config)
344 {
345 int bank;
346 int num_banks = hndmem_num_banks(sih, mem);
347 int err = BCME_OK;
348
349 if (!IS_MEMTYPE_VALID(mem)) {
350 err = BCME_BADOPTION;
351 goto exit;
352 }
353
354 if (!IS_MEMCONFIG_VALID(config)) {
355 err = BCME_BADOPTION;
356 goto exit;
357 }
358
359 for (bank = 0; bank < num_banks; bank++) {
360 err = hndmem_activepda_bank_config(sih, mem, bank, config, 0);
361 }
362
363 exit:
364 return err;
365 }
366
367 /* Turn off/on all the possible banks in a given memory range.
368 * Currently this works only for SOCRAM as this is restricted by HW.
369 */
hndmem_activepda_mem_config(si_t * sih,hndmem_type_t mem,uint32 mem_start,uint32 size,hndmem_config_t config)370 int hndmem_activepda_mem_config(si_t *sih, hndmem_type_t mem, uint32 mem_start,
371 uint32 size, hndmem_config_t config)
372 {
373 int bank, bank_sz, num_banks;
374 int mem_end;
375 int bank_start_addr, bank_end_addr;
376 int err = BCME_OK;
377
378 /* We can get bank size for only SOCRAM/TCM only. Support is not avilable
379 * for other memories (BM, UCM and SHM)
380 */
381 if (mem != MEM_SOCRAM) {
382 err = BCME_UNSUPPORTED;
383 goto exit;
384 }
385
386 num_banks = hndmem_num_banks(sih, mem);
387 bank_start_addr = hndmem_mem_base(sih, mem);
388 mem_end = mem_start + size - 1;
389
390 for (bank = 0; bank < num_banks; bank++) {
391 /* Bank size is spcified in bankXinfo register in terms on KBs */
392 bank_sz = 0x400 * hndmem_bank_size(sih, mem, bank);
393
394 bank_end_addr = bank_start_addr + bank_sz - 1;
395
396 if (config == PDA_CONFIG_SET_FULL) {
397 /* Check if the bank is completely overlapping with the given mem
398 * range */
399 if ((mem_start <= bank_start_addr) && (mem_end >= bank_end_addr)) {
400 err = hndmem_activepda_bank_config(sih, mem, bank, config, 0);
401 }
402 } else {
403 /* Check if the bank is completely overlaped with the given mem
404 * range */
405 if (((mem_start <= bank_start_addr) &&
406 (mem_end >= bank_end_addr)) ||
407 /* Check if the bank is partially overlaped with the given range
408 */
409 ((mem_start <= bank_end_addr) &&
410 (mem_end >= bank_start_addr))) {
411 err = hndmem_activepda_bank_config(sih, mem, bank, config, 0);
412 }
413 }
414
415 bank_start_addr += bank_sz;
416 }
417
418 exit:
419 return err;
420 }
421