diff options
Diffstat (limited to 'drivers/mmc/host/rtsx_pci_sdmmc.c')
-rw-r--r-- | drivers/mmc/host/rtsx_pci_sdmmc.c | 529 |
1 files changed, 382 insertions, 147 deletions
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index c46feda07d56..5fb994f9a653 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c | |||
@@ -31,14 +31,9 @@ | |||
31 | #include <linux/mfd/rtsx_pci.h> | 31 | #include <linux/mfd/rtsx_pci.h> |
32 | #include <asm/unaligned.h> | 32 | #include <asm/unaligned.h> |
33 | 33 | ||
34 | /* SD Tuning Data Structure | 34 | struct realtek_next { |
35 | * Record continuous timing phase path | 35 | unsigned int sg_count; |
36 | */ | 36 | s32 cookie; |
37 | struct timing_phase_path { | ||
38 | int start; | ||
39 | int end; | ||
40 | int mid; | ||
41 | int len; | ||
42 | }; | 37 | }; |
43 | 38 | ||
44 | struct realtek_pci_sdmmc { | 39 | struct realtek_pci_sdmmc { |
@@ -46,9 +41,18 @@ struct realtek_pci_sdmmc { | |||
46 | struct rtsx_pcr *pcr; | 41 | struct rtsx_pcr *pcr; |
47 | struct mmc_host *mmc; | 42 | struct mmc_host *mmc; |
48 | struct mmc_request *mrq; | 43 | struct mmc_request *mrq; |
49 | 44 | struct mmc_command *cmd; | |
50 | struct mutex host_mutex; | 45 | struct mmc_data *data; |
51 | 46 | ||
47 | spinlock_t lock; | ||
48 | struct timer_list timer; | ||
49 | struct tasklet_struct cmd_tasklet; | ||
50 | struct tasklet_struct data_tasklet; | ||
51 | struct tasklet_struct finish_tasklet; | ||
52 | |||
53 | u8 rsp_type; | ||
54 | u8 rsp_len; | ||
55 | int sg_count; | ||
52 | u8 ssc_depth; | 56 | u8 ssc_depth; |
53 | unsigned int clock; | 57 | unsigned int clock; |
54 | bool vpclk; | 58 | bool vpclk; |
@@ -58,8 +62,13 @@ struct realtek_pci_sdmmc { | |||
58 | int power_state; | 62 | int power_state; |
59 | #define SDMMC_POWER_ON 1 | 63 | #define SDMMC_POWER_ON 1 |
60 | #define SDMMC_POWER_OFF 0 | 64 | #define SDMMC_POWER_OFF 0 |
65 | |||
66 | struct realtek_next next_data; | ||
61 | }; | 67 | }; |
62 | 68 | ||
69 | static int sd_start_multi_rw(struct realtek_pci_sdmmc *host, | ||
70 | struct mmc_request *mrq); | ||
71 | |||
63 | static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) | 72 | static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) |
64 | { | 73 | { |
65 | return &(host->pdev->dev); | 74 | return &(host->pdev->dev); |
@@ -96,6 +105,95 @@ static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) | |||
96 | #define sd_print_debug_regs(host) | 105 | #define sd_print_debug_regs(host) |
97 | #endif /* DEBUG */ | 106 | #endif /* DEBUG */ |
98 | 107 | ||
108 | static void sd_isr_done_transfer(struct platform_device *pdev) | ||
109 | { | ||
110 | struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); | ||
111 | |||
112 | spin_lock(&host->lock); | ||
113 | if (host->cmd) | ||
114 | tasklet_schedule(&host->cmd_tasklet); | ||
115 | if (host->data) | ||
116 | tasklet_schedule(&host->data_tasklet); | ||
117 | spin_unlock(&host->lock); | ||
118 | } | ||
119 | |||
120 | static void sd_request_timeout(unsigned long host_addr) | ||
121 | { | ||
122 | struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr; | ||
123 | unsigned long flags; | ||
124 | |||
125 | spin_lock_irqsave(&host->lock, flags); | ||
126 | |||
127 | if (!host->mrq) { | ||
128 | dev_err(sdmmc_dev(host), "error: no request exist\n"); | ||
129 | goto out; | ||
130 | } | ||
131 | |||
132 | if (host->cmd) | ||
133 | host->cmd->error = -ETIMEDOUT; | ||
134 | if (host->data) | ||
135 | host->data->error = -ETIMEDOUT; | ||
136 | |||
137 | dev_dbg(sdmmc_dev(host), "timeout for request\n"); | ||
138 | |||
139 | out: | ||
140 | tasklet_schedule(&host->finish_tasklet); | ||
141 | spin_unlock_irqrestore(&host->lock, flags); | ||
142 | } | ||
143 | |||
144 | static void sd_finish_request(unsigned long host_addr) | ||
145 | { | ||
146 | struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr; | ||
147 | struct rtsx_pcr *pcr = host->pcr; | ||
148 | struct mmc_request *mrq; | ||
149 | struct mmc_command *cmd; | ||
150 | struct mmc_data *data; | ||
151 | unsigned long flags; | ||
152 | bool any_error; | ||
153 | |||
154 | spin_lock_irqsave(&host->lock, flags); | ||
155 | |||
156 | del_timer(&host->timer); | ||
157 | mrq = host->mrq; | ||
158 | if (!mrq) { | ||
159 | dev_err(sdmmc_dev(host), "error: no request need finish\n"); | ||
160 | goto out; | ||
161 | } | ||
162 | |||
163 | cmd = mrq->cmd; | ||
164 | data = mrq->data; | ||
165 | |||
166 | any_error = (mrq->sbc && mrq->sbc->error) || | ||
167 | (mrq->stop && mrq->stop->error) || | ||
168 | (cmd && cmd->error) || (data && data->error); | ||
169 | |||
170 | if (any_error) { | ||
171 | rtsx_pci_stop_cmd(pcr); | ||
172 | sd_clear_error(host); | ||
173 | } | ||
174 | |||
175 | if (data) { | ||
176 | if (any_error) | ||
177 | data->bytes_xfered = 0; | ||
178 | else | ||
179 | data->bytes_xfered = data->blocks * data->blksz; | ||
180 | |||
181 | if (!data->host_cookie) | ||
182 | rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, | ||
183 | data->flags & MMC_DATA_READ); | ||
184 | |||
185 | } | ||
186 | |||
187 | host->mrq = NULL; | ||
188 | host->cmd = NULL; | ||
189 | host->data = NULL; | ||
190 | |||
191 | out: | ||
192 | spin_unlock_irqrestore(&host->lock, flags); | ||
193 | mutex_unlock(&pcr->pcr_mutex); | ||
194 | mmc_request_done(host->mmc, mrq); | ||
195 | } | ||
196 | |||
99 | static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, | 197 | static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, |
100 | u8 *buf, int buf_len, int timeout) | 198 | u8 *buf, int buf_len, int timeout) |
101 | { | 199 | { |
@@ -213,8 +311,7 @@ static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, | |||
213 | return 0; | 311 | return 0; |
214 | } | 312 | } |
215 | 313 | ||
216 | static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, | 314 | static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd) |
217 | struct mmc_command *cmd) | ||
218 | { | 315 | { |
219 | struct rtsx_pcr *pcr = host->pcr; | 316 | struct rtsx_pcr *pcr = host->pcr; |
220 | u8 cmd_idx = (u8)cmd->opcode; | 317 | u8 cmd_idx = (u8)cmd->opcode; |
@@ -222,11 +319,14 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, | |||
222 | int err = 0; | 319 | int err = 0; |
223 | int timeout = 100; | 320 | int timeout = 100; |
224 | int i; | 321 | int i; |
225 | u8 *ptr; | ||
226 | int stat_idx = 0; | ||
227 | u8 rsp_type; | 322 | u8 rsp_type; |
228 | int rsp_len = 5; | 323 | int rsp_len = 5; |
229 | bool clock_toggled = false; | 324 | unsigned long flags; |
325 | |||
326 | if (host->cmd) | ||
327 | dev_err(sdmmc_dev(host), "error: cmd already exist\n"); | ||
328 | |||
329 | host->cmd = cmd; | ||
230 | 330 | ||
231 | dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", | 331 | dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", |
232 | __func__, cmd_idx, arg); | 332 | __func__, cmd_idx, arg); |
@@ -261,6 +361,8 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, | |||
261 | err = -EINVAL; | 361 | err = -EINVAL; |
262 | goto out; | 362 | goto out; |
263 | } | 363 | } |
364 | host->rsp_type = rsp_type; | ||
365 | host->rsp_len = rsp_len; | ||
264 | 366 | ||
265 | if (rsp_type == SD_RSP_TYPE_R1b) | 367 | if (rsp_type == SD_RSP_TYPE_R1b) |
266 | timeout = 3000; | 368 | timeout = 3000; |
@@ -270,8 +372,6 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, | |||
270 | 0xFF, SD_CLK_TOGGLE_EN); | 372 | 0xFF, SD_CLK_TOGGLE_EN); |
271 | if (err < 0) | 373 | if (err < 0) |
272 | goto out; | 374 | goto out; |
273 | |||
274 | clock_toggled = true; | ||
275 | } | 375 | } |
276 | 376 | ||
277 | rtsx_pci_init_cmd(pcr); | 377 | rtsx_pci_init_cmd(pcr); |
@@ -295,25 +395,60 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, | |||
295 | /* Read data from ping-pong buffer */ | 395 | /* Read data from ping-pong buffer */ |
296 | for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) | 396 | for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) |
297 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); | 397 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); |
298 | stat_idx = 16; | ||
299 | } else if (rsp_type != SD_RSP_TYPE_R0) { | 398 | } else if (rsp_type != SD_RSP_TYPE_R0) { |
300 | /* Read data from SD_CMDx registers */ | 399 | /* Read data from SD_CMDx registers */ |
301 | for (i = SD_CMD0; i <= SD_CMD4; i++) | 400 | for (i = SD_CMD0; i <= SD_CMD4; i++) |
302 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); | 401 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); |
303 | stat_idx = 5; | ||
304 | } | 402 | } |
305 | 403 | ||
306 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); | 404 | rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); |
307 | 405 | ||
308 | err = rtsx_pci_send_cmd(pcr, timeout); | 406 | mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout)); |
309 | if (err < 0) { | 407 | |
310 | sd_print_debug_regs(host); | 408 | spin_lock_irqsave(&pcr->lock, flags); |
311 | sd_clear_error(host); | 409 | pcr->trans_result = TRANS_NOT_READY; |
312 | dev_dbg(sdmmc_dev(host), | 410 | rtsx_pci_send_cmd_no_wait(pcr); |
313 | "rtsx_pci_send_cmd error (err = %d)\n", err); | 411 | spin_unlock_irqrestore(&pcr->lock, flags); |
412 | |||
413 | return; | ||
414 | |||
415 | out: | ||
416 | cmd->error = err; | ||
417 | tasklet_schedule(&host->finish_tasklet); | ||
418 | } | ||
419 | |||
420 | static void sd_get_rsp(unsigned long host_addr) | ||
421 | { | ||
422 | struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr; | ||
423 | struct rtsx_pcr *pcr = host->pcr; | ||
424 | struct mmc_command *cmd; | ||
425 | int i, err = 0, stat_idx; | ||
426 | u8 *ptr, rsp_type; | ||
427 | unsigned long flags; | ||
428 | |||
429 | spin_lock_irqsave(&host->lock, flags); | ||
430 | |||
431 | cmd = host->cmd; | ||
432 | host->cmd = NULL; | ||
433 | |||
434 | if (!cmd) { | ||
435 | dev_err(sdmmc_dev(host), "error: cmd not exist\n"); | ||
314 | goto out; | 436 | goto out; |
315 | } | 437 | } |
316 | 438 | ||
439 | spin_lock(&pcr->lock); | ||
440 | if (pcr->trans_result == TRANS_NO_DEVICE) | ||
441 | err = -ENODEV; | ||
442 | else if (pcr->trans_result != TRANS_RESULT_OK) | ||
443 | err = -EINVAL; | ||
444 | spin_unlock(&pcr->lock); | ||
445 | |||
446 | if (err < 0) | ||
447 | goto out; | ||
448 | |||
449 | rsp_type = host->rsp_type; | ||
450 | stat_idx = host->rsp_len; | ||
451 | |||
317 | if (rsp_type == SD_RSP_TYPE_R0) { | 452 | if (rsp_type == SD_RSP_TYPE_R0) { |
318 | err = 0; | 453 | err = 0; |
319 | goto out; | 454 | goto out; |
@@ -350,26 +485,106 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, | |||
350 | cmd->resp[0]); | 485 | cmd->resp[0]); |
351 | } | 486 | } |
352 | 487 | ||
488 | if (cmd == host->mrq->sbc) { | ||
489 | sd_send_cmd(host, host->mrq->cmd); | ||
490 | spin_unlock_irqrestore(&host->lock, flags); | ||
491 | return; | ||
492 | } | ||
493 | |||
494 | if (cmd == host->mrq->stop) | ||
495 | goto out; | ||
496 | |||
497 | if (cmd->data) { | ||
498 | sd_start_multi_rw(host, host->mrq); | ||
499 | spin_unlock_irqrestore(&host->lock, flags); | ||
500 | return; | ||
501 | } | ||
502 | |||
353 | out: | 503 | out: |
354 | cmd->error = err; | 504 | cmd->error = err; |
355 | 505 | ||
356 | if (err && clock_toggled) | 506 | tasklet_schedule(&host->finish_tasklet); |
357 | rtsx_pci_write_register(pcr, SD_BUS_STAT, | 507 | spin_unlock_irqrestore(&host->lock, flags); |
358 | SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); | ||
359 | } | 508 | } |
360 | 509 | ||
361 | static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) | 510 | static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host, |
511 | struct mmc_data *data, struct realtek_next *next) | ||
512 | { | ||
513 | struct rtsx_pcr *pcr = host->pcr; | ||
514 | int read = data->flags & MMC_DATA_READ; | ||
515 | int sg_count = 0; | ||
516 | |||
517 | if (!next && data->host_cookie && | ||
518 | data->host_cookie != host->next_data.cookie) { | ||
519 | dev_err(sdmmc_dev(host), | ||
520 | "error: invalid cookie data[%d] host[%d]\n", | ||
521 | data->host_cookie, host->next_data.cookie); | ||
522 | data->host_cookie = 0; | ||
523 | } | ||
524 | |||
525 | if (next || (!next && data->host_cookie != host->next_data.cookie)) | ||
526 | sg_count = rtsx_pci_dma_map_sg(pcr, | ||
527 | data->sg, data->sg_len, read); | ||
528 | else | ||
529 | sg_count = host->next_data.sg_count; | ||
530 | |||
531 | if (next) { | ||
532 | next->sg_count = sg_count; | ||
533 | if (++next->cookie < 0) | ||
534 | next->cookie = 1; | ||
535 | data->host_cookie = next->cookie; | ||
536 | } | ||
537 | |||
538 | return sg_count; | ||
539 | } | ||
540 | |||
541 | static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, | ||
542 | bool is_first_req) | ||
543 | { | ||
544 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
545 | struct mmc_data *data = mrq->data; | ||
546 | |||
547 | if (data->host_cookie) { | ||
548 | dev_err(sdmmc_dev(host), | ||
549 | "error: descard already cookie data[%d]\n", | ||
550 | data->host_cookie); | ||
551 | data->host_cookie = 0; | ||
552 | } | ||
553 | |||
554 | dev_dbg(sdmmc_dev(host), "dma sg prepared: %d\n", | ||
555 | sd_pre_dma_transfer(host, data, &host->next_data)); | ||
556 | } | ||
557 | |||
558 | static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, | ||
559 | int err) | ||
560 | { | ||
561 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | ||
562 | struct rtsx_pcr *pcr = host->pcr; | ||
563 | struct mmc_data *data = mrq->data; | ||
564 | int read = data->flags & MMC_DATA_READ; | ||
565 | |||
566 | rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, read); | ||
567 | data->host_cookie = 0; | ||
568 | } | ||
569 | |||
570 | static int sd_start_multi_rw(struct realtek_pci_sdmmc *host, | ||
571 | struct mmc_request *mrq) | ||
362 | { | 572 | { |
363 | struct rtsx_pcr *pcr = host->pcr; | 573 | struct rtsx_pcr *pcr = host->pcr; |
364 | struct mmc_host *mmc = host->mmc; | 574 | struct mmc_host *mmc = host->mmc; |
365 | struct mmc_card *card = mmc->card; | 575 | struct mmc_card *card = mmc->card; |
366 | struct mmc_data *data = mrq->data; | 576 | struct mmc_data *data = mrq->data; |
367 | int uhs = mmc_card_uhs(card); | 577 | int uhs = mmc_card_uhs(card); |
368 | int read = (data->flags & MMC_DATA_READ) ? 1 : 0; | 578 | int read = data->flags & MMC_DATA_READ; |
369 | u8 cfg2, trans_mode; | 579 | u8 cfg2, trans_mode; |
370 | int err; | 580 | int err; |
371 | size_t data_len = data->blksz * data->blocks; | 581 | size_t data_len = data->blksz * data->blocks; |
372 | 582 | ||
583 | if (host->data) | ||
584 | dev_err(sdmmc_dev(host), "error: data already exist\n"); | ||
585 | |||
586 | host->data = data; | ||
587 | |||
373 | if (read) { | 588 | if (read) { |
374 | cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | | 589 | cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | |
375 | SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; | 590 | SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; |
@@ -420,17 +635,56 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) | |||
420 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, | 635 | rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, |
421 | SD_TRANSFER_END, SD_TRANSFER_END); | 636 | SD_TRANSFER_END, SD_TRANSFER_END); |
422 | 637 | ||
638 | mod_timer(&host->timer, jiffies + 10 * HZ); | ||
423 | rtsx_pci_send_cmd_no_wait(pcr); | 639 | rtsx_pci_send_cmd_no_wait(pcr); |
424 | 640 | ||
425 | err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000); | 641 | err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read); |
426 | if (err < 0) { | 642 | if (err < 0) { |
427 | sd_clear_error(host); | 643 | data->error = err; |
428 | return err; | 644 | tasklet_schedule(&host->finish_tasklet); |
429 | } | 645 | } |
430 | |||
431 | return 0; | 646 | return 0; |
432 | } | 647 | } |
433 | 648 | ||
649 | static void sd_finish_multi_rw(unsigned long host_addr) | ||
650 | { | ||
651 | struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr; | ||
652 | struct rtsx_pcr *pcr = host->pcr; | ||
653 | struct mmc_data *data; | ||
654 | int err = 0; | ||
655 | unsigned long flags; | ||
656 | |||
657 | spin_lock_irqsave(&host->lock, flags); | ||
658 | |||
659 | if (!host->data) { | ||
660 | dev_err(sdmmc_dev(host), "error: no data exist\n"); | ||
661 | goto out; | ||
662 | } | ||
663 | |||
664 | data = host->data; | ||
665 | host->data = NULL; | ||
666 | |||
667 | if (pcr->trans_result == TRANS_NO_DEVICE) | ||
668 | err = -ENODEV; | ||
669 | else if (pcr->trans_result != TRANS_RESULT_OK) | ||
670 | err = -EINVAL; | ||
671 | |||
672 | if (err < 0) { | ||
673 | data->error = err; | ||
674 | goto out; | ||
675 | } | ||
676 | |||
677 | if (!host->mrq->sbc && data->stop) { | ||
678 | sd_send_cmd(host, data->stop); | ||
679 | spin_unlock_irqrestore(&host->lock, flags); | ||
680 | return; | ||
681 | } | ||
682 | |||
683 | out: | ||
684 | tasklet_schedule(&host->finish_tasklet); | ||
685 | spin_unlock_irqrestore(&host->lock, flags); | ||
686 | } | ||
687 | |||
434 | static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) | 688 | static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) |
435 | { | 689 | { |
436 | rtsx_pci_write_register(host->pcr, SD_CFG1, | 690 | rtsx_pci_write_register(host->pcr, SD_CFG1, |
@@ -511,85 +765,47 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host, | |||
511 | return 0; | 765 | return 0; |
512 | } | 766 | } |
513 | 767 | ||
514 | static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) | 768 | static inline u32 test_phase_bit(u32 phase_map, unsigned int bit) |
515 | { | 769 | { |
516 | struct timing_phase_path path[MAX_PHASE + 1]; | 770 | bit %= RTSX_PHASE_MAX; |
517 | int i, j, cont_path_cnt; | 771 | return phase_map & (1 << bit); |
518 | int new_block, max_len, final_path_idx; | 772 | } |
519 | u8 final_phase = 0xFF; | ||
520 | 773 | ||
521 | /* Parse phase_map, take it as a bit-ring */ | 774 | static int sd_get_phase_len(u32 phase_map, unsigned int start_bit) |
522 | cont_path_cnt = 0; | 775 | { |
523 | new_block = 1; | 776 | int i; |
524 | j = 0; | ||
525 | for (i = 0; i < MAX_PHASE + 1; i++) { | ||
526 | if (phase_map & (1 << i)) { | ||
527 | if (new_block) { | ||
528 | new_block = 0; | ||
529 | j = cont_path_cnt++; | ||
530 | path[j].start = i; | ||
531 | path[j].end = i; | ||
532 | } else { | ||
533 | path[j].end = i; | ||
534 | } | ||
535 | } else { | ||
536 | new_block = 1; | ||
537 | if (cont_path_cnt) { | ||
538 | /* Calculate path length and middle point */ | ||
539 | int idx = cont_path_cnt - 1; | ||
540 | path[idx].len = | ||
541 | path[idx].end - path[idx].start + 1; | ||
542 | path[idx].mid = | ||
543 | path[idx].start + path[idx].len / 2; | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | 777 | ||
548 | if (cont_path_cnt == 0) { | 778 | for (i = 0; i < RTSX_PHASE_MAX; i++) { |
549 | dev_dbg(sdmmc_dev(host), "No continuous phase path\n"); | 779 | if (test_phase_bit(phase_map, start_bit + i) == 0) |
550 | goto finish; | 780 | return i; |
551 | } else { | ||
552 | /* Calculate last continuous path length and middle point */ | ||
553 | int idx = cont_path_cnt - 1; | ||
554 | path[idx].len = path[idx].end - path[idx].start + 1; | ||
555 | path[idx].mid = path[idx].start + path[idx].len / 2; | ||
556 | } | 781 | } |
782 | return RTSX_PHASE_MAX; | ||
783 | } | ||
784 | |||
785 | static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) | ||
786 | { | ||
787 | int start = 0, len = 0; | ||
788 | int start_final = 0, len_final = 0; | ||
789 | u8 final_phase = 0xFF; | ||
557 | 790 | ||
558 | /* Connect the first and last continuous paths if they are adjacent */ | 791 | if (phase_map == 0) { |
559 | if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { | 792 | dev_err(sdmmc_dev(host), "phase error: [map:%x]\n", phase_map); |
560 | /* Using negative index */ | 793 | return final_phase; |
561 | path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; | ||
562 | path[0].len += path[cont_path_cnt - 1].len; | ||
563 | path[0].mid = path[0].start + path[0].len / 2; | ||
564 | /* Convert negative middle point index to positive one */ | ||
565 | if (path[0].mid < 0) | ||
566 | path[0].mid += MAX_PHASE + 1; | ||
567 | cont_path_cnt--; | ||
568 | } | 794 | } |
569 | 795 | ||
570 | /* Choose the longest continuous phase path */ | 796 | while (start < RTSX_PHASE_MAX) { |
571 | max_len = 0; | 797 | len = sd_get_phase_len(phase_map, start); |
572 | final_phase = 0; | 798 | if (len_final < len) { |
573 | final_path_idx = 0; | 799 | start_final = start; |
574 | for (i = 0; i < cont_path_cnt; i++) { | 800 | len_final = len; |
575 | if (path[i].len > max_len) { | ||
576 | max_len = path[i].len; | ||
577 | final_phase = (u8)path[i].mid; | ||
578 | final_path_idx = i; | ||
579 | } | 801 | } |
580 | 802 | start += len ? len : 1; | |
581 | dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n", | ||
582 | i, path[i].start); | ||
583 | dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n", | ||
584 | i, path[i].end); | ||
585 | dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n", | ||
586 | i, path[i].len); | ||
587 | dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n", | ||
588 | i, path[i].mid); | ||
589 | } | 803 | } |
590 | 804 | ||
591 | finish: | 805 | final_phase = (start_final + len_final / 2) % RTSX_PHASE_MAX; |
592 | dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase); | 806 | dev_dbg(sdmmc_dev(host), "phase: [map:%x] [maxlen:%d] [final:%d]\n", |
807 | phase_map, len_final, final_phase); | ||
808 | |||
593 | return final_phase; | 809 | return final_phase; |
594 | } | 810 | } |
595 | 811 | ||
@@ -635,7 +851,7 @@ static int sd_tuning_phase(struct realtek_pci_sdmmc *host, | |||
635 | int err, i; | 851 | int err, i; |
636 | u32 raw_phase_map = 0; | 852 | u32 raw_phase_map = 0; |
637 | 853 | ||
638 | for (i = MAX_PHASE; i >= 0; i--) { | 854 | for (i = 0; i < RTSX_PHASE_MAX; i++) { |
639 | err = sd_tuning_rx_cmd(host, opcode, (u8)i); | 855 | err = sd_tuning_rx_cmd(host, opcode, (u8)i); |
640 | if (err == 0) | 856 | if (err == 0) |
641 | raw_phase_map |= 1 << i; | 857 | raw_phase_map |= 1 << i; |
@@ -685,6 +901,13 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) | |||
685 | return 0; | 901 | return 0; |
686 | } | 902 | } |
687 | 903 | ||
904 | static inline bool sd_use_muti_rw(struct mmc_command *cmd) | ||
905 | { | ||
906 | return mmc_op_multi(cmd->opcode) || | ||
907 | (cmd->opcode == MMC_READ_SINGLE_BLOCK) || | ||
908 | (cmd->opcode == MMC_WRITE_BLOCK); | ||
909 | } | ||
910 | |||
688 | static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | 911 | static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) |
689 | { | 912 | { |
690 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | 913 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); |
@@ -693,6 +916,14 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
693 | struct mmc_data *data = mrq->data; | 916 | struct mmc_data *data = mrq->data; |
694 | unsigned int data_size = 0; | 917 | unsigned int data_size = 0; |
695 | int err; | 918 | int err; |
919 | unsigned long flags; | ||
920 | |||
921 | mutex_lock(&pcr->pcr_mutex); | ||
922 | spin_lock_irqsave(&host->lock, flags); | ||
923 | |||
924 | if (host->mrq) | ||
925 | dev_err(sdmmc_dev(host), "error: request already exist\n"); | ||
926 | host->mrq = mrq; | ||
696 | 927 | ||
697 | if (host->eject) { | 928 | if (host->eject) { |
698 | cmd->error = -ENOMEDIUM; | 929 | cmd->error = -ENOMEDIUM; |
@@ -705,8 +936,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
705 | goto finish; | 936 | goto finish; |
706 | } | 937 | } |
707 | 938 | ||
708 | mutex_lock(&pcr->pcr_mutex); | ||
709 | |||
710 | rtsx_pci_start_run(pcr); | 939 | rtsx_pci_start_run(pcr); |
711 | 940 | ||
712 | rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth, | 941 | rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth, |
@@ -715,46 +944,28 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
715 | rtsx_pci_write_register(pcr, CARD_SHARE_MODE, | 944 | rtsx_pci_write_register(pcr, CARD_SHARE_MODE, |
716 | CARD_SHARE_MASK, CARD_SHARE_48_SD); | 945 | CARD_SHARE_MASK, CARD_SHARE_48_SD); |
717 | 946 | ||
718 | mutex_lock(&host->host_mutex); | ||
719 | host->mrq = mrq; | ||
720 | mutex_unlock(&host->host_mutex); | ||
721 | |||
722 | if (mrq->data) | 947 | if (mrq->data) |
723 | data_size = data->blocks * data->blksz; | 948 | data_size = data->blocks * data->blksz; |
724 | 949 | ||
725 | if (!data_size || mmc_op_multi(cmd->opcode) || | 950 | if (sd_use_muti_rw(cmd)) |
726 | (cmd->opcode == MMC_READ_SINGLE_BLOCK) || | 951 | host->sg_count = sd_pre_dma_transfer(host, data, NULL); |
727 | (cmd->opcode == MMC_WRITE_BLOCK)) { | ||
728 | sd_send_cmd_get_rsp(host, cmd); | ||
729 | |||
730 | if (!cmd->error && data_size) { | ||
731 | sd_rw_multi(host, mrq); | ||
732 | 952 | ||
733 | if (mmc_op_multi(cmd->opcode) && mrq->stop) | 953 | if (!data_size || sd_use_muti_rw(cmd)) { |
734 | sd_send_cmd_get_rsp(host, mrq->stop); | 954 | if (mrq->sbc) |
735 | } | 955 | sd_send_cmd(host, mrq->sbc); |
956 | else | ||
957 | sd_send_cmd(host, cmd); | ||
958 | spin_unlock_irqrestore(&host->lock, flags); | ||
736 | } else { | 959 | } else { |
960 | spin_unlock_irqrestore(&host->lock, flags); | ||
737 | sd_normal_rw(host, mrq); | 961 | sd_normal_rw(host, mrq); |
962 | tasklet_schedule(&host->finish_tasklet); | ||
738 | } | 963 | } |
739 | 964 | return; | |
740 | if (mrq->data) { | ||
741 | if (cmd->error || data->error) | ||
742 | data->bytes_xfered = 0; | ||
743 | else | ||
744 | data->bytes_xfered = data->blocks * data->blksz; | ||
745 | } | ||
746 | |||
747 | mutex_unlock(&pcr->pcr_mutex); | ||
748 | 965 | ||
749 | finish: | 966 | finish: |
750 | if (cmd->error) | 967 | tasklet_schedule(&host->finish_tasklet); |
751 | dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); | 968 | spin_unlock_irqrestore(&host->lock, flags); |
752 | |||
753 | mutex_lock(&host->host_mutex); | ||
754 | host->mrq = NULL; | ||
755 | mutex_unlock(&host->host_mutex); | ||
756 | |||
757 | mmc_request_done(mmc, mrq); | ||
758 | } | 969 | } |
759 | 970 | ||
760 | static int sd_set_bus_width(struct realtek_pci_sdmmc *host, | 971 | static int sd_set_bus_width(struct realtek_pci_sdmmc *host, |
@@ -1189,6 +1400,8 @@ out: | |||
1189 | } | 1400 | } |
1190 | 1401 | ||
1191 | static const struct mmc_host_ops realtek_pci_sdmmc_ops = { | 1402 | static const struct mmc_host_ops realtek_pci_sdmmc_ops = { |
1403 | .pre_req = sdmmc_pre_req, | ||
1404 | .post_req = sdmmc_post_req, | ||
1192 | .request = sdmmc_request, | 1405 | .request = sdmmc_request, |
1193 | .set_ios = sdmmc_set_ios, | 1406 | .set_ios = sdmmc_set_ios, |
1194 | .get_ro = sdmmc_get_ro, | 1407 | .get_ro = sdmmc_get_ro, |
@@ -1252,6 +1465,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) | |||
1252 | struct realtek_pci_sdmmc *host; | 1465 | struct realtek_pci_sdmmc *host; |
1253 | struct rtsx_pcr *pcr; | 1466 | struct rtsx_pcr *pcr; |
1254 | struct pcr_handle *handle = pdev->dev.platform_data; | 1467 | struct pcr_handle *handle = pdev->dev.platform_data; |
1468 | unsigned long host_addr; | ||
1255 | 1469 | ||
1256 | if (!handle) | 1470 | if (!handle) |
1257 | return -ENXIO; | 1471 | return -ENXIO; |
@@ -1275,8 +1489,15 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) | |||
1275 | pcr->slots[RTSX_SD_CARD].p_dev = pdev; | 1489 | pcr->slots[RTSX_SD_CARD].p_dev = pdev; |
1276 | pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; | 1490 | pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; |
1277 | 1491 | ||
1278 | mutex_init(&host->host_mutex); | 1492 | host_addr = (unsigned long)host; |
1493 | host->next_data.cookie = 1; | ||
1494 | setup_timer(&host->timer, sd_request_timeout, host_addr); | ||
1495 | tasklet_init(&host->cmd_tasklet, sd_get_rsp, host_addr); | ||
1496 | tasklet_init(&host->data_tasklet, sd_finish_multi_rw, host_addr); | ||
1497 | tasklet_init(&host->finish_tasklet, sd_finish_request, host_addr); | ||
1498 | spin_lock_init(&host->lock); | ||
1279 | 1499 | ||
1500 | pcr->slots[RTSX_SD_CARD].done_transfer = sd_isr_done_transfer; | ||
1280 | realtek_init_host(host); | 1501 | realtek_init_host(host); |
1281 | 1502 | ||
1282 | mmc_add_host(mmc); | 1503 | mmc_add_host(mmc); |
@@ -1289,6 +1510,8 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) | |||
1289 | struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); | 1510 | struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); |
1290 | struct rtsx_pcr *pcr; | 1511 | struct rtsx_pcr *pcr; |
1291 | struct mmc_host *mmc; | 1512 | struct mmc_host *mmc; |
1513 | struct mmc_request *mrq; | ||
1514 | unsigned long flags; | ||
1292 | 1515 | ||
1293 | if (!host) | 1516 | if (!host) |
1294 | return 0; | 1517 | return 0; |
@@ -1296,25 +1519,37 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) | |||
1296 | pcr = host->pcr; | 1519 | pcr = host->pcr; |
1297 | pcr->slots[RTSX_SD_CARD].p_dev = NULL; | 1520 | pcr->slots[RTSX_SD_CARD].p_dev = NULL; |
1298 | pcr->slots[RTSX_SD_CARD].card_event = NULL; | 1521 | pcr->slots[RTSX_SD_CARD].card_event = NULL; |
1522 | pcr->slots[RTSX_SD_CARD].done_transfer = NULL; | ||
1299 | mmc = host->mmc; | 1523 | mmc = host->mmc; |
1300 | host->eject = true; | 1524 | mrq = host->mrq; |
1301 | 1525 | ||
1302 | mutex_lock(&host->host_mutex); | 1526 | spin_lock_irqsave(&host->lock, flags); |
1303 | if (host->mrq) { | 1527 | if (host->mrq) { |
1304 | dev_dbg(&(pdev->dev), | 1528 | dev_dbg(&(pdev->dev), |
1305 | "%s: Controller removed during transfer\n", | 1529 | "%s: Controller removed during transfer\n", |
1306 | mmc_hostname(mmc)); | 1530 | mmc_hostname(mmc)); |
1307 | 1531 | ||
1308 | rtsx_pci_complete_unfinished_transfer(pcr); | 1532 | if (mrq->sbc) |
1533 | mrq->sbc->error = -ENOMEDIUM; | ||
1534 | if (mrq->cmd) | ||
1535 | mrq->cmd->error = -ENOMEDIUM; | ||
1536 | if (mrq->stop) | ||
1537 | mrq->stop->error = -ENOMEDIUM; | ||
1538 | if (mrq->data) | ||
1539 | mrq->data->error = -ENOMEDIUM; | ||
1309 | 1540 | ||
1310 | host->mrq->cmd->error = -ENOMEDIUM; | 1541 | tasklet_schedule(&host->finish_tasklet); |
1311 | if (host->mrq->stop) | ||
1312 | host->mrq->stop->error = -ENOMEDIUM; | ||
1313 | mmc_request_done(mmc, host->mrq); | ||
1314 | } | 1542 | } |
1315 | mutex_unlock(&host->host_mutex); | 1543 | spin_unlock_irqrestore(&host->lock, flags); |
1544 | |||
1545 | del_timer_sync(&host->timer); | ||
1546 | tasklet_kill(&host->cmd_tasklet); | ||
1547 | tasklet_kill(&host->data_tasklet); | ||
1548 | tasklet_kill(&host->finish_tasklet); | ||
1316 | 1549 | ||
1317 | mmc_remove_host(mmc); | 1550 | mmc_remove_host(mmc); |
1551 | host->eject = true; | ||
1552 | |||
1318 | mmc_free_host(mmc); | 1553 | mmc_free_host(mmc); |
1319 | 1554 | ||
1320 | dev_dbg(&(pdev->dev), | 1555 | dev_dbg(&(pdev->dev), |