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