OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* Copyright Statement: |
2 | * |
||
3 | * This software/firmware and related documentation ("MediaTek Software") are |
||
4 | * protected under relevant copyright laws. The information contained herein |
||
5 | * is confidential and proprietary to MediaTek Inc. and/or its licensors. |
||
6 | * Without the prior written permission of MediaTek inc. and/or its licensors, |
||
7 | * any reproduction, modification, use or disclosure of MediaTek Software, |
||
8 | * and information contained herein, in whole or in part, shall be strictly prohibited. |
||
9 | * |
||
10 | * MediaTek Inc. (C) 2010. All rights reserved. |
||
11 | * |
||
12 | * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
||
13 | * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
||
14 | * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON |
||
15 | * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
||
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
||
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
||
18 | * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
||
19 | * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
||
20 | * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH |
||
21 | * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES |
||
22 | * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES |
||
23 | * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK |
||
24 | * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
||
25 | * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND |
||
26 | * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
||
27 | * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
||
28 | * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO |
||
29 | * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
||
30 | * |
||
31 | * The following software/firmware and/or related documentation ("MediaTek Software") |
||
32 | * have been modified by MediaTek Inc. All revisions are subject to any receiver's |
||
33 | * applicable license agreements with MediaTek Inc. |
||
34 | */ |
||
35 | |||
36 | #include <linux/module.h> |
||
3 | office | 37 | #include <linux/moduleparam.h> |
38 | #include <linux/init.h> |
||
1 | office | 39 | #include <linux/spinlock.h> |
3 | office | 40 | #include <linux/timer.h> |
41 | #include <linux/ioport.h> |
||
42 | #include <linux/device.h> |
||
1 | office | 43 | #include <linux/platform_device.h> |
44 | #include <linux/interrupt.h> |
||
3 | office | 45 | #include <linux/delay.h> |
46 | #include <linux/blkdev.h> |
||
47 | #include <linux/slab.h> |
||
1 | office | 48 | #include <linux/mmc/host.h> |
3 | office | 49 | #include <linux/mmc/card.h> |
50 | #include <linux/mmc/core.h> |
||
1 | office | 51 | #include <linux/mmc/mmc.h> |
52 | #include <linux/mmc/sd.h> |
||
53 | #include <linux/mmc/sdio.h> |
||
3 | office | 54 | #include <linux/dma-mapping.h> |
1 | office | 55 | |
3 | office | 56 | /* +++ by chhung */ |
57 | #include <linux/types.h> |
||
58 | #include <linux/kernel.h> |
||
59 | #include <linux/version.h> |
||
60 | #include <linux/pm.h> |
||
61 | #include <linux/of.h> |
||
1 | office | 62 | |
3 | office | 63 | #define MSDC_SMPL_FALLING (1) |
64 | #define MSDC_CD_PIN_EN (1 << 0) /* card detection pin is wired */ |
||
65 | #define MSDC_WP_PIN_EN (1 << 1) /* write protection pin is wired */ |
||
66 | #define MSDC_REMOVABLE (1 << 5) /* removable slot */ |
||
67 | #define MSDC_SYS_SUSPEND (1 << 6) /* suspended by system */ |
||
68 | #define MSDC_HIGHSPEED (1 << 7) |
||
1 | office | 69 | |
70 | //#define IRQ_SDC 14 //MT7620 /*FIXME*/ |
||
71 | #ifdef CONFIG_SOC_MT7621 |
||
72 | #define RALINK_SYSCTL_BASE 0xbe000000 |
||
73 | #define RALINK_MSDC_BASE 0xbe130000 |
||
74 | #else |
||
75 | #define RALINK_SYSCTL_BASE 0xb0000000 |
||
76 | #define RALINK_MSDC_BASE 0xb0130000 |
||
77 | #endif |
||
78 | #define IRQ_SDC 22 /*FIXME*/ |
||
79 | |||
3 | office | 80 | #include <asm/dma.h> |
81 | /* end of +++ */ |
||
82 | |||
83 | |||
84 | #include <asm/mach-ralink/ralink_regs.h> |
||
85 | |||
86 | #if 0 /* --- by chhung */ |
||
87 | #include <mach/board.h> |
||
88 | #include <mach/mt6575_devs.h> |
||
89 | #include <mach/mt6575_typedefs.h> |
||
90 | #include <mach/mt6575_clock_manager.h> |
||
91 | #include <mach/mt6575_pm_ldo.h> |
||
92 | //#include <mach/mt6575_pll.h> |
||
93 | //#include <mach/mt6575_gpio.h> |
||
94 | //#include <mach/mt6575_gpt_sw.h> |
||
95 | #include <asm/tcm.h> |
||
96 | // #include <mach/mt6575_gpt.h> |
||
97 | #endif /* end of --- */ |
||
98 | |||
99 | #include "mt6575_sd.h" |
||
100 | #include "dbg.h" |
||
101 | |||
102 | /* +++ by chhung */ |
||
103 | #include "board.h" |
||
104 | /* end of +++ */ |
||
105 | |||
106 | #if 0 /* --- by chhung */ |
||
107 | #define isb() __asm__ __volatile__ ("" : : : "memory") |
||
108 | #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \ |
||
109 | : : "r" (0) : "memory") |
||
110 | #define dmb() __asm__ __volatile__ ("" : : : "memory") |
||
111 | #endif /* end of --- */ |
||
112 | |||
1 | office | 113 | #define DRV_NAME "mtk-sd" |
114 | |||
3 | office | 115 | #define HOST_MAX_NUM (1) /* +/- by chhung */ |
116 | |||
117 | #if defined (CONFIG_SOC_MT7620) |
||
1 | office | 118 | #define HOST_MAX_MCLK (48000000) /* +/- by chhung */ |
3 | office | 119 | #elif defined (CONFIG_SOC_MT7621) |
1 | office | 120 | #define HOST_MAX_MCLK (50000000) /* +/- by chhung */ |
121 | #endif |
||
122 | #define HOST_MIN_MCLK (260000) |
||
123 | |||
124 | #define HOST_MAX_BLKSZ (2048) |
||
125 | |||
126 | #define MSDC_OCR_AVAIL (MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33) |
||
127 | |||
128 | #define GPIO_PULL_DOWN (0) |
||
129 | #define GPIO_PULL_UP (1) |
||
130 | |||
131 | #if 0 /* --- by chhung */ |
||
132 | #define MSDC_CLKSRC_REG (0xf100000C) |
||
3 | office | 133 | #define PDN_REG (0xF1000010) |
1 | office | 134 | #endif /* end of --- */ |
135 | |||
136 | #define DEFAULT_DEBOUNCE (8) /* 8 cycles */ |
||
137 | #define DEFAULT_DTOC (40) /* data timeout counter. 65536x40 sclk. */ |
||
138 | |||
3 | office | 139 | #define CMD_TIMEOUT (HZ/10) /* 100ms */ |
140 | #define DAT_TIMEOUT (HZ/2 * 5) /* 500ms x5 */ |
||
1 | office | 141 | |
142 | #define MAX_DMA_CNT (64 * 1024 - 512) /* a single transaction for WIFI may be 50K*/ |
||
143 | |||
144 | #define MAX_GPD_NUM (1 + 1) /* one null gpd */ |
||
145 | #define MAX_BD_NUM (1024) |
||
146 | #define MAX_BD_PER_GPD (MAX_BD_NUM) |
||
147 | |||
148 | #define MAX_HW_SGMTS (MAX_BD_NUM) |
||
149 | #define MAX_PHY_SGMTS (MAX_BD_NUM) |
||
150 | #define MAX_SGMT_SZ (MAX_DMA_CNT) |
||
3 | office | 151 | #define MAX_REQ_SZ (MAX_SGMT_SZ * 8) |
1 | office | 152 | |
3 | office | 153 | static int mtk_sw_poll; |
154 | |||
1 | office | 155 | static int cd_active_low = 1; |
156 | |||
157 | //================================= |
||
158 | #define PERI_MSDC0_PDN (15) |
||
159 | //#define PERI_MSDC1_PDN (16) |
||
160 | //#define PERI_MSDC2_PDN (17) |
||
161 | //#define PERI_MSDC3_PDN (18) |
||
162 | |||
163 | #if 0 /* --- by chhung */ |
||
164 | /* gate means clock power down */ |
||
3 | office | 165 | static int g_clk_gate = 0; |
1 | office | 166 | #define msdc_gate_clock(id) \ |
3 | office | 167 | do { \ |
168 | g_clk_gate &= ~(1 << ((id) + PERI_MSDC0_PDN)); \ |
||
169 | } while(0) |
||
1 | office | 170 | /* not like power down register. 1 means clock on. */ |
171 | #define msdc_ungate_clock(id) \ |
||
3 | office | 172 | do { \ |
173 | g_clk_gate |= 1 << ((id) + PERI_MSDC0_PDN); \ |
||
174 | } while(0) |
||
1 | office | 175 | |
3 | office | 176 | // do we need sync object or not |
177 | void msdc_clk_status(int * status) |
||
1 | office | 178 | { |
3 | office | 179 | *status = g_clk_gate; |
1 | office | 180 | } |
181 | #endif /* end of --- */ |
||
182 | |||
183 | /* +++ by chhung */ |
||
184 | struct msdc_hw msdc0_hw = { |
||
185 | .clk_src = 0, |
||
3 | office | 186 | .cmd_edge = MSDC_SMPL_FALLING, |
187 | .data_edge = MSDC_SMPL_FALLING, |
||
188 | .clk_drv = 4, |
||
189 | .cmd_drv = 4, |
||
190 | .dat_drv = 4, |
||
191 | .data_pins = 4, |
||
192 | .data_offset = 0, |
||
193 | .flags = MSDC_SYS_SUSPEND | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED, |
||
194 | // .flags = MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE, |
||
1 | office | 195 | }; |
196 | |||
3 | office | 197 | static struct resource mtk_sd_resources[] = { |
198 | [0] = { |
||
199 | .start = RALINK_MSDC_BASE, |
||
200 | .end = RALINK_MSDC_BASE+0x3fff, |
||
201 | .flags = IORESOURCE_MEM, |
||
202 | }, |
||
203 | [1] = { |
||
204 | .start = IRQ_SDC, /*FIXME*/ |
||
205 | .end = IRQ_SDC, /*FIXME*/ |
||
206 | .flags = IORESOURCE_IRQ, |
||
207 | }, |
||
208 | }; |
||
209 | |||
210 | static struct platform_device mtk_sd_device = { |
||
211 | .name = "mtk-sd", |
||
212 | .id = 0, |
||
213 | .num_resources = ARRAY_SIZE(mtk_sd_resources), |
||
214 | .resource = mtk_sd_resources, |
||
215 | }; |
||
1 | office | 216 | /* end of +++ */ |
217 | |||
218 | static int msdc_rsp[] = { |
||
3 | office | 219 | 0, /* RESP_NONE */ |
220 | 1, /* RESP_R1 */ |
||
221 | 2, /* RESP_R2 */ |
||
222 | 3, /* RESP_R3 */ |
||
223 | 4, /* RESP_R4 */ |
||
224 | 1, /* RESP_R5 */ |
||
225 | 1, /* RESP_R6 */ |
||
226 | 1, /* RESP_R7 */ |
||
227 | 7, /* RESP_R1b */ |
||
1 | office | 228 | }; |
229 | |||
3 | office | 230 | /* For Inhanced DMA */ |
231 | #define msdc_init_gpd_ex(gpd,extlen,cmd,arg,blknum) \ |
||
232 | do { \ |
||
233 | ((gpd_t*)gpd)->extlen = extlen; \ |
||
234 | ((gpd_t*)gpd)->cmd = cmd; \ |
||
235 | ((gpd_t*)gpd)->arg = arg; \ |
||
236 | ((gpd_t*)gpd)->blknum = blknum; \ |
||
237 | }while(0) |
||
238 | |||
239 | #define msdc_init_bd(bd, blkpad, dwpad, dptr, dlen) \ |
||
240 | do { \ |
||
241 | BUG_ON(dlen > 0xFFFFUL); \ |
||
242 | ((bd_t*)bd)->blkpad = blkpad; \ |
||
243 | ((bd_t*)bd)->dwpad = dwpad; \ |
||
244 | ((bd_t*)bd)->ptr = (void*)dptr; \ |
||
245 | ((bd_t*)bd)->buflen = dlen; \ |
||
246 | }while(0) |
||
247 | |||
1 | office | 248 | #define msdc_txfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16) |
249 | #define msdc_rxfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) >> 0) |
||
250 | #define msdc_fifo_write32(v) sdr_write32(MSDC_TXDATA, (v)) |
||
251 | #define msdc_fifo_write8(v) sdr_write8(MSDC_TXDATA, (v)) |
||
252 | #define msdc_fifo_read32() sdr_read32(MSDC_RXDATA) |
||
3 | office | 253 | #define msdc_fifo_read8() sdr_read8(MSDC_RXDATA) |
1 | office | 254 | |
3 | office | 255 | |
1 | office | 256 | #define msdc_dma_on() sdr_clr_bits(MSDC_CFG, MSDC_CFG_PIO) |
3 | office | 257 | #define msdc_dma_off() sdr_set_bits(MSDC_CFG, MSDC_CFG_PIO) |
1 | office | 258 | |
3 | office | 259 | #define msdc_retry(expr,retry,cnt) \ |
260 | do { \ |
||
261 | int backup = cnt; \ |
||
262 | while (retry) { \ |
||
263 | if (!(expr)) break; \ |
||
264 | if (cnt-- == 0) { \ |
||
265 | retry--; mdelay(1); cnt = backup; \ |
||
266 | } \ |
||
267 | } \ |
||
268 | WARN_ON(retry == 0); \ |
||
269 | } while(0) |
||
1 | office | 270 | |
3 | office | 271 | #if 0 /* --- by chhung */ |
272 | #define msdc_reset() \ |
||
273 | do { \ |
||
274 | int retry = 3, cnt = 1000; \ |
||
275 | sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \ |
||
276 | dsb(); \ |
||
277 | msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \ |
||
278 | } while(0) |
||
279 | #else |
||
280 | #define msdc_reset() \ |
||
281 | do { \ |
||
282 | int retry = 3, cnt = 1000; \ |
||
283 | sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \ |
||
284 | msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \ |
||
285 | } while(0) |
||
286 | #endif /* end of +/- */ |
||
1 | office | 287 | |
288 | #define msdc_clr_int() \ |
||
3 | office | 289 | do { \ |
290 | volatile u32 val = sdr_read32(MSDC_INT); \ |
||
291 | sdr_write32(MSDC_INT, val); \ |
||
292 | } while(0) |
||
1 | office | 293 | |
294 | #define msdc_clr_fifo() \ |
||
3 | office | 295 | do { \ |
296 | int retry = 3, cnt = 1000; \ |
||
297 | sdr_set_bits(MSDC_FIFOCS, MSDC_FIFOCS_CLR); \ |
||
298 | msdc_retry(sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_CLR, retry, cnt); \ |
||
299 | } while(0) |
||
1 | office | 300 | |
301 | #define msdc_irq_save(val) \ |
||
3 | office | 302 | do { \ |
303 | val = sdr_read32(MSDC_INTEN); \ |
||
304 | sdr_clr_bits(MSDC_INTEN, val); \ |
||
305 | } while(0) |
||
306 | |||
1 | office | 307 | #define msdc_irq_restore(val) \ |
3 | office | 308 | do { \ |
309 | sdr_set_bits(MSDC_INTEN, val); \ |
||
310 | } while(0) |
||
1 | office | 311 | |
312 | /* clock source for host: global */ |
||
3 | office | 313 | #if defined (CONFIG_SOC_MT7620) |
1 | office | 314 | static u32 hclks[] = {48000000}; /* +/- by chhung */ |
3 | office | 315 | #elif defined (CONFIG_SOC_MT7621) |
1 | office | 316 | static u32 hclks[] = {50000000}; /* +/- by chhung */ |
317 | #endif |
||
318 | |||
319 | //============================================ |
||
320 | // the power for msdc host controller: global |
||
3 | office | 321 | // always keep the VMC on. |
1 | office | 322 | //============================================ |
323 | #define msdc_vcore_on(host) \ |
||
3 | office | 324 | do { \ |
325 | INIT_MSG("[+]VMC ref. count<%d>", ++host->pwr_ref); \ |
||
326 | (void)hwPowerOn(MT65XX_POWER_LDO_VMC, VOL_3300, "SD"); \ |
||
327 | } while (0) |
||
1 | office | 328 | #define msdc_vcore_off(host) \ |
3 | office | 329 | do { \ |
330 | INIT_MSG("[-]VMC ref. count<%d>", --host->pwr_ref); \ |
||
331 | (void)hwPowerDown(MT65XX_POWER_LDO_VMC, "SD"); \ |
||
332 | } while (0) |
||
1 | office | 333 | |
334 | //==================================== |
||
3 | office | 335 | // the vdd output for card: global |
336 | // always keep the VMCH on. |
||
337 | //==================================== |
||
1 | office | 338 | #define msdc_vdd_on(host) \ |
3 | office | 339 | do { \ |
340 | (void)hwPowerOn(MT65XX_POWER_LDO_VMCH, VOL_3300, "SD"); \ |
||
341 | } while (0) |
||
1 | office | 342 | #define msdc_vdd_off(host) \ |
3 | office | 343 | do { \ |
344 | (void)hwPowerDown(MT65XX_POWER_LDO_VMCH, "SD"); \ |
||
345 | } while (0) |
||
1 | office | 346 | |
347 | #define sdc_is_busy() (sdr_read32(SDC_STS) & SDC_STS_SDCBUSY) |
||
348 | #define sdc_is_cmd_busy() (sdr_read32(SDC_STS) & SDC_STS_CMDBUSY) |
||
349 | |||
3 | office | 350 | #define sdc_send_cmd(cmd,arg) \ |
351 | do { \ |
||
352 | sdr_write32(SDC_ARG, (arg)); \ |
||
353 | sdr_write32(SDC_CMD, (cmd)); \ |
||
354 | } while(0) |
||
1 | office | 355 | |
356 | // can modify to read h/w register. |
||
357 | //#define is_card_present(h) ((sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1); |
||
3 | office | 358 | #define is_card_present(h) (((struct msdc_host*)(h))->card_inserted) |
1 | office | 359 | |
360 | /* +++ by chhung */ |
||
361 | #ifndef __ASSEMBLY__ |
||
362 | #define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff) |
||
363 | #else |
||
364 | #define PHYSADDR(a) ((a) & 0x1fffffff) |
||
365 | #endif |
||
366 | /* end of +++ */ |
||
3 | office | 367 | static unsigned int msdc_do_command(struct msdc_host *host, |
368 | struct mmc_command *cmd, |
||
369 | int tune, |
||
370 | unsigned long timeout); |
||
371 | |||
372 | static int msdc_tune_cmdrsp(struct msdc_host*host,struct mmc_command *cmd); |
||
1 | office | 373 | |
374 | #ifdef MT6575_SD_DEBUG |
||
375 | static void msdc_dump_card_status(struct msdc_host *host, u32 status) |
||
376 | { |
||
3 | office | 377 | static char *state[] = { |
378 | "Idle", /* 0 */ |
||
379 | "Ready", /* 1 */ |
||
380 | "Ident", /* 2 */ |
||
381 | "Stby", /* 3 */ |
||
382 | "Tran", /* 4 */ |
||
383 | "Data", /* 5 */ |
||
384 | "Rcv", /* 6 */ |
||
385 | "Prg", /* 7 */ |
||
386 | "Dis", /* 8 */ |
||
387 | "Reserved", /* 9 */ |
||
388 | "Reserved", /* 10 */ |
||
389 | "Reserved", /* 11 */ |
||
390 | "Reserved", /* 12 */ |
||
391 | "Reserved", /* 13 */ |
||
392 | "Reserved", /* 14 */ |
||
393 | "I/O mode", /* 15 */ |
||
394 | }; |
||
395 | if (status & R1_OUT_OF_RANGE) |
||
396 | N_MSG(RSP, "[CARD_STATUS] Out of Range"); |
||
397 | if (status & R1_ADDRESS_ERROR) |
||
398 | N_MSG(RSP, "[CARD_STATUS] Address Error"); |
||
399 | if (status & R1_BLOCK_LEN_ERROR) |
||
400 | N_MSG(RSP, "[CARD_STATUS] Block Len Error"); |
||
401 | if (status & R1_ERASE_SEQ_ERROR) |
||
402 | N_MSG(RSP, "[CARD_STATUS] Erase Seq Error"); |
||
403 | if (status & R1_ERASE_PARAM) |
||
404 | N_MSG(RSP, "[CARD_STATUS] Erase Param"); |
||
405 | if (status & R1_WP_VIOLATION) |
||
406 | N_MSG(RSP, "[CARD_STATUS] WP Violation"); |
||
407 | if (status & R1_CARD_IS_LOCKED) |
||
408 | N_MSG(RSP, "[CARD_STATUS] Card is Locked"); |
||
409 | if (status & R1_LOCK_UNLOCK_FAILED) |
||
410 | N_MSG(RSP, "[CARD_STATUS] Lock/Unlock Failed"); |
||
411 | if (status & R1_COM_CRC_ERROR) |
||
412 | N_MSG(RSP, "[CARD_STATUS] Command CRC Error"); |
||
413 | if (status & R1_ILLEGAL_COMMAND) |
||
414 | N_MSG(RSP, "[CARD_STATUS] Illegal Command"); |
||
415 | if (status & R1_CARD_ECC_FAILED) |
||
416 | N_MSG(RSP, "[CARD_STATUS] Card ECC Failed"); |
||
417 | if (status & R1_CC_ERROR) |
||
418 | N_MSG(RSP, "[CARD_STATUS] CC Error"); |
||
419 | if (status & R1_ERROR) |
||
420 | N_MSG(RSP, "[CARD_STATUS] Error"); |
||
421 | if (status & R1_UNDERRUN) |
||
422 | N_MSG(RSP, "[CARD_STATUS] Underrun"); |
||
423 | if (status & R1_OVERRUN) |
||
424 | N_MSG(RSP, "[CARD_STATUS] Overrun"); |
||
425 | if (status & R1_CID_CSD_OVERWRITE) |
||
426 | N_MSG(RSP, "[CARD_STATUS] CID/CSD Overwrite"); |
||
427 | if (status & R1_WP_ERASE_SKIP) |
||
428 | N_MSG(RSP, "[CARD_STATUS] WP Eraser Skip"); |
||
429 | if (status & R1_CARD_ECC_DISABLED) |
||
430 | N_MSG(RSP, "[CARD_STATUS] Card ECC Disabled"); |
||
431 | if (status & R1_ERASE_RESET) |
||
432 | N_MSG(RSP, "[CARD_STATUS] Erase Reset"); |
||
433 | if (status & R1_READY_FOR_DATA) |
||
434 | N_MSG(RSP, "[CARD_STATUS] Ready for Data"); |
||
435 | if (status & R1_SWITCH_ERROR) |
||
436 | N_MSG(RSP, "[CARD_STATUS] Switch error"); |
||
437 | if (status & R1_APP_CMD) |
||
438 | N_MSG(RSP, "[CARD_STATUS] App Command"); |
||
439 | |||
440 | N_MSG(RSP, "[CARD_STATUS] '%s' State", state[R1_CURRENT_STATE(status)]); |
||
1 | office | 441 | } |
442 | |||
443 | static void msdc_dump_ocr_reg(struct msdc_host *host, u32 resp) |
||
444 | { |
||
3 | office | 445 | if (resp & (1 << 7)) |
446 | N_MSG(RSP, "[OCR] Low Voltage Range"); |
||
447 | if (resp & (1 << 15)) |
||
448 | N_MSG(RSP, "[OCR] 2.7-2.8 volt"); |
||
449 | if (resp & (1 << 16)) |
||
450 | N_MSG(RSP, "[OCR] 2.8-2.9 volt"); |
||
451 | if (resp & (1 << 17)) |
||
452 | N_MSG(RSP, "[OCR] 2.9-3.0 volt"); |
||
453 | if (resp & (1 << 18)) |
||
454 | N_MSG(RSP, "[OCR] 3.0-3.1 volt"); |
||
455 | if (resp & (1 << 19)) |
||
456 | N_MSG(RSP, "[OCR] 3.1-3.2 volt"); |
||
457 | if (resp & (1 << 20)) |
||
458 | N_MSG(RSP, "[OCR] 3.2-3.3 volt"); |
||
459 | if (resp & (1 << 21)) |
||
460 | N_MSG(RSP, "[OCR] 3.3-3.4 volt"); |
||
461 | if (resp & (1 << 22)) |
||
462 | N_MSG(RSP, "[OCR] 3.4-3.5 volt"); |
||
463 | if (resp & (1 << 23)) |
||
464 | N_MSG(RSP, "[OCR] 3.5-3.6 volt"); |
||
465 | if (resp & (1 << 24)) |
||
466 | N_MSG(RSP, "[OCR] Switching to 1.8V Accepted (S18A)"); |
||
467 | if (resp & (1 << 30)) |
||
468 | N_MSG(RSP, "[OCR] Card Capacity Status (CCS)"); |
||
469 | if (resp & (1 << 31)) |
||
470 | N_MSG(RSP, "[OCR] Card Power Up Status (Idle)"); |
||
471 | else |
||
472 | N_MSG(RSP, "[OCR] Card Power Up Status (Busy)"); |
||
1 | office | 473 | } |
474 | |||
475 | static void msdc_dump_rca_resp(struct msdc_host *host, u32 resp) |
||
476 | { |
||
3 | office | 477 | u32 status = (((resp >> 15) & 0x1) << 23) | |
478 | (((resp >> 14) & 0x1) << 22) | |
||
479 | (((resp >> 13) & 0x1) << 19) | |
||
480 | (resp & 0x1fff); |
||
481 | |||
482 | N_MSG(RSP, "[RCA] 0x%.4x", resp >> 16); |
||
483 | msdc_dump_card_status(host, status); |
||
1 | office | 484 | } |
485 | |||
486 | static void msdc_dump_io_resp(struct msdc_host *host, u32 resp) |
||
487 | { |
||
3 | office | 488 | u32 flags = (resp >> 8) & 0xFF; |
489 | char *state[] = {"DIS", "CMD", "TRN", "RFU"}; |
||
490 | |||
491 | if (flags & (1 << 7)) |
||
492 | N_MSG(RSP, "[IO] COM_CRC_ERR"); |
||
493 | if (flags & (1 << 6)) |
||
494 | N_MSG(RSP, "[IO] Illgal command"); |
||
495 | if (flags & (1 << 3)) |
||
496 | N_MSG(RSP, "[IO] Error"); |
||
497 | if (flags & (1 << 2)) |
||
498 | N_MSG(RSP, "[IO] RFU"); |
||
499 | if (flags & (1 << 1)) |
||
500 | N_MSG(RSP, "[IO] Function number error"); |
||
501 | if (flags & (1 << 0)) |
||
502 | N_MSG(RSP, "[IO] Out of range"); |
||
1 | office | 503 | |
3 | office | 504 | N_MSG(RSP, "[IO] State: %s, Data:0x%x", state[(resp >> 12) & 0x3], resp & 0xFF); |
1 | office | 505 | } |
506 | #endif |
||
507 | |||
508 | static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) |
||
509 | { |
||
3 | office | 510 | u32 base = host->base; |
511 | u32 timeout, clk_ns; |
||
1 | office | 512 | |
3 | office | 513 | host->timeout_ns = ns; |
514 | host->timeout_clks = clks; |
||
1 | office | 515 | |
3 | office | 516 | clk_ns = 1000000000UL / host->sclk; |
517 | timeout = ns / clk_ns + clks; |
||
518 | timeout = timeout >> 16; /* in 65536 sclk cycle unit */ |
||
519 | timeout = timeout > 1 ? timeout - 1 : 0; |
||
520 | timeout = timeout > 255 ? 255 : timeout; |
||
1 | office | 521 | |
3 | office | 522 | sdr_set_field(SDC_CFG, SDC_CFG_DTOC, timeout); |
1 | office | 523 | |
3 | office | 524 | N_MSG(OPS, "Set read data timeout: %dns %dclks -> %d x 65536 cycles", |
525 | ns, clks, timeout + 1); |
||
1 | office | 526 | } |
527 | |||
3 | office | 528 | /* msdc_eirq_sdio() will be called when EIRQ(for WIFI) */ |
529 | static void msdc_eirq_sdio(void *data) |
||
530 | { |
||
531 | struct msdc_host *host = (struct msdc_host *)data; |
||
532 | |||
533 | N_MSG(INT, "SDIO EINT"); |
||
534 | |||
535 | mmc_signal_sdio_irq(host->mmc); |
||
536 | } |
||
537 | |||
538 | /* msdc_eirq_cd will not be used! We not using EINT for card detection. */ |
||
539 | static void msdc_eirq_cd(void *data) |
||
540 | { |
||
541 | struct msdc_host *host = (struct msdc_host *)data; |
||
542 | |||
543 | N_MSG(INT, "CD EINT"); |
||
544 | |||
545 | #if 0 |
||
546 | tasklet_hi_schedule(&host->card_tasklet); |
||
547 | #else |
||
548 | schedule_delayed_work(&host->card_delaywork, HZ); |
||
549 | #endif |
||
550 | } |
||
551 | |||
552 | #if 0 |
||
553 | static void msdc_tasklet_card(unsigned long arg) |
||
554 | { |
||
555 | struct msdc_host *host = (struct msdc_host *)arg; |
||
556 | #else |
||
1 | office | 557 | static void msdc_tasklet_card(struct work_struct *work) |
558 | { |
||
3 | office | 559 | struct msdc_host *host = (struct msdc_host *)container_of(work, |
560 | struct msdc_host, card_delaywork.work); |
||
561 | #endif |
||
562 | struct msdc_hw *hw = host->hw; |
||
563 | u32 base = host->base; |
||
564 | u32 inserted; |
||
565 | u32 status = 0; |
||
1 | office | 566 | //u32 change = 0; |
567 | |||
3 | office | 568 | spin_lock(&host->lock); |
1 | office | 569 | |
3 | office | 570 | if (hw->get_cd_status) { // NULL |
571 | inserted = hw->get_cd_status(); |
||
572 | } else { |
||
573 | status = sdr_read32(MSDC_PS); |
||
574 | if (cd_active_low) |
||
1 | office | 575 | inserted = (status & MSDC_PS_CDSTS) ? 0 : 1; |
576 | else |
||
3 | office | 577 | inserted = (status & MSDC_PS_CDSTS) ? 1 : 0; |
578 | } |
||
579 | if (host->mmc->caps & MMC_CAP_NEEDS_POLL) |
||
580 | inserted = 1; |
||
1 | office | 581 | |
582 | #if 0 |
||
3 | office | 583 | change = host->card_inserted ^ inserted; |
584 | host->card_inserted = inserted; |
||
585 | |||
586 | if (change && !host->suspend) { |
||
587 | if (inserted) { |
||
588 | host->mmc->f_max = HOST_MAX_MCLK; // work around |
||
589 | } |
||
590 | mmc_detect_change(host->mmc, msecs_to_jiffies(20)); |
||
591 | } |
||
1 | office | 592 | #else /* Make sure: handle the last interrupt */ |
3 | office | 593 | host->card_inserted = inserted; |
594 | |||
595 | if (!host->suspend) { |
||
596 | host->mmc->f_max = HOST_MAX_MCLK; |
||
597 | mmc_detect_change(host->mmc, msecs_to_jiffies(20)); |
||
598 | } |
||
599 | |||
600 | IRQ_MSG("card found<%s>", inserted ? "inserted" : "removed"); |
||
1 | office | 601 | #endif |
602 | |||
3 | office | 603 | spin_unlock(&host->lock); |
1 | office | 604 | } |
605 | |||
606 | #if 0 /* --- by chhung */ |
||
607 | /* For E2 only */ |
||
608 | static u8 clk_src_bit[4] = { |
||
3 | office | 609 | 0, 3, 5, 7 |
1 | office | 610 | }; |
611 | |||
3 | office | 612 | static void msdc_select_clksrc(struct msdc_host* host, unsigned char clksrc) |
1 | office | 613 | { |
3 | office | 614 | u32 val; |
615 | u32 base = host->base; |
||
616 | |||
617 | BUG_ON(clksrc > 3); |
||
618 | INIT_MSG("set clock source to <%d>", clksrc); |
||
1 | office | 619 | |
3 | office | 620 | val = sdr_read32(MSDC_CLKSRC_REG); |
621 | if (sdr_read32(MSDC_ECO_VER) >= 4) { |
||
622 | val &= ~(0x3 << clk_src_bit[host->id]); |
||
623 | val |= clksrc << clk_src_bit[host->id]; |
||
624 | } else { |
||
625 | val &= ~0x3; val |= clksrc; |
||
626 | } |
||
627 | sdr_write32(MSDC_CLKSRC_REG, val); |
||
628 | |||
629 | host->hclk = hclks[clksrc]; |
||
630 | host->hw->clk_src = clksrc; |
||
1 | office | 631 | } |
632 | #endif /* end of --- */ |
||
633 | |||
634 | static void msdc_set_mclk(struct msdc_host *host, int ddr, unsigned int hz) |
||
635 | { |
||
3 | office | 636 | //struct msdc_hw *hw = host->hw; |
637 | u32 base = host->base; |
||
638 | u32 mode; |
||
639 | u32 flags; |
||
640 | u32 div; |
||
641 | u32 sclk; |
||
642 | u32 hclk = host->hclk; |
||
643 | //u8 clksrc = hw->clk_src; |
||
1 | office | 644 | |
3 | office | 645 | if (!hz) { // set mmc system clock to 0 ? |
646 | //ERR_MSG("set mclk to 0!!!"); |
||
647 | msdc_reset(); |
||
648 | return; |
||
649 | } |
||
1 | office | 650 | |
3 | office | 651 | msdc_irq_save(flags); |
652 | |||
653 | #if defined (CONFIG_MT7621_FPGA) || defined (CONFIG_MT7628_FPGA) |
||
654 | mode = 0x0; /* use divisor */ |
||
655 | if (hz >= (hclk >> 1)) { |
||
656 | div = 0; /* mean div = 1/2 */ |
||
657 | sclk = hclk >> 1; /* sclk = clk / 2 */ |
||
658 | } else { |
||
659 | div = (hclk + ((hz << 2) - 1)) / (hz << 2); |
||
660 | sclk = (hclk >> 2) / div; |
||
661 | } |
||
662 | #else |
||
663 | if (ddr) { |
||
664 | mode = 0x2; /* ddr mode and use divisor */ |
||
665 | if (hz >= (hclk >> 2)) { |
||
666 | div = 1; /* mean div = 1/4 */ |
||
667 | sclk = hclk >> 2; /* sclk = clk / 4 */ |
||
668 | } else { |
||
669 | div = (hclk + ((hz << 2) - 1)) / (hz << 2); |
||
670 | sclk = (hclk >> 2) / div; |
||
671 | } |
||
672 | } else if (hz >= hclk) { /* bug fix */ |
||
673 | mode = 0x1; /* no divisor and divisor is ignored */ |
||
674 | div = 0; |
||
675 | sclk = hclk; |
||
676 | } else { |
||
677 | mode = 0x0; /* use divisor */ |
||
678 | if (hz >= (hclk >> 1)) { |
||
679 | div = 0; /* mean div = 1/2 */ |
||
680 | sclk = hclk >> 1; /* sclk = clk / 2 */ |
||
681 | } else { |
||
682 | div = (hclk + ((hz << 2) - 1)) / (hz << 2); |
||
683 | sclk = (hclk >> 2) / div; |
||
684 | } |
||
685 | } |
||
686 | #endif |
||
687 | /* set clock mode and divisor */ |
||
688 | sdr_set_field(MSDC_CFG, MSDC_CFG_CKMOD, mode); |
||
689 | sdr_set_field(MSDC_CFG, MSDC_CFG_CKDIV, div); |
||
690 | |||
691 | /* wait clock stable */ |
||
692 | while (!(sdr_read32(MSDC_CFG) & MSDC_CFG_CKSTB)); |
||
1 | office | 693 | |
3 | office | 694 | host->sclk = sclk; |
695 | host->mclk = hz; |
||
696 | msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); // need? |
||
697 | |||
698 | INIT_MSG("================"); |
||
699 | INIT_MSG("!!! Set<%dKHz> Source<%dKHz> -> sclk<%dKHz>", hz/1000, hclk/1000, sclk/1000); |
||
700 | INIT_MSG("================"); |
||
1 | office | 701 | |
3 | office | 702 | msdc_irq_restore(flags); |
1 | office | 703 | } |
704 | |||
705 | /* Fix me. when need to abort */ |
||
706 | static void msdc_abort_data(struct msdc_host *host) |
||
707 | { |
||
3 | office | 708 | u32 base = host->base; |
709 | struct mmc_command *stop = host->mrq->stop; |
||
1 | office | 710 | |
3 | office | 711 | ERR_MSG("Need to Abort. dma<%d>", host->dma_xfer); |
712 | |||
713 | msdc_reset(); |
||
714 | msdc_clr_fifo(); |
||
715 | msdc_clr_int(); |
||
1 | office | 716 | |
3 | office | 717 | // need to check FIFO count 0 ? |
718 | |||
719 | if (stop) { /* try to stop, but may not success */ |
||
720 | ERR_MSG("stop when abort CMD<%d>", stop->opcode); |
||
721 | (void)msdc_do_command(host, stop, 0, CMD_TIMEOUT); |
||
722 | } |
||
723 | |||
724 | //if (host->mclk >= 25000000) { |
||
725 | // msdc_set_mclk(host, 0, host->mclk >> 1); |
||
726 | //} |
||
1 | office | 727 | } |
728 | |||
729 | #if 0 /* --- by chhung */ |
||
730 | static void msdc_pin_config(struct msdc_host *host, int mode) |
||
731 | { |
||
3 | office | 732 | struct msdc_hw *hw = host->hw; |
733 | u32 base = host->base; |
||
734 | int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN; |
||
1 | office | 735 | |
3 | office | 736 | /* Config WP pin */ |
737 | if (hw->flags & MSDC_WP_PIN_EN) { |
||
738 | if (hw->config_gpio_pin) /* NULL */ |
||
739 | hw->config_gpio_pin(MSDC_WP_PIN, pull); |
||
740 | } |
||
1 | office | 741 | |
3 | office | 742 | switch (mode) { |
743 | case MSDC_PIN_PULL_UP: |
||
744 | //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 1); /* Check & FIXME */ |
||
745 | //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */ |
||
746 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 1); |
||
747 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0); |
||
748 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 1); |
||
749 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0); |
||
750 | break; |
||
751 | case MSDC_PIN_PULL_DOWN: |
||
752 | //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */ |
||
753 | //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 1); /* Check & FIXME */ |
||
754 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0); |
||
755 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 1); |
||
756 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0); |
||
757 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 1); |
||
758 | break; |
||
759 | case MSDC_PIN_PULL_NONE: |
||
760 | default: |
||
761 | //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */ |
||
762 | //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */ |
||
763 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0); |
||
764 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0); |
||
765 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0); |
||
766 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0); |
||
767 | break; |
||
768 | } |
||
769 | |||
770 | N_MSG(CFG, "Pins mode(%d), down(%d), up(%d)", |
||
771 | mode, MSDC_PIN_PULL_DOWN, MSDC_PIN_PULL_UP); |
||
1 | office | 772 | } |
773 | |||
774 | void msdc_pin_reset(struct msdc_host *host, int mode) |
||
775 | { |
||
3 | office | 776 | struct msdc_hw *hw = (struct msdc_hw *)host->hw; |
777 | u32 base = host->base; |
||
778 | int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN; |
||
1 | office | 779 | |
3 | office | 780 | /* Config reset pin */ |
781 | if (hw->flags & MSDC_RST_PIN_EN) { |
||
782 | if (hw->config_gpio_pin) /* NULL */ |
||
783 | hw->config_gpio_pin(MSDC_RST_PIN, pull); |
||
1 | office | 784 | |
3 | office | 785 | if (mode == MSDC_PIN_PULL_UP) { |
786 | sdr_clr_bits(EMMC_IOCON, EMMC_IOCON_BOOTRST); |
||
787 | } else { |
||
788 | sdr_set_bits(EMMC_IOCON, EMMC_IOCON_BOOTRST); |
||
789 | } |
||
790 | } |
||
1 | office | 791 | } |
792 | |||
793 | static void msdc_core_power(struct msdc_host *host, int on) |
||
794 | { |
||
3 | office | 795 | N_MSG(CFG, "Turn %s %s power (copower: %d -> %d)", |
796 | on ? "on" : "off", "core", host->core_power, on); |
||
1 | office | 797 | |
3 | office | 798 | if (on && host->core_power == 0) { |
799 | msdc_vcore_on(host); |
||
800 | host->core_power = 1; |
||
801 | msleep(1); |
||
802 | } else if (!on && host->core_power == 1) { |
||
803 | msdc_vcore_off(host); |
||
804 | host->core_power = 0; |
||
805 | msleep(1); |
||
806 | } |
||
1 | office | 807 | } |
808 | |||
809 | static void msdc_host_power(struct msdc_host *host, int on) |
||
810 | { |
||
3 | office | 811 | N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "host"); |
1 | office | 812 | |
3 | office | 813 | if (on) { |
814 | //msdc_core_power(host, 1); // need do card detection. |
||
815 | msdc_pin_reset(host, MSDC_PIN_PULL_UP); |
||
816 | } else { |
||
817 | msdc_pin_reset(host, MSDC_PIN_PULL_DOWN); |
||
818 | //msdc_core_power(host, 0); |
||
819 | } |
||
1 | office | 820 | } |
821 | |||
822 | static void msdc_card_power(struct msdc_host *host, int on) |
||
823 | { |
||
3 | office | 824 | N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "card"); |
1 | office | 825 | |
3 | office | 826 | if (on) { |
827 | msdc_pin_config(host, MSDC_PIN_PULL_UP); |
||
828 | if (host->hw->ext_power_on) { |
||
829 | host->hw->ext_power_on(); |
||
830 | } else { |
||
831 | //msdc_vdd_on(host); // need todo card detection. |
||
832 | } |
||
833 | msleep(1); |
||
834 | } else { |
||
835 | if (host->hw->ext_power_off) { |
||
836 | host->hw->ext_power_off(); |
||
837 | } else { |
||
838 | //msdc_vdd_off(host); |
||
839 | } |
||
840 | msdc_pin_config(host, MSDC_PIN_PULL_DOWN); |
||
841 | msleep(1); |
||
842 | } |
||
1 | office | 843 | } |
844 | |||
845 | static void msdc_set_power_mode(struct msdc_host *host, u8 mode) |
||
846 | { |
||
3 | office | 847 | N_MSG(CFG, "Set power mode(%d)", mode); |
1 | office | 848 | |
3 | office | 849 | if (host->power_mode == MMC_POWER_OFF && mode != MMC_POWER_OFF) { |
850 | msdc_host_power(host, 1); |
||
851 | msdc_card_power(host, 1); |
||
852 | } else if (host->power_mode != MMC_POWER_OFF && mode == MMC_POWER_OFF) { |
||
853 | msdc_card_power(host, 0); |
||
854 | msdc_host_power(host, 0); |
||
855 | } |
||
856 | host->power_mode = mode; |
||
1 | office | 857 | } |
858 | #endif /* end of --- */ |
||
859 | |||
860 | #ifdef CONFIG_PM |
||
861 | /* |
||
3 | office | 862 | register as callback function of WIFI(combo_sdio_register_pm) . |
863 | can called by msdc_drv_suspend/resume too. |
||
1 | office | 864 | */ |
865 | static void msdc_pm(pm_message_t state, void *data) |
||
866 | { |
||
3 | office | 867 | struct msdc_host *host = (struct msdc_host *)data; |
868 | int evt = state.event; |
||
1 | office | 869 | |
3 | office | 870 | if (evt == PM_EVENT_USER_RESUME || evt == PM_EVENT_USER_SUSPEND) { |
871 | INIT_MSG("USR_%s: suspend<%d> power<%d>", |
||
872 | evt == PM_EVENT_USER_RESUME ? "EVENT_USER_RESUME" : "EVENT_USER_SUSPEND", |
||
873 | host->suspend, host->power_mode); |
||
874 | } |
||
1 | office | 875 | |
3 | office | 876 | if (evt == PM_EVENT_SUSPEND || evt == PM_EVENT_USER_SUSPEND) { |
877 | if (host->suspend) /* already suspend */ /* default 0*/ |
||
878 | return; |
||
1 | office | 879 | |
3 | office | 880 | /* for memory card. already power off by mmc */ |
881 | if (evt == PM_EVENT_SUSPEND && host->power_mode == MMC_POWER_OFF) |
||
882 | return; |
||
1 | office | 883 | |
3 | office | 884 | host->suspend = 1; |
885 | host->pm_state = state; /* default PMSG_RESUME */ |
||
886 | |||
887 | INIT_MSG("%s Suspend", evt == PM_EVENT_SUSPEND ? "PM" : "USR"); |
||
888 | if(host->hw->flags & MSDC_SYS_SUSPEND) /* set for card */ |
||
889 | (void)mmc_suspend_host(host->mmc); |
||
890 | else { |
||
891 | // host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* just for double confirm */ /* --- by chhung */ |
||
892 | mmc_remove_host(host->mmc); |
||
893 | } |
||
894 | } else if (evt == PM_EVENT_RESUME || evt == PM_EVENT_USER_RESUME) { |
||
895 | if (!host->suspend){ |
||
896 | //ERR_MSG("warning: already resume"); |
||
897 | return; |
||
898 | } |
||
1 | office | 899 | |
3 | office | 900 | /* No PM resume when USR suspend */ |
901 | if (evt == PM_EVENT_RESUME && host->pm_state.event == PM_EVENT_USER_SUSPEND) { |
||
902 | ERR_MSG("PM Resume when in USR Suspend"); /* won't happen. */ |
||
903 | return; |
||
904 | } |
||
905 | |||
906 | host->suspend = 0; |
||
907 | host->pm_state = state; |
||
908 | |||
909 | INIT_MSG("%s Resume", evt == PM_EVENT_RESUME ? "PM" : "USR"); |
||
910 | if(host->hw->flags & MSDC_SYS_SUSPEND) { /* will not set for WIFI */ |
||
911 | (void)mmc_resume_host(host->mmc); |
||
912 | } |
||
913 | else { |
||
914 | // host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* --- by chhung */ |
||
915 | mmc_add_host(host->mmc); |
||
916 | } |
||
917 | } |
||
1 | office | 918 | } |
919 | #endif |
||
920 | |||
921 | /*--------------------------------------------------------------------------*/ |
||
922 | /* mmc_host_ops members */ |
||
923 | /*--------------------------------------------------------------------------*/ |
||
3 | office | 924 | static unsigned int msdc_command_start(struct msdc_host *host, |
925 | struct mmc_command *cmd, |
||
926 | int tune, /* not used */ |
||
927 | unsigned long timeout) |
||
1 | office | 928 | { |
3 | office | 929 | u32 base = host->base; |
930 | u32 opcode = cmd->opcode; |
||
931 | u32 rawcmd; |
||
932 | u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | |
||
933 | MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | |
||
934 | MSDC_INT_ACMD19_DONE; |
||
935 | |||
936 | u32 resp; |
||
937 | unsigned long tmo; |
||
1 | office | 938 | |
3 | office | 939 | /* Protocol layer does not provide response type, but our hardware needs |
940 | * to know exact type, not just size! |
||
941 | */ |
||
942 | if (opcode == MMC_SEND_OP_COND || opcode == SD_APP_OP_COND) |
||
943 | resp = RESP_R3; |
||
944 | else if (opcode == MMC_SET_RELATIVE_ADDR || opcode == SD_SEND_RELATIVE_ADDR) |
||
945 | resp = (mmc_cmd_type(cmd) == MMC_CMD_BCR) ? RESP_R6 : RESP_R1; |
||
946 | else if (opcode == MMC_FAST_IO) |
||
947 | resp = RESP_R4; |
||
948 | else if (opcode == MMC_GO_IRQ_STATE) |
||
949 | resp = RESP_R5; |
||
950 | else if (opcode == MMC_SELECT_CARD) |
||
951 | resp = (cmd->arg != 0) ? RESP_R1B : RESP_NONE; |
||
952 | else if (opcode == SD_IO_RW_DIRECT || opcode == SD_IO_RW_EXTENDED) |
||
953 | resp = RESP_R1; /* SDIO workaround. */ |
||
954 | else if (opcode == SD_SEND_IF_COND && (mmc_cmd_type(cmd) == MMC_CMD_BCR)) |
||
955 | resp = RESP_R1; |
||
956 | else { |
||
957 | switch (mmc_resp_type(cmd)) { |
||
958 | case MMC_RSP_R1: |
||
959 | resp = RESP_R1; |
||
960 | break; |
||
961 | case MMC_RSP_R1B: |
||
962 | resp = RESP_R1B; |
||
963 | break; |
||
964 | case MMC_RSP_R2: |
||
965 | resp = RESP_R2; |
||
966 | break; |
||
967 | case MMC_RSP_R3: |
||
968 | resp = RESP_R3; |
||
969 | break; |
||
970 | case MMC_RSP_NONE: |
||
971 | default: |
||
972 | resp = RESP_NONE; |
||
973 | break; |
||
974 | } |
||
975 | } |
||
1 | office | 976 | |
3 | office | 977 | cmd->error = 0; |
978 | /* rawcmd : |
||
979 | * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 | |
||
980 | * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode |
||
981 | */ |
||
982 | rawcmd = opcode | msdc_rsp[resp] << 7 | host->blksz << 16; |
||
983 | |||
984 | if (opcode == MMC_READ_MULTIPLE_BLOCK) { |
||
985 | rawcmd |= (2 << 11); |
||
986 | } else if (opcode == MMC_READ_SINGLE_BLOCK) { |
||
987 | rawcmd |= (1 << 11); |
||
988 | } else if (opcode == MMC_WRITE_MULTIPLE_BLOCK) { |
||
989 | rawcmd |= ((2 << 11) | (1 << 13)); |
||
990 | } else if (opcode == MMC_WRITE_BLOCK) { |
||
991 | rawcmd |= ((1 << 11) | (1 << 13)); |
||
992 | } else if (opcode == SD_IO_RW_EXTENDED) { |
||
993 | if (cmd->data->flags & MMC_DATA_WRITE) |
||
994 | rawcmd |= (1 << 13); |
||
995 | if (cmd->data->blocks > 1) |
||
996 | rawcmd |= (2 << 11); |
||
997 | else |
||
998 | rawcmd |= (1 << 11); |
||
999 | } else if (opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int)-1) { |
||
1000 | rawcmd |= (1 << 14); |
||
1001 | } else if ((opcode == SD_APP_SEND_SCR) || |
||
1002 | (opcode == SD_APP_SEND_NUM_WR_BLKS) || |
||
1003 | (opcode == SD_SWITCH && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) || |
||
1004 | (opcode == SD_APP_SD_STATUS && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) || |
||
1005 | (opcode == MMC_SEND_EXT_CSD && (mmc_cmd_type(cmd) == MMC_CMD_ADTC))) { |
||
1006 | rawcmd |= (1 << 11); |
||
1007 | } else if (opcode == MMC_STOP_TRANSMISSION) { |
||
1008 | rawcmd |= (1 << 14); |
||
1009 | rawcmd &= ~(0x0FFF << 16); |
||
1010 | } |
||
1 | office | 1011 | |
3 | office | 1012 | N_MSG(CMD, "CMD<%d><0x%.8x> Arg<0x%.8x>", opcode , rawcmd, cmd->arg); |
1 | office | 1013 | |
3 | office | 1014 | tmo = jiffies + timeout; |
1 | office | 1015 | |
3 | office | 1016 | if (opcode == MMC_SEND_STATUS) { |
1017 | for (;;) { |
||
1018 | if (!sdc_is_cmd_busy()) |
||
1019 | break; |
||
1020 | |||
1021 | if (time_after(jiffies, tmo)) { |
||
1022 | ERR_MSG("XXX cmd_busy timeout: before CMD<%d>", opcode); |
||
1023 | cmd->error = (unsigned int)-ETIMEDOUT; |
||
1024 | msdc_reset(); |
||
1025 | goto end; |
||
1026 | } |
||
1027 | } |
||
1028 | }else { |
||
1029 | for (;;) { |
||
1030 | if (!sdc_is_busy()) |
||
1031 | break; |
||
1032 | if (time_after(jiffies, tmo)) { |
||
1033 | ERR_MSG("XXX sdc_busy timeout: before CMD<%d>", opcode); |
||
1034 | cmd->error = (unsigned int)-ETIMEDOUT; |
||
1035 | msdc_reset(); |
||
1036 | goto end; |
||
1037 | } |
||
1038 | } |
||
1039 | } |
||
1040 | |||
1041 | //BUG_ON(in_interrupt()); |
||
1042 | host->cmd = cmd; |
||
1043 | host->cmd_rsp = resp; |
||
1044 | |||
1045 | init_completion(&host->cmd_done); |
||
1 | office | 1046 | |
3 | office | 1047 | sdr_set_bits(MSDC_INTEN, wints); |
1048 | sdc_send_cmd(rawcmd, cmd->arg); |
||
1049 | |||
1050 | end: |
||
1051 | return cmd->error; |
||
1 | office | 1052 | } |
1053 | |||
3 | office | 1054 | static unsigned int msdc_command_resp(struct msdc_host *host, |
1055 | struct mmc_command *cmd, |
||
1056 | int tune, |
||
1057 | unsigned long timeout) |
||
1 | office | 1058 | { |
3 | office | 1059 | u32 base = host->base; |
1060 | u32 opcode = cmd->opcode; |
||
1061 | //u32 rawcmd; |
||
1062 | u32 resp; |
||
1063 | u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | |
||
1064 | MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | |
||
1065 | MSDC_INT_ACMD19_DONE; |
||
1066 | |||
1067 | resp = host->cmd_rsp; |
||
1 | office | 1068 | |
3 | office | 1069 | BUG_ON(in_interrupt()); |
1070 | //init_completion(&host->cmd_done); |
||
1071 | //sdr_set_bits(MSDC_INTEN, wints); |
||
1072 | |||
1073 | spin_unlock(&host->lock); |
||
1074 | if(!wait_for_completion_timeout(&host->cmd_done, 10*timeout)){ |
||
1075 | ERR_MSG("XXX CMD<%d> wait_for_completion timeout ARG<0x%.8x>", opcode, cmd->arg); |
||
1076 | cmd->error = (unsigned int)-ETIMEDOUT; |
||
1077 | msdc_reset(); |
||
1078 | } |
||
1079 | spin_lock(&host->lock); |
||
1 | office | 1080 | |
3 | office | 1081 | sdr_clr_bits(MSDC_INTEN, wints); |
1082 | host->cmd = NULL; |
||
1 | office | 1083 | |
1084 | //end: |
||
1085 | #ifdef MT6575_SD_DEBUG |
||
3 | office | 1086 | switch (resp) { |
1087 | case RESP_NONE: |
||
1088 | N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)", opcode, cmd->error, resp); |
||
1089 | break; |
||
1090 | case RESP_R2: |
||
1091 | N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= %.8x %.8x %.8x %.8x", |
||
1092 | opcode, cmd->error, resp, cmd->resp[0], cmd->resp[1], |
||
1093 | cmd->resp[2], cmd->resp[3]); |
||
1094 | break; |
||
1095 | default: /* Response types 1, 3, 4, 5, 6, 7(1b) */ |
||
1096 | N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= 0x%.8x", |
||
1097 | opcode, cmd->error, resp, cmd->resp[0]); |
||
1098 | if (cmd->error == 0) { |
||
1099 | switch (resp) { |
||
1100 | case RESP_R1: |
||
1101 | case RESP_R1B: |
||
1102 | msdc_dump_card_status(host, cmd->resp[0]); |
||
1103 | break; |
||
1104 | case RESP_R3: |
||
1105 | msdc_dump_ocr_reg(host, cmd->resp[0]); |
||
1106 | break; |
||
1107 | case RESP_R5: |
||
1108 | msdc_dump_io_resp(host, cmd->resp[0]); |
||
1109 | break; |
||
1110 | case RESP_R6: |
||
1111 | msdc_dump_rca_resp(host, cmd->resp[0]); |
||
1112 | break; |
||
1113 | } |
||
1114 | } |
||
1115 | break; |
||
1116 | } |
||
1 | office | 1117 | #endif |
1118 | |||
3 | office | 1119 | /* do we need to save card's RCA when SD_SEND_RELATIVE_ADDR */ |
1 | office | 1120 | |
3 | office | 1121 | if (!tune) { |
1122 | return cmd->error; |
||
1123 | } |
||
1 | office | 1124 | |
3 | office | 1125 | /* memory card CRC */ |
1126 | if(host->hw->flags & MSDC_REMOVABLE && cmd->error == (unsigned int)(-EIO) ) { |
||
1127 | if (sdr_read32(SDC_CMD) & 0x1800) { /* check if has data phase */ |
||
1128 | msdc_abort_data(host); |
||
1129 | } else { |
||
1130 | /* do basic: reset*/ |
||
1131 | msdc_reset(); |
||
1132 | msdc_clr_fifo(); |
||
1133 | msdc_clr_int(); |
||
1134 | } |
||
1135 | cmd->error = msdc_tune_cmdrsp(host,cmd); |
||
1136 | } |
||
1 | office | 1137 | |
3 | office | 1138 | // check DAT0 |
1139 | /* if (resp == RESP_R1B) { |
||
1140 | while ((sdr_read32(MSDC_PS) & 0x10000) != 0x10000); |
||
1141 | } */ |
||
1142 | /* CMD12 Error Handle */ |
||
1143 | |||
1144 | return cmd->error; |
||
1145 | } |
||
1 | office | 1146 | |
3 | office | 1147 | static unsigned int msdc_do_command(struct msdc_host *host, |
1148 | struct mmc_command *cmd, |
||
1149 | int tune, |
||
1150 | unsigned long timeout) |
||
1151 | { |
||
1152 | if (msdc_command_start(host, cmd, tune, timeout)) |
||
1153 | goto end; |
||
1154 | |||
1155 | if (msdc_command_resp(host, cmd, tune, timeout)) |
||
1156 | goto end; |
||
1157 | |||
1158 | end: |
||
1159 | |||
1160 | N_MSG(CMD, " return<%d> resp<0x%.8x>", cmd->error, cmd->resp[0]); |
||
1161 | return cmd->error; |
||
1 | office | 1162 | } |
3 | office | 1163 | |
1164 | /* The abort condition when PIO read/write |
||
1165 | tmo: |
||
1166 | */ |
||
1167 | static int msdc_pio_abort(struct msdc_host *host, struct mmc_data *data, unsigned long tmo) |
||
1 | office | 1168 | { |
3 | office | 1169 | int ret = 0; |
1170 | u32 base = host->base; |
||
1171 | |||
1172 | if (atomic_read(&host->abort)) { |
||
1173 | ret = 1; |
||
1174 | } |
||
1 | office | 1175 | |
3 | office | 1176 | if (time_after(jiffies, tmo)) { |
1177 | data->error = (unsigned int)-ETIMEDOUT; |
||
1178 | ERR_MSG("XXX PIO Data Timeout: CMD<%d>", host->mrq->cmd->opcode); |
||
1179 | ret = 1; |
||
1180 | } |
||
1181 | |||
1182 | if(ret) { |
||
1183 | msdc_reset(); |
||
1184 | msdc_clr_fifo(); |
||
1185 | msdc_clr_int(); |
||
1186 | ERR_MSG("msdc pio find abort"); |
||
1187 | } |
||
1188 | return ret; |
||
1189 | } |
||
1 | office | 1190 | |
3 | office | 1191 | /* |
1192 | Need to add a timeout, or WDT timeout, system reboot. |
||
1193 | */ |
||
1194 | // pio mode data read/write |
||
1195 | static int msdc_pio_read(struct msdc_host *host, struct mmc_data *data) |
||
1196 | { |
||
1197 | struct scatterlist *sg = data->sg; |
||
1198 | u32 base = host->base; |
||
1199 | u32 num = data->sg_len; |
||
1200 | u32 *ptr; |
||
1201 | u8 *u8ptr; |
||
1202 | u32 left = 0; |
||
1203 | u32 count, size = 0; |
||
1204 | u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; |
||
1205 | unsigned long tmo = jiffies + DAT_TIMEOUT; |
||
1206 | |||
1207 | sdr_set_bits(MSDC_INTEN, wints); |
||
1208 | while (num) { |
||
1209 | left = sg_dma_len(sg); |
||
1210 | ptr = sg_virt(sg); |
||
1211 | while (left) { |
||
1212 | if ((left >= MSDC_FIFO_THD) && (msdc_rxfifocnt() >= MSDC_FIFO_THD)) { |
||
1213 | count = MSDC_FIFO_THD >> 2; |
||
1214 | do { |
||
1215 | *ptr++ = msdc_fifo_read32(); |
||
1216 | } while (--count); |
||
1217 | left -= MSDC_FIFO_THD; |
||
1218 | } else if ((left < MSDC_FIFO_THD) && msdc_rxfifocnt() >= left) { |
||
1219 | while (left > 3) { |
||
1220 | *ptr++ = msdc_fifo_read32(); |
||
1221 | left -= 4; |
||
1222 | } |
||
1223 | |||
1224 | u8ptr = (u8 *)ptr; |
||
1225 | while(left) { |
||
1226 | * u8ptr++ = msdc_fifo_read8(); |
||
1227 | left--; |
||
1228 | } |
||
1229 | } |
||
1230 | |||
1231 | if (msdc_pio_abort(host, data, tmo)) { |
||
1232 | goto end; |
||
1233 | } |
||
1234 | } |
||
1235 | size += sg_dma_len(sg); |
||
1236 | sg = sg_next(sg); num--; |
||
1237 | } |
||
1 | office | 1238 | end: |
3 | office | 1239 | data->bytes_xfered += size; |
1240 | N_MSG(FIO, " PIO Read<%d>bytes", size); |
||
1241 | |||
1242 | sdr_clr_bits(MSDC_INTEN, wints); |
||
1243 | if(data->error) ERR_MSG("read pio data->error<%d> left<%d> size<%d>", data->error, left, size); |
||
1244 | return data->error; |
||
1245 | } |
||
1 | office | 1246 | |
3 | office | 1247 | /* please make sure won't using PIO when size >= 512 |
1248 | which means, memory card block read/write won't using pio |
||
1249 | then don't need to handle the CMD12 when data error. |
||
1250 | */ |
||
1251 | static int msdc_pio_write(struct msdc_host* host, struct mmc_data *data) |
||
1252 | { |
||
1253 | u32 base = host->base; |
||
1254 | struct scatterlist *sg = data->sg; |
||
1255 | u32 num = data->sg_len; |
||
1256 | u32 *ptr; |
||
1257 | u8 *u8ptr; |
||
1258 | u32 left; |
||
1259 | u32 count, size = 0; |
||
1260 | u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; |
||
1261 | unsigned long tmo = jiffies + DAT_TIMEOUT; |
||
1262 | |||
1263 | sdr_set_bits(MSDC_INTEN, wints); |
||
1264 | while (num) { |
||
1265 | left = sg_dma_len(sg); |
||
1266 | ptr = sg_virt(sg); |
||
1267 | |||
1268 | while (left) { |
||
1269 | if (left >= MSDC_FIFO_SZ && msdc_txfifocnt() == 0) { |
||
1270 | count = MSDC_FIFO_SZ >> 2; |
||
1271 | do { |
||
1272 | msdc_fifo_write32(*ptr); ptr++; |
||
1273 | } while (--count); |
||
1274 | left -= MSDC_FIFO_SZ; |
||
1275 | } else if (left < MSDC_FIFO_SZ && msdc_txfifocnt() == 0) { |
||
1276 | while (left > 3) { |
||
1277 | msdc_fifo_write32(*ptr); ptr++; |
||
1278 | left -= 4; |
||
1279 | } |
||
1280 | |||
1281 | u8ptr = (u8*)ptr; |
||
1282 | while(left){ |
||
1283 | msdc_fifo_write8(*u8ptr); u8ptr++; |
||
1284 | left--; |
||
1285 | } |
||
1286 | } |
||
1287 | |||
1288 | if (msdc_pio_abort(host, data, tmo)) { |
||
1289 | goto end; |
||
1290 | } |
||
1291 | } |
||
1292 | size += sg_dma_len(sg); |
||
1293 | sg = sg_next(sg); num--; |
||
1294 | } |
||
1295 | end: |
||
1296 | data->bytes_xfered += size; |
||
1297 | N_MSG(FIO, " PIO Write<%d>bytes", size); |
||
1298 | if(data->error) ERR_MSG("write pio data->error<%d>", data->error); |
||
1299 | |||
1300 | sdr_clr_bits(MSDC_INTEN, wints); |
||
1301 | return data->error; |
||
1 | office | 1302 | } |
1303 | |||
1304 | #if 0 /* --- by chhung */ |
||
3 | office | 1305 | // DMA resume / start / stop |
1 | office | 1306 | static void msdc_dma_resume(struct msdc_host *host) |
1307 | { |
||
3 | office | 1308 | u32 base = host->base; |
1 | office | 1309 | |
3 | office | 1310 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_RESUME, 1); |
1 | office | 1311 | |
3 | office | 1312 | N_MSG(DMA, "DMA resume"); |
1 | office | 1313 | } |
1314 | #endif /* end of --- */ |
||
1315 | |||
1316 | static void msdc_dma_start(struct msdc_host *host) |
||
1317 | { |
||
3 | office | 1318 | u32 base = host->base; |
1319 | u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; |
||
1320 | |||
1321 | sdr_set_bits(MSDC_INTEN, wints); |
||
1322 | //dsb(); /* --- by chhung */ |
||
1323 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1); |
||
1 | office | 1324 | |
3 | office | 1325 | N_MSG(DMA, "DMA start"); |
1 | office | 1326 | } |
1327 | |||
1328 | static void msdc_dma_stop(struct msdc_host *host) |
||
1329 | { |
||
3 | office | 1330 | u32 base = host->base; |
1331 | //u32 retries=500; |
||
1332 | u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; |
||
1333 | |||
1334 | N_MSG(DMA, "DMA status: 0x%.8x",sdr_read32(MSDC_DMA_CFG)); |
||
1335 | //while (sdr_read32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS); |
||
1 | office | 1336 | |
3 | office | 1337 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1); |
1338 | while (sdr_read32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS); |
||
1 | office | 1339 | |
3 | office | 1340 | //dsb(); /* --- by chhung */ |
1341 | sdr_clr_bits(MSDC_INTEN, wints); /* Not just xfer_comp */ |
||
1 | office | 1342 | |
3 | office | 1343 | N_MSG(DMA, "DMA stop"); |
1344 | } |
||
1 | office | 1345 | |
3 | office | 1346 | #if 0 /* --- by chhung */ |
1347 | /* dump a gpd list */ |
||
1348 | static void msdc_dma_dump(struct msdc_host *host, struct msdc_dma *dma) |
||
1349 | { |
||
1350 | gpd_t *gpd = dma->gpd; |
||
1351 | bd_t *bd = dma->bd; |
||
1352 | bd_t *ptr; |
||
1353 | int i = 0; |
||
1354 | int p_to_v; |
||
1355 | |||
1356 | if (dma->mode != MSDC_MODE_DMA_DESC) { |
||
1357 | return; |
||
1358 | } |
||
1359 | |||
1360 | ERR_MSG("try to dump gpd and bd"); |
||
1361 | |||
1362 | /* dump gpd */ |
||
1363 | ERR_MSG(".gpd<0x%.8x> gpd_phy<0x%.8x>", (int)gpd, (int)dma->gpd_addr); |
||
1364 | ERR_MSG("...hwo <%d>", gpd->hwo ); |
||
1365 | ERR_MSG("...bdp <%d>", gpd->bdp ); |
||
1366 | ERR_MSG("...chksum<0x%.8x>", gpd->chksum ); |
||
1367 | //ERR_MSG("...intr <0x%.8x>", gpd->intr ); |
||
1368 | ERR_MSG("...next <0x%.8x>", (int)gpd->next ); |
||
1369 | ERR_MSG("...ptr <0x%.8x>", (int)gpd->ptr ); |
||
1370 | ERR_MSG("...buflen<0x%.8x>", gpd->buflen ); |
||
1371 | //ERR_MSG("...extlen<0x%.8x>", gpd->extlen ); |
||
1372 | //ERR_MSG("...arg <0x%.8x>", gpd->arg ); |
||
1373 | //ERR_MSG("...blknum<0x%.8x>", gpd->blknum ); |
||
1374 | //ERR_MSG("...cmd <0x%.8x>", gpd->cmd ); |
||
1375 | |||
1376 | /* dump bd */ |
||
1377 | ERR_MSG(".bd<0x%.8x> bd_phy<0x%.8x> gpd_ptr<0x%.8x>", (int)bd, (int)dma->bd_addr, (int)gpd->ptr); |
||
1378 | ptr = bd; |
||
1379 | p_to_v = ((u32)bd - (u32)dma->bd_addr); |
||
1380 | while (1) { |
||
1381 | ERR_MSG(".bd[%d]", i); i++; |
||
1382 | ERR_MSG("...eol <%d>", ptr->eol ); |
||
1383 | ERR_MSG("...chksum<0x%.8x>", ptr->chksum ); |
||
1384 | //ERR_MSG("...blkpad<0x%.8x>", ptr->blkpad ); |
||
1385 | //ERR_MSG("...dwpad <0x%.8x>", ptr->dwpad ); |
||
1386 | ERR_MSG("...next <0x%.8x>", (int)ptr->next ); |
||
1387 | ERR_MSG("...ptr <0x%.8x>", (int)ptr->ptr ); |
||
1388 | ERR_MSG("...buflen<0x%.8x>", (int)ptr->buflen ); |
||
1389 | |||
1390 | if (ptr->eol == 1) { |
||
1391 | break; |
||
1392 | } |
||
1393 | |||
1394 | /* find the next bd, virtual address of ptr->next */ |
||
1395 | /* don't need to enable when use malloc */ |
||
1396 | //BUG_ON( (ptr->next + p_to_v)!=(ptr+1) ); |
||
1397 | //ERR_MSG(".next bd<0x%.8x><0x%.8x>", (ptr->next + p_to_v), (ptr+1)); |
||
1398 | ptr++; |
||
1399 | } |
||
1400 | |||
1401 | ERR_MSG("dump gpd and bd finished"); |
||
1 | office | 1402 | } |
3 | office | 1403 | #endif /* end of --- */ |
1 | office | 1404 | |
1405 | /* calc checksum */ |
||
1406 | static u8 msdc_dma_calcs(u8 *buf, u32 len) |
||
1407 | { |
||
3 | office | 1408 | u32 i, sum = 0; |
1409 | for (i = 0; i < len; i++) { |
||
1410 | sum += buf[i]; |
||
1411 | } |
||
1412 | return 0xFF - (u8)sum; |
||
1 | office | 1413 | } |
1414 | |||
1415 | /* gpd bd setup + dma registers */ |
||
3 | office | 1416 | static int msdc_dma_config(struct msdc_host *host, struct msdc_dma *dma) |
1 | office | 1417 | { |
3 | office | 1418 | u32 base = host->base; |
1419 | u32 sglen = dma->sglen; |
||
1420 | //u32 i, j, num, bdlen, arg, xfersz; |
||
1421 | u32 j, num, bdlen; |
||
1422 | u8 blkpad, dwpad, chksum; |
||
1423 | struct scatterlist *sg = dma->sg; |
||
1424 | gpd_t *gpd; |
||
1425 | bd_t *bd; |
||
1 | office | 1426 | |
3 | office | 1427 | switch (dma->mode) { |
1428 | case MSDC_MODE_DMA_BASIC: |
||
1429 | BUG_ON(dma->xfersz > 65535); |
||
1430 | BUG_ON(dma->sglen != 1); |
||
1431 | sdr_write32(MSDC_DMA_SA, PHYSADDR(sg_dma_address(sg))); |
||
1432 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_LASTBUF, 1); |
||
1 | office | 1433 | //#if defined (CONFIG_RALINK_MT7620) |
3 | office | 1434 | if (ralink_soc == MT762X_SOC_MT7620A) |
1435 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_XFERSZ, sg_dma_len(sg)); |
||
1 | office | 1436 | //#elif defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) |
3 | office | 1437 | else |
1438 | sdr_write32((volatile u32*)(RALINK_MSDC_BASE+0xa8), sg_dma_len(sg)); |
||
1 | office | 1439 | //#endif |
3 | office | 1440 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz); |
1441 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 0); |
||
1442 | break; |
||
1443 | case MSDC_MODE_DMA_DESC: |
||
1444 | blkpad = (dma->flags & DMA_FLAG_PAD_BLOCK) ? 1 : 0; |
||
1445 | dwpad = (dma->flags & DMA_FLAG_PAD_DWORD) ? 1 : 0; |
||
1446 | chksum = (dma->flags & DMA_FLAG_EN_CHKSUM) ? 1 : 0; |
||
1 | office | 1447 | |
3 | office | 1448 | /* calculate the required number of gpd */ |
1449 | num = (sglen + MAX_BD_PER_GPD - 1) / MAX_BD_PER_GPD; |
||
1450 | BUG_ON(num !=1 ); |
||
1451 | |||
1452 | gpd = dma->gpd; |
||
1453 | bd = dma->bd; |
||
1454 | bdlen = sglen; |
||
1 | office | 1455 | |
3 | office | 1456 | /* modify gpd*/ |
1457 | //gpd->intr = 0; |
||
1458 | gpd->hwo = 1; /* hw will clear it */ |
||
1459 | gpd->bdp = 1; |
||
1460 | gpd->chksum = 0; /* need to clear first. */ |
||
1461 | gpd->chksum = (chksum ? msdc_dma_calcs((u8 *)gpd, 16) : 0); |
||
1462 | |||
1463 | /* modify bd*/ |
||
1464 | for (j = 0; j < bdlen; j++) { |
||
1465 | msdc_init_bd(&bd[j], blkpad, dwpad, sg_dma_address(sg), sg_dma_len(sg)); |
||
1466 | if(j == bdlen - 1) { |
||
1467 | bd[j].eol = 1; /* the last bd */ |
||
1468 | } else { |
||
1469 | bd[j].eol = 0; |
||
1470 | } |
||
1471 | bd[j].chksum = 0; /* checksume need to clear first */ |
||
1472 | bd[j].chksum = (chksum ? msdc_dma_calcs((u8 *)(&bd[j]), 16) : 0); |
||
1473 | sg++; |
||
1474 | } |
||
1475 | |||
1476 | dma->used_gpd += 2; |
||
1477 | dma->used_bd += bdlen; |
||
1 | office | 1478 | |
3 | office | 1479 | sdr_set_field(MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, chksum); |
1480 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz); |
||
1481 | sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 1); |
||
1 | office | 1482 | |
3 | office | 1483 | sdr_write32(MSDC_DMA_SA, PHYSADDR((u32)dma->gpd_addr)); |
1484 | break; |
||
1 | office | 1485 | |
3 | office | 1486 | default: |
1487 | break; |
||
1488 | } |
||
1489 | |||
1490 | N_MSG(DMA, "DMA_CTRL = 0x%x", sdr_read32(MSDC_DMA_CTRL)); |
||
1491 | N_MSG(DMA, "DMA_CFG = 0x%x", sdr_read32(MSDC_DMA_CFG)); |
||
1492 | N_MSG(DMA, "DMA_SA = 0x%x", sdr_read32(MSDC_DMA_SA)); |
||
1 | office | 1493 | |
3 | office | 1494 | return 0; |
1495 | } |
||
1 | office | 1496 | |
3 | office | 1497 | static void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, |
1498 | struct scatterlist *sg, unsigned int sglen) |
||
1499 | { |
||
1500 | BUG_ON(sglen > MAX_BD_NUM); /* not support currently */ |
||
1 | office | 1501 | |
3 | office | 1502 | dma->sg = sg; |
1503 | dma->flags = DMA_FLAG_EN_CHKSUM; |
||
1504 | //dma->flags = DMA_FLAG_NONE; /* CHECKME */ |
||
1505 | dma->sglen = sglen; |
||
1506 | dma->xfersz = host->xfer_size; |
||
1507 | dma->burstsz = MSDC_BRUST_64B; |
||
1508 | |||
1509 | if (sglen == 1 && sg_dma_len(sg) <= MAX_DMA_CNT) |
||
1510 | dma->mode = MSDC_MODE_DMA_BASIC; |
||
1511 | else |
||
1512 | dma->mode = MSDC_MODE_DMA_DESC; |
||
1 | office | 1513 | |
3 | office | 1514 | N_MSG(DMA, "DMA mode<%d> sglen<%d> xfersz<%d>", dma->mode, dma->sglen, dma->xfersz); |
1 | office | 1515 | |
3 | office | 1516 | msdc_dma_config(host, dma); |
1517 | |||
1518 | /*if (dma->mode == MSDC_MODE_DMA_DESC) { |
||
1519 | //msdc_dma_dump(host, dma); |
||
1520 | } */ |
||
1 | office | 1521 | } |
1522 | |||
3 | office | 1523 | /* set block number before send command */ |
1524 | static void msdc_set_blknum(struct msdc_host *host, u32 blknum) |
||
1 | office | 1525 | { |
3 | office | 1526 | u32 base = host->base; |
1 | office | 1527 | |
3 | office | 1528 | sdr_write32(SDC_BLK_NUM, blknum); |
1 | office | 1529 | } |
1530 | |||
3 | office | 1531 | static int msdc_do_request(struct mmc_host*mmc, struct mmc_request*mrq) |
1 | office | 1532 | { |
3 | office | 1533 | struct msdc_host *host = mmc_priv(mmc); |
1534 | struct mmc_command *cmd; |
||
1535 | struct mmc_data *data; |
||
1536 | u32 base = host->base; |
||
1537 | //u32 intsts = 0; |
||
1538 | unsigned int left=0; |
||
1539 | int dma = 0, read = 1, dir = DMA_FROM_DEVICE, send_type=0; |
||
1540 | |||
1541 | #define SND_DAT 0 |
||
1542 | #define SND_CMD 1 |
||
1 | office | 1543 | |
3 | office | 1544 | BUG_ON(mmc == NULL); |
1545 | BUG_ON(mrq == NULL); |
||
1 | office | 1546 | |
3 | office | 1547 | host->error = 0; |
1548 | atomic_set(&host->abort, 0); |
||
1549 | |||
1550 | cmd = mrq->cmd; |
||
1551 | data = mrq->cmd->data; |
||
1552 | |||
1 | office | 1553 | #if 0 /* --- by chhung */ |
3 | office | 1554 | //if(host->id ==1){ |
1555 | N_MSG(OPS, "enable clock!"); |
||
1556 | msdc_ungate_clock(host->id); |
||
1557 | //} |
||
1 | office | 1558 | #endif /* end of --- */ |
3 | office | 1559 | |
1560 | if (!data) { |
||
1561 | send_type=SND_CMD; |
||
1562 | if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) { |
||
1563 | goto done; |
||
1564 | } |
||
1565 | } else { |
||
1566 | BUG_ON(data->blksz > HOST_MAX_BLKSZ); |
||
1567 | send_type=SND_DAT; |
||
1 | office | 1568 | |
3 | office | 1569 | data->error = 0; |
1570 | read = data->flags & MMC_DATA_READ ? 1 : 0; |
||
1571 | host->data = data; |
||
1572 | host->xfer_size = data->blocks * data->blksz; |
||
1573 | host->blksz = data->blksz; |
||
1 | office | 1574 | |
3 | office | 1575 | /* deside the transfer mode */ |
1576 | if (drv_mode[host->id] == MODE_PIO) { |
||
1577 | host->dma_xfer = dma = 0; |
||
1578 | } else if (drv_mode[host->id] == MODE_DMA) { |
||
1579 | host->dma_xfer = dma = 1; |
||
1580 | } else if (drv_mode[host->id] == MODE_SIZE_DEP) { |
||
1581 | host->dma_xfer = dma = ((host->xfer_size >= dma_size[host->id]) ? 1 : 0); |
||
1582 | } |
||
1 | office | 1583 | |
3 | office | 1584 | if (read) { |
1585 | if ((host->timeout_ns != data->timeout_ns) || |
||
1586 | (host->timeout_clks != data->timeout_clks)) { |
||
1587 | msdc_set_timeout(host, data->timeout_ns, data->timeout_clks); |
||
1588 | } |
||
1589 | } |
||
1590 | |||
1591 | msdc_set_blknum(host, data->blocks); |
||
1592 | //msdc_clr_fifo(); /* no need */ |
||
1 | office | 1593 | |
3 | office | 1594 | if (dma) { |
1595 | msdc_dma_on(); /* enable DMA mode first!! */ |
||
1596 | init_completion(&host->xfer_done); |
||
1597 | |||
1598 | /* start the command first*/ |
||
1599 | if (msdc_command_start(host, cmd, 1, CMD_TIMEOUT) != 0) |
||
1600 | goto done; |
||
1 | office | 1601 | |
3 | office | 1602 | dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; |
1603 | (void)dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, dir); |
||
1604 | msdc_dma_setup(host, &host->dma, data->sg, data->sg_len); |
||
1605 | |||
1606 | /* then wait command done */ |
||
1607 | if (msdc_command_resp(host, cmd, 1, CMD_TIMEOUT) != 0) |
||
1608 | goto done; |
||
1 | office | 1609 | |
3 | office | 1610 | /* for read, the data coming too fast, then CRC error |
1611 | start DMA no business with CRC. */ |
||
1612 | //init_completion(&host->xfer_done); |
||
1613 | msdc_dma_start(host); |
||
1614 | |||
1615 | spin_unlock(&host->lock); |
||
1616 | if(!wait_for_completion_timeout(&host->xfer_done, DAT_TIMEOUT)){ |
||
1617 | ERR_MSG("XXX CMD<%d> wait xfer_done<%d> timeout!!", cmd->opcode, data->blocks * data->blksz); |
||
1618 | ERR_MSG(" DMA_SA = 0x%x", sdr_read32(MSDC_DMA_SA)); |
||
1619 | ERR_MSG(" DMA_CA = 0x%x", sdr_read32(MSDC_DMA_CA)); |
||
1620 | ERR_MSG(" DMA_CTRL = 0x%x", sdr_read32(MSDC_DMA_CTRL)); |
||
1621 | ERR_MSG(" DMA_CFG = 0x%x", sdr_read32(MSDC_DMA_CFG)); |
||
1622 | data->error = (unsigned int)-ETIMEDOUT; |
||
1623 | |||
1624 | msdc_reset(); |
||
1625 | msdc_clr_fifo(); |
||
1626 | msdc_clr_int(); |
||
1627 | } |
||
1628 | spin_lock(&host->lock); |
||
1629 | msdc_dma_stop(host); |
||
1630 | } else { |
||
1631 | /* Firstly: send command */ |
||
1632 | if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) { |
||
1633 | goto done; |
||
1634 | } |
||
1635 | |||
1636 | /* Secondly: pio data phase */ |
||
1637 | if (read) { |
||
1638 | if (msdc_pio_read(host, data)){ |
||
1639 | goto done; |
||
1640 | } |
||
1641 | } else { |
||
1642 | if (msdc_pio_write(host, data)) { |
||
1643 | goto done; |
||
1644 | } |
||
1645 | } |
||
1 | office | 1646 | |
3 | office | 1647 | /* For write case: make sure contents in fifo flushed to device */ |
1648 | if (!read) { |
||
1649 | while (1) { |
||
1650 | left=msdc_txfifocnt(); |
||
1651 | if (left == 0) { |
||
1652 | break; |
||
1653 | } |
||
1654 | if (msdc_pio_abort(host, data, jiffies + DAT_TIMEOUT)) { |
||
1655 | break; |
||
1656 | /* Fix me: what about if data error, when stop ? how to? */ |
||
1657 | } |
||
1658 | } |
||
1659 | } else { |
||
1660 | /* Fix me: read case: need to check CRC error */ |
||
1661 | } |
||
1 | office | 1662 | |
3 | office | 1663 | /* For write case: SDCBUSY and Xfer_Comp will assert when DAT0 not busy. |
1664 | For read case : SDCBUSY and Xfer_Comp will assert when last byte read out from FIFO. |
||
1665 | */ |
||
1666 | |||
1667 | /* try not to wait xfer_comp interrupt. |
||
1668 | the next command will check SDC_BUSY. |
||
1669 | SDC_BUSY means xfer_comp assert |
||
1670 | */ |
||
1671 | |||
1672 | } // PIO mode |
||
1673 | |||
1674 | /* Last: stop transfer */ |
||
1675 | if (data->stop){ |
||
1676 | if (msdc_do_command(host, data->stop, 0, CMD_TIMEOUT) != 0) { |
||
1677 | goto done; |
||
1678 | } |
||
1679 | } |
||
1680 | } |
||
1 | office | 1681 | |
1682 | done: |
||
3 | office | 1683 | if (data != NULL) { |
1684 | host->data = NULL; |
||
1685 | host->dma_xfer = 0; |
||
1686 | if (dma != 0) { |
||
1687 | msdc_dma_off(); |
||
1688 | host->dma.used_bd = 0; |
||
1689 | host->dma.used_gpd = 0; |
||
1690 | dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len, dir); |
||
1691 | } |
||
1692 | host->blksz = 0; |
||
1693 | |||
1 | office | 1694 | #if 0 // don't stop twice! |
3 | office | 1695 | if(host->hw->flags & MSDC_REMOVABLE && data->error) { |
1696 | msdc_abort_data(host); |
||
1697 | /* reset in IRQ, stop command has issued. -> No need */ |
||
1698 | } |
||
1699 | #endif |
||
1 | office | 1700 | |
3 | office | 1701 | N_MSG(OPS, "CMD<%d> data<%s %s> blksz<%d> block<%d> error<%d>",cmd->opcode, (dma? "dma":"pio"), |
1702 | (read ? "read ":"write") ,data->blksz, data->blocks, data->error); |
||
1703 | } |
||
1 | office | 1704 | |
1705 | #if 0 /* --- by chhung */ |
||
3 | office | 1706 | #if 1 |
1707 | //if(host->id==1) { |
||
1708 | if(send_type==SND_CMD) { |
||
1709 | if(cmd->opcode == MMC_SEND_STATUS) { |
||
1710 | if((cmd->resp[0] & CARD_READY_FOR_DATA) ||(CARD_CURRENT_STATE(cmd->resp[0]) != 7)){ |
||
1711 | N_MSG(OPS,"disable clock, CMD13 IDLE"); |
||
1712 | msdc_gate_clock(host->id); |
||
1713 | } |
||
1714 | } else { |
||
1715 | N_MSG(OPS,"disable clock, CMD<%d>", cmd->opcode); |
||
1716 | msdc_gate_clock(host->id); |
||
1717 | } |
||
1718 | } else { |
||
1719 | if(read) { |
||
1720 | N_MSG(OPS,"disable clock!!! Read CMD<%d>",cmd->opcode); |
||
1721 | msdc_gate_clock(host->id); |
||
1722 | } |
||
1723 | } |
||
1724 | //} |
||
1 | office | 1725 | #else |
3 | office | 1726 | msdc_gate_clock(host->id); |
1 | office | 1727 | #endif |
1728 | #endif /* end of --- */ |
||
3 | office | 1729 | |
1730 | if (mrq->cmd->error) host->error = 0x001; |
||
1731 | if (mrq->data && mrq->data->error) host->error |= 0x010; |
||
1732 | if (mrq->stop && mrq->stop->error) host->error |= 0x100; |
||
1 | office | 1733 | |
3 | office | 1734 | //if (host->error) ERR_MSG("host->error<%d>", host->error); |
1 | office | 1735 | |
3 | office | 1736 | return host->error; |
1 | office | 1737 | } |
1738 | |||
1739 | static int msdc_app_cmd(struct mmc_host *mmc, struct msdc_host *host) |
||
1740 | { |
||
3 | office | 1741 | struct mmc_command cmd; |
1742 | struct mmc_request mrq; |
||
1743 | u32 err; |
||
1 | office | 1744 | |
3 | office | 1745 | memset(&cmd, 0, sizeof(struct mmc_command)); |
1746 | cmd.opcode = MMC_APP_CMD; |
||
1747 | #if 0 /* bug: we meet mmc->card is null when ACMD6 */ |
||
1748 | cmd.arg = mmc->card->rca << 16; |
||
1749 | #else |
||
1750 | cmd.arg = host->app_cmd_arg; |
||
1751 | #endif |
||
1752 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; |
||
1 | office | 1753 | |
3 | office | 1754 | memset(&mrq, 0, sizeof(struct mmc_request)); |
1755 | mrq.cmd = &cmd; cmd.mrq = &mrq; |
||
1756 | cmd.data = NULL; |
||
1 | office | 1757 | |
3 | office | 1758 | err = msdc_do_command(host, &cmd, 0, CMD_TIMEOUT); |
1759 | return err; |
||
1 | office | 1760 | } |
1761 | |||
3 | office | 1762 | static int msdc_tune_cmdrsp(struct msdc_host*host, struct mmc_command *cmd) |
1 | office | 1763 | { |
3 | office | 1764 | int result = -1; |
1765 | u32 base = host->base; |
||
1766 | u32 rsmpl, cur_rsmpl, orig_rsmpl; |
||
1767 | u32 rrdly, cur_rrdly = 0xffffffff, orig_rrdly; |
||
1768 | u32 skip = 1; |
||
1769 | |||
1770 | /* ==== don't support 3.0 now ==== |
||
1771 | 1: R_SMPL[1] |
||
1772 | 2: PAD_CMD_RESP_RXDLY[26:22] |
||
1773 | ==========================*/ |
||
1 | office | 1774 | |
3 | office | 1775 | // save the previous tune result |
1776 | sdr_get_field(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl); |
||
1777 | sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, orig_rrdly); |
||
1 | office | 1778 | |
3 | office | 1779 | rrdly = 0; |
1780 | do { |
||
1781 | for (rsmpl = 0; rsmpl < 2; rsmpl++) { |
||
1782 | /* Lv1: R_SMPL[1] */ |
||
1783 | cur_rsmpl = (orig_rsmpl + rsmpl) % 2; |
||
1784 | if (skip == 1) { |
||
1785 | skip = 0; |
||
1786 | continue; |
||
1787 | } |
||
1788 | sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, cur_rsmpl); |
||
1 | office | 1789 | |
3 | office | 1790 | if (host->app_cmd) { |
1791 | result = msdc_app_cmd(host->mmc, host); |
||
1792 | if (result) { |
||
1793 | ERR_MSG("TUNE_CMD app_cmd<%d> failed: RESP_RXDLY<%d>,R_SMPL<%d>", |
||
1794 | host->mrq->cmd->opcode, cur_rrdly, cur_rsmpl); |
||
1795 | continue; |
||
1796 | } |
||
1797 | } |
||
1798 | result = msdc_do_command(host, cmd, 0, CMD_TIMEOUT); // not tune. |
||
1799 | ERR_MSG("TUNE_CMD<%d> %s PAD_CMD_RESP_RXDLY[26:22]<%d> R_SMPL[1]<%d>", cmd->opcode, |
||
1800 | (result == 0) ? "PASS" : "FAIL", cur_rrdly, cur_rsmpl); |
||
1801 | |||
1802 | if (result == 0) { |
||
1803 | return 0; |
||
1804 | } |
||
1805 | if (result != (unsigned int)(-EIO)) { |
||
1806 | ERR_MSG("TUNE_CMD<%d> Error<%d> not -EIO", cmd->opcode, result); |
||
1807 | return result; |
||
1808 | } |
||
1 | office | 1809 | |
3 | office | 1810 | /* should be EIO */ |
1811 | if (sdr_read32(SDC_CMD) & 0x1800) { /* check if has data phase */ |
||
1812 | msdc_abort_data(host); |
||
1813 | } |
||
1814 | } |
||
1815 | |||
1816 | /* Lv2: PAD_CMD_RESP_RXDLY[26:22] */ |
||
1817 | cur_rrdly = (orig_rrdly + rrdly + 1) % 32; |
||
1818 | sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, cur_rrdly); |
||
1819 | }while (++rrdly < 32); |
||
1820 | |||
1821 | return result; |
||
1 | office | 1822 | } |
1823 | |||
1824 | /* Support SD2.0 Only */ |
||
1825 | static int msdc_tune_bread(struct mmc_host *mmc, struct mmc_request *mrq) |
||
1826 | { |
||
3 | office | 1827 | struct msdc_host *host = mmc_priv(mmc); |
1828 | u32 base = host->base; |
||
1829 | u32 ddr=0; |
||
1830 | u32 dcrc=0; |
||
1831 | u32 rxdly, cur_rxdly0, cur_rxdly1; |
||
1832 | u32 dsmpl, cur_dsmpl, orig_dsmpl; |
||
1833 | u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3; |
||
1834 | u32 cur_dat4, cur_dat5, cur_dat6, cur_dat7; |
||
1835 | u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3; |
||
1836 | u32 orig_dat4, orig_dat5, orig_dat6, orig_dat7; |
||
1837 | int result = -1; |
||
1838 | u32 skip = 1; |
||
1 | office | 1839 | |
3 | office | 1840 | sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl); |
1841 | |||
1842 | /* Tune Method 2. */ |
||
1843 | sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); |
||
1 | office | 1844 | |
3 | office | 1845 | rxdly = 0; |
1846 | do { |
||
1847 | for (dsmpl = 0; dsmpl < 2; dsmpl++) { |
||
1848 | cur_dsmpl = (orig_dsmpl + dsmpl) % 2; |
||
1849 | if (skip == 1) { |
||
1850 | skip = 0; |
||
1851 | continue; |
||
1852 | } |
||
1853 | sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl); |
||
1 | office | 1854 | |
3 | office | 1855 | if (host->app_cmd) { |
1856 | result = msdc_app_cmd(host->mmc, host); |
||
1857 | if (result) { |
||
1858 | ERR_MSG("TUNE_BREAD app_cmd<%d> failed", host->mrq->cmd->opcode); |
||
1859 | continue; |
||
1860 | } |
||
1861 | } |
||
1862 | result = msdc_do_request(mmc,mrq); |
||
1863 | |||
1864 | sdr_get_field(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc); /* RO */ |
||
1865 | if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG; |
||
1866 | ERR_MSG("TUNE_BREAD<%s> dcrc<0x%x> DATRDDLY0/1<0x%x><0x%x> dsmpl<0x%x>", |
||
1867 | (result == 0 && dcrc == 0) ? "PASS" : "FAIL", dcrc, |
||
1868 | sdr_read32(MSDC_DAT_RDDLY0), sdr_read32(MSDC_DAT_RDDLY1), cur_dsmpl); |
||
1 | office | 1869 | |
3 | office | 1870 | /* Fix me: result is 0, but dcrc is still exist */ |
1871 | if (result == 0 && dcrc == 0) { |
||
1872 | goto done; |
||
1873 | } else { |
||
1874 | /* there is a case: command timeout, and data phase not processed */ |
||
1875 | if (mrq->data->error != 0 && mrq->data->error != (unsigned int)(-EIO)) { |
||
1876 | ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>", |
||
1877 | result, mrq->cmd->error, mrq->data->error); |
||
1878 | goto done; |
||
1879 | } |
||
1880 | } |
||
1881 | } |
||
1 | office | 1882 | |
3 | office | 1883 | cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0); |
1884 | cur_rxdly1 = sdr_read32(MSDC_DAT_RDDLY1); |
||
1 | office | 1885 | |
3 | office | 1886 | /* E1 ECO. YD: Reverse */ |
1887 | if (sdr_read32(MSDC_ECO_VER) >= 4) { |
||
1888 | orig_dat0 = (cur_rxdly0 >> 24) & 0x1F; |
||
1889 | orig_dat1 = (cur_rxdly0 >> 16) & 0x1F; |
||
1890 | orig_dat2 = (cur_rxdly0 >> 8) & 0x1F; |
||
1891 | orig_dat3 = (cur_rxdly0 >> 0) & 0x1F; |
||
1892 | orig_dat4 = (cur_rxdly1 >> 24) & 0x1F; |
||
1893 | orig_dat5 = (cur_rxdly1 >> 16) & 0x1F; |
||
1894 | orig_dat6 = (cur_rxdly1 >> 8) & 0x1F; |
||
1895 | orig_dat7 = (cur_rxdly1 >> 0) & 0x1F; |
||
1896 | } else { |
||
1897 | orig_dat0 = (cur_rxdly0 >> 0) & 0x1F; |
||
1898 | orig_dat1 = (cur_rxdly0 >> 8) & 0x1F; |
||
1899 | orig_dat2 = (cur_rxdly0 >> 16) & 0x1F; |
||
1900 | orig_dat3 = (cur_rxdly0 >> 24) & 0x1F; |
||
1901 | orig_dat4 = (cur_rxdly1 >> 0) & 0x1F; |
||
1902 | orig_dat5 = (cur_rxdly1 >> 8) & 0x1F; |
||
1903 | orig_dat6 = (cur_rxdly1 >> 16) & 0x1F; |
||
1904 | orig_dat7 = (cur_rxdly1 >> 24) & 0x1F; |
||
1905 | } |
||
1906 | |||
1907 | if (ddr) { |
||
1908 | cur_dat0 = (dcrc & (1 << 0) || dcrc & (1 << 8)) ? ((orig_dat0 + 1) % 32) : orig_dat0; |
||
1909 | cur_dat1 = (dcrc & (1 << 1) || dcrc & (1 << 9)) ? ((orig_dat1 + 1) % 32) : orig_dat1; |
||
1910 | cur_dat2 = (dcrc & (1 << 2) || dcrc & (1 << 10)) ? ((orig_dat2 + 1) % 32) : orig_dat2; |
||
1911 | cur_dat3 = (dcrc & (1 << 3) || dcrc & (1 << 11)) ? ((orig_dat3 + 1) % 32) : orig_dat3; |
||
1912 | } else { |
||
1913 | cur_dat0 = (dcrc & (1 << 0)) ? ((orig_dat0 + 1) % 32) : orig_dat0; |
||
1914 | cur_dat1 = (dcrc & (1 << 1)) ? ((orig_dat1 + 1) % 32) : orig_dat1; |
||
1915 | cur_dat2 = (dcrc & (1 << 2)) ? ((orig_dat2 + 1) % 32) : orig_dat2; |
||
1916 | cur_dat3 = (dcrc & (1 << 3)) ? ((orig_dat3 + 1) % 32) : orig_dat3; |
||
1917 | } |
||
1918 | cur_dat4 = (dcrc & (1 << 4)) ? ((orig_dat4 + 1) % 32) : orig_dat4; |
||
1919 | cur_dat5 = (dcrc & (1 << 5)) ? ((orig_dat5 + 1) % 32) : orig_dat5; |
||
1920 | cur_dat6 = (dcrc & (1 << 6)) ? ((orig_dat6 + 1) % 32) : orig_dat6; |
||
1921 | cur_dat7 = (dcrc & (1 << 7)) ? ((orig_dat7 + 1) % 32) : orig_dat7; |
||
1 | office | 1922 | |
3 | office | 1923 | cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0); |
1924 | cur_rxdly1 = (cur_dat4 << 24) | (cur_dat5 << 16) | (cur_dat6 << 8) | (cur_dat7 << 0); |
||
1 | office | 1925 | |
3 | office | 1926 | sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0); |
1927 | sdr_write32(MSDC_DAT_RDDLY1, cur_rxdly1); |
||
1 | office | 1928 | |
3 | office | 1929 | } while (++rxdly < 32); |
1930 | |||
1 | office | 1931 | done: |
3 | office | 1932 | return result; |
1 | office | 1933 | } |
1934 | |||
3 | office | 1935 | static int msdc_tune_bwrite(struct mmc_host *mmc,struct mmc_request *mrq) |
1 | office | 1936 | { |
3 | office | 1937 | struct msdc_host *host = mmc_priv(mmc); |
1938 | u32 base = host->base; |
||
1 | office | 1939 | |
3 | office | 1940 | u32 wrrdly, cur_wrrdly = 0xffffffff, orig_wrrdly; |
1941 | u32 dsmpl, cur_dsmpl, orig_dsmpl; |
||
1942 | u32 rxdly, cur_rxdly0; |
||
1943 | u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3; |
||
1944 | u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3; |
||
1945 | int result = -1; |
||
1946 | u32 skip = 1; |
||
1 | office | 1947 | |
3 | office | 1948 | // MSDC_IOCON_DDR50CKD need to check. [Fix me] |
1949 | |||
1950 | sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, orig_wrrdly); |
||
1951 | sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl ); |
||
1 | office | 1952 | |
3 | office | 1953 | /* Tune Method 2. just DAT0 */ |
1954 | sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); |
||
1955 | cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0); |
||
1956 | |||
1957 | /* E1 ECO. YD: Reverse */ |
||
1958 | if (sdr_read32(MSDC_ECO_VER) >= 4) { |
||
1959 | orig_dat0 = (cur_rxdly0 >> 24) & 0x1F; |
||
1960 | orig_dat1 = (cur_rxdly0 >> 16) & 0x1F; |
||
1961 | orig_dat2 = (cur_rxdly0 >> 8) & 0x1F; |
||
1962 | orig_dat3 = (cur_rxdly0 >> 0) & 0x1F; |
||
1963 | } else { |
||
1964 | orig_dat0 = (cur_rxdly0 >> 0) & 0x1F; |
||
1965 | orig_dat1 = (cur_rxdly0 >> 8) & 0x1F; |
||
1966 | orig_dat2 = (cur_rxdly0 >> 16) & 0x1F; |
||
1967 | orig_dat3 = (cur_rxdly0 >> 24) & 0x1F; |
||
1968 | } |
||
1 | office | 1969 | |
3 | office | 1970 | rxdly = 0; |
1971 | do { |
||
1972 | wrrdly = 0; |
||
1973 | do { |
||
1974 | for (dsmpl = 0; dsmpl < 2; dsmpl++) { |
||
1975 | cur_dsmpl = (orig_dsmpl + dsmpl) % 2; |
||
1976 | if (skip == 1) { |
||
1977 | skip = 0; |
||
1978 | continue; |
||
1979 | } |
||
1980 | sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl); |
||
1981 | |||
1982 | if (host->app_cmd) { |
||
1983 | result = msdc_app_cmd(host->mmc, host); |
||
1984 | if (result) { |
||
1985 | ERR_MSG("TUNE_BWRITE app_cmd<%d> failed", host->mrq->cmd->opcode); |
||
1986 | continue; |
||
1987 | } |
||
1988 | } |
||
1989 | result = msdc_do_request(mmc,mrq); |
||
1990 | |||
1991 | ERR_MSG("TUNE_BWRITE<%s> DSPL<%d> DATWRDLY<%d> MSDC_DAT_RDDLY0<0x%x>", |
||
1992 | result == 0 ? "PASS" : "FAIL", |
||
1993 | cur_dsmpl, cur_wrrdly, cur_rxdly0); |
||
1994 | |||
1995 | if (result == 0) { |
||
1996 | goto done; |
||
1997 | } |
||
1998 | else { |
||
1999 | /* there is a case: command timeout, and data phase not processed */ |
||
2000 | if (mrq->data->error != (unsigned int)(-EIO)) { |
||
2001 | ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>", |
||
2002 | result, mrq->cmd->error, mrq->data->error); |
||
2003 | goto done; |
||
2004 | } |
||
2005 | } |
||
2006 | } |
||
2007 | cur_wrrdly = (orig_wrrdly + wrrdly + 1) % 32; |
||
2008 | sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, cur_wrrdly); |
||
2009 | } while (++wrrdly < 32); |
||
2010 | |||
2011 | cur_dat0 = (orig_dat0 + rxdly) % 32; /* only adjust bit-1 for crc */ |
||
2012 | cur_dat1 = orig_dat1; |
||
2013 | cur_dat2 = orig_dat2; |
||
2014 | cur_dat3 = orig_dat3; |
||
2015 | |||
2016 | cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0); |
||
2017 | sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0); |
||
2018 | } while (++rxdly < 32); |
||
1 | office | 2019 | |
2020 | done: |
||
3 | office | 2021 | return result; |
1 | office | 2022 | } |
2023 | |||
2024 | static int msdc_get_card_status(struct mmc_host *mmc, struct msdc_host *host, u32 *status) |
||
2025 | { |
||
3 | office | 2026 | struct mmc_command cmd; |
2027 | struct mmc_request mrq; |
||
2028 | u32 err; |
||
1 | office | 2029 | |
3 | office | 2030 | memset(&cmd, 0, sizeof(struct mmc_command)); |
2031 | cmd.opcode = MMC_SEND_STATUS; |
||
2032 | if (mmc->card) { |
||
2033 | cmd.arg = mmc->card->rca << 16; |
||
2034 | } else { |
||
2035 | ERR_MSG("cmd13 mmc card is null"); |
||
2036 | cmd.arg = host->app_cmd_arg; |
||
2037 | } |
||
2038 | cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; |
||
1 | office | 2039 | |
3 | office | 2040 | memset(&mrq, 0, sizeof(struct mmc_request)); |
2041 | mrq.cmd = &cmd; cmd.mrq = &mrq; |
||
2042 | cmd.data = NULL; |
||
1 | office | 2043 | |
3 | office | 2044 | err = msdc_do_command(host, &cmd, 1, CMD_TIMEOUT); |
2045 | |||
2046 | if (status) { |
||
2047 | *status = cmd.resp[0]; |
||
2048 | } |
||
2049 | |||
2050 | return err; |
||
1 | office | 2051 | } |
2052 | |||
2053 | static int msdc_check_busy(struct mmc_host *mmc, struct msdc_host *host) |
||
2054 | { |
||
3 | office | 2055 | u32 err = 0; |
2056 | u32 status = 0; |
||
2057 | |||
2058 | do { |
||
2059 | err = msdc_get_card_status(mmc, host, &status); |
||
2060 | if (err) return err; |
||
2061 | /* need cmd12? */ |
||
2062 | ERR_MSG("cmd<13> resp<0x%x>", status); |
||
2063 | } while (R1_CURRENT_STATE(status) == 7); |
||
2064 | |||
2065 | return err; |
||
1 | office | 2066 | } |
2067 | |||
2068 | /* failed when msdc_do_request */ |
||
2069 | static int msdc_tune_request(struct mmc_host *mmc, struct mmc_request *mrq) |
||
2070 | { |
||
3 | office | 2071 | struct msdc_host *host = mmc_priv(mmc); |
2072 | struct mmc_command *cmd; |
||
2073 | struct mmc_data *data; |
||
2074 | //u32 base = host->base; |
||
2075 | int ret=0, read; |
||
2076 | |||
2077 | cmd = mrq->cmd; |
||
2078 | data = mrq->cmd->data; |
||
2079 | |||
2080 | read = data->flags & MMC_DATA_READ ? 1 : 0; |
||
1 | office | 2081 | |
3 | office | 2082 | if (read) { |
2083 | if (data->error == (unsigned int)(-EIO)) { |
||
2084 | ret = msdc_tune_bread(mmc,mrq); |
||
2085 | } |
||
2086 | } else { |
||
2087 | ret = msdc_check_busy(mmc, host); |
||
2088 | if (ret){ |
||
2089 | ERR_MSG("XXX cmd13 wait program done failed"); |
||
2090 | return ret; |
||
2091 | } |
||
2092 | /* CRC and TO */ |
||
2093 | /* Fix me: don't care card status? */ |
||
2094 | ret = msdc_tune_bwrite(mmc,mrq); |
||
2095 | } |
||
1 | office | 2096 | |
3 | office | 2097 | return ret; |
1 | office | 2098 | } |
2099 | |||
2100 | /* ops.request */ |
||
3 | office | 2101 | static void msdc_ops_request(struct mmc_host *mmc,struct mmc_request *mrq) |
2102 | { |
||
2103 | struct msdc_host *host = mmc_priv(mmc); |
||
1 | office | 2104 | |
3 | office | 2105 | //=== for sdio profile === |
1 | office | 2106 | #if 0 /* --- by chhung */ |
3 | office | 2107 | u32 old_H32, old_L32, new_H32, new_L32; |
2108 | u32 ticks = 0, opcode = 0, sizes = 0, bRx = 0; |
||
1 | office | 2109 | #endif /* end of --- */ |
3 | office | 2110 | |
2111 | if(host->mrq){ |
||
2112 | ERR_MSG("XXX host->mrq<0x%.8x>", (int)host->mrq); |
||
2113 | BUG(); |
||
2114 | } |
||
2115 | |||
2116 | if (!is_card_present(host) || host->power_mode == MMC_POWER_OFF) { |
||
2117 | ERR_MSG("cmd<%d> card<%d> power<%d>", mrq->cmd->opcode, is_card_present(host), host->power_mode); |
||
2118 | mrq->cmd->error = (unsigned int)-ENOMEDIUM; |
||
2119 | |||
2120 | #if 1 |
||
2121 | mrq->done(mrq); // call done directly. |
||
2122 | #else |
||
2123 | mrq->cmd->retries = 0; // please don't retry. |
||
2124 | mmc_request_done(mmc, mrq); |
||
2125 | #endif |
||
1 | office | 2126 | |
3 | office | 2127 | return; |
2128 | } |
||
2129 | |||
2130 | /* start to process */ |
||
2131 | spin_lock(&host->lock); |
||
1 | office | 2132 | #if 0 /* --- by chhung */ |
3 | office | 2133 | if (sdio_pro_enable) { //=== for sdio profile === |
2134 | if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53) { |
||
2135 | GPT_GetCounter64(&old_L32, &old_H32); |
||
2136 | } |
||
2137 | } |
||
1 | office | 2138 | #endif /* end of --- */ |
3 | office | 2139 | |
2140 | host->mrq = mrq; |
||
1 | office | 2141 | |
3 | office | 2142 | if (msdc_do_request(mmc,mrq)) { |
2143 | if(host->hw->flags & MSDC_REMOVABLE && ralink_soc == MT762X_SOC_MT7621AT && mrq->data && mrq->data->error) { |
||
2144 | msdc_tune_request(mmc,mrq); |
||
2145 | } |
||
2146 | } |
||
1 | office | 2147 | |
3 | office | 2148 | /* ==== when request done, check if app_cmd ==== */ |
2149 | if (mrq->cmd->opcode == MMC_APP_CMD) { |
||
2150 | host->app_cmd = 1; |
||
2151 | host->app_cmd_arg = mrq->cmd->arg; /* save the RCA */ |
||
2152 | } else { |
||
2153 | host->app_cmd = 0; |
||
2154 | //host->app_cmd_arg = 0; |
||
2155 | } |
||
2156 | |||
2157 | host->mrq = NULL; |
||
1 | office | 2158 | |
2159 | #if 0 /* --- by chhung */ |
||
3 | office | 2160 | //=== for sdio profile === |
2161 | if (sdio_pro_enable) { |
||
2162 | if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53) { |
||
2163 | GPT_GetCounter64(&new_L32, &new_H32); |
||
2164 | ticks = msdc_time_calc(old_L32, old_H32, new_L32, new_H32); |
||
2165 | |||
2166 | opcode = mrq->cmd->opcode; |
||
2167 | if (mrq->cmd->data) { |
||
2168 | sizes = mrq->cmd->data->blocks * mrq->cmd->data->blksz; |
||
2169 | bRx = mrq->cmd->data->flags & MMC_DATA_READ ? 1 : 0 ; |
||
2170 | } else { |
||
2171 | bRx = mrq->cmd->arg & 0x80000000 ? 1 : 0; |
||
2172 | } |
||
2173 | |||
2174 | if (!mrq->cmd->error) { |
||
2175 | msdc_performance(opcode, sizes, bRx, ticks); |
||
2176 | } |
||
2177 | } |
||
2178 | } |
||
1 | office | 2179 | #endif /* end of --- */ |
3 | office | 2180 | spin_unlock(&host->lock); |
2181 | |||
2182 | mmc_request_done(mmc, mrq); |
||
2183 | |||
2184 | return; |
||
1 | office | 2185 | } |
2186 | |||
2187 | /* called by ops.set_ios */ |
||
2188 | static void msdc_set_buswidth(struct msdc_host *host, u32 width) |
||
2189 | { |
||
3 | office | 2190 | u32 base = host->base; |
2191 | u32 val = sdr_read32(SDC_CFG); |
||
2192 | |||
2193 | val &= ~SDC_CFG_BUSWIDTH; |
||
2194 | |||
2195 | switch (width) { |
||
2196 | default: |
||
2197 | case MMC_BUS_WIDTH_1: |
||
2198 | width = 1; |
||
2199 | val |= (MSDC_BUS_1BITS << 16); |
||
2200 | break; |
||
2201 | case MMC_BUS_WIDTH_4: |
||
2202 | val |= (MSDC_BUS_4BITS << 16); |
||
2203 | break; |
||
2204 | case MMC_BUS_WIDTH_8: |
||
2205 | val |= (MSDC_BUS_8BITS << 16); |
||
2206 | break; |
||
2207 | } |
||
2208 | |||
2209 | sdr_write32(SDC_CFG, val); |
||
1 | office | 2210 | |
3 | office | 2211 | N_MSG(CFG, "Bus Width = %d", width); |
1 | office | 2212 | } |
2213 | |||
2214 | /* ops.set_ios */ |
||
2215 | static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
||
2216 | { |
||
3 | office | 2217 | struct msdc_host *host = mmc_priv(mmc); |
2218 | struct msdc_hw *hw=host->hw; |
||
2219 | u32 base = host->base; |
||
2220 | u32 ddr = 0; |
||
1 | office | 2221 | |
2222 | #ifdef MT6575_SD_DEBUG |
||
3 | office | 2223 | static char *vdd[] = { |
2224 | "1.50v", "1.55v", "1.60v", "1.65v", "1.70v", "1.80v", "1.90v", |
||
2225 | "2.00v", "2.10v", "2.20v", "2.30v", "2.40v", "2.50v", "2.60v", |
||
2226 | "2.70v", "2.80v", "2.90v", "3.00v", "3.10v", "3.20v", "3.30v", |
||
2227 | "3.40v", "3.50v", "3.60v" |
||
2228 | }; |
||
2229 | static char *power_mode[] = { |
||
2230 | "OFF", "UP", "ON" |
||
2231 | }; |
||
2232 | static char *bus_mode[] = { |
||
2233 | "UNKNOWN", "OPENDRAIN", "PUSHPULL" |
||
2234 | }; |
||
2235 | static char *timing[] = { |
||
2236 | "LEGACY", "MMC_HS", "SD_HS" |
||
2237 | }; |
||
1 | office | 2238 | |
3 | office | 2239 | printk("SET_IOS: CLK(%dkHz), BUS(%s), BW(%u), PWR(%s), VDD(%s), TIMING(%s)", |
2240 | ios->clock / 1000, bus_mode[ios->bus_mode], |
||
2241 | (ios->bus_width == MMC_BUS_WIDTH_4) ? 4 : 1, |
||
2242 | power_mode[ios->power_mode], vdd[ios->vdd], timing[ios->timing]); |
||
1 | office | 2243 | #endif |
2244 | |||
3 | office | 2245 | msdc_set_buswidth(host, ios->bus_width); |
2246 | |||
2247 | /* Power control ??? */ |
||
2248 | switch (ios->power_mode) { |
||
2249 | case MMC_POWER_OFF: |
||
2250 | case MMC_POWER_UP: |
||
2251 | // msdc_set_power_mode(host, ios->power_mode); /* --- by chhung */ |
||
2252 | break; |
||
2253 | case MMC_POWER_ON: |
||
2254 | host->power_mode = MMC_POWER_ON; |
||
2255 | break; |
||
2256 | default: |
||
2257 | break; |
||
2258 | } |
||
1 | office | 2259 | |
3 | office | 2260 | /* Clock control */ |
2261 | if (host->mclk != ios->clock) { |
||
2262 | if(ios->clock > 25000000) { |
||
2263 | //if (!(host->hw->flags & MSDC_REMOVABLE)) { |
||
2264 | INIT_MSG("SD data latch edge<%d>", hw->data_edge); |
||
2265 | sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, hw->cmd_edge); |
||
2266 | sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, hw->data_edge); |
||
2267 | //} /* for tuning debug */ |
||
2268 | } else { /* default value */ |
||
2269 | sdr_write32(MSDC_IOCON, 0x00000000); |
||
2270 | // sdr_write32(MSDC_DAT_RDDLY0, 0x00000000); |
||
2271 | sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward |
||
2272 | sdr_write32(MSDC_DAT_RDDLY1, 0x00000000); |
||
2273 | // sdr_write32(MSDC_PAD_TUNE, 0x00000000); |
||
2274 | sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward |
||
2275 | } |
||
2276 | msdc_set_mclk(host, ddr, ios->clock); |
||
2277 | } |
||
1 | office | 2278 | } |
2279 | |||
2280 | /* ops.get_ro */ |
||
2281 | static int msdc_ops_get_ro(struct mmc_host *mmc) |
||
2282 | { |
||
3 | office | 2283 | struct msdc_host *host = mmc_priv(mmc); |
2284 | u32 base = host->base; |
||
2285 | unsigned long flags; |
||
2286 | int ro = 0; |
||
1 | office | 2287 | |
3 | office | 2288 | if (host->hw->flags & MSDC_WP_PIN_EN) { /* set for card */ |
2289 | spin_lock_irqsave(&host->lock, flags); |
||
2290 | ro = (sdr_read32(MSDC_PS) >> 31); |
||
2291 | spin_unlock_irqrestore(&host->lock, flags); |
||
2292 | } |
||
2293 | return ro; |
||
1 | office | 2294 | } |
2295 | |||
2296 | /* ops.get_cd */ |
||
2297 | static int msdc_ops_get_cd(struct mmc_host *mmc) |
||
2298 | { |
||
3 | office | 2299 | struct msdc_host *host = mmc_priv(mmc); |
2300 | u32 base = host->base; |
||
2301 | unsigned long flags; |
||
2302 | int present = 1; |
||
1 | office | 2303 | |
3 | office | 2304 | /* for sdio, MSDC_REMOVABLE not set, always return 1 */ |
2305 | if (!(host->hw->flags & MSDC_REMOVABLE)) { |
||
2306 | /* For sdio, read H/W always get<1>, but may timeout some times */ |
||
1 | office | 2307 | #if 1 |
3 | office | 2308 | host->card_inserted = 1; |
2309 | return 1; |
||
1 | office | 2310 | #else |
3 | office | 2311 | host->card_inserted = (host->pm_state.event == PM_EVENT_USER_RESUME) ? 1 : 0; |
2312 | INIT_MSG("sdio ops_get_cd<%d>", host->card_inserted); |
||
2313 | return host->card_inserted; |
||
1 | office | 2314 | #endif |
3 | office | 2315 | } |
1 | office | 2316 | |
3 | office | 2317 | /* MSDC_CD_PIN_EN set for card */ |
2318 | if (host->hw->flags & MSDC_CD_PIN_EN) { |
||
2319 | spin_lock_irqsave(&host->lock, flags); |
||
2320 | #if 0 |
||
2321 | present = host->card_inserted; /* why not read from H/W: Fix me*/ |
||
1 | office | 2322 | #else |
3 | office | 2323 | // CD |
2324 | if (cd_active_low) |
||
2325 | present = (sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1; |
||
2326 | else |
||
2327 | present = (sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 1 : 0; |
||
2328 | if (host->mmc->caps & MMC_CAP_NEEDS_POLL) |
||
2329 | present = 1; |
||
2330 | host->card_inserted = present; |
||
2331 | #endif |
||
2332 | spin_unlock_irqrestore(&host->lock, flags); |
||
2333 | } else { |
||
2334 | present = 0; /* TODO? Check DAT3 pins for card detection */ |
||
2335 | } |
||
1 | office | 2336 | |
3 | office | 2337 | INIT_MSG("ops_get_cd return<%d>", present); |
2338 | return present; |
||
1 | office | 2339 | } |
2340 | |||
3 | office | 2341 | /* ops.enable_sdio_irq */ |
2342 | static void msdc_ops_enable_sdio_irq(struct mmc_host *mmc, int enable) |
||
2343 | { |
||
2344 | struct msdc_host *host = mmc_priv(mmc); |
||
2345 | struct msdc_hw *hw = host->hw; |
||
2346 | u32 base = host->base; |
||
2347 | u32 tmp; |
||
2348 | |||
2349 | if (hw->flags & MSDC_EXT_SDIO_IRQ) { /* yes for sdio */ |
||
2350 | if (enable) { |
||
2351 | hw->enable_sdio_eirq(); /* combo_sdio_enable_eirq */ |
||
2352 | } else { |
||
2353 | hw->disable_sdio_eirq(); /* combo_sdio_disable_eirq */ |
||
2354 | } |
||
2355 | } else { |
||
2356 | ERR_MSG("XXX "); /* so never enter here */ |
||
2357 | tmp = sdr_read32(SDC_CFG); |
||
2358 | /* FIXME. Need to interrupt gap detection */ |
||
2359 | if (enable) { |
||
2360 | tmp |= (SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP); |
||
2361 | } else { |
||
2362 | tmp &= ~(SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP); |
||
2363 | } |
||
2364 | sdr_write32(SDC_CFG, tmp); |
||
2365 | } |
||
2366 | } |
||
2367 | |||
1 | office | 2368 | static struct mmc_host_ops mt_msdc_ops = { |
3 | office | 2369 | .request = msdc_ops_request, |
2370 | .set_ios = msdc_ops_set_ios, |
||
2371 | .get_ro = msdc_ops_get_ro, |
||
2372 | .get_cd = msdc_ops_get_cd, |
||
2373 | .enable_sdio_irq = msdc_ops_enable_sdio_irq, |
||
1 | office | 2374 | }; |
2375 | |||
2376 | /*--------------------------------------------------------------------------*/ |
||
2377 | /* interrupt handler */ |
||
2378 | /*--------------------------------------------------------------------------*/ |
||
2379 | static irqreturn_t msdc_irq(int irq, void *dev_id) |
||
2380 | { |
||
3 | office | 2381 | struct msdc_host *host = (struct msdc_host *)dev_id; |
2382 | struct mmc_data *data = host->data; |
||
2383 | struct mmc_command *cmd = host->cmd; |
||
2384 | u32 base = host->base; |
||
2385 | |||
2386 | u32 cmdsts = MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | MSDC_INT_CMDRDY | |
||
2387 | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | MSDC_INT_ACMDRDY | |
||
2388 | MSDC_INT_ACMD19_DONE; |
||
2389 | u32 datsts = MSDC_INT_DATCRCERR |MSDC_INT_DATTMO; |
||
1 | office | 2390 | |
3 | office | 2391 | u32 intsts = sdr_read32(MSDC_INT); |
2392 | u32 inten = sdr_read32(MSDC_INTEN); inten &= intsts; |
||
1 | office | 2393 | |
3 | office | 2394 | sdr_write32(MSDC_INT, intsts); /* clear interrupts */ |
2395 | /* MSG will cause fatal error */ |
||
2396 | |||
2397 | /* card change interrupt */ |
||
2398 | if (intsts & MSDC_INT_CDSC){ |
||
2399 | if (mtk_sw_poll) |
||
2400 | return IRQ_HANDLED; |
||
2401 | IRQ_MSG("MSDC_INT_CDSC irq<0x%.8x>", intsts); |
||
2402 | #if 0 /* ---/+++ by chhung: fix slot mechanical bounce issue */ |
||
2403 | tasklet_hi_schedule(&host->card_tasklet); |
||
2404 | #else |
||
2405 | schedule_delayed_work(&host->card_delaywork, HZ); |
||
2406 | #endif |
||
2407 | /* tuning when plug card ? */ |
||
2408 | } |
||
2409 | |||
2410 | /* sdio interrupt */ |
||
2411 | if (intsts & MSDC_INT_SDIOIRQ){ |
||
2412 | IRQ_MSG("XXX MSDC_INT_SDIOIRQ"); /* seems not sdio irq */ |
||
2413 | //mmc_signal_sdio_irq(host->mmc); |
||
2414 | } |
||
1 | office | 2415 | |
3 | office | 2416 | /* transfer complete interrupt */ |
2417 | if (data != NULL) { |
||
2418 | if (inten & MSDC_INT_XFER_COMPL) { |
||
2419 | data->bytes_xfered = host->dma.xfersz; |
||
2420 | complete(&host->xfer_done); |
||
2421 | } |
||
2422 | |||
2423 | if (intsts & datsts) { |
||
2424 | /* do basic reset, or stop command will sdc_busy */ |
||
2425 | msdc_reset(); |
||
2426 | msdc_clr_fifo(); |
||
2427 | msdc_clr_int(); |
||
2428 | atomic_set(&host->abort, 1); /* For PIO mode exit */ |
||
2429 | |||
2430 | if (intsts & MSDC_INT_DATTMO){ |
||
2431 | IRQ_MSG("XXX CMD<%d> MSDC_INT_DATTMO", host->mrq->cmd->opcode); |
||
2432 | data->error = (unsigned int)-ETIMEDOUT; |
||
2433 | } |
||
2434 | else if (intsts & MSDC_INT_DATCRCERR){ |
||
2435 | IRQ_MSG("XXX CMD<%d> MSDC_INT_DATCRCERR, SDC_DCRC_STS<0x%x>", host->mrq->cmd->opcode, sdr_read32(SDC_DCRC_STS)); |
||
2436 | data->error = (unsigned int)-EIO; |
||
2437 | } |
||
2438 | |||
2439 | //if(sdr_read32(MSDC_INTEN) & MSDC_INT_XFER_COMPL) { |
||
2440 | if (host->dma_xfer) { |
||
2441 | complete(&host->xfer_done); /* Read CRC come fast, XFER_COMPL not enabled */ |
||
2442 | } /* PIO mode can't do complete, because not init */ |
||
2443 | } |
||
2444 | } |
||
1 | office | 2445 | |
3 | office | 2446 | /* command interrupts */ |
2447 | if ((cmd != NULL) && (intsts & cmdsts)) { |
||
2448 | if ((intsts & MSDC_INT_CMDRDY) || (intsts & MSDC_INT_ACMDRDY) || |
||
2449 | (intsts & MSDC_INT_ACMD19_DONE)) { |
||
2450 | u32 *rsp = &cmd->resp[0]; |
||
2451 | |||
2452 | switch (host->cmd_rsp) { |
||
2453 | case RESP_NONE: |
||
2454 | break; |
||
2455 | case RESP_R2: |
||
2456 | *rsp++ = sdr_read32(SDC_RESP3); *rsp++ = sdr_read32(SDC_RESP2); |
||
2457 | *rsp++ = sdr_read32(SDC_RESP1); *rsp++ = sdr_read32(SDC_RESP0); |
||
2458 | break; |
||
2459 | default: /* Response types 1, 3, 4, 5, 6, 7(1b) */ |
||
2460 | if ((intsts & MSDC_INT_ACMDRDY) || (intsts & MSDC_INT_ACMD19_DONE)) { |
||
2461 | *rsp = sdr_read32(SDC_ACMD_RESP); |
||
2462 | } else { |
||
2463 | *rsp = sdr_read32(SDC_RESP0); |
||
2464 | } |
||
2465 | break; |
||
2466 | } |
||
2467 | } else if ((intsts & MSDC_INT_RSPCRCERR) || (intsts & MSDC_INT_ACMDCRCERR)) { |
||
2468 | if(intsts & MSDC_INT_ACMDCRCERR){ |
||
2469 | IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDCRCERR",cmd->opcode); |
||
2470 | } |
||
2471 | else { |
||
2472 | IRQ_MSG("XXX CMD<%d> MSDC_INT_RSPCRCERR",cmd->opcode); |
||
2473 | } |
||
2474 | cmd->error = (unsigned int)-EIO; |
||
2475 | } else if ((intsts & MSDC_INT_CMDTMO) || (intsts & MSDC_INT_ACMDTMO)) { |
||
2476 | if(intsts & MSDC_INT_ACMDTMO){ |
||
2477 | IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDTMO",cmd->opcode); |
||
2478 | } |
||
2479 | else { |
||
2480 | IRQ_MSG("XXX CMD<%d> MSDC_INT_CMDTMO",cmd->opcode); |
||
2481 | } |
||
2482 | cmd->error = (unsigned int)-ETIMEDOUT; |
||
2483 | msdc_reset(); |
||
2484 | msdc_clr_fifo(); |
||
2485 | msdc_clr_int(); |
||
2486 | } |
||
2487 | complete(&host->cmd_done); |
||
2488 | } |
||
1 | office | 2489 | |
3 | office | 2490 | /* mmc irq interrupts */ |
2491 | if (intsts & MSDC_INT_MMCIRQ) { |
||
2492 | printk(KERN_INFO "msdc[%d] MMCIRQ: SDC_CSTS=0x%.8x\r\n", host->id, sdr_read32(SDC_CSTS)); |
||
2493 | } |
||
2494 | |||
2495 | #ifdef MT6575_SD_DEBUG |
||
2496 | { |
||
2497 | msdc_int_reg *int_reg = (msdc_int_reg*)&intsts; |
||
2498 | N_MSG(INT, "IRQ_EVT(0x%x): MMCIRQ(%d) CDSC(%d), ACRDY(%d), ACTMO(%d), ACCRE(%d) AC19DN(%d)", |
||
2499 | intsts, |
||
2500 | int_reg->mmcirq, |
||
2501 | int_reg->cdsc, |
||
2502 | int_reg->atocmdrdy, |
||
2503 | int_reg->atocmdtmo, |
||
2504 | int_reg->atocmdcrc, |
||
2505 | int_reg->atocmd19done); |
||
2506 | N_MSG(INT, "IRQ_EVT(0x%x): SDIO(%d) CMDRDY(%d), CMDTMO(%d), RSPCRC(%d), CSTA(%d)", |
||
2507 | intsts, |
||
2508 | int_reg->sdioirq, |
||
2509 | int_reg->cmdrdy, |
||
2510 | int_reg->cmdtmo, |
||
2511 | int_reg->rspcrc, |
||
2512 | int_reg->csta); |
||
2513 | N_MSG(INT, "IRQ_EVT(0x%x): XFCMP(%d) DXDONE(%d), DATTMO(%d), DATCRC(%d), DMAEMP(%d)", |
||
2514 | intsts, |
||
2515 | int_reg->xfercomp, |
||
2516 | int_reg->dxferdone, |
||
2517 | int_reg->dattmo, |
||
2518 | int_reg->datcrc, |
||
2519 | int_reg->dmaqempty); |
||
1 | office | 2520 | |
3 | office | 2521 | } |
1 | office | 2522 | #endif |
3 | office | 2523 | |
2524 | return IRQ_HANDLED; |
||
1 | office | 2525 | } |
2526 | |||
2527 | /*--------------------------------------------------------------------------*/ |
||
2528 | /* platform_driver members */ |
||
2529 | /*--------------------------------------------------------------------------*/ |
||
2530 | /* called by msdc_drv_probe/remove */ |
||
2531 | static void msdc_enable_cd_irq(struct msdc_host *host, int enable) |
||
2532 | { |
||
2533 | struct msdc_hw *hw = host->hw; |
||
3 | office | 2534 | u32 base = host->base; |
1 | office | 2535 | |
2536 | /* for sdio, not set */ |
||
2537 | if ((hw->flags & MSDC_CD_PIN_EN) == 0) { |
||
2538 | /* Pull down card detection pin since it is not avaiable */ |
||
2539 | /* |
||
3 | office | 2540 | if (hw->config_gpio_pin) |
2541 | hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN); |
||
2542 | */ |
||
1 | office | 2543 | sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); |
2544 | sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC); |
||
2545 | sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP); |
||
2546 | return; |
||
2547 | } |
||
2548 | |||
2549 | N_MSG(CFG, "CD IRQ Eanable(%d)", enable); |
||
2550 | |||
2551 | if (enable) { |
||
3 | office | 2552 | if (hw->enable_cd_eirq) { /* not set, never enter */ |
2553 | hw->enable_cd_eirq(); |
||
2554 | } else { |
||
2555 | /* card detection circuit relies on the core power so that the core power |
||
2556 | * shouldn't be turned off. Here adds a reference count to keep |
||
2557 | * the core power alive. |
||
2558 | */ |
||
2559 | //msdc_vcore_on(host); //did in msdc_init_hw() |
||
1 | office | 2560 | |
3 | office | 2561 | if (hw->config_gpio_pin) /* NULL */ |
2562 | hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_UP); |
||
1 | office | 2563 | |
3 | office | 2564 | sdr_set_field(MSDC_PS, MSDC_PS_CDDEBOUNCE, DEFAULT_DEBOUNCE); |
2565 | sdr_set_bits(MSDC_PS, MSDC_PS_CDEN); |
||
2566 | sdr_set_bits(MSDC_INTEN, MSDC_INTEN_CDSC); |
||
2567 | sdr_set_bits(SDC_CFG, SDC_CFG_INSWKUP); /* not in document! Fix me */ |
||
2568 | } |
||
2569 | } else { |
||
2570 | if (hw->disable_cd_eirq) { |
||
2571 | hw->disable_cd_eirq(); |
||
2572 | } else { |
||
2573 | if (hw->config_gpio_pin) /* NULL */ |
||
2574 | hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN); |
||
1 | office | 2575 | |
3 | office | 2576 | sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP); |
2577 | sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); |
||
2578 | sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC); |
||
1 | office | 2579 | |
3 | office | 2580 | /* Here decreases a reference count to core power since card |
2581 | * detection circuit is shutdown. |
||
2582 | */ |
||
2583 | //msdc_vcore_off(host); |
||
2584 | } |
||
2585 | } |
||
1 | office | 2586 | } |
2587 | |||
2588 | /* called by msdc_drv_probe */ |
||
2589 | static void msdc_init_hw(struct msdc_host *host) |
||
2590 | { |
||
3 | office | 2591 | u32 base = host->base; |
2592 | struct msdc_hw *hw = host->hw; |
||
1 | office | 2593 | |
3 | office | 2594 | /* Power on */ |
1 | office | 2595 | #if 0 /* --- by chhung */ |
3 | office | 2596 | msdc_vcore_on(host); |
2597 | msdc_pin_reset(host, MSDC_PIN_PULL_UP); |
||
2598 | msdc_select_clksrc(host, hw->clk_src); |
||
2599 | enable_clock(PERI_MSDC0_PDN + host->id, "SD"); |
||
2600 | msdc_vdd_on(host); |
||
1 | office | 2601 | #endif /* end of --- */ |
3 | office | 2602 | /* Configure to MMC/SD mode */ |
2603 | sdr_set_field(MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC); |
||
2604 | |||
2605 | /* Reset */ |
||
2606 | msdc_reset(); |
||
2607 | msdc_clr_fifo(); |
||
1 | office | 2608 | |
3 | office | 2609 | /* Disable card detection */ |
2610 | sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); |
||
1 | office | 2611 | |
3 | office | 2612 | /* Disable and clear all interrupts */ |
2613 | sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN)); |
||
2614 | sdr_write32(MSDC_INT, sdr_read32(MSDC_INT)); |
||
2615 | |||
1 | office | 2616 | #if 1 |
2617 | /* reset tuning parameter */ |
||
3 | office | 2618 | sdr_write32(MSDC_PAD_CTL0, 0x00090000); |
2619 | sdr_write32(MSDC_PAD_CTL1, 0x000A0000); |
||
2620 | sdr_write32(MSDC_PAD_CTL2, 0x000A0000); |
||
2621 | // sdr_write32(MSDC_PAD_TUNE, 0x00000000); |
||
2622 | sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward |
||
2623 | // sdr_write32(MSDC_DAT_RDDLY0, 0x00000000); |
||
2624 | sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward |
||
2625 | sdr_write32(MSDC_DAT_RDDLY1, 0x00000000); |
||
2626 | sdr_write32(MSDC_IOCON, 0x00000000); |
||
1 | office | 2627 | #if 0 // use MT7620 default value: 0x403c004f |
3 | office | 2628 | sdr_write32(MSDC_PATCH_BIT0, 0x003C000F); /* bit0 modified: Rx Data Clock Source: 1 -> 2.0*/ |
1 | office | 2629 | #endif |
2630 | |||
3 | office | 2631 | if (sdr_read32(MSDC_ECO_VER) >= 4) { |
2632 | if (host->id == 1) { |
||
2633 | sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_WRDAT_CRCS, 1); |
||
2634 | sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMD_RSP, 1); |
||
2635 | |||
2636 | /* internal clock: latch read data */ |
||
2637 | sdr_set_bits(MSDC_PATCH_BIT0, MSDC_PATCH_BIT_CKGEN_CK); |
||
2638 | } |
||
2639 | } |
||
2640 | #endif |
||
1 | office | 2641 | |
3 | office | 2642 | /* for safety, should clear SDC_CFG.SDIO_INT_DET_EN & set SDC_CFG.SDIO in |
2643 | pre-loader,uboot,kernel drivers. and SDC_CFG.SDIO_INT_DET_EN will be only |
||
2644 | set when kernel driver wants to use SDIO bus interrupt */ |
||
2645 | /* Configure to enable SDIO mode. it's must otherwise sdio cmd5 failed */ |
||
2646 | sdr_set_bits(SDC_CFG, SDC_CFG_SDIO); |
||
1 | office | 2647 | |
3 | office | 2648 | /* disable detect SDIO device interupt function */ |
2649 | sdr_clr_bits(SDC_CFG, SDC_CFG_SDIOIDE); |
||
1 | office | 2650 | |
3 | office | 2651 | /* eneable SMT for glitch filter */ |
2652 | sdr_set_bits(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKSMT); |
||
2653 | sdr_set_bits(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDSMT); |
||
2654 | sdr_set_bits(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATSMT); |
||
1 | office | 2655 | |
2656 | #if 1 |
||
3 | office | 2657 | /* set clk, cmd, dat pad driving */ |
2658 | sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, hw->clk_drv); |
||
2659 | sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, hw->clk_drv); |
||
2660 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, hw->cmd_drv); |
||
2661 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, hw->cmd_drv); |
||
2662 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, hw->dat_drv); |
||
2663 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, hw->dat_drv); |
||
2664 | #else |
||
2665 | sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, 0); |
||
2666 | sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, 0); |
||
2667 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, 0); |
||
2668 | sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, 0); |
||
2669 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, 0); |
||
2670 | sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, 0); |
||
1 | office | 2671 | #endif |
2672 | |||
3 | office | 2673 | /* set sampling edge */ |
1 | office | 2674 | |
3 | office | 2675 | /* write crc timeout detection */ |
2676 | sdr_set_field(MSDC_PATCH_BIT0, 1 << 30, 1); |
||
1 | office | 2677 | |
3 | office | 2678 | /* Configure to default data timeout */ |
2679 | sdr_set_field(SDC_CFG, SDC_CFG_DTOC, DEFAULT_DTOC); |
||
1 | office | 2680 | |
3 | office | 2681 | msdc_set_buswidth(host, MMC_BUS_WIDTH_1); |
1 | office | 2682 | |
3 | office | 2683 | N_MSG(FUC, "init hardware done!"); |
1 | office | 2684 | } |
2685 | |||
2686 | /* called by msdc_drv_remove */ |
||
2687 | static void msdc_deinit_hw(struct msdc_host *host) |
||
2688 | { |
||
3 | office | 2689 | u32 base = host->base; |
1 | office | 2690 | |
3 | office | 2691 | /* Disable and clear all interrupts */ |
2692 | sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN)); |
||
2693 | sdr_write32(MSDC_INT, sdr_read32(MSDC_INT)); |
||
1 | office | 2694 | |
3 | office | 2695 | /* Disable card detection */ |
2696 | msdc_enable_cd_irq(host, 0); |
||
2697 | // msdc_set_power_mode(host, MMC_POWER_OFF); /* make sure power down */ /* --- by chhung */ |
||
1 | office | 2698 | } |
2699 | |||
2700 | /* init gpd and bd list in msdc_drv_probe */ |
||
2701 | static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma) |
||
2702 | { |
||
3 | office | 2703 | gpd_t *gpd = dma->gpd; |
2704 | bd_t *bd = dma->bd; |
||
2705 | bd_t *ptr, *prev; |
||
2706 | |||
2707 | /* we just support one gpd */ |
||
2708 | int bdlen = MAX_BD_PER_GPD; |
||
1 | office | 2709 | |
3 | office | 2710 | /* init the 2 gpd */ |
2711 | memset(gpd, 0, sizeof(gpd_t) * 2); |
||
2712 | //gpd->next = (void *)virt_to_phys(gpd + 1); /* pointer to a null gpd, bug! kmalloc <-> virt_to_phys */ |
||
2713 | //gpd->next = (dma->gpd_addr + 1); /* bug */ |
||
2714 | gpd->next = (void *)((u32)dma->gpd_addr + sizeof(gpd_t)); |
||
1 | office | 2715 | |
3 | office | 2716 | //gpd->intr = 0; |
2717 | gpd->bdp = 1; /* hwo, cs, bd pointer */ |
||
2718 | //gpd->ptr = (void*)virt_to_phys(bd); |
||
2719 | gpd->ptr = (void *)dma->bd_addr; /* physical address */ |
||
2720 | |||
2721 | memset(bd, 0, sizeof(bd_t) * bdlen); |
||
2722 | ptr = bd + bdlen - 1; |
||
2723 | //ptr->eol = 1; /* 0 or 1 [Fix me]*/ |
||
2724 | //ptr->next = 0; |
||
2725 | |||
2726 | while (ptr != bd) { |
||
2727 | prev = ptr - 1; |
||
2728 | prev->next = (void *)(dma->bd_addr + sizeof(bd_t) *(ptr - bd)); |
||
2729 | ptr = prev; |
||
2730 | } |
||
1 | office | 2731 | } |
2732 | |||
2733 | static int msdc_drv_probe(struct platform_device *pdev) |
||
2734 | { |
||
3 | office | 2735 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
2736 | __iomem void *base; |
||
2737 | struct mmc_host *mmc; |
||
2738 | struct resource *mem; |
||
2739 | struct msdc_host *host; |
||
2740 | struct msdc_hw *hw; |
||
2741 | int ret, irq; |
||
1 | office | 2742 | u32 reg; |
2743 | |||
3 | office | 2744 | printk("MTK MSDC device init.\n"); |
2745 | mtk_sd_device.dev.platform_data = &msdc0_hw; |
||
2746 | if (ralink_soc == MT762X_SOC_MT7620A || ralink_soc == MT762X_SOC_MT7621AT) { |
||
2747 | //#if defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) |
||
2748 | reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60)) & ~(0x3<<18); |
||
2749 | //#if defined (CONFIG_RALINK_MT7620) |
||
2750 | if (ralink_soc == MT762X_SOC_MT7620A) |
||
2751 | reg |= 0x1<<18; |
||
2752 | //#endif |
||
2753 | } else { |
||
2754 | //#elif defined (CONFIG_RALINK_MT7628) |
||
2755 | /* TODO: maybe omitted when RAether already toggle AGPIO_CFG */ |
||
2756 | reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x3c)); |
||
1 | office | 2757 | reg |= 0x1e << 16; |
3 | office | 2758 | sdr_write32((volatile u32*)(RALINK_SYSCTL_BASE + 0x3c), reg); |
1 | office | 2759 | |
3 | office | 2760 | reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60)) & ~(0x3<<10); |
2761 | #if defined (CONFIG_MTK_MMC_EMMC_8BIT) |
||
2762 | reg |= 0x3<<26 | 0x3<<28 | 0x3<<30; |
||
2763 | msdc0_hw.data_pins = 8, |
||
2764 | #endif |
||
2765 | //#endif |
||
1 | office | 2766 | } |
3 | office | 2767 | sdr_write32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60), reg); |
2768 | //platform_device_register(&mtk_sd_device); |
||
2769 | /* end of +++ */ |
||
2770 | |||
2771 | pdev->dev.platform_data = &msdc0_hw; |
||
2772 | |||
2773 | if (of_property_read_bool(pdev->dev.of_node, "mtk,wp-en")) |
||
2774 | msdc0_hw.flags |= MSDC_WP_PIN_EN; |
||
2775 | |||
2776 | /* Allocate MMC host for this device */ |
||
2777 | mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); |
||
2778 | if (!mmc) return -ENOMEM; |
||
1 | office | 2779 | |
3 | office | 2780 | hw = (struct msdc_hw*)pdev->dev.platform_data; |
2781 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
2782 | irq = platform_get_irq(pdev, 0); |
||
1 | office | 2783 | |
3 | office | 2784 | //BUG_ON((!hw) || (!mem) || (irq < 0)); /* --- by chhung */ |
2785 | |||
2786 | base = devm_ioremap_resource(&pdev->dev, res); |
||
2787 | if (IS_ERR(base)) |
||
2788 | return PTR_ERR(base); |
||
1 | office | 2789 | |
3 | office | 2790 | /* Set host parameters to mmc */ |
2791 | mmc->ops = &mt_msdc_ops; |
||
2792 | mmc->f_min = HOST_MIN_MCLK; |
||
2793 | mmc->f_max = HOST_MAX_MCLK; |
||
2794 | mmc->ocr_avail = MSDC_OCR_AVAIL; |
||
2795 | |||
2796 | /* For sd card: MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED, |
||
2797 | For sdio : MSDC_EXT_SDIO_IRQ | MSDC_HIGHSPEED */ |
||
2798 | if (hw->flags & MSDC_HIGHSPEED) { |
||
2799 | mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; |
||
2800 | } |
||
2801 | if (hw->data_pins == 4) { /* current data_pins are all 4*/ |
||
2802 | mmc->caps |= MMC_CAP_4_BIT_DATA; |
||
2803 | } else if (hw->data_pins == 8) { |
||
2804 | mmc->caps |= MMC_CAP_8_BIT_DATA; |
||
2805 | } |
||
2806 | if ((hw->flags & MSDC_SDIO_IRQ) || (hw->flags & MSDC_EXT_SDIO_IRQ)) |
||
2807 | mmc->caps |= MMC_CAP_SDIO_IRQ; /* yes for sdio */ |
||
1 | office | 2808 | |
3 | office | 2809 | cd_active_low = !of_property_read_bool(pdev->dev.of_node, "mediatek,cd-high"); |
2810 | mtk_sw_poll = of_property_read_bool(pdev->dev.of_node, "mediatek,cd-poll"); |
||
1 | office | 2811 | |
3 | office | 2812 | if (mtk_sw_poll) |
2813 | mmc->caps |= MMC_CAP_NEEDS_POLL; |
||
1 | office | 2814 | |
3 | office | 2815 | /* MMC core transfer sizes tunable parameters */ |
2816 | #if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) |
||
2817 | mmc->max_segs = MAX_HW_SGMTS; |
||
2818 | #else |
||
2819 | mmc->max_hw_segs = MAX_HW_SGMTS; |
||
2820 | mmc->max_phys_segs = MAX_PHY_SGMTS; |
||
2821 | #endif |
||
2822 | mmc->max_seg_size = MAX_SGMT_SZ; |
||
2823 | mmc->max_blk_size = HOST_MAX_BLKSZ; |
||
2824 | mmc->max_req_size = MAX_REQ_SZ; |
||
2825 | mmc->max_blk_count = mmc->max_req_size; |
||
1 | office | 2826 | |
3 | office | 2827 | host = mmc_priv(mmc); |
2828 | host->hw = hw; |
||
2829 | host->mmc = mmc; |
||
2830 | host->id = 0; |
||
2831 | host->error = 0; |
||
2832 | host->irq = irq; |
||
2833 | host->base = (unsigned long) base; |
||
2834 | host->mclk = 0; /* mclk: the request clock of mmc sub-system */ |
||
2835 | host->hclk = hclks[hw->clk_src]; /* hclk: clock of clock source to msdc controller */ |
||
2836 | host->sclk = 0; /* sclk: the really clock after divition */ |
||
2837 | host->pm_state = PMSG_RESUME; |
||
2838 | host->suspend = 0; |
||
2839 | host->core_clkon = 0; |
||
2840 | host->card_clkon = 0; |
||
2841 | host->core_power = 0; |
||
2842 | host->power_mode = MMC_POWER_OFF; |
||
2843 | // host->card_inserted = hw->flags & MSDC_REMOVABLE ? 0 : 1; |
||
2844 | host->timeout_ns = 0; |
||
2845 | host->timeout_clks = DEFAULT_DTOC * 65536; |
||
2846 | |||
2847 | host->mrq = NULL; |
||
2848 | //init_MUTEX(&host->sem); /* we don't need to support multiple threads access */ |
||
2849 | |||
2850 | host->dma.used_gpd = 0; |
||
2851 | host->dma.used_bd = 0; |
||
2852 | mmc_dev(mmc)->dma_mask = NULL; |
||
1 | office | 2853 | |
3 | office | 2854 | /* using dma_alloc_coherent*/ /* todo: using 1, for all 4 slots */ |
2855 | host->dma.gpd = dma_alloc_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), &host->dma.gpd_addr, GFP_KERNEL); |
||
2856 | host->dma.bd = dma_alloc_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), &host->dma.bd_addr, GFP_KERNEL); |
||
2857 | BUG_ON((!host->dma.gpd) || (!host->dma.bd)); |
||
2858 | msdc_init_gpd_bd(host, &host->dma); |
||
2859 | |||
2860 | #if 0 |
||
2861 | tasklet_init(&host->card_tasklet, msdc_tasklet_card, (ulong)host); |
||
2862 | #else |
||
2863 | INIT_DELAYED_WORK(&host->card_delaywork, msdc_tasklet_card); |
||
2864 | #endif |
||
2865 | spin_lock_init(&host->lock); |
||
2866 | msdc_init_hw(host); |
||
1 | office | 2867 | |
3 | office | 2868 | if (ralink_soc == MT762X_SOC_MT7621AT) |
2869 | ret = request_irq((unsigned int)irq, msdc_irq, 0, dev_name(&pdev->dev), host); |
||
2870 | else |
||
2871 | ret = request_irq((unsigned int)irq, msdc_irq, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), host); |
||
1 | office | 2872 | |
3 | office | 2873 | if (ret) goto release; |
2874 | // mt65xx_irq_unmask(irq); /* --- by chhung */ |
||
2875 | |||
2876 | if (hw->flags & MSDC_CD_PIN_EN) { /* not set for sdio */ |
||
2877 | if (hw->request_cd_eirq) { /* not set for MT6575 */ |
||
2878 | hw->request_cd_eirq(msdc_eirq_cd, (void*)host); /* msdc_eirq_cd will not be used! */ |
||
2879 | } |
||
2880 | } |
||
1 | office | 2881 | |
3 | office | 2882 | if (hw->request_sdio_eirq) /* set to combo_sdio_request_eirq() for WIFI */ |
2883 | hw->request_sdio_eirq(msdc_eirq_sdio, (void*)host); /* msdc_eirq_sdio() will be called when EIRQ */ |
||
1 | office | 2884 | |
3 | office | 2885 | if (hw->register_pm) {/* yes for sdio */ |
2886 | #ifdef CONFIG_PM |
||
2887 | hw->register_pm(msdc_pm, (void*)host); /* combo_sdio_register_pm() */ |
||
2888 | #endif |
||
2889 | if(hw->flags & MSDC_SYS_SUSPEND) { /* will not set for WIFI */ |
||
2890 | ERR_MSG("MSDC_SYS_SUSPEND and register_pm both set"); |
||
2891 | } |
||
2892 | //mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* pm not controlled by system but by client. */ /* --- by chhung */ |
||
2893 | } |
||
2894 | |||
2895 | platform_set_drvdata(pdev, mmc); |
||
1 | office | 2896 | |
3 | office | 2897 | ret = mmc_add_host(mmc); |
2898 | if (ret) goto free_irq; |
||
1 | office | 2899 | |
3 | office | 2900 | /* Config card detection pin and enable interrupts */ |
2901 | if (hw->flags & MSDC_CD_PIN_EN) { /* set for card */ |
||
2902 | msdc_enable_cd_irq(host, 1); |
||
2903 | } else { |
||
2904 | msdc_enable_cd_irq(host, 0); |
||
2905 | } |
||
1 | office | 2906 | |
3 | office | 2907 | return 0; |
1 | office | 2908 | |
3 | office | 2909 | free_irq: |
2910 | free_irq(irq, host); |
||
2911 | release: |
||
2912 | platform_set_drvdata(pdev, NULL); |
||
2913 | msdc_deinit_hw(host); |
||
1 | office | 2914 | |
3 | office | 2915 | #if 0 |
2916 | tasklet_kill(&host->card_tasklet); |
||
2917 | #else |
||
2918 | cancel_delayed_work_sync(&host->card_delaywork); |
||
2919 | #endif |
||
1 | office | 2920 | |
3 | office | 2921 | if (mem) |
2922 | release_mem_region(mem->start, mem->end - mem->start + 1); |
||
1 | office | 2923 | |
3 | office | 2924 | mmc_free_host(mmc); |
1 | office | 2925 | |
3 | office | 2926 | return ret; |
1 | office | 2927 | } |
2928 | |||
2929 | /* 4 device share one driver, using "drvdata" to show difference */ |
||
2930 | static int msdc_drv_remove(struct platform_device *pdev) |
||
2931 | { |
||
3 | office | 2932 | struct mmc_host *mmc; |
2933 | struct msdc_host *host; |
||
2934 | struct resource *mem; |
||
1 | office | 2935 | |
3 | office | 2936 | mmc = platform_get_drvdata(pdev); |
2937 | BUG_ON(!mmc); |
||
2938 | |||
2939 | host = mmc_priv(mmc); |
||
2940 | BUG_ON(!host); |
||
1 | office | 2941 | |
3 | office | 2942 | ERR_MSG("removed !!!"); |
1 | office | 2943 | |
3 | office | 2944 | platform_set_drvdata(pdev, NULL); |
2945 | mmc_remove_host(host->mmc); |
||
2946 | msdc_deinit_hw(host); |
||
1 | office | 2947 | |
3 | office | 2948 | #if 0 |
2949 | tasklet_kill(&host->card_tasklet); |
||
2950 | #else |
||
2951 | cancel_delayed_work_sync(&host->card_delaywork); |
||
2952 | #endif |
||
2953 | free_irq(host->irq, host); |
||
1 | office | 2954 | |
3 | office | 2955 | dma_free_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), host->dma.gpd, host->dma.gpd_addr); |
2956 | dma_free_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), host->dma.bd, host->dma.bd_addr); |
||
1 | office | 2957 | |
3 | office | 2958 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1 | office | 2959 | |
3 | office | 2960 | if (mem) |
2961 | release_mem_region(mem->start, mem->end - mem->start + 1); |
||
1 | office | 2962 | |
3 | office | 2963 | mmc_free_host(host->mmc); |
2964 | |||
2965 | return 0; |
||
1 | office | 2966 | } |
2967 | |||
2968 | /* Fix me: Power Flow */ |
||
2969 | #ifdef CONFIG_PM |
||
3 | office | 2970 | static int msdc_drv_suspend(struct platform_device *pdev, pm_message_t state) |
1 | office | 2971 | { |
3 | office | 2972 | int ret = 0; |
2973 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
||
2974 | struct msdc_host *host = mmc_priv(mmc); |
||
1 | office | 2975 | |
3 | office | 2976 | if (mmc && state.event == PM_EVENT_SUSPEND && (host->hw->flags & MSDC_SYS_SUSPEND)) { /* will set for card */ |
2977 | msdc_pm(state, (void*)host); |
||
2978 | } |
||
2979 | |||
2980 | return ret; |
||
1 | office | 2981 | } |
2982 | |||
2983 | static int msdc_drv_resume(struct platform_device *pdev) |
||
2984 | { |
||
3 | office | 2985 | int ret = 0; |
2986 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
||
2987 | struct msdc_host *host = mmc_priv(mmc); |
||
2988 | struct pm_message state; |
||
1 | office | 2989 | |
3 | office | 2990 | state.event = PM_EVENT_RESUME; |
2991 | if (mmc && (host->hw->flags & MSDC_SYS_SUSPEND)) {/* will set for card */ |
||
2992 | msdc_pm(state, (void*)host); |
||
2993 | } |
||
2994 | |||
2995 | /* This mean WIFI not controller by PM */ |
||
2996 | |||
2997 | return ret; |
||
1 | office | 2998 | } |
2999 | #endif |
||
3000 | |||
3001 | static const struct of_device_id mt7620_sdhci_match[] = { |
||
3002 | { .compatible = "ralink,mt7620-sdhci" }, |
||
3003 | {}, |
||
3004 | }; |
||
3005 | MODULE_DEVICE_TABLE(of, mt7620_sdhci_match); |
||
3006 | |||
3007 | static struct platform_driver mt_msdc_driver = { |
||
3 | office | 3008 | .probe = msdc_drv_probe, |
3009 | .remove = msdc_drv_remove, |
||
1 | office | 3010 | #ifdef CONFIG_PM |
3 | office | 3011 | .suspend = msdc_drv_suspend, |
3012 | .resume = msdc_drv_resume, |
||
1 | office | 3013 | #endif |
3 | office | 3014 | .driver = { |
3015 | .name = DRV_NAME, |
||
3016 | .of_match_table = mt7620_sdhci_match, |
||
3017 | }, |
||
1 | office | 3018 | }; |
3019 | |||
3020 | /*--------------------------------------------------------------------------*/ |
||
3021 | /* module init/exit */ |
||
3022 | /*--------------------------------------------------------------------------*/ |
||
3023 | static int __init mt_msdc_init(void) |
||
3024 | { |
||
3 | office | 3025 | int ret; |
1 | office | 3026 | |
3 | office | 3027 | ret = platform_driver_register(&mt_msdc_driver); |
3028 | if (ret) { |
||
3029 | printk(KERN_ERR DRV_NAME ": Can't register driver"); |
||
3030 | return ret; |
||
3031 | } |
||
3032 | printk(KERN_INFO DRV_NAME ": MediaTek MT6575 MSDC Driver\n"); |
||
1 | office | 3033 | |
3 | office | 3034 | #if defined (MT6575_SD_DEBUG) |
3035 | msdc_debug_proc_init(); |
||
1 | office | 3036 | #endif |
3 | office | 3037 | return 0; |
1 | office | 3038 | } |
3039 | |||
3040 | static void __exit mt_msdc_exit(void) |
||
3041 | { |
||
3 | office | 3042 | // platform_device_unregister(&mtk_sd_device); |
3043 | platform_driver_unregister(&mt_msdc_driver); |
||
1 | office | 3044 | } |
3045 | |||
3046 | module_init(mt_msdc_init); |
||
3047 | module_exit(mt_msdc_exit); |
||
3048 | MODULE_LICENSE("GPL"); |