Commit | Line | Data |
---|---|---|
d2839953 RC |
1 | /* |
2 | * Utility routines for configuring different memories in Broadcom chips. | |
3 | * | |
965f77c4 | 4 | * Copyright (C) 1999-2019, Broadcom. |
d2839953 RC |
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 | * 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) ((cfg >= PDA_CONFIG_CLEAR) && (cfg < PDA_CONFIG_MAX)) | |
42 | ||
43 | /* Returns the number of banks in a given memory */ | |
44 | int | |
45 | 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 | /* TODO: 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 >= 9) { | |
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 = (mem_info & WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_MASK) >> | |
72 | WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_SHIFT; | |
73 | break; | |
74 | case MEM_BM: | |
75 | num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACBM_MASK) >> | |
76 | WLAN_MEM_INFO_REG_NUMD11MACBM_SHIFT; | |
77 | break; | |
78 | case MEM_UCM: | |
79 | num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACUCM_MASK) >> | |
80 | WLAN_MEM_INFO_REG_NUMD11MACUCM_SHIFT; | |
81 | break; | |
82 | case MEM_SHM: | |
83 | num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACSHM_MASK) >> | |
84 | WLAN_MEM_INFO_REG_NUMD11MACSHM_SHIFT; | |
85 | break; | |
86 | default: | |
87 | ASSERT(0); | |
88 | break; | |
89 | } | |
90 | } else { | |
91 | /* TODO: Figure out bank information using SOCRAM registers */ | |
92 | } | |
93 | ||
94 | si_setcoreidx(sih, savecore); | |
95 | exit: | |
96 | return num_banks; | |
97 | } | |
98 | ||
99 | /* Returns the size of a give bank in a given memory */ | |
100 | int | |
101 | 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 | /* TODO: 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 >= 9) { | |
121 | gciregs = si_setcore(sih, GCI_CORE_ID, 0); | |
122 | ||
123 | reg_data = ((mem & | |
124 | GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) << | |
125 | GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) | | |
126 | ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK) | |
127 | << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT); | |
128 | W_REG(osh, &gciregs->gci_indirect_addr, reg_data); | |
129 | ||
130 | bank_info = R_REG(osh, &gciregs->wlan_bankxinfo); | |
131 | bank_sz = (bank_info & WLAN_BANKXINFO_BANK_SIZE_MASK) >> | |
132 | WLAN_BANKXINFO_BANK_SIZE_SHIFT; | |
133 | } else { | |
134 | /* TODO: Figure out bank size using SOCRAM registers */ | |
135 | } | |
136 | ||
137 | si_setcoreidx(sih, savecore); | |
138 | exit: | |
139 | return bank_sz; | |
140 | } | |
141 | ||
142 | /* Returns the start address of given memory */ | |
143 | uint32 | |
144 | hndmem_mem_base(si_t *sih, hndmem_type_t mem) | |
145 | { | |
146 | uint32 savecore, base_addr = 0; | |
147 | ||
148 | /* Currently only support of SOCRAM is available in hardware */ | |
149 | if (mem != MEM_SOCRAM) { | |
150 | goto exit; | |
151 | } | |
152 | ||
153 | savecore = si_coreidx(sih); | |
154 | ||
155 | if (si_setcore(sih, SOCRAM_CORE_ID, 0)) | |
156 | { | |
157 | base_addr = si_get_slaveport_addr(sih, CORE_SLAVE_PORT_1, | |
158 | CORE_BASE_ADDR_0, SOCRAM_CORE_ID, 0); | |
159 | } else { | |
160 | /* TODO: Add code to get the base address of TCM */ | |
161 | base_addr = 0; | |
162 | } | |
163 | ||
164 | si_setcoreidx(sih, savecore); | |
165 | ||
166 | exit: | |
167 | return base_addr; | |
168 | } | |
169 | ||
170 | #ifdef BCMDEBUG | |
171 | char *hndmem_type_str[] = | |
172 | { | |
173 | "SOCRAM", /* 0 */ | |
174 | "BM", /* 1 */ | |
175 | "UCM", /* 2 */ | |
176 | "SHM", /* 3 */ | |
177 | }; | |
178 | ||
179 | /* Dumps the complete memory information */ | |
180 | void | |
181 | hndmem_dump_meminfo_all(si_t *sih) | |
182 | { | |
183 | int mem, bank, bank_cnt, bank_sz; | |
184 | ||
185 | for (mem = MEM_SOCRAM; mem < MEM_MAX; mem++) { | |
186 | bank_cnt = hndmem_num_banks(sih, mem); | |
187 | ||
188 | printf("\nMemtype: %s\n", hndmem_type_str[mem]); | |
189 | for (bank = 0; bank < bank_cnt; bank++) { | |
190 | bank_sz = hndmem_bank_size(sih, mem, bank); | |
191 | printf("Bank-%d: %d KB\n", bank, bank_sz); | |
192 | } | |
193 | } | |
194 | } | |
195 | #endif /* BCMDEBUG */ | |
196 | ||
197 | /* Configures the Sleep PDA for a particular bank for a given memory type */ | |
198 | int | |
199 | hndmem_sleeppda_bank_config(si_t *sih, hndmem_type_t mem, int bank_num, | |
200 | hndmem_config_t config, uint32 pda) | |
201 | { | |
202 | uint32 savecore, reg_data; | |
203 | gciregs_t *gciregs; | |
204 | int err = BCME_OK; | |
205 | osl_t *osh = si_osh(sih); | |
206 | ||
207 | /* TODO: Check whether SOCRAM core is present or not. If not, bail out */ | |
208 | /* In future we need to add code for TCM based chips as well */ | |
209 | if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) { | |
210 | err = BCME_UNSUPPORTED; | |
211 | goto exit; | |
212 | } | |
213 | ||
214 | /* Sleep PDA is supported only by GCI rev >= 9 */ | |
215 | if (sih->gcirev < 9) { | |
216 | err = BCME_UNSUPPORTED; | |
217 | goto exit; | |
218 | } | |
219 | ||
220 | if (!IS_MEMTYPE_VALID(mem)) { | |
221 | err = BCME_BADOPTION; | |
222 | goto exit; | |
223 | } | |
224 | ||
225 | if (!IS_MEMCONFIG_VALID(config)) { | |
226 | err = BCME_BADOPTION; | |
227 | goto exit; | |
228 | } | |
229 | ||
230 | savecore = si_coreidx(sih); | |
231 | gciregs = si_setcore(sih, GCI_CORE_ID, 0); | |
232 | ||
233 | reg_data = ((mem & | |
234 | GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) << | |
235 | GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) | | |
236 | ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK) | |
237 | << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT); | |
238 | ||
239 | W_REG(osh, &gciregs->gci_indirect_addr, reg_data); | |
240 | ||
241 | if (config == PDA_CONFIG_SET_PARTIAL) { | |
242 | W_REG(osh, &gciregs->wlan_bankxsleeppda, pda); | |
243 | W_REG(osh, &gciregs->wlan_bankxkill, 0); | |
244 | } | |
245 | else if (config == PDA_CONFIG_SET_FULL) { | |
246 | W_REG(osh, &gciregs->wlan_bankxsleeppda, WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK); | |
247 | W_REG(osh, &gciregs->wlan_bankxkill, WLAN_BANKX_PKILL_REG_SLEEPPDA_MASK); | |
248 | } else { | |
249 | W_REG(osh, &gciregs->wlan_bankxsleeppda, 0); | |
250 | W_REG(osh, &gciregs->wlan_bankxkill, 0); | |
251 | } | |
252 | ||
253 | si_setcoreidx(sih, savecore); | |
254 | ||
255 | exit: | |
256 | return err; | |
257 | } | |
258 | ||
259 | /* Configures the Active PDA for a particular bank for a given memory type */ | |
260 | int | |
261 | hndmem_activepda_bank_config(si_t *sih, hndmem_type_t mem, | |
262 | int bank_num, hndmem_config_t config, uint32 pda) | |
263 | { | |
264 | uint32 savecore, reg_data; | |
265 | gciregs_t *gciregs; | |
266 | int err = BCME_OK; | |
267 | osl_t *osh = si_osh(sih); | |
268 | ||
269 | if (!IS_MEMTYPE_VALID(mem)) { | |
270 | err = BCME_BADOPTION; | |
271 | goto exit; | |
272 | } | |
273 | ||
274 | if (!IS_MEMCONFIG_VALID(config)) { | |
275 | err = BCME_BADOPTION; | |
276 | goto exit; | |
277 | } | |
278 | ||
279 | savecore = si_coreidx(sih); | |
280 | ||
281 | /* TODO: Check whether SOCRAM core is present or not. If not, bail out */ | |
282 | /* In future we need to add code for TCM based chips as well */ | |
283 | if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) { | |
284 | err = BCME_UNSUPPORTED; | |
285 | goto exit; | |
286 | } | |
287 | ||
288 | if (sih->gcirev >= 9) { | |
289 | gciregs = si_setcore(sih, GCI_CORE_ID, 0); | |
290 | ||
291 | reg_data = ((mem & | |
292 | GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) << | |
293 | GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) | | |
294 | ((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK) | |
295 | << GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT); | |
296 | ||
297 | W_REG(osh, &gciregs->gci_indirect_addr, reg_data); | |
298 | ||
299 | if (config == PDA_CONFIG_SET_PARTIAL) { | |
300 | W_REG(osh, &gciregs->wlan_bankxactivepda, pda); | |
301 | } | |
302 | else if (config == PDA_CONFIG_SET_FULL) { | |
303 | W_REG(osh, &gciregs->wlan_bankxactivepda, | |
304 | WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK); | |
305 | } else { | |
306 | W_REG(osh, &gciregs->wlan_bankxactivepda, 0); | |
307 | } | |
308 | } else { | |
309 | /* TODO: Configure SOCRAM PDA using SOCRAM registers */ | |
310 | err = BCME_UNSUPPORTED; | |
311 | } | |
312 | ||
313 | si_setcoreidx(sih, savecore); | |
314 | ||
315 | exit: | |
316 | return err; | |
317 | } | |
318 | ||
319 | /* Configures the Sleep PDA for all the banks for a given memory type */ | |
320 | int | |
321 | hndmem_sleeppda_config(si_t *sih, hndmem_type_t mem, hndmem_config_t config) | |
322 | { | |
323 | int bank; | |
324 | int num_banks = hndmem_num_banks(sih, mem); | |
325 | int err = BCME_OK; | |
326 | ||
327 | /* Sleep PDA is supported only by GCI rev >= 9 */ | |
328 | if (sih->gcirev < 9) { | |
329 | err = BCME_UNSUPPORTED; | |
330 | goto exit; | |
331 | } | |
332 | ||
333 | if (!IS_MEMTYPE_VALID(mem)) { | |
334 | err = BCME_BADOPTION; | |
335 | goto exit; | |
336 | } | |
337 | ||
338 | if (!IS_MEMCONFIG_VALID(config)) { | |
339 | err = BCME_BADOPTION; | |
340 | goto exit; | |
341 | } | |
342 | ||
343 | for (bank = 0; bank < num_banks; bank++) | |
344 | { | |
345 | err = hndmem_sleeppda_bank_config(sih, mem, bank, config, 0); | |
346 | } | |
347 | ||
348 | exit: | |
349 | return err; | |
350 | } | |
351 | ||
352 | /* Configures the Active PDA for all the banks for a given memory type */ | |
353 | int | |
354 | hndmem_activepda_config(si_t *sih, hndmem_type_t mem, hndmem_config_t config) | |
355 | { | |
356 | int bank; | |
357 | int num_banks = hndmem_num_banks(sih, mem); | |
358 | int err = BCME_OK; | |
359 | ||
360 | if (!IS_MEMTYPE_VALID(mem)) { | |
361 | err = BCME_BADOPTION; | |
362 | goto exit; | |
363 | } | |
364 | ||
365 | if (!IS_MEMCONFIG_VALID(config)) { | |
366 | err = BCME_BADOPTION; | |
367 | goto exit; | |
368 | } | |
369 | ||
370 | for (bank = 0; bank < num_banks; bank++) | |
371 | { | |
372 | err = hndmem_activepda_bank_config(sih, mem, bank, config, 0); | |
373 | } | |
374 | ||
375 | exit: | |
376 | return err; | |
377 | } | |
378 | ||
379 | /* Turn off/on all the possible banks in a given memory range. | |
380 | * Currently this works only for SOCRAM as this is restricted by HW. | |
381 | */ | |
382 | int | |
383 | hndmem_activepda_mem_config(si_t *sih, hndmem_type_t mem, uint32 mem_start, | |
384 | uint32 size, hndmem_config_t config) | |
385 | { | |
386 | int bank, bank_sz, num_banks; | |
387 | int mem_end; | |
388 | int bank_start_addr, bank_end_addr; | |
389 | int err = BCME_OK; | |
390 | ||
391 | /* We can get bank size for only SOCRAM/TCM only. Support is not avilable | |
392 | * for other memories (BM, UCM and SHM) | |
393 | */ | |
394 | if (mem != MEM_SOCRAM) { | |
395 | err = BCME_UNSUPPORTED; | |
396 | goto exit; | |
397 | } | |
398 | ||
399 | num_banks = hndmem_num_banks(sih, mem); | |
400 | bank_start_addr = hndmem_mem_base(sih, mem); | |
401 | mem_end = mem_start + size - 1; | |
402 | ||
403 | for (bank = 0; bank < num_banks; bank++) | |
404 | { | |
405 | /* Bank size is spcified in bankXinfo register in terms on KBs */ | |
406 | bank_sz = 1024 * hndmem_bank_size(sih, mem, bank); | |
407 | ||
408 | bank_end_addr = bank_start_addr + bank_sz - 1; | |
409 | ||
410 | if (config == PDA_CONFIG_SET_FULL) { | |
411 | /* Check if the bank is completely overlapping with the given mem range */ | |
412 | if ((mem_start <= bank_start_addr) && (mem_end >= bank_end_addr)) { | |
413 | err = hndmem_activepda_bank_config(sih, mem, bank, config, 0); | |
414 | } | |
415 | } else { | |
416 | /* Check if the bank is completely overlaped with the given mem range */ | |
417 | if (((mem_start <= bank_start_addr) && (mem_end >= bank_end_addr)) || | |
418 | /* Check if the bank is partially overlaped with the given range */ | |
419 | ((mem_start <= bank_end_addr) && (mem_end >= bank_start_addr))) { | |
420 | err = hndmem_activepda_bank_config(sih, mem, bank, config, 0); | |
421 | } | |
422 | } | |
423 | ||
424 | bank_start_addr += bank_sz; | |
425 | } | |
426 | ||
427 | exit: | |
428 | return err; | |
429 | } |