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