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 /*-------------------------------------------------------------------*/
SDIO_SetFunc(struct sdio_func * func)48 void SDIO_SetFunc( struct sdio_func *func )
49 {
50 tiwlan_func = func;
51 }
52
SDIO_GetFunc(void)53 struct sdio_func *SDIO_GetFunc( void )
54 {
55 return tiwlan_func;
56 }
57
SDIO_Init(SDIO_ConfigParams * ConfigParams,SDIO_Handle * Handle)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
SDIO_Shutdown(SDIO_Handle Handle)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
SDIO_Start(SDIO_Handle Handle)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
SDIO_Reset(SDIO_Handle Handle)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
SDIO_Stop(SDIO_Handle Handle,unsigned long Wait_Window)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
spans_page(void * s,int len)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
vmalloc_to_unity(void * a)131 static void *vmalloc_to_unity(void *a)
132 {
133 pte_t *pte;
134 unsigned long virt = (unsigned long) a;
135 unsigned long phys;
136
137 pte = pte_offset_map(pmd_offset(pgd_offset_k(virt), virt), virt);
138 phys = (pte_val(*pte) & ~(PAGE_SIZE -1)) | (virt & (PAGE_SIZE -1));
139 pte_unmap(pte);
140 return phys_to_virt(phys);
141 }
142
SDIO_SyncRead(SDIO_Handle Handle,SDIO_Request_t * Req)143 SDIO_Status SDIO_SyncRead(SDIO_Handle Handle, SDIO_Request_t *Req)
144 {
145 struct sdio_func *func = (struct sdio_func *)Handle;
146 int rc;
147 void *tgt = Req->buffer;
148
149 if (Req->buffer_len >= DMA_THRESHOLD_SIZE) {
150 if (is_vmalloc_addr(tgt)) {
151 if (!spans_page(tgt, Req->buffer_len)) {
152 tgt = vmalloc_to_unity(tgt);
153 dmac_flush_range(Req->buffer,
154 Req->buffer + Req->buffer_len);
155 } else
156 tgt = sdio_dma_ptr;
157 }
158 }
159
160 if ((rc = sdio_memcpy_fromio(func, tgt, Req->peripheral_addr,
161 Req->buffer_len))) {
162 printk(KERN_ERR "%s: failed (%d)\n", __func__, rc);
163 return SDIO_FAILURE;
164 }
165
166 if (tgt == sdio_dma_ptr)
167 memcpy(Req->buffer, sdio_dma_ptr, Req->buffer_len);
168
169 return SDIO_SUCCESS;
170 }
171
SDIO_SyncWrite(SDIO_Handle Handle,SDIO_Request_t * Req)172 SDIO_Status SDIO_SyncWrite(SDIO_Handle Handle, SDIO_Request_t *Req)
173 {
174 struct sdio_func *func = (struct sdio_func *)Handle;
175 int rc;
176 void *src = Req->buffer;
177
178 if (Req->buffer_len >= DMA_THRESHOLD_SIZE) {
179 #if USE_SKETCHY_WRITES
180 if (is_vmalloc_addr(src)) {
181 if (!spans_page(src, Req->buffer_len)) {
182 src = vmalloc_to_unity(src);
183 dmac_clean_range(Req->buffer,
184 Req->buffer + Req->buffer_len);
185 } else {
186 #endif
187 src = sdio_dma_ptr;
188 memcpy(src, Req->buffer, Req->buffer_len);
189 #if USE_SKETCHY_WRITES
190 }
191 }
192 #endif
193 }
194
195 rc = sdio_memcpy_toio(func, Req->peripheral_addr, src,
196 Req->buffer_len);
197
198 if (!rc)
199 return SDIO_SUCCESS;
200
201 printk(KERN_ERR "%s: failed (%d)\n", __func__, rc);
202 return SDIO_FAILURE;
203 }
204 #endif
205