Read in the mmc v4 EXT_CSD and populate the mmc_ext_csd.
--phil
Signed-off-by: Philip Langdale <[email protected]>
---
mmc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
--- linux-old/drivers/mmc/mmc.c 2006-04-08 13:12:18.000000000 -0700 +++ linux/drivers/mmc/mmc.c 2006-04-08
13:12:25.000000000 -0700
@@ -953,6 +953,88 @@
}
}
+static void mmc_read_ext_csds(struct mmc_host *host)
+{
+ int err;
+ struct mmc_card *card;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+
+ struct scatterlist sg;
+
+ /*
+ * As the ext_csd is so large and mostly unused, we don't store the
+ * raw block in mmc_card.
+ */
+ u8 ext_csd[512];
+
+ list_for_each_entry(card, &host->cards, node) {
+ if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+ continue;
+ if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+ continue;
+
+ err = mmc_select_card(host, card);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_EXT_CSD;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 10;
+ data.timeout_clks = card->csd.tacc_clks * 10;
+ data.blksz_bits = 9;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, &ext_csd, 512);
+
+ mmc_wait_for_req(host, &mrq);
+
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ card->ext_csd.cmd_set_rev = ext_csd[EXT_CSD_CMD_SET_REV];
+ card->ext_csd.ext_csd_rev = ext_csd[EXT_CSD_EXT_CSD_REV];
+ card->ext_csd.csd_structure = ext_csd[EXT_CSD_CSD_STRUCTURE];
+ card->ext_csd.card_type = ext_csd[EXT_CSD_CARD_TYPE];
+
+ card->ext_csd.pwr_cl_52_195 = ext_csd[EXT_CSD_PWR_CL_52_195];
+ card->ext_csd.pwr_cl_26_195 = ext_csd[EXT_CSD_PWR_CL_26_195];
+ card->ext_csd.pwr_cl_52_360 = ext_csd[EXT_CSD_PWR_CL_52_360];
+ card->ext_csd.pwr_cl_26_360 = ext_csd[EXT_CSD_PWR_CL_26_360];
+
+ card->ext_csd.min_perf_r_4_26 = ext_csd[EXT_CSD_MIN_PERF_R_4_26];
+ card->ext_csd.min_perf_w_4_26 = ext_csd[EXT_CSD_MIN_PERF_W_4_26];
+ card->ext_csd.min_perf_r_8_26_4_52 = ext_csd[EXT_CSD_MIN_PERF_R_8_26_4_52];
+ card->ext_csd.min_perf_w_8_26_4_52 = ext_csd[EXT_CSD_MIN_PERF_W_8_26_4_52];
+ card->ext_csd.min_perf_r_8_52 = ext_csd[EXT_CSD_MIN_PERF_R_8_52];
+ card->ext_csd.min_perf_w_8_52 = ext_csd[EXT_CSD_MIN_PERF_W_8_52];
+
+ card->ext_csd.s_cmd_set = ext_csd[EXT_CSD_S_CMD_SET];
+ }
+
+ mmc_deselect_cards(host);
+}
+
static void mmc_read_scrs(struct mmc_host *host)
{
int err;
@@ -1153,6 +1420,8 @@
if (host->mode == MMC_MODE_SD)
mmc_read_scrs(host);
+ else
+ mmc_read_ext_csds(host);
}
[email protected] wrote:
> + list_for_each_entry(card, &host->cards, node) {
> + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
> + continue;
>
Please use the macros.
> + if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> + continue;
> +
>
You need to check that the card isn't SD before you can look at that
part of the csd structure. BUG_ON or similar is acceptable if you
consider it an error to call this function if SD cards are present.
> + err = mmc_select_card(host, card);
> + if (err != MMC_ERR_NONE) {
> + mmc_card_set_dead(card);
> + continue;
> + }
> +
> + memset(&cmd, 0, sizeof(struct mmc_command));
> +
> + cmd.opcode = MMC_SEND_EXT_CSD;
> + cmd.arg = 0;
> + cmd.flags = MMC_RSP_R1;
> +
> + memset(&data, 0, sizeof(struct mmc_data));
> +
> + data.timeout_ns = card->csd.tacc_ns * 10;
> + data.timeout_clks = card->csd.tacc_clks * 10;
>
We have a new function for setting timeouts that you should use called
mmc_set_data_timeout().
Rgds
Pierre
Pierre,
I will reorganise these patches into a series that detects and sets up
high-speed support. This is pretty simple. Wide-bus is harder because
you have to run their weird test pattern and check all the power class
stuff. Hopefully I'll have that done this week.
Pierre Ossman wrote:
> [email protected] wrote:
>> + list_for_each_entry(card, &host->cards, node) {
>> + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
>> + continue;
>>
>
> Please use the macros.
I'm confused: mmc_read_scrs and mmc_read_csds use this exact same
construction in 2.6.18 and Linus' current tree. Should I be checking
another tree?
Will address all other comments.
Thanks,
--phil
Philip Langdale wrote:
> Pierre,
>
> I will reorganise these patches into a series that detects and sets up
> high-speed support. This is pretty simple. Wide-bus is harder because
> you have to run their weird test pattern and check all the power class
> stuff. Hopefully I'll have that done this week.
>
Goodie. Have these patches seen any wide spread testing?
> Pierre Ossman wrote:
>
>> [email protected] wrote:
>>
>>> + list_for_each_entry(card, &host->cards, node) {
>>> + if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
>>> + continue;
>>>
>>>
>> Please use the macros.
>>
>
> I'm confused: mmc_read_scrs and mmc_read_csds use this exact same
> construction in 2.6.18 and Linus' current tree. Should I be checking
> another tree?
>
>
Nah, they're also wrong. Patches welcome ;)
Rgds
Pierre
Pierre Ossman wrote:
>
>Goodie. Have these patches seen any wide spread testing?
Several people tried in on Nokia N770. So far there were no error
reports and some successful ones. Speed selection (52 vs 26Mhz) seems to
work fine.
Succesful report examples:
http://www.gossamer-threads.com/lists/maemo/developers/11613#11613
http://www.gossamer-threads.com/lists/maemo/developers/11573#11573
I wouldn't call it widespread testing but it definitely works for some
people.
Frantisek