Vipin Bhandari <[email protected]> writes:
> The scatterlist traversal is made proper. The patch has some minor
> comments modification and also sets the value written to the
> DAVINCI_MMCTOR register properly. The timeout calculation is made
> proper by deriving it from the clock values.
>
> This patch incorporates the review comments given on LKLM by
> Pierre Ossman.
> Many thanks to David Brownell for his all support for review.
>
> Signed-off-by: Vipin Bhandari <[email protected]>
> Signed-off-by: Purushotam Kumar <[email protected]>
Pierre has had some more questions/comments on LKML. Are you planning
to address those and re-submit upstream?
I'd like to see this driver get re-submitted upstream before pulling
into DaVinci git.
Kevin
> ---
> drivers/mmc/host/davinci_mmc.c | 102 +++++++++++++++++++++------------------
> 1 files changed, 55 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
> index 9b23802..c595934 100644
> --- a/drivers/mmc/host/davinci_mmc.c
> +++ b/drivers/mmc/host/davinci_mmc.c
> @@ -30,9 +30,9 @@
> #include <linux/irq.h>
> #include <linux/delay.h>
> #include <linux/dma-mapping.h>
> +#include <linux/mmc/mmc.h>
>
> #include <mach/mmc.h>
> -#include <mach/cpu.h>
> #include <mach/edma.h>
>
> /*
> @@ -130,7 +130,7 @@
> #define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */
>
>
> -/* MMCSD Init clock in Hz in opendain mode */
> +/* MMCSD Init clock in Hz in opendrain mode */
> #define MMCSD_INIT_CLOCK 200000
>
> /*
> @@ -194,21 +194,20 @@ struct mmc_davinci_host {
>
> /* For PIO we walk scatterlists one segment at a time. */
> unsigned int sg_len;
> - int sg_idx;
> + struct scatterlist *sg;
>
> /* Version of the MMC/SD controller */
> u8 version;
> + /* for ns in one cycle calculation */
> + unsigned ns_in_one_cycle;
> };
>
>
> /* PIO only */
> static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
> {
> - struct scatterlist *sg;
> -
> - sg = host->data->sg + host->sg_idx;
> - host->buffer_bytes_left = sg_dma_len(sg);
> - host->buffer = sg_virt(sg);
> + host->buffer_bytes_left = sg_dma_len(host->sg);
> + host->buffer = sg_virt(host->sg);
> if (host->buffer_bytes_left > host->bytes_left)
> host->buffer_bytes_left = host->bytes_left;
> }
> @@ -220,8 +219,7 @@ static void davinci_fifo_data_trans(struct
> mmc_davinci_host *host,
> unsigned int i;
>
> if (host->buffer_bytes_left == 0) {
> - host->sg_idx++;
> - BUG_ON(host->sg_idx == host->sg_len);
> + host->sg = sg_next(host->data->sg);
> mmc_davinci_sg_to_buf(host);
> }
>
> @@ -312,10 +310,6 @@ static void mmc_davinci_start_command(struct
> mmc_davinci_host *host,
> /* Set command index */
> cmd_reg |= cmd->opcode;
>
> - /* Setting initialize clock */
> - if (cmd->opcode == 0)
> - cmd_reg |= MMCCMD_INITCK;
> -
> /* Enable EDMA transfer triggers */
> if (host->do_dma)
> cmd_reg |= MMCCMD_DMATRIG;
> @@ -340,7 +334,7 @@ static void mmc_davinci_start_command(struct
> mmc_davinci_host *host,
> cmd_reg |= MMCCMD_PPLEN;
>
> /* set Command timeout */
> - writel(0xFFFF, host->base + DAVINCI_MMCTOR);
> + writel(0x1FFF, host->base + DAVINCI_MMCTOR);
>
> /* Enable interrupt (calculate here, defer until FIFO is stuffed). */
> im_val = MMCST0_RSPDNE | MMCST0_CRCRS | MMCST0_TOUTRS;
> @@ -358,10 +352,10 @@ static void mmc_davinci_start_command(struct
> mmc_davinci_host *host,
>
> /*
> * Before non-DMA WRITE commands the controller needs priming:
> - * FIFO should be populated with 32 bytes
> + * FIFO should be populated with 32 bytes i.e. whatever is the FIFO size
> */
> if (!host->do_dma && (host->data_dir == DAVINCI_MMC_DATADIR_WRITE))
> - davinci_fifo_data_trans(host, 32);
> + davinci_fifo_data_trans(host, rw_threshold);
>
> writel(cmd->arg, host->base + DAVINCI_MMCARGHL);
> writel(cmd_reg, host->base + DAVINCI_MMCCMD);
> @@ -489,13 +483,14 @@ static void mmc_davinci_send_dma_request(struct
> mmc_davinci_host *host,
> }
>
> /* We know sg_len and ccnt will never be out of range because
> - * we told the block layer to ensure that it only hands us one
> - * scatterlist segment per EDMA PARAM entry. Update the PARAM
> + * we told the mmc layer which in turn tells the block layer
> + * to ensure that it only hands us one scatterlist segment
> + * per EDMA PARAM entry. Update the PARAM
> * entries needed for each segment of this scatterlist.
> */
> for (slot = channel, link = 0, sg = data->sg, sg_len = host->sg_len;
> sg_len-- != 0 && bytes_left;
> - sg++, slot = host->links[link++]) {
> + sg = sg_next(sg), slot = host->links[link++]) {
> u32 buf = sg_dma_address(sg);
> unsigned count = sg_dma_len(sg);
>
> @@ -638,11 +633,8 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host,
> struct mmc_request *req)
> data->blocks, data->blksz);
> dev_dbg(mmc_dev(host->mmc), " DTO %d cycles + %d ns\n",
> data->timeout_clks, data->timeout_ns);
> -
> - /* Convert ns to clock cycles by assuming 20MHz frequency
> - * 1 cycle at 20MHz = 500 ns
> - */
> - timeout = data->timeout_clks + data->timeout_ns / 500;
> + timeout = data->timeout_clks +
> + (data->timeout_ns / host->ns_in_one_cycle);
> if (timeout > 0xffff)
> timeout = 0xffff;
>
> @@ -686,8 +678,8 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host,
> struct mmc_request *req)
> host->bytes_left = 0;
> } else {
> /* Revert to CPU Copy */
> - host->sg_idx = 0;
> host->sg_len = data->sg_len;
> + host->sg = host->data->sg;
> mmc_davinci_sg_to_buf(host);
> }
> }
> @@ -722,21 +714,30 @@ static void mmc_davinci_request(struct mmc_host *mmc,
> struct mmc_request *req)
> static unsigned int calculate_freq_for_card(struct mmc_davinci_host *host,
> unsigned int mmc_req_freq)
> {
> - unsigned int mmc_freq = 0, cpu_arm_clk = 0, mmc_push_pull = 0;
> + unsigned int mmc_freq = 0, cpu_arm_clk = 0, mmc_push_pull_divisor = 0;
>
> cpu_arm_clk = host->mmc_input_clk;
> - if (cpu_arm_clk > (2 * mmc_req_freq))
> - mmc_push_pull = ((unsigned int)cpu_arm_clk
> + if (mmc_req_freq && cpu_arm_clk > (2 * mmc_req_freq))
> + mmc_push_pull_divisor = ((unsigned int)cpu_arm_clk
> / (2 * mmc_req_freq)) - 1;
> else
> - mmc_push_pull = 0;
> + mmc_push_pull_divisor = 0;
>
> - mmc_freq = (unsigned int)cpu_arm_clk / (2 * (mmc_push_pull + 1));
> + mmc_freq = (unsigned int)cpu_arm_clk
> + / (2 * (mmc_push_pull_divisor + 1));
>
> if (mmc_freq > mmc_req_freq)
> - mmc_push_pull = mmc_push_pull + 1;
> + mmc_push_pull_divisor = mmc_push_pull_divisor + 1;
> +
> + /* Convert ns to clock cycles */
> + if (mmc_req_freq < 400000)
> + host->ns_in_one_cycle = 1000000 / ((cpu_arm_clk
> + / (2 * (mmc_push_pull_divisor + 1)))/1000);
> + else
> + host->ns_in_one_cycle = 1000000 / ((cpu_arm_clk
> + / (2 * (mmc_push_pull_divisor + 1)))/1000000);
>
> - return mmc_push_pull;
> + return mmc_push_pull_divisor;
> }
>
> static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> @@ -762,11 +763,22 @@ static void mmc_davinci_set_ios(struct mmc_host *mmc,
> struct mmc_ios *ios)
>
> if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
> u32 temp;
> +
> + /* Ignoring the init clock value passed for fixing the inter
> + * operability with different cards.
> + */
> open_drain_freq = ((unsigned int)cpu_arm_clk
> / (2 * MMCSD_INIT_CLOCK)) - 1;
> - temp = readl(host->base + DAVINCI_MMCCLK) & ~0xFF;
> +
> + if (open_drain_freq > 0xFF)
> + open_drain_freq = 0xFF;
> +
> + temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKRT_MASK;
> temp |= open_drain_freq;
> writel(temp, host->base + DAVINCI_MMCCLK);
> +
> + /* Convert ns to clock cycles */
> + host->ns_in_one_cycle = (1000000) / (MMCSD_INIT_CLOCK/1000);
> } else {
> u32 temp;
> mmc_push_pull_freq = calculate_freq_for_card(host, ios->clock);
> @@ -863,10 +875,6 @@ davinci_abort_data(struct mmc_davinci_host *host, struct
> mmc_data *data)
> {
> u32 temp;
>
> - /* record how much data we transferred */
> - temp = readl(host->base + DAVINCI_MMCNBLC);
> - data->bytes_xfered += (data->blocks - temp) * data->blksz;
> -
> /* reset command and data state machines */
> temp = readl(host->base + DAVINCI_MMCCTL);
> writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
> @@ -922,7 +930,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
> davinci_fifo_data_trans(host, host->bytes_left);
> }
> end_transfer = 1;
> - data->bytes_xfered += data->blocks * data->blksz;
> + data->bytes_xfered = data->blocks * data->blksz;
> } else {
> dev_err(mmc_dev(host->mmc),
> "DATDNE with no host->data\n");
> @@ -984,9 +992,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
> /* Command CRC error */
> dev_dbg(mmc_dev(host->mmc), "Command CRC error\n");
> if (host->cmd) {
> - /* Ignore CMD CRC errors during high speed operation */
> - if (host->mmc->ios.clock <= 25000000)
> - host->cmd->error = -EILSEQ;
> + host->cmd->error = -EILSEQ;
> end_command = 1;
> }
> }
> @@ -1047,7 +1053,7 @@ static void __init init_mmcsd_host(struct
> mmc_davinci_host *host)
> writel(0, host->base + DAVINCI_MMCCLK);
> writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK);
>
> - writel(0xFFFF, host->base + DAVINCI_MMCTOR);
> + writel(0x1FFF, host->base + DAVINCI_MMCTOR);
> writel(0xFFFF, host->base + DAVINCI_MMCTOD);
>
> writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_DATRST,
> @@ -1076,7 +1082,7 @@ static int __init davinci_mmcsd_probe(struct
> platform_device *pdev)
> goto out;
>
> ret = -EBUSY;
> - mem_size = r->end - r->start + 1;
> + mem_size = resource_size(r);
> mem = request_mem_region(r->start, mem_size, pdev->name);
> if (!mem)
> goto out;
> @@ -1111,6 +1117,7 @@ static int __init davinci_mmcsd_probe(struct
> platform_device *pdev)
> goto out;
> }
> clk_enable(host->clk);
> + host->ns_in_one_cycle = 1;
> host->mmc_input_clk = clk_get_rate(host->clk);
>
> init_mmcsd_host(host);
> @@ -1132,9 +1139,9 @@ static int __init davinci_mmcsd_probe(struct
> platform_device *pdev)
> mmc->ops = &mmc_davinci_ops;
> mmc->f_min = 312500;
> mmc->f_max = 25000000;
> - if (pdata->max_freq)
> + if (pdata && pdata->max_freq)
> mmc->f_max = pdata->max_freq;
> - if (pdata->caps)
> + if (pdata && pdata->caps)
> mmc->caps |= pdata->caps;
> mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
>
> @@ -1149,7 +1156,7 @@ static int __init davinci_mmcsd_probe(struct
> platform_device *pdev)
> mmc->max_seg_size = MAX_CCNT * rw_threshold;
>
> /* MMC/SD controller limits for multiblock requests */
> - mmc->max_blk_size = 4095; /* BLEN is 11 bits */
> + mmc->max_blk_size = 4095; /* BLEN is 12 bits */
> mmc->max_blk_count = 65535; /* NBLK is 16 bits */
> mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
>
> @@ -1267,5 +1274,6 @@ static void __exit davinci_mmcsd_exit(void)
> }
> module_exit(davinci_mmcsd_exit);
>
> +MODULE_AUTHOR("Texas Instruments India <[email protected]>");
> MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("MMC/SD driver for Davinci MMC controller");
> --
> 1.5.6
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source