1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2016  Realtek Corporation.
5  *
6  * Contact Information:
7  * wlanfae <wlanfae@realtek.com>
8  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
9  * Hsinchu 300, Taiwan.
10  *
11  * Larry Finger <Larry.Finger@lwfinger.net>
12  *
13  *****************************************************************************/
14 #include "halmac_2_platform.h"
15 #include "halmac_type.h"
16 #include "halmac_88xx/halmac_api_88xx.h"
17 #include "halmac_88xx/halmac_88xx_cfg.h"
18 
19 #include "halmac_88xx/halmac_8822b/halmac_8822b_cfg.h"
20 
21 static enum halmac_ret_status
halmac_check_platform_api(void * driver_adapter,enum halmac_interface halmac_interface,struct halmac_platform_api * halmac_platform_api)22 halmac_check_platform_api(void *driver_adapter,
23 			  enum halmac_interface halmac_interface,
24 			  struct halmac_platform_api *halmac_platform_api)
25 {
26 	void *adapter_local = NULL;
27 
28 	adapter_local = driver_adapter;
29 
30 	if (!halmac_platform_api)
31 		return HALMAC_RET_PLATFORM_API_NULL;
32 
33 	if (halmac_interface == HALMAC_INTERFACE_SDIO) {
34 		if (!halmac_platform_api->SDIO_CMD52_READ) {
35 			pr_err("(!halmac_platform_api->SDIO_CMD52_READ)\n");
36 			return HALMAC_RET_PLATFORM_API_NULL;
37 		}
38 		if (!halmac_platform_api->SDIO_CMD53_READ_8) {
39 			pr_err("(!halmac_platform_api->SDIO_CMD53_READ_8)\n");
40 			return HALMAC_RET_PLATFORM_API_NULL;
41 		}
42 		if (!halmac_platform_api->SDIO_CMD53_READ_16) {
43 			pr_err("(!halmac_platform_api->SDIO_CMD53_READ_16)\n");
44 			return HALMAC_RET_PLATFORM_API_NULL;
45 		}
46 		if (!halmac_platform_api->SDIO_CMD53_READ_32) {
47 			pr_err("(!halmac_platform_api->SDIO_CMD53_READ_32)\n");
48 			return HALMAC_RET_PLATFORM_API_NULL;
49 		}
50 		if (!halmac_platform_api->SDIO_CMD53_READ_N) {
51 			pr_err("(!halmac_platform_api->SDIO_CMD53_READ_N)\n");
52 			return HALMAC_RET_PLATFORM_API_NULL;
53 		}
54 		if (!halmac_platform_api->SDIO_CMD52_WRITE) {
55 			pr_err("(!halmac_platform_api->SDIO_CMD52_WRITE)\n");
56 			return HALMAC_RET_PLATFORM_API_NULL;
57 		}
58 		if (!halmac_platform_api->SDIO_CMD53_WRITE_8) {
59 			pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_8)\n");
60 			return HALMAC_RET_PLATFORM_API_NULL;
61 		}
62 		if (!halmac_platform_api->SDIO_CMD53_WRITE_16) {
63 			pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_16)\n");
64 			return HALMAC_RET_PLATFORM_API_NULL;
65 		}
66 		if (!halmac_platform_api->SDIO_CMD53_WRITE_32) {
67 			pr_err("(!halmac_platform_api->SDIO_CMD53_WRITE_32)\n");
68 			return HALMAC_RET_PLATFORM_API_NULL;
69 		}
70 	}
71 
72 	if (halmac_interface == HALMAC_INTERFACE_USB ||
73 	    halmac_interface == HALMAC_INTERFACE_PCIE) {
74 		if (!halmac_platform_api->REG_READ_8) {
75 			pr_err("(!halmac_platform_api->REG_READ_8)\n");
76 			return HALMAC_RET_PLATFORM_API_NULL;
77 		}
78 		if (!halmac_platform_api->REG_READ_16) {
79 			pr_err("(!halmac_platform_api->REG_READ_16)\n");
80 			return HALMAC_RET_PLATFORM_API_NULL;
81 		}
82 		if (!halmac_platform_api->REG_READ_32) {
83 			pr_err("(!halmac_platform_api->REG_READ_32)\n");
84 			return HALMAC_RET_PLATFORM_API_NULL;
85 		}
86 		if (!halmac_platform_api->REG_WRITE_8) {
87 			pr_err("(!halmac_platform_api->REG_WRITE_8)\n");
88 			return HALMAC_RET_PLATFORM_API_NULL;
89 		}
90 		if (!halmac_platform_api->REG_WRITE_16) {
91 			pr_err("(!halmac_platform_api->REG_WRITE_16)\n");
92 			return HALMAC_RET_PLATFORM_API_NULL;
93 		}
94 		if (!halmac_platform_api->REG_WRITE_32) {
95 			pr_err("(!halmac_platform_api->REG_WRITE_32)\n");
96 			return HALMAC_RET_PLATFORM_API_NULL;
97 		}
98 	}
99 
100 	if (!halmac_platform_api->EVENT_INDICATION) {
101 		pr_err("(!halmac_platform_api->EVENT_INDICATION)\n");
102 		return HALMAC_RET_PLATFORM_API_NULL;
103 	}
104 
105 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
106 			"%s ==========>\n", __func__);
107 
108 	return HALMAC_RET_SUCCESS;
109 }
110 
111 static enum halmac_ret_status
halmac_convert_to_sdio_bus_offset(u32 * halmac_offset)112 halmac_convert_to_sdio_bus_offset(u32 *halmac_offset)
113 {
114 	switch ((*halmac_offset) & 0xFFFF0000) {
115 	case WLAN_IOREG_OFFSET:
116 		*halmac_offset = (HALMAC_SDIO_CMD_ADDR_MAC_REG << 13) |
117 				 (*halmac_offset & HALMAC_WLAN_MAC_REG_MSK);
118 		break;
119 	case SDIO_LOCAL_OFFSET:
120 		*halmac_offset = (HALMAC_SDIO_CMD_ADDR_SDIO_REG << 13) |
121 				 (*halmac_offset & HALMAC_SDIO_LOCAL_MSK);
122 		break;
123 	default:
124 		*halmac_offset = 0xFFFFFFFF;
125 		return HALMAC_RET_CONVERT_SDIO_OFFSET_FAIL;
126 	}
127 
128 	return HALMAC_RET_SUCCESS;
129 }
130 
131 static u8
platform_reg_read_8_sdio(void * driver_adapter,struct halmac_platform_api * halmac_platform_api,u32 offset)132 platform_reg_read_8_sdio(void *driver_adapter,
133 			 struct halmac_platform_api *halmac_platform_api,
134 			 u32 offset)
135 {
136 	u8 value8;
137 	u32 halmac_offset = offset;
138 	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
139 
140 	if ((halmac_offset & 0xFFFF0000) == 0)
141 		halmac_offset |= WLAN_IOREG_OFFSET;
142 
143 	status = halmac_convert_to_sdio_bus_offset(&halmac_offset);
144 	if (status != HALMAC_RET_SUCCESS) {
145 		pr_err("%s error = %x\n", __func__, status);
146 		return status;
147 	}
148 
149 	value8 = halmac_platform_api->SDIO_CMD52_READ(driver_adapter,
150 						      halmac_offset);
151 
152 	return value8;
153 }
154 
155 static enum halmac_ret_status
platform_reg_write_8_sdio(void * driver_adapter,struct halmac_platform_api * halmac_platform_api,u32 offset,u8 data)156 platform_reg_write_8_sdio(void *driver_adapter,
157 			  struct halmac_platform_api *halmac_platform_api,
158 			  u32 offset, u8 data)
159 {
160 	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
161 	u32 halmac_offset = offset;
162 
163 	if ((halmac_offset & 0xFFFF0000) == 0)
164 		halmac_offset |= WLAN_IOREG_OFFSET;
165 
166 	status = halmac_convert_to_sdio_bus_offset(&halmac_offset);
167 
168 	if (status != HALMAC_RET_SUCCESS) {
169 		pr_err("halmac_reg_write_8_sdio_88xx error = %x\n", status);
170 		return status;
171 	}
172 	halmac_platform_api->SDIO_CMD52_WRITE(driver_adapter, halmac_offset,
173 					      data);
174 
175 	return HALMAC_RET_SUCCESS;
176 }
177 
178 static enum halmac_ret_status
halmac_get_chip_info(void * driver_adapter,struct halmac_platform_api * halmac_platform_api,enum halmac_interface halmac_interface,struct halmac_adapter * halmac_adapter)179 halmac_get_chip_info(void *driver_adapter,
180 		     struct halmac_platform_api *halmac_platform_api,
181 		     enum halmac_interface halmac_interface,
182 		     struct halmac_adapter *halmac_adapter)
183 {
184 	struct halmac_api *halmac_api = (struct halmac_api *)NULL;
185 	u8 chip_id, chip_version;
186 	u32 polling_count;
187 
188 	halmac_api = (struct halmac_api *)halmac_adapter->halmac_api;
189 
190 	/* Get Chip_id and Chip_version */
191 	if (halmac_adapter->halmac_interface == HALMAC_INTERFACE_SDIO) {
192 		platform_reg_write_8_sdio(
193 			driver_adapter, halmac_platform_api, REG_SDIO_HSUS_CTRL,
194 			platform_reg_read_8_sdio(driver_adapter,
195 						 halmac_platform_api,
196 						 REG_SDIO_HSUS_CTRL) &
197 				~(BIT(0)));
198 
199 		polling_count = 10000;
200 		while (!(platform_reg_read_8_sdio(driver_adapter,
201 						  halmac_platform_api,
202 						  REG_SDIO_HSUS_CTRL) &
203 			 0x02)) {
204 			polling_count--;
205 			if (polling_count == 0)
206 				return HALMAC_RET_SDIO_LEAVE_SUSPEND_FAIL;
207 		}
208 
209 		chip_id = platform_reg_read_8_sdio(
210 			driver_adapter, halmac_platform_api, REG_SYS_CFG2);
211 		chip_version = platform_reg_read_8_sdio(driver_adapter,
212 							halmac_platform_api,
213 							REG_SYS_CFG1 + 1) >>
214 			       4;
215 	} else {
216 		chip_id = halmac_platform_api->REG_READ_8(driver_adapter,
217 							  REG_SYS_CFG2);
218 		chip_version = halmac_platform_api->REG_READ_8(
219 				       driver_adapter, REG_SYS_CFG1 + 1) >>
220 			       4;
221 	}
222 
223 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
224 			"[TRACE]Chip id : 0x%X\n", chip_id);
225 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
226 			"[TRACE]Chip version : 0x%X\n", chip_version);
227 
228 	halmac_adapter->chip_version = (enum halmac_chip_ver)chip_version;
229 
230 	if (chip_id == HALMAC_CHIP_ID_HW_DEF_8822B)
231 		halmac_adapter->chip_id = HALMAC_CHIP_ID_8822B;
232 	else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8821C)
233 		halmac_adapter->chip_id = HALMAC_CHIP_ID_8821C;
234 	else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8814B)
235 		halmac_adapter->chip_id = HALMAC_CHIP_ID_8814B;
236 	else if (chip_id == HALMAC_CHIP_ID_HW_DEF_8197F)
237 		halmac_adapter->chip_id = HALMAC_CHIP_ID_8197F;
238 	else
239 		halmac_adapter->chip_id = HALMAC_CHIP_ID_UNDEFINE;
240 
241 	if (halmac_adapter->chip_id == HALMAC_CHIP_ID_UNDEFINE)
242 		return HALMAC_RET_CHIP_NOT_SUPPORT;
243 
244 	return HALMAC_RET_SUCCESS;
245 }
246 
247 /**
248  * halmac_init_adapter() - init halmac_adapter
249  * @driver_adapter : the adapter of caller
250  * @halmac_platform_api : the platform APIs which is used in halmac APIs
251  * @halmac_interface : bus interface
252  * @pp_halmac_adapter : the adapter of halmac
253  * @pp_halmac_api : the function pointer of APIs, caller shall call APIs by
254  *                 function pointer
255  * Author : KaiYuan Chang / Ivan Lin
256  * Return : enum halmac_ret_status
257  * More details of status code can be found in prototype document
258  */
259 enum halmac_ret_status
halmac_init_adapter(void * driver_adapter,struct halmac_platform_api * halmac_platform_api,enum halmac_interface halmac_interface,struct halmac_adapter ** pp_halmac_adapter,struct halmac_api ** pp_halmac_api)260 halmac_init_adapter(void *driver_adapter,
261 		    struct halmac_platform_api *halmac_platform_api,
262 		    enum halmac_interface halmac_interface,
263 		    struct halmac_adapter **pp_halmac_adapter,
264 		    struct halmac_api **pp_halmac_api)
265 {
266 	struct halmac_adapter *halmac_adapter = (struct halmac_adapter *)NULL;
267 	enum halmac_ret_status status = HALMAC_RET_SUCCESS;
268 
269 	union {
270 		u32 i;
271 		u8 x[4];
272 	} ENDIAN_CHECK = {0x01000000};
273 
274 	status = halmac_check_platform_api(driver_adapter, halmac_interface,
275 					   halmac_platform_api);
276 	if (status != HALMAC_RET_SUCCESS)
277 		return status;
278 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
279 			HALMAC_SVN_VER "\n");
280 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
281 			"HALMAC_MAJOR_VER = %x\n", HALMAC_MAJOR_VER);
282 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
283 			"HALMAC_PROTOTYPE_VER = %x\n", HALMAC_PROTOTYPE_VER);
284 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
285 			"HALMAC_MINOR_VER = %x\n", HALMAC_MINOR_VER);
286 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
287 			"HALMAC_PATCH_VER = %x\n", HALMAC_PATCH_VER);
288 
289 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
290 			"halmac_init_adapter_88xx ==========>\n");
291 
292 	/* Check endian setting - Little endian : 1, Big endian : 0*/
293 	if (ENDIAN_CHECK.x[0] == HALMAC_SYSTEM_ENDIAN) {
294 		pr_err("Endian setting Err!!\n");
295 		return HALMAC_RET_ENDIAN_ERR;
296 	}
297 
298 	halmac_adapter = kzalloc(sizeof(*halmac_adapter), GFP_KERNEL);
299 	if (!halmac_adapter) {
300 		/* out of memory */
301 		return HALMAC_RET_MALLOC_FAIL;
302 	}
303 
304 	/* return halmac adapter address to caller */
305 	*pp_halmac_adapter = halmac_adapter;
306 
307 	/* Record caller info */
308 	halmac_adapter->halmac_platform_api = halmac_platform_api;
309 	halmac_adapter->driver_adapter = driver_adapter;
310 	halmac_interface = halmac_interface == HALMAC_INTERFACE_AXI ?
311 				   HALMAC_INTERFACE_PCIE :
312 				   halmac_interface;
313 	halmac_adapter->halmac_interface = halmac_interface;
314 
315 	spin_lock_init(&halmac_adapter->efuse_lock);
316 	spin_lock_init(&halmac_adapter->h2c_seq_lock);
317 
318 	/*Get Chip*/
319 	if (halmac_get_chip_info(driver_adapter, halmac_platform_api,
320 				 halmac_interface,
321 				 halmac_adapter) != HALMAC_RET_SUCCESS) {
322 		pr_err("HALMAC_RET_CHIP_NOT_SUPPORT\n");
323 		return HALMAC_RET_CHIP_NOT_SUPPORT;
324 	}
325 
326 	/* Assign function pointer to halmac API */
327 	halmac_init_adapter_para_88xx(halmac_adapter);
328 	status = halmac_mount_api_88xx(halmac_adapter);
329 
330 	/* Return halmac API function pointer */
331 	*pp_halmac_api = (struct halmac_api *)halmac_adapter->halmac_api;
332 
333 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
334 			"halmac_init_adapter_88xx <==========\n");
335 
336 	return status;
337 }
338 
339 /**
340  * halmac_halt_api() - stop halmac_api action
341  * @halmac_adapter : the adapter of halmac
342  * Author : Ivan Lin
343  * Return : enum halmac_ret_status
344  * More details of status code can be found in prototype document
345  */
halmac_halt_api(struct halmac_adapter * halmac_adapter)346 enum halmac_ret_status halmac_halt_api(struct halmac_adapter *halmac_adapter)
347 {
348 	void *driver_adapter = NULL;
349 	struct halmac_platform_api *halmac_platform_api =
350 		(struct halmac_platform_api *)NULL;
351 
352 	if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS)
353 		return HALMAC_RET_ADAPTER_INVALID;
354 
355 	driver_adapter = halmac_adapter->driver_adapter;
356 	halmac_platform_api = halmac_adapter->halmac_platform_api;
357 
358 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
359 			"%s ==========>\n", __func__);
360 	halmac_adapter->halmac_state.api_state = HALMAC_API_STATE_HALT;
361 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
362 			"%s ==========>\n", __func__);
363 	return HALMAC_RET_SUCCESS;
364 }
365 
366 /**
367  * halmac_deinit_adapter() - deinit halmac adapter
368  * @halmac_adapter : the adapter of halmac
369  * Author : KaiYuan Chang / Ivan Lin
370  * Return : enum halmac_ret_status
371  * More details of status code can be found in prototype document
372  */
373 enum halmac_ret_status
halmac_deinit_adapter(struct halmac_adapter * halmac_adapter)374 halmac_deinit_adapter(struct halmac_adapter *halmac_adapter)
375 {
376 	void *driver_adapter = NULL;
377 
378 	if (halmac_adapter_validate(halmac_adapter) != HALMAC_RET_SUCCESS)
379 		return HALMAC_RET_ADAPTER_INVALID;
380 
381 	driver_adapter = halmac_adapter->driver_adapter;
382 
383 	HALMAC_RT_TRACE(driver_adapter, HALMAC_MSG_INIT, DBG_DMESG,
384 			"[TRACE]halmac_deinit_adapter_88xx ==========>\n");
385 
386 	kfree(halmac_adapter->hal_efuse_map);
387 	halmac_adapter->hal_efuse_map = (u8 *)NULL;
388 
389 	kfree(halmac_adapter->halmac_state.psd_set.data);
390 	halmac_adapter->halmac_state.psd_set.data = (u8 *)NULL;
391 
392 	kfree(halmac_adapter->halmac_api);
393 	halmac_adapter->halmac_api = NULL;
394 
395 	halmac_adapter->hal_adapter_backup = NULL;
396 	kfree(halmac_adapter);
397 
398 	return HALMAC_RET_SUCCESS;
399 }
400 
401 /**
402  * halmac_get_version() - get HALMAC version
403  * @version : return version of major, prototype and minor information
404  * Author : KaiYuan Chang / Ivan Lin
405  * Return : enum halmac_ret_status
406  * More details of status code can be found in prototype document
407  */
halmac_get_version(struct halmac_ver * version)408 enum halmac_ret_status halmac_get_version(struct halmac_ver *version)
409 {
410 	version->major_ver = (u8)HALMAC_MAJOR_VER;
411 	version->prototype_ver = (u8)HALMAC_PROTOTYPE_VER;
412 	version->minor_ver = (u8)HALMAC_MINOR_VER;
413 
414 	return HALMAC_RET_SUCCESS;
415 }
416