1 /* 2 * SdioAdapter.c 3 * 4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved. 5 * Copyright(c) 2008 - 2009 Google, Inc. All rights reserved. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name Texas Instruments nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /** \file SdioAdapter.c 36 * \brief The SDIO driver adapter. Platform dependent. 37 * 38 * An adaptation layer between the lower SDIO driver (in BSP) and the upper Sdio 39 * Used for issuing all SDIO transaction types towards the lower SDIO-driver. 40 * Makes the decision whether to use Sync or Async transaction, and reflects it 41 * by the return value and calling its callback in case of Async. 42 * 43 * \see SdioAdapter.h, SdioDrv.c & h 44 */ 45 46 #ifdef CONFIG_MMC_EMBEDDED_SDIO 47 #include <linux/kernel.h> 48 #include <linux/mutex.h> 49 #include <linux/mmc/core.h> 50 #include <linux/mmc/card.h> 51 #include <linux/mmc/sdio_func.h> 52 #include <linux/mmc/sdio_ids.h> 53 #include "TxnDefs.h" 54 55 #define TI_SDIO_DEBUG 56 57 #define TIWLAN_MMC_MAX_DMA 8192 58 59 int wifi_set_carddetect( int on ); 60 61 static struct sdio_func *tiwlan_func = NULL; 62 static struct completion sdio_wait; 63 64 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 65 unsigned int uHwAddr, 66 void * pHostAddr, 67 unsigned int uLength, 68 unsigned int bDirection, 69 unsigned int bMore); 70 71 static int sdio_wifi_probe(struct sdio_func *func, 72 const struct sdio_device_id *id) 73 { 74 int rc; 75 76 printk("%s: %d\n", __FUNCTION__, func->class); 77 78 if (func->class != SDIO_CLASS_WLAN) 79 return -EINVAL; 80 81 sdio_claim_host(func); 82 83 rc = sdio_enable_func(func); 84 if (rc) 85 goto err1; 86 rc = sdio_set_block_size(func, 512); 87 88 if (rc) { 89 printk("%s: Unable to set blocksize\n", __FUNCTION__); 90 goto err2; 91 } 92 93 tiwlan_func = func; 94 complete(&sdio_wait); 95 return 0; 96 err2: 97 sdio_disable_func(func); 98 err1: 99 sdio_release_host(func); 100 complete(&sdio_wait); 101 return rc; 102 } 103 104 static void sdio_wifi_remove(struct sdio_func *func) 105 { 106 } 107 108 static const struct sdio_device_id sdio_wifi_ids[] = { 109 { SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN) }, 110 { }, 111 }; 112 113 MODULE_DEVICE_TABLE(sdio, sdio_wifi_ids); 114 115 static struct sdio_driver sdio_wifi_driver = { 116 .probe = sdio_wifi_probe, 117 .remove = sdio_wifi_remove, 118 .name = "sdio_wifi", 119 .id_table = sdio_wifi_ids, 120 }; 121 122 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 123 unsigned int uHwAddr, 124 void * pHostAddr, 125 unsigned int uLength, 126 unsigned int bDirection, 127 unsigned int bMore); 128 129 int sdioAdapt_ConnectBus (void * fCbFunc, 130 void * hCbArg, 131 unsigned int uBlkSizeShift, 132 unsigned int uSdioThreadPriority, 133 unsigned char **pTxDmaSrcAddr) 134 { 135 int rc; 136 137 init_completion(&sdio_wait); 138 wifi_set_carddetect( 1 ); 139 rc = sdio_register_driver(&sdio_wifi_driver); 140 if (rc < 0) { 141 printk(KERN_ERR "%s: Fail to register sdio_wifi_driver\n", __func__); 142 return rc; 143 } 144 if (!wait_for_completion_timeout(&sdio_wait, msecs_to_jiffies(10000))) { 145 printk(KERN_ERR "%s: Timed out waiting for device detect\n", __func__); 146 sdio_unregister_driver(&sdio_wifi_driver); 147 return -ENODEV; 148 } 149 /* Provide the DMA buffer address to the upper layer so it will use it as the transactions host buffer. */ 150 if (pTxDmaSrcAddr) { /* Dm: check what to do with it */ 151 *pTxDmaSrcAddr = kmalloc(TIWLAN_MMC_MAX_DMA, GFP_KERNEL | GFP_DMA); 152 } 153 return 0; 154 } 155 156 int sdioAdapt_DisconnectBus (void) 157 { 158 if (tiwlan_func) { 159 sdio_disable_func( tiwlan_func ); 160 sdio_release_host( tiwlan_func ); 161 } 162 wifi_set_carddetect( 0 ); 163 sdio_unregister_driver(&sdio_wifi_driver); 164 return 0; 165 } 166 167 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 168 unsigned int uHwAddr, 169 void * pHostAddr, 170 unsigned int uLength, 171 unsigned int bDirection, 172 unsigned int bMore) 173 { 174 unsigned char *pData = pHostAddr; 175 unsigned int i; 176 int rc = 0, final_rc = 0; 177 178 for (i = 0; i < uLength; i++) { 179 if( bDirection ) { 180 if (uFuncId == 0) 181 *pData = (unsigned char)sdio_f0_readb(tiwlan_func, uHwAddr, &rc); 182 else 183 *pData = (unsigned char)sdio_readb(tiwlan_func, uHwAddr, &rc); 184 } 185 else { 186 if (uFuncId == 0) 187 sdio_f0_writeb(tiwlan_func, *pData, uHwAddr, &rc); 188 else 189 sdio_writeb(tiwlan_func, *pData, uHwAddr, &rc); 190 } 191 if( rc ) { 192 final_rc = rc; 193 } 194 #ifdef TI_SDIO_DEBUG 195 printk(KERN_INFO "%c52: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)*pData); 196 #endif 197 uHwAddr++; 198 pData++; 199 } 200 /* If failed return ERROR, if succeeded return COMPLETE */ 201 if (final_rc) { 202 return TXN_STATUS_ERROR; 203 } 204 return TXN_STATUS_COMPLETE; 205 } 206 207 ETxnStatus sdioAdapt_Transact (unsigned int uFuncId, 208 unsigned int uHwAddr, 209 void * pHostAddr, 210 unsigned int uLength, 211 unsigned int bDirection, 212 unsigned int bBlkMode, 213 unsigned int bFixedAddr, 214 unsigned int bMore) 215 { 216 int rc; 217 218 if (uFuncId == 0) 219 return sdioAdapt_TransactBytes (uFuncId, uHwAddr, pHostAddr, 220 uLength, bDirection, bMore); 221 if (bDirection) { 222 if (bFixedAddr) 223 rc = sdio_memcpy_fromio(tiwlan_func, pHostAddr, uHwAddr, uLength); 224 else 225 rc = sdio_readsb(tiwlan_func, pHostAddr, uHwAddr, uLength); 226 227 } 228 else { 229 if (bFixedAddr) 230 rc = sdio_memcpy_toio(tiwlan_func, uHwAddr, pHostAddr, uLength); 231 else 232 rc = sdio_writesb(tiwlan_func, uHwAddr, pHostAddr, uLength); 233 } 234 #ifdef TI_SDIO_DEBUG 235 if (uLength == 1) 236 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(char *)pHostAddr)); 237 else if (uLength == 2) 238 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(short *)pHostAddr)); 239 else if (uLength == 4) 240 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(long *)pHostAddr)); 241 else 242 printk(KERN_INFO "%c53: [0x%x](%u) F[%d] B[%d] I[%d] = %d\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, uFuncId, bBlkMode, bFixedAddr, rc); 243 #endif 244 /* If failed return ERROR, if succeeded return COMPLETE */ 245 if (rc) { 246 return TXN_STATUS_ERROR; 247 } 248 return TXN_STATUS_COMPLETE; 249 } 250 251 #else 252 253 #include "SdioDrvDbg.h" 254 #include "TxnDefs.h" 255 #include "SdioAdapter.h" 256 #include "SdioDrv.h" 257 #include "bmtrace_api.h" 258 #include <linux/slab.h> 259 260 #ifdef SDIO_1_BIT /* see also in SdioDrv.c */ 261 #define SDIO_BITS_CODE 0x80 /* 1 bits */ 262 #else 263 #define SDIO_BITS_CODE 0x82 /* 4 bits */ 264 #endif 265 266 static unsigned char *pDmaBufAddr = 0; 267 268 /************************************************************************ 269 * Defines 270 ************************************************************************/ 271 /* Sync/Async Threshold */ 272 #ifdef FULL_ASYNC_MODE 273 #define SYNC_ASYNC_LENGTH_THRESH 0 /* Use Async for all transactions */ 274 #else 275 #define SYNC_ASYNC_LENGTH_THRESH 360 /* Use Async for transactions longer than this threshold (in bytes) */ 276 #endif 277 278 #define MAX_RETRIES 10 279 280 #define MAX_BUS_TXN_SIZE 8192 /* Max bus transaction size in bytes (for the DMA buffer allocation) */ 281 282 /* For block mode configuration */ 283 #define FN0_FBR2_REG_108 0x210 284 #define FN0_FBR2_REG_108_BIT_MASK 0xFFF 285 286 int sdioAdapt_ConnectBus (void * fCbFunc, 287 void * hCbArg, 288 unsigned int uBlkSizeShift, 289 unsigned int uSdioThreadPriority, 290 unsigned char **pRxDmaBufAddr, 291 unsigned int *pRxDmaBufLen, 292 unsigned char **pTxDmaBufAddr, 293 unsigned int *pTxDmaBufLen) 294 { 295 unsigned char uByte; 296 unsigned long uLong; 297 unsigned long uCount = 0; 298 unsigned int uBlkSize = 1 << uBlkSizeShift; 299 int iStatus; 300 301 if (uBlkSize < SYNC_ASYNC_LENGTH_THRESH) 302 { 303 PERR1("%s(): Block-Size should be bigger than SYNC_ASYNC_LENGTH_THRESH!!\n", __FUNCTION__ ); 304 } 305 306 /* Enabling clocks if thet are not enabled */ 307 sdioDrv_clk_enable(); 308 309 /* Allocate a DMA-able buffer and provide it to the upper layer to be used for all read and write transactions */ 310 if (pDmaBufAddr == 0) /* allocate only once (in case this function is called multiple times) */ 311 { 312 pDmaBufAddr = kmalloc(MAX_BUS_TXN_SIZE, GFP_KERNEL | GFP_DMA); 313 if (pDmaBufAddr == 0) 314 { 315 iStatus = -1; 316 goto fail; 317 } 318 } 319 *pRxDmaBufAddr = *pTxDmaBufAddr = pDmaBufAddr; 320 *pRxDmaBufLen = *pTxDmaBufLen = MAX_BUS_TXN_SIZE; 321 322 /* Init SDIO driver and HW */ 323 iStatus = sdioDrv_ConnectBus (fCbFunc, hCbArg, uBlkSizeShift, uSdioThreadPriority); 324 if (iStatus) { goto fail; } 325 326 /* Send commands sequence: 0, 5, 3, 7 */ 327 iStatus = sdioDrv_ExecuteCmd (SD_IO_GO_IDLE_STATE, 0, MMC_RSP_NONE, &uByte, sizeof(uByte)); 328 if (iStatus) 329 { 330 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_GO_IDLE_STATE); 331 goto fail; 332 } 333 334 iStatus = sdioDrv_ExecuteCmd (SDIO_CMD5, VDD_VOLTAGE_WINDOW, MMC_RSP_R4, &uByte, sizeof(uByte)); 335 if (iStatus) { 336 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SDIO_CMD5); 337 goto fail; 338 } 339 340 iStatus = sdioDrv_ExecuteCmd (SD_IO_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6, &uLong, sizeof(uLong)); 341 if (iStatus) { 342 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SEND_RELATIVE_ADDR); 343 goto fail; 344 } 345 346 iStatus = sdioDrv_ExecuteCmd (SD_IO_SELECT_CARD, uLong, MMC_RSP_R6, &uByte, sizeof(uByte)); 347 if (iStatus) { 348 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SELECT_CARD); 349 goto fail; 350 } 351 352 /* NOTE: 353 * ===== 354 * Each of the following loops is a workaround for a HW bug that will be solved in PG1.1 !! 355 * Each write of CMD-52 to function-0 should use it as follows: 356 * 1) Write the desired byte using CMD-52 357 * 2) Read back the byte using CMD-52 358 * 3) Write two dummy bytes to address 0xC8 using CMD-53 359 * 4) If the byte read in step 2 is different than the written byte repeat the sequence 360 */ 361 362 /* set device side bus width to 4 bit (for 1 bit write 0x80 instead of 0x82) */ 363 do 364 { 365 uByte = SDIO_BITS_CODE; 366 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1); 367 if (iStatus) { goto fail; } 368 369 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1); 370 if (iStatus) { goto fail; } 371 372 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 373 if (iStatus) { goto fail; } 374 375 uCount++; 376 377 } while ((uByte != SDIO_BITS_CODE) && (uCount < MAX_RETRIES)); 378 379 uCount = 0; 380 381 /* allow function 2 */ 382 do 383 { 384 uByte = 4; 385 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1); 386 if (iStatus) { goto fail; } 387 388 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1); 389 if (iStatus) { goto fail; } 390 391 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 392 if (iStatus) { goto fail; } 393 394 uCount++; 395 396 } while ((uByte != 4) && (uCount < MAX_RETRIES)); 397 398 399 #ifdef SDIO_IN_BAND_INTERRUPT 400 401 uCount = 0; 402 403 do 404 { 405 uByte = 3; 406 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1); 407 if (iStatus) { goto fail; } 408 409 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1); 410 if (iStatus) { goto fail; } 411 412 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 413 if (iStatus) { goto fail; } 414 415 uCount++; 416 417 } while ((uByte != 3) && (uCount < MAX_RETRIES)); 418 419 420 #endif 421 422 uCount = 0; 423 424 /* set block size for SDIO block mode */ 425 do 426 { 427 uLong = uBlkSize; 428 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1); 429 if (iStatus) { goto fail; } 430 431 iStatus = sdioDrv_ReadSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1); 432 if (iStatus) { goto fail; } 433 434 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1); 435 if (iStatus) { goto fail; } 436 437 uCount++; 438 439 } while (((uLong & FN0_FBR2_REG_108_BIT_MASK) != uBlkSize) && (uCount < MAX_RETRIES)); 440 441 if (uCount >= MAX_RETRIES) 442 { 443 /* Failed to write CMD52_WRITE to function 0 */ 444 iStatus = (int)uCount; 445 } 446 447 fail: 448 /* Disable the clocks for now */ 449 sdioDrv_clk_disable(); 450 451 return iStatus; 452 } 453 454 455 int sdioAdapt_DisconnectBus (void) 456 { 457 if (pDmaBufAddr) 458 { 459 kfree (pDmaBufAddr); 460 pDmaBufAddr = 0; 461 } 462 463 return sdioDrv_DisconnectBus (); 464 } 465 466 ETxnStatus sdioAdapt_Transact (unsigned int uFuncId, 467 unsigned int uHwAddr, 468 void * pHostAddr, 469 unsigned int uLength, 470 unsigned int bDirection, 471 unsigned int bBlkMode, 472 unsigned int bFixedAddr, 473 unsigned int bMore) 474 { 475 int iStatus; 476 477 /* If transction length is below threshold, use Sync methods */ 478 if (uLength < SYNC_ASYNC_LENGTH_THRESH) 479 { 480 /* Call read or write Sync method */ 481 if (bDirection) 482 { 483 CL_TRACE_START_L2(); 484 iStatus = sdioDrv_ReadSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore); 485 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadSync"); 486 } 487 else 488 { 489 CL_TRACE_START_L2(); 490 iStatus = sdioDrv_WriteSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore); 491 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteSync"); 492 } 493 494 /* If failed return ERROR, if succeeded return COMPLETE */ 495 if (iStatus) 496 { 497 return TXN_STATUS_ERROR; 498 } 499 return TXN_STATUS_COMPLETE; 500 } 501 502 /* If transction length is above threshold, use Async methods */ 503 else 504 { 505 /* Call read or write Async method */ 506 if (bDirection) 507 { 508 CL_TRACE_START_L2(); 509 iStatus = sdioDrv_ReadAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore); 510 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadAsync"); 511 } 512 else 513 { 514 CL_TRACE_START_L2(); 515 iStatus = sdioDrv_WriteAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore); 516 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteAsync"); 517 } 518 519 /* If failed return ERROR, if succeeded return PENDING */ 520 if (iStatus) 521 { 522 return TXN_STATUS_ERROR; 523 } 524 return TXN_STATUS_PENDING; 525 } 526 } 527 528 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId, 529 unsigned int uHwAddr, 530 void * pHostAddr, 531 unsigned int uLength, 532 unsigned int bDirection, 533 unsigned int bMore) 534 { 535 static unsigned int lastMore = 0; 536 int iStatus; 537 538 if ((bMore == 1) || (lastMore == bMore)) 539 { 540 sdioDrv_cancel_inact_timer(); 541 sdioDrv_clk_enable(); 542 } 543 544 /* Call read or write bytes Sync method */ 545 if (bDirection) 546 { 547 iStatus = sdioDrv_ReadSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore); 548 } 549 else 550 { 551 iStatus = sdioDrv_WriteSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore); 552 } 553 554 if (bMore == 0) 555 { 556 sdioDrv_start_inact_timer(); 557 } 558 lastMore = bMore; 559 560 /* If failed return ERROR, if succeeded return COMPLETE */ 561 if (iStatus) 562 { 563 return TXN_STATUS_ERROR; 564 } 565 return TXN_STATUS_COMPLETE; 566 } 567 #endif 568