1daeccac2SArend van Spriel // SPDX-License-Identifier: ISC
205491d2cSKalle Valo /*
305491d2cSKalle Valo * Copyright (c) 2010 Broadcom Corporation
405491d2cSKalle Valo */
505491d2cSKalle Valo
605491d2cSKalle Valo #include <linux/kernel.h>
705491d2cSKalle Valo #include <linux/string.h>
805491d2cSKalle Valo #include <linux/netdevice.h>
95dc3b7b9SFelix Fietkau #include <linux/module.h>
10fdd0bd88SChung-Hsien Hsu #include <linux/firmware.h>
1105491d2cSKalle Valo #include <brcmu_wifi.h>
1205491d2cSKalle Valo #include <brcmu_utils.h>
1305491d2cSKalle Valo #include "core.h"
1405491d2cSKalle Valo #include "bus.h"
1505491d2cSKalle Valo #include "debug.h"
1605491d2cSKalle Valo #include "fwil.h"
1705491d2cSKalle Valo #include "fwil_types.h"
1805491d2cSKalle Valo #include "tracepoint.h"
1905491d2cSKalle Valo #include "common.h"
208ea56be0SHante Meuleman #include "of.h"
21fdd0bd88SChung-Hsien Hsu #include "firmware.h"
22756a2b39SArend Van Spriel #include "chip.h"
2305491d2cSKalle Valo
24d84d99e0SHante Meuleman MODULE_AUTHOR("Broadcom Corporation");
25d84d99e0SHante Meuleman MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
26d84d99e0SHante Meuleman MODULE_LICENSE("Dual BSD/GPL");
27d84d99e0SHante Meuleman
2805491d2cSKalle Valo #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
2905491d2cSKalle Valo #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40
3005491d2cSKalle Valo
317705ba6fSArend van Spriel /* default boost value for RSSI_DELTA in preferred join selection */
3205491d2cSKalle Valo #define BRCMF_JOIN_PREF_RSSI_BOOST 8
3305491d2cSKalle Valo
347d34b056SHante Meuleman #define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
357d34b056SHante Meuleman
367d34b056SHante Meuleman static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
377d34b056SHante Meuleman module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
387d34b056SHante Meuleman MODULE_PARM_DESC(txglomsz, "Maximum tx packet chain size [SDIO]");
397d34b056SHante Meuleman
407d34b056SHante Meuleman /* Debug level configuration. See debug.h for bits, sysfs modifiable */
417d34b056SHante Meuleman int brcmf_msg_level;
422ef00c53SJoe Perches module_param_named(debug, brcmf_msg_level, int, 0600);
437d34b056SHante Meuleman MODULE_PARM_DESC(debug, "Level of debug output");
447d34b056SHante Meuleman
457d34b056SHante Meuleman static int brcmf_p2p_enable;
467d34b056SHante Meuleman module_param_named(p2pon, brcmf_p2p_enable, int, 0);
477d34b056SHante Meuleman MODULE_PARM_DESC(p2pon, "Enable legacy p2p management functionality");
487d34b056SHante Meuleman
497d34b056SHante Meuleman static int brcmf_feature_disable;
507d34b056SHante Meuleman module_param_named(feature_disable, brcmf_feature_disable, int, 0);
517d34b056SHante Meuleman MODULE_PARM_DESC(feature_disable, "Disable features");
527d34b056SHante Meuleman
537d34b056SHante Meuleman static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
547d34b056SHante Meuleman module_param_string(alternative_fw_path, brcmf_firmware_path,
552ef00c53SJoe Perches BRCMF_FW_ALTPATH_LEN, 0400);
567d34b056SHante Meuleman MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
577d34b056SHante Meuleman
587d34b056SHante Meuleman static int brcmf_fcmode;
597d34b056SHante Meuleman module_param_named(fcmode, brcmf_fcmode, int, 0);
607d34b056SHante Meuleman MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
617d34b056SHante Meuleman
627d34b056SHante Meuleman static int brcmf_roamoff;
632ef00c53SJoe Perches module_param_named(roamoff, brcmf_roamoff, int, 0400);
647d34b056SHante Meuleman MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
657d34b056SHante Meuleman
6612590551SRafał Miłecki static int brcmf_iapp_enable;
6712590551SRafał Miłecki module_param_named(iapp, brcmf_iapp_enable, int, 0);
6812590551SRafał Miłecki MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
6912590551SRafał Miłecki
708ba83d4dSArend van Spriel #ifdef DEBUG
71e8cd4750SRafał Miłecki /* always succeed brcmf_bus_started() */
728ba83d4dSArend van Spriel static int brcmf_ignore_probe_fail;
738ba83d4dSArend van Spriel module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);
748ba83d4dSArend van Spriel MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
758ba83d4dSArend van Spriel #endif
768ba83d4dSArend van Spriel
774d792895SHante Meuleman static struct brcmfmac_platform_data *brcmfmac_pdata;
787d34b056SHante Meuleman struct brcmf_mp_global_t brcmf_mp_global;
797d34b056SHante Meuleman
brcmf_c_set_joinpref_default(struct brcmf_if * ifp)807705ba6fSArend van Spriel void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
817705ba6fSArend van Spriel {
82dcb1471bSRafał Miłecki struct brcmf_pub *drvr = ifp->drvr;
837705ba6fSArend van Spriel struct brcmf_join_pref_params join_pref_params[2];
847705ba6fSArend van Spriel int err;
857705ba6fSArend van Spriel
867705ba6fSArend van Spriel /* Setup join_pref to select target by RSSI (boost on 5GHz) */
877705ba6fSArend van Spriel join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
887705ba6fSArend van Spriel join_pref_params[0].len = 2;
897705ba6fSArend van Spriel join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
907705ba6fSArend van Spriel join_pref_params[0].band = WLC_BAND_5G;
917705ba6fSArend van Spriel
927705ba6fSArend van Spriel join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
937705ba6fSArend van Spriel join_pref_params[1].len = 2;
947705ba6fSArend van Spriel join_pref_params[1].rssi_gain = 0;
957705ba6fSArend van Spriel join_pref_params[1].band = 0;
967705ba6fSArend van Spriel err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
977705ba6fSArend van Spriel sizeof(join_pref_params));
987705ba6fSArend van Spriel if (err)
99dcb1471bSRafał Miłecki bphy_err(drvr, "Set join_pref error (%d)\n", err);
1007705ba6fSArend van Spriel }
1017705ba6fSArend van Spriel
brcmf_c_download(struct brcmf_if * ifp,u16 flag,struct brcmf_dload_data_le * dload_buf,u32 len,const char * var)102fdd0bd88SChung-Hsien Hsu static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
103fdd0bd88SChung-Hsien Hsu struct brcmf_dload_data_le *dload_buf,
104dd7e5540SHector Martin u32 len, const char *var)
105fdd0bd88SChung-Hsien Hsu {
106fdd0bd88SChung-Hsien Hsu s32 err;
107fdd0bd88SChung-Hsien Hsu
108fdd0bd88SChung-Hsien Hsu flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
109fdd0bd88SChung-Hsien Hsu dload_buf->flag = cpu_to_le16(flag);
110fdd0bd88SChung-Hsien Hsu dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
111fdd0bd88SChung-Hsien Hsu dload_buf->len = cpu_to_le32(len);
112fdd0bd88SChung-Hsien Hsu dload_buf->crc = cpu_to_le32(0);
113fdd0bd88SChung-Hsien Hsu
114dd7e5540SHector Martin err = brcmf_fil_iovar_data_set(ifp, var, dload_buf,
115633a9b6fSGustavo A. R. Silva struct_size(dload_buf, data, len));
116fdd0bd88SChung-Hsien Hsu
117fdd0bd88SChung-Hsien Hsu return err;
118fdd0bd88SChung-Hsien Hsu }
119fdd0bd88SChung-Hsien Hsu
brcmf_c_download_blob(struct brcmf_if * ifp,const void * data,size_t size,const char * loadvar,const char * statvar)120dd7e5540SHector Martin static int brcmf_c_download_blob(struct brcmf_if *ifp,
121dd7e5540SHector Martin const void *data, size_t size,
122dd7e5540SHector Martin const char *loadvar, const char *statvar)
123fdd0bd88SChung-Hsien Hsu {
124dcb1471bSRafał Miłecki struct brcmf_pub *drvr = ifp->drvr;
125fdd0bd88SChung-Hsien Hsu struct brcmf_dload_data_le *chunk_buf;
126fdd0bd88SChung-Hsien Hsu u32 chunk_len;
127fdd0bd88SChung-Hsien Hsu u32 datalen;
128fdd0bd88SChung-Hsien Hsu u32 cumulative_len;
129fdd0bd88SChung-Hsien Hsu u16 dl_flag = DL_BEGIN;
130fdd0bd88SChung-Hsien Hsu u32 status;
131fdd0bd88SChung-Hsien Hsu s32 err;
132fdd0bd88SChung-Hsien Hsu
133fdd0bd88SChung-Hsien Hsu brcmf_dbg(TRACE, "Enter\n");
134fdd0bd88SChung-Hsien Hsu
135633a9b6fSGustavo A. R. Silva chunk_buf = kzalloc(struct_size(chunk_buf, data, MAX_CHUNK_LEN),
136633a9b6fSGustavo A. R. Silva GFP_KERNEL);
137fdd0bd88SChung-Hsien Hsu if (!chunk_buf) {
138fdd0bd88SChung-Hsien Hsu err = -ENOMEM;
139dd7e5540SHector Martin return -ENOMEM;
140fdd0bd88SChung-Hsien Hsu }
141fdd0bd88SChung-Hsien Hsu
142dd7e5540SHector Martin datalen = size;
143fdd0bd88SChung-Hsien Hsu cumulative_len = 0;
144fdd0bd88SChung-Hsien Hsu do {
145fdd0bd88SChung-Hsien Hsu if (datalen > MAX_CHUNK_LEN) {
146fdd0bd88SChung-Hsien Hsu chunk_len = MAX_CHUNK_LEN;
147fdd0bd88SChung-Hsien Hsu } else {
148fdd0bd88SChung-Hsien Hsu chunk_len = datalen;
149fdd0bd88SChung-Hsien Hsu dl_flag |= DL_END;
150fdd0bd88SChung-Hsien Hsu }
151dd7e5540SHector Martin memcpy(chunk_buf->data, data + cumulative_len, chunk_len);
152fdd0bd88SChung-Hsien Hsu
153dd7e5540SHector Martin err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len,
154dd7e5540SHector Martin loadvar);
155fdd0bd88SChung-Hsien Hsu
156fdd0bd88SChung-Hsien Hsu dl_flag &= ~DL_BEGIN;
157fdd0bd88SChung-Hsien Hsu
158fdd0bd88SChung-Hsien Hsu cumulative_len += chunk_len;
159fdd0bd88SChung-Hsien Hsu datalen -= chunk_len;
160fdd0bd88SChung-Hsien Hsu } while ((datalen > 0) && (err == 0));
161fdd0bd88SChung-Hsien Hsu
162fdd0bd88SChung-Hsien Hsu if (err) {
163dd7e5540SHector Martin bphy_err(drvr, "%s (%zu byte file) failed (%d)\n",
164dd7e5540SHector Martin loadvar, size, err);
165dd7e5540SHector Martin /* Retrieve status and print */
166dd7e5540SHector Martin err = brcmf_fil_iovar_int_get(ifp, statvar, &status);
167fdd0bd88SChung-Hsien Hsu if (err)
168dd7e5540SHector Martin bphy_err(drvr, "get %s failed (%d)\n", statvar, err);
169fdd0bd88SChung-Hsien Hsu else
170dd7e5540SHector Martin brcmf_dbg(INFO, "%s=%d\n", statvar, status);
171fdd0bd88SChung-Hsien Hsu err = -EIO;
172fdd0bd88SChung-Hsien Hsu }
173fdd0bd88SChung-Hsien Hsu
174fdd0bd88SChung-Hsien Hsu kfree(chunk_buf);
175dd7e5540SHector Martin return err;
176dd7e5540SHector Martin }
177dd7e5540SHector Martin
brcmf_c_process_clm_blob(struct brcmf_if * ifp)178dd7e5540SHector Martin static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
179dd7e5540SHector Martin {
180dd7e5540SHector Martin struct brcmf_pub *drvr = ifp->drvr;
181dd7e5540SHector Martin struct brcmf_bus *bus = drvr->bus_if;
182dd7e5540SHector Martin const struct firmware *fw = NULL;
183dd7e5540SHector Martin s32 err;
184dd7e5540SHector Martin
185dd7e5540SHector Martin brcmf_dbg(TRACE, "Enter\n");
186dd7e5540SHector Martin
187dd7e5540SHector Martin err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_CLM);
188dd7e5540SHector Martin if (err || !fw) {
189dd7e5540SHector Martin brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
190dd7e5540SHector Martin err);
191dd7e5540SHector Martin return 0;
192dd7e5540SHector Martin }
193dd7e5540SHector Martin
194dd7e5540SHector Martin err = brcmf_c_download_blob(ifp, fw->data, fw->size,
195dd7e5540SHector Martin "clmload", "clmload_status");
196dd7e5540SHector Martin
197dd7e5540SHector Martin release_firmware(fw);
198dd7e5540SHector Martin return err;
199dd7e5540SHector Martin }
200dd7e5540SHector Martin
brcmf_c_process_txcap_blob(struct brcmf_if * ifp)201dd7e5540SHector Martin static int brcmf_c_process_txcap_blob(struct brcmf_if *ifp)
202dd7e5540SHector Martin {
203dd7e5540SHector Martin struct brcmf_pub *drvr = ifp->drvr;
204dd7e5540SHector Martin struct brcmf_bus *bus = drvr->bus_if;
205dd7e5540SHector Martin const struct firmware *fw = NULL;
206dd7e5540SHector Martin s32 err;
207dd7e5540SHector Martin
208dd7e5540SHector Martin brcmf_dbg(TRACE, "Enter\n");
209dd7e5540SHector Martin
210dd7e5540SHector Martin err = brcmf_bus_get_blob(bus, &fw, BRCMF_BLOB_TXCAP);
211dd7e5540SHector Martin if (err || !fw) {
212dd7e5540SHector Martin brcmf_info("no txcap_blob available (err=%d)\n", err);
213dd7e5540SHector Martin return 0;
214dd7e5540SHector Martin }
215dd7e5540SHector Martin
216dd7e5540SHector Martin brcmf_info("TxCap blob found, loading\n");
217dd7e5540SHector Martin err = brcmf_c_download_blob(ifp, fw->data, fw->size,
218dd7e5540SHector Martin "txcapload", "txcapload_status");
219dd7e5540SHector Martin
220dd7e5540SHector Martin release_firmware(fw);
221fdd0bd88SChung-Hsien Hsu return err;
222fdd0bd88SChung-Hsien Hsu }
223fdd0bd88SChung-Hsien Hsu
brcmf_c_set_cur_etheraddr(struct brcmf_if * ifp,const u8 * addr)224cf1239e5SHans de Goede int brcmf_c_set_cur_etheraddr(struct brcmf_if *ifp, const u8 *addr)
225cf1239e5SHans de Goede {
226cf1239e5SHans de Goede s32 err;
227cf1239e5SHans de Goede
228cf1239e5SHans de Goede err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", addr, ETH_ALEN);
229cf1239e5SHans de Goede if (err < 0)
230cf1239e5SHans de Goede bphy_err(ifp->drvr, "Setting cur_etheraddr failed, %d\n", err);
231cf1239e5SHans de Goede
232cf1239e5SHans de Goede return err;
233cf1239e5SHans de Goede }
234cf1239e5SHans de Goede
2354af4c0b9SHans de Goede /* On some boards there is no eeprom to hold the nvram, in this case instead
2364af4c0b9SHans de Goede * a board specific nvram is loaded from /lib/firmware. On most boards the
2374af4c0b9SHans de Goede * macaddr setting in the /lib/firmware nvram file is ignored because the
2384af4c0b9SHans de Goede * wifibt chip has a unique MAC programmed into the chip itself.
2394af4c0b9SHans de Goede * But in some cases the actual MAC from the /lib/firmware nvram file gets
2404af4c0b9SHans de Goede * used, leading to MAC conflicts.
2414af4c0b9SHans de Goede * The MAC addresses in the troublesome nvram files seem to all come from
2424af4c0b9SHans de Goede * the same nvram file template, so we only need to check for 1 known
2434af4c0b9SHans de Goede * address to detect this.
2444af4c0b9SHans de Goede */
2454af4c0b9SHans de Goede static const u8 brcmf_default_mac_address[ETH_ALEN] = {
2464af4c0b9SHans de Goede 0x00, 0x90, 0x4c, 0xc5, 0x12, 0x38
2474af4c0b9SHans de Goede };
2484af4c0b9SHans de Goede
brcmf_c_process_cal_blob(struct brcmf_if * ifp)249*5b3ee998SHector Martin static int brcmf_c_process_cal_blob(struct brcmf_if *ifp)
250*5b3ee998SHector Martin {
251*5b3ee998SHector Martin struct brcmf_pub *drvr = ifp->drvr;
252*5b3ee998SHector Martin struct brcmf_mp_device *settings = drvr->settings;
253*5b3ee998SHector Martin s32 err;
254*5b3ee998SHector Martin
255*5b3ee998SHector Martin brcmf_dbg(TRACE, "Enter\n");
256*5b3ee998SHector Martin
257*5b3ee998SHector Martin if (!settings->cal_blob || !settings->cal_size)
258*5b3ee998SHector Martin return 0;
259*5b3ee998SHector Martin
260*5b3ee998SHector Martin brcmf_info("Calibration blob provided by platform, loading\n");
261*5b3ee998SHector Martin err = brcmf_c_download_blob(ifp, settings->cal_blob, settings->cal_size,
262*5b3ee998SHector Martin "calload", "calload_status");
263*5b3ee998SHector Martin return err;
264*5b3ee998SHector Martin }
265*5b3ee998SHector Martin
brcmf_c_preinit_dcmds(struct brcmf_if * ifp)26605491d2cSKalle Valo int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
26705491d2cSKalle Valo {
268dcb1471bSRafał Miłecki struct brcmf_pub *drvr = ifp->drvr;
26905491d2cSKalle Valo s8 eventmask[BRCMF_EVENTING_MASK_LEN];
27005491d2cSKalle Valo u8 buf[BRCMF_DCMD_SMLEN];
271756a2b39SArend Van Spriel struct brcmf_bus *bus;
27205491d2cSKalle Valo struct brcmf_rev_info_le revinfo;
27305491d2cSKalle Valo struct brcmf_rev_info *ri;
274fdd0bd88SChung-Hsien Hsu char *clmver;
27505491d2cSKalle Valo char *ptr;
27605491d2cSKalle Valo s32 err;
27705491d2cSKalle Valo
278716c220bSPavel Löbl if (is_valid_ether_addr(ifp->mac_addr)) {
279716c220bSPavel Löbl /* set mac address */
280cf1239e5SHans de Goede err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
281cf1239e5SHans de Goede if (err < 0)
282716c220bSPavel Löbl goto done;
283716c220bSPavel Löbl } else {
284716c220bSPavel Löbl /* retrieve mac address */
28505491d2cSKalle Valo err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
28605491d2cSKalle Valo sizeof(ifp->mac_addr));
28705491d2cSKalle Valo if (err < 0) {
288dcb1471bSRafał Miłecki bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err);
28905491d2cSKalle Valo goto done;
29005491d2cSKalle Valo }
2914af4c0b9SHans de Goede
2924af4c0b9SHans de Goede if (ether_addr_equal_unaligned(ifp->mac_addr, brcmf_default_mac_address)) {
2934af4c0b9SHans de Goede bphy_err(drvr, "Default MAC is used, replacing with random MAC to avoid conflicts\n");
2944af4c0b9SHans de Goede eth_random_addr(ifp->mac_addr);
2954af4c0b9SHans de Goede ifp->ndev->addr_assign_type = NET_ADDR_RANDOM;
2964af4c0b9SHans de Goede err = brcmf_c_set_cur_etheraddr(ifp, ifp->mac_addr);
2974af4c0b9SHans de Goede if (err < 0)
2984af4c0b9SHans de Goede goto done;
2994af4c0b9SHans de Goede }
300716c220bSPavel Löbl }
301716c220bSPavel Löbl
30205491d2cSKalle Valo memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
3031eb4e9f6SWright Feng memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
30405491d2cSKalle Valo
305756a2b39SArend Van Spriel bus = ifp->drvr->bus_if;
306756a2b39SArend Van Spriel ri = &ifp->drvr->revinfo;
307756a2b39SArend Van Spriel
30805491d2cSKalle Valo err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,
30905491d2cSKalle Valo &revinfo, sizeof(revinfo));
31005491d2cSKalle Valo if (err < 0) {
311dcb1471bSRafał Miłecki bphy_err(drvr, "retrieving revision info failed, %d\n", err);
312bf99f11dSWolfram Sang strscpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname));
31305491d2cSKalle Valo } else {
31405491d2cSKalle Valo ri->vendorid = le32_to_cpu(revinfo.vendorid);
31505491d2cSKalle Valo ri->deviceid = le32_to_cpu(revinfo.deviceid);
31605491d2cSKalle Valo ri->radiorev = le32_to_cpu(revinfo.radiorev);
31705491d2cSKalle Valo ri->corerev = le32_to_cpu(revinfo.corerev);
31805491d2cSKalle Valo ri->boardid = le32_to_cpu(revinfo.boardid);
31905491d2cSKalle Valo ri->boardvendor = le32_to_cpu(revinfo.boardvendor);
32005491d2cSKalle Valo ri->boardrev = le32_to_cpu(revinfo.boardrev);
32105491d2cSKalle Valo ri->driverrev = le32_to_cpu(revinfo.driverrev);
32205491d2cSKalle Valo ri->ucoderev = le32_to_cpu(revinfo.ucoderev);
32305491d2cSKalle Valo ri->bus = le32_to_cpu(revinfo.bus);
32405491d2cSKalle Valo ri->phytype = le32_to_cpu(revinfo.phytype);
32505491d2cSKalle Valo ri->phyrev = le32_to_cpu(revinfo.phyrev);
32605491d2cSKalle Valo ri->anarev = le32_to_cpu(revinfo.anarev);
32705491d2cSKalle Valo ri->chippkg = le32_to_cpu(revinfo.chippkg);
32805491d2cSKalle Valo ri->nvramrev = le32_to_cpu(revinfo.nvramrev);
329756a2b39SArend Van Spriel
330856d5a01SArend Van Spriel /* use revinfo if not known yet */
331756a2b39SArend Van Spriel if (!bus->chip) {
332756a2b39SArend Van Spriel bus->chip = le32_to_cpu(revinfo.chipnum);
333756a2b39SArend Van Spriel bus->chiprev = le32_to_cpu(revinfo.chiprev);
334756a2b39SArend Van Spriel }
33505491d2cSKalle Valo }
33605491d2cSKalle Valo ri->result = err;
33705491d2cSKalle Valo
338756a2b39SArend Van Spriel if (bus->chip)
339756a2b39SArend Van Spriel brcmf_chip_name(bus->chip, bus->chiprev,
340756a2b39SArend Van Spriel ri->chipname, sizeof(ri->chipname));
341756a2b39SArend Van Spriel
342fdd0bd88SChung-Hsien Hsu /* Do any CLM downloading */
343fdd0bd88SChung-Hsien Hsu err = brcmf_c_process_clm_blob(ifp);
344fdd0bd88SChung-Hsien Hsu if (err < 0) {
345dcb1471bSRafał Miłecki bphy_err(drvr, "download CLM blob file failed, %d\n", err);
346fdd0bd88SChung-Hsien Hsu goto done;
347fdd0bd88SChung-Hsien Hsu }
348fdd0bd88SChung-Hsien Hsu
349dd7e5540SHector Martin /* Do TxCap downloading, if needed */
350dd7e5540SHector Martin err = brcmf_c_process_txcap_blob(ifp);
351dd7e5540SHector Martin if (err < 0) {
352dd7e5540SHector Martin bphy_err(drvr, "download TxCap blob file failed, %d\n", err);
353dd7e5540SHector Martin goto done;
354dd7e5540SHector Martin }
355dd7e5540SHector Martin
356*5b3ee998SHector Martin /* Download external calibration blob, if available */
357*5b3ee998SHector Martin err = brcmf_c_process_cal_blob(ifp);
358*5b3ee998SHector Martin if (err < 0) {
359*5b3ee998SHector Martin bphy_err(drvr, "download calibration blob file failed, %d\n", err);
360*5b3ee998SHector Martin goto done;
361*5b3ee998SHector Martin }
362*5b3ee998SHector Martin
36305491d2cSKalle Valo /* query for 'ver' to get version info from firmware */
36405491d2cSKalle Valo memset(buf, 0, sizeof(buf));
36505491d2cSKalle Valo err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
36605491d2cSKalle Valo if (err < 0) {
367dcb1471bSRafał Miłecki bphy_err(drvr, "Retrieving version information failed, %d\n",
36805491d2cSKalle Valo err);
36905491d2cSKalle Valo goto done;
37005491d2cSKalle Valo }
3710a06cadcSJisoo Jang buf[sizeof(buf) - 1] = '\0';
37205491d2cSKalle Valo ptr = (char *)buf;
37305491d2cSKalle Valo strsep(&ptr, "\n");
37405491d2cSKalle Valo
37505491d2cSKalle Valo /* Print fw version info */
376756a2b39SArend Van Spriel brcmf_info("Firmware: %s %s\n", ri->chipname, buf);
37705491d2cSKalle Valo
37805491d2cSKalle Valo /* locate firmware version number for ethtool */
379683b9728SJisoo Jang ptr = strrchr(buf, ' ');
380683b9728SJisoo Jang if (!ptr) {
381683b9728SJisoo Jang bphy_err(drvr, "Retrieving version number failed");
382683b9728SJisoo Jang goto done;
383683b9728SJisoo Jang }
384683b9728SJisoo Jang strscpy(ifp->drvr->fwver, ptr + 1, sizeof(ifp->drvr->fwver));
38505491d2cSKalle Valo
386fdd0bd88SChung-Hsien Hsu /* Query for 'clmver' to get CLM version info from firmware */
387fdd0bd88SChung-Hsien Hsu memset(buf, 0, sizeof(buf));
388fdd0bd88SChung-Hsien Hsu err = brcmf_fil_iovar_data_get(ifp, "clmver", buf, sizeof(buf));
389fdd0bd88SChung-Hsien Hsu if (err) {
390fdd0bd88SChung-Hsien Hsu brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err);
391fdd0bd88SChung-Hsien Hsu } else {
392660145d7SJisoo Jang buf[sizeof(buf) - 1] = '\0';
393fdd0bd88SChung-Hsien Hsu clmver = (char *)buf;
394fdd0bd88SChung-Hsien Hsu
395fdd0bd88SChung-Hsien Hsu /* Replace all newline/linefeed characters with space
396fdd0bd88SChung-Hsien Hsu * character
397fdd0bd88SChung-Hsien Hsu */
398cb18e2e9SRasmus Villemoes strreplace(clmver, '\n', ' ');
399fdd0bd88SChung-Hsien Hsu
400660145d7SJisoo Jang /* store CLM version for adding it to revinfo debugfs file */
401660145d7SJisoo Jang memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));
402660145d7SJisoo Jang
403fdd0bd88SChung-Hsien Hsu brcmf_dbg(INFO, "CLM version = %s\n", clmver);
404fdd0bd88SChung-Hsien Hsu }
405fdd0bd88SChung-Hsien Hsu
40605491d2cSKalle Valo /* set mpc */
40705491d2cSKalle Valo err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
40805491d2cSKalle Valo if (err) {
409dcb1471bSRafał Miłecki bphy_err(drvr, "failed setting mpc\n");
41005491d2cSKalle Valo goto done;
41105491d2cSKalle Valo }
41205491d2cSKalle Valo
4137705ba6fSArend van Spriel brcmf_c_set_joinpref_default(ifp);
41405491d2cSKalle Valo
41505491d2cSKalle Valo /* Setup event_msgs, enable E_IF */
41605491d2cSKalle Valo err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
41705491d2cSKalle Valo BRCMF_EVENTING_MASK_LEN);
41805491d2cSKalle Valo if (err) {
419dcb1471bSRafał Miłecki bphy_err(drvr, "Get event_msgs error (%d)\n", err);
42005491d2cSKalle Valo goto done;
42105491d2cSKalle Valo }
42205491d2cSKalle Valo setbit(eventmask, BRCMF_E_IF);
42305491d2cSKalle Valo err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
42405491d2cSKalle Valo BRCMF_EVENTING_MASK_LEN);
42505491d2cSKalle Valo if (err) {
426dcb1471bSRafał Miłecki bphy_err(drvr, "Set event_msgs error (%d)\n", err);
42705491d2cSKalle Valo goto done;
42805491d2cSKalle Valo }
42905491d2cSKalle Valo
43005491d2cSKalle Valo /* Setup default scan channel time */
43105491d2cSKalle Valo err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
43205491d2cSKalle Valo BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
43305491d2cSKalle Valo if (err) {
434dcb1471bSRafał Miłecki bphy_err(drvr, "BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
43505491d2cSKalle Valo err);
43605491d2cSKalle Valo goto done;
43705491d2cSKalle Valo }
43805491d2cSKalle Valo
43905491d2cSKalle Valo /* Setup default scan unassoc time */
44005491d2cSKalle Valo err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
44105491d2cSKalle Valo BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
44205491d2cSKalle Valo if (err) {
443dcb1471bSRafał Miłecki bphy_err(drvr, "BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
44405491d2cSKalle Valo err);
44505491d2cSKalle Valo goto done;
44605491d2cSKalle Valo }
44705491d2cSKalle Valo
4487bf65aa9SHante Meuleman /* Enable tx beamforming, errors can be ignored (not supported) */
4497bf65aa9SHante Meuleman (void)brcmf_fil_iovar_int_set(ifp, "txbf", 1);
45005491d2cSKalle Valo done:
45105491d2cSKalle Valo return err;
45205491d2cSKalle Valo }
45305491d2cSKalle Valo
454087fa712SRafał Miłecki #ifndef CONFIG_BRCM_TRACING
__brcmf_err(struct brcmf_bus * bus,const char * func,const char * fmt,...)4555cc898fbSRafał Miłecki void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...)
456087fa712SRafał Miłecki {
457087fa712SRafał Miłecki struct va_format vaf;
458087fa712SRafał Miłecki va_list args;
459087fa712SRafał Miłecki
460087fa712SRafał Miłecki va_start(args, fmt);
461087fa712SRafał Miłecki
462087fa712SRafał Miłecki vaf.fmt = fmt;
463087fa712SRafał Miłecki vaf.va = &args;
4645cc898fbSRafał Miłecki if (bus)
4655cc898fbSRafał Miłecki dev_err(bus->dev, "%s: %pV", func, &vaf);
4665cc898fbSRafał Miłecki else
467087fa712SRafał Miłecki pr_err("%s: %pV", func, &vaf);
468087fa712SRafał Miłecki
469087fa712SRafał Miłecki va_end(args);
470087fa712SRafał Miłecki }
471087fa712SRafał Miłecki #endif
472087fa712SRafał Miłecki
47305491d2cSKalle Valo #if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
__brcmf_dbg(u32 level,const char * func,const char * fmt,...)47405491d2cSKalle Valo void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
47505491d2cSKalle Valo {
47605491d2cSKalle Valo struct va_format vaf = {
47705491d2cSKalle Valo .fmt = fmt,
47805491d2cSKalle Valo };
47905491d2cSKalle Valo va_list args;
48005491d2cSKalle Valo
48105491d2cSKalle Valo va_start(args, fmt);
48205491d2cSKalle Valo vaf.va = &args;
48305491d2cSKalle Valo if (brcmf_msg_level & level)
48405491d2cSKalle Valo pr_debug("%s %pV", func, &vaf);
48505491d2cSKalle Valo trace_brcmf_dbg(level, func, &vaf);
48605491d2cSKalle Valo va_end(args);
48705491d2cSKalle Valo }
48805491d2cSKalle Valo #endif
4897d34b056SHante Meuleman
brcmf_mp_attach(void)490d84d99e0SHante Meuleman static void brcmf_mp_attach(void)
4917d34b056SHante Meuleman {
4924d792895SHante Meuleman /* If module param firmware path is set then this will always be used,
4934d792895SHante Meuleman * if not set then if available use the platform data version. To make
4944d792895SHante Meuleman * sure it gets initialized at all, always copy the module param version
4954d792895SHante Meuleman */
496bf99f11dSWolfram Sang strscpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
4977d34b056SHante Meuleman BRCMF_FW_ALTPATH_LEN);
4984d792895SHante Meuleman if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
4994d792895SHante Meuleman (brcmf_mp_global.firmware_path[0] == '\0')) {
500bf99f11dSWolfram Sang strscpy(brcmf_mp_global.firmware_path,
5014d792895SHante Meuleman brcmfmac_pdata->fw_alternative_path,
5024d792895SHante Meuleman BRCMF_FW_ALTPATH_LEN);
5034d792895SHante Meuleman }
5047d34b056SHante Meuleman }
5057d34b056SHante Meuleman
brcmf_get_module_param(struct device * dev,enum brcmf_bus_type bus_type,u32 chip,u32 chiprev)506af5b5e62SHante Meuleman struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
5074d792895SHante Meuleman enum brcmf_bus_type bus_type,
5084d792895SHante Meuleman u32 chip, u32 chiprev)
5098ea56be0SHante Meuleman {
510af5b5e62SHante Meuleman struct brcmf_mp_device *settings;
5114d792895SHante Meuleman struct brcmfmac_pd_device *device_pd;
512af5b5e62SHante Meuleman bool found;
5134d792895SHante Meuleman int i;
5144d792895SHante Meuleman
515af5b5e62SHante Meuleman brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip,
516af5b5e62SHante Meuleman chiprev);
517af5b5e62SHante Meuleman settings = kzalloc(sizeof(*settings), GFP_ATOMIC);
518af5b5e62SHante Meuleman if (!settings)
519af5b5e62SHante Meuleman return NULL;
520af5b5e62SHante Meuleman
521af5b5e62SHante Meuleman /* start by using the module paramaters */
522af5b5e62SHante Meuleman settings->p2p_enable = !!brcmf_p2p_enable;
523af5b5e62SHante Meuleman settings->feature_disable = brcmf_feature_disable;
524af5b5e62SHante Meuleman settings->fcmode = brcmf_fcmode;
525af5b5e62SHante Meuleman settings->roamoff = !!brcmf_roamoff;
52612590551SRafał Miłecki settings->iapp = !!brcmf_iapp_enable;
527af5b5e62SHante Meuleman #ifdef DEBUG
528af5b5e62SHante Meuleman settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
529af5b5e62SHante Meuleman #endif
530af5b5e62SHante Meuleman
531af5b5e62SHante Meuleman if (bus_type == BRCMF_BUSTYPE_SDIO)
532af5b5e62SHante Meuleman settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
533af5b5e62SHante Meuleman
534af5b5e62SHante Meuleman /* See if there is any device specific platform data configured */
535af5b5e62SHante Meuleman found = false;
5364d792895SHante Meuleman if (brcmfmac_pdata) {
5374d792895SHante Meuleman for (i = 0; i < brcmfmac_pdata->device_count; i++) {
5384d792895SHante Meuleman device_pd = &brcmfmac_pdata->devices[i];
5394d792895SHante Meuleman if ((device_pd->bus_type == bus_type) &&
5404d792895SHante Meuleman (device_pd->id == chip) &&
5414d792895SHante Meuleman ((device_pd->rev == chiprev) ||
5424d792895SHante Meuleman (device_pd->rev == -1))) {
5434d792895SHante Meuleman brcmf_dbg(INFO, "Platform data for device found\n");
544af5b5e62SHante Meuleman settings->country_codes =
545af5b5e62SHante Meuleman device_pd->country_codes;
5464d792895SHante Meuleman if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO)
547af5b5e62SHante Meuleman memcpy(&settings->bus.sdio,
548af5b5e62SHante Meuleman &device_pd->bus.sdio,
549af5b5e62SHante Meuleman sizeof(settings->bus.sdio));
550af5b5e62SHante Meuleman found = true;
5514d792895SHante Meuleman break;
5524d792895SHante Meuleman }
5534d792895SHante Meuleman }
5544d792895SHante Meuleman }
555e457a8a0SRafał Miłecki if (!found) {
556bd1e82bbSHans de Goede /* No platform data for this device, try OF and DMI data */
557bd1e82bbSHans de Goede brcmf_dmi_probe(settings, chip, chiprev);
558554da386SHans de Goede brcmf_of_probe(dev, bus_type, settings);
5590f485805SHector Martin brcmf_acpi_probe(dev, bus_type, settings);
560af5b5e62SHante Meuleman }
561af5b5e62SHante Meuleman return settings;
5628ea56be0SHante Meuleman }
5638ea56be0SHante Meuleman
brcmf_release_module_param(struct brcmf_mp_device * module_param)564af5b5e62SHante Meuleman void brcmf_release_module_param(struct brcmf_mp_device *module_param)
5657d34b056SHante Meuleman {
566af5b5e62SHante Meuleman kfree(module_param);
5677d34b056SHante Meuleman }
5687d34b056SHante Meuleman
brcmf_common_pd_probe(struct platform_device * pdev)5698ea56be0SHante Meuleman static int __init brcmf_common_pd_probe(struct platform_device *pdev)
5708ea56be0SHante Meuleman {
5718ea56be0SHante Meuleman brcmf_dbg(INFO, "Enter\n");
5728ea56be0SHante Meuleman
5738ea56be0SHante Meuleman brcmfmac_pdata = dev_get_platdata(&pdev->dev);
5748ea56be0SHante Meuleman
5758ea56be0SHante Meuleman if (brcmfmac_pdata->power_on)
5768ea56be0SHante Meuleman brcmfmac_pdata->power_on();
5778ea56be0SHante Meuleman
5788ea56be0SHante Meuleman return 0;
5798ea56be0SHante Meuleman }
5808ea56be0SHante Meuleman
brcmf_common_pd_remove(struct platform_device * pdev)5818ea56be0SHante Meuleman static int brcmf_common_pd_remove(struct platform_device *pdev)
5828ea56be0SHante Meuleman {
5838ea56be0SHante Meuleman brcmf_dbg(INFO, "Enter\n");
5848ea56be0SHante Meuleman
5858ea56be0SHante Meuleman if (brcmfmac_pdata->power_off)
5868ea56be0SHante Meuleman brcmfmac_pdata->power_off();
5878ea56be0SHante Meuleman
5888ea56be0SHante Meuleman return 0;
5898ea56be0SHante Meuleman }
5908ea56be0SHante Meuleman
5918ea56be0SHante Meuleman static struct platform_driver brcmf_pd = {
5928ea56be0SHante Meuleman .remove = brcmf_common_pd_remove,
5938ea56be0SHante Meuleman .driver = {
5944d792895SHante Meuleman .name = BRCMFMAC_PDATA_NAME,
5958ea56be0SHante Meuleman }
5968ea56be0SHante Meuleman };
5978ea56be0SHante Meuleman
brcmfmac_module_init(void)598d84d99e0SHante Meuleman static int __init brcmfmac_module_init(void)
599d84d99e0SHante Meuleman {
600d84d99e0SHante Meuleman int err;
601d84d99e0SHante Meuleman
6028ea56be0SHante Meuleman /* Get the platform data (if available) for our devices */
6038ea56be0SHante Meuleman err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
6048ea56be0SHante Meuleman if (err == -ENODEV)
6058ea56be0SHante Meuleman brcmf_dbg(INFO, "No platform data available.\n");
6068ea56be0SHante Meuleman
607d84d99e0SHante Meuleman /* Initialize global module paramaters */
608d84d99e0SHante Meuleman brcmf_mp_attach();
609d84d99e0SHante Meuleman
610d84d99e0SHante Meuleman /* Continue the initialization by registering the different busses */
611d84d99e0SHante Meuleman err = brcmf_core_init();
6128ea56be0SHante Meuleman if (err) {
6138ea56be0SHante Meuleman if (brcmfmac_pdata)
6148ea56be0SHante Meuleman platform_driver_unregister(&brcmf_pd);
6158ea56be0SHante Meuleman }
616d84d99e0SHante Meuleman
617d84d99e0SHante Meuleman return err;
618d84d99e0SHante Meuleman }
619d84d99e0SHante Meuleman
brcmfmac_module_exit(void)620d84d99e0SHante Meuleman static void __exit brcmfmac_module_exit(void)
621d84d99e0SHante Meuleman {
622d84d99e0SHante Meuleman brcmf_core_exit();
6238ea56be0SHante Meuleman if (brcmfmac_pdata)
6248ea56be0SHante Meuleman platform_driver_unregister(&brcmf_pd);
625d84d99e0SHante Meuleman }
626d84d99e0SHante Meuleman
627d84d99e0SHante Meuleman module_init(brcmfmac_module_init);
628d84d99e0SHante Meuleman module_exit(brcmfmac_module_exit);
629d84d99e0SHante Meuleman
630