| #include "headers.h" | |
| /* | |
| Function: InterfaceIdleModeWakeup | |
| Description: This is the hardware specific Function for waking up HW device from Idle mode. | |
| A software abort pattern is written to the device to wake it and necessary power state | |
| transitions from host are performed here. | |
| Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context | |
| Return: BCM_STATUS_SUCCESS - If Wakeup of the HW Interface was successful. | |
| Other - If an error occurred. | |
| */ | |
| /* | |
| Function: InterfaceIdleModeRespond | |
| Description: This is the hardware specific Function for responding to Idle mode request from target. | |
| Necessary power state transitions from host for idle mode or other device specific | |
| initializations are performed here. | |
| Input parameters: IN struct bcm_mini_adapter * Adapter - Miniport Adapter Context | |
| Return: BCM_STATUS_SUCCESS - If Idle mode response related HW configuration was successful. | |
| Other - If an error occurred. | |
| */ | |
| /* | |
| "dmem bfc02f00 100" tells how many time device went in Idle mode. | |
| this value will be at address bfc02fa4.just before value d0ea1dle. | |
| Set time value by writing at bfc02f98 7d0 | |
| checking the Ack timer expire on kannon by running command | |
| d qcslog .. if it shows e means host has not send response to f/w with in 200 ms. Response should be | |
| send to f/w with in 200 ms after the Idle/Shutdown req issued | |
| */ | |
| int InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter, unsigned int *puiBuffer) | |
| { | |
| int status = STATUS_SUCCESS; | |
| unsigned int uiRegRead = 0; | |
| int bytes; | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "SubType of Message :0x%X", ntohl(*puiBuffer)); | |
| if (ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, " Got GO_TO_IDLE_MODE_PAYLOAD(210) Msg Subtype"); | |
| if (ntohl(*(puiBuffer+1)) == 0 ) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Got IDLE MODE WAKE UP Response From F/W"); | |
| status = wrmalt (Adapter, SW_ABORT_IDLEMODE_LOC, &uiRegRead, sizeof(uiRegRead)); | |
| if (status) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg"); | |
| return status; | |
| } | |
| if (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) { | |
| uiRegRead = 0x00000000 ; | |
| status = wrmalt (Adapter, DEBUG_INTERRUPT_GENERATOR_REGISTOR, &uiRegRead, sizeof(uiRegRead)); | |
| if (status) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg"); | |
| return status; | |
| } | |
| } | |
| /* Below Register should not br read in case of Manual and Protocol Idle mode */ | |
| else if (Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) { | |
| /* clear on read Register */ | |
| bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, &uiRegRead, sizeof(uiRegRead)); | |
| if (bytes < 0) { | |
| status = bytes; | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort Reg0"); | |
| return status; | |
| } | |
| /* clear on read Register */ | |
| bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1, &uiRegRead, sizeof(uiRegRead)); | |
| if (bytes < 0) { | |
| status = bytes; | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort Reg1"); | |
| return status; | |
| } | |
| } | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Device Up from Idle Mode"); | |
| /* Set Idle Mode Flag to False and Clear IdleMode reg. */ | |
| Adapter->IdleMode = FALSE; | |
| Adapter->bTriedToWakeUpFromlowPowerMode = FALSE; | |
| wake_up(&Adapter->lowpower_mode_wait_queue); | |
| } else { | |
| if (TRUE == Adapter->IdleMode) | |
| { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Device is already in Idle mode...."); | |
| return status ; | |
| } | |
| uiRegRead = 0; | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Got Req from F/W to go in IDLE mode \n"); | |
| if (Adapter->chip_id == BCS220_2 || | |
| Adapter->chip_id == BCS220_2BC || | |
| Adapter->chip_id == BCS250_BC || | |
| Adapter->chip_id == BCS220_3) { | |
| bytes = rdmalt(Adapter, HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead)); | |
| if (bytes < 0) { | |
| status = bytes; | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "rdm failed while Reading HPM_CONFIG_LDO145 Reg 0\n"); | |
| return status; | |
| } | |
| uiRegRead |= (1<<17); | |
| status = wrmalt (Adapter, HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead)); | |
| if (status) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg\n"); | |
| return status; | |
| } | |
| } | |
| SendIdleModeResponse(Adapter); | |
| } | |
| } else if (ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "OverRiding Service Flow Params"); | |
| OverrideServiceFlowParams(Adapter, puiBuffer); | |
| } | |
| return status; | |
| } | |
| static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter, unsigned int Pattern) | |
| { | |
| int status = STATUS_SUCCESS; | |
| unsigned int value; | |
| unsigned int chip_id ; | |
| unsigned long timeout = 0, itr = 0; | |
| int lenwritten = 0; | |
| unsigned char aucAbortPattern[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |
| struct bcm_interface_adapter *psInterfaceAdapter = Adapter->pvInterfaceAdapter; | |
| /* Abort Bus suspend if its already suspended */ | |
| if ((TRUE == psInterfaceAdapter->bSuspended) && (TRUE == Adapter->bDoSuspend)) { | |
| status = usb_autopm_get_interface(psInterfaceAdapter->interface); | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Bus got wakeup..Aborting Idle mode... status:%d \n", status); | |
| } | |
| if ((Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) | |
| || | |
| (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) { | |
| /* write the SW abort pattern. */ | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Writing pattern<%d> to SW_ABORT_IDLEMODE_LOC\n", Pattern); | |
| status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, &Pattern, sizeof(Pattern)); | |
| if (status) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "WRM to Register SW_ABORT_IDLEMODE_LOC failed.."); | |
| return status; | |
| } | |
| } | |
| if (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) { | |
| value = 0x80000000; | |
| status = wrmalt(Adapter, DEBUG_INTERRUPT_GENERATOR_REGISTOR, &value, sizeof(value)); | |
| if (status) | |
| { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "WRM to DEBUG_INTERRUPT_GENERATOR_REGISTOR Register failed"); | |
| return status; | |
| } | |
| } else if (Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) { | |
| /* | |
| * Get a Interrupt Out URB and send 8 Bytes Down | |
| * To be Done in Thread Context. | |
| * Not using Asynchronous Mechanism. | |
| */ | |
| status = usb_interrupt_msg (psInterfaceAdapter->udev, | |
| usb_sndintpipe(psInterfaceAdapter->udev, | |
| psInterfaceAdapter->sIntrOut.int_out_endpointAddr), | |
| aucAbortPattern, | |
| 8, | |
| &lenwritten, | |
| 5000); | |
| if (status) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Sending Abort pattern down fails with status:%d..\n", status); | |
| return status; | |
| } else { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "NOB Sent down :%d", lenwritten); | |
| } | |
| /* mdelay(25); */ | |
| timeout = jiffies + msecs_to_jiffies(50) ; | |
| while ( timeout > jiffies ) { | |
| itr++ ; | |
| rdmalt(Adapter, CHIP_ID_REG, &chip_id, sizeof(UINT)); | |
| if (0xbece3200 == (chip_id&~(0xF0))) | |
| chip_id = chip_id&~(0xF0); | |
| if (chip_id == Adapter->chip_id) | |
| break; | |
| } | |
| if (timeout < jiffies ) | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Not able to read chip-id even after 25 msec"); | |
| else | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Number of completed iteration to read chip-id :%lu", itr); | |
| status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, &Pattern, sizeof(status)); | |
| if (status) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM to Register SW_ABORT_IDLEMODE_LOC failed.."); | |
| return status; | |
| } | |
| } | |
| return status; | |
| } | |
| int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter) | |
| { | |
| ULONG Status = 0; | |
| if (Adapter->bTriedToWakeUpFromlowPowerMode) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Wake up already attempted.. ignoring\n"); | |
| } else { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Writing Low Power Mode Abort pattern to the Device\n"); | |
| Adapter->bTriedToWakeUpFromlowPowerMode = TRUE; | |
| InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern); | |
| } | |
| return Status; | |
| } | |
| void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter) | |
| { | |
| unsigned int uiRegVal = 0; | |
| INT Status = 0; | |
| int bytes; | |
| if (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) { | |
| /* clear idlemode interrupt. */ | |
| uiRegVal = 0; | |
| Status = wrmalt(Adapter, DEBUG_INTERRUPT_GENERATOR_REGISTOR, &uiRegVal, sizeof(uiRegVal)); | |
| if (Status) { | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,"WRM to DEBUG_INTERRUPT_GENERATOR_REGISTOR Failed with err :%d", Status); | |
| return; | |
| } | |
| } | |
| else { | |
| /* clear Interrupt EP registers. */ | |
| bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, &uiRegVal, sizeof(uiRegVal)); | |
| if (bytes < 0) { | |
| Status = bytes; | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM of DEVICE_INT_OUT_EP_REG0 failed with Err :%d", Status); | |
| return; | |
| } | |
| bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1, &uiRegVal, sizeof(uiRegVal)); | |
| if (bytes < 0) { | |
| Status = bytes; | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM of DEVICE_INT_OUT_EP_REG1 failed with Err :%d", Status); | |
| return; | |
| } | |
| } | |
| } | |