xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/hndmem.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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