1 /* tnetw_sdio.c 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 as 5 * published by the Free Software Foundation. 6 * 7 * Copyright Texas Instruments Incorporated (Oct 2005) 8 * THIS CODE/PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 9 * EITHER EXPRESS OR IMPLIED, INCLUDED BUT NOT LIMITED TO , THE IMPLIED 10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 11 * This program has been modified from its original operation by Texas 12 * Instruments Incorporated. These changes are covered under version 2 13 * of the GNU General Public License, dated June 1991. 14 * 15 * Copyright Google Inc (Feb 2008) 16 */ 17 /*-------------------------------------------------------------------*/ 18 #ifdef TIWLAN_MSM7000 19 #include <linux/mm.h> 20 #include <linux/vmalloc.h> 21 #include <linux/pagemap.h> 22 #include <asm/pgtable.h> 23 #include <asm/cacheflush.h> 24 25 #include <linux/delay.h> 26 #include <linux/mmc/core.h> 27 #include <linux/mmc/card.h> 28 #include <linux/mmc/host.h> 29 #include <linux/mmc/sdio_func.h> 30 #include <linux/mmc/sdio_ids.h> 31 #include "esta_drv.h" 32 #include "mmc_omap_api.h" 33 #include "osApi.h" 34 35 /*-------------------------------------------------------------------*/ 36 extern int tiwlan_sdio_init(struct sdio_func *func); 37 extern int sdio_reset_comm(struct mmc_card *card); 38 39 /*-------------------------------------------------------------------*/ 40 static struct sdio_func *tiwlan_func = NULL; 41 static int sdio_reset_flag = 0; 42 43 #define DMA_THRESHOLD_SIZE 64 44 static void *sdio_dma_ptr = NULL; 45 #define USE_SKETCHY_WRITES 0 46 47 /*-------------------------------------------------------------------*/ 48 void SDIO_SetFunc( struct sdio_func *func ) 49 { 50 tiwlan_func = func; 51 } 52 53 struct sdio_func *SDIO_GetFunc( void ) 54 { 55 return tiwlan_func; 56 } 57 58 SDIO_Status SDIO_Init(SDIO_ConfigParams *ConfigParams, SDIO_Handle *Handle) 59 { 60 if (Handle == NULL) { 61 printk(KERN_ERR "Error: SDIO_Init() called with NULL!\n"); 62 return SDIO_FAILURE; 63 } 64 65 *Handle = (SDIO_Handle)SDIO_GetFunc(); 66 if ((*Handle) == NULL) { 67 printk(KERN_ERR "SDIO_Init() called before init!\n"); 68 return SDIO_FAILURE; 69 } 70 71 if (!sdio_dma_ptr) { 72 if (!(sdio_dma_ptr = kmalloc(PAGE_SIZE, GFP_KERNEL))) { 73 printk(KERN_ERR "Failed to alloc DMA bounce buffer\n"); 74 return SDIO_FAILURE; 75 } 76 } 77 return SDIO_SUCCESS; 78 } 79 80 SDIO_Status SDIO_Shutdown(SDIO_Handle Handle) 81 { 82 if (sdio_dma_ptr) { 83 kfree(sdio_dma_ptr); 84 sdio_dma_ptr = NULL; 85 } 86 return SDIO_SUCCESS; 87 } 88 89 SDIO_Status SDIO_Start(SDIO_Handle Handle) 90 { 91 struct sdio_func *func = (struct sdio_func *)Handle; 92 93 if (func) { 94 if (sdio_reset_flag) { 95 sdio_reset_flag = 0; 96 if (tiwlan_sdio_init(func)) { 97 printk("TI: tiwlan_sdio_init Error!\n"); 98 return SDIO_FAILURE; 99 } 100 101 } 102 } 103 return SDIO_SUCCESS; 104 } 105 106 SDIO_Status SDIO_Reset(SDIO_Handle Handle) 107 { 108 struct sdio_func *func = (struct sdio_func *)Handle; 109 110 if (func && func->card) { 111 sdio_release_host(func); 112 sdio_reset_comm(func->card); 113 sdio_claim_host(func); 114 } 115 return SDIO_SUCCESS; 116 } 117 118 SDIO_Status SDIO_Stop(SDIO_Handle Handle, unsigned long Wait_Window) 119 { 120 sdio_reset_flag = 1; 121 return SDIO_Reset(Handle); 122 } 123 124 static inline int spans_page(void *s, int len) 125 { 126 if (((unsigned long) s + len) <= ((((unsigned long) s) & ~(PAGE_SIZE-1)) + PAGE_SIZE)) 127 return 0; 128 return 1; 129 } 130 131 static void *vmalloc_to_unity(void *a) 132 { 133 struct page *pg; 134 unsigned long virt = (unsigned long) a; 135 136 pg = vmalloc_to_page(a); 137 virt = (unsigned long)page_address(pg) | (virt & (PAGE_SIZE -1)); 138 return (void *)virt; 139 } 140 141 SDIO_Status SDIO_SyncRead(SDIO_Handle Handle, SDIO_Request_t *Req) 142 { 143 struct sdio_func *func = (struct sdio_func *)Handle; 144 int rc; 145 void *tgt = Req->buffer; 146 147 if (Req->buffer_len >= DMA_THRESHOLD_SIZE) { 148 if (is_vmalloc_addr(tgt)) { 149 if (!spans_page(tgt, Req->buffer_len)) { 150 tgt = vmalloc_to_unity(tgt); 151 dmac_flush_range(Req->buffer, 152 Req->buffer + Req->buffer_len); 153 } else 154 tgt = sdio_dma_ptr; 155 } 156 } 157 158 if ((rc = sdio_memcpy_fromio(func, tgt, Req->peripheral_addr, 159 Req->buffer_len))) { 160 printk(KERN_ERR "%s: failed (%d)\n", __func__, rc); 161 return SDIO_FAILURE; 162 } 163 164 if (tgt == sdio_dma_ptr) 165 memcpy(Req->buffer, sdio_dma_ptr, Req->buffer_len); 166 167 return SDIO_SUCCESS; 168 } 169 170 SDIO_Status SDIO_SyncWrite(SDIO_Handle Handle, SDIO_Request_t *Req) 171 { 172 struct sdio_func *func = (struct sdio_func *)Handle; 173 int rc; 174 void *src = Req->buffer; 175 176 if (Req->buffer_len >= DMA_THRESHOLD_SIZE) { 177 #if USE_SKETCHY_WRITES 178 if (is_vmalloc_addr(src)) { 179 if (!spans_page(src, Req->buffer_len)) { 180 src = vmalloc_to_unity(src); 181 dmac_clean_range(Req->buffer, 182 Req->buffer + Req->buffer_len); 183 } else { 184 #endif 185 src = sdio_dma_ptr; 186 memcpy(src, Req->buffer, Req->buffer_len); 187 #if USE_SKETCHY_WRITES 188 } 189 } 190 #endif 191 } 192 193 rc = sdio_memcpy_toio(func, Req->peripheral_addr, src, 194 Req->buffer_len); 195 196 if (!rc) 197 return SDIO_SUCCESS; 198 199 printk(KERN_ERR "%s: failed (%d)\n", __func__, rc); 200 return SDIO_FAILURE; 201 } 202 #endif 203