Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 1 | #include "headers.h" |
| 2 | |
| 3 | /* |
| 4 | Function: InterfaceIdleModeWakeup |
| 5 | |
| 6 | Description: This is the hardware specific Function for waking up HW device from Idle mode. |
| 7 | A software abort pattern is written to the device to wake it and necessary power state |
| 8 | transitions from host are performed here. |
| 9 | |
| 10 | Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context |
| 11 | |
| 12 | |
| 13 | Return: BCM_STATUS_SUCCESS - If Wakeup of the HW Interface was successful. |
Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 14 | Other - If an error occurred. |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | |
| 18 | /* |
| 19 | Function: InterfaceIdleModeRespond |
| 20 | |
| 21 | Description: This is the hardware specific Function for responding to Idle mode request from target. |
| 22 | Necessary power state transitions from host for idle mode or other device specific |
| 23 | initializations are performed here. |
| 24 | |
| 25 | Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context |
| 26 | |
| 27 | |
| 28 | Return: BCM_STATUS_SUCCESS - If Idle mode response related HW configuration was successful. |
Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 29 | Other - If an error occurred. |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 30 | */ |
| 31 | |
| 32 | /* |
| 33 | "dmem bfc02f00 100" tells how many time device went in Idle mode. |
| 34 | this value will be at address bfc02fa4.just before value d0ea1dle. |
| 35 | |
| 36 | Set time value by writing at bfc02f98 7d0 |
| 37 | |
| 38 | checking the Ack timer expire on kannon by running command |
| 39 | d qcslog .. if it shows e means host has not send response to f/w with in 200 ms. Response should be |
| 40 | send to f/w with in 200 ms after the Idle/Shutdown req issued |
| 41 | |
| 42 | */ |
| 43 | |
| 44 | |
Arnd Bergmann | 44a17eff | 2010-09-30 10:24:12 +0200 | [diff] [blame] | 45 | int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer) |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 46 | { |
| 47 | int status = STATUS_SUCCESS; |
| 48 | unsigned int uiRegRead = 0; |
| 49 | |
| 50 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"SubType of Message :0x%X", ntohl(*puiBuffer)); |
| 51 | |
| 52 | if(ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD) |
| 53 | { |
| 54 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL," Got GO_TO_IDLE_MODE_PAYLOAD(210) Msg Subtype"); |
| 55 | if(ntohl(*(puiBuffer+1)) == 0 ) |
| 56 | { |
| 57 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"Got IDLE MODE WAKE UP Response From F/W"); |
| 58 | |
| 59 | status = wrmalt (Adapter,SW_ABORT_IDLEMODE_LOC, &uiRegRead, sizeof(uiRegRead)); |
| 60 | if(status) |
| 61 | { |
| 62 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg"); |
| 63 | return status; |
| 64 | } |
| 65 | |
| 66 | if(Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) |
| 67 | { |
| 68 | uiRegRead = 0x00000000 ; |
| 69 | status = wrmalt (Adapter,DEBUG_INTERRUPT_GENERATOR_REGISTOR, &uiRegRead, sizeof(uiRegRead)); |
| 70 | if(status) |
| 71 | { |
| 72 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg"); |
| 73 | return status; |
| 74 | } |
| 75 | } |
| 76 | //Below Register should not br read in case of Manual and Protocol Idle mode. |
| 77 | else if(Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) |
| 78 | { |
| 79 | //clear on read Register |
| 80 | status = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, &uiRegRead, sizeof(uiRegRead)); |
| 81 | if(status) |
| 82 | { |
| 83 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort Reg0"); |
| 84 | return status; |
| 85 | } |
| 86 | //clear on read Register |
| 87 | status = rdmalt (Adapter, DEVICE_INT_OUT_EP_REG1, &uiRegRead, sizeof(uiRegRead)); |
| 88 | if(status) |
| 89 | { |
| 90 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort Reg1"); |
| 91 | return status; |
| 92 | } |
| 93 | } |
| 94 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Device Up from Idle Mode"); |
| 95 | |
| 96 | // Set Idle Mode Flag to False and Clear IdleMode reg. |
| 97 | Adapter->IdleMode = FALSE; |
| 98 | Adapter->bTriedToWakeUpFromlowPowerMode = FALSE; |
| 99 | |
| 100 | wake_up(&Adapter->lowpower_mode_wait_queue); |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 101 | |
| 102 | } |
| 103 | else |
| 104 | { |
| 105 | if(TRUE == Adapter->IdleMode) |
| 106 | { |
| 107 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"Device is already in Idle mode...."); |
| 108 | return status ; |
| 109 | } |
| 110 | |
| 111 | uiRegRead = 0; |
| 112 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Got Req from F/W to go in IDLE mode \n"); |
| 113 | |
| 114 | if (Adapter->chip_id== BCS220_2 || |
| 115 | Adapter->chip_id == BCS220_2BC || |
| 116 | Adapter->chip_id== BCS250_BC || |
| 117 | Adapter->chip_id== BCS220_3) |
| 118 | { |
| 119 | |
| 120 | status = rdmalt(Adapter, HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead)); |
| 121 | if(status) |
| 122 | { |
| 123 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "rdm failed while Reading HPM_CONFIG_LDO145 Reg 0\n"); |
| 124 | return status; |
| 125 | } |
| 126 | |
| 127 | |
| 128 | uiRegRead |= (1<<17); |
| 129 | |
| 130 | status = wrmalt (Adapter,HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead)); |
| 131 | if(status) |
| 132 | { |
| 133 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg\n"); |
| 134 | return status; |
| 135 | } |
| 136 | |
| 137 | } |
| 138 | SendIdleModeResponse(Adapter); |
| 139 | } |
| 140 | } |
| 141 | else if(ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG) |
| 142 | { |
| 143 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "OverRiding Service Flow Params"); |
| 144 | OverrideServiceFlowParams(Adapter,puiBuffer); |
| 145 | } |
| 146 | return status; |
| 147 | } |
| 148 | |
Stephen Hemminger | 9dd47ee | 2010-11-01 12:24:00 -0400 | [diff] [blame] | 149 | static int InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern) |
Stephen Hemminger | f8942e0 | 2010-09-08 14:46:36 -0700 | [diff] [blame] | 150 | { |
| 151 | int status = STATUS_SUCCESS; |
| 152 | unsigned int value; |
| 153 | unsigned int chip_id ; |
| 154 | unsigned long timeout = 0 ,itr = 0; |
| 155 | |
| 156 | int lenwritten = 0; |
| 157 | unsigned char aucAbortPattern[8]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; |
| 158 | PS_INTERFACE_ADAPTER psInterfaceAdapter = Adapter->pvInterfaceAdapter; |
| 159 | |
| 160 | //Abort Bus suspend if its already suspended |
| 161 | if((TRUE == psInterfaceAdapter->bSuspended) && (TRUE == Adapter->bDoSuspend)) |
| 162 | { |
| 163 | status = usb_autopm_get_interface(psInterfaceAdapter->interface); |
| 164 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"Bus got wakeup..Aborting Idle mode... status:%d \n",status); |
| 165 | |
| 166 | } |
| 167 | |
| 168 | if((Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) |
| 169 | || |
| 170 | (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) |
| 171 | { |
| 172 | //write the SW abort pattern. |
| 173 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Writing pattern<%d> to SW_ABORT_IDLEMODE_LOC\n", Pattern); |
| 174 | status = wrmalt(Adapter,SW_ABORT_IDLEMODE_LOC, &Pattern, sizeof(Pattern)); |
| 175 | if(status) |
| 176 | { |
| 177 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"WRM to Register SW_ABORT_IDLEMODE_LOC failed.."); |
| 178 | return status; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | if(Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) |
| 183 | { |
| 184 | value = 0x80000000; |
| 185 | status = wrmalt(Adapter,DEBUG_INTERRUPT_GENERATOR_REGISTOR, &value, sizeof(value)); |
| 186 | if(status) |
| 187 | { |
| 188 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"WRM to DEBUG_INTERRUPT_GENERATOR_REGISTOR Register failed"); |
| 189 | return status; |
| 190 | } |
| 191 | } |
| 192 | else if(Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) |
| 193 | { |
| 194 | /* |
| 195 | * Get a Interrupt Out URB and send 8 Bytes Down |
| 196 | * To be Done in Thread Context. |
| 197 | * Not using Asynchronous Mechanism. |
| 198 | */ |
| 199 | status = usb_interrupt_msg (psInterfaceAdapter->udev, |
| 200 | usb_sndintpipe(psInterfaceAdapter->udev, |
| 201 | psInterfaceAdapter->sIntrOut.int_out_endpointAddr), |
| 202 | aucAbortPattern, |
| 203 | 8, |
| 204 | &lenwritten, |
| 205 | 5000); |
| 206 | if(status) |
| 207 | { |
| 208 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Sending Abort pattern down fails with status:%d..\n",status); |
| 209 | return status; |
| 210 | } |
| 211 | else |
| 212 | { |
| 213 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "NOB Sent down :%d", lenwritten); |
| 214 | } |
| 215 | |
| 216 | //mdelay(25); |
| 217 | |
| 218 | timeout= jiffies + msecs_to_jiffies(50) ; |
| 219 | while( timeout > jiffies ) |
| 220 | { |
| 221 | itr++ ; |
| 222 | rdmalt(Adapter, CHIP_ID_REG, &chip_id, sizeof(UINT)); |
| 223 | if(0xbece3200==(chip_id&~(0xF0))) |
| 224 | { |
| 225 | chip_id = chip_id&~(0xF0); |
| 226 | } |
| 227 | if(chip_id == Adapter->chip_id) |
| 228 | break; |
| 229 | } |
| 230 | if(timeout < jiffies ) |
| 231 | { |
| 232 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"Not able to read chip-id even after 25 msec"); |
| 233 | } |
| 234 | else |
| 235 | { |
| 236 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"Number of completed iteration to read chip-id :%lu", itr); |
| 237 | } |
| 238 | |
| 239 | status = wrmalt(Adapter,SW_ABORT_IDLEMODE_LOC, &Pattern, sizeof(status)); |
| 240 | if(status) |
| 241 | { |
| 242 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"WRM to Register SW_ABORT_IDLEMODE_LOC failed.."); |
| 243 | return status; |
| 244 | } |
| 245 | } |
| 246 | return status; |
| 247 | } |
| 248 | int InterfaceIdleModeWakeup(PMINI_ADAPTER Adapter) |
| 249 | { |
| 250 | ULONG Status = 0; |
| 251 | if(Adapter->bTriedToWakeUpFromlowPowerMode) |
| 252 | { |
| 253 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Wake up already attempted.. ignoring\n"); |
| 254 | } |
| 255 | else |
| 256 | { |
| 257 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"Writing Low Power Mode Abort pattern to the Device\n"); |
| 258 | Adapter->bTriedToWakeUpFromlowPowerMode = TRUE; |
| 259 | InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern); |
| 260 | |
| 261 | } |
| 262 | return Status; |
| 263 | } |
| 264 | |
| 265 | void InterfaceHandleShutdownModeWakeup(PMINI_ADAPTER Adapter) |
| 266 | { |
| 267 | unsigned int uiRegVal = 0; |
| 268 | INT Status = 0; |
| 269 | if(Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) |
| 270 | { |
| 271 | // clear idlemode interrupt. |
| 272 | uiRegVal = 0; |
| 273 | Status =wrmalt(Adapter,DEBUG_INTERRUPT_GENERATOR_REGISTOR, &uiRegVal, sizeof(uiRegVal)); |
| 274 | if(Status) |
| 275 | { |
| 276 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"WRM to DEBUG_INTERRUPT_GENERATOR_REGISTOR Failed with err :%d", Status); |
| 277 | return; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | else |
| 282 | { |
| 283 | |
| 284 | //clear Interrupt EP registers. |
| 285 | Status = rdmalt(Adapter,DEVICE_INT_OUT_EP_REG0, &uiRegVal, sizeof(uiRegVal)); |
| 286 | if(Status) |
| 287 | { |
| 288 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"RDM of DEVICE_INT_OUT_EP_REG0 failed with Err :%d", Status); |
| 289 | return; |
| 290 | } |
| 291 | |
| 292 | Status = rdmalt(Adapter,DEVICE_INT_OUT_EP_REG1, &uiRegVal, sizeof(uiRegVal)); |
| 293 | if(Status) |
| 294 | { |
| 295 | BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"RDM of DEVICE_INT_OUT_EP_REG1 failed with Err :%d", Status); |
| 296 | return; |
| 297 | } |
| 298 | } |
| 299 | } |
| 300 | |