[PATCH] mmc: core: add core-level function for sending tuning commands

Barry Song 21cnbao at gmail.com
Mon Nov 24 19:19:26 PST 2014


2014-11-24 19:44 GMT+08:00 Ulf Hansson <ulf.hansson at linaro.org>:
> On 21 November 2014 at 15:46, Barry Song <21cnbao at gmail.com> wrote:
>> From: Minda Chen <Minda.Chen at csr.com>
>>
>> According to the SD card spec, Add a manual tuning command function
>> for SDR104/HS200 by sending command 19 or command 21 to read data
>> and compare with the tuning block pattern.
>>
>> this patch will help to decrease some platform private codes in
>> SDHCI platform_execute_tuning() callbacks.
>>
>> Signed-off-by: Minda Chen <Minda.Chen at csr.com>
>> Signed-off-by: Barry Song <Baohua.Song at csr.com>
>> ---
>>  drivers/mmc/core/mmc_ops.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/mmc/core.h   |  1 +
>>  2 files changed, 66 insertions(+)
>>
>> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
>> index 7911e05..ecc7789 100644
>> --- a/drivers/mmc/core/mmc_ops.c
>> +++ b/drivers/mmc/core/mmc_ops.c
>> @@ -543,6 +543,71 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>>  }
>>  EXPORT_SYMBOL_GPL(mmc_switch);
>>
>> +int mmc_send_tuning(struct mmc_card *card, u32 opcode)
>> +{
>> +       struct mmc_request mrq = {NULL};
>> +       struct mmc_command cmd = {0};
>> +       struct mmc_data data = {0};
>> +       struct scatterlist sg;
>> +       struct mmc_host *mmc = card->host;
>> +       struct mmc_ios *ios = &mmc->ios;
>> +       const u8 *tuning_block_pattern;
>> +       int size, err = 0;
>> +       u8 *data_buf;
>> +
>> +       if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
>
> I don't think we need to care about the opcode. Let's just check the bus_width.
>
>> +               if (ios->bus_width == MMC_BUS_WIDTH_8) {
>> +                       tuning_block_pattern = tuning_blk_pattern_8bit;
>> +                       size = sizeof(tuning_blk_pattern_8bit);
>> +               } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
>> +                       tuning_block_pattern = tuning_blk_pattern_4bit;
>> +                       size = sizeof(tuning_blk_pattern_4bit);
>> +               } else
>> +                       return -EINVAL;
>> +       } else if (opcode == MMC_SEND_TUNING_BLOCK) {
>> +               tuning_block_pattern = tuning_blk_pattern_4bit;
>> +               size = sizeof(tuning_blk_pattern_4bit);
>> +       } else
>> +               return -EINVAL;
>> +
>> +       data_buf = kmalloc(size, GFP_KERNEL);
>
> You should use kzalloc() to get the zeroed buffer you want.
>
>> +       if (!data_buf)
>> +               return -ENOMEM;
>> +
>> +       mrq.cmd = &cmd;
>> +       mrq.data = &data;
>> +
>> +       cmd.opcode = opcode;
>> +       cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
>> +
>> +       data.blksz = size;
>> +       data.blocks = 1;
>> +       data.flags = MMC_DATA_READ;
>
> These needs to be assigned as well:
>
> data.sg = &sg;
> data.sg_len = 1;
>
>> +
>> +       mmc_set_data_timeout(&data, card);
>
> mmc_set_data_timeout() doesn't handle CMD21/19.
>
> The specs tells us about 40 commands should be executed within 150ms.
> I would pick a value of 150ms, just to be sure we are inside that
> range. Also, assign "data->timeout_ns" here, instead of relying on
> mmc_set_data_timeout().
>
>> +       sg_init_one(&sg, data_buf, size);
>> +       memset(data_buf, 0, size);
>> +       mmc_wait_for_req(mmc, &mrq);
>> +
>> +       if (cmd.error) {
>> +               err = cmd.error;
>> +               goto out;
>> +       }
>> +
>> +       if (data.error) {
>> +               err = data.error;
>> +               goto out;
>> +       }
>> +
>> +       if (memcmp(data_buf, tuning_block_pattern, size))
>> +               err = -EIO;
>> +
>> +out:
>> +       kfree(data_buf);
>> +       return err;
>> +}
>> +EXPORT_SYMBOL_GPL(mmc_send_tuning);
>> +
>>  static int
>>  mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
>>                   u8 len)
>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
>> index f206e29..82a0119 100644
>> --- a/include/linux/mmc/core.h
>> +++ b/include/linux/mmc/core.h
>> @@ -154,6 +154,7 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
>>  extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
>>                         bool, bool);
>>  extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
>> +extern int mmc_send_tuning(struct mmc_card *, u32);
>>  extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
>>
>>  #define MMC_ERASE_ARG          0x00000000
>> --
>> 2.1.1
>>

What about?

546 int mmc_send_tuning(struct mmc_card *card)
547 {
548         struct mmc_request mrq = {NULL};
549         struct mmc_command cmd = {0};
550         struct mmc_data data = {0};
551         struct scatterlist sg;
552         struct mmc_host *mmc = card->host;
553         struct mmc_ios *ios = &mmc->ios;
554         const u8 *tuning_block_pattern;
555         int size, err = 0;
556         u8 *data_buf;
557         u32 opcode;
558
559         if (ios->bus_width == MMC_BUS_WIDTH_8) {
560                 tuning_block_pattern = tuning_blk_pattern_8bit;
561                 size = sizeof(tuning_blk_pattern_8bit);
562                 opcode = MMC_SEND_TUNING_BLOCK_HS200;
563         } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
564                 tuning_block_pattern = tuning_blk_pattern_4bit;
565                 size = sizeof(tuning_blk_pattern_4bit);
566                 opcode = MMC_SEND_TUNING_BLOCK;
567         } else
568                 return -EINVAL;
569
570         data_buf = kzalloc(size, GFP_KERNEL);
571         if (!data_buf)
572                 return -ENOMEM;
573
574         mrq.cmd = &cmd;
575         mrq.data = &data;
576
577         cmd.opcode = opcode;
578         cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
579
580         data.blksz = size;
581         data.blocks = 1;
582         data.flags = MMC_DATA_READ;
583
584         /*
585          * According to the tuning specs, Tuning process
586          * is normally shorter 40 executions of CMD19,
587          * and timeout value should be shorter than 150 ms
588          */
589         data.timeout_ns = 150 * NSEC_PER_MSEC;
590
591         data.sg = &sg;
592         data.sg_len = 1;
593         sg_init_one(&sg, data_buf, size);
594
595         mmc_wait_for_req(mmc, &mrq);
596
597         if (cmd.error) {
598                 err = cmd.error;
599                 goto out;
600         }
601
602         if (data.error) {
603                 err = data.error;
604                 goto out;
605         }
606
607         if (memcmp(data_buf, tuning_block_pattern, size))
608                 err = -EIO;
609
610 out:
611         kfree(data_buf);
612         return err;
613 }
614 EXPORT_SYMBOL_GPL(mmc_send_tuning);

>
> Kind regards
> Uffe

-barry



More information about the linux-arm-kernel mailing list