]> git.ipfire.org Git - thirdparty/openwrt.git/blob
1e2016bcadec7b43abb4114ac39e974eab0e4216
[thirdparty/openwrt.git] /
1 From e7400640cafcf6bd84049308feb5aeabecf55b46 Mon Sep 17 00:00:00 2001
2 From: Praveen Babu C <pucn@cypress.com>
3 Date: Tue, 9 Jan 2018 11:33:10 +0530
4 Subject: [PATCH] non-upstream: support DS1 exit firmware re-download
5
6 In deep sleep mode (DS1) ARM is off and once exit trigger comes than
7 mailbox Interrupt comes to host and whole reinitiation should be done
8 in the ARM to start TX/RX.
9
10 Also fix below issus for DS1 exit:
11 1. Sent Tx Control frame only after firmware redownload complete (check
12 F2 Ready before sending Tx Control frame to Firmware)
13 2. intermittent High DS1 TX Exit latency time (almost 3sec) ==> This is
14 fixed by skipping host Mailbox interrupt Multiple times (ulp state
15 mechanism)
16 3. RX GlOM save/restore in Firmware
17 4. Add ULP event enable & event_msgs_ext iovar configuration in FMAC
18 5. Add ULP_EVENT_RECV state machine for sbwad support
19 6. Support 2 Byte Shared memory read for DS1 Exit HUDI implementation
20
21 Signed-off-by: Praveen Babu C <pucn@cypress.com>
22 Signed-off-by: Naveen Gupta <nagu@cypress.com>
23 [Merge from 4.14.77 to 5.4.18; set BRCMF_SDIO_MAX_ACCESS_ERRORS to 20]
24 Signed-off-by: Chi-hsien Lin <chi-hsien.lin@cypress.com>
25 JIRA: SWWLAN-135583
26 JIRA: SWWLAN-136577
27 ---
28 .../broadcom/brcm80211/brcmfmac/bus.h | 2 +-
29 .../broadcom/brcm80211/brcmfmac/common.c | 39 +++
30 .../broadcom/brcm80211/brcmfmac/core.c | 13 +-
31 .../broadcom/brcm80211/brcmfmac/debug.h | 1 +
32 .../broadcom/brcm80211/brcmfmac/fweh.h | 31 ++-
33 .../broadcom/brcm80211/brcmfmac/pcie.c | 2 +-
34 .../broadcom/brcm80211/brcmfmac/sdio.c | 260 +++++++++++++++++-
35 .../broadcom/brcm80211/brcmfmac/sdio.h | 110 ++++++++
36 .../broadcom/brcm80211/brcmfmac/usb.c | 4 +-
37 .../broadcom/brcm80211/include/chipcommon.h | 2 +
38 10 files changed, 448 insertions(+), 16 deletions(-)
39
40 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
41 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
42 @@ -298,7 +298,7 @@ void brcmf_rx_event(struct device *dev,
43
44 int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings);
45 /* Indication from bus module regarding presence/insertion of dongle. */
46 -int brcmf_attach(struct device *dev);
47 +int brcmf_attach(struct device *dev, bool start_bus);
48 /* Indication from bus module regarding removal/absence of dongle */
49 void brcmf_detach(struct device *dev);
50 void brcmf_free(struct device *dev);
51 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
52 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
53 @@ -20,6 +20,8 @@
54 #include "of.h"
55 #include "firmware.h"
56 #include "chip.h"
57 +#include "fweh.h"
58 +#include <brcm_hw_ids.h>
59
60 MODULE_AUTHOR("Broadcom Corporation");
61 MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
62 @@ -274,6 +276,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_i
63 char *clmver;
64 char *ptr;
65 s32 err;
66 + struct eventmsgs_ext *eventmask_msg = NULL;
67 + u8 msglen;
68
69 if (is_valid_ether_addr(ifp->mac_addr)) {
70 /* set mac address */
71 @@ -433,6 +437,41 @@ int brcmf_c_preinit_dcmds(struct brcmf_i
72 goto done;
73 }
74
75 + /* Enable event_msg_ext specific to 43012 chip */
76 + if (bus->chip == CY_CC_43012_CHIP_ID) {
77 + /* Program event_msg_ext to support event larger than 128 */
78 + msglen = (roundup(BRCMF_E_LAST, NBBY) / NBBY) +
79 + EVENTMSGS_EXT_STRUCT_SIZE;
80 + /* Allocate buffer for eventmask_msg */
81 + eventmask_msg = kzalloc(msglen, GFP_KERNEL);
82 + if (!eventmask_msg) {
83 + err = -ENOMEM;
84 + goto done;
85 + }
86 +
87 + /* Read the current programmed event_msgs_ext */
88 + eventmask_msg->ver = EVENTMSGS_VER;
89 + eventmask_msg->len = roundup(BRCMF_E_LAST, NBBY) / NBBY;
90 + err = brcmf_fil_iovar_data_get(ifp, "event_msgs_ext",
91 + eventmask_msg,
92 + msglen);
93 +
94 + /* Enable ULP event */
95 + brcmf_dbg(EVENT, "enable event ULP\n");
96 + setbit(eventmask_msg->mask, BRCMF_E_ULP);
97 +
98 + /* Write updated Event mask */
99 + eventmask_msg->ver = EVENTMSGS_VER;
100 + eventmask_msg->command = EVENTMSGS_SET_MASK;
101 + eventmask_msg->len = (roundup(BRCMF_E_LAST, NBBY) / NBBY);
102 +
103 + err = brcmf_fil_iovar_data_set(ifp, "event_msgs_ext",
104 + eventmask_msg, msglen);
105 + if (err) {
106 + brcmf_err("Set event_msgs_ext error (%d)\n", err);
107 + goto done;
108 + }
109 + }
110 /* Setup default scan channel time */
111 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
112 BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
113 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
114 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
115 @@ -1317,7 +1317,7 @@ int brcmf_alloc(struct device *dev, stru
116 return 0;
117 }
118
119 -int brcmf_attach(struct device *dev)
120 +int brcmf_attach(struct device *dev, bool start_bus)
121 {
122 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
123 struct brcmf_pub *drvr = bus_if->drvr;
124 @@ -1358,10 +1358,13 @@ int brcmf_attach(struct device *dev)
125 brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
126 brcmf_psm_watchdog_notify);
127
128 - ret = brcmf_bus_started(drvr, drvr->ops);
129 - if (ret != 0) {
130 - bphy_err(drvr, "dongle is not responding: err=%d\n", ret);
131 - goto fail;
132 + if (start_bus) {
133 + ret = brcmf_bus_started(drvr, drvr->ops);
134 + if (ret != 0) {
135 + bphy_err(drvr, "dongle is not responding: err=%d\n",
136 + ret);
137 + goto fail;
138 + }
139 }
140
141 return 0;
142 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
143 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
144 @@ -29,6 +29,7 @@
145 #define BRCMF_MSGBUF_VAL 0x00040000
146 #define BRCMF_PCIE_VAL 0x00080000
147 #define BRCMF_FWCON_VAL 0x00100000
148 +#define BRCMF_ULP_VAL 0x00200000
149
150 /* set default print format */
151 #undef pr_fmt
152 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
153 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
154 @@ -94,7 +94,8 @@ struct brcmf_cfg80211_info;
155 BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
156 BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \
157 BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \
158 - BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127)
159 + BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \
160 + BRCMF_ENUM_DEF(ULP, 146)
161
162 #define BRCMF_ENUM_DEF(id, val) \
163 BRCMF_E_##id = (val),
164 @@ -102,6 +103,12 @@ struct brcmf_cfg80211_info;
165 /* firmware event codes sent by the dongle */
166 enum brcmf_fweh_event_code {
167 BRCMF_FWEH_EVENT_ENUM_DEFLIST
168 +
169 + /* this determines event mask length which must match
170 + * minimum length check in device firmware so it is
171 + * hard-coded here.
172 + */
173 + BRCMF_E_LAST
174 };
175 #undef BRCMF_ENUM_DEF
176
177 @@ -280,6 +287,28 @@ struct brcmf_if_event {
178 u8 role;
179 };
180
181 +enum event_msgs_ext_command {
182 + EVENTMSGS_NONE = 0,
183 + EVENTMSGS_SET_BIT = 1,
184 + EVENTMSGS_RESET_BIT = 2,
185 + EVENTMSGS_SET_MASK = 3
186 +};
187 +
188 +#define EVENTMSGS_VER 1
189 +#define EVENTMSGS_EXT_STRUCT_SIZE offsetof(struct eventmsgs_ext, mask[0])
190 +
191 +/* len- for SET it would be mask size from the application to the firmware */
192 +/* for GET it would be actual firmware mask size */
193 +/* maxgetsize - is only used for GET. indicate max mask size that the */
194 +/* application can read from the firmware */
195 +struct eventmsgs_ext {
196 + u8 ver;
197 + u8 command;
198 + u8 len;
199 + u8 maxgetsize;
200 + u8 mask[1];
201 +};
202 +
203 typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
204 const struct brcmf_event_msg *evtmsg,
205 void *data);
206 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
207 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
208 @@ -2207,7 +2207,7 @@ static void brcmf_pcie_setup(struct devi
209
210 init_waitqueue_head(&devinfo->mbdata_resp_wait);
211
212 - ret = brcmf_attach(&devinfo->pdev->dev);
213 + ret = brcmf_attach(&devinfo->pdev->dev, true);
214 if (ret)
215 goto fail;
216
217 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
218 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
219 @@ -35,9 +35,12 @@
220 #include "core.h"
221 #include "common.h"
222 #include "bcdc.h"
223 +#include "debug.h"
224 +#include "fwil.h"
225
226 #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
227 #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
228 +#define ULP_HUDI_PROC_DONE_TIME msecs_to_jiffies(2500)
229
230 /* watermark expressed in number of words */
231 #define DEFAULT_F2_WATERMARK 0x8
232 @@ -325,7 +328,16 @@ struct rte_console {
233
234 #define KSO_WAIT_US 50
235 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
236 -#define BRCMF_SDIO_MAX_ACCESS_ERRORS 5
237 +#define BRCMF_SDIO_MAX_ACCESS_ERRORS 20
238 +
239 +static void brcmf_sdio_firmware_callback(struct device *dev, int err,
240 + struct brcmf_fw_request *fwreq);
241 +static struct brcmf_fw_request *
242 + brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus);
243 +static int brcmf_sdio_f2_ready(struct brcmf_sdio *bus);
244 +static int brcmf_ulp_event_notify(struct brcmf_if *ifp,
245 + const struct brcmf_event_msg *evtmsg,
246 + void *data);
247
248 #ifdef DEBUG
249 /* Device console log buffer state */
250 @@ -1105,7 +1117,7 @@ static void brcmf_sdio_get_console_addr(
251 }
252 #endif /* DEBUG */
253
254 -static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
255 +static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus, u32 *hmbd)
256 {
257 struct brcmf_sdio_dev *sdiod = bus->sdiodev;
258 struct brcmf_core *core = bus->sdio_core;
259 @@ -1194,6 +1206,9 @@ static u32 brcmf_sdio_hostmail(struct br
260 HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
261 brcmf_err("Unknown mailbox data content: 0x%02x\n",
262 hmb_data);
263 + /* Populate hmb_data if argument is passed for DS1 check later */
264 + if (hmbd)
265 + *hmbd = hmb_data;
266
267 return intstatus;
268 }
269 @@ -2580,6 +2595,182 @@ static int brcmf_sdio_intr_rstatus(struc
270 return ret;
271 }
272
273 +/* This Function is used to retrieve important
274 + * details from dongle related to ULP mode Mostly
275 + * values/SHM details that will be vary depending
276 + * on the firmware branches
277 + */
278 +static void
279 +brcmf_sdio_ulp_preinit(struct device *dev)
280 +{
281 + struct brcmf_bus *bus_if = dev_get_drvdata(dev);
282 + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
283 + struct brcmf_if *ifp = bus_if->drvr->iflist[0];
284 +
285 + brcmf_dbg(ULP, "Enter\n");
286 +
287 + /* Query ulp_sdioctrl iovar to get the ULP related SHM offsets */
288 + brcmf_fil_iovar_data_get(ifp, "ulp_sdioctrl",
289 + &sdiodev->fmac_ulp.ulp_shm_offset,
290 + sizeof(sdiodev->fmac_ulp.ulp_shm_offset));
291 +
292 + sdiodev->ulp = false;
293 +
294 + brcmf_dbg(ULP, "m_ulp_ctrl_sdio[%x] m_ulp_wakeevt_ind [%x]\n",
295 + M_DS1_CTRL_SDIO(sdiodev->fmac_ulp),
296 + M_WAKEEVENT_IND(sdiodev->fmac_ulp));
297 + brcmf_dbg(ULP, "m_ulp_wakeind [%x]\n",
298 + M_ULP_WAKE_IND(sdiodev->fmac_ulp));
299 +}
300 +
301 +/* Reinitialize ARM because In DS1 mode ARM got off */
302 +static int
303 +brcmf_sdio_ulp_reinit_fw(struct brcmf_sdio *bus)
304 +{
305 + struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
306 + struct brcmf_fw_request *fwreq;
307 + int err = 0;
308 +
309 + /* After firmware redownload tx/rx seq are reset accordingly
310 + * these values are reset on FMAC side tx_max is initially set to 4,
311 + * which later is updated by FW.
312 + */
313 + bus->tx_seq = 0;
314 + bus->rx_seq = 0;
315 + bus->tx_max = 4;
316 +
317 + fwreq = brcmf_sdio_prepare_fw_request(bus);
318 + if (!fwreq)
319 + return -ENOMEM;
320 +
321 + err = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
322 + brcmf_sdio_firmware_callback);
323 + if (err != 0) {
324 + brcmf_err("async firmware request failed: %d\n", err);
325 + kfree(fwreq);
326 + }
327 +
328 + return err;
329 +}
330 +
331 +/* Check if device is in DS1 mode and handshake with ULP UCODE */
332 +static bool
333 +brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus, u32 hmb_data)
334 +{
335 + struct brcmf_sdio_dev *sdiod = bus->sdiodev;
336 + int err = 0;
337 + u32 value = 0;
338 + u32 val32, ulp_wake_ind, wowl_wake_ind;
339 + int reg_addr;
340 + unsigned long timeout;
341 + struct brcmf_ulp *fmac_ulp = &bus->sdiodev->fmac_ulp;
342 + int i = 0;
343 +
344 + /* If any host mail box data is present, ignore DS1 exit sequence */
345 + if (hmb_data)
346 + return false;
347 + /* Skip if DS1 Exit is already in progress
348 + * This can happen if firmware download is taking more time
349 + */
350 + if (fmac_ulp->ulp_state == FMAC_ULP_TRIGGERED)
351 + return false;
352 +
353 + value = brcmf_sdiod_func0_rb(sdiod, SDIO_CCCR_IOEx, &err);
354 +
355 + if (value == SDIO_FUNC_ENABLE_1) {
356 + brcmf_dbg(ULP, "GOT THE INTERRUPT FROM UCODE\n");
357 + sdiod->ulp = true;
358 + fmac_ulp->ulp_state = FMAC_ULP_TRIGGERED;
359 + ulp_wake_ind = D11SHM_RDW(sdiod,
360 + M_ULP_WAKE_IND(sdiod->fmac_ulp),
361 + &err);
362 + wowl_wake_ind = D11SHM_RDW(sdiod,
363 + M_WAKEEVENT_IND(sdiod->fmac_ulp),
364 + &err);
365 +
366 + brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x state %s\n",
367 + wowl_wake_ind, ulp_wake_ind, (fmac_ulp->ulp_state) ?
368 + "DS1 Exit Triggered" : "IDLE State");
369 +
370 + if (wowl_wake_ind || ulp_wake_ind) {
371 + /* RX wake Don't do anything.
372 + * Just bail out and re-download firmware.
373 + */
374 + /* Print out PHY TX error block when bit 9 set */
375 + if ((ulp_wake_ind & C_DS1_PHY_TXERR) &&
376 + M_DS1_PHYTX_ERR_BLK(sdiod->fmac_ulp)) {
377 + brcmf_err("Dump PHY TX Error SHM Locations\n");
378 + for (i = 0; i < PHYTX_ERR_BLK_SIZE; i++) {
379 + pr_err("0x%x",
380 + D11SHM_RDW(sdiod,
381 + (M_DS1_PHYTX_ERR_BLK(sdiod->fmac_ulp) +
382 + (i * 2)), &err));
383 + }
384 + brcmf_err("\n");
385 + }
386 + } else {
387 + /* TX wake negotiate with MAC */
388 + brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n",
389 + (u32)D11SHM_RDW(sdiod,
390 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
391 + &err));
392 + val32 = D11SHM_RD(sdiod,
393 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
394 + &err);
395 + D11SHM_WR(sdiod, M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
396 + val32, (C_DS1_CTRL_SDIO_DS1_EXIT |
397 + C_DS1_CTRL_REQ_VALID), &err);
398 + val32 = D11REG_RD(sdiod, D11_MACCONTROL_REG, &err);
399 + val32 = val32 | D11_MACCONTROL_REG_WAKE;
400 + D11REG_WR(sdiod, D11_MACCONTROL_REG, val32, &err);
401 +
402 + /* Poll for PROC_DONE to be set by ucode */
403 + value = D11SHM_RDW(sdiod,
404 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
405 + &err);
406 + /* Wait here (polling) for C_DS1_CTRL_PROC_DONE */
407 + timeout = jiffies + ULP_HUDI_PROC_DONE_TIME;
408 + while (!(value & C_DS1_CTRL_PROC_DONE)) {
409 + value = D11SHM_RDW(sdiod,
410 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
411 + &err);
412 + if (time_after(jiffies, timeout))
413 + break;
414 + usleep_range(1000, 2000);
415 + }
416 + brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n",
417 + (u32)D11SHM_RDW(sdiod,
418 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp), &err));
419 + value = D11SHM_RDW(sdiod,
420 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
421 + &err);
422 + if (!(value & C_DS1_CTRL_PROC_DONE)) {
423 + brcmf_err("Timeout Failed to enter DS1 Exit state!\n");
424 + return false;
425 + }
426 + }
427 +
428 + ulp_wake_ind = D11SHM_RDW(sdiod,
429 + M_ULP_WAKE_IND(sdiod->fmac_ulp),
430 + &err);
431 + wowl_wake_ind = D11SHM_RDW(sdiod,
432 + M_WAKEEVENT_IND(sdiod->fmac_ulp),
433 + &err);
434 + brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n",
435 + wowl_wake_ind, ulp_wake_ind);
436 + reg_addr = CORE_CC_REG(
437 + brcmf_chip_get_pmu(bus->ci)->base, min_res_mask);
438 + brcmf_sdiod_writel(sdiod, reg_addr,
439 + DEFAULT_43012_MIN_RES_MASK, &err);
440 + if (err)
441 + brcmf_err("min_res_mask failed\n");
442 +
443 + return true;
444 + }
445 +
446 + return false;
447 +}
448 +
449 static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
450 {
451 struct brcmf_sdio_dev *sdiod = bus->sdiodev;
452 @@ -2651,8 +2842,11 @@ static void brcmf_sdio_dpc(struct brcmf_
453
454 /* Handle host mailbox indication */
455 if (intstatus & I_HMB_HOST_INT) {
456 + u32 hmb_data = 0;
457 intstatus &= ~I_HMB_HOST_INT;
458 - intstatus |= brcmf_sdio_hostmail(bus);
459 + intstatus |= brcmf_sdio_hostmail(bus, &hmb_data);
460 + if (brcmf_sdio_ulp_pre_redownload_check(bus, hmb_data))
461 + brcmf_sdio_ulp_reinit_fw(bus);
462 }
463
464 sdio_release_host(bus->sdiodev->func1);
465 @@ -2697,7 +2891,7 @@ static void brcmf_sdio_dpc(struct brcmf_
466 brcmf_sdio_clrintr(bus);
467
468 if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
469 - txctl_ok(bus)) {
470 + txctl_ok(bus) && brcmf_sdio_f2_ready(bus)) {
471 sdio_claim_host(bus->sdiodev->func1);
472 if (bus->ctrl_frame_stat) {
473 err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
474 @@ -3567,6 +3761,10 @@ static int brcmf_sdio_bus_preinit(struct
475 if (err < 0)
476 goto done;
477
478 + /* initialize SHM address from firmware for DS1 */
479 + if (!bus->sdiodev->ulp)
480 + brcmf_sdio_ulp_preinit(dev);
481 +
482 bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
483 if (sdiodev->sg_support) {
484 bus->txglom = false;
485 @@ -4215,7 +4413,7 @@ static void brcmf_sdio_firmware_callback
486 u8 saveclk, bpreq;
487 u8 devctl;
488
489 - brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
490 + brcmf_dbg(ULP, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
491
492 if (err)
493 goto fail;
494 @@ -4392,12 +4590,25 @@ static void brcmf_sdio_firmware_callback
495 }
496
497 /* Attach to the common layer, reserve hdr space */
498 - err = brcmf_attach(sdiod->dev);
499 + err = brcmf_attach(sdiod->dev, !bus->sdiodev->ulp);
500 if (err != 0) {
501 brcmf_err("brcmf_attach failed\n");
502 goto free;
503 }
504
505 + /* Register for ULP events */
506 + if (sdiod->func1->device == SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012)
507 + brcmf_fweh_register(bus_if->drvr, BRCMF_E_ULP,
508 + brcmf_ulp_event_notify);
509 +
510 + if (bus->sdiodev->ulp) {
511 + /* For ULP, after firmware redownload complete
512 + * set ULP state to IDLE
513 + */
514 + if (bus->sdiodev->fmac_ulp.ulp_state == FMAC_ULP_TRIGGERED)
515 + bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_IDLE;
516 + }
517 +
518 /* ready */
519 return;
520
521 @@ -4640,3 +4851,40 @@ int brcmf_sdio_sleep(struct brcmf_sdio *
522
523 return ret;
524 }
525 +
526 +/* Check F2 Ready bit before sending data to Firmware */
527 +static int
528 +brcmf_sdio_f2_ready(struct brcmf_sdio *bus)
529 +{
530 + int ret = -1;
531 + int iordy_status = 0;
532 +
533 + sdio_claim_host(bus->sdiodev->func1);
534 + /* Read the status of IOR2 */
535 + iordy_status = brcmf_sdiod_func0_rb(bus->sdiodev, SDIO_CCCR_IORx, NULL);
536 +
537 + sdio_release_host(bus->sdiodev->func1);
538 + ret = iordy_status & SDIO_FUNC_ENABLE_2;
539 + return ret;
540 +}
541 +
542 +static int brcmf_ulp_event_notify(struct brcmf_if *ifp,
543 + const struct brcmf_event_msg *evtmsg,
544 + void *data)
545 +{
546 + int err = 0;
547 + struct brcmf_bus *bus_if = ifp->drvr->bus_if;
548 + struct brcmf_sdio_dev *sdiodev;
549 + struct brcmf_sdio *bus;
550 + struct brcmf_ulp_event *ulp_event = (struct brcmf_ulp_event *)data;
551 +
552 + sdiodev = bus_if->bus_priv.sdio;
553 + bus = sdiodev->bus;
554 +
555 + brcmf_dbg(ULP, "Chip went to DS1 state : action %d\n",
556 + ulp_event->ulp_dongle_action);
557 + if (ulp_event->ulp_dongle_action == FMAC_ULP_ENTRY)
558 + bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_ENTRY_RECV;
559 +
560 + return err;
561 +}
562 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
563 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
564 @@ -165,6 +165,35 @@ struct brcmf_sdreg {
565 struct brcmf_sdio;
566 struct brcmf_sdiod_freezer;
567
568 +/* ULP SHM Offsets info */
569 +struct ulp_shm_info {
570 + u32 m_ulp_ctrl_sdio;
571 + u32 m_ulp_wakeevt_ind;
572 + u32 m_ulp_wakeind;
573 + u32 m_ulp_phytxblk;
574 +};
575 +
576 +/* FMAC ULP state machine */
577 +#define FMAC_ULP_IDLE (0)
578 +#define FMAC_ULP_ENTRY_RECV (1)
579 +#define FMAC_ULP_TRIGGERED (2)
580 +
581 +/* BRCMF_E_ULP event data */
582 +#define FMAC_ULP_EVENT_VERSION 1
583 +#define FMAC_ULP_DISABLE_CONSOLE 1 /* Disable console */
584 +#define FMAC_ULP_UCODE_DOWNLOAD 2 /* Download ULP ucode file */
585 +#define FMAC_ULP_ENTRY 3 /* Inform ulp entry to Host */
586 +
587 +struct brcmf_ulp {
588 + uint ulp_state;
589 + struct ulp_shm_info ulp_shm_offset;
590 +};
591 +
592 +struct brcmf_ulp_event {
593 + u16 version;
594 + u16 ulp_dongle_action;
595 +};
596 +
597 struct brcmf_sdio_dev {
598 struct sdio_func *func1;
599 struct sdio_func *func2;
600 @@ -193,6 +222,8 @@ struct brcmf_sdio_dev {
601 enum brcmf_sdiod_state state;
602 struct brcmf_sdiod_freezer *freezer;
603 const struct firmware *clm_fw;
604 + struct brcmf_ulp fmac_ulp;
605 + bool ulp;
606 };
607
608 /* sdio core registers */
609 @@ -367,4 +398,83 @@ void brcmf_sdio_wowl_config(struct devic
610 int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep);
611 void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus);
612
613 +/* SHM offsets */
614 +#define M_DS1_CTRL_SDIO(ptr) ((ptr).ulp_shm_offset.m_ulp_ctrl_sdio)
615 +#define M_WAKEEVENT_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeevt_ind)
616 +#define M_ULP_WAKE_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeind)
617 +#define M_DS1_PHYTX_ERR_BLK(ptr) ((ptr).ulp_shm_offset.m_ulp_phytxblk)
618 +
619 +#define D11_BASE_ADDR 0x18001000
620 +#define D11_AXI_BASE_ADDR 0xE8000000
621 +#define D11_SHM_BASE_ADDR (D11_AXI_BASE_ADDR + 0x4000)
622 +
623 +#define D11REG_ADDR(offset) (D11_BASE_ADDR + (offset))
624 +#define D11IHR_ADDR(offset) (D11_AXI_BASE_ADDR + 0x400 + (2 * (offset)))
625 +#define D11SHM_ADDR(offset) (D11_SHM_BASE_ADDR + (offset))
626 +
627 +/* MacControl register */
628 +#define D11_MACCONTROL_REG D11REG_ADDR(0x120)
629 +#define D11_MACCONTROL_REG_WAKE 0x4000000
630 +
631 +/* HUDI Sequence SHM bits */
632 +#define C_DS1_CTRL_SDIO_DS1_SLEEP 0x1
633 +#define C_DS1_CTRL_SDIO_MAC_ON 0x2
634 +#define C_DS1_CTRL_SDIO_RADIO_PHY_ON 0x4
635 +#define C_DS1_CTRL_SDIO_DS1_EXIT 0x8
636 +#define C_DS1_CTRL_PROC_DONE 0x100
637 +#define C_DS1_CTRL_REQ_VALID 0x200
638 +
639 +/* M_ULP_WAKEIND bits */
640 +#define C_WATCHDOG_EXPIRY BIT(0)
641 +#define C_FCBS_ERROR BIT(1)
642 +#define C_RETX_FAILURE BIT(2)
643 +#define C_HOST_WAKEUP BIT(3)
644 +#define C_INVALID_FCBS_BLOCK BIT(4)
645 +#define C_HUDI_DS1_EXIT BIT(5)
646 +#define C_LOB_SLEEP BIT(6)
647 +#define C_DS1_PHY_TXERR BIT(9)
648 +#define C_DS1_WAKE_TIMER BIT(10)
649 +
650 +#define PHYTX_ERR_BLK_SIZE 18
651 +#define D11SHM_FIRST2BYTE_MASK 0xFFFF0000
652 +#define D11SHM_SECOND2BYTE_MASK 0x0000FFFF
653 +#define D11SHM_2BYTE_SHIFT 16
654 +
655 +#define D11SHM_RD(sdh, offset, ret) \
656 + brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret)
657 +
658 +/* SHM Read is motified based on SHM 4 byte alignment as SHM size is 2 bytes and
659 + * 2 byte is currently not working on FMAC
660 + * If SHM address is not 4 byte aligned, then right shift by 16
661 + * otherwise, mask the first two MSB bytes
662 + * Suppose data in address 7260 is 0x440002 and it is 4 byte aligned
663 + * Correct SHM value is 0x2 for this SHM offset and next SHM value is 0x44
664 + */
665 +#define D11SHM_RDW(sdh, offset, ret) \
666 + ((offset % 4) ? \
667 + (brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) \
668 + >> D11SHM_2BYTE_SHIFT) : \
669 + (brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) \
670 + & D11SHM_SECOND2BYTE_MASK))
671 +
672 +/* SHM is of size 2 bytes, 4 bytes write will overwrite other SHM's
673 + * First read 4 bytes and then clear the required two bytes based on
674 + * 4 byte alignment, then update the required value and write the
675 + * 4 byte value now
676 + */
677 +#define D11SHM_WR(sdh, offset, val, mask, ret) \
678 + do { \
679 + if ((offset) % 4) \
680 + val = (val & D11SHM_SECOND2BYTE_MASK) | \
681 + ((mask) << D11SHM_2BYTE_SHIFT); \
682 + else \
683 + val = (mask) | (val & D11SHM_FIRST2BYTE_MASK); \
684 + brcmf_sdiod_writel(sdh, D11SHM_ADDR(offset), val, ret); \
685 + } while (0)
686 +#define D11REG_WR(sdh, addr, val, ret) \
687 + brcmf_sdiod_writel(sdh, addr, val, ret)
688 +
689 +#define D11REG_RD(sdh, addr, ret) \
690 + brcmf_sdiod_readl(sdh, addr, ret)
691 +
692 #endif /* BRCMFMAC_SDIO_H */
693 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
694 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
695 @@ -1200,7 +1200,7 @@ static void brcmf_usb_probe_phase2(struc
696 goto error;
697
698 /* Attach to the common driver interface */
699 - ret = brcmf_attach(devinfo->dev);
700 + ret = brcmf_attach(devinfo->dev, true);
701 if (ret)
702 goto error;
703
704 @@ -1277,7 +1277,7 @@ static int brcmf_usb_probe_cb(struct brc
705 ret = brcmf_alloc(devinfo->dev, devinfo->settings);
706 if (ret)
707 goto fail;
708 - ret = brcmf_attach(devinfo->dev);
709 + ret = brcmf_attach(devinfo->dev, true);
710 if (ret)
711 goto fail;
712 /* we are done */
713 --- a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
714 +++ b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h
715 @@ -308,4 +308,6 @@ struct chipcregs {
716 */
717 #define PMU_MAX_TRANSITION_DLY 15000
718
719 +#define DEFAULT_43012_MIN_RES_MASK 0x0f8bfe77
720 +
721 #endif /* _SBCHIPC_H */