From c1e8cae17dbc71c5b0a7f09ba23938b1837778df Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E6=9D=A8=E4=BA=91?= Date: Sat, 16 Jul 2011 09:08:53 +0800 Subject: [PATCH] Revert "RK29 SDMMC Ver1.14 2011-06-26 release from XBW" This reverts commit 543f1a582cda4d8b4945bbda8a9a876b76712ba1. --- drivers/mmc/card/block.c | 29 +- drivers/mmc/core/bus.c | 1 + drivers/mmc/core/core.c | 216 +- drivers/mmc/core/host.c | 8 + drivers/mmc/core/mmc.c | 29 - drivers/mmc/core/sd.c | 53 - drivers/mmc/core/sdio.c | 11 +- drivers/mmc/host/rk29_sdmmc.c | 3700 ++++++++++----------------------- drivers/mmc/host/rk29_sdmmc.h | 202 -- drivers/mmc/host/sdhci-pci.c | 1 + drivers/mmc/host/sdhci.c | 9 +- fs/partitions/check.c | 14 - fs/partitions/efi.c | 6 + fs/partitions/ldm.c | 26 +- fs/partitions/mac.c | 17 +- fs/partitions/msdos.c | 47 - fs/partitions/osf.c | 12 +- include/linux/mmc/host.h | 8 +- include/linux/mmc/mmc.h | 13 - 19 files changed, 1266 insertions(+), 3136 deletions(-) delete mode 100755 drivers/mmc/host/rk29_sdmmc.h diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index a428440e9199..98f74b0087b5 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -43,7 +43,6 @@ MODULE_ALIAS("mmc:block"); -static DEFINE_MUTEX(block_mutex); //added by xbw at 2011-04-21 /* * max 8 partitions per card */ @@ -107,7 +106,6 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode) struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk); int ret = -ENXIO; - mutex_lock(&block_mutex); //added by xbw at 2011-04-21 if (md) { if (md->usage == 2) check_disk_change(bdev); @@ -118,7 +116,6 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode) ret = -EROFS; } } - mutex_unlock(&block_mutex); return ret; } @@ -127,9 +124,7 @@ static int mmc_blk_release(struct gendisk *disk, fmode_t mode) { struct mmc_blk_data *md = disk->private_data; - mutex_lock(&block_mutex); //added by xbw at 2011-04-21 mmc_blk_put(md); - mutex_unlock(&block_mutex); return 0; } @@ -229,7 +224,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) return result; } -#if 0 //Deleted by xbw@2011-03-21 static u32 get_card_status(struct mmc_card *card, struct request *req) { struct mmc_command cmd; @@ -246,7 +240,6 @@ static u32 get_card_status(struct mmc_card *card, struct request *req) req->rq_disk->disk_name, err); return cmd.resp[0]; } -#endif static int mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) @@ -290,17 +283,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) #endif mmc_claim_host(card->host); - //card->host->re_initialized_flags = 0; //added by xbw@2011-04-07 do { - //struct mmc_command cmd;//Deleted by xbw@2011-03-21 + struct mmc_command cmd; u32 readcmd, writecmd, status = 0; memset(&brq, 0, sizeof(struct mmc_blk_request)); brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - - brq.cmd.retries = 2; //suppot retry read-write; added by xbw@2011-03-21 brq.cmd.arg = blk_rq_pos(req); if (!mmc_card_blockaddr(card)) @@ -381,8 +371,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_queue_bounce_post(mq); - #if 0 //not turn CMD18 to CMD17. deleted by xbw at 2011-04-21 - /* * Check for errors here, but don't jump to cmd_err * until later as we need to wait for the card to leave @@ -396,13 +384,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) disable_multi = 1; continue; } - - //status = get_card_status(card, req); //Deleted by xbw@2011-03-21 - + status = get_card_status(card, req); } else if (disable_multi == 1) { disable_multi = 0; - } - #endif + } if (brq.cmd.error) { printk(KERN_DEBUG "%s: error %d sending read/write " @@ -429,10 +414,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.stop.resp[0], status); } - #if 0 //Deleted by xbw@2011-03-21 if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { - - do { int err; @@ -453,7 +435,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd.resp[0]) == 7)); - #if 0 if (cmd.resp[0] & ~0x00000900) printk(KERN_ERR "%s: status = %08x\n", @@ -462,9 +443,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) goto cmd_err; #endif } -#endif - if (brq.cmd.error || brq.stop.error || brq.data.error) { + if (brq.cmd.error || brq.stop.error || brq.data.error) { if (rq_data_dir(req) == READ) { /* * After an error, we redo I/O one sector at a @@ -591,7 +571,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) */ sprintf(md->disk->disk_name, "mmcblk%d", devidx); - printk("%s..%d **** devidx=%d, dev_use[0]=%lu, disk_name=%s *** ==xbw[%s]==\n",__FUNCTION__,__LINE__, devidx, dev_use[0], md->disk->disk_name,mmc_hostname(card->host)); blk_queue_logical_block_size(md->queue.queue, 512); diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index bdb165f93046..812b22035626 100755 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -279,6 +279,7 @@ void mmc_remove_card(struct mmc_card *card) #endif if (mmc_card_present(card)) { + mmc_card_clr_present(card); if (mmc_host_is_spi(card->host)) { printk(KERN_INFO "%s: SPI card removed\n", mmc_hostname(card->host)); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f0ddaa7b4cc7..5148f8e5ea71 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -202,11 +202,7 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) mmc_start_request(host, mrq); - #if 0 wait_for_completion(&complete); - #else - wait_for_completion_timeout(&complete,HZ*3); //for cmd dead. Modifyed by xbw at 2011-06-02 - #endif } EXPORT_SYMBOL(mmc_wait_for_req); @@ -1071,8 +1067,18 @@ void mmc_rescan(struct work_struct *work) u32 ocr; int err; int extend_wakelock = 0; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (host->rescan_disable) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + spin_unlock_irqrestore(&host->lock, flags); + - mmc_bus_get(host); /* if there is a card registered, check whether it is still present */ @@ -1103,105 +1109,54 @@ void mmc_rescan(struct work_struct *work) * release the lock here. */ mmc_bus_put(host); - printk("\n%s...%d.. ===== mmc_rescan Begin....======xbw[%s]=====\n",__FILE__, __LINE__, mmc_hostname(host)); if (host->ops->get_cd && host->ops->get_cd(host) == 0) - { - printk("\n=================\n%s..%d.. ====find no SDMMC host.====xbw[%s]=====\n", \ - __FUNCTION__, __LINE__, mmc_hostname(host)); - goto out; - } mmc_claim_host(host); - + mmc_power_up(host); - mmc_go_idle(host); - /* - In oder to improve the initialization process in rockchip IC, I modify the following code about the the initialization process of SDIO-SD-MMC. - So I deleted the CMD8 and add a conditional to distinguish between the two card type,i.e.SDMMC process and SDIO process. - For detail,please refer to "RK29XX Technical Reference Manual" and "SD-MMC-SDIO Specifications". - Noted by xbw@2011-04-09 - */ - - //mmc_send_if_cond(host, host->ocr_avail); //deleted by xbw@2011-04-09 - - if( strncmp( mmc_hostname(host) ,"mmc0" , strlen("mmc0")) ){ - /* - * First we search for SDIO... - */ - err = mmc_send_io_op_cond(host, 0, &ocr); - if (!err) { - printk("\n%s..%d.. ===== Begin to identify card as SDIO-card===xbw[%s]===\n",__FUNCTION__, __LINE__, mmc_hostname(host)); - - if (mmc_attach_sdio(host, ocr)) - { - printk("\n=====\n %s..%d.. ===== Initialize SDIO-card unsuccessfully!!! ===xbw[%s]===\n=====\n",\ - __FUNCTION__, __LINE__, mmc_hostname(host)); - - mmc_power_off(host); - } - else - { - printk("%s..%d.. ===== Initialize SDIO successfully. ===xbw[%s]===\n",__FUNCTION__, __LINE__, mmc_hostname(host)); - } - extend_wakelock = 1; - goto out; - } - } - - - /* - * ...then normal SD... - */ - err = mmc_send_app_op_cond(host, 0, &ocr); - if (!err) { - printk("\n%s..%d.. ===== Begin to identify card as SD-card ===xbw[%s]===\n",__FUNCTION__, __LINE__, mmc_hostname(host)); - - if (mmc_attach_sd(host, ocr)) - { - printk("\n=====\n%s..%d.. ===== Initialize SD-card unsuccessfully!!! ===xbw[%s]===\n====\n",\ - __FUNCTION__, __LINE__, mmc_hostname(host)); - - mmc_power_off(host); - } - else - { - printk("%s..%d.. ===== Initialize SD-card successfully. ===xbw[%s]===\n",__FUNCTION__, __LINE__, mmc_hostname(host)); - } - extend_wakelock = 1; - goto out; - } - - /* - * ...and finally MMC. - */ - err = mmc_send_op_cond(host, 0, &ocr); - if (!err) { - printk("\n%s..%d.. ===== Begin to identify card as MMC-card ===xbw[%s]===\n", __FUNCTION__, __LINE__, mmc_hostname(host)); - - if (mmc_attach_mmc(host, ocr)) - { - printk("\n =====\n%s..%d.. ===== Initialize MMC-card unsuccessfully!!! ===xbw[%s]===\n======\n",\ - __FUNCTION__, __LINE__, mmc_hostname(host)); - - mmc_power_off(host); - } - else - { - printk("%s...%d.. ===== Initialize MMC-card successfully. ===xbw[%s]===\n",__FUNCTION__, __LINE__, mmc_hostname(host)); - } - extend_wakelock = 1; - goto out; - } + mmc_send_if_cond(host, host->ocr_avail); + + /* + * First we search for SDIO... + */ + err = mmc_send_io_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_sdio(host, ocr)) + mmc_power_off(host); + extend_wakelock = 1; + goto out; + } + + /* + * ...then normal SD... + */ + err = mmc_send_app_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_sd(host, ocr)) + mmc_power_off(host); + extend_wakelock = 1; + goto out; + } + + /* + * ...and finally MMC. + */ + err = mmc_send_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_mmc(host, ocr)) + mmc_power_off(host); + extend_wakelock = 1; + goto out; + } mmc_release_host(host); mmc_power_off(host); out: - if (extend_wakelock) wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2); else @@ -1337,7 +1292,6 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) if (mmc_bus_needs_resume(host)) return 0; - printk("%s: %s go into suspend function.\n",__FUNCTION__, mmc_hostname(host)); if (host->caps & MMC_CAP_DISABLE) cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); @@ -1347,21 +1301,9 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->suspend) err = host->bus_ops->suspend(host); - if (err == -ENOSYS || !host->bus_ops->resume) { - /* - * We simply "remove" the card in this case. - * It will be redetected on resume. - */ - if (host->bus_ops->remove) - host->bus_ops->remove(host); - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); - err = 0; - } } mmc_bus_put(host); - printk("%s: %s exit suspend function.\n",__FUNCTION__, mmc_hostname(host)); + if (!err) mmc_power_off(host); @@ -1389,39 +1331,65 @@ int mmc_resume_host(struct mmc_host *host) mmc_power_up(host); mmc_select_voltage(host, host->ocr); BUG_ON(!host->bus_ops->resume); - - #if 0 //panic if the card is being removed during the resume, deleted by xbw at 2011-06-20 err = host->bus_ops->resume(host); if (err) { printk(KERN_WARNING "%s: error %d during resume " "(card was removed?)\n", mmc_hostname(host), err); - if (host->bus_ops->remove) - host->bus_ops->remove(host); - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); - /* no need to bother upper layers */ err = 0; } - #else - host->bus_ops->resume(host); - - #endif } mmc_bus_put(host); - /* - * We add a slight delay here so that resume can progress - * in parallel. - */ - mmc_detect_change(host, 1); - return err; } - EXPORT_SYMBOL(mmc_resume_host); +/* Do the card removal on suspend if card is assumed removeable + * Do that in pm notifier while userspace isn't yet frozen, so we will be able + to sync the card. +*/ +int mmc_pm_notify(struct notifier_block *notify_block, + unsigned long mode, void *unused) +{ + struct mmc_host *host = container_of( + notify_block, struct mmc_host, pm_notify); + unsigned long flags; + + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + + spin_lock_irqsave(&host->lock, flags); + host->rescan_disable = 1; + spin_unlock_irqrestore(&host->lock, flags); + cancel_delayed_work_sync(&host->detect); + + if (!host->bus_ops || host->bus_ops->suspend) + break; + + mmc_claim_host(host); + + if (host->bus_ops->remove) + host->bus_ops->remove(host); + + mmc_detach_bus(host); + mmc_release_host(host); + break; + + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + + spin_lock_irqsave(&host->lock, flags); + host->rescan_disable = 0; + spin_unlock_irqrestore(&host->lock, flags); + mmc_detect_change(host, 0); + + } + + return 0; +} #endif #ifdef CONFIG_MMC_EMBEDDED_SDIO diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index a268d12f1af0..94f35ca5c413 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -84,6 +85,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); +#ifdef CONFIG_PM + host->pm_notify.notifier_call = mmc_pm_notify; +#endif /* * By default, hosts do not support SGIO or large requests. @@ -132,6 +136,8 @@ int mmc_add_host(struct mmc_host *host) #endif mmc_start_host(host); + if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) + register_pm_notifier(&host->pm_notify); return 0; } @@ -148,6 +154,8 @@ EXPORT_SYMBOL(mmc_add_host); */ void mmc_remove_host(struct mmc_host *host) { + if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) + unregister_pm_notifier(&host->pm_notify); mmc_stop_host(host); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 32eefeb98aa5..32af45c419f4 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -321,10 +321,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* The extra bit indicates that we support high capacity */ err = mmc_send_op_cond(host, ocr | (1 << 30), NULL); if (err) - { - printk("%s..%d.. ====*Identify the card as MMC , but OCR error, so fail to initialize.===xbw[%s]===\n", __FUNCTION__, __LINE__, mmc_hostname(host)); goto err; - } /* * For SPI, enable CRC as appropriate. @@ -441,7 +438,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (max_dtr > card->ext_csd.hs_max_dtr) max_dtr = card->ext_csd.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { - card->csd.max_dtr = (card->csd.max_dtr > MMC_FPP_FREQ) ? MMC_FPP_FREQ : (card->csd.max_dtr); //in order to expand the compatibility of card. Added by xbw@2011-03-21 max_dtr = card->csd.max_dtr; } @@ -664,7 +660,6 @@ static void mmc_attach_bus_ops(struct mmc_host *host) int mmc_attach_mmc(struct mmc_host *host, u32 ocr) { int err; - int retry_times = 3; BUG_ON(!host); WARN_ON(!host->claimed); @@ -710,33 +705,9 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) mmc_release_host(host); -#if 0 // Deleted by xbw at 2011-04-09 - err = mmc_add_card(host->card); - if (err) - goto remove_card; - -#else //modifyed by xbw at 2011--04-11 - -Retry_add: err = mmc_add_card(host->card); if (err) - { - //retry add the card; Added by xbw - if((--retry_times >= 0)) - { - printk("\n%s..%s..%d ****error in add partition, so retry. ===xbw[%s]===\n",__FUNCTION__,__FILE__,__LINE__, mmc_hostname(host)); - /* sleep some time */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/2); - - goto Retry_add; - } - goto remove_card; - - } -#endif - return 0; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 53bca2f724eb..8fe5e9ece251 100755 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -362,10 +362,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, err = mmc_send_app_op_cond(host, ocr, NULL); if (err) - { - printk("%s..%d.. ====*Identify the card as SD , but OCR error, so fail to initialize.===xbw[%s]===\n", __FUNCTION__, __LINE__, mmc_hostname(host)); goto err; - } /* * Fetch CID from card. @@ -461,11 +458,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, printk(KERN_WARNING "%s: read switch failed (attempt %d)\n", mmc_hostname(host), retries); - - if(0 == host->re_initialized_flags) - { - break; //Added by xbw at 2011-06-21 - } } } #else @@ -504,7 +496,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (max_dtr > card->sw_caps.hs_max_dtr) max_dtr = card->sw_caps.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { - card->csd.max_dtr = (card->csd.max_dtr > SD_FPP_FREQ) ? SD_FPP_FREQ : (card->csd.max_dtr); //in order to expand the compatibility of card. Added by xbw@2011-03-21 max_dtr = card->csd.max_dtr; } @@ -585,13 +576,6 @@ static void mmc_sd_detect(struct mmc_host *host) err = mmc_send_status(host->card, NULL); if (err) { retries--; - - if(0 == host->re_initialized_flags) - { - retries = 0; - break; //Added by xbw at 2011-06-21 - } - udelay(5); continue; } @@ -652,7 +636,6 @@ static int mmc_sd_resume(struct mmc_host *host) #ifdef CONFIG_MMC_PARANOID_SD_INIT retries = 5; while (retries) { - err = mmc_sd_init_card(host, host->ocr, host->card); if (err) { @@ -660,11 +643,6 @@ static int mmc_sd_resume(struct mmc_host *host) mmc_hostname(host), err, retries); mdelay(5); retries--; - - if(0 == host->re_initialized_flags) - { - break; //Added by xbw at 2011-06-21 - } continue; } break; @@ -737,8 +715,6 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host) int mmc_attach_sd(struct mmc_host *host, u32 ocr) { int err; - int retry_times = 3; - #ifdef CONFIG_MMC_PARANOID_SD_INIT int retries; #endif @@ -796,12 +772,6 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) err = mmc_sd_init_card(host, host->ocr, NULL); if (err) { retries--; - - if(0 == host->re_initialized_flags) - { - retries = 0; - break; //Added by xbw at 2011-06-21 - } continue; } break; @@ -820,32 +790,9 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) mmc_release_host(host); -#if 0 // Deleted by xbw at 2011-04-09 - err = mmc_add_card(host->card); - if (err) - goto remove_card; - -#else //modifyed by xbw at 2011--04-11 - -Retry_add: err = mmc_add_card(host->card); if (err) - { - //retry add the card; Added by xbw - if((--retry_times >= 0)) - { - printk("\n%s..%s..%d ****error in add partition, so retry. ===xbw[%s]===\n",__FUNCTION__,__FILE__,__LINE__, mmc_hostname(host)); - /* sleep some time */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/2); - - goto Retry_add; - } - goto remove_card; - - } -#endif return 0; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 735e41f5c778..21fffa2094bd 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -241,10 +241,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ err = mmc_send_io_op_cond(host, host->ocr, &ocr); if (err) - { - printk("%s..%d.. ====*Identify the card as SDIO , but OCR error, so fail to initialize.===xbw[%s]===\n", __FUNCTION__, __LINE__, mmc_hostname(host)); goto err; - } /* * For SPI, enable CRC as appropriate. @@ -281,6 +278,14 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (err) goto remove; + /* + * Update oldcard with the new RCA received from the SDIO + * device -- we're doing this so that it's updated in the + * "card" struct when oldcard overwrites that later. + */ + if (oldcard) + oldcard->rca = card->rca; + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c index 7e00db34ae8f..b33d69c2300b 100755 --- a/drivers/mmc/host/rk29_sdmmc.c +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -10,7 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * * mount -t debugfs debugfs /data/debugfs;cat /data/debugfs/mmc0/status * echo 't' >/proc/sysrq-trigger * echo 19 >/sys/module/wakelock/parameters/debug_mask @@ -36,6 +35,7 @@ #include #include #include +#include #include #include @@ -46,63 +46,73 @@ #include #include -#include "rk29_sdmmc.h" - - -#define RK29_SDMMC_xbw_Debug 0 - -#if RK29_SDMMC_xbw_Debug -int debug_level = 7; -#define xbwprintk(n, format, arg...) \ - if (n <= debug_level) { \ - printk(format,##arg); \ - } -#else -#define xbwprintk(n, arg...) -#endif - -#define RK29_SDMMC_ERROR_FLAGS (SDMMC_INT_FRUN | SDMMC_INT_RTO | SDMMC_INT_HLE ) - -#define RK29_SDMMC_INTMASK_USEDMA (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD) -#define RK29_SDMMC_INTMASK_USEIO (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR ) +#include "rk2818-sdmmc.h" +#define RK29_SDMMC_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | SDMMC_INT_HTO | SDMMC_INT_SBE | SDMMC_INT_EBE | SDMMC_INT_FRUN) +#define RK29_SDMMC_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | SDMMC_INT_RE | SDMMC_INT_HLE) +#define RK29_SDMMC_ERROR_FLAGS (RK29_SDMMC_DATA_ERROR_FLAGS | RK29_SDMMC_CMD_ERROR_FLAGS | SDMMC_INT_HLE) -#define RK29_SDMMC_SEND_START_TIMEOUT 5000 //The time interval from the time SEND_CMD to START_CMD_BIT cleared. -#define RK29_ERROR_PRINTK_INTERVAL 200 //The time interval between the two printk for the same error. -#define RK29_SDMMC_WAIT_DTO_INTERNVAL 1500 //The time interval from the CMD_DONE_INT to DTO_INT -#define RK29_SDMMC_REMOVAL_DELAY 2000 //The time interval from the CD_INT to detect_timer react. - -#define RK29_SDMMC_VERSION "Ver.1.14. The last modify date is 2011-06-26,modifyed by XBW." - -#define RK29_CTRL_SDMMC_ID 0 //mainly used by SDMMC -#define RK29_CTRL_SDIO1_ID 1 //mainly used by sdio-wifi -#define RK29_CTRL_SDIO2_ID 2 //mainly used by sdio-card - -#define RK29_SDMMC_NOTIFY_REMOVE_INSERTION /* use sysfs to notify the removal or insertion of sd-card*/ -//#define RK29_SDMMC_LIST_QUEUE /* use list-queue for multi-card*/ +#define RK29_SDMMC_TMO_COUNT 10000 +#define RK29_SDCARD_CLK 48 //48Mhz +#define RK29_SDIO_CLK 36 //36Mhz enum { EVENT_CMD_COMPLETE = 0, + EVENT_XFER_COMPLETE, EVENT_DATA_COMPLETE, EVENT_DATA_ERROR, EVENT_XFER_ERROR }; - +enum { + MRQ_REQUEST_START = 0, + MRQ_INT_CMD_DONE, //1 + MRQ_INT_CMD_ERR, //2 + MRQ_INT_DATA_DONE, //3 + MRQ_INT_DATA_ERR, //4 + MRQ_INT_CD, //5 + MRQ_INT_SDIO, //6 + MRQ_HAS_DATA, //7 + MRQ_HAS_STOP, //8 + MRQ_CMD_START_TMO, //9 + MRQ_CMD_START_DONE, //10 + MRQ_STOP_START_TMO, //11 + MRQ_STOP_START_DONE, //12 + MRQ_CLK_START_TMO, //13 + MRQ_CLK_START_DONE, //14 + MRQ_RESET_CTRL_ERR, //15 + MRQ_RESET_CTRL_DONE, //16 + MRQ_DMA_SET_ERR, //17 + MRQ_START_DMA, //18 + MRQ_STOP_DMA, //19 + MRQ_DMA_DONE, //20 + MRQ_REQUEST_DONE, //21 +}; enum rk29_sdmmc_state { STATE_IDLE = 0, STATE_SENDING_CMD, + STATE_SENDING_DATA, STATE_DATA_BUSY, STATE_SENDING_STOP, + STATE_DATA_ERROR, }; +#define rk29_sdmmc_test_and_clear_pending(host, event) \ + test_and_clear_bit(event, &host->pending_events) +#define rk29_sdmmc_set_completed(host, event) \ + set_bit(event, &host->completed_events) +#define rk29_sdmmc_set_pending(host, event) \ + set_bit(event, &host->pending_events) +#define rk29_sdmmc_set_mrq_status(host, status) \ + set_bit(status, &host->mrq_status) +#define rk29_sdmmc_test_mrq_status(host, status) \ + test_bit(status, &host->mrq_status) struct rk29_sdmmc_dma_info { enum dma_ch chn; char *name; struct rk29_dma_client client; }; - -static struct rk29_sdmmc_dma_info rk29_sdmmc_dma_infos[]= { +static struct rk29_sdmmc_dma_info dma_infos[] = { { .chn = DMACH_SDMMC, .client = { @@ -115,105 +125,61 @@ static struct rk29_sdmmc_dma_info rk29_sdmmc_dma_infos[]= { .name = "rk29-dma-sdio1", } }, - - { - .chn = DMACH_EMMC, - .client = { - .name = "rk29-dma-sdio2", - } - }, }; - - -/* Interrupt Information */ -typedef struct TagSDC_INT_INFO +static int rk29_sdmmc_is_sdio(struct rk29_sdmmc_platform_data *pdata) { - u32 transLen; //the length of data sent. - u32 desLen; //the total length of the all data. - u32 *pBuf; //the data buffer for interrupt read or write. -}SDC_INT_INFO_T; - + if(strncmp(pdata->dma_name, "sdio", strlen("sdio")) == 0) + return 1; + else + return 0; +} struct rk29_sdmmc { - spinlock_t lock; - void __iomem *regs; - struct clk *clk; - - struct mmc_request *mrq; - struct mmc_request *new_mrq; - struct mmc_command *cmd; - struct mmc_data *data; - - dma_addr_t dma_addr;; - unsigned int use_dma:1; - char dma_name[8]; - u32 cmd_status; - u32 data_status; - u32 stop_cmdr; - - u32 old_div; - u32 cmdr; //the value setted into command-register - u32 dodma; //sign the DMA used for transfer. - u32 errorstep;//record the error point. - u32 *pbuf; - SDC_INT_INFO_T intInfo; - struct rk29_sdmmc_dma_info dma_info; - - int error_times; - u32 old_cmd; + struct device *dev; - struct tasklet_struct tasklet; - unsigned long pending_events; - unsigned long completed_events; - enum rk29_sdmmc_state state; - -#ifdef RK29_SDMMC_LIST_QUEUE - struct list_head queue; - struct list_head queue_node; -#endif - - u32 bus_hz; - struct platform_device *pdev; - struct mmc_host *mmc; - u32 ctype; - unsigned int clock; - unsigned long flags; + int is_sdio; + int is_init; + int gpio_det; + int gpio_irq; + int irq; + + int enable_sd_warkup; + + unsigned int clock; + unsigned int ios_clock; + unsigned int div; + spinlock_t lock; + unsigned int stop_cmdr; + unsigned int cmd_intsts; + unsigned int data_intsts; + unsigned long pending_events; + unsigned long completed_events; + unsigned long mrq_status; + unsigned long old_mrq_status; + + unsigned int bus_hz; -#define RK29_SDMMC_CARD_PRESENT 0 - int id; + void __iomem *regs; - struct timer_list detect_timer; - struct timer_list request_timer; //the timer for INT_CMD_DONE - struct timer_list DTO_timer; //the timer for INT_DTO - struct mmc_command stopcmd; + struct mmc_host *mmc; + struct delayed_work work; + struct rk29_sdmmc_dma_info dma_info; + struct tasklet_struct tasklet; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct clk *clk; + struct timer_list monitor_timer; - /* flag for current bus settings */ - u32 bus_mode; - - unsigned int oldstatus; - -#ifdef CONFIG_PM - int gpio_irq; - int gpio_det; + enum rk29_sdmmc_state state; + dma_addr_t dma_addr; + + int (*get_wifi_cd)(struct device *); +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; #endif }; - - -#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION -static struct rk29_sdmmc *globalSDhost[3]; -#endif - -#define rk29_sdmmc_test_and_clear_pending(host, event) \ - test_and_clear_bit(event, &host->pending_events) -#define rk29_sdmmc_set_completed(host, event) \ - set_bit(event, &host->completed_events) - -#define rk29_sdmmc_set_pending(host, event) \ - set_bit(event, &host->pending_events) - -static void rk29_sdmmc_start_error(struct rk29_sdmmc *host); - +struct rk29_sdmmc *sdio_host = NULL; static void rk29_sdmmc_write(unsigned char __iomem *regbase, unsigned int regOff,unsigned int val) { __raw_writel(val,regbase + regOff); @@ -224,209 +190,52 @@ static unsigned int rk29_sdmmc_read(unsigned char __iomem *regbase, unsigned in return __raw_readl(regbase + regOff); } -static int rk29_sdmmc_regs_printk(struct rk29_sdmmc *host) -{ - printk("SDMMC_CTRL: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTRL)); - printk("SDMMC_PWREN: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_PWREN)); - printk("SDMMC_CLKDIV: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKDIV)); - printk("SDMMC_CLKSRC: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKSRC)); - printk("SDMMC_CLKENA: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKENA)); - printk("SDMMC_TMOUT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TMOUT)); - printk("SDMMC_CTYPE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTYPE)); - printk("SDMMC_BLKSIZ: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BLKSIZ)); - printk("SDMMC_BYTCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BYTCNT)); - printk("SDMMC_INTMASK:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_INTMASK)); - printk("SDMMC_CMDARG: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMDARG)); - printk("SDMMC_CMD: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMD)); - printk("SDMMC_RESP0: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP0)); - printk("SDMMC_RESP1: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP1)); - printk("SDMMC_RESP2: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP2)); - printk("SDMMC_RESP3: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP3)); - printk("SDMMC_MINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_MINTSTS)); - printk("SDMMC_RINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RINTSTS)); - printk("SDMMC_STATUS: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_STATUS)); - printk("SDMMC_FIFOTH: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_FIFOTH)); - printk("SDMMC_CDETECT:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CDETECT)); - printk("SDMMC_WRTPRT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_WRTPRT)); - printk("SDMMC_TCBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TCBCNT)); - printk("SDMMC_TBBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TBBCNT)); - printk("SDMMC_DEBNCE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_DEBNCE)); - printk("=======printk %s-register end =========\n", host->dma_name); - return 0; -} - -#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION -ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count) +#if defined (CONFIG_DEBUG_FS) +/* + * The debugfs stuff below is mostly optimized away when + * CONFIG_DEBUG_FS is not set. + */ +static int rk29_sdmmc_req_show(struct seq_file *s, void *v) { - struct rk29_sdmmc *host = NULL; - - if( !strncmp(buf,"version" , strlen("version"))) - { - printk("The driver SDMMC named 'rk29_sdmmc.c' is %s. ====xbw====\n", RK29_SDMMC_VERSION); - return count; - } - - spin_lock(&host->lock); - - //envalue the address of host base on input-parameter. - if( !strncmp(buf,"sd-" , strlen("sd-")) ) - { - host = (struct rk29_sdmmc *)globalSDhost[RK29_CTRL_SDMMC_ID]; - if(!host) - { - printk("%s..%d.. fail to call progress_store because the host is null. ==xbw==\n",__FUNCTION__,__LINE__); - goto progress_store_out; - } - } - else if( !strncmp(buf,"sdio1-" , strlen("sdio1-")) ) - { - host = (struct rk29_sdmmc *)globalSDhost[RK29_CTRL_SDIO1_ID]; - if(!host) - { - printk("%s..%d.. fail to call progress_store because the host-sdio1 is null. ==xbw==\n",__FUNCTION__,__LINE__); - goto progress_store_out; - } - } - else if( !strncmp(buf,"sdio2-" , strlen("sdio2-")) ) - { - host = (struct rk29_sdmmc *)globalSDhost[RK29_CTRL_SDIO2_ID]; - if(!host) - { - printk("%s..%d.. fail to call progress_store because the host-sdio2 is null. ==xbw==\n",__FUNCTION__,__LINE__); - goto progress_store_out; - } - } - else - { - printk("%s..%d.. You want to use sysfs for SDMMC but input-parameter is wrong.====xbw====\n",__FUNCTION__,__LINE__); - goto progress_store_out;//return count; - } - - //printk(".%d.. MMC0 receive the message %s from VOLD.====xbw[%s]====\n", __LINE__, buf, host->dma_name); - - /* - * //deal with the message - * insert card state-change: No-Media ==> Pending ==> Idle-Unmounted ==> Checking ==>Mounted - * remove card state-change: Unmounting ==> Idle-Unmounted ==> No-Media - */ - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - if(!strncmp(buf, "sd-Unmounting", strlen("sd-Unmounting"))) - { - printk(".%d.. MMC0 receive the message State_Unmounting from VOLD.====xbw[%s]====\n", __LINE__, host->dma_name); - host->mmc->re_initialized_flags = 0; - mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY)); - } - else if( !strncmp(buf, "sd-No-Media", strlen("sd-No-Media"))) - { - printk(".%d.. MMC0 receive the message No-Media from VOLD.====xbw[%s]====\n" ,__LINE__, host->dma_name); - del_timer_sync(&host->detect_timer); - host->mmc->re_initialized_flags = 1; - - if(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) - { - mmc_detect_change(host->mmc, 0); - } - } - else if( !strncmp(buf, "sd-Ready", strlen("sd-Ready"))) - { - printk(".%d.. MMC0 receive the message State_Ready(ReInitFlag=%d) from VOLD.====xbw[%s]====\n" ,\ - __LINE__, host->mmc->re_initialized_flags, host->dma_name); - - if(0==host->mmc->re_initialized_flags) - { - host->mmc->re_initialized_flags = 1; - //del_timer_sync(&host->detect_timer); - } - } - else if( !strncmp(buf,"sd-reset" , strlen("sd-reset")) ) - { - printk(".%d.. Now manual reset for SDMMC0. ====xbw[%s]====\n",__LINE__, host->dma_name); - mmc_detect_change(host->mmc, 0); - } - else if( !strncmp(buf, "sd-regs", strlen("sd-regs"))) - { - printk(".%d.. Now printk the register of SDMMC0. ====xbw[%s]====\n",__LINE__, host->dma_name); - rk29_sdmmc_regs_printk(host); - } - - } - else if(RK29_CTRL_SDIO1_ID == host->pdev->id) - { - if( !strncmp(buf, "sdio1-regs", strlen("sdio1-regs"))) - { - printk(".%d.. Now printk the register of SDMMC1. ====xbw[%s]====\n",__LINE__, host->dma_name); - rk29_sdmmc_regs_printk(host); - } - else if( !strncmp(buf,"sdio1-reset" , strlen("sdio1-reset")) ) - { - printk(".%d.. Now manual reset for SDMMC1. ====xbw[%s]====\n",__LINE__, host->dma_name); - mmc_detect_change(host->mmc, 0); - } - } - else if(RK29_CTRL_SDIO2_ID == host->pdev->id) - { - if( !strncmp(buf, "sdio2-regs", strlen("sdio2-regs"))) - { - printk(".%d.. Now printk the register of SDMMC2. ====xbw[%s]====\n",__LINE__, host->dma_name); - rk29_sdmmc_regs_printk(host); - } - else if( !strncmp(buf,"sdio2-reset" , strlen("sdio2-reset")) ) - { - printk(".%d.. Now manual reset for SDMMC2. ====xbw[%s]====\n",__LINE__, host->dma_name); - mmc_detect_change(host->mmc, 0); - } - } - -progress_store_out: - spin_unlock(&host->lock); - - return count; -} + struct rk29_sdmmc *host = s->private; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_command *stop; + struct mmc_data *data; + /* Make sure we get a consistent snapshot */ + spin_lock(&host->lock); + mrq = host->mrq; + if (mrq) { + cmd = mrq->cmd; + data = mrq->data; + stop = mrq->stop; -struct kobj_attribute mmc_reset_attrs = -{ - .attr = { - .name = "rescan", - .mode = 0777}, - .show = NULL, - .store = rk29_sdmmc_progress_store, -}; -struct attribute *mmc_attrs[] = -{ - &mmc_reset_attrs.attr, - NULL -}; + if (cmd) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + cmd->opcode, cmd->arg, cmd->flags, + cmd->resp[0], cmd->resp[1], cmd->resp[2], + cmd->resp[2], cmd->error); + if (data) + seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", + data->bytes_xfered, data->blocks, + data->blksz, data->flags, data->error); + if (stop) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + stop->opcode, stop->arg, stop->flags, + stop->resp[0], stop->resp[1], stop->resp[2], + stop->resp[2], stop->error); + } -static struct kobj_type mmc_kset_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = &mmc_attrs[0], -}; + spin_unlock(&host->lock); -static int rk29_sdmmc_progress_add_attr( struct platform_device *pdev ) -{ - int result; - struct kobject *parentkobject; - struct kobject * me = kmalloc(sizeof(struct kobject) , GFP_KERNEL ); - if(!me) - { - return -ENOMEM; - } - memset(me ,0,sizeof(struct kobject)); - kobject_init( me , &mmc_kset_ktype ); - - parentkobject = &pdev->dev.kobj ; - result = kobject_add( me , parentkobject->parent->parent->parent,"%s", "sd-sdio" ); - - return result; + return 0; } -#endif -#if defined (CONFIG_DEBUG_FS) static int rk29_sdmmc_regs_show(struct seq_file *s, void *v) { struct rk29_sdmmc *host = s->private; @@ -460,51 +269,20 @@ static int rk29_sdmmc_regs_show(struct seq_file *s, void *v) return 0; } - -/* - * The debugfs stuff below is mostly optimized away when - * CONFIG_DEBUG_FS is not set. - */ -static int rk29_sdmmc_req_show(struct seq_file *s, void *v) +static int rk29_sdmmc_status_show(struct seq_file *s, void *v) { struct rk29_sdmmc *host = s->private; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_command *stop; - struct mmc_data *data; - - /* Make sure we get a consistent snapshot */ - spin_lock(&host->lock); - mrq = host->mrq; - - if (mrq) { - cmd = mrq->cmd; - data = mrq->data; - stop = mrq->stop; - - if (cmd) - seq_printf(s, - "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", - cmd->opcode, cmd->arg, cmd->flags, - cmd->resp[0], cmd->resp[1], cmd->resp[2], - cmd->resp[2], cmd->error); - if (data) - seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", - data->bytes_xfered, data->blocks, - data->blksz, data->flags, data->error); - if (stop) - seq_printf(s, - "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", - stop->opcode, stop->arg, stop->flags, - stop->resp[0], stop->resp[1], stop->resp[2], - stop->resp[2], stop->error); - } - spin_unlock(&host->lock); + seq_printf(s, "state: \t\t0x%08x\n", host->state); + seq_printf(s, "pending_events: \t0x%08lx\n", host->pending_events); + seq_printf(s, "completed_events: \t0x%08lx\n", host->completed_events); + seq_printf(s, "mrq_status: \t\t0x%08lx\n", host->mrq_status); + seq_printf(s, "old_mrq_status: \t0x%08lx\n", host->old_mrq_status); return 0; } + static int rk29_sdmmc_req_open(struct inode *inode, struct file *file) { return single_open(file, rk29_sdmmc_req_show, inode->i_private); @@ -518,7 +296,6 @@ static const struct file_operations rk29_sdmmc_req_fops = { .release = single_release, }; - static int rk29_sdmmc_regs_open(struct inode *inode, struct file *file) { return single_open(file, rk29_sdmmc_regs_show, inode->i_private); @@ -531,6 +308,18 @@ static const struct file_operations rk29_sdmmc_regs_fops = { .llseek = seq_lseek, .release = single_release, }; +static int rk29_sdmmc_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, rk29_sdmmc_status_show, inode->i_private); +} + +static const struct file_operations rk29_sdmmc_status_fops = { + .owner = THIS_MODULE, + .open = rk29_sdmmc_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; static void rk29_sdmmc_init_debugfs(struct rk29_sdmmc *host) { @@ -542,10 +331,7 @@ static void rk29_sdmmc_init_debugfs(struct rk29_sdmmc *host) if (!root) return; - node = debugfs_create_file("regs", S_IRUSR, root, host, - &rk29_sdmmc_regs_fops); - if (IS_ERR(node)) - return; + node = debugfs_create_file("regs", S_IRUSR, root, host,&rk29_sdmmc_regs_fops); if (!node) goto err; @@ -553,17 +339,7 @@ static void rk29_sdmmc_init_debugfs(struct rk29_sdmmc *host) if (!node) goto err; - node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); - if (!node) - goto err; - - node = debugfs_create_x32("pending_events", S_IRUSR, root, - (u32 *)&host->pending_events); - if (!node) - goto err; - - node = debugfs_create_x32("completed_events", S_IRUSR, root, - (u32 *)&host->completed_events); + node = debugfs_create_file("status", S_IRUSR, root, host, &rk29_sdmmc_status_fops); if (!node) goto err; @@ -573,1429 +349,502 @@ err: dev_err(&mmc->class_dev, "failed to initialize debugfs for host\n"); } #endif - - -static u32 rk29_sdmmc_prepare_command(struct mmc_command *cmd) +static void rk29_sdmmc_show_info(struct rk29_sdmmc *host) +{ + dev_info(host->dev, "state: \t\t0x%08x\n", host->state); + dev_info(host->dev, "pending_events: \t0x%08lx\n", host->pending_events); + dev_info(host->dev, "completed_events: \t0x%08lx\n", host->completed_events); + dev_info(host->dev, "mrq_status: \t\t0x%08lx\n\n", host->mrq_status); + dev_info(host->dev, "old_mrq_status: \t0x%08lx\n\n", host->old_mrq_status); + dev_info(host->dev, "SDMMC_CTRL: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTRL)); + dev_info(host->dev, "SDMMC_PWREN: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_PWREN)); + dev_info(host->dev, "SDMMC_CLKDIV: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKDIV)); + dev_info(host->dev, "SDMMC_CLKSRC: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKSRC)); + dev_info(host->dev, "SDMMC_CLKENA: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CLKENA)); + dev_info(host->dev, "SDMMC_TMOUT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TMOUT)); + dev_info(host->dev, "SDMMC_CTYPE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CTYPE)); + dev_info(host->dev, "SDMMC_BLKSIZ: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BLKSIZ)); + dev_info(host->dev, "SDMMC_BYTCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_BYTCNT)); + dev_info(host->dev, "SDMMC_INTMASK:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_INTMASK)); + dev_info(host->dev, "SDMMC_CMDARG: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMDARG)); + dev_info(host->dev, "SDMMC_CMD: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CMD)); + dev_info(host->dev, "SDMMC_RESP0: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP0)); + dev_info(host->dev, "SDMMC_RESP1: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP1)); + dev_info(host->dev, "SDMMC_RESP2: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP2)); + dev_info(host->dev, "SDMMC_RESP3: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RESP3)); + dev_info(host->dev, "SDMMC_MINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_MINTSTS)); + dev_info(host->dev, "SDMMC_RINTSTS:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_RINTSTS)); + dev_info(host->dev, "SDMMC_STATUS: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_STATUS)); + dev_info(host->dev, "SDMMC_FIFOTH: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_FIFOTH)); + dev_info(host->dev, "SDMMC_CDETECT:\t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_CDETECT)); + dev_info(host->dev, "SDMMC_WRTPRT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_WRTPRT)); + dev_info(host->dev, "SDMMC_TCBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TCBCNT)); + dev_info(host->dev, "SDMMC_TBBCNT: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_TBBCNT)); + dev_info(host->dev, "SDMMC_DEBNCE: \t0x%08x\n", rk29_sdmmc_read(host->regs, SDMMC_DEBNCE)); +} +static int rk29_sdmmc_reset_fifo(struct rk29_sdmmc *host) { - u32 cmdr = cmd->opcode; + int tmo; + int retry = RK29_SDMMC_TMO_COUNT; + if(!(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY|SDMMC_STAUTS_DATA_BUSY)) && + (rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) + return 0; - switch(cmdr) + while(retry--) { - case MMC_GO_IDLE_STATE: - cmdr |= (SDMMC_CMD_INIT | SDMMC_CMD_PRV_DAT_NO_WAIT); - break; - - case MMC_STOP_TRANSMISSION: - cmdr |= (SDMMC_CMD_STOP | SDMMC_CMD_PRV_DAT_NO_WAIT); - break; - case MMC_SEND_STATUS: - case MMC_GO_INACTIVE_STATE: - cmdr |= SDMMC_CMD_PRV_DAT_NO_WAIT; - break; - - default: - cmdr |= SDMMC_CMD_PRV_DAT_WAIT; - break; + tmo = RK29_SDMMC_TMO_COUNT; + rk29_sdmmc_write(host->regs, SDMMC_CTRL, rk29_sdmmc_read(host->regs, SDMMC_CTRL) | SDMMC_CTRL_FIFO_RESET); + while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CTRL) & SDMMC_CTRL_FIFO_RESET); + if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY|SDMMC_STAUTS_DATA_BUSY)) + udelay(5); + else + break; } - - /* response type */ - switch(mmc_resp_type(cmd)) - { - case MMC_RSP_R1: - case MMC_RSP_R1B: - // case MMC_RSP_R5: //R5,R6,R7 is same with the R1 - //case MMC_RSP_R6: - // case R6m_TYPE: - // case MMC_RSP_R7: - cmdr |= (SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_SHORT | SDMMC_CMD_RESP_EXP); - break; - case MMC_RSP_R3: - //case MMC_RSP_R4: - /* these response not contain crc7, so don't care crc error and response error */ - cmdr |= (SDMMC_CMD_RESP_NO_CRC | SDMMC_CMD_RESP_SHORT | SDMMC_CMD_RESP_EXP); - break; - case MMC_RSP_R2: - cmdr |= (SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_LONG | SDMMC_CMD_RESP_EXP); - break; - case MMC_RSP_NONE: - cmdr |= (SDMMC_CMD_RESP_CRC_NOCARE | SDMMC_CMD_RESP_NOCARE | SDMMC_CMD_RESP_NO_EXP); - break; - default: - cmdr |= (SDMMC_CMD_RESP_CRC_NOCARE | SDMMC_CMD_RESP_NOCARE | SDMMC_CMD_RESP_NO_EXP); - break; + if(retry <= 0){ + dev_dbg(host->dev, "%s error\n", __func__); + return -1; } - - return cmdr; + else + return 0; } - - -static int rk29_sdmmc_start_command(struct rk29_sdmmc *host, struct mmc_command *cmd, u32 cmd_flags) +static int rk29_sdmmc_reset_ctrl(struct rk29_sdmmc *host) { - int tmo = RK29_SDMMC_SEND_START_TIMEOUT; - - host->cmd = cmd; - host->old_cmd = cmd->opcode; - - rk29_sdmmc_write(host->regs, SDMMC_CMDARG, cmd->arg); // write to SDMMC_CMDARG register - rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); // write to SDMMC_CMD register + int tmo = RK29_SDMMC_TMO_COUNT; + /* + if(!(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY|SDMMC_STAUTS_DATA_BUSY))) + return 0; + */ + rk29_sdmmc_write(host->regs, SDMMC_CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + rk29_sdmmc_write(host->regs, SDMMC_CTRL, rk29_sdmmc_read(host->regs, SDMMC_CTRL) | SDMMC_CTRL_INT_ENABLE); + + if(tmo > 0) { + rk29_sdmmc_set_mrq_status(host, MRQ_RESET_CTRL_DONE); + host->is_init = 1; + return 0; + } + else { + rk29_sdmmc_set_mrq_status(host, MRQ_RESET_CTRL_ERR); + dev_err(host->dev, "%s error\n", __func__); + return -1; + } +} +static int rk29_sdmmc_start_command(struct rk29_sdmmc *host, + struct mmc_command *cmd, u32 cmd_flags) +{ + int tmo = RK29_SDMMC_TMO_COUNT; + unsigned long flags; - xbwprintk(5, "\n%s..%d..************.start cmd=%d, arg=0x%x ********=====xbw[%s]=======\n", \ - __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->dma_name); + local_irq_save(flags); + + rk29_sdmmc_write(host->regs, SDMMC_CMDARG, cmd->arg); + rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); + local_irq_restore(flags); - /* wait until CIU accepts the command */ - while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) - { + while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START) cpu_relax(); - } - - if(!tmo) - { - printk("%s..%d.. wait for CMD_START timeout!!!!!======xbw[%s]======\n",\ - __FUNCTION__,__LINE__, host->dma_name); + if(tmo > 0) + return 0; + else + return -1; +} - cmd->error = -ETIMEDOUT; - host->mrq->cmd->error = -ETIMEDOUT; - del_timer_sync(&host->request_timer); - - host->errorstep = 0x1; - return SDM_WAIT_FOR_CMDSTART_TIMEOUT; +static int send_stop_cmd(struct rk29_sdmmc *host) +{ + dev_dbg(host->dev,"start cmd:%d ARGR=0x%08x CMDR=0x%08x\n", + host->mrq->data->stop->opcode, host->mrq->data->stop->arg, host->stop_cmdr); + if(rk29_sdmmc_start_command(host, host->mrq->data->stop, host->stop_cmdr)) { + rk29_sdmmc_set_mrq_status(host, MRQ_STOP_START_TMO); + return -1; + } + else { + rk29_sdmmc_set_mrq_status(host, MRQ_STOP_START_DONE); + return 0; } - - return SDM_SUCCESS; } - -static int rk29_sdmmc_reset_fifo(struct rk29_sdmmc *host) +static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host) { - u32 value; - int timeout; - int ret = SDM_SUCCESS; - - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - if (!(value & SDMMC_STAUTS_FIFO_EMPTY)) - { - value = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - value |= SDMMC_CTRL_FIFO_RESET; - rk29_sdmmc_write(host->regs, SDMMC_CTRL, value); - - timeout = 1000; - while (((value = rk29_sdmmc_read(host->regs, SDMMC_CTRL)) & (SDMMC_CTRL_FIFO_RESET)) && (timeout > 0)) - { - udelay(1); - timeout--; - } - if (timeout == 0) - { - host->errorstep = 0x2; - ret = SDM_WAIT_FOR_FIFORESET_TIMEOUT; - } - } - - return ret; - + struct mmc_data *data = host->mrq->data; + if (data) + dma_unmap_sg(host->dev, data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); } -static int rk29_sdmmc_wait_unbusy(struct rk29_sdmmc *host) +static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host) { - int time_out = 250000; //max is 250ms + int ret = 0; + rk29_sdmmc_set_mrq_status(host, MRQ_STOP_DMA); + rk29_sdmmc_dma_cleanup(host); + ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); + if(ret < 0) + dev_err(host->dev, "stop dma:rk29_dma_ctrl stop error\n"); + ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); + if(ret < 0) + dev_err(host->dev, "stop dma:rk29_dma_ctrl flush error\n"); + rk29_sdmmc_write(host->regs, SDMMC_CTRL, + (rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE)); +} - while (rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_DATA_BUSY) - { - udelay(1); - time_out--; +static void rk29_sdmmc_request_done(struct rk29_sdmmc *host,struct mmc_request *mrq) +{ + int tmo = RK29_SDMMC_TMO_COUNT; - if(time_out == 0) - { - host->errorstep = 0x3; - return SDM_BUSY_TIMEOUT; - } + spin_unlock(&host->lock); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, + rk29_sdmmc_read(host->regs, SDMMC_INTMASK) & + ~(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS)); + + if(!rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) && + rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)) + rk29_sdmmc_stop_dma(host); + if(mrq->stop && !rk29_sdmmc_test_mrq_status(host, MRQ_STOP_START_DONE)) + send_stop_cmd(host); + if(mrq->cmd->opcode == 17 && (host->data_intsts & SDMMC_INT_SBE)){ + rk29_sdmmc_write(host->regs, SDMMC_CMD, 12|SDMMC_CMD_STOP | SDMMC_CMD_START); + while (--tmo && rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START); } - - return SDM_SUCCESS; + if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_FULL ){ + rk29_sdmmc_read(host->regs, SDMMC_DATA); + rk29_sdmmc_read(host->regs, SDMMC_DATA); + } + //if(mrq->data && mrq->data->error) + rk29_sdmmc_reset_fifo(host); + + host->mrq = NULL; + host->state = STATE_IDLE; + rk29_sdmmc_set_mrq_status(host, MRQ_REQUEST_DONE); + mmc_request_done(host->mmc, mrq); + del_timer(&host->monitor_timer); + + spin_lock(&host->lock); } -static void send_stop_cmd(struct rk29_sdmmc *host) +static int sdmmc_send_cmd(struct rk29_sdmmc *host, unsigned int cmd, int arg) { - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+2500)); - - host->stopcmd.opcode = MMC_STOP_TRANSMISSION; - host->stopcmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;; - host->stopcmd.arg = 0; - host->stopcmd.data = NULL; - host->stopcmd.mrq = NULL; - host->stopcmd.retries = host->cmd->retries; - - host->cmdr = rk29_sdmmc_prepare_command(&host->stopcmd); - rk29_sdmmc_start_command(host, &host->stopcmd, host->cmdr); + int tmo = RK29_SDMMC_TMO_COUNT; + rk29_sdmmc_write(host->regs, SDMMC_CMDARG, arg); + rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd); + while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START); + if(tmo > 0) + return 0; + else + return -1; } -static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host) +int rk29_sdmmc_set_clock(struct rk29_sdmmc *host) { - if (host->data) - { - dma_unmap_sg(&host->pdev->dev, host->data->sg, host->data->sg_len, - ((host->data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); - } + unsigned int div; + if(!host->ios_clock) + return 0; + div = (((host->bus_hz + (host->bus_hz / 5)) / host->ios_clock)) >> 1; +/* + if(div == 0) + div = 1; +*/ + if(host->div == div) + return 0; + + rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0); + rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); + if(sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0)) + goto send_cmd_err; + rk29_sdmmc_write(host->regs, SDMMC_CLKDIV, div); + host->div = div; + host->clock = (div == 0)? host->bus_hz :(host->bus_hz / div) >> 1; + if(sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0)) + goto send_cmd_err; + rk29_sdmmc_write(host->regs, SDMMC_CLKENA, SDMMC_CLKEN_ENABLE); + if(sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0)) + goto send_cmd_err; + + rk29_sdmmc_set_mrq_status(host, MRQ_CLK_START_DONE); + return 0; +send_cmd_err: + rk29_sdmmc_set_mrq_status(host, MRQ_CLK_START_TMO); + return -1; } -static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host) +static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { - int ret = 0; - - if(host->use_dma == 0) - return; - - if (host->dma_info.chn> 0) - { - rk29_sdmmc_dma_cleanup(host); - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); - if(ret < 0) - { - printk("%s..%d...rk29_dma_ctrl STOP error!===xbw[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x95; - return; - } + struct rk29_sdmmc *host = mmc_priv(mmc);; - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); - if(ret < 0) - { - printk("%s..%d...rk29_dma_ctrl FLUSH error!===xbw[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x96; - return; - } - - } - else - { - /* Data transfer was stopped by the interrupt handler */ - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + rk29_sdmmc_write(host->regs, SDMMC_CTYPE, 0); + break; + case MMC_BUS_WIDTH_4: + rk29_sdmmc_write(host->regs, SDMMC_CTYPE, SDMMC_CTYPE_4BIT); + break; + } + host->ios_clock = ios->clock; + + switch (ios->power_mode) { + case MMC_POWER_UP: + host->is_init = 1; + rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1); + break; + default: + break; } } -static void rk29_sdmmc_control_host_dma(struct rk29_sdmmc *host, bool enable) +static int rk29_sdmmc_get_ro(struct mmc_host *mmc) { - u32 value = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - - if (enable) - { - value |= SDMMC_CTRL_DMA_ENABLE; - } - else - { - value &= ~(SDMMC_CTRL_DMA_ENABLE); - } + struct rk29_sdmmc *host = mmc_priv(mmc); + u32 wrtprt = rk29_sdmmc_read(host->regs, SDMMC_WRTPRT); - rk29_sdmmc_write(host->regs, SDMMC_CTRL, value); + return (wrtprt & SDMMC_WRITE_PROTECT)?1:0; } -/* This function is called by the DMA driver from tasklet context. */ -static void rk29_sdmmc_dma_complete(void *arg, int size, enum rk29_dma_buffresult result) -{ - struct rk29_sdmmc *host = arg; - - if(host->use_dma == 0) - return; - - host->intInfo.transLen = host->intInfo.desLen; -} - -static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data *data) +static int rk29_sdmmc_get_cd(struct mmc_host *mmc) { - struct scatterlist *sg; - unsigned int i,direction, sgDirection; - int ret, dma_len=0; - - if(host->use_dma == 0) - { - printk("%s..%d...setup DMA fail!!!!!!. host->use_dma=0 ===xbw=[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x4; - return -ENOSYS; - } - /* If we don't have a channel, we can't do DMA */ - if (host->dma_info.chn < 0) - { - printk("%s..%d...setup DMA fail!!!!!!!. dma_info.chn < 0 ===xbw[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x5; - return -ENODEV; - } + struct rk29_sdmmc *host = mmc_priv(mmc); - if (data->blksz & 3) - return -EINVAL; - for_each_sg(data->sg, sg, data->sg_len, i) - { - if (sg->offset & 3 || sg->length & 3) - { - printk("%s..%d...call for_each_sg() fail !!===xbw[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x7; - return -EINVAL; - } - } - if (data->flags & MMC_DATA_READ) - { - direction = RK29_DMASRC_HW; - sgDirection = DMA_FROM_DEVICE; - } + if(host->is_sdio) + return host->get_wifi_cd(mmc_dev(host->mmc)); + else if(host->gpio_det == INVALID_GPIO) + return 1; else - { - direction = RK29_DMASRC_MEM; - sgDirection = DMA_TO_DEVICE; - } - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); - if(ret < 0) - { - printk("%s..%d...rk29_dma_ctrl stop error!===xbw[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x91; - return -ENOSYS; - } - - ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); - if(ret < 0) - { - printk("%s..%d...rk29_dma_ctrl flush error!===xbw[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x91; - return -ENOSYS; - } - - - ret = rk29_dma_devconfig(host->dma_info.chn, direction, (unsigned long )(host->dma_addr)); - if(0 != ret) - { - printk("%s..%d...call rk29_dma_devconfig() fail !!!!===xbw=[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x8; - return -ENOSYS; - } - - dma_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, sgDirection); - for (i = 0; i < dma_len; i++) - { - ret = rk29_dma_enqueue(host->dma_info.chn, host, sg_dma_address(&data->sg[i]),sg_dma_len(&data->sg[i])); - if(ret < 0) - { - printk("%s..%d...call rk29_dma_devconfig() fail !!!!===xbw=[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x93; - return -ENOSYS; - } - } - - rk29_sdmmc_control_host_dma(host, TRUE);// enable dma - ret = rk29_dma_ctrl(host->dma_info.chn, RK29_DMAOP_START); - if(ret < 0) - { - printk("%s..%d...rk29_dma_ctrl start error!===xbw[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - host->errorstep = 0x94; - return -ENOSYS; - } - - return 0; + return gpio_get_value(host->gpio_det)?0:1; } - -static int rk29_sdmmc_prepare_write_data(struct rk29_sdmmc *host, struct mmc_data *data) -{ - //uint32 value; - int output; - u32 i = 0; - u32 dataLen; - u32 count, *pBuf = (u32 *)host->pbuf; - - output = SDM_SUCCESS; - dataLen = data->blocks*data->blksz; - - host->dodma = 0; //DMA still no request; - - //SDMMC controller request the data is multiple of 4. - count = (dataLen >> 2) + ((dataLen & 0x3) ? 1:0); - - if (count <= FIFO_DEPTH) - { - for (i=0; iregs, SDMMC_DATA, pBuf[i]); - } - } - else - { - host->intInfo.desLen = count; - host->intInfo.transLen = 0; - host->intInfo.pBuf = (u32 *)pBuf; - - if(0)//(host->intInfo.desLen <= 512 ) - { - //ʹÓÃpioģʽ - return SDM_SUCCESS; - } - else - { - xbwprintk(3, "%s..%d... trace data, ======xbw=[%s]====\n", __FUNCTION__, __LINE__, host->dma_name); - output = rk29_sdmmc_submit_data_dma(host, data); - if(output) - { - host->dodma = 0; - - printk("%s..%d... CMD%d setupDMA failure!!!!! ==xbw[%s]==\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode, host->dma_name); - - host->errorstep = 0x81; - - rk29_sdmmc_control_host_dma(host, FALSE); - } - else - { - host->dodma = 1; - } - } - - } - - return output; -} - - - - -static int rk29_sdmmc_prepare_read_data(struct rk29_sdmmc *host, struct mmc_data *data) +static inline unsigned ns_to_clocks(unsigned clkrate, unsigned ns) { - u32 count = 0; - u32 dataLen; - int output; - - output = SDM_SUCCESS; - dataLen = data->blocks*data->blksz; - - host->dodma = 0;//DMA still no request; - - //SDMMC controller request the data is multiple of 4. - count = (dataLen >> 2) ;//+ ((dataLen & 0x3) ? 1:0); - - host->intInfo.desLen = (dataLen >> 2); - host->intInfo.transLen = 0; - host->intInfo.pBuf = (u32 *)host->pbuf; - - if (count > (RX_WMARK+1)) //datasheet error.actually, it can nont waken the interrupt when less and equal than RX_WMARK+1 - { - if(0) //(host->intInfo.desLen <= 512 ) - { - //ʹÓÃpioģʽ - return SDM_SUCCESS; - } - else - { - output = rk29_sdmmc_submit_data_dma(host, data); - if(output) - { - host->dodma = 0; - - printk("%s..%d... CMD%d setupDMA failure!!! ==xbw[%s]==\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode, host->dma_name); - - host->errorstep = 0x82; - - rk29_sdmmc_control_host_dma(host, FALSE); - } - else - { - host->dodma = 1; - } - } - } - - return output; -} - - + u32 clks; + if (clkrate > 1000000) + clks = (ns * (clkrate / 1000000) + 999) / 1000; + else + clks = ((ns/1000) * (clkrate / 1000) + 999) / 1000; -static int rk29_sdmmc_read_remain_data(struct rk29_sdmmc *host, u32 originalLen, void *pDataBuf) -{ - u32 value = 0; - - u32 i = 0; - u32 *pBuf = (u32 *)pDataBuf; - u8 *pByteBuf = (u8 *)pDataBuf; - u32 lastData = 0; - - //SDMMC controller must be multiple of 32. so if transfer 13, then actuall we should write or read 16 byte. - u32 count = (originalLen >> 2) + ((originalLen & 0x3) ? 1:0); - - if(1 == host->dodma) - { - //when use DMA, there are remain data only when datalen/4 less than RX_WMARK+1 same as equaltion. or not multiple of 4 - if (!((value = rk29_sdmmc_read(host->regs, SDMMC_STATUS)) & SDMMC_STAUTS_FIFO_EMPTY)) - { - if (count <= (RX_WMARK+1)) - { - i = 0; - while ((i<(originalLen >> 2))&&(!(value & SDMMC_STAUTS_FIFO_EMPTY))) - { - pBuf[i++] = rk29_sdmmc_read(host->regs, SDMMC_DATA); - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - } - } - - if (count > (originalLen >> 2)) - { - lastData = rk29_sdmmc_read(host->regs, SDMMC_DATA); - - //fill the 1 to 3 byte. - for (i=0; i<(originalLen & 0x3); i++) - { - pByteBuf[(originalLen & 0xFFFFFFFC) + i] = (u8)((lastData >> (i << 3)) & 0xFF); //default little-endian - } - } - } - } - else - { - if (!((value = rk29_sdmmc_read(host->regs, SDMMC_STATUS)) & SDMMC_STAUTS_FIFO_EMPTY)) - { - while ( (host->intInfo.transLen < host->intInfo.desLen) && (!(value & SDMMC_STAUTS_FIFO_EMPTY)) ) - { - pBuf[host->intInfo.transLen++] = rk29_sdmmc_read(host->regs, SDMMC_DATA); - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - } - - if (count > (originalLen >> 2)) - { - lastData = rk29_sdmmc_read(host->regs, SDMMC_DATA); - - //fill the 1 to 3 byte. - for (i=0; i<(originalLen & 0x3); i++) - { - pByteBuf[(originalLen & 0xFFFFFFFC) + i] = (u8)((lastData >> (i << 3)) & 0xFF); //default little-endian - } - } - } - } - - return SDM_SUCCESS; + return clks; } - -static void rk29_sdmmc_do_pio_read(struct rk29_sdmmc *host) +static void rk29_sdmmc_set_timeout(struct rk29_sdmmc *host,struct mmc_data *data) { - int i; - for (i=0; i<(RX_WMARK+1); i++) - { - host->intInfo.pBuf[host->intInfo.transLen + i] = rk29_sdmmc_read(host->regs, SDMMC_DATA); - } - host->intInfo.transLen += (RX_WMARK+1); + unsigned timeout; + unsigned int clock; + + if(host->div == -1) + return; + else if(host->div == 0) + clock = host->bus_hz; + else + clock = (host->bus_hz / host->div) >> 1; + timeout = ns_to_clocks(clock, data->timeout_ns) + data->timeout_clks; + rk29_sdmmc_write(host->regs, SDMMC_TMOUT, 0xffffffff); + //rk29_sdmmc_write(host->regs, SDMMC_TMOUT, (timeout << 8) | (70)); } - -static void rk29_sdmmc_do_pio_write(struct rk29_sdmmc *host) +static u32 rk29_sdmmc_prepare_command(struct mmc_host *mmc, + struct mmc_command *cmd) { - int i; - if ( (host->intInfo.desLen - host->intInfo.transLen) > (FIFO_DEPTH - TX_WMARK) ) - { - for (i=0; i<(FIFO_DEPTH - TX_WMARK); i++) - { - rk29_sdmmc_write(host->regs, SDMMC_DATA, host->intInfo.pBuf[host->intInfo.transLen + i]); - } - host->intInfo.transLen += (FIFO_DEPTH - TX_WMARK); - } - else - { - for (i=0; i<(host->intInfo.desLen - host->intInfo.transLen); i++) - { - rk29_sdmmc_write(host->regs, SDMMC_DATA, host->intInfo.pBuf[host->intInfo.transLen + i]); - } - host->intInfo.transLen = host->intInfo.desLen; - } - -} + struct mmc_data *data; + u32 cmdr; + + cmd->error = -EINPROGRESS; + cmdr = cmd->opcode; + if(cmdr == 12) + cmdr |= SDMMC_CMD_STOP; + else if(cmdr == 13) + cmdr &= ~SDMMC_CMD_PRV_DAT_WAIT; + else + cmdr |= SDMMC_CMD_PRV_DAT_WAIT; -static void rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *data) -{ - int ret; - - if(data) - { - host->data = data; - data->error = 0; - - data->bytes_xfered = 0; - host->pbuf = (u32*)sg_virt(data->sg); - - if (data->flags & MMC_DATA_STREAM) - { - host->cmdr |= SDMMC_CMD_STRM_MODE; //set stream mode - } - else - { - host->cmdr |= SDMMC_CMD_BLOCK_MODE; //set block mode - } + if (cmd->flags & MMC_RSP_PRESENT) { + cmdr |= SDMMC_CMD_RESP_EXP; // expect the respond, need to set this bit + if (cmd->flags & MMC_RSP_136) + cmdr |= SDMMC_CMD_RESP_LONG; // expect long respond - //set the blocks and blocksize - rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,data->blksz*data->blocks); - rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,data->blksz); - - xbwprintk(3, "%s..%d... trace data, CMD%d, data->blksz=%d, data->blocks=%d ======xbw=[%s]====\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode,data->blksz, data->blocks, host->dma_name); - - if (data->flags & MMC_DATA_WRITE) - { - host->cmdr |= (SDMMC_CMD_DAT_WRITE | SDMMC_CMD_DAT_EXP); - xbwprintk(3, "%s..%d... write data, len=%d ======xbw=[%s]====\n", \ - __FUNCTION__, __LINE__, data->blksz*data->blocks, host->dma_name); - - ret = rk29_sdmmc_prepare_write_data(host, data); - } - else - { - host->cmdr |= (SDMMC_CMD_DAT_READ | SDMMC_CMD_DAT_EXP); - xbwprintk(3, "%s..%d... read data len=%d ======xbw=[%s]====\n", \ - __FUNCTION__, __LINE__, data->blksz*data->blocks, host->dma_name); - - ret = rk29_sdmmc_prepare_read_data(host, data); - } - - } - else - { - rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ, 0); - rk29_sdmmc_write(host->regs, SDMMC_BYTCNT, 0); - } -} - - -static int sdmmc_send_cmd_start(struct rk29_sdmmc *host, unsigned int cmd) -{ - int tmo = 1000; - - rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd); - while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START) - { - cpu_relax(); + if(cmd->flags & MMC_RSP_CRC) + cmdr |= SDMMC_CMD_RESP_CRC; } - - if(!tmo) - { - printk("%s.. %d set cmd(value=0x%x) register timeout error ! ====xbw[%s]====\n",\ - __FUNCTION__,__LINE__, cmd, host->dma_name); - host->errorstep = 0x9; - return SDM_START_CMD_FAIL; + data = cmd->data; + if (data) { + cmdr |= SDMMC_CMD_DAT_EXP; + if (data->flags & MMC_DATA_STREAM) + cmdr |= SDMMC_CMD_STRM_MODE; // set stream mode + if (data->flags & MMC_DATA_WRITE) + cmdr |= SDMMC_CMD_DAT_WR; } - - return SDM_SUCCESS; -} - -static int rk29_sdmmc_get_cd(struct mmc_host *mmc) -{ - struct rk29_sdmmc *host = mmc_priv(mmc); - u32 cdetect; - -#ifdef CONFIG_PM - if(host->gpio_det == INVALID_GPIO) - return 1; -#endif - - cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT); - - return (cdetect & SDMMC_CARD_DETECT_N)?0:1; + return cmdr; } - - -/****************************************************************/ -//reset the SDMMC controller of the current host -/****************************************************************/ -int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host) +static int rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *data) { - u32 value = 0; - int timeOut = 0; - - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); - - /* reset SDMMC IP */ - //SDPAM_SDCClkEnable(host, TRUE); - - //Clean the fifo. - for(timeOut=0; timeOutregs, SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY) - break; - - value = rk29_sdmmc_read(host->regs, SDMMC_DATA); - } - - /* reset */ - rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET )); - - timeOut = 1000; - value = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - while (( value & (SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_RESET)) && (timeOut > 0)) - { - udelay(1); - timeOut--; - value = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - } - - if (timeOut == 0) - { - printk("%s..%s..%d.. reset controller fail!!! =====xbw[%s]=====\n",\ - __FILE__, __FUNCTION__,__LINE__, host->dma_name); - - host->errorstep = 0x0A; - return SDM_WAIT_FOR_FIFORESET_TIMEOUT; - } - - /* FIFO threshold settings */ - rk29_sdmmc_write(host->regs, SDMMC_FIFOTH, (SD_MSIZE_16 | (RX_WMARK << RX_WMARK_SHIFT) | (TX_WMARK << TX_WMARK_SHIFT))); - - rk29_sdmmc_write(host->regs, SDMMC_CTYPE, SDMMC_CTYPE_1BIT); - rk29_sdmmc_write(host->regs, SDMMC_CLKSRC, CLK_DIV_SRC_0); - /* config debounce */ - host->bus_hz = clk_get_rate(host->clk); - if((host->bus_hz > 52000000) || (host->bus_hz <= 0)) - { - printk("%s..%s..%d..****Error!!!!!! Bus clock %d hz is beyond the prescribed limits ====xbw[%s]===\n",\ - __FILE__, __FUNCTION__,__LINE__,host->bus_hz, host->dma_name); - - host->errorstep = 0x0B; - return SDM_PARAM_ERROR; - } - - rk29_sdmmc_write(host->regs, SDMMC_DEBNCE, (DEBOUNCE_TIME*host->bus_hz)&0xFFFFFF); - - /* config interrupt */ - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); + struct scatterlist *sg; + unsigned int i,direction; + int dma_len=0, ret = 0; - if(host->use_dma) - { - if(0 == host->pdev->id) - { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA); - } - else - { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEDMA | SDMMC_INT_SDIO); + if (data->blksz & 3){ + dev_info(host->dev, "data->blksz = %d\n", data->blksz); + return -EINVAL; + } + for_each_sg(data->sg, sg, data->sg_len, i) { + if (sg->offset & 3 || sg->length & 3){ + dev_info(host->dev, "sg->offset = %d, sg->length = %d\n", + sg->offset, sg->length); + return -EINVAL; } } + if (data->flags & MMC_DATA_READ) + direction = RK29_DMASRC_HW; else - { - if(0 == host->pdev->id) - { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO); - } - else - { - rk29_sdmmc_write(host->regs, SDMMC_INTMASK,RK29_SDMMC_INTMASK_USEIO | SDMMC_INT_SDIO); - } - } - - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); + direction = RK29_DMASRC_MEM; - rk29_sdmmc_write(host->regs, SDMMC_CTRL,SDMMC_CTRL_INT_ENABLE); // enable mci interrupt - - return SDM_SUCCESS; -} - - - - -//enable/disnable the clk. -static int rk29_sdmmc_control_clock(struct rk29_sdmmc *host, bool enable) -{ - u32 value = 0; - int tmo = 0; - int ret = SDM_SUCCESS; - - //wait previous start to clear - tmo = 1000; - while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) - { - cpu_relax(); - } - if(!tmo) - { - host->errorstep = 0x0C; - ret = SDM_START_CMD_FAIL; - goto Error_exit; - } - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - //SDMMC use low-power mode - if (enable) - { - value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_ENABLE); - } - else - { - value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_DISABLE); - } - } - else - { - //SDIO-card use non-low-power mode - if (enable) - { - value = (SDMMC_CLKEN_ENABLE); - } - else - { - value = (SDMMC_CLKEN_DISABLE); - } - } - - rk29_sdmmc_write(host->regs, SDMMC_CLKENA, value); - - /* inform CIU */ - ret = sdmmc_send_cmd_start(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT); - if(ret != SDM_SUCCESS) - { - goto Error_exit; - } - - return SDM_SUCCESS; - -Error_exit: - printk("\n%s....%d.. control clock fail!!! Enable=%d, ret=%d ===xbw[%s]====\n",\ - __FILE__,__LINE__,enable,ret, host->dma_name); - - return ret; - -} - - -//adjust the frequency.ie, to set the frequency division control -int rk29_sdmmc_change_clk_div(struct rk29_sdmmc *host, u32 freqHz) -{ - u32 div; - u32 tmo; - int ret = SDM_SUCCESS; - - if(0 == freqHz) - { - ret = SDM_PARAM_ERROR; - goto SetFreq_error; - } - - ret = rk29_sdmmc_control_clock(host, FALSE); - if (ret != SDM_SUCCESS) - { - goto SetFreq_error; - } - - - host->bus_hz = clk_get_rate(host->clk); - if((host->bus_hz > 52000000) || (host->bus_hz <= 0)) - { - printk("%s..%s..%d..****Error!!!!!! Bus clock %d hz is beyond the prescribed limits ====xbw[%s]===\n",\ - __FILE__, __FUNCTION__,__LINE__,host->bus_hz, host->dma_name); - - host->errorstep = 0x0D; - ret = SDM_PARAM_ERROR; - goto SetFreq_error; - } - - //calculate the divider - div = host->bus_hz/freqHz + ((( host->bus_hz%freqHz ) > 0) ? 1:0 ); - if( (div & 0x01) && (1 != div) ) - { - //It is sure that the value of div is even. - ++div; - } - - if(div > 1) - { - host->clock = host->bus_hz/div; - } - else - { - host->clock = host->bus_hz; - } - div = (div >> 1); - - //wait previous start to clear - tmo = 1000; - while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) - { - cpu_relax(); - } - if(!tmo) - { - host->errorstep = 0x0E; - ret = SDM_START_CMD_FAIL; - goto SetFreq_error; - } - - /* set clock to desired speed */ - rk29_sdmmc_write(host->regs, SDMMC_CLKDIV, div); - - /* inform CIU */ - ret = sdmmc_send_cmd_start(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT); - if(ret != SDM_SUCCESS) - { - host->errorstep = 0x0E1; - goto SetFreq_error; - } - - if(host->old_div != div) - { - printk("%s..%d.. newDiv=%u, newCLK=%uKhz====xbw[%s]=====\n", \ - __FUNCTION__, __LINE__,div, host->clock/1000, host->dma_name); - } - - ret = rk29_sdmmc_control_clock(host, TRUE); - if(ret != SDM_SUCCESS) - { - goto SetFreq_error; - } - host->old_div = div; - - return SDM_SUCCESS; - -SetFreq_error: - - printk("%s..%s..%d.. change division fail, ret=%d !!! ====xbw[%s]====\n",\ - __FILE__, __FUNCTION__,__LINE__,ret, host->dma_name); - - return ret; - -} - - - -static int rk29_sdmmc_hw_init(struct rk29_sdmmc *host) -{ - /* reset controller */ - rk29_sdmmc_reset_controller(host); - rk29_sdmmc_change_clk_div(host, FOD_FREQ); - - return SDM_SUCCESS; -} - - - -int rk29_sdmmc_set_iomux(struct rk29_sdmmc *host) -{ - #if 0 - switch (host->busWidth) - { - case - rk29_mux_api_set(GPIO1D1_SDMMC0CMD_NAME, GPIO1H_SDMMC0_CMD); - rk29_mux_api_set(GPIO1D0_SDMMC0CLKOUT_NAME, GPIO1H_SDMMC0_CLKOUT); - rk29_mux_api_set(GPIO1D2_SDMMC0DATA0_NAME, GPIO1H_SDMMC0_DATA0); - rk29_mux_api_set(GPIO1D3_SDMMC0DATA1_NAME, GPIO1H_SDMMC0_DATA1); - rk29_mux_api_set(GPIO1D4_SDMMC0DATA2_NAME, GPIO1H_SDMMC0_DATA2); + ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP); + if(ret < 0) + dev_err(host->dev, "rk29_dma_ctrl stop error\n"); + ret = rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH); + if(ret < 0) + dev_err(host->dev, "rk29_dma_ctrl flush error\n"); + ret = rk29_dma_devconfig(host->dma_info.chn, direction, (unsigned long )(host->dma_addr)); + if(ret < 0) + dev_err(host->dev, "rk29_dma_devconfig error\n"); + dma_len = dma_map_sg(host->dev, data->sg, data->sg_len, + (data->flags & MMC_DATA_READ)? DMA_FROM_DEVICE : DMA_TO_DEVICE); + for (i = 0; i < dma_len; i++) { + ret = rk29_dma_enqueue(host->dma_info.chn, host, sg_dma_address(&data->sg[i]),sg_dma_len(&data->sg[i])); // data->sg->dma_address, data->sg->length); + if(ret < 0) + dev_err(host->dev, "rk29 dma enqueue error\n"); } - #endif - + rk29_sdmmc_write(host->regs, SDMMC_CTRL, (rk29_sdmmc_read(host->regs, SDMMC_CTRL))|SDMMC_CTRL_DMA_ENABLE);// enable dma + ret = rk29_dma_ctrl(host->dma_info.chn, RK29_DMAOP_START); + if(ret < 0) + dev_err(host->dev, "rk29_dma_ctrl start error\n"); + rk29_sdmmc_set_mrq_status(host, MRQ_START_DMA); return 0; } - -int rk29_sdmmc_set_buswidth(struct rk29_sdmmc *host) +static int rk29_sdmmc_test_cmd_start(struct rk29_sdmmc *host) { - //int ret; - switch (host->ctype) - { - case SDMMC_CTYPE_1BIT: - case SDMMC_CTYPE_4BIT: - break; - case SDMMC_CTYPE_8BIT: - return SDM_PARAM_ERROR; //Now, not support 8 bit width - default: - return SDM_PARAM_ERROR; - } - rk29_sdmmc_set_iomux(host); - - /* Set the current bus width */ - rk29_sdmmc_write(host->regs, SDMMC_CTYPE, host->ctype); - - return SDM_SUCCESS; + return rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START; } - - -void rk29_sdmmc_set_frq(struct rk29_sdmmc *host) +static int rk29_sdmmc_start_request(struct rk29_sdmmc *host,struct mmc_request *mrq) { - struct mmc_host *mmchost = platform_get_drvdata(host->pdev); - struct mmc_card *card; - struct mmc_ios *ios; - unsigned int max_dtr; - - extern void mmc_set_clock(struct mmc_host *host, unsigned int hz); - - if(!mmchost) - return; - - card = (struct mmc_card *)mmchost->card; - ios = ( struct mmc_ios *)&mmchost->ios; - - if(!card && !ios) - return; - - if(MMC_POWER_ON == ios->power_mode) - return; - - max_dtr = (unsigned int)-1; - - if (mmc_card_highspeed(card)) - { - if (max_dtr > card->ext_csd.hs_max_dtr) - max_dtr = card->ext_csd.hs_max_dtr; - - } - else if (max_dtr > card->csd.max_dtr) - { - if(MMC_TYPE_SD == card->type) - { - max_dtr = (card->csd.max_dtr > SD_FPP_FREQ) ? SD_FPP_FREQ : (card->csd.max_dtr); - } - else - { - max_dtr = (card->csd.max_dtr > MMC_FPP_FREQ) ? MMC_FPP_FREQ : (card->csd.max_dtr); - } - } - - xbwprintk(7, "%s..%d... call mmc_set_clock() set clk=%d ===xbw[%s]===\n", \ - __FUNCTION__, __LINE__, max_dtr, host->dma_name); - - - mmc_set_clock(mmchost, max_dtr); - -} - -static void rk29_sdmmc_dealwith_timeout(struct rk29_sdmmc *host) -{ - switch(host->state) - { - case STATE_IDLE: - { - #if 1 - break; - #else - if(!host->cmd) - break; - - host->cmd->error = -EIO; - - if(host->cmd->data) - { - host->cmd->data->error = -EILSEQ; - } - host->state = STATE_SENDING_CMD; - /* fall through */ - #endif - } - - case STATE_SENDING_CMD: - host->cmd_status |= SDMMC_INT_RTO; - host->cmd->error = -ETIME; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,(SDMMC_INT_CMD_DONE | SDMMC_INT_RTO)); // clear interrupt - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); - break; - case STATE_DATA_BUSY: - host->data_status |= (SDMMC_INT_DCRC|SDMMC_INT_EBE); - host->cmd->data->error = -EILSEQ; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); // clear interrupt - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); - tasklet_schedule(&host->tasklet); - break; - case STATE_SENDING_STOP: - host->cmd_status |= SDMMC_INT_RTO; - host->cmd->error = -ETIME; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,(SDMMC_INT_CMD_DONE | SDMMC_INT_RTO)); // clear interrupt - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); - break; - } -} - - -static void rk29_sdmmc_INT_CMD_DONE_timeout(unsigned long host_data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data; + int ret = 0; + struct mmc_command *cmd; + u32 cmdflags; - if(STATE_SENDING_CMD == host->state) - { - if(0==host->cmd->retries) - { - printk("%s..%d... cmd=%d, INT_CMD_DONE timeout, errorStep=0x%x, host->state=%x ===xbw[%s]===\n",\ - __FUNCTION__, __LINE__,host->cmd->opcode, host->errorstep,host->state,host->dma_name); - } - - rk29_sdmmc_dealwith_timeout(host); - } + BUG_ON(host->state != STATE_IDLE); -} - - -static void rk29_sdmmc_INT_DTO_timeout(unsigned long host_data) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *) host_data; - - - if( (host->cmdr & SDMMC_CMD_DAT_EXP) && (STATE_DATA_BUSY == host->state)) - { - if(0==host->cmd->retries) - { - printk("%s..%d... cmd=%d INT_DTO timeout,cmdr=0x%x, host->errorStep=0x%x, Hoststate=%x===xbw[%s]===\n", \ - __FUNCTION__, __LINE__,host->cmd->opcode,host->cmdr ,host->errorstep,host->state,host->dma_name); - } + spin_lock(&host->lock); - rk29_sdmmc_dealwith_timeout(host); + if(rk29_sdmmc_test_cmd_start(host)){ + dev_info(host->dev, "cmd_start bit is set ,reset ctroller\n"); + ret = rk29_sdmmc_reset_ctrl(host); } - -} - - -//to excute a request -static int rk29_sdmmc_start_request(struct mmc_host *mmc ) -{ - struct rk29_sdmmc *host = mmc_priv(mmc); - struct mmc_request *mrq; - struct mmc_command *cmd; - - u32 cmdr, ret; - unsigned long iflags; - - spin_lock_irqsave(&host->lock, iflags); - - //host->mrq = host->new_mrq; - mrq = host->new_mrq;//mrq = host->mrq; - cmd = mrq->cmd; - cmd->error = 0; + if(ret < 0) + goto start_err; - cmdr = rk29_sdmmc_prepare_command(cmd); - ret = SDM_SUCCESS; + host->state = STATE_SENDING_CMD; - - /*clean FIFO if it is a new request*/ - if((RK29_CTRL_SDMMC_ID == host->pdev->id) && ( !(cmdr & SDMMC_CMD_STOP))) - { - ret = rk29_sdmmc_reset_fifo(host); - if(SDM_SUCCESS != ret) - { - host->mrq = host->new_mrq;/// - cmd->error = -ENOMEDIUM; - host->errorstep = 0x0F; - ret = SDM_FALSE; - goto start_request_Err; - } - } - - //check data-busy if the current command has the bit13 in command register. - if( cmdr & SDMMC_CMD_PRV_DAT_WAIT ) - { - if(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_DATA_BUSY) - { - host->mrq = host->new_mrq;/// - cmd->error = -ETIMEDOUT; - ret = SDM_BUSY_TIMEOUT; - host->errorstep = 0x10; - goto start_request_Err; - } - } - - host->state = STATE_SENDING_CMD; - host->mrq = host->new_mrq; - mrq = host->mrq; + if (mrq->data) { + rk29_sdmmc_set_timeout(host,mrq->data); + rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,mrq->data->blksz*mrq->data->blocks); + rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,mrq->data->blksz); + } cmd = mrq->cmd; - cmd->error = 0; - - host->cmdr = cmdr; - host->cmd = cmd; - host->pending_events = 0; - host->completed_events = 0; - host->data_status = 0; - host->data = NULL; - - host->errorstep = 0; - host->dodma = 0; - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - //adjust the frequency division control of SDMMC0 every time. - rk29_sdmmc_set_frq(host); - } - - - //setting for the data - rk29_sdmmc_submit_data(host, mrq->data); - - - xbwprintk(7, "%s..%d... CMD%d begin to call rk29_sdmmc_start_command() ===xbw[%s]===\n", \ - __FUNCTION__, __LINE__ , cmd->opcode,host->dma_name); + cmdflags = rk29_sdmmc_prepare_command(host->mmc, cmd); + if (host->is_init) { + host->is_init = 0; + cmdflags |= SDMMC_CMD_INIT; + } - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+700)); + if (mrq->data) { + rk29_sdmmc_set_mrq_status(host, MRQ_HAS_DATA); + ret = rk29_sdmmc_submit_data(host, mrq->data); } - else - { - mod_timer(&host->request_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_SEND_START_TIMEOUT+500)); + if(ret < 0) { + rk29_sdmmc_set_mrq_status(host, MRQ_DMA_SET_ERR); + goto start_err; } - - - ret = rk29_sdmmc_start_command(host, cmd, host->cmdr); - if(SDM_SUCCESS != ret) - { - cmd->error = -ETIMEDOUT; - printk("%s..%d... start_command(CMD%d, arg=%x) fail !!!!!!! ret=%d =========xbw=[%s]===\n",\ - __FUNCTION__, __LINE__ , cmd->opcode,cmd->arg,ret, host->dma_name); - host->errorstep = 0x11; - del_timer_sync(&host->request_timer); - - goto start_request_Err; + dev_dbg(host->dev,"start cmd:%d ARGR=0x%08x CMDR=0x%08x\n", + cmd->opcode, cmd->arg, cmdflags); + + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, + rk29_sdmmc_read(host->regs, SDMMC_INTMASK) | + (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS)); + ret = rk29_sdmmc_start_command(host, cmd, cmdflags); + if(ret < 0) { + rk29_sdmmc_set_mrq_status(host, MRQ_CMD_START_TMO); + goto start_err; } - - xbwprintk(7, "%s..%d... CMD=%d, wait for INT_CMD_DONE, ret=%d , \n \ - host->state=0x%x, cmdINT=0x%x \n host->pendingEvent=0x%lu, host->completeEvents=0x%lu =========xbw=[%s]=====\n\n",\ - __FUNCTION__, __LINE__, host->cmd->opcode,ret, \ - host->state,host->cmd_status, host->pending_events,host->completed_events,host->dma_name); - - spin_unlock_irqrestore(&host->lock, iflags); - return SDM_SUCCESS; - -start_request_Err: - rk29_sdmmc_start_error(host); - - printk("%s: CMD%d fail to call sdmmc_start_command() err=%d, Errorstep=0x%x ====xbw[%s]===\n\n",\ - __FUNCTION__, cmd->opcode,ret,host->errorstep,host->dma_name); - - spin_unlock_irqrestore(&host->lock, iflags); - - host->state = STATE_IDLE; - mmc_request_done(host->mmc, host->mrq); - - return ret; - + rk29_sdmmc_set_mrq_status(host, MRQ_CMD_START_DONE); + if (mrq->stop) { + rk29_sdmmc_set_mrq_status(host, MRQ_HAS_STOP); + host->stop_cmdr = rk29_sdmmc_prepare_command(host->mmc, mrq->stop); + if(mrq->cmd->opcode == 25) + host->stop_cmdr |= SDMMC_CMD_DAT_WR; + } + spin_unlock(&host->lock); + return 0; +start_err: + spin_unlock(&host->lock); + return ret; } - static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) { + int timeout; struct rk29_sdmmc *host = mmc_priv(mmc); - - #if 0 - //set 1 to close the controller for Debug. - if(RK29_CTRL_SDMMC_ID==host->pdev->id)//if(RK29_CTRL_SDIO_ID==host->pdev->id) - { - mrq->cmd->error = -ENOMEDIUM; - printk("%s..%d.. ==== The %s had been closed by myself for the experiment. ====xbw[%s]===\n",\ - __FUNCTION__, __LINE__, host->dma_name, host->dma_name); - mmc_request_done(mmc, mrq); - return; - } - #endif - - xbwprintk(5, "\n\n%s..%d...Begin a new cmd=%2d. ====@@@@@@@@==== host->flags=0x%lu, state=0x%x ===xbw[%s]====\n", \ - __FUNCTION__, __LINE__,mrq->cmd->opcode, host->flags,host->state, host->dma_name); - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - if(!rk29_sdmmc_get_cd(mmc) || ((0==mmc->re_initialized_flags)&&(MMC_GO_IDLE_STATE != mrq->cmd->opcode))) - { - mrq->cmd->error = -ENOMEDIUM; - - if((RK29_CTRL_SDMMC_ID == host->pdev->id)&&(0==mrq->cmd->retries)) - { - if(host->old_cmd != mrq->cmd->opcode) - { - if( ((17==host->old_cmd)&&(18==mrq->cmd->opcode)) || ((18==host->old_cmd)&&(17==mrq->cmd->opcode)) ||\ - ((24==host->old_cmd)&&(25==mrq->cmd->opcode)) || ((25==host->old_cmd)&&(24==mrq->cmd->opcode))) - { - host->old_cmd = mrq->cmd->opcode; - if(host->error_times++ %RK29_ERROR_PRINTK_INTERVAL ==0) - { - printk("%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 1==xbw[%s]==\n", \ - __FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name); - } - } - else - { - host->old_cmd = mrq->cmd->opcode; - host->error_times = 0; - printk("%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 2==xbw[%s]==\n", \ - __FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name); - } - } - else - { - if(host->error_times++ %RK29_ERROR_PRINTK_INTERVAL ==0) - { - printk("%s: Refuse to run CMD%2d(arg=0x%8x) due to the removal of card. 3==xbw[%s]==\n", \ - __FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg, host->dma_name); - } - } - } - - mmc_request_done(mmc, mrq); - return; - } - else - { - if(host->old_cmd != mrq->cmd->opcode) - { - host->old_cmd = mrq->cmd->opcode; - host->error_times = 0; + if(!mrq) + dev_info(host->dev, "mrq = NULL!!!!!\n"); + if(host->mrq){ + dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); + rk29_sdmmc_show_info(host); } - } - } + if((!rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) && + rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)) || + (rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) && + !rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA))) + dev_warn(host->dev, "start_dma but no stop_dma, or no start_dma but stop_dma\n"); + WARN_ON(host->mrq); + host->old_mrq_status = host->mrq_status; + host->mrq_status = 0; + host->pending_events = 0; + host->completed_events= 0; + host->cmd_intsts = 0; + host->data_intsts = 0; + host->mrq = mrq; + + if(!mrq->data) + timeout = 5000; else - { - host->old_cmd = mrq->cmd->opcode; - host->error_times = 0; - } + timeout = 5000 + mrq->data->timeout_ns/1000000; + mod_timer(&host->monitor_timer, jiffies + msecs_to_jiffies(timeout)); - //host->mrq = mrq; //replaced by xbw - host->new_mrq = mrq; - if (host->state == STATE_IDLE) - { - //host->state = STATE_SENDING_CMD; //replaced by xbw - rk29_sdmmc_start_request(mmc); - } - else - { - #ifdef RK29_SDMMC_LIST_QUEUE - - printk("%s..%d...Danger! Danger! New request was added to queue. ===xbw[%s]===\n", \ - __FUNCTION__, __LINE__,host->dma_name); - list_add_tail(&host->queue_node, &host->queue); - - #else - - printk("%s..%d...host state Error! old_state=%d, NewCMD%2d,arg=0x%x ====xbw[%s]======\n", \ - __FUNCTION__, __LINE__, host->state, mrq->cmd->opcode,mrq->cmd->arg, host->dma_name); - + if (!rk29_sdmmc_get_cd(mmc)) { mrq->cmd->error = -ENOMEDIUM; - mmc_request_done(mmc, mrq); + rk29_sdmmc_request_done(host, mrq); + dev_dbg(host->dev, "mrq_status = 0x%08lx\n", host->mrq_status); return; - - #endif - } -} - - - -static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - int timeout = 100; - unsigned int value; - unsigned long iflags; - struct rk29_sdmmc *host = mmc_priv(mmc); - - spin_lock_irqsave(&host->lock, iflags); - - /* - * Waiting SDIO controller to be IDLE. - */ - while (timeout-- > 0) - { - value = rk29_sdmmc_read(host->regs, SDMMC_STATUS); - if ((value & SDMMC_STAUTS_DATA_BUSY) == 0 &&(value & SDMMC_CMD_FSM_MASK) == SDMMC_CMD_FSM_IDLE) - { - break; - } - - mdelay(1); - } - if (timeout <= 0) - { - printk("%s..%d...Waiting for SDIO controller to be IDLE timeout.==xbw[%s]===\n", \ - __FUNCTION__, __LINE__, host->dma_name); - - goto out; - } - - //if(host->bus_mode != ios->power_mode) - { - switch (ios->power_mode) - { - case MMC_POWER_UP: - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_ENABLE); - - //reset the controller if it is SDMMC0 - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - xbwprintk(7, "%s..%d..POWER_UP, call reset_controller, initialized_flags=%d ====xbw[%s]=====\n",\ - __FUNCTION__, __LINE__, host->mmc->re_initialized_flags,host->dma_name); - - mdelay(5); - - rk29_sdmmc_hw_init(host); - } - - break; - case MMC_POWER_OFF: - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - rk29_sdmmc_control_clock(host, FALSE); - rk29_sdmmc_write(host->regs, SDMMC_PWREN, POWER_DISABLE); - - if(5 == host->bus_mode) - { - mdelay(5); - xbwprintk(7, "%s..%d..Fisrt powerOFF, call reset_controller ======xbw[%s]====\n", \ - __FUNCTION__, __LINE__,host->dma_name); - - rk29_sdmmc_reset_controller(host); - } - - } - - break; - default: - break; - } - - host->bus_mode = ios->power_mode; - } - - if(host->ctype != ios->bus_width) - { - switch (ios->bus_width) - { - case MMC_BUS_WIDTH_1: - host->ctype = SDMMC_CTYPE_1BIT; - break; - case MMC_BUS_WIDTH_4: - host->ctype = SDMMC_CTYPE_4BIT; - break; - case MMC_BUS_WIDTH_8: - host->ctype = SDMMC_CTYPE_8BIT; - break; - default: - host->ctype = 0; - break; - } - - rk29_sdmmc_set_buswidth(host); - + if(rk29_sdmmc_set_clock(host)) { + mrq->cmd->error = -EINPROGRESS; + dev_info(host->dev, "rk29_sdmmc_set_clock timeout, ios_clock = %d, clock = %d\n", host->ios_clock, host->clock); + rk29_sdmmc_request_done(host, mrq); + rk29_sdmmc_reset_ctrl(host); + rk29_sdmmc_show_info(host); + return; } - - if (ios->clock && (ios->clock != host->clock)) - { - /* - * Use mirror of ios->clock to prevent race with mmc - * core ios update when finding the minimum. - */ - //host->clock = ios->clock; - rk29_sdmmc_change_clk_div(host, ios->clock); + + if(rk29_sdmmc_start_request(host,mrq)) { + dev_info(host->dev, "rk29_sdmmc_start_request timeout\n"); + mrq->cmd->error = -EINPROGRESS; + rk29_sdmmc_request_done(host, mrq); + rk29_sdmmc_reset_ctrl(host); + rk29_sdmmc_show_info(host); } -out: - - spin_unlock_irqrestore(&host->lock, iflags); -} - -static int rk29_sdmmc_get_ro(struct mmc_host *mmc) -{ - struct rk29_sdmmc *host = mmc_priv(mmc); - u32 wrtprt = rk29_sdmmc_read(host->regs, SDMMC_WRTPRT); - - return (wrtprt & SDMMC_WRITE_PROTECT)?1:0; + return; } - static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) { u32 intmask; @@ -2004,7 +853,6 @@ static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_lock_irqsave(&host->lock, flags); intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK); - if(enable) rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask | SDMMC_INT_SDIO); else @@ -2017,8 +865,6 @@ static void rk29_sdmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) card->quirks = MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; } - - static const struct mmc_host_ops rk29_sdmmc_ops[] = { { .request = rk29_sdmmc_request, @@ -2029,658 +875,389 @@ static const struct mmc_host_ops rk29_sdmmc_ops[] = { { .request = rk29_sdmmc_request, .set_ios = rk29_sdmmc_set_ios, - .enable_sdio_irq = rk29_sdmmc_enable_sdio_irq, - .init_card = rk29_sdmmc_init_card, - }, -}; - -static void rk29_sdmmc_request_end(struct rk29_sdmmc *host, struct mmc_command *cmd) -{ - u32 status; - int output=SDM_SUCCESS; - - xbwprintk(7, "%s..%d... cmd=%d, host->state=0x%x,\n pendingEvent=0x%lu, completeEvents=0x%lu ====xbw=[%s]====\n\n",\ - __FUNCTION__, __LINE__,cmd->opcode,host->state, host->pending_events,host->completed_events,host->dma_name); - - del_timer_sync(&host->DTO_timer); - - //stop DMA - if(host->dodma) - { - rk29_sdmmc_stop_dma(host); - rk29_sdmmc_control_host_dma(host, FALSE); - host->dodma = 0; - } - - if(cmd->error) - { - goto exit;//It need not to wait-for-busy if the CMD-ERROR happen. - } - - if(cmd->data) - { - - status = host->data_status; - - if(host->cmdr & SDMMC_CMD_DAT_WRITE) - { - if(status & (SDMMC_INT_DCRC | SDMMC_INT_EBE)) - { - cmd->data->error = -EILSEQ;;//mrq->data->error = -EILSEQ; - output = SDM_DATA_CRC_ERROR; - host->errorstep = 0x16; - } - else - { - output = rk29_sdmmc_wait_unbusy(host); - if(SDM_SUCCESS != output) - { - host->errorstep = 0x17; - cmd->data->error = -ETIMEDOUT; - } - - host->data->bytes_xfered = host->data->blocks * host->data->blksz; - } - } - else - { - if( status & SDMMC_INT_SBE) - { - cmd->data->error = -EIO; - host->errorstep = 0x18; - output = SDM_START_BIT_ERROR; - } - else if((status & SDMMC_INT_EBE) && (cmd->opcode != 14)) //MMC4.0, BUSTEST_R, A host read the reserved bus testing data parttern from a card. - { - cmd->data->error = -EILSEQ; - host->errorstep = 0x19; - output = SDM_END_BIT_ERROR; - } - else if(status & SDMMC_INT_DRTO) - { - cmd->data->error = -ETIMEDOUT; - host->errorstep = 0x1A; - output = SDM_DATA_READ_TIMEOUT; - } - else if(status & SDMMC_INT_DCRC) - { - host->errorstep = 0x1B; - cmd->data->error = -EILSEQ; - output = SDM_DATA_CRC_ERROR; - } - else - { - output = rk29_sdmmc_read_remain_data(host, (host->data->blocks * host->data->blksz), host->pbuf); - if(SDM_SUCCESS == output) - { - host->data->bytes_xfered = host->data->blocks * host->data->blksz; - } - } - } - } - - if(SDM_SUCCESS == output) - { - if ((mmc_resp_type(cmd) == MMC_RSP_R1B) || (MMC_STOP_TRANSMISSION == cmd->opcode)) - { - output = rk29_sdmmc_wait_unbusy(host); - if(SDM_SUCCESS != output) - { - cmd->error = -ETIMEDOUT; - host->mrq->cmd->error = -ETIMEDOUT; - host->errorstep = 0x1C; - printk("%s..%d... CMD12 wait busy timeout!!!!! ====xbw=[%s]====\n", \ - __FUNCTION__, __LINE__, host->dma_name); - } - } - } - - //trace error - if(cmd->data && cmd->data->error) - { - if( (!cmd->error) && (0==cmd->retries) && (host->error_times++%RK29_ERROR_PRINTK_INTERVAL == 0)) - { - printk("%s..%d......CMD=%d error!!!, arg=%x, errorTimes=%d, errorStep=0x%x ! ====xbw[%s]====\n",\ - __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->error_times,host->errorstep, host->dma_name); - } - } - -exit: - -#ifdef RK29_SDMMC_LIST_QUEUE - if (!list_empty(&host->queue)) - { - printk("%s..%d.. Danger!Danger!. continue the next request in the queue. ====xbw[%s]====\n",\ - __FUNCTION__, __LINE__, host->dma_name); - - host = list_entry(host->queue.next, - struct rk29_sdmmc, queue_node); - list_del(&host->queue_node); - host->state = STATE_SENDING_CMD; - rk29_sdmmc_start_request(host->mmc); - } - else - { - dev_vdbg(&host->pdev->dev, "list empty\n"); - host->state = STATE_IDLE; - } -#else - dev_vdbg(&host->pdev->dev, "list empty\n"); - host->state = STATE_IDLE; -#endif - -} - -static int rk29_sdmmc_command_complete(struct rk29_sdmmc *host, - struct mmc_command *cmd) -{ - u32 value, status = host->cmd_status; - int timeout, output= SDM_SUCCESS; - - xbwprintk(7, "%s..%d. cmd=%d, host->state=0x%x, cmdINT=0x%x\n,pendingEvent=0x%lu,completeEvents=0x%lu ===xbw[%s]===\n\n",\ - __FUNCTION__, __LINE__,cmd->opcode,host->state,status, host->pending_events,host->completed_events,host->dma_name); - - - del_timer_sync(&host->request_timer); - - host->cmd_status = 0; - - if((RK29_CTRL_SDMMC_ID == host->pdev->id) && (host->cmdr & SDMMC_CMD_STOP)) - { - output = rk29_sdmmc_reset_fifo(host); - if (SDM_SUCCESS != output) - { - printk("%s..%d......reset fifo fail!!! =======xbw[%s]=====\n",__FUNCTION__, __LINE__, host->dma_name); - cmd->error = -ETIMEDOUT; - host->mrq->cmd->error = cmd->error; - output = SDM_ERROR; - host->errorstep = 0x1C; - goto CMD_Errror; - } - } - - //status = rk29_sdmmc_read(host->regs, SDMMC_RINTSTS); - if(status & SDMMC_INT_RTO) - { - cmd->error = -ENOMEM; - host->mrq->cmd->error = cmd->error; - output = SDM_BUSY_TIMEOUT; - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RTO); - - if(host->use_dma)//if(host->dodma) - { - if(host->dodma) - { - rk29_sdmmc_stop_dma(host); - rk29_sdmmc_control_host_dma(host, FALSE); - host->dodma = 0; - } - - value = rk29_sdmmc_read(host->regs, SDMMC_CTRL); - value |= SDMMC_CTRL_FIFO_RESET; - rk29_sdmmc_write(host->regs, SDMMC_CTRL, value); - - timeout = 1000; - while (((value = rk29_sdmmc_read(host->regs, SDMMC_CTRL)) & (SDMMC_CTRL_FIFO_RESET)) && (timeout > 0)) - { - udelay(1); - timeout--; - } - if (timeout == 0) - { - output = SDM_FALSE; - host->errorstep = 0x1D; - printk("%s..%d......reset CTRL fail!!! =======xbw[%s]=====\n",__FUNCTION__, __LINE__, host->dma_name); - - goto CMD_Errror; - } - } - - } - - if(cmd->flags & MMC_RSP_PRESENT) - { - if(cmd->flags & MMC_RSP_136) - { - cmd->resp[3] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); - cmd->resp[2] = rk29_sdmmc_read(host->regs, SDMMC_RESP1); - cmd->resp[1] = rk29_sdmmc_read(host->regs, SDMMC_RESP2); - cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP3); - } - else - { - cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); - } - } - - if(cmd->error) - { - del_timer_sync(&host->DTO_timer); - - //trace error - if((0==cmd->retries) && (host->error_times++%RK29_ERROR_PRINTK_INTERVAL == 0)) - { - if( ((RK29_CTRL_SDMMC_ID==host->pdev->id)&&(MMC_SLEEP_AWAKE!=cmd->opcode)) || - ((RK29_CTRL_SDMMC_ID!=host->pdev->id)&&(MMC_SEND_EXT_CSD!=cmd->opcode)) ) - { - printk("%s..%d...CMD=%d, arg=%x, errorTimes=%d, errorStep=0x%x !!!!!! =======xbw[%s]=====\n",\ - __FUNCTION__, __LINE__, cmd->opcode, cmd->arg,host->error_times,host->errorstep, host->dma_name); - } - } - - } - del_timer_sync(&host->request_timer); - - - return SDM_SUCCESS; - -CMD_Errror: - del_timer_sync(&host->request_timer); - del_timer_sync(&host->DTO_timer); - - if((0==cmd->retries) && (host->error_times++%RK29_ERROR_PRINTK_INTERVAL == 0)) - { - printk("%s..%d......command_complete(CMD=%d, arg=%x) error=%d =======xbw[%s]=====\n",\ - __FUNCTION__, __LINE__, host->cmd->opcode,host->cmd->arg, output, host->dma_name); - } - - return output; - -} - - -static void rk29_sdmmc_start_error(struct rk29_sdmmc *host) -{ - host->cmd->error = -EIO; - host->mrq->cmd->error = -EIO; - host->cmd_status = SDMMC_INT_RTO; - - del_timer_sync(&host->request_timer); - - rk29_sdmmc_command_complete(host, host->mrq->cmd); - rk29_sdmmc_request_end(host, host->mrq->cmd); - -} - -static void rk29_sdmmc_tasklet_func(unsigned long priv) -{ - struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv; - struct mmc_data *data = host->cmd->data; - enum rk29_sdmmc_state state = host->state; - int done_flag=0; - - spin_lock(&host->lock); - - state = host->state; - done_flag = 0; - - do - { - switch (state) - { - case STATE_IDLE: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_IDLE ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, host->dma_name); - break; - } - - case STATE_SENDING_CMD: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_SENDING_CMD, pendingEvernt=0x%lu ====xbw[%s]====\n",\ - __FUNCTION__, __LINE__,host->completed_events, host->dma_name); - - if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) - break; - - del_timer_sync(&host->request_timer); //delete the timer for INT_COME_DONE - - rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE); - rk29_sdmmc_command_complete(host, host->cmd); - - - if (!data) - { - rk29_sdmmc_request_end(host, host->cmd); - - xbwprintk(7, "%s..%d.. CMD%d call mmc_request_done()====xbw[%s]====\n", \ - __FUNCTION__, __LINE__,host->cmd->opcode,host->dma_name); - - done_flag = 1; - goto unlock; - } - - if(host->cmd->error) - { - del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO - - if(data->stop) - { - xbwprintk(7, "%s..%d.. cmderr, so call send_stop_cmd() ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, host->dma_name); - - state = STATE_SENDING_CMD;//STATE_SENDING_STOP; - send_stop_cmd(host); - break; - } - - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); - } - - - state = STATE_DATA_BUSY; - /* fall through */ - } - - case STATE_DATA_BUSY: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_DATA_BUSY, pendingEvernt=0x%lu ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__,host->pending_events, host->dma_name); - - if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_DATA_COMPLETE)) - break; - - rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE); - del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO - - rk29_sdmmc_request_end(host, host->cmd); - - if (data && !data->stop) - { - xbwprintk(7, "%s..%d.. CMD%d call mmc_request_done()====xbw[%s]====\n", \ - __FUNCTION__, __LINE__,host->cmd->opcode,host->dma_name); - - if(!( (MMC_READ_SINGLE_BLOCK == host->cmd->opcode)&&( -EIO == data->error))) //deal with START_BIT_ERROR - { - done_flag = 1; - goto unlock; - } - - } - - xbwprintk(7, "%s..%d.. after DATA_COMPLETE, so call send_stop_cmd() ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, host->dma_name); - - state = STATE_SENDING_CMD; - send_stop_cmd(host); - break; - } - - case STATE_SENDING_STOP: - { - xbwprintk(7, "%s..%d.. prev_state= STATE_SENDING_STOP, pendingEvernt=0x%lu ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, host->pending_events, host->dma_name); - - if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) - break; - - rk29_sdmmc_command_complete(host, host->cmd); - del_timer_sync(&host->request_timer); //delete the timer for INT_CMD_DONE int CMD12 - rk29_sdmmc_request_end(host, host->cmd); - - done_flag = 1; - goto unlock; - } - - } - } while(0); - - host->state = state; - -unlock: - if(0==done_flag) - { - spin_unlock(&host->lock); - return; - } - - host->state = STATE_IDLE; - spin_unlock(&host->lock); - - mmc_request_done(host->mmc, host->mrq); -} - + .enable_sdio_irq = rk29_sdmmc_enable_sdio_irq, + .init_card = rk29_sdmmc_init_card, + }, +}; -static inline void rk29_sdmmc_cmd_interrupt(struct rk29_sdmmc *host, u32 status) +static void rk29_sdmmc_request_end(struct rk29_sdmmc *host) + __releases(&host->lock) + __acquires(&host->lock) { - if(!host->cmd_status) - host->cmd_status = status; - - if((MMC_STOP_TRANSMISSION != host->cmd->opcode) && (host->cmdr & SDMMC_CMD_DAT_EXP)) - { - mod_timer(&host->DTO_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_WAIT_DTO_INTERNVAL)); - } - - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); - tasklet_schedule(&host->tasklet); + if(host->mrq) + rk29_sdmmc_request_done(host, host->mrq); } -static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id) +static void rk29_sdmmc_command_complete(struct rk29_sdmmc *host, + struct mmc_command *cmd) { - struct rk29_sdmmc *host = dev_id; - u32 status, pending; - bool present; - bool present_old; - unsigned long iflags; - - spin_lock_irqsave(&host->lock, iflags); - - status = rk29_sdmmc_read(host->regs, SDMMC_RINTSTS); - pending = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);// read only mask reg - if (!pending) - { - spin_unlock_irqrestore(&host->lock, iflags); - return IRQ_HANDLED; - } + unsigned int intsts = host->cmd_intsts; + host->cmd_intsts = 0; + if(cmd->flags & MMC_RSP_PRESENT) { - if(pending & SDMMC_INT_CD) - { - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, SDMMC_INT_CD); // clear sd detect int - present = rk29_sdmmc_get_cd(host->mmc); - present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - - if(present != present_old) - { - printk("\n******************\n%s:INT_CD=0x%x,INT-En=%d,hostState=%d, present Old=%d ==> New=%d ==xbw[%s]==\n",\ - __FUNCTION__, pending, host->mmc->re_initialized_flags, host->state, present_old, present, host->dma_name); - - rk28_send_wakeup_key(); //wake up backlight - host->error_times = 0; - - #if 1 - rk29_sdmmc_dealwith_timeout(host); - #endif - - if(present) - { - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - - if(host->mmc->re_initialized_flags) - { - mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY/2)); - } - else - { - mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2)); - } - } - else - { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - host->mmc->re_initialized_flags = 0; - - mmc_detect_change(host->mmc, 200); - } - - } - - spin_unlock_irqrestore(&host->lock, iflags); - return IRQ_HANDLED; - - } + if(cmd->flags & MMC_RSP_136) { + cmd->resp[3] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); + cmd->resp[2] = rk29_sdmmc_read(host->regs, SDMMC_RESP1); + cmd->resp[1] = rk29_sdmmc_read(host->regs, SDMMC_RESP2); + cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP3); + } else { + cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0); + cmd->resp[1] = 0; + cmd->resp[2] = 0; + cmd->resp[3] = 0; + } + } + if (intsts & SDMMC_INT_RTO) + cmd->error = -ETIMEDOUT; + else if ((cmd->flags & MMC_RSP_CRC) && (intsts & SDMMC_INT_RCRC)) + cmd->error = -EILSEQ; + else if (intsts & SDMMC_INT_RE) + cmd->error = -EIO; + else if(intsts & SDMMC_INT_HLE) + cmd->error = -EIO; + else + cmd->error = 0; - if (pending & SDMMC_INT_CMD_DONE) { + if (cmd->error) { + dev_dbg(host->dev, + "command error: status=0x%08x resp=0x%08x\n" + "cmd=0x%08x arg=0x%08x flg=0x%08x err=%d\n", + intsts, cmd->resp[0], + cmd->opcode, cmd->arg, cmd->flags, cmd->error); - xbwprintk(6, "%s..%d.. CMD%d INT_CMD_DONE INT=0x%x ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode,pending, host->dma_name); + if (cmd->data) { + rk29_sdmmc_stop_dma(host); + } + } +} - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE); // clear interrupt +static void rk29_sdmmc_tasklet_func(unsigned long priv) +{ + struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv; + enum rk29_sdmmc_state state; + enum rk29_sdmmc_state prev_state; + unsigned int intsts; - rk29_sdmmc_cmd_interrupt(host, status); - } + spin_lock(&host->lock); + state = host->state; - if(pending & SDMMC_INT_SDIO) - { - xbwprintk(7, "%s..%d.. INT_SDIO INT=0x%x ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, pending, host->dma_name); + do { + prev_state = state; + switch (state) { + case STATE_IDLE: + break; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_SDIO); - mmc_signal_sdio_irq(host->mmc); - } + case STATE_SENDING_CMD: + if (!rk29_sdmmc_test_and_clear_pending(host, + EVENT_CMD_COMPLETE)) + break; + rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE); + if(!host->mrq){ + dev_info(host->dev, "sending cmd, host->mrq = NULL\n"); + rk29_sdmmc_show_info(host); + }else{ + rk29_sdmmc_command_complete(host, host->mrq->cmd); + if (!host->mrq->data || (host->mrq->cmd->error)) { + rk29_sdmmc_request_end(host); + goto unlock; + } + prev_state = state = STATE_SENDING_DATA; + } + case STATE_SENDING_DATA: + if (rk29_sdmmc_test_and_clear_pending(host, + EVENT_DATA_ERROR)) { + if(!host->mrq){ + dev_info(host->dev, "sending data, host->mrq = NULL\n"); + rk29_sdmmc_show_info(host); + } + if(!rk29_sdmmc_test_mrq_status(host, MRQ_DMA_DONE) && + rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)) + dev_info(host->dev, "dma is running...\n"); + rk29_sdmmc_stop_dma(host); + if (host->mrq->data->stop) + send_stop_cmd(host); + state = STATE_DATA_ERROR; + break; + } + prev_state = state = STATE_DATA_BUSY; + + case STATE_DATA_BUSY: + if (!rk29_sdmmc_test_and_clear_pending(host,EVENT_DATA_COMPLETE) && + !(host->data_intsts & SDMMC_INT_SBE)) + break; + + rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE); + intsts = host->data_intsts; + if(!host->mrq){ + dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); + rk29_sdmmc_show_info(host); + } + if(host->mrq->data) { + if (unlikely(intsts & RK29_SDMMC_DATA_ERROR_FLAGS)) { + if (intsts & SDMMC_INT_DRTO) { + dev_err(host->dev,"data timeout error\n"); + host->mrq->data->error = -ETIMEDOUT; + } else if (intsts & SDMMC_INT_DCRC) { + dev_err(host->dev,"data CRC error\n"); + host->mrq->data->error = -EILSEQ; + } else if (intsts & SDMMC_INT_SBE) { + dev_err(host->dev,"data start bit error\n"); + host->mrq->data->error = -EILSEQ; + }else { + dev_err(host->dev,"data FIFO error (status=%08x)\n",intsts); + host->mrq->data->error = -EIO; + } + rk29_sdmmc_show_info(host); + }else { + host->mrq->data->bytes_xfered = host->mrq->data->blocks * host->mrq->data->blksz; + host->mrq->data->error = 0; + } + } + if (!host->mrq->data->stop) { + rk29_sdmmc_request_end(host); + goto unlock; + } + prev_state = state = STATE_SENDING_STOP; + if (host->mrq->data && !host->mrq->data->error) + send_stop_cmd(host); + /* fall through */ + + case STATE_SENDING_STOP: + if (!rk29_sdmmc_test_and_clear_pending(host, + EVENT_CMD_COMPLETE)) + break; + if(!host->mrq){ + dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); + rk29_sdmmc_show_info(host); + } + if(host->mrq->stop) + rk29_sdmmc_command_complete(host, host->mrq->stop); + rk29_sdmmc_request_end(host); + goto unlock; + case STATE_DATA_ERROR: + state = STATE_DATA_BUSY; + break; + } + } while (state != prev_state); - if(pending & SDMMC_INT_RTO) - { - xbwprintk(7, "%s..%d.. CMD%d CMD_ERROR_FLAGS INT=0x%x ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, host->cmd->opcode,pending, host->dma_name); + host->state = state; - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RTO); - host->cmd_status = status; - smp_wmb(); - rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); +unlock: + spin_unlock(&host->lock); - if(!(pending & SDMMC_INT_CMD_DONE)) - tasklet_schedule(&host->tasklet); +} - spin_unlock_irqrestore(&host->lock, iflags); - return IRQ_HANDLED; - } - if(pending & SDMMC_INT_HLE) - { - printk("%s: write error due to hardware locked. Please check your hardware. ==xbw[%s]==\n",\ - __FUNCTION__, host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_HLE); - spin_unlock_irqrestore(&host->lock, iflags); - return IRQ_HANDLED; - } +static irqreturn_t rk29_sdmmc_isr(int irq, void *dev_id) +{ + struct rk29_sdmmc *host = dev_id; + unsigned int intsts; + intsts = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS); - if(pending & SDMMC_INT_DTO) - { - xbwprintk(7, "%s..%d.. CMD%d INT_DTO INT=0x%x ==xbw[%s]==\n", \ - __FUNCTION__, __LINE__,host->cmd->opcode,pending, host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); - del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO + spin_lock(&host->lock); + if(intsts & RK29_SDMMC_CMD_ERROR_FLAGS) { + rk29_sdmmc_set_mrq_status(host, MRQ_INT_CMD_ERR); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_CMD_ERROR_FLAGS); + host->cmd_intsts = intsts; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); + if(!host->mrq){ + dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); + rk29_sdmmc_show_info(host); + } + else + dev_info(host->dev, "[cmd%d] cmd error(intsts 0x%x, host->state %d, pending_events %ld)\n", + host->mrq->cmd->opcode,intsts,host->state,host->pending_events); + tasklet_schedule(&host->tasklet); + } - if (!host->data_status) - host->data_status = status; + if (intsts & RK29_SDMMC_DATA_ERROR_FLAGS) { + rk29_sdmmc_set_mrq_status(host, MRQ_INT_DATA_ERR); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_DATA_ERROR_FLAGS); + host->data_intsts = intsts; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR); + if(!host->mrq){ + dev_info(host->dev, "%s-> host->mrq = NULL\n", __func__); + rk29_sdmmc_show_info(host); + } + else + dev_info(host->dev, "[cmd%d] data error(intsts 0x%x, host->state %d, pending_events %ld)\n", + host->mrq->cmd->opcode, intsts,host->state,host->pending_events); + tasklet_schedule(&host->tasklet); + } - smp_wmb(); + if(intsts & SDMMC_INT_DTO) { + rk29_sdmmc_set_mrq_status(host, MRQ_INT_DATA_DONE); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); + if (!host->data_intsts) + host->data_intsts = intsts; + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); + tasklet_schedule(&host->tasklet); + } + if (intsts & SDMMC_INT_CMD_DONE) { + rk29_sdmmc_set_mrq_status(host, MRQ_INT_CMD_DONE); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE); + if(!host->cmd_intsts) + host->cmd_intsts = intsts; + + smp_wmb(); + rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE); + tasklet_schedule(&host->tasklet); + } + if(host->is_sdio && (intsts & SDMMC_INT_SDIO)) { + rk29_sdmmc_set_mrq_status(host, MRQ_INT_SDIO); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_SDIO); + mmc_signal_sdio_irq(host->mmc); + } + spin_unlock(&host->lock); + return IRQ_HANDLED; +} - rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE); - tasklet_schedule(&host->tasklet); +static void rk29_sdmmc_dma_complete(void *arg, int size, enum rk29_dma_buffresult result) +{ + struct rk29_sdmmc *host = arg; + + dev_dbg(host->dev, "DMA complete\n"); + rk29_sdmmc_set_mrq_status(host, MRQ_DMA_DONE); +} - spin_unlock_irqrestore(&host->lock, iflags); - return IRQ_HANDLED; - } +static void rk29_sdmmc_detect_change(struct rk29_sdmmc *host) +{ + spin_lock(&host->lock); + del_timer(&host->monitor_timer); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, ~SDMMC_INT_SDIO); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, + rk29_sdmmc_read(host->regs, SDMMC_INTMASK) & + ~(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS)); + if (host->mrq) { + switch (host->state) { + case STATE_IDLE: + break; + case STATE_SENDING_CMD: + if(host->mrq->cmd) + host->mrq->cmd->error = -ENOMEDIUM; + if (!host->mrq->data) + break; + /* fall through */ + case STATE_SENDING_DATA: + if(host->mrq->data) + host->mrq->data->error = -ENOMEDIUM; + rk29_sdmmc_stop_dma(host); + break; + case STATE_DATA_BUSY: + case STATE_DATA_ERROR: + if (host->mrq->data && host->mrq->data->error == -EINPROGRESS) + host->mrq->data->error = -ENOMEDIUM; + if (!host->mrq->stop) + break; + /* fall through */ + case STATE_SENDING_STOP: + if(host->mrq->stop) { + host->mrq->stop->error = -ENOMEDIUM; + } + break; + } + rk29_sdmmc_request_end(host); + } + rk29_sdmmc_reset_fifo(host); + spin_unlock(&host->lock); + mmc_detect_change(host->mmc, 0); +} - if (pending & SDMMC_INT_FRUN) - { - printk("%s: INT=0x%x Oh!My God,let me see!What happened?Why?Where? ==xbw[%s]==\n", \ - __FUNCTION__, pending,host->dma_name); - - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_FRUN); - spin_unlock_irqrestore(&host->lock, iflags); - return IRQ_HANDLED; - } +static void rk29_sdmmc1_status_notify_cb(int card_present, void *dev_id) +{ + struct rk29_sdmmc *host = dev_id; - if (pending & SDMMC_INT_RXDR) - { - xbwprintk(6, "%s..%d.. SDMMC_INT_RXDR INT=0x%x ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, pending, host->dma_name); + card_present = rk29_sdmmc_get_cd(host->mmc); + dev_info(host->dev, "sdio change detected,status is %d\n",card_present); + + rk29_sdmmc_detect_change(host); +} - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RXDR); // clear interrupt - rk29_sdmmc_do_pio_read(host); - } +static void rk29_sdmmc_get_dma_dma_info(struct rk29_sdmmc *host) +{ + if(host->is_sdio) + host->dma_info = dma_infos[1]; + else + host->dma_info = dma_infos[0]; +} - if (pending & SDMMC_INT_TXDR) - { - xbwprintk(6, "%s..%d.. SDMMC_INT_TXDR INT=0x%x ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, pending, host->dma_name); +static irqreturn_t rk29_sdmmc_detect_change_isr(int irq, void *dev_id); +static void rk29_sdmmc_detect_change_work(struct work_struct *work) +{ + int ret; + struct rk29_sdmmc *host = container_of(work, struct rk29_sdmmc, work.work); - rk29_sdmmc_do_pio_write(host); + dev_info(host->dev, "sd detect change, card is %s\n", + rk29_sdmmc_get_cd(host->mmc)?"inserted":"removed"); + if(host->enable_sd_warkup && rk29_sdmmc_get_cd(host->mmc)) + rk28_send_wakeup_key(); + rk29_sdmmc_detect_change(host); - rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR); // clear interrupt - } + free_irq(host->gpio_irq, host); + ret = request_irq(host->gpio_irq, + rk29_sdmmc_detect_change_isr, + rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING, + "sd_detect", + host); + if(ret < 0) + dev_err(host->dev, "gpio request_irq error\n"); +} +static irqreturn_t rk29_sdmmc_detect_change_isr(int irq, void *dev_id) +{ + struct rk29_sdmmc *host = dev_id; - spin_unlock_irqrestore(&host->lock, iflags); + disable_irq_nosync(host->gpio_irq); + if(rk29_sdmmc_get_cd(host->mmc)) + schedule_delayed_work(&host->work, msecs_to_jiffies(500)); + else + schedule_delayed_work(&host->work, 0); + return IRQ_HANDLED; } - -/* - * - * MMC card detect thread, kicked off from detect interrupt, 1 timer - * - */ -static void rk29_sdmmc_detect_change(unsigned long data) +static void rk29_sdmmc_monitor_timer(unsigned long data) { struct rk29_sdmmc *host = (struct rk29_sdmmc *)data; - - if(!host->mmc) - return; - - smp_rmb(); - - if(RK29_CTRL_SDMMC_ID == host->pdev->id) - { - host->mmc->re_initialized_flags =1; - } - - mmc_detect_change(host->mmc, 0); - + + if(!rk29_sdmmc_test_mrq_status(host, MRQ_REQUEST_DONE)){ + dev_info(host->dev, "no dto interrupt\n"); + rk29_sdmmc_show_info(host); + host->mrq->cmd->error = -ETIMEDOUT; + if(host->mrq->data) + host->mrq->data->error = -ETIMEDOUT; + rk29_sdmmc_request_end(host); + //rk29_sdmmc_reset_ctrl(host); + } + } -static void rk29_sdmmc1_check_status(unsigned long data) +#ifdef CONFIG_HAS_EARLYSUSPEND +static void rk29_sdmmc_early_suspend(struct early_suspend *h) { - struct rk29_sdmmc *host = (struct rk29_sdmmc *)data; - struct rk29_sdmmc_platform_data *pdata = host->pdev->dev.platform_data; - unsigned int status; - - status = pdata->status(mmc_dev(host->mmc)); - - if (status ^ host->oldstatus) - { - pr_info("%s: slot status change detected(%d-%d)\n",mmc_hostname(host->mmc), host->oldstatus, status); - if (status) - { - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(200)); - } - else - { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - rk29_sdmmc_detect_change((unsigned long)host); - } - } + struct rk29_sdmmc *host = container_of(h, + struct rk29_sdmmc, + early_suspend); - host->oldstatus = status; + dev_dbg(host->dev, "Enter rk29_sdmmc_early_suspend\n"); } -static void rk29_sdmmc1_status_notify_cb(int card_present, void *dev_id) +static void rk29_sdmmc_early_resume(struct early_suspend *h) { - struct rk29_sdmmc *host = dev_id; - printk(KERN_INFO "%s, card_present %d\n", mmc_hostname(host->mmc), card_present); - rk29_sdmmc1_check_status((unsigned long)host); + struct rk29_sdmmc *host = container_of(h, + struct rk29_sdmmc, + early_suspend); + + dev_dbg(host->dev, "Exit rk29_sdmmc_early_resume\n"); } +#endif static int rk29_sdmmc_probe(struct platform_device *pdev) @@ -2689,365 +1266,270 @@ static int rk29_sdmmc_probe(struct platform_device *pdev) struct rk29_sdmmc *host; struct resource *regs; struct rk29_sdmmc_platform_data *pdata; - int irq; int ret = 0; - /* must have platform data */ pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "Platform data missing\n"); - ret = -ENODEV; - host->errorstep = 0x87; - goto out; - } - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) - { - host->errorstep = 0x88; - return -ENXIO; + return -ENODEV; } + if(pdata->io_init) + pdata->io_init(); mmc = mmc_alloc_host(sizeof(struct rk29_sdmmc), &pdev->dev); if (!mmc) - { - host->errorstep = 0x89; - ret = -ENOMEM; - goto rel_regions; - } + return -ENOMEM; host = mmc_priv(mmc); host->mmc = mmc; - host->pdev = pdev; - - host->ctype = 0; // set default 1 bit mode - host->errorstep = 0; - host->bus_mode = 5; - host->old_cmd = 100; - host->clock =0; - host->old_div = 0xFF; - host->error_times = 0; + host->dev = &pdev->dev; + host->mrq = NULL; + host->state = STATE_IDLE; + host->div = -1; + host->is_init = 1; + host->is_sdio = rk29_sdmmc_is_sdio(pdata); + + if(host->is_sdio) + sdio_host = host; + host->get_wifi_cd = pdata->status; + + host->irq = platform_get_irq(pdev, 0); + if (host->irq < 0) { + dev_err(&pdev->dev, "platform_get_irq error\n"); + ret = host->irq; + goto err_mmc_free_host; + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "platform_get_resource error\n"); + ret = -ENXIO; + goto err_mmc_free_host; + } -#ifdef CONFIG_PM - host->gpio_det = pdata->detect_irq; -#endif - - if(pdata->io_init) - pdata->io_init(); - - spin_lock_init(&host->lock); - -#ifdef RK29_SDMMC_LIST_QUEUE - INIT_LIST_HEAD(&host->queue); -#endif - - host->clk = clk_get(&pdev->dev, "mmc"); - clk_set_rate(host->clk,SDHC_FPP_FREQ); - clk_enable(host->clk); - clk_enable(clk_get(&pdev->dev, "hclk_mmc")); - - ret = -ENOMEM; host->regs = ioremap(regs->start, regs->end - regs->start); - if (!host->regs) - { - host->errorstep = 0x8A; - goto err_freemap; + if (!host->regs){ + dev_err(&pdev->dev, "ioremap error\n"); + ret = ENXIO; + goto err_mmc_free_host; } + spin_lock_init(&host->lock); - mmc->ops = &rk29_sdmmc_ops[pdev->id]; - mmc->f_min = FOD_FREQ; -#if 0 - mmc->f_max = SDHC_FPP_FREQ; -#else - if(RK29_CTRL_SDMMC_ID== host->pdev->id) - { - mmc->f_max = SDHC_FPP_FREQ; - } - else - { - mmc->f_max = SDHC_FPP_FREQ / 2; - } - -#endif - //mmc->ocr_avail = pdata->host_ocr_avail; - mmc->ocr_avail = MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31 - | MMC_VDD_31_32|MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_34_35| MMC_VDD_35_36; ///set valid volage 2.7---3.6v - mmc->caps = pdata->host_caps; - mmc->re_initialized_flags = 1; - - /* - * We can do SGIO - */ - mmc->max_phys_segs = 64; - mmc->max_hw_segs = 64; - - /* - * Block size can be up to 2048 bytes, but must be a power of two. - */ - mmc->max_blk_size = 4095; - - /* - * No limit on the number of blocks transferred. - */ - mmc->max_blk_count = 4096; - - /* - * Since we only have a 16-bit data length register, we must - * ensure that we don't exceed 2^16-1 bytes in a single request. - */ - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; //8M bytes(2K*4K) - - /* - * Set the maximum segment size. Since we aren't doing DMA - * (yet) we are only limited by the data length register. - */ - mmc->max_seg_size = mmc->max_req_size; - - tasklet_init(&host->tasklet, rk29_sdmmc_tasklet_func, (unsigned long)host); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - { - host->errorstep = 0x8B; - ret = -EINVAL; - goto err_freemap; + /* dma init */ + rk29_sdmmc_get_dma_dma_info(host); + ret = rk29_dma_request(host->dma_info.chn, &(host->dma_info.client), NULL); + if (ret < 0){ + dev_err(&pdev->dev, "rk29_dma_request error\n"); + goto err_iounmap; } + ret = rk29_dma_config(host->dma_info.chn, 4, 1); - memcpy(host->dma_name, pdata->dma_name, 8); - host->use_dma = pdata->use_dma; - - /*DMA init*/ - if(host->use_dma) - { - host->dma_info = rk29_sdmmc_dma_infos[host->pdev->id]; - ret = rk29_dma_request(host->dma_info.chn, &(host->dma_info.client), NULL); - if (ret < 0) - { - printk("%s..%d...rk29_dma_request error=%d.===xbw[%s]====\n", \ - __FUNCTION__, __LINE__,ret, host->dma_name); - host->errorstep = 0x97; - goto err_freemap; - } - - ret = rk29_dma_config(host->dma_info.chn, 4); - if(ret < 0) - { - printk("%s..%d.. rk29_dma_config error=%d ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, ret, host->dma_name); - host->errorstep = 0x98; - goto err_dmaunmap; - } - - ret = rk29_dma_set_buffdone_fn(host->dma_info.chn, rk29_sdmmc_dma_complete); - if(ret < 0) - { - printk("%s..%d.. dma_set_buffdone_fn error=%d ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, ret, host->dma_name); - host->errorstep = 0x99; - goto err_dmaunmap; - } - - host->dma_addr = regs->start + SDMMC_DATA; + if (ret < 0){ + dev_err(&pdev->dev, "rk29_dma_config error\n"); + //goto err_rk29_dma_free; } + ret = rk29_dma_set_buffdone_fn(host->dma_info.chn, rk29_sdmmc_dma_complete); + if (ret < 0){ + dev_err(&pdev->dev, "rk29_dma_set_buffdone_fn error\n"); + goto err_rk29_dma_free; + } + host->dma_addr = regs->start + SDMMC_DATA; - rk29_sdmmc_hw_init(host); - - ret = request_irq(irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host); - if (ret) - { - - printk("%s..%d.. request_irq error=%d ====xbw[%s]====\n", \ - __FUNCTION__, __LINE__, ret, host->dma_name); - host->errorstep = 0x8C; - goto err_dmaunmap; + /* clk init */ + host->clk = clk_get(&pdev->dev, "mmc"); + if(host->is_sdio) + clk_set_rate(host->clk,RK29_SDIO_CLK * 1000000); + else + clk_set_rate(host->clk,RK29_SDCARD_CLK * 1000000); + clk_enable(host->clk); + clk_enable(clk_get(&pdev->dev, "hclk_mmc")); + host->bus_hz = clk_get_rate(host->clk); + + /* reset all blocks */ + rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + /* wait till resets clear */ + while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)); + /* Clear the interrupts for the host controller */ + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first + /* Put in max timeout */ + rk29_sdmmc_write(host->regs, SDMMC_TMOUT, 0xFFFFFFFF); + + /* FIFO threshold settings */ + rk29_sdmmc_write(host->regs, SDMMC_FIFOTH, ((0x3 << 28) | (0x0f << 16) | (0x10 << 0))); // RXMark = 15, TXMark = 16, DMA Size = 16 + /* disable clock to CIU */ + rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0); + rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); + rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1); + + ret = request_irq(host->irq, rk29_sdmmc_isr, 0, dev_name(&pdev->dev), host); + if (ret < 0){ + dev_err(&pdev->dev, "request_irq error\n"); + goto err_rk29_dma_free; } - /* setup sdmmc1 wifi card detect change */ + /* card insert flags init*/ if (pdata->register_status_notify) { pdata->register_status_notify(rk29_sdmmc1_status_notify_cb, host); } - if(RK29_CTRL_SDMMC_ID== host->pdev->id) - { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - } - - - /* sdmmc1 wifi card slot status initially */ - if (pdata->status) { - host->oldstatus = pdata->status(mmc_dev(host->mmc)); - if (host->oldstatus) { - set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - }else { - clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags); - } - } - - /* Create card detect handler thread */ - setup_timer(&host->detect_timer, rk29_sdmmc_detect_change,(unsigned long)host); - setup_timer(&host->request_timer,rk29_sdmmc_INT_CMD_DONE_timeout,(unsigned long)host); - setup_timer(&host->DTO_timer,rk29_sdmmc_INT_DTO_timeout,(unsigned long)host); - - platform_set_drvdata(pdev, mmc); - - mmc_add_host(mmc); - -#ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION - - globalSDhost[pdev->id] = (struct rk29_sdmmc *)host; - if(RK29_CTRL_SDMMC_ID== host->pdev->id) - { - rk29_sdmmc_progress_add_attr(pdev); - } -#endif + /* add host */ + if(host->is_sdio) + mmc->ops = &rk29_sdmmc_ops[1]; + else + mmc->ops = &rk29_sdmmc_ops[0]; + + if (host->is_sdio) + mmc->pm_flags = MMC_PM_IGNORE_PM_NOTIFY; //ignore pm notify + + mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510); + mmc->f_max = host->bus_hz; + mmc->ocr_avail = pdata->host_ocr_avail; + mmc->caps = pdata->host_caps; + mmc->max_phys_segs = 64; + mmc->max_hw_segs = 64; + mmc->max_blk_size = 4095; + mmc->max_blk_count = 65535; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; + + ret = mmc_add_host(mmc); + if (ret < 0){ + dev_err(&pdev->dev, "mmc_add_host error\n"); + goto err_free_irq; + } #if defined (CONFIG_DEBUG_FS) rk29_sdmmc_init_debugfs(host); #endif - - printk("..Line%d..The End of the SDMMC probe %s ===xbw[%s]===\n\n", __LINE__, RK29_SDMMC_VERSION,host->dma_name); - return 0; - - -err_dmaunmap: - if(host->use_dma) - { - rk29_dma_free(host->dma_info.chn, &host->dma_info.client); + tasklet_init(&host->tasklet, rk29_sdmmc_tasklet_func, (unsigned long)host); + setup_timer(&host->monitor_timer, rk29_sdmmc_monitor_timer,(unsigned long)host); + + host->gpio_det = pdata->detect_irq; + if(!host->is_sdio && host->gpio_det != INVALID_GPIO) { + INIT_DELAYED_WORK(&host->work, rk29_sdmmc_detect_change_work); + ret = gpio_request(host->gpio_det, "sd_detect"); + if(ret < 0) { + dev_err(&pdev->dev, "gpio_request error\n"); + goto err_mmc_remove_host; + } + gpio_direction_input(host->gpio_det); + host->gpio_irq = gpio_to_irq(host->gpio_det); + + ret = request_irq(host->gpio_irq, + rk29_sdmmc_detect_change_isr, + rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING, + "sd_detect", + host); + if(ret < 0) { + dev_err(&pdev->dev, "gpio request_irq error\n"); + goto err_gpio_free; + } + host->enable_sd_warkup = pdata->enable_sd_wakeup; + if(host->enable_sd_warkup) + enable_irq_wake(host->gpio_irq); } - -err_freemap: + platform_set_drvdata(pdev, host); + rk29_sdmmc_write(host->regs, SDMMC_CTYPE, 0); + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK,SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS); + rk29_sdmmc_write(host->regs, SDMMC_CTRL,SDMMC_CTRL_INT_ENABLE); + rk29_sdmmc_write(host->regs, SDMMC_CLKENA,1); +#ifdef CONFIG_HAS_EARLYSUSPEND + host->early_suspend.suspend = rk29_sdmmc_early_suspend; + host->early_suspend.resume = rk29_sdmmc_early_resume; + host->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + register_early_suspend(&host->early_suspend); +#endif + dev_info(host->dev, "RK29 SDMMC controller at irq %d\n", host->irq); + return 0; + free_irq(host->gpio_irq, host); +err_gpio_free: + gpio_free(host->gpio_det); +err_mmc_remove_host: + mmc_remove_host(host->mmc); +err_free_irq: + free_irq(host->irq, host); +err_rk29_dma_free: + rk29_dma_free(host->dma_info.chn, &host->dma_info.client); +err_iounmap: iounmap(host->regs); +err_mmc_free_host: + mmc_free_host(host->mmc); -rel_regions: - mmc_free_host(mmc); - -out: - + while(1); return ret; + } static int __exit rk29_sdmmc_remove(struct platform_device *pdev) { + struct rk29_sdmmc *host = platform_get_drvdata(pdev); - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct rk29_sdmmc *host; - struct resource *regs; - - if (!mmc) - return -1; - - host = mmc_priv(mmc); - + rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); + rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first + smp_wmb(); - rk29_sdmmc_control_clock(host, 0); - - /* Shutdown detect IRQ and kill detect thread */ - del_timer_sync(&host->detect_timer); - del_timer_sync(&host->request_timer); - del_timer_sync(&host->DTO_timer); - - tasklet_disable(&host->tasklet); - free_irq(platform_get_irq(pdev, 0), host); - if(host->use_dma) - { - rk29_dma_free(host->dma_info.chn, &host->dma_info.client); - } - - mmc_remove_host(mmc); - - iounmap(host->regs); + free_irq(host->gpio_irq, host); + gpio_free(host->gpio_det); + mmc_remove_host(host->mmc); + free_irq(host->irq, host); + rk29_dma_free(host->dma_info.chn, &host->dma_info.client); - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(regs->start,resource_size(regs)); - - mmc_free_host(mmc); - platform_set_drvdata(pdev, NULL); - + /* disable clock to CIU */ + rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0); + rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0); + + iounmap(host->regs); + mmc_free_host(host->mmc); return 0; } - - -#ifdef CONFIG_PM - -static irqreturn_t det_keys_isr(int irq, void *dev_id) -{ - struct rk29_sdmmc *host = dev_id; - dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n", - gpio_get_value(RK29_PIN2_PA2)?"removed":"insert"); - rk29_sdmmc_detect_change((unsigned long)dev_id); - - return IRQ_HANDLED; -} - -static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host) +static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) { int ret = 0; - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2); - gpio_request(RK29_PIN2_PA2, "sd_detect"); - gpio_direction_input(RK29_PIN2_PA2); - - host->gpio_irq = gpio_to_irq(RK29_PIN2_PA2); - ret = request_irq(host->gpio_irq, det_keys_isr, - (gpio_get_value(RK29_PIN2_PA2))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, - "sd_detect", - host); - - enable_irq_wake(host->gpio_irq); +#ifdef CONFIG_PM + struct rk29_sdmmc *host = platform_get_drvdata(pdev); + dev_info(host->dev, "Enter rk29_sdmmc_suspend\n"); + if(host->mmc && !host->is_sdio && host->gpio_det != INVALID_GPIO){ + ret = mmc_suspend_host(host->mmc,state); + if(!host->enable_sd_warkup) + free_irq(host->gpio_irq, host); + } + rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0); + clk_disable(host->clk); +#endif return ret; } -static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host) -{ - disable_irq_wake(host->gpio_irq); - free_irq(host->gpio_irq,host); - gpio_free(RK29_PIN2_PA2); - rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); -} - - - -static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct rk29_sdmmc *host = mmc_priv(mmc); - int ret = 0; - - if(host && host->pdev && (RK29_CTRL_SDMMC_ID == host->pdev->id)) //only the SDMMC0 have suspend-resume; noted by xbw - { - if (mmc) - ret = mmc_suspend_host(mmc, state); - - if(rk29_sdmmc_sdcard_suspend(host) < 0) - dev_info(&host->pdev->dev, "rk29_sdmmc_sdcard_suspend error\n"); - } - - return ret; -} static int rk29_sdmmc_resume(struct platform_device *pdev) { - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct rk29_sdmmc *host = mmc_priv(mmc); - int ret = 0; - - if(host && host->pdev && (RK29_CTRL_SDMMC_ID == host->pdev->id)) //only the SDMMC0 have suspend-resume; noted by xbw - { - if (mmc) - { - rk29_sdmmc_sdcard_resume(host); - ret = mmc_resume_host(mmc); - } - } + int ret = 0; +#ifdef CONFIG_PM + struct rk29_sdmmc *host = platform_get_drvdata(pdev); + dev_info(host->dev, "Exit rk29_sdmmc_suspend\n"); + clk_enable(host->clk); + rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 1); + if(host->mmc && !host->is_sdio && host->gpio_det != INVALID_GPIO){ + if(!host->enable_sd_warkup){ + ret = request_irq(host->gpio_irq, + rk29_sdmmc_detect_change_isr, + rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING, + "sd_detect", + host); + if(ret < 0) + dev_err(host->dev, "gpio request_irq error\n"); + } + host->is_init = 1; + ret = mmc_resume_host(host->mmc); + mmc_detect_change(host->mmc, 0); + } +#endif return ret; } -#else -#define rk29_sdmmc_suspend NULL -#define rk29_sdmmc_resume NULL -#endif - static struct platform_driver rk29_sdmmc_driver = { .suspend = rk29_sdmmc_suspend, .resume = rk29_sdmmc_resume, @@ -3071,6 +1553,6 @@ module_init(rk29_sdmmc_init); module_exit(rk29_sdmmc_exit); MODULE_DESCRIPTION("Rk29 Multimedia Card Interface driver"); -MODULE_AUTHOR("xbw@rock-chips.com"); +MODULE_AUTHOR("Rockchips"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/rk29_sdmmc.h b/drivers/mmc/host/rk29_sdmmc.h deleted file mode 100755 index 1f6ef4a8f89e..000000000000 --- a/drivers/mmc/host/rk29_sdmmc.h +++ /dev/null @@ -1,202 +0,0 @@ -/* drivers/mmc/host/rk29_sdmmc.h - * - * Copyright (C) 2011 ROCKCHIP, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __RK2918_SDMMC_H -#define __RK2918_SDMMC_H - -#define MAX_SG_CHN 2 - - -#define SDMMC_CTRL (0x000) //SDMMC Control register -#define SDMMC_PWREN (0x004) //Power enable register -#define SDMMC_CLKDIV (0x008) //Clock divider register -#define SDMMC_CLKSRC (0x00c) //Clock source register -#define SDMMC_CLKENA (0x010) //Clock enable register -#define SDMMC_TMOUT (0x014) //Time out register -#define SDMMC_CTYPE (0x018) //Card type register -#define SDMMC_BLKSIZ (0x01c) //Block size register -#define SDMMC_BYTCNT (0x020) //Byte count register -#define SDMMC_INTMASK (0x024) //Interrupt mask register -#define SDMMC_CMDARG (0x028) //Command argument register -#define SDMMC_CMD (0x02c) //Command register -#define SDMMC_RESP0 (0x030) //Response 0 register -#define SDMMC_RESP1 (0x034) //Response 1 register -#define SDMMC_RESP2 (0x038) //Response 2 register -#define SDMMC_RESP3 (0x03c) //Response 3 register -#define SDMMC_MINTSTS (0x040) //Masked interrupt status register -#define SDMMC_RINTSTS (0x044) //Raw interrupt status register -#define SDMMC_STATUS (0x048) //Status register -#define SDMMC_FIFOTH (0x04c) //FIFO threshold register -#define SDMMC_CDETECT (0x050) //Card detect register -#define SDMMC_WRTPRT (0x054) //Write protect register -#define SDMMC_TCBCNT (0x05c) //Transferred CIU card byte count -#define SDMMC_TBBCNT (0x060) //Transferred host/DMA to/from BIU_FIFO byte count -#define SDMMC_DEBNCE (0x064) //Card detect debounce register -#define SDMMC_DATA (0x100) - -#define RK2818_BIT(n) (1<<(n)) -#define RK_CLEAR_BIT(n) (0<<(n)) - - -/* Control register defines (base+ 0x00)*/ -#define SDMMC_CTRL_OD_PULLUP RK2818_BIT(24) -#define SDMMC_CTRL_DMA_ENABLE RK2818_BIT(5) -#define SDMMC_CTRL_INT_ENABLE RK2818_BIT(4) -#define SDMMC_CTRL_FIFO_RESET RK2818_BIT(1) -#define SDMMC_CTRL_RESET RK2818_BIT(0) - -/* Power Enable Register(base+ 0x04) */ -#define POWER_ENABLE RK2818_BIT(0) //Power enable -#define POWER_DISABLE RK_CLEAR_BIT(0) //Power off - -/* SDMMC Clock source Register(base+ 0x0C) */ -#define CLK_DIV_SRC_0 (0x0) //clock divider 0 selected -#define CLK_DIV_SRC_1 (0x1) //clock divider 1 selected -#define CLK_DIV_SRC_2 (0x2) //clock divider 2 selected -#define CLK_DIV_SRC_3 (0x3) //clock divider 3 selected - - -/* Clock Enable register defines(base+0x10) */ -#define SDMMC_CLKEN_LOW_PWR RK2818_BIT(16) -#define SDMMC_CLKEN_NO_LOW_PWR RK_CLEAR_BIT(16) //low-power mode disabled -#define SDMMC_CLKEN_ENABLE RK2818_BIT(0) -#define SDMMC_CLKEN_DISABLE RK_CLEAR_BIT(16) //clock disabled - -/* time-out register defines(base+0x14) */ -#define SDMMC_TMOUT_DATA(n) _SBF(8, (n)) -#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00 -#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF) -#define SDMMC_TMOUT_RESP_MSK 0xFF - -/* card-type register defines(base+0x18) */ -#define SDMMC_CTYPE_8BIT RK2818_BIT(16) -#define SDMMC_CTYPE_4BIT RK2818_BIT(0) -#define SDMMC_CTYPE_1BIT RK_CLEAR_BIT(0) - -/* Interrupt status & mask register defines(base+0x24) */ -#define SDMMC_INT_SDIO RK2818_BIT(16) //SDIO interrupt -#define SDMMC_INT_EBE RK2818_BIT(15) //End Bit Error(read)/Write no CRC -#define SDMMC_INT_ACD RK2818_BIT(14) //Auto Command Done -#define SDMMC_INT_SBE RK2818_BIT(13) //Start Bit Error -#define SDMMC_INT_HLE RK2818_BIT(12) //Hardware Locked Write Error -#define SDMMC_INT_FRUN RK2818_BIT(11) //FIFO Underrun/Overrun Error -#define SDMMC_INT_HTO RK2818_BIT(10) //Data Starvation by Host Timeout -#define SDMMC_INT_DRTO RK2818_BIT(9) //Data Read TimeOut -#define SDMMC_INT_RTO RK2818_BIT(8) //Response TimeOut -#define SDMMC_INT_DCRC RK2818_BIT(7) //Data CRC Error -#define SDMMC_INT_RCRC RK2818_BIT(6) //Response CRC Error -#define SDMMC_INT_RXDR RK2818_BIT(5) //Receive FIFO Data Request -#define SDMMC_INT_TXDR RK2818_BIT(4) //Transmit FIFO Data Request -#define SDMMC_INT_DTO RK2818_BIT(3) //Data Transfer Over -#define SDMMC_INT_CMD_DONE RK2818_BIT(2) //Command Done -#define SDMMC_INT_RE RK2818_BIT(1) //Response Error -#define SDMMC_INT_CD RK2818_BIT(0) //Card Detect - -/* Command register defines(base+0x2C) */ -#define SDMMC_CMD_START RK2818_BIT(31) //start command -#define SDMMC_CMD_UPD_CLK RK2818_BIT(21) //update clock register only -#define SDMMC_CMD_INIT RK2818_BIT(15) //send initialization sequence -#define SDMMC_CMD_STOP RK2818_BIT(14) //stop abort command -#define SDMMC_CMD_PRV_DAT_NO_WAIT RK_CLEAR_BIT(13) //not wait previous data transfer complete, send command at once -#define SDMMC_CMD_PRV_DAT_WAIT RK2818_BIT(13) //wait previous data transfer complete -#define SDMMC_CMD_SEND_STOP RK2818_BIT(12) //send auto stop command at end of data transfer -#define SDMMC_CMD_BLOCK_MODE RK_CLEAR_BIT(11) //block data transfer command -#define SDMMC_CMD_STRM_MODE RK2818_BIT(11) //stream data transfer command -#define SDMMC_CMD_DAT_READ RK_CLEAR_BIT(10) //read from card -#define SDMMC_CMD_DAT_WRITE RK2818_BIT(10) //write to card; -#define SDMMC_CMD_DAT_WR RK2818_BIT(10) //write to card; -#define SDMMC_CMD_DAT_NO_EXP RK_CLEAR_BIT(9) //no data transfer expected -#define SDMMC_CMD_DAT_EXP RK2818_BIT(9) //data transfer expected -#define SDMMC_CMD_RESP_NO_CRC RK_CLEAR_BIT(8) //do not check response crc -#define SDMMC_CMD_RESP_CRC RK2818_BIT(8) //check response crc -#define SDMMC_CMD_RESP_CRC_NOCARE SDMMC_CMD_RESP_CRC //not care response crc -#define SDMMC_CMD_RESP_SHORT RK_CLEAR_BIT(7) //short response expected from card -#define SDMMC_CMD_RESP_LONG RK2818_BIT(7) //long response expected from card; -#define SDMMC_CMD_RESP_NOCARE SDMMC_CMD_RESP_SHORT //not care response length -#define SDMMC_CMD_RESP_NO_EXP RK_CLEAR_BIT(6) //no response expected from card -#define SDMMC_CMD_RESP_EXP RK2818_BIT(6) //response expected from card -#define SDMMC_CMD_INDX(n) ((n) & 0x1F) - - -/* Status register defines (base+0x48)*/ -#define SDMMC_STAUTS_DATA_BUSY RK2818_BIT(9) //Card busy -#define SDMMC_CMD_FSM_MASK (0x0F << 4) //Command FSM status mask -#define SDMMC_CMD_FSM_IDLE (0x00) //CMD FSM is IDLE -#define SDMMC_STAUTS_FIFO_FULL RK2818_BIT(3) //FIFO is full status -#define SDMMC_STAUTS_FIFO_EMPTY RK2818_BIT(2) //FIFO is empty status - -#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF)//fifo_count, numbers of filled locations in FIFO -#define SDMMC_FIFO_SZ 32 - - -/* FIFO Register (base + 0x4c)*/ -#define SD_MSIZE_1 (0x0 << 28) //DW_DMA_Multiple_Transaction_Size -#define SD_MSIZE_4 (0x1 << 28) -#define SD_MSIZE_8 (0x1 << 28) -#define SD_MSIZE_16 (0x3 << 28) -#define SD_MSIZE_32 (0x4 << 28) -#define SD_MSIZE_64 (0x5 << 28) -#define SD_MSIZE_128 (0x6 << 28) -#define SD_MSIZE_256 (0x7 << 28) - -#define FIFO_DEPTH (0x20) //FIFO depth = 32 word -#define RX_WMARK_SHIFT (16) -#define TX_WMARK_SHIFT (0) - -/* FIFO watermark */ -#define RX_WMARK (0xF) //RX watermark level set to 15 -#define TX_WMARK (0x10) //TX watermark level set to 16 - - -/* CDETECT register defines (base+0x50)*/ -#define SDMMC_CARD_DETECT_N RK2818_BIT(0) //0--represents presence of card. - -/* WRIPRT register defines (base+0x54)*/ -#define SDMMC_WRITE_PROTECT RK2818_BIT(0) // 1--represents write protect - - - -/* Specifies how often in millisecs to poll for card removal-insertion changes - * when the timer switch is open */ -#define RK_SDMMC0_SWITCH_POLL_DELAY 35 - - - -/* SDMMC progress return value */ -#define SDM_SUCCESS (0) -#define SDM_FALSE (1) -#define SDM_PARAM_ERROR (2) -#define SDM_RESP_ERROR (3) -#define SDM_RESP_TIMEOUT (4) -#define SDM_DATA_CRC_ERROR (5) -#define SDM_DATA_READ_TIMEOUT (6) -#define SDM_END_BIT_ERROR (7) -#define SDM_START_BIT_ERROR (8) -#define SDM_BUSY_TIMEOUT (9) -#define SDM_ERROR (10) //SDMMC host controller error -#define SDM_START_CMD_FAIL (11) -#define SDM_WAIT_FOR_CMDSTART_TIMEOUT (12) -#define SDM_WAIT_FOR_FIFORESET_TIMEOUT (13) - - - -#define FALSE 0 -#define TRUE 1 - - -#define DEBOUNCE_TIME (25) //uint is ms, recommend 5--25ms - - -#endif diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index e0356644d1aa..6fd20b428344 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -569,6 +569,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( host->ioaddr = pci_ioremap_bar(pdev, bar); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); + ret = -ENOMEM; goto release; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c279fbc4c2e5..e6c65a78c46c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1266,6 +1266,13 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; + /* + * If this tasklet gets rescheduled while running, it will + * be run again afterwards but without any active request. + */ + if (!host->mrq) + return; + spin_lock_irqsave(&host->lock, flags); del_timer(&host->timer); @@ -1277,7 +1284,7 @@ static void sdhci_tasklet_finish(unsigned long param) * upon error conditions. */ if (!(host->flags & SDHCI_DEVICE_DEAD) && - (mrq->cmd->error || + ((mrq->cmd && mrq->cmd->error) || (mrq->data && (mrq->data->error || (mrq->data->stop && mrq->data->stop->error))) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 4c24a7f83291..5689a0a889a9 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -541,14 +541,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) int p, highest, res; if (bdev->bd_part_count) - { - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d.. The sdcard partition have been using.So device busy! ====xbw===\n",__FUNCTION__, __LINE__); - } - return -EBUSY; - } res = invalidate_partition(disk, 0); if (res) return res; @@ -563,14 +556,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) check_disk_size_change(disk, bdev); bdev->bd_invalidated = 0; if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) - { - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d... ==== check partition fail. partitionAddr=%x ====xbw===\n",__FUNCTION__, __LINE__, state); - } - return 0; - } if (IS_ERR(state)) /* I/O error reading the partition table */ return -EIO; diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index 49cfd5f54238..2aac7764b7e5 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c @@ -349,6 +349,12 @@ is_gpt_valid(struct block_device *bdev, u64 lba, goto fail; } + /* Check that sizeof_partition_entry has the correct value */ + if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) { + pr_debug("GUID Partitition Entry Size check failed.\n"); + goto fail; + } + if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt))) goto fail; diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 8652fb99e962..dd6efdba939f 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c @@ -251,6 +251,11 @@ static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm) } vm->vblk_size = get_unaligned_be32(data + 0x08); + if (vm->vblk_size == 0) { + ldm_error ("Illegal VBLK size"); + return false; + } + vm->vblk_offset = get_unaligned_be32(data + 0x0C); vm->last_vblk_seq = get_unaligned_be32(data + 0x04); @@ -1294,6 +1299,11 @@ static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags) BUG_ON (!data || !frags); + if (size < 2 * VBLK_SIZE_HEAD) { + ldm_error("Value of size is to small."); + return false; + } + group = get_unaligned_be32(data + 0x08); rec = get_unaligned_be16(data + 0x0C); num = get_unaligned_be16(data + 0x0E); @@ -1301,6 +1311,10 @@ static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags) ldm_error ("A VBLK claims to have %d parts.", num); return false; } + if (rec >= num) { + ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num); + return false; + } list_for_each (item, frags) { f = list_entry (item, struct frag, list); @@ -1321,6 +1335,11 @@ static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags) list_add_tail (&f->list, frags); found: + if (rec >= f->num) { + ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num); + return false; + } + if (f->map & (1 << rec)) { ldm_error ("Duplicate VBLK, part %d.", rec); f->map &= 0x7F; /* Mark the group as broken */ @@ -1329,10 +1348,9 @@ found: f->map |= (1 << rec); - if (num > 0) { - data += VBLK_SIZE_HEAD; - size -= VBLK_SIZE_HEAD; - } + data += VBLK_SIZE_HEAD; + size -= VBLK_SIZE_HEAD; + memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size); return true; diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index d4a0fad3563b..5765198e9228 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c @@ -29,10 +29,9 @@ static inline void mac_fix_string(char *stg, int len) int mac_partition(struct parsed_partitions *state, struct block_device *bdev) { - int slot = 1; Sector sect; unsigned char *data; - int blk, blocks_in_map; + int slot, blocks_in_map; unsigned secsize; #ifdef CONFIG_PPC_PMAC int found_root = 0; @@ -59,10 +58,14 @@ int mac_partition(struct parsed_partitions *state, struct block_device *bdev) put_dev_sector(sect); return 0; /* not a MacOS disk */ } - printk(" [mac]"); blocks_in_map = be32_to_cpu(part->map_count); - for (blk = 1; blk <= blocks_in_map; ++blk) { - int pos = blk * secsize; + if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) { + put_dev_sector(sect); + return 0; + } + printk(" [mac]"); + for (slot = 1; slot <= blocks_in_map; ++slot) { + int pos = slot * secsize; put_dev_sector(sect); data = read_dev_sector(bdev, pos/512, §); if (!data) @@ -113,13 +116,11 @@ int mac_partition(struct parsed_partitions *state, struct block_device *bdev) } if (goodness > found_root_goodness) { - found_root = blk; + found_root = slot; found_root_goodness = goodness; } } #endif /* CONFIG_PPC_PMAC */ - - ++slot; } #ifdef CONFIG_PPC_PMAC if (found_root_goodness) diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index c79407ee4bbc..90be97f1f5a8 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -440,11 +440,6 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) return 0; } - if(179 == MAJOR(bdev->bd_dev)) - { - printk("\n%s..%d... ==== Begin to parse sdcard-partition. ====xbw[mmc0]===\n",__FUNCTION__, __LINE__); - } - /* * Now that the 55aa signature is present, this is probably * either the boot sector of a FAT filesystem or a DOS-type @@ -454,12 +449,6 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) p = (struct partition *) (data + 0x1be); for (slot = 1; slot <= 4; slot++, p++) { if (p->boot_ind != 0 && p->boot_ind != 0x80) { - - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d... ==== The sdcard has not MBR. ====xbw[mmc0]===\n",__FUNCTION__, __LINE__); - } - /* * Even without a valid boot inidicator value * its still possible this is valid FAT filesystem @@ -470,21 +459,9 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) && fat_valid_media(fb->media)) { printk("\n"); put_dev_sector(sect); - - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d... ==== The DBR(slot=%d) is valid. ====xbw[mmc0]===\n",__FUNCTION__, __LINE__, slot); - } - return 1; } else { put_dev_sector(sect); - - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d... ==== The DBR is invalid. ====xbw[mmc0]===\n",__FUNCTION__, __LINE__); - } - return 0; } } @@ -496,7 +473,6 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) /* If this is an EFI GPT disk, msdos should ignore it. */ if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) { put_dev_sector(sect); - return 0; } } @@ -509,24 +485,12 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) * On the second pass look inside *BSD, Unixware and Solaris partitions. */ - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d... ==== The sdcard has MBR. ====xbw[mmc0]===\n", __FUNCTION__, __LINE__); - } state->next = 5; for (slot = 1 ; slot <= 4 ; slot++, p++) { sector_t start = start_sect(p)*sector_size; sector_t size = nr_sects(p)*sector_size; - if (!size) continue; - - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d... ==== partition-%d, size=%luKB ====xbw[mmc0]===\n",\ - __FUNCTION__, __LINE__, slot, size/2); - } - if (is_extended_partition(p)) { /* * prevent someone doing mkfs or mkswap on an @@ -536,11 +500,6 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) */ sector_t n = 2; n = min(size, max(sector_size, n)); - - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s...%d... ==== extend partition-%d....====xbw[mmc0]===\n",__FUNCTION__, __LINE__, slot); - } put_partition(state, slot, start, n); printk(" <"); @@ -548,12 +507,6 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) printk(" >"); continue; } - - if(179 == MAJOR(bdev->bd_dev)) - { - printk("%s..%d... ==== main partition-%d....====xbw[mmc0]===\n",__FUNCTION__, __LINE__, slot); - } - put_partition(state, slot, start, size); if (SYS_IND(p) == LINUX_RAID_PARTITION) state->parts[slot].flags = 1; diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c index c05c17bc5df3..9ddca5891278 100644 --- a/fs/partitions/osf.c +++ b/fs/partitions/osf.c @@ -10,10 +10,13 @@ #include "check.h" #include "osf.h" +#define MAX_OSF_PARTITIONS 18 + int osf_partition(struct parsed_partitions *state, struct block_device *bdev) { int i; int slot = 1; + unsigned int npartitions; Sector sect; unsigned char *data; struct disklabel { @@ -45,7 +48,7 @@ int osf_partition(struct parsed_partitions *state, struct block_device *bdev) u8 p_fstype; u8 p_frag; __le16 p_cpg; - } d_partitions[8]; + } d_partitions[MAX_OSF_PARTITIONS]; } * label; struct d_partition * partition; @@ -63,7 +66,12 @@ int osf_partition(struct parsed_partitions *state, struct block_device *bdev) put_dev_sector(sect); return 0; } - for (i = 0 ; i < le16_to_cpu(label->d_npartitions); i++, partition++) { + npartitions = le16_to_cpu(label->d_npartitions); + if (npartitions > MAX_OSF_PARTITIONS) { + put_dev_sector(sect); + return 0; + } + for (i = 0 ; i < npartitions; i++, partition++) { if (slot == state->limit) break; if (le32_to_cpu(partition->p_size)) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 00a015a19412..01f21a50a2bf 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -14,6 +14,7 @@ #include #include +#include struct mmc_ios { unsigned int clock; /* clock rate */ @@ -123,6 +124,7 @@ struct mmc_host { unsigned int f_min; unsigned int f_max; u32 ocr_avail; + struct notifier_block pm_notify; #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ @@ -180,6 +182,7 @@ struct mmc_host { /* Only used with MMC_CAP_DISABLE */ int enabled; /* host is enabled */ + int rescan_disable; /* disable card detection */ int nesting_cnt; /* "enable" nesting count */ int en_dis_recurs; /* detect recursion */ unsigned int disable_delay; /* disable delay in msecs */ @@ -200,12 +203,12 @@ struct mmc_host { #define MMC_BUSRESUME_MANUAL_RESUME (1 << 0) #define MMC_BUSRESUME_NEEDS_RESUME (1 << 1) - unsigned int re_initialized_flags; //in order to begin the rescan ; added by xbw@2011-04-07 - unsigned int sdio_irqs; struct task_struct *sdio_irq_thread; atomic_t sdio_irq_thread_abort; + mmc_pm_flag_t pm_flags; /* requested pm features */ + #ifdef CONFIG_LEDS_TRIGGERS struct led_trigger *led; /* activity led */ #endif @@ -286,6 +289,7 @@ int mmc_card_can_sleep(struct mmc_host *host); int mmc_host_enable(struct mmc_host *host); int mmc_host_disable(struct mmc_host *host); int mmc_host_lazy_disable(struct mmc_host *host); +int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *); static inline void mmc_set_disable_delay(struct mmc_host *host, unsigned int disable_delay) diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index b96f110efbb4..c02c8db73701 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -282,18 +282,5 @@ struct _mmc_csd { #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ - -/* -* some limit value of SDMMC about protocol ; Added by xbw at 2011-03-21 -*/ -#define FOD_FREQ (300000) // in the identify stage, unit: hz, max is 400Khz, - // the least frequency is FREQ_HCLK_MAX/8 -#define SD_FPP_FREQ (24000000) // normal sd freq, 25Mhz -#define SDHC_FPP_FREQ (49000000) // SDHC in the highspeed. unit is hz, max is 50Mhz. -#define MMC_FPP_FREQ (19000000) // MMC freq, unit is hz, max is 20MHz -#define MMCHS_26_FPP_FREQ (24000000) // highspeed mode support 26M HS-MMC, unit is hz, max is 26Mhz, -#define MMCHS_52_FPP_FREQ (49000000) // highspeed support 52M HS-MMC, unit is hz, max is 52Mhz, - - #endif /* MMC_MMC_PROTOCOL_H */ -- 2.34.1