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
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.
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
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
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>
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(-)
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,
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
58 +#include <brcm_hw_ids.h>
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
66 + struct eventmsgs_ext *eventmask_msg = NULL;
69 if (is_valid_ether_addr(ifp->mac_addr)) {
71 @@ -433,6 +437,41 @@ int brcmf_c_preinit_dcmds(struct brcmf_i
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) {
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",
94 + /* Enable ULP event */
95 + brcmf_dbg(EVENT, "enable event ULP\n");
96 + setbit(eventmask_msg->mask, BRCMF_E_ULP);
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);
103 + err = brcmf_fil_iovar_data_set(ifp, "event_msgs_ext",
104 + eventmask_msg, msglen);
106 + brcmf_err("Set event_msgs_ext error (%d)\n", err);
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
119 -int brcmf_attach(struct device *dev)
120 +int brcmf_attach(struct device *dev, bool start_bus)
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);
128 - ret = brcmf_bus_started(drvr, drvr->ops);
130 - bphy_err(drvr, "dongle is not responding: err=%d\n", ret);
133 + ret = brcmf_bus_started(drvr, drvr->ops);
135 + bphy_err(drvr, "dongle is not responding: err=%d\n",
142 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
143 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
145 #define BRCMF_MSGBUF_VAL 0x00040000
146 #define BRCMF_PCIE_VAL 0x00080000
147 #define BRCMF_FWCON_VAL 0x00100000
148 +#define BRCMF_ULP_VAL 0x00200000
150 /* set default print format */
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)
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
169 + /* this determines event mask length which must match
170 + * minimum length check in device firmware so it is
175 #undef BRCMF_ENUM_DEF
177 @@ -280,6 +287,28 @@ struct brcmf_if_event {
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
188 +#define EVENTMSGS_VER 1
189 +#define EVENTMSGS_EXT_STRUCT_SIZE offsetof(struct eventmsgs_ext, mask[0])
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 {
203 typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
204 const struct brcmf_event_msg *evtmsg,
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
210 init_waitqueue_head(&devinfo->mbdata_resp_wait);
212 - ret = brcmf_attach(&devinfo->pdev->dev);
213 + ret = brcmf_attach(&devinfo->pdev->dev, true);
217 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
218 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
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)
230 /* watermark expressed in number of words */
231 #define DEFAULT_F2_WATERMARK 0x8
232 @@ -325,7 +328,16 @@ struct rte_console {
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
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,
249 /* Device console log buffer state */
250 @@ -1105,7 +1117,7 @@ static void brcmf_sdio_get_console_addr(
254 -static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)
255 +static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus, u32 *hmbd)
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",
263 + /* Populate hmb_data if argument is passed for DS1 check later */
269 @@ -2580,6 +2595,182 @@ static int brcmf_sdio_intr_rstatus(struc
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
279 +brcmf_sdio_ulp_preinit(struct device *dev)
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];
285 + brcmf_dbg(ULP, "Enter\n");
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));
292 + sdiodev->ulp = false;
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));
301 +/* Reinitialize ARM because In DS1 mode ARM got off */
303 +brcmf_sdio_ulp_reinit_fw(struct brcmf_sdio *bus)
305 + struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
306 + struct brcmf_fw_request *fwreq;
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.
317 + fwreq = brcmf_sdio_prepare_fw_request(bus);
321 + err = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
322 + brcmf_sdio_firmware_callback);
324 + brcmf_err("async firmware request failed: %d\n", err);
331 +/* Check if device is in DS1 mode and handshake with ULP UCODE */
333 +brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus, u32 hmb_data)
335 + struct brcmf_sdio_dev *sdiod = bus->sdiodev;
338 + u32 val32, ulp_wake_ind, wowl_wake_ind;
340 + unsigned long timeout;
341 + struct brcmf_ulp *fmac_ulp = &bus->sdiodev->fmac_ulp;
344 + /* If any host mail box data is present, ignore DS1 exit sequence */
347 + /* Skip if DS1 Exit is already in progress
348 + * This can happen if firmware download is taking more time
350 + if (fmac_ulp->ulp_state == FMAC_ULP_TRIGGERED)
353 + value = brcmf_sdiod_func0_rb(sdiod, SDIO_CCCR_IOEx, &err);
355 + if (value == SDIO_FUNC_ENABLE_1) {
356 + brcmf_dbg(ULP, "GOT THE INTERRUPT FROM UCODE\n");
358 + fmac_ulp->ulp_state = FMAC_ULP_TRIGGERED;
359 + ulp_wake_ind = D11SHM_RDW(sdiod,
360 + M_ULP_WAKE_IND(sdiod->fmac_ulp),
362 + wowl_wake_ind = D11SHM_RDW(sdiod,
363 + M_WAKEEVENT_IND(sdiod->fmac_ulp),
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");
370 + if (wowl_wake_ind || ulp_wake_ind) {
371 + /* RX wake Don't do anything.
372 + * Just bail out and re-download firmware.
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++) {
381 + (M_DS1_PHYTX_ERR_BLK(sdiod->fmac_ulp) +
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),
392 + val32 = D11SHM_RD(sdiod,
393 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
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);
402 + /* Poll for PROC_DONE to be set by ucode */
403 + value = D11SHM_RDW(sdiod,
404 + M_DS1_CTRL_SDIO(sdiod->fmac_ulp),
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),
412 + if (time_after(jiffies, timeout))
414 + usleep_range(1000, 2000);
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),
422 + if (!(value & C_DS1_CTRL_PROC_DONE)) {
423 + brcmf_err("Timeout Failed to enter DS1 Exit state!\n");
428 + ulp_wake_ind = D11SHM_RDW(sdiod,
429 + M_ULP_WAKE_IND(sdiod->fmac_ulp),
431 + wowl_wake_ind = D11SHM_RDW(sdiod,
432 + M_WAKEEVENT_IND(sdiod->fmac_ulp),
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);
441 + brcmf_err("min_res_mask failed\n");
449 static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
451 struct brcmf_sdio_dev *sdiod = bus->sdiodev;
452 @@ -2651,8 +2842,11 @@ static void brcmf_sdio_dpc(struct brcmf_
454 /* Handle host mailbox indication */
455 if (intstatus & I_HMB_HOST_INT) {
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);
464 sdio_release_host(bus->sdiodev->func1);
465 @@ -2697,7 +2891,7 @@ static void brcmf_sdio_dpc(struct brcmf_
466 brcmf_sdio_clrintr(bus);
468 if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
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
478 + /* initialize SHM address from firmware for DS1 */
479 + if (!bus->sdiodev->ulp)
480 + brcmf_sdio_ulp_preinit(dev);
482 bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
483 if (sdiodev->sg_support) {
485 @@ -4215,7 +4413,7 @@ static void brcmf_sdio_firmware_callback
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);
494 @@ -4392,12 +4590,25 @@ static void brcmf_sdio_firmware_callback
497 /* Attach to the common layer, reserve hdr space */
498 - err = brcmf_attach(sdiod->dev);
499 + err = brcmf_attach(sdiod->dev, !bus->sdiodev->ulp);
501 brcmf_err("brcmf_attach failed\n");
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);
510 + if (bus->sdiodev->ulp) {
511 + /* For ULP, after firmware redownload complete
512 + * set ULP state to IDLE
514 + if (bus->sdiodev->fmac_ulp.ulp_state == FMAC_ULP_TRIGGERED)
515 + bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_IDLE;
521 @@ -4640,3 +4851,40 @@ int brcmf_sdio_sleep(struct brcmf_sdio *
526 +/* Check F2 Ready bit before sending data to Firmware */
528 +brcmf_sdio_f2_ready(struct brcmf_sdio *bus)
531 + int iordy_status = 0;
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);
537 + sdio_release_host(bus->sdiodev->func1);
538 + ret = iordy_status & SDIO_FUNC_ENABLE_2;
542 +static int brcmf_ulp_event_notify(struct brcmf_if *ifp,
543 + const struct brcmf_event_msg *evtmsg,
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;
552 + sdiodev = bus_if->bus_priv.sdio;
553 + bus = sdiodev->bus;
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;
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 {
566 struct brcmf_sdiod_freezer;
568 +/* ULP SHM Offsets info */
569 +struct ulp_shm_info {
570 + u32 m_ulp_ctrl_sdio;
571 + u32 m_ulp_wakeevt_ind;
573 + u32 m_ulp_phytxblk;
576 +/* FMAC ULP state machine */
577 +#define FMAC_ULP_IDLE (0)
578 +#define FMAC_ULP_ENTRY_RECV (1)
579 +#define FMAC_ULP_TRIGGERED (2)
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 */
589 + struct ulp_shm_info ulp_shm_offset;
592 +struct brcmf_ulp_event {
594 + u16 ulp_dongle_action;
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;
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);
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)
619 +#define D11_BASE_ADDR 0x18001000
620 +#define D11_AXI_BASE_ADDR 0xE8000000
621 +#define D11_SHM_BASE_ADDR (D11_AXI_BASE_ADDR + 0x4000)
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))
627 +/* MacControl register */
628 +#define D11_MACCONTROL_REG D11REG_ADDR(0x120)
629 +#define D11_MACCONTROL_REG_WAKE 0x4000000
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
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)
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
655 +#define D11SHM_RD(sdh, offset, ret) \
656 + brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret)
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
665 +#define D11SHM_RDW(sdh, offset, ret) \
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))
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
677 +#define D11SHM_WR(sdh, offset, val, mask, ret) \
679 + if ((offset) % 4) \
680 + val = (val & D11SHM_SECOND2BYTE_MASK) | \
681 + ((mask) << D11SHM_2BYTE_SHIFT); \
683 + val = (mask) | (val & D11SHM_FIRST2BYTE_MASK); \
684 + brcmf_sdiod_writel(sdh, D11SHM_ADDR(offset), val, ret); \
686 +#define D11REG_WR(sdh, addr, val, ret) \
687 + brcmf_sdiod_writel(sdh, addr, val, ret)
689 +#define D11REG_RD(sdh, addr, ret) \
690 + brcmf_sdiod_readl(sdh, addr, ret)
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
698 /* Attach to the common driver interface */
699 - ret = brcmf_attach(devinfo->dev);
700 + ret = brcmf_attach(devinfo->dev, true);
704 @@ -1277,7 +1277,7 @@ static int brcmf_usb_probe_cb(struct brc
705 ret = brcmf_alloc(devinfo->dev, devinfo->settings);
708 - ret = brcmf_attach(devinfo->dev);
709 + ret = brcmf_attach(devinfo->dev, true);
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 {
717 #define PMU_MAX_TRANSITION_DLY 15000
719 +#define DEFAULT_43012_MIN_RES_MASK 0x0f8bfe77
721 #endif /* _SBCHIPC_H */