* [patch 2.6.22-git5 0/4] MMC-over-SPI @ 2007-07-14 22:04 David Brownell [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-14 22:04 UTC (permalink / raw) To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Anton Vorontsov, Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, Pierre Ossman Here's an updated version of the MMC-over-SPI patches, reworked to address most of Pierre's issues (moving even more code into the MMC core) and to clean up the I/O paths. To build/run these, you'll need the CRC7 patch from recent MM trees. - headers learn about SPI - mmc_block learns about SPI - mmc core updates - mmc_spi host driver The bits related to card lock/unlock aren't included here, since those didn't go upstream yet. ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* [patch 2.6.22-git5 1/4] MMC headers learn about SPI [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-14 22:05 ` David Brownell [not found] ` <200707141506.00262.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-14 22:06 ` [patch 2.6.22-git5 2/4] MMC block learns " David Brownell ` (3 subsequent siblings) 4 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-14 22:05 UTC (permalink / raw) To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Anton Vorontsov, Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, Pierre Ossman Teach the MMC/SD/SDIO system headers that some hosts use SPI mode - New host capabilities and status bits * MMC_CAP_SPI, with mmc_host_is_spi() test * mmc_host.use_spi-crc flag - SPI-specific declarations: * Response types, MMC_RSP_SPI_R* * Two SPI-only commands * Status bits used native to SPI: R1_SPI_*, R2_SPI_* - Fix a few (unrelated) whitespace bugs in the headers. - Reorder a few mmc_host fields, removing several bytes of padding None of these changes affect current code. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- include/linux/mmc/core.h | 23 ++++++++++++++++++++-- include/linux/mmc/host.h | 9 ++++++-- include/linux/mmc/mmc.h | 48 ++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 69 insertions(+), 11 deletions(-) --- g26.orig/include/linux/mmc/host.h 2007-07-14 14:47:13.000000000 -0700 +++ g26/include/linux/mmc/host.h 2007-07-14 14:47:51.000000000 -0700 @@ -90,6 +90,7 @@ struct mmc_host { #define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */ #define MMC_CAP_MMC_HIGHSPEED (1 << 3) /* Can do MMC high-speed timing */ #define MMC_CAP_SD_HIGHSPEED (1 << 4) /* Can do SD high-speed timing */ +#define MMC_CAP_SPI (1 << 5) /* Talks only SPI protocols */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ @@ -115,14 +116,16 @@ struct mmc_host { wait_queue_head_t wq; unsigned int claimed:1; /* host exclusively claimed */ - struct delayed_work detect; + unsigned int use_spi_crc:1; + #ifdef CONFIG_MMC_DEBUG unsigned int removed:1; /* host is being removed */ #endif + unsigned int bus_dead:1; /* bus has been released */ + struct delayed_work detect; const struct mmc_bus_ops *bus_ops; /* current bus driver */ unsigned int bus_refs; /* reference counter */ - unsigned int bus_dead:1; /* bus has been released */ unsigned long private[0] ____cacheline_aligned; }; @@ -137,6 +140,8 @@ static inline void *mmc_priv(struct mmc_ return (void *)host->private; } +#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI) + #define mmc_dev(x) ((x)->parent) #define mmc_classdev(x) (&(x)->class_dev) #define mmc_hostname(x) ((x)->class_dev.bus_id) --- g26.orig/include/linux/mmc/core.h 2007-07-14 14:47:13.000000000 -0700 +++ g26/include/linux/mmc/core.h 2007-07-14 14:47:51.000000000 -0700 @@ -25,14 +25,19 @@ struct mmc_command { #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ -#define MMC_CMD_MASK (3 << 5) /* command type */ + +#define MMC_CMD_MASK (3 << 5) /* non-SPI command type */ #define MMC_CMD_AC (0 << 5) #define MMC_CMD_ADTC (1 << 5) #define MMC_CMD_BC (2 << 5) #define MMC_CMD_BCR (3 << 5) +#define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ +#define MMC_RSP_SPI_S2 (1 << 8) /* second status byte */ +#define MMC_RSP_SPI_B4 (1 << 9) /* four data bytes */ + /* - * These are the response types, and correspond to valid bit + * These are the native response types, and correspond to valid bit * patterns of the above flags. One additional valid pattern * is all zeros, which means we don't expect a response. */ @@ -47,6 +52,20 @@ struct mmc_command { #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) /* + * These are the SPI response types for MMC and SD cards (not SDIO). + * Commands return R1, with maybe more info. Zero is an error type; + * callers must always provide the appropriate MMC_RSP_SPI_Rx flags. + */ +#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) +#define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_BUSY) +#define MMC_RSP_SPI_R2 (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2) +#define MMC_RSP_SPI_R3 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) +#define MMC_RSP_SPI_R7 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) + +#define mmc_spi_resp_type(cmd) ((cmd)->flags & \ + (MMC_RSP_SPI_S1|MMC_RSP_BUSY|MMC_RSP_SPI_S2|MMC_RSP_SPI_B4)) + +/* * These are the command types. */ #define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK) --- g26.orig/include/linux/mmc/mmc.h 2007-07-14 14:47:12.000000000 -0700 +++ g26/include/linux/mmc/mmc.h 2007-07-14 14:47:51.000000000 -0700 @@ -27,7 +27,7 @@ /* Standard MMC commands (4.1) type argument response */ /* class 1 */ -#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ @@ -39,8 +39,10 @@ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ #define MMC_STOP_TRANSMISSION 12 /* ac R1b */ -#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ #define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ +#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ /* class 2 */ #define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ @@ -90,15 +92,15 @@ */ /* - MMC status in R1 + MMC status in R1, for native mode (SPI bits are different) Type - e : error bit + e : error bit s : status bit r : detected and set for the actual command response x : detected and set during command execution. the host must poll the card by sending status command in order to read these bits. Clear condition - a : according to the card state + a : according to the card state b : always related to the previous command. Reception of a valid command will clear it (with a delay of one command) c : clear by read @@ -124,10 +126,42 @@ #define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ #define R1_ERASE_RESET (1 << 13) /* sr, c */ #define R1_STATUS(x) (x & 0xFFFFE000) -#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ +/* + * MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS + * R1 is the low order byte; R2 is the next highest byte, when present. + */ +#define R1_SPI_IDLE (1 << 0) +#define R1_SPI_ERASE_RESET (1 << 1) +#define R1_SPI_ILLEGAL_COMMAND (1 << 2) +#define R1_SPI_COM_CRC (1 << 3) +#define R1_SPI_ERASE_SEQ (1 << 4) +#define R1_SPI_ADDRESS (1 << 5) +#define R1_SPI_PARAMETER (1 << 6) +/* R1 bit 7 is always zero */ +#define R2_SPI_CARD_LOCKED (1 << 8) +#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */ +#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP +#define R2_SPI_ERROR (1 << 10) +#define R2_SPI_CC_ERROR (1 << 11) +#define R2_SPI_CARD_ECC_ERROR (1 << 12) +#define R2_SPI_WP_VIOLATION (1 << 13) +#define R2_SPI_ERASE_PARAM (1 << 14) +#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ +#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE + +static inline int mmc_status_card_is_locked(struct mmc_host *host, u32 status) +{ + if (mmc_host_is_spi(host)) + return status & R2_SPI_CARD_LOCKED; + else + return status & R1_CARD_IS_LOCKED; +} + + /* These are unpacked versions of the actual responses */ struct _mmc_csd { @@ -182,6 +216,7 @@ struct _mmc_csd { */ #define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ + /* (and for SPI, CMD58,59) */ #define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ /* (CMD11) */ #define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707141506.00262.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 1/4] MMC headers learn about SPI [not found] ` <200707141506.00262.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-26 16:31 ` Pierre Ossman [not found] ` <20070726183150.024930aa-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-07-26 16:31 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Sat, 14 Jul 2007 15:05:59 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > @@ -115,14 +116,16 @@ struct mmc_host { > wait_queue_head_t wq; > unsigned int claimed:1; /* host exclusively claimed */ > > - struct delayed_work detect; > + unsigned int use_spi_crc:1; > + > #ifdef CONFIG_MMC_DEBUG > unsigned int removed:1; /* host is being removed */ > #endif > + unsigned int bus_dead:1; /* bus has been released */ > + struct delayed_work detect; > > const struct mmc_bus_ops *bus_ops; /* current bus driver */ > unsigned int bus_refs; /* reference counter */ > - unsigned int bus_dead:1; /* bus has been released */ > > unsigned long private[0] ____cacheline_aligned; > }; Some needless shuffling of existing members here. > @@ -47,6 +52,20 @@ struct mmc_command { > #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) > > /* > + * These are the SPI response types for MMC and SD cards (not SDIO). > + * Commands return R1, with maybe more info. Zero is an error type; > + * callers must always provide the appropriate MMC_RSP_SPI_Rx flags. > + */ > +#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) > +#define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_BUSY) I think it's probably safe to keep the two response types separate, even though it is very unlikely that we'll have a command that only uses busy signalling in one of the modes. Other than that, it looks fine. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070726183150.024930aa-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 1/4] MMC headers learn about SPI [not found] ` <20070726183150.024930aa-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-07-26 16:55 ` David Brownell [not found] ` <200707260955.22967.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-26 16:55 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 26 July 2007, Pierre Ossman wrote: > On Sat, 14 Jul 2007 15:05:59 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > @@ -115,14 +116,16 @@ struct mmc_host { > > wait_queue_head_t wq; > > unsigned int claimed:1; /* host exclusively claimed */ > > > > - struct delayed_work detect; > > + unsigned int use_spi_crc:1; > > + > > #ifdef CONFIG_MMC_DEBUG > > unsigned int removed:1; /* host is being removed */ > > #endif > > + unsigned int bus_dead:1; /* bus has been released */ > > + struct delayed_work detect; > > > > const struct mmc_bus_ops *bus_ops; /* current bus driver */ > > unsigned int bus_refs; /* reference counter */ > > - unsigned int bus_dead:1; /* bus has been released */ > > > > unsigned long private[0] ____cacheline_aligned; > > }; > > Some needless shuffling of existing members here. As explained in the comment: this reduces the padding. The previous way needed one word per bitfield; this way they all fit into the same word... > > @@ -47,6 +52,20 @@ struct mmc_command { > > #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) > > > > /* > > + * These are the SPI response types for MMC and SD cards (not SDIO). > > + * Commands return R1, with maybe more info. Zero is an error type; > > + * callers must always provide the appropriate MMC_RSP_SPI_Rx flags. > > + */ > > +#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) > > +#define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_BUSY) > > I think it's probably safe to keep the two response types separate, even > though it is very unlikely that we'll have a command that only uses busy > signalling in one of the modes. That bothered me a smidgeon ... > Other than that, it looks fine. I'm not sure what you mean here, but then my first cup of coffee is still trying to do its work. Are you saying you want me to - increase the padding again? - define an MMC_RSP_SPI_BUSY, and use that? The former would bother me a bit, but I could understand if you wanted it to be in a different patch. The latter is no problem at all. - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707260955.22967.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 1/4] MMC headers learn about SPI [not found] ` <200707260955.22967.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-26 18:05 ` Pierre Ossman [not found] ` <20070726200525.6a5b7d72-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-07-26 18:05 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thu, 26 Jul 2007 09:55:22 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > As explained in the comment: this reduces the padding. > The previous way needed one word per bitfield; this way > they all fit into the same word... > Ah, didn't realize that. I blame the effect two weeks of vacation has on the brain. :) Perhaps shuffling them all to the end (before private) so that it is more clear that they are grouped because of padding issues? > > I'm not sure what you mean here, but then my first cup of coffee is > still trying to do its work. Are you saying you want me to > > - increase the padding again? > - define an MMC_RSP_SPI_BUSY, and use that? > > The former would bother me a bit, but I could understand if you wanted > it to be in a different patch. The latter is no problem at all. > Well, both initially. But padding is a relevant concern, so I'm content with the latter. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070726200525.6a5b7d72-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 1/4] MMC headers learn about SPI [not found] ` <20070726200525.6a5b7d72-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-07-26 20:08 ` David Brownell 0 siblings, 0 replies; 47+ messages in thread From: David Brownell @ 2007-07-26 20:08 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 26 July 2007, Pierre Ossman wrote: > On Thu, 26 Jul 2007 09:55:22 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > > > As explained in the comment: this reduces the padding. > > The previous way needed one word per bitfield; this way > > they all fit into the same word... > > > > Ah, didn't realize that. I blame the effect two weeks of > vacation has on the brain. :) > > Perhaps shuffling them all to the end (before private) so > that it is more clear that they are grouped because of padding issues? What I did was add a comment about the padding, then grouped them all after the 'u32 ocr' to save a smidgeon more padding (on 64bit machines). Overall, there's more padding to remove. > > I'm not sure what you mean here, but then my first cup of coffee is > > still trying to do its work. Are you saying you want me to > > > > - increase the padding again? > > - define an MMC_RSP_SPI_BUSY, and use that? > > > > The former would bother me a bit, but I could understand if you wanted > > it to be in a different patch. The latter is no problem at all. > > > > Well, both initially. But padding is a relevant concern, so I'm > content with the latter. Did both. See the appended patch. - Dave ========== CUT HERE Teach the MMC/SD/SDIO system headers that some hosts use SPI mode - New host capabilities and status bits * MMC_CAP_SPI, with mmc_host_is_spi() test * mmc_host.use_spi_crc flag - SPI-specific declarations: * Response types, MMC_RSP_SPI_R* * Two SPI-only commands * Status bits used native to SPI: R1_SPI_*, R2_SPI_* - Fix a few (unrelated) whitespace bugs in the headers. - Reorder a few mmc_host fields, removing several bytes of padding None of these changes affect current code. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- include/linux/mmc/core.h | 24 ++++++++++++++++++++++-- include/linux/mmc/host.h | 16 +++++++++++----- include/linux/mmc/mmc.h | 47 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 13 deletions(-) --- g26.orig/include/linux/mmc/host.h 2007-07-26 13:06:47.000000000 -0700 +++ g26/include/linux/mmc/host.h 2007-07-26 13:06:59.000000000 -0700 @@ -90,6 +90,7 @@ struct mmc_host { #define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */ #define MMC_CAP_MMC_HIGHSPEED (1 << 3) /* Can do MMC high-speed timing */ #define MMC_CAP_SD_HIGHSPEED (1 << 4) /* Can do SD high-speed timing */ +#define MMC_CAP_SPI (1 << 5) /* Talks only SPI protocols */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ @@ -106,6 +107,14 @@ struct mmc_host { struct mmc_ios ios; /* current io bus settings */ u32 ocr; /* the current OCR setting */ + /* group bitfields together to minimize padding */ + unsigned int use_spi_crc:1; + unsigned int claimed:1; /* host exclusively claimed */ + unsigned int bus_dead:1; /* bus has been released */ +#ifdef CONFIG_MMC_DEBUG + unsigned int removed:1; /* host is being removed */ +#endif + unsigned int mode; /* current card mode of host */ #define MMC_MODE_MMC 0 #define MMC_MODE_SD 1 @@ -113,16 +122,11 @@ struct mmc_host { struct mmc_card *card; /* device attached to this host */ wait_queue_head_t wq; - unsigned int claimed:1; /* host exclusively claimed */ struct delayed_work detect; -#ifdef CONFIG_MMC_DEBUG - unsigned int removed:1; /* host is being removed */ -#endif const struct mmc_bus_ops *bus_ops; /* current bus driver */ unsigned int bus_refs; /* reference counter */ - unsigned int bus_dead:1; /* bus has been released */ unsigned long private[0] ____cacheline_aligned; }; @@ -137,6 +141,8 @@ static inline void *mmc_priv(struct mmc_ return (void *)host->private; } +#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI) + #define mmc_dev(x) ((x)->parent) #define mmc_classdev(x) (&(x)->class_dev) #define mmc_hostname(x) ((x)->class_dev.bus_id) --- g26.orig/include/linux/mmc/core.h 2007-07-26 13:06:47.000000000 -0700 +++ g26/include/linux/mmc/core.h 2007-07-26 13:06:59.000000000 -0700 @@ -25,14 +25,20 @@ struct mmc_command { #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ -#define MMC_CMD_MASK (3 << 5) /* command type */ + +#define MMC_CMD_MASK (3 << 5) /* non-SPI command type */ #define MMC_CMD_AC (0 << 5) #define MMC_CMD_ADTC (1 << 5) #define MMC_CMD_BC (2 << 5) #define MMC_CMD_BCR (3 << 5) +#define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ +#define MMC_RSP_SPI_S2 (1 << 8) /* second status byte */ +#define MMC_RSP_SPI_B4 (1 << 9) /* four data bytes */ +#define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ + /* - * These are the response types, and correspond to valid bit + * These are the native response types, and correspond to valid bit * patterns of the above flags. One additional valid pattern * is all zeros, which means we don't expect a response. */ @@ -47,6 +53,20 @@ struct mmc_command { #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) /* + * These are the SPI response types for MMC and SD cards (not SDIO). + * Commands return R1, with maybe more info. Zero is an error type; + * callers must always provide the appropriate MMC_RSP_SPI_Rx flags. + */ +#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) +#define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY) +#define MMC_RSP_SPI_R2 (MMC_RSP_SPI_S1|MMC_RSP_SPI_S2) +#define MMC_RSP_SPI_R3 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) +#define MMC_RSP_SPI_R7 (MMC_RSP_SPI_S1|MMC_RSP_SPI_B4) + +#define mmc_spi_resp_type(cmd) ((cmd)->flags & \ + (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY|MMC_RSP_SPI_S2|MMC_RSP_SPI_B4)) + +/* * These are the command types. */ #define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK) --- g26.orig/include/linux/mmc/mmc.h 2007-07-26 13:06:47.000000000 -0700 +++ g26/include/linux/mmc/mmc.h 2007-07-26 13:06:59.000000000 -0700 @@ -27,7 +27,7 @@ /* Standard MMC commands (4.1) type argument response */ /* class 1 */ -#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ @@ -39,8 +39,10 @@ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ #define MMC_STOP_TRANSMISSION 12 /* ac R1b */ -#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ #define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ +#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ /* class 2 */ #define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ @@ -90,15 +92,15 @@ */ /* - MMC status in R1 + MMC status in R1, for native mode (SPI bits are different) Type - e : error bit + e : error bit s : status bit r : detected and set for the actual command response x : detected and set during command execution. the host must poll the card by sending status command in order to read these bits. Clear condition - a : according to the card state + a : according to the card state b : always related to the previous command. Reception of a valid command will clear it (with a delay of one command) c : clear by read @@ -124,10 +126,42 @@ #define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ #define R1_ERASE_RESET (1 << 13) /* sr, c */ #define R1_STATUS(x) (x & 0xFFFFE000) -#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ +/* + * MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS + * R1 is the low order byte; R2 is the next highest byte, when present. + */ +#define R1_SPI_IDLE (1 << 0) +#define R1_SPI_ERASE_RESET (1 << 1) +#define R1_SPI_ILLEGAL_COMMAND (1 << 2) +#define R1_SPI_COM_CRC (1 << 3) +#define R1_SPI_ERASE_SEQ (1 << 4) +#define R1_SPI_ADDRESS (1 << 5) +#define R1_SPI_PARAMETER (1 << 6) +/* R1 bit 7 is always zero */ +#define R2_SPI_CARD_LOCKED (1 << 8) +#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */ +#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP +#define R2_SPI_ERROR (1 << 10) +#define R2_SPI_CC_ERROR (1 << 11) +#define R2_SPI_CARD_ECC_ERROR (1 << 12) +#define R2_SPI_WP_VIOLATION (1 << 13) +#define R2_SPI_ERASE_PARAM (1 << 14) +#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ +#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE + +static inline int mmc_status_card_is_locked(struct mmc_host *host, u32 status) +{ + if (mmc_host_is_spi(host)) + return status & R2_SPI_CARD_LOCKED; + else + return status & R1_CARD_IS_LOCKED; +} + + /* These are unpacked versions of the actual responses */ struct _mmc_csd { @@ -182,6 +216,7 @@ struct _mmc_csd { */ #define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ + /* (and for SPI, CMD58,59) */ #define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ /* (CMD11) */ #define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* [patch 2.6.22-git5 2/4] MMC block learns about SPI [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-14 22:05 ` [patch 2.6.22-git5 1/4] MMC headers learn about SPI David Brownell @ 2007-07-14 22:06 ` David Brownell [not found] ` <200707141506.42880.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-14 22:07 ` [patch 2.6.22-git5 3/4] MMC core " David Brownell ` (2 subsequent siblings) 4 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-14 22:06 UTC (permalink / raw) To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Anton Vorontsov, Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, Pierre Ossman Teaching the MMC/SD block card driver about SPI. - Provide the SPI response type flags with each request issued. The model is that if no such flags are provided, it will be rejected by the MMC-over-SPI host. - Understand that multiblock SPI writes don't use STOP_TRANSMISSION. - Correct check for APP_CMD failure. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- drivers/mmc/card/block.c | 26 +++++++++++++++++--------- 1 files changed, 17 insertions(+), 9 deletions(-) --- g26.orig/drivers/mmc/card/block.c 2007-07-14 14:47:12.000000000 -0700 +++ g26/drivers/mmc/card/block.c 2007-07-14 14:47:55.000000000 -0700 @@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct m cmd.opcode = MMC_APP_CMD; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); - if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) + if (err != MMC_ERR_NONE) + return (u32)-1; + if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) return (u32)-1; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_SEND_NUM_WR_BLKS; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; memset(&data, 0, sizeof(struct mmc_data)); @@ -220,11 +222,11 @@ static int mmc_blk_issue_rq(struct mmc_q brq.cmd.arg = req->sector; if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; - brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; - brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); if (brq.data.blocks > card->host->max_blk_count) brq.data.blocks = card->host->max_blk_count; @@ -244,7 +246,12 @@ static int mmc_blk_issue_rq(struct mmc_q if (brq.data.blocks > 1) { brq.data.flags |= MMC_DATA_MULTI; - brq.mrq.stop = &brq.stop; + /* SPI multiblock writes terminate using a special + * token, not a STOP_TRANSMISSION request. + */ + if (!mmc_host_is_spi(card->host) + || rq_data_dir(req) == READ) + brq.mrq.stop = &brq.stop; readcmd = MMC_READ_MULTIPLE_BLOCK; writecmd = MMC_WRITE_MULTIPLE_BLOCK; } else { @@ -302,13 +309,14 @@ static int mmc_blk_issue_rq(struct mmc_q goto cmd_err; } - if (rq_data_dir(req) != READ) { + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { do { int err; cmd.opcode = MMC_SEND_STATUS; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 + | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); if (err) { printk(KERN_ERR "%s: error %d requesting status\n", @@ -511,7 +519,7 @@ mmc_blk_set_blksize(struct mmc_blk_data mmc_claim_host(card->host); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); mmc_release_host(card->host); ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707141506.42880.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 2/4] MMC block learns about SPI [not found] ` <200707141506.42880.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-26 16:33 ` Pierre Ossman [not found] ` <20070726183339.6631243f-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-07-26 16:33 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Sat, 14 Jul 2007 15:06:42 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > @@ -302,13 +309,14 @@ static int mmc_blk_issue_rq(struct mmc_q > goto cmd_err; > } > > - if (rq_data_dir(req) != READ) { > + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { > do { > int err; > > cmd.opcode = MMC_SEND_STATUS; > cmd.arg = card->rca << 16; > - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; > + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 > + | MMC_CMD_AC; > err = mmc_wait_for_cmd(card->host, &cmd, 5); > if (err) { > printk(KERN_ERR "%s: error %d requesting status\n", Nitpicking, but if this code isn't executed on a SPI host then a SPI response type is hardly needed. :) Otherwise ok. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070726183339.6631243f-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 2/4] MMC block learns about SPI [not found] ` <20070726183339.6631243f-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-07-26 17:00 ` David Brownell [not found] ` <200707261000.17339.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-26 17:00 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 26 July 2007, Pierre Ossman wrote: > On Sat, 14 Jul 2007 15:06:42 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > @@ -302,13 +309,14 @@ static int mmc_blk_issue_rq(struct mmc_q > > goto cmd_err; > > } > > > > - if (rq_data_dir(req) != READ) { > > + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { > > do { > > int err; > > > > cmd.opcode = MMC_SEND_STATUS; > > cmd.arg = card->rca << 16; > > - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; > > + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 > > + | MMC_CMD_AC; > > err = mmc_wait_for_cmd(card->host, &cmd, 5); > > if (err) { > > printk(KERN_ERR "%s: error %d requesting status\n", > > Nitpicking, but if this code isn't executed on a SPI host then a SPI > response type is hardly needed. :) But then it can't hurt either, and will be safer to cut'n'paste. :) Andrew Morton regularly gives feedback which amounts to "that's correct in this context, but please adopt this always-safe idiom" on the grounds that a *LOT* of Linux code is developed by cloning. It's hard for me to disagree with that... especially when I see my code showing up in some rather strange contexts! > Otherwise ok. So -- should I change that? - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707261000.17339.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 2/4] MMC block learns about SPI [not found] ` <200707261000.17339.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-26 18:06 ` Pierre Ossman [not found] ` <20070726200639.06242858-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-07-26 18:06 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thu, 26 Jul 2007 10:00:16 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > But then it can't hurt either, and will be safer to cut'n'paste. :) > > Andrew Morton regularly gives feedback which amounts to "that's correct > in this context, but please adopt this always-safe idiom" on the grounds > that a *LOT* of Linux code is developed by cloning. It's hard for me to > disagree with that... especially when I see my code showing up in some > rather strange contexts! > Fair enough. But then you'd probably also need to have a look at the clause terminating that while loop. I believe it is specific to the native protocol. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070726200639.06242858-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 2/4] MMC block learns about SPI [not found] ` <20070726200639.06242858-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-07-26 20:15 ` David Brownell 0 siblings, 0 replies; 47+ messages in thread From: David Brownell @ 2007-07-26 20:15 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 26 July 2007, Pierre Ossman wrote: > On Thu, 26 Jul 2007 10:00:16 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > > > But then it can't hurt either, and will be safer to cut'n'paste. :) > > > > Andrew Morton regularly gives feedback which amounts to "that's correct > > in this context, but please adopt this always-safe idiom" on the grounds > > that a *LOT* of Linux code is developed by cloning. It's hard for me to > > disagree with that... especially when I see my code showing up in some > > rather strange contexts! > > > > Fair enough. But then you'd probably also need to have a look at the > clause terminating that while loop. I believe it is specific to the > native protocol. Sigh; yes it is. In this case, the code won't be cut/pastable. ;) Updated patch appended. (BTW these refreshes are against current GIT.) ======== CUT HERE Teaching the MMC/SD block card driver about SPI. - Provide the SPI response type flags with each request issued. The model is that if no such flags are provided, it will be rejected by the MMC-over-SPI host. - Understand that multiblock SPI writes don't use STOP_TRANSMISSION. - Correct check for APP_CMD failure. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- drivers/mmc/card/block.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) --- g26.orig/drivers/mmc/card/block.c 2007-07-26 13:06:46.000000000 -0700 +++ g26/drivers/mmc/card/block.c 2007-07-26 13:13:38.000000000 -0700 @@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct m cmd.opcode = MMC_APP_CMD; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); - if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) + if (err != MMC_ERR_NONE) + return (u32)-1; + if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) return (u32)-1; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_SEND_NUM_WR_BLKS; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; memset(&data, 0, sizeof(struct mmc_data)); @@ -220,11 +222,11 @@ static int mmc_blk_issue_rq(struct mmc_q brq.cmd.arg = req->sector; if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; - brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; - brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); if (brq.data.blocks > card->host->max_blk_count) brq.data.blocks = card->host->max_blk_count; @@ -244,7 +246,12 @@ static int mmc_blk_issue_rq(struct mmc_q if (brq.data.blocks > 1) { brq.data.flags |= MMC_DATA_MULTI; - brq.mrq.stop = &brq.stop; + /* SPI multiblock writes terminate using a special + * token, not a STOP_TRANSMISSION request. + */ + if (!mmc_host_is_spi(card->host) + || rq_data_dir(req) == READ) + brq.mrq.stop = &brq.stop; readcmd = MMC_READ_MULTIPLE_BLOCK; writecmd = MMC_WRITE_MULTIPLE_BLOCK; } else { @@ -302,7 +309,7 @@ static int mmc_blk_issue_rq(struct mmc_q goto cmd_err; } - if (rq_data_dir(req) != READ) { + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { do { int err; @@ -510,7 +517,7 @@ mmc_blk_set_blksize(struct mmc_blk_data mmc_claim_host(card->host); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); mmc_release_host(card->host); ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-14 22:05 ` [patch 2.6.22-git5 1/4] MMC headers learn about SPI David Brownell 2007-07-14 22:06 ` [patch 2.6.22-git5 2/4] MMC block learns " David Brownell @ 2007-07-14 22:07 ` David Brownell [not found] ` <200707141507.17484.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-14 22:08 ` [patch 2.6.22-git5 4/4] mmc_spi host driver David Brownell 2007-07-16 16:48 ` [patch 2.6.22-git5 0/4] MMC-over-SPI Anton Vorontsov 4 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-14 22:07 UTC (permalink / raw) To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Anton Vorontsov, Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, Pierre Ossman Teach the MMC/SD/SDIO core about using SPI mode. - Use mmc_host_is_spi() so enumeration works through SPI signaling, and protocols, not just the native versions. - Provide the SPI response type flags with each request issued, including requests from the new lock/unlock code. - Understand that some commands act a bit differently ... notably: * OP_COND command reports busy status differently * OP_COND command doesn't return the OCR * APP_CMD status doesn't have an R1_APP_CMD analogue - Understand that cmd->resp[0] and mmc_get_status() results for SPI return different values than for "native" MMC/SD protocol; this affects checking card lock status, and some others. Those changes required some new and updated primitives: - Provide utilities to access two SPI-only requests, and one request that wasn't previously needed: * mmc_spi_read_ocr() ... SPI only * mmc_spi_set_crc() ... SPI only (override by module parm) * mmc_spi_send_cid() ... works without broadcast mode - Updated internal routines: * Previous mmc_send_csd() modified into mmc_send_cxd_native(); it uses native "R2" responses, which include 16 bytes of data. * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data() helper for command-and-data access * Bugfix to that mmc_send_cxd_data() code: dma-to-stack is unsafe/nonportable, so kmalloc a bounce buffer instead. - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use those helper routines based on whether they're native or SPI The SPI support hasn't been tested on the new MMC4 cards (they're not widely available); likewise SD cards with 4GB and up may have surprises lurking. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- drivers/mmc/core/core.c | 24 +++++- drivers/mmc/core/mmc.c | 33 ++++++--- drivers/mmc/core/mmc_ops.c | 158 ++++++++++++++++++++++++++++++++++++--------- drivers/mmc/core/mmc_ops.h | 4 + drivers/mmc/core/sd.c | 31 +++++--- drivers/mmc/core/sd_ops.c | 32 ++++++--- 6 files changed, 215 insertions(+), 67 deletions(-) --- g26.orig/drivers/mmc/core/mmc_ops.h 2007-07-14 14:47:12.000000000 -0700 +++ g26/drivers/mmc/core/mmc_ops.h 2007-07-14 14:47:54.000000000 -0700 @@ -23,5 +23,9 @@ int mmc_send_ext_csd(struct mmc_card *ca int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); int mmc_send_status(struct mmc_card *card, u32 *status); +int mmc_spi_send_cid(struct mmc_host *host, u32 *cid); +int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp); +int mmc_spi_set_crc(struct mmc_host *host); + #endif --- g26.orig/drivers/mmc/core/core.c 2007-07-14 14:47:12.000000000 -0700 +++ g26/drivers/mmc/core/core.c 2007-07-14 14:47:54.000000000 -0700 @@ -404,8 +404,13 @@ static void mmc_power_up(struct mmc_host int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (mmc_host_is_spi(host)) { + host->ios.chip_select = MMC_CS_HIGH; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -424,8 +429,10 @@ static void mmc_power_off(struct mmc_hos { host->ios.clock = 0; host->ios.vdd = 0; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (!mmc_host_is_spi(host)) { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + } host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -541,7 +548,9 @@ void mmc_rescan(struct work_struct *work err = mmc_send_app_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { - if (mmc_attach_sd(host, ocr)) + if (mmc_host_is_spi(host)) + err = mmc_spi_read_ocr(host, &ocr); + if (err != MMC_ERR_NONE || mmc_attach_sd(host, ocr)) mmc_power_off(host); } else { /* @@ -550,7 +559,10 @@ void mmc_rescan(struct work_struct *work */ err = mmc_send_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { - if (mmc_attach_mmc(host, ocr)) + if (mmc_host_is_spi(host)) + err = mmc_spi_read_ocr(host, &ocr); + if (err != MMC_ERR_NONE + || mmc_attach_mmc(host, ocr)) mmc_power_off(host); } else { mmc_power_off(host); --- g26.orig/drivers/mmc/core/mmc_ops.c 2007-07-14 14:47:12.000000000 -0700 +++ g26/drivers/mmc/core/mmc_ops.c 2007-07-14 14:47:54.000000000 -0700 @@ -63,23 +63,34 @@ int mmc_go_idle(struct mmc_host *host) int err; struct mmc_command cmd; - mmc_set_chip_select(host, MMC_CS_HIGH); - - mmc_delay(1); + /* + * Non-SPI hosts need to prevent chipselect going active during + * GO_IDLE; that would put chips into SPI mode. Remind them of + * that in case of hardware that won't pull up DAT3/nCS otherwise. + * + * SPI hosts ignore ios.chip_select; it's managed according to + * rules that must accomodate non-MMC slaves which this layer + * won't even know about. + */ + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_HIGH); + mmc_delay(1); + } memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; - cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; err = mmc_wait_for_cmd(host, &cmd, 0); mmc_delay(1); - mmc_set_chip_select(host, MMC_CS_DONTCARE); - - mmc_delay(1); + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_DONTCARE); + mmc_delay(1); + } return err; } @@ -95,14 +106,18 @@ int mmc_send_op_cond(struct mmc_host *ho cmd.opcode = MMC_SEND_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); if (err != MMC_ERR_NONE) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + if (mmc_host_is_spi(host)) { + /* wait until reset completes */ + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; err = MMC_ERR_TIMEOUT; @@ -110,7 +125,7 @@ int mmc_send_op_cond(struct mmc_host *ho mmc_delay(10); } - if (rocr) + if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; return err; @@ -160,40 +175,45 @@ int mmc_set_relative_addr(struct mmc_car return MMC_ERR_NONE; } -int mmc_send_csd(struct mmc_card *card, u32 *csd) +static int +mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; struct mmc_command cmd; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!csd); + BUG_ON(!host); + BUG_ON(!cxd); memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SEND_CSD; - cmd.arg = card->rca << 16; + cmd.opcode = opcode; + cmd.arg = arg; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) return err; - memcpy(csd, cmd.resp, sizeof(u32) * 4); + memcpy(cxd, cmd.resp, sizeof(u32) * 4); return MMC_ERR_NONE; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int +mmc_send_cxd_data(struct mmc_host *host, u32 opcode, void *buf, unsigned len) { struct mmc_request mrq; struct mmc_command cmd; struct mmc_data data; struct scatterlist sg; + void *data_buf; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!ext_csd); + /* dma onto stack is unsafe/nonportable, but callers here + * normally provide temporary on-stack buffers. + */ + data_buf = kmalloc(len, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); @@ -202,21 +222,32 @@ int mmc_send_ext_csd(struct mmc_card *ca mrq.cmd = &cmd; mrq.data = &data; - cmd.opcode = MMC_SEND_EXT_CSD; + cmd.opcode = opcode; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - data.blksz = 512; + /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we + * rely on callers to never use this with "native" calls for reading + * CSD or CID. Native versions of those commands use the R2 type, + * not R1 plus a data block. + */ + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = len; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, ext_csd, 512); + sg_init_one(&sg, data_buf, len); - mmc_set_data_timeout(&data, card, 0); + /* Note that for MMC_SEND_EXT_CSD we could set the timeout; but + * not for the other requests. But host->card isn't set yet! + */ - mmc_wait_for_req(card->host, &mrq); + mmc_wait_for_req(host, &mrq); + + memcpy(buf, data_buf, len); + kfree(data_buf); if (cmd.error != MMC_ERR_NONE) return cmd.error; @@ -226,6 +257,67 @@ int mmc_send_ext_csd(struct mmc_card *ca return MMC_ERR_NONE; } +int mmc_send_csd(struct mmc_card *card, u32 *csd) +{ + if (!mmc_host_is_spi(card->host)) + return mmc_send_cxd_native(card->host, card->rca << 16, + csd, MMC_SEND_CSD); + + return mmc_send_cxd_data(card->host, MMC_SEND_CSD, csd, 16); +} + +int mmc_spi_send_cid(struct mmc_host *host, u32 *cid) +{ + if (!mmc_host_is_spi(host)) + return mmc_send_cxd_native(host, 0, cid, MMC_SEND_CID); + + return mmc_send_cxd_data(host, MMC_SEND_CID, cid, 16); +} + +int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +{ + return mmc_send_cxd_data(card->host, MMC_SEND_EXT_CSD, ext_csd, 512); +} + +int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_READ_OCR; + cmd.flags = MMC_RSP_SPI_R3; + + err = mmc_wait_for_cmd(host, &cmd, 0); + + *ocrp = cmd.resp[1]; + return err; +} + +/* Enabling software CRCs can be a significant (30%) performance cost, + * and for other reasons isn't always desired; so it can be disabled. + */ +static int use_spi_crc = 1; +module_param(use_spi_crc, bool, 0); + +int mmc_spi_set_crc(struct mmc_host *host) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_CRC_ON_OFF; + cmd.flags = MMC_RSP_SPI_R1; + cmd.arg = use_spi_crc; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) + host->use_spi_crc = use_spi_crc; + return err; +} + int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; @@ -241,7 +333,7 @@ int mmc_switch(struct mmc_card *card, u8 (index << 16) | (value << 8) | set; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) @@ -261,13 +353,17 @@ int mmc_send_status(struct mmc_card *car memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + if (!mmc_host_is_spi(card->host)) + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) return err; + /* NOTE: callers are required to understand the difference + * between "native" and SPI format status words! + */ if (status) *status = cmd.resp[0]; --- g26.orig/drivers/mmc/core/mmc.c 2007-07-14 14:47:12.000000000 -0700 +++ g26/drivers/mmc/core/mmc.c 2007-07-14 14:47:54.000000000 -0700 @@ -264,7 +264,13 @@ static int mmc_init_card(struct mmc_host /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host); + if (err != MMC_ERR_NONE) + goto err; + err = mmc_spi_send_cid(host, cid); + } else + err = mmc_all_send_cid(host, cid); if (err != MMC_ERR_NONE) goto err; @@ -287,13 +293,15 @@ static int mmc_init_card(struct mmc_host } /* - * Set card RCA. + * For native busses: set card RCA and leave open drain mode. */ - err = mmc_set_relative_addr(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_set_relative_addr(card); + if (err != MMC_ERR_NONE) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -314,13 +322,15 @@ static int mmc_init_card(struct mmc_host /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err != MMC_ERR_NONE) + goto free_card; + } if (!oldcard) { /* - * Fetch and process extened CSD. + * Fetch and process extended CSD. */ err = mmc_read_ext_csd(card); if (err != MMC_ERR_NONE) @@ -480,7 +490,8 @@ static void mmc_suspend(struct mmc_host BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } --- g26.orig/drivers/mmc/core/sd.c 2007-07-14 14:47:12.000000000 -0700 +++ g26/drivers/mmc/core/sd.c 2007-07-14 14:47:54.000000000 -0700 @@ -321,7 +321,13 @@ static int mmc_sd_init_card(struct mmc_h /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host); + if (err != MMC_ERR_NONE) + goto err; + err = mmc_spi_send_cid(host, cid); + } else + err = mmc_all_send_cid(host, cid); if (err != MMC_ERR_NONE) goto err; @@ -343,13 +349,15 @@ static int mmc_sd_init_card(struct mmc_h } /* - * Set card RCA. + * For native busses: get card RCA and leave open drain mode. */ - err = mmc_send_relative_addr(host, &card->rca); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err != MMC_ERR_NONE) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -369,9 +377,11 @@ static int mmc_sd_init_card(struct mmc_h /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err != MMC_ERR_NONE) + goto free_card; + } if (!oldcard) { /* @@ -554,7 +564,8 @@ static void mmc_sd_suspend(struct mmc_ho BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } --- g26.orig/drivers/mmc/core/sd_ops.c 2007-07-14 14:47:12.000000000 -0700 +++ g26/drivers/mmc/core/sd_ops.c 2007-07-14 14:47:54.000000000 -0700 @@ -70,6 +70,12 @@ int mmc_wait_for_app_cmd(struct mmc_host err = cmd->error; if (cmd->error == MMC_ERR_NONE) break; + + /* no point in retrying illegal commands! */ + if (mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + break; + } } return err; @@ -89,10 +95,10 @@ int mmc_app_cmd(struct mmc_host *host, s if (card) { cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; } else { cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; } err = mmc_wait_for_cmd(host, &cmd, 0); @@ -100,8 +106,8 @@ int mmc_app_cmd(struct mmc_host *host, s return err; /* Check that card supported application commands */ - if (!(cmd.resp[0] & R1_APP_CMD)) - return MMC_ERR_FAILED; + if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) + return (u32)-1; return MMC_ERR_NONE; } @@ -148,14 +154,18 @@ int mmc_send_app_op_cond(struct mmc_host cmd.opcode = SD_APP_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + if (mmc_host_is_spi(host)) { + /* wait until reset completes */ + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; err = MMC_ERR_TIMEOUT; @@ -182,7 +192,7 @@ int mmc_send_if_cond(struct mmc_host *ho */ cmd.opcode = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; - cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, 0); if (err != MMC_ERR_NONE) @@ -229,6 +239,8 @@ int mmc_app_send_scr(struct mmc_card *ca BUG_ON(!card->host); BUG_ON(!scr); + /* NOTE: caller guarantees scr is heap-allocated */ + err = mmc_app_cmd(card->host, card); if (err != MMC_ERR_NONE) return err; @@ -242,7 +254,7 @@ int mmc_app_send_scr(struct mmc_card *ca cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 8; data.blocks = 1; @@ -278,6 +290,8 @@ int mmc_sd_switch(struct mmc_card *card, BUG_ON(!card); BUG_ON(!card->host); + /* NOTE: caller guarantees resp is heap-allocated */ + mode = !!mode; value &= 0xF; @@ -292,7 +306,7 @@ int mmc_sd_switch(struct mmc_card *card, cmd.arg = mode << 31 | 0x00FFFFFF; cmd.arg &= ~(0xF << (group * 4)); cmd.arg |= value << (group * 4); - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 64; data.blocks = 1; ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707141507.17484.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <200707141507.17484.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-26 17:18 ` Pierre Ossman [not found] ` <20070726191824.569542fd-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-07-26 17:18 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Sat, 14 Jul 2007 15:07:16 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > @@ -541,7 +548,9 @@ void mmc_rescan(struct work_struct *work > > err = mmc_send_app_op_cond(host, 0, &ocr); > if (err == MMC_ERR_NONE) { > - if (mmc_attach_sd(host, ocr)) > + if (mmc_host_is_spi(host)) > + err = mmc_spi_read_ocr(host, &ocr); > + if (err != MMC_ERR_NONE || mmc_attach_sd(host, ocr)) > mmc_power_off(host); > } else { > /* Getting the OCR is not vital to determine if it's SD or MMC, so we can move that into mmc.c and sd.c, reducing the code in here. > @@ -550,7 +559,10 @@ void mmc_rescan(struct work_struct *work > */ > err = mmc_send_op_cond(host, 0, &ocr); > if (err == MMC_ERR_NONE) { > - if (mmc_attach_mmc(host, ocr)) > + if (mmc_host_is_spi(host)) > + err = mmc_spi_read_ocr(host, &ocr); > + if (err != MMC_ERR_NONE > + || mmc_attach_mmc(host, ocr)) > mmc_power_off(host); > } else { > mmc_power_off(host); This will fail to initialise a high capacity MMC card. From the MMC spec: "Without the CMD58 with bits [30:29] set as "10b" in prior to the CMD1 a higher than 2GB of density of memory will remain in Idle state forever." > @@ -95,14 +106,18 @@ int mmc_send_op_cond(struct mmc_host *ho > > cmd.opcode = MMC_SEND_OP_COND; > cmd.arg = ocr; Argument is "None", not "Ignored", so this should be 0 for SPI. > > - mmc_set_data_timeout(&data, card, 0); > + /* Note that for MMC_SEND_EXT_CSD we could set the timeout; but > + * not for the other requests. But host->card isn't set yet! > + */ > This will break on native hosts as a timeout of 0 means exactly that. > + > +int mmc_spi_send_cid(struct mmc_host *host, u32 *cid) > +{ > + if (!mmc_host_is_spi(host)) > + return mmc_send_cxd_native(host, 0, cid, MMC_SEND_CID); > + > + return mmc_send_cxd_data(host, MMC_SEND_CID, cid, 16); > +} > + As this is not SPI specific (except for its current use), why not mmc_send_cid() ? And the argument for it is the RCA (in native mode). > + > +/* Enabling software CRCs can be a significant (30%) performance cost, > + * and for other reasons isn't always desired; so it can be disabled. > + */ > +static int use_spi_crc = 1; > +module_param(use_spi_crc, bool, 0); > + The *_ops.c only contain function wrappers of protocol commands, not policy. So I think this is better placed where mmc_spi_set_crc() is called. > --- g26.orig/drivers/mmc/core/mmc.c 2007-07-14 14:47:12.000000000 -0700 > +++ g26/drivers/mmc/core/mmc.c 2007-07-14 14:47:54.000000000 -0700 > @@ -264,7 +264,13 @@ static int mmc_init_card(struct mmc_host > /* > * Fetch CID from card. > */ > - err = mmc_all_send_cid(host, cid); > + if (mmc_host_is_spi(host)) { > + err = mmc_spi_set_crc(host); > + if (err != MMC_ERR_NONE) > + goto err; > + err = mmc_spi_send_cid(host, cid); > + } else > + err = mmc_all_send_cid(host, cid); > if (err != MMC_ERR_NONE) > goto err; > A matter of taste, but wouldn't it be clearer if you separated out the crc bit and did that earlier, before the above comment? > --- g26.orig/drivers/mmc/core/sd.c 2007-07-14 14:47:12.000000000 -0700 > +++ g26/drivers/mmc/core/sd.c 2007-07-14 14:47:54.000000000 -0700 > @@ -321,7 +321,13 @@ static int mmc_sd_init_card(struct mmc_h > /* > * Fetch CID from card. > */ > - err = mmc_all_send_cid(host, cid); > + if (mmc_host_is_spi(host)) { > + err = mmc_spi_set_crc(host); > + if (err != MMC_ERR_NONE) > + goto err; > + err = mmc_spi_send_cid(host, cid); > + } else > + err = mmc_all_send_cid(host, cid); > if (err != MMC_ERR_NONE) > goto err; > Ditto. > --- g26.orig/drivers/mmc/core/sd_ops.c 2007-07-14 14:47:12.000000000 -0700 > +++ g26/drivers/mmc/core/sd_ops.c 2007-07-14 14:47:54.000000000 -0700 > @@ -70,6 +70,12 @@ int mmc_wait_for_app_cmd(struct mmc_host > err = cmd->error; > if (cmd->error == MMC_ERR_NONE) > break; > + > + /* no point in retrying illegal commands! */ > + if (mmc_host_is_spi(host)) { > + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) > + break; > + } > } > > return err; "Illegal command" refers to the previous command sent (and failed). So this can give false negatives. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070726191824.569542fd-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <20070726191824.569542fd-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-07-26 21:58 ` David Brownell [not found] ` <200707261458.55558.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-26 21:58 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 26 July 2007, Pierre Ossman wrote: > On Sat, 14 Jul 2007 15:07:16 -0700 > David Brownell <david-b@pacbell.net> wrote: > > > @@ -541,7 +548,9 @@ void mmc_rescan(struct work_struct *work > > > > err = mmc_send_app_op_cond(host, 0, &ocr); > > if (err == MMC_ERR_NONE) { > > - if (mmc_attach_sd(host, ocr)) > > + if (mmc_host_is_spi(host)) > > + err = mmc_spi_read_ocr(host, &ocr); > > + if (err != MMC_ERR_NONE || mmc_attach_sd(host, ocr)) > > mmc_power_off(host); > > } else { > > /* > > Getting the OCR is not vital to determine if it's SD or MMC, so > we can move that into mmc.c and sd.c, reducing the code in here. Yes we could ... but this way is IMO simpler, since it retains a simple invariant: that the OCR parameter to attach() methods is always valid. As one would expect! Which gives another advantage: no surprises. > > @@ -550,7 +559,10 @@ void mmc_rescan(struct work_struct *work > > */ > > err = mmc_send_op_cond(host, 0, &ocr); > > if (err == MMC_ERR_NONE) { > > - if (mmc_attach_mmc(host, ocr)) > > + if (mmc_host_is_spi(host)) > > + err = mmc_spi_read_ocr(host, &ocr); > > + if (err != MMC_ERR_NONE > > + || mmc_attach_mmc(host, ocr)) > > mmc_power_off(host); > > } else { > > mmc_power_off(host); > > This will fail to initialise a high capacity MMC card. From the MMC spec: > > "Without the CMD58 with bits [30:29] set as "10b" in prior to the CMD1 a > higher than 2GB of density of memory will remain in Idle state forever." The first thing mmc_attach_mmc() does is reset the card... Are you sure that "forever" means that reset will fail? That would be a very foolish thing to specify. And while I've seen strange things in specs, that would be one of the worst that's not a vendor-specific part of a papering over errata ... I'd be inclined to leave this alone unless someone gets such a card and notices that it doesn't work. After all, lack of testing on those new (and-I-still-can't-find-one) cards is a general disclaimer. > > @@ -95,14 +106,18 @@ int mmc_send_op_cond(struct mmc_host *ho > > > > cmd.opcode = MMC_SEND_OP_COND; > > cmd.arg = ocr; > > Argument is "None", not "Ignored", so this should be 0 for SPI. Indeed. The specs would make more sense if they said "zero" in such cases, so the language isn't in conflict with the day-to-day/commonsense uses of those words! > > - mmc_set_data_timeout(&data, card, 0); > > + /* Note that for MMC_SEND_EXT_CSD we could set the timeout; but > > + * not for the other requests. But host->card isn't set yet! > > + */ > > > > This will break on native hosts as a timeout of 0 means exactly that. Urgh. OK; I just grew the parameter list by one more member, which is NULL before there's a card. (You might consider setting host->card earlier...) > > + > > +int mmc_spi_send_cid(struct mmc_host *host, u32 *cid) > > +{ > > + if (!mmc_host_is_spi(host)) > > + return mmc_send_cxd_native(host, 0, cid, MMC_SEND_CID); > > + > > + return mmc_send_cxd_data(host, MMC_SEND_CID, cid, 16); > > +} > > + > > As this is not SPI specific (except for its current use), why not mmc_send_cid() ? > > And the argument for it is the RCA (in native mode). OK ... renamed, and passed "rca << 16". At least, if host->card has been set, which only happens *after* the enumeration sequence needs to fetch the CID ... which is done before it knows whether to create a card struct or not. (The SEND_ALL_CID request is used for non-SPI hosts.) > > + > > +/* Enabling software CRCs can be a significant (30%) performance cost, > > + * and for other reasons isn't always desired; so it can be disabled. > > + */ > > +static int use_spi_crc = 1; > > +module_param(use_spi_crc, bool, 0); > > + > > The *_ops.c only contain function wrappers of protocol commands, not > policy. So I think this is better placed where mmc_spi_set_crc() is called. You mean, have separate module params for SD and for MMC? It seems cleaner this way... > > --- g26.orig/drivers/mmc/core/mmc.c 2007-07-14 14:47:12.000000000 -0700 > > +++ g26/drivers/mmc/core/mmc.c 2007-07-14 14:47:54.000000000 -0700 > > @@ -264,7 +264,13 @@ static int mmc_init_card(struct mmc_host > > /* > > * Fetch CID from card. > > */ > > - err = mmc_all_send_cid(host, cid); > > + if (mmc_host_is_spi(host)) { > > + err = mmc_spi_set_crc(host); > > + if (err != MMC_ERR_NONE) > > + goto err; > > + err = mmc_spi_send_cid(host, cid); > > + } else > > + err = mmc_all_send_cid(host, cid); > > if (err != MMC_ERR_NONE) > > goto err; > > > > A matter of taste, but wouldn't it be clearer if you separated out > the crc bit and did that earlier, before the above comment? > [ ditto for SD ] OK. The comment probably should have been updated, but I'd expect GCC will merge the two adjacent "if (it's spi)" blocks which will be the result. > > --- g26.orig/drivers/mmc/core/sd_ops.c 2007-07-14 14:47:12.000000000 -0700 > > +++ g26/drivers/mmc/core/sd_ops.c 2007-07-14 14:47:54.000000000 -0700 > > @@ -70,6 +70,12 @@ int mmc_wait_for_app_cmd(struct mmc_host > > err = cmd->error; > > if (cmd->error == MMC_ERR_NONE) > > break; > > + > > + /* no point in retrying illegal commands! */ > > + if (mmc_host_is_spi(host)) { > > + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) > > + break; > > + } > > } > > > > return err; > > "Illegal command" refers to the previous command sent (and failed). > So this can give false negatives. The immediately preceding command would be MMC_APP_CMD ... ? I didn't see any language in the specs which could let me interpret this as anything other than APP_CMD failure: When an error bit is detected in “R” mode the card will report the error in the response to the command that raised the exception. The command will not be executed and the associated state transition will not take place. What this does is to quickly abort retries of SD card ops that were sent to MMC cards, and which always fail with ILLEGAL_COMMAND. - Dave ======== CUT HERE Teach the MMC/SD/SDIO core about using SPI mode. - Use mmc_host_is_spi() so enumeration works through SPI signaling and protocols, not just the native versions. - Provide the SPI response type flags with each request issued, including requests from the new lock/unlock code. - Understand that some commands act a bit differently ... notably: * OP_COND command reports busy status differently * OP_COND command doesn't return the OCR * APP_CMD status doesn't have an R1_APP_CMD analogue - Understand that cmd->resp[0] and mmc_get_status() results for SPI return different values than for "native" MMC/SD protocol; this affects checking card lock status, and some others. Those changes required some new and updated primitives: - Provide utilities to access two SPI-only requests, and one request that wasn't previously needed: * mmc_spi_read_ocr() ... SPI only * mmc_spi_set_crc() ... SPI only (override by module parm) * mmc_spi_send_cid() ... works without broadcast mode - Updated internal routines: * Previous mmc_send_csd() modified into mmc_send_cxd_native(); it uses native "R2" responses, which include 16 bytes of data. * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data() helper for command-and-data access * Bugfix to that mmc_send_cxd_data() code: dma-to-stack is unsafe/nonportable, so kmalloc a bounce buffer instead. - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use those helper routines based on whether they're native or SPI The SPI support hasn't been tested on the new MMC4 cards (they're not widely available); likewise SD cards with 4GB and up may have surprises lurking. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> --- drivers/mmc/core/core.c | 24 ++++-- drivers/mmc/core/mmc.c | 39 +++++++--- drivers/mmc/core/mmc_ops.c | 165 ++++++++++++++++++++++++++++++++++++--------- drivers/mmc/core/mmc_ops.h | 3 drivers/mmc/core/sd.c | 37 +++++++--- drivers/mmc/core/sd_ops.c | 32 ++++++-- 6 files changed, 232 insertions(+), 68 deletions(-) --- g26.orig/drivers/mmc/core/mmc_ops.h 2007-07-26 13:13:23.000000000 -0700 +++ g26/drivers/mmc/core/mmc_ops.h 2007-07-26 14:54:35.000000000 -0700 @@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); int mmc_send_status(struct mmc_card *card, u32 *status); +int mmc_send_cid(struct mmc_host *host, u32 *cid); +int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp); +int mmc_spi_set_crc(struct mmc_host *host); #endif --- g26.orig/drivers/mmc/core/core.c 2007-07-26 13:13:24.000000000 -0700 +++ g26/drivers/mmc/core/core.c 2007-07-26 14:54:35.000000000 -0700 @@ -404,8 +404,13 @@ static void mmc_power_up(struct mmc_host int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (mmc_host_is_spi(host)) { + host->ios.chip_select = MMC_CS_HIGH; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -424,8 +429,10 @@ static void mmc_power_off(struct mmc_hos { host->ios.clock = 0; host->ios.vdd = 0; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (!mmc_host_is_spi(host)) { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + } host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -541,7 +548,9 @@ void mmc_rescan(struct work_struct *work err = mmc_send_app_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { - if (mmc_attach_sd(host, ocr)) + if (mmc_host_is_spi(host)) + err = mmc_spi_read_ocr(host, &ocr); + if (err != MMC_ERR_NONE || mmc_attach_sd(host, ocr)) mmc_power_off(host); } else { /* @@ -550,7 +559,10 @@ void mmc_rescan(struct work_struct *work */ err = mmc_send_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { - if (mmc_attach_mmc(host, ocr)) + if (mmc_host_is_spi(host)) + err = mmc_spi_read_ocr(host, &ocr); + if (err != MMC_ERR_NONE + || mmc_attach_mmc(host, ocr)) mmc_power_off(host); } else { mmc_power_off(host); --- g26.orig/drivers/mmc/core/mmc_ops.c 2007-07-26 13:13:23.000000000 -0700 +++ g26/drivers/mmc/core/mmc_ops.c 2007-07-26 14:54:35.000000000 -0700 @@ -63,23 +63,34 @@ int mmc_go_idle(struct mmc_host *host) int err; struct mmc_command cmd; - mmc_set_chip_select(host, MMC_CS_HIGH); - - mmc_delay(1); + /* + * Non-SPI hosts need to prevent chipselect going active during + * GO_IDLE; that would put chips into SPI mode. Remind them of + * that in case of hardware that won't pull up DAT3/nCS otherwise. + * + * SPI hosts ignore ios.chip_select; it's managed according to + * rules that must accomodate non-MMC slaves which this layer + * won't even know about. + */ + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_HIGH); + mmc_delay(1); + } memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; - cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; err = mmc_wait_for_cmd(host, &cmd, 0); mmc_delay(1); - mmc_set_chip_select(host, MMC_CS_DONTCARE); - - mmc_delay(1); + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_DONTCARE); + mmc_delay(1); + } return err; } @@ -94,15 +105,19 @@ int mmc_send_op_cond(struct mmc_host *ho memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); if (err != MMC_ERR_NONE) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + if (mmc_host_is_spi(host)) { + /* wait until reset completes */ + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; err = MMC_ERR_TIMEOUT; @@ -110,7 +125,7 @@ int mmc_send_op_cond(struct mmc_host *ho mmc_delay(10); } - if (rocr) + if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; return err; @@ -160,40 +175,46 @@ int mmc_set_relative_addr(struct mmc_car return MMC_ERR_NONE; } -int mmc_send_csd(struct mmc_card *card, u32 *csd) +static int +mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; struct mmc_command cmd; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!csd); + BUG_ON(!host); + BUG_ON(!cxd); memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SEND_CSD; - cmd.arg = card->rca << 16; + cmd.opcode = opcode; + cmd.arg = arg; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) return err; - memcpy(csd, cmd.resp, sizeof(u32) * 4); + memcpy(cxd, cmd.resp, sizeof(u32) * 4); return MMC_ERR_NONE; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int +mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, + u32 opcode, void *buf, unsigned len) { struct mmc_request mrq; struct mmc_command cmd; struct mmc_data data; struct scatterlist sg; + void *data_buf; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!ext_csd); + /* dma onto stack is unsafe/nonportable, but callers here + * normally provide temporary on-stack buffers. + */ + data_buf = kmalloc(len, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); @@ -202,21 +223,31 @@ int mmc_send_ext_csd(struct mmc_card *ca mrq.cmd = &cmd; mrq.data = &data; - cmd.opcode = MMC_SEND_EXT_CSD; + cmd.opcode = opcode; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - data.blksz = 512; + /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we + * rely on callers to never use this with "native" calls for reading + * CSD or CID. Native versions of those commands use the R2 type, + * not R1 plus a data block. + */ + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = len; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, ext_csd, 512); + sg_init_one(&sg, data_buf, len); - mmc_set_data_timeout(&data, card, 0); + if (card) + mmc_set_data_timeout(&data, card, 0); - mmc_wait_for_req(card->host, &mrq); + mmc_wait_for_req(host, &mrq); + + memcpy(buf, data_buf, len); + kfree(data_buf); if (cmd.error != MMC_ERR_NONE) return cmd.error; @@ -226,6 +257,72 @@ int mmc_send_ext_csd(struct mmc_card *ca return MMC_ERR_NONE; } +int mmc_send_csd(struct mmc_card *card, u32 *csd) +{ + if (!mmc_host_is_spi(card->host)) + return mmc_send_cxd_native(card->host, card->rca << 16, + csd, MMC_SEND_CSD); + + return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); +} + +int mmc_send_cid(struct mmc_host *host, u32 *cid) +{ + if (!mmc_host_is_spi(host)) { + if (!host->card) + return MMC_ERR_INVALID; + return mmc_send_cxd_native(host->card, host->card->rca << 16, + cid, MMC_SEND_CID); + } + + return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); +} + +int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +{ + return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, + ext_csd, 512); +} + +int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_READ_OCR; + cmd.flags = MMC_RSP_SPI_R3; + + err = mmc_wait_for_cmd(host, &cmd, 0); + + *ocrp = cmd.resp[1]; + return err; +} + +/* Enabling software CRCs can be a significant (30%) performance cost, + * and for other reasons isn't always desired; so it can be disabled. + */ +static int use_spi_crc = 1; +module_param(use_spi_crc, bool, 0); + +int mmc_spi_set_crc(struct mmc_host *host) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_CRC_ON_OFF; + cmd.flags = MMC_RSP_SPI_R1; + cmd.arg = use_spi_crc; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) + host->use_spi_crc = use_spi_crc; + return err; +} + int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; @@ -241,7 +338,7 @@ int mmc_switch(struct mmc_card *card, u8 (index << 16) | (value << 8) | set; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) @@ -261,13 +358,17 @@ int mmc_send_status(struct mmc_card *car memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + if (!mmc_host_is_spi(card->host)) + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) return err; + /* NOTE: callers are required to understand the difference + * between "native" and SPI format status words! + */ if (status) *status = cmd.resp[0]; --- g26.orig/drivers/mmc/core/mmc.c 2007-07-26 13:13:24.000000000 -0700 +++ g26/drivers/mmc/core/mmc.c 2007-07-26 14:54:35.000000000 -0700 @@ -262,9 +262,21 @@ static int mmc_init_card(struct mmc_host goto err; /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host); + if (err != MMC_ERR_NONE) + goto err; + } + + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err != MMC_ERR_NONE) goto err; @@ -287,13 +299,15 @@ static int mmc_init_card(struct mmc_host } /* - * Set card RCA. + * For native busses: set card RCA and leave open drain mode. */ - err = mmc_set_relative_addr(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_set_relative_addr(card); + if (err != MMC_ERR_NONE) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -314,13 +328,15 @@ static int mmc_init_card(struct mmc_host /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err != MMC_ERR_NONE) + goto free_card; + } if (!oldcard) { /* - * Fetch and process extened CSD. + * Fetch and process extended CSD. */ err = mmc_read_ext_csd(card); if (err != MMC_ERR_NONE) @@ -480,7 +496,8 @@ static void mmc_suspend(struct mmc_host BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } --- g26.orig/drivers/mmc/core/sd.c 2007-07-26 13:13:23.000000000 -0700 +++ g26/drivers/mmc/core/sd.c 2007-07-26 14:54:35.000000000 -0700 @@ -319,9 +319,21 @@ static int mmc_sd_init_card(struct mmc_h goto err; /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host); + if (err != MMC_ERR_NONE) + goto err; + } + + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err != MMC_ERR_NONE) goto err; @@ -343,13 +355,15 @@ static int mmc_sd_init_card(struct mmc_h } /* - * Set card RCA. + * For native busses: get card RCA and leave open drain mode. */ - err = mmc_send_relative_addr(host, &card->rca); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err != MMC_ERR_NONE) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -369,9 +383,11 @@ static int mmc_sd_init_card(struct mmc_h /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err != MMC_ERR_NONE) + goto free_card; + } if (!oldcard) { /* @@ -554,7 +570,8 @@ static void mmc_sd_suspend(struct mmc_ho BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } --- g26.orig/drivers/mmc/core/sd_ops.c 2007-07-26 13:13:24.000000000 -0700 +++ g26/drivers/mmc/core/sd_ops.c 2007-07-26 14:54:35.000000000 -0700 @@ -70,6 +70,12 @@ int mmc_wait_for_app_cmd(struct mmc_host err = cmd->error; if (cmd->error == MMC_ERR_NONE) break; + + /* no point in retrying illegal commands! */ + if (mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + break; + } } return err; @@ -89,10 +95,10 @@ int mmc_app_cmd(struct mmc_host *host, s if (card) { cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; } else { cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; } err = mmc_wait_for_cmd(host, &cmd, 0); @@ -100,8 +106,8 @@ int mmc_app_cmd(struct mmc_host *host, s return err; /* Check that card supported application commands */ - if (!(cmd.resp[0] & R1_APP_CMD)) - return MMC_ERR_FAILED; + if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) + return (u32)-1; return MMC_ERR_NONE; } @@ -148,14 +154,18 @@ int mmc_send_app_op_cond(struct mmc_host cmd.opcode = SD_APP_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + if (mmc_host_is_spi(host)) { + /* wait until reset completes */ + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; err = MMC_ERR_TIMEOUT; @@ -182,7 +192,7 @@ int mmc_send_if_cond(struct mmc_host *ho */ cmd.opcode = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; - cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, 0); if (err != MMC_ERR_NONE) @@ -229,6 +239,8 @@ int mmc_app_send_scr(struct mmc_card *ca BUG_ON(!card->host); BUG_ON(!scr); + /* NOTE: caller guarantees scr is heap-allocated */ + err = mmc_app_cmd(card->host, card); if (err != MMC_ERR_NONE) return err; @@ -242,7 +254,7 @@ int mmc_app_send_scr(struct mmc_card *ca cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 8; data.blocks = 1; @@ -278,6 +290,8 @@ int mmc_sd_switch(struct mmc_card *card, BUG_ON(!card); BUG_ON(!card->host); + /* NOTE: caller guarantees resp is heap-allocated */ + mode = !!mode; value &= 0xF; @@ -292,7 +306,7 @@ int mmc_sd_switch(struct mmc_card *card, cmd.arg = mode << 31 | 0x00FFFFFF; cmd.arg &= ~(0xF << (group * 4)); cmd.arg |= value << (group * 4); - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 64; data.blocks = 1; ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707261458.55558.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <200707261458.55558.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-26 22:22 ` David Brownell 2007-08-01 15:02 ` Pierre Ossman 1 sibling, 0 replies; 47+ messages in thread From: David Brownell @ 2007-07-26 22:22 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Grr ... sent wrong version. This passes "host" not "host->card" in one place (GCC would warn, and is otherwise the same. ====== CUT HERE Teach the MMC/SD/SDIO core about using SPI mode. - Use mmc_host_is_spi() so enumeration works through SPI signaling and protocols, not just the native versions. - Provide the SPI response type flags with each request issued, including requests from the new lock/unlock code. - Understand that some commands act a bit differently ... notably: * OP_COND command reports busy status differently * OP_COND command doesn't return the OCR * APP_CMD status doesn't have an R1_APP_CMD analogue - Understand that cmd->resp[0] and mmc_get_status() results for SPI return different values than for "native" MMC/SD protocol; this affects checking card lock status, and some others. Those changes required some new and updated primitives: - Provide utilities to access two SPI-only requests, and one request that wasn't previously needed: * mmc_spi_read_ocr() ... SPI only * mmc_spi_set_crc() ... SPI only (override by module parm) * mmc_spi_send_cid() ... works without broadcast mode - Updated internal routines: * Previous mmc_send_csd() modified into mmc_send_cxd_native(); it uses native "R2" responses, which include 16 bytes of data. * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data() helper for command-and-data access * Bugfix to that mmc_send_cxd_data() code: dma-to-stack is unsafe/nonportable, so kmalloc a bounce buffer instead. - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use those helper routines based on whether they're native or SPI The SPI support hasn't been tested on the new MMC4 cards (they're not widely available); likewise SD cards with 4GB and up may have surprises lurking. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> --- drivers/mmc/core/core.c | 24 ++++-- drivers/mmc/core/mmc.c | 39 +++++++--- drivers/mmc/core/mmc_ops.c | 165 ++++++++++++++++++++++++++++++++++++--------- drivers/mmc/core/mmc_ops.h | 3 drivers/mmc/core/sd.c | 37 +++++++--- drivers/mmc/core/sd_ops.c | 32 ++++++-- 6 files changed, 232 insertions(+), 68 deletions(-) --- g26.orig/drivers/mmc/core/mmc_ops.h 2007-07-26 13:13:23.000000000 -0700 +++ g26/drivers/mmc/core/mmc_ops.h 2007-07-26 14:54:35.000000000 -0700 @@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); int mmc_send_status(struct mmc_card *card, u32 *status); +int mmc_send_cid(struct mmc_host *host, u32 *cid); +int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp); +int mmc_spi_set_crc(struct mmc_host *host); #endif --- g26.orig/drivers/mmc/core/core.c 2007-07-26 13:13:24.000000000 -0700 +++ g26/drivers/mmc/core/core.c 2007-07-26 14:54:35.000000000 -0700 @@ -404,8 +404,13 @@ static void mmc_power_up(struct mmc_host int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (mmc_host_is_spi(host)) { + host->ios.chip_select = MMC_CS_HIGH; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -424,8 +429,10 @@ static void mmc_power_off(struct mmc_hos { host->ios.clock = 0; host->ios.vdd = 0; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (!mmc_host_is_spi(host)) { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + } host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -541,7 +548,9 @@ void mmc_rescan(struct work_struct *work err = mmc_send_app_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { - if (mmc_attach_sd(host, ocr)) + if (mmc_host_is_spi(host)) + err = mmc_spi_read_ocr(host, &ocr); + if (err != MMC_ERR_NONE || mmc_attach_sd(host, ocr)) mmc_power_off(host); } else { /* @@ -550,7 +559,10 @@ void mmc_rescan(struct work_struct *work */ err = mmc_send_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { - if (mmc_attach_mmc(host, ocr)) + if (mmc_host_is_spi(host)) + err = mmc_spi_read_ocr(host, &ocr); + if (err != MMC_ERR_NONE + || mmc_attach_mmc(host, ocr)) mmc_power_off(host); } else { mmc_power_off(host); --- g26.orig/drivers/mmc/core/mmc_ops.c 2007-07-26 13:13:23.000000000 -0700 +++ g26/drivers/mmc/core/mmc_ops.c 2007-07-26 15:21:57.000000000 -0700 @@ -63,23 +63,34 @@ int mmc_go_idle(struct mmc_host *host) int err; struct mmc_command cmd; - mmc_set_chip_select(host, MMC_CS_HIGH); - - mmc_delay(1); + /* + * Non-SPI hosts need to prevent chipselect going active during + * GO_IDLE; that would put chips into SPI mode. Remind them of + * that in case of hardware that won't pull up DAT3/nCS otherwise. + * + * SPI hosts ignore ios.chip_select; it's managed according to + * rules that must accomodate non-MMC slaves which this layer + * won't even know about. + */ + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_HIGH); + mmc_delay(1); + } memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; - cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; err = mmc_wait_for_cmd(host, &cmd, 0); mmc_delay(1); - mmc_set_chip_select(host, MMC_CS_DONTCARE); - - mmc_delay(1); + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_DONTCARE); + mmc_delay(1); + } return err; } @@ -94,15 +105,19 @@ int mmc_send_op_cond(struct mmc_host *ho memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); if (err != MMC_ERR_NONE) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + if (mmc_host_is_spi(host)) { + /* wait until reset completes */ + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; err = MMC_ERR_TIMEOUT; @@ -110,7 +125,7 @@ int mmc_send_op_cond(struct mmc_host *ho mmc_delay(10); } - if (rocr) + if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; return err; @@ -160,40 +175,46 @@ int mmc_set_relative_addr(struct mmc_car return MMC_ERR_NONE; } -int mmc_send_csd(struct mmc_card *card, u32 *csd) +static int +mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; struct mmc_command cmd; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!csd); + BUG_ON(!host); + BUG_ON(!cxd); memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SEND_CSD; - cmd.arg = card->rca << 16; + cmd.opcode = opcode; + cmd.arg = arg; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) return err; - memcpy(csd, cmd.resp, sizeof(u32) * 4); + memcpy(cxd, cmd.resp, sizeof(u32) * 4); return MMC_ERR_NONE; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int +mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, + u32 opcode, void *buf, unsigned len) { struct mmc_request mrq; struct mmc_command cmd; struct mmc_data data; struct scatterlist sg; + void *data_buf; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!ext_csd); + /* dma onto stack is unsafe/nonportable, but callers here + * normally provide temporary on-stack buffers. + */ + data_buf = kmalloc(len, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); @@ -202,21 +223,31 @@ int mmc_send_ext_csd(struct mmc_card *ca mrq.cmd = &cmd; mrq.data = &data; - cmd.opcode = MMC_SEND_EXT_CSD; + cmd.opcode = opcode; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - data.blksz = 512; + /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we + * rely on callers to never use this with "native" calls for reading + * CSD or CID. Native versions of those commands use the R2 type, + * not R1 plus a data block. + */ + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = len; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, ext_csd, 512); + sg_init_one(&sg, data_buf, len); - mmc_set_data_timeout(&data, card, 0); + if (card) + mmc_set_data_timeout(&data, card, 0); - mmc_wait_for_req(card->host, &mrq); + mmc_wait_for_req(host, &mrq); + + memcpy(buf, data_buf, len); + kfree(data_buf); if (cmd.error != MMC_ERR_NONE) return cmd.error; @@ -226,6 +257,72 @@ int mmc_send_ext_csd(struct mmc_card *ca return MMC_ERR_NONE; } +int mmc_send_csd(struct mmc_card *card, u32 *csd) +{ + if (!mmc_host_is_spi(card->host)) + return mmc_send_cxd_native(card->host, card->rca << 16, + csd, MMC_SEND_CSD); + + return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); +} + +int mmc_send_cid(struct mmc_host *host, u32 *cid) +{ + if (!mmc_host_is_spi(host)) { + if (!host->card) + return MMC_ERR_INVALID; + return mmc_send_cxd_native(host, host->card->rca << 16, + cid, MMC_SEND_CID); + } + + return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); +} + +int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +{ + return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, + ext_csd, 512); +} + +int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_READ_OCR; + cmd.flags = MMC_RSP_SPI_R3; + + err = mmc_wait_for_cmd(host, &cmd, 0); + + *ocrp = cmd.resp[1]; + return err; +} + +/* Enabling software CRCs can be a significant (30%) performance cost, + * and for other reasons isn't always desired; so it can be disabled. + */ +static int use_spi_crc = 1; +module_param(use_spi_crc, bool, 0); + +int mmc_spi_set_crc(struct mmc_host *host) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_CRC_ON_OFF; + cmd.flags = MMC_RSP_SPI_R1; + cmd.arg = use_spi_crc; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) + host->use_spi_crc = use_spi_crc; + return err; +} + int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; @@ -241,7 +338,7 @@ int mmc_switch(struct mmc_card *card, u8 (index << 16) | (value << 8) | set; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) @@ -261,13 +358,17 @@ int mmc_send_status(struct mmc_card *car memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + if (!mmc_host_is_spi(card->host)) + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) return err; + /* NOTE: callers are required to understand the difference + * between "native" and SPI format status words! + */ if (status) *status = cmd.resp[0]; --- g26.orig/drivers/mmc/core/mmc.c 2007-07-26 13:13:24.000000000 -0700 +++ g26/drivers/mmc/core/mmc.c 2007-07-26 14:54:35.000000000 -0700 @@ -262,9 +262,21 @@ static int mmc_init_card(struct mmc_host goto err; /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host); + if (err != MMC_ERR_NONE) + goto err; + } + + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err != MMC_ERR_NONE) goto err; @@ -287,13 +299,15 @@ static int mmc_init_card(struct mmc_host } /* - * Set card RCA. + * For native busses: set card RCA and leave open drain mode. */ - err = mmc_set_relative_addr(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_set_relative_addr(card); + if (err != MMC_ERR_NONE) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -314,13 +328,15 @@ static int mmc_init_card(struct mmc_host /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err != MMC_ERR_NONE) + goto free_card; + } if (!oldcard) { /* - * Fetch and process extened CSD. + * Fetch and process extended CSD. */ err = mmc_read_ext_csd(card); if (err != MMC_ERR_NONE) @@ -480,7 +496,8 @@ static void mmc_suspend(struct mmc_host BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } --- g26.orig/drivers/mmc/core/sd.c 2007-07-26 13:13:23.000000000 -0700 +++ g26/drivers/mmc/core/sd.c 2007-07-26 14:54:35.000000000 -0700 @@ -319,9 +319,21 @@ static int mmc_sd_init_card(struct mmc_h goto err; /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host); + if (err != MMC_ERR_NONE) + goto err; + } + + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err != MMC_ERR_NONE) goto err; @@ -343,13 +355,15 @@ static int mmc_sd_init_card(struct mmc_h } /* - * Set card RCA. + * For native busses: get card RCA and leave open drain mode. */ - err = mmc_send_relative_addr(host, &card->rca); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err != MMC_ERR_NONE) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -369,9 +383,11 @@ static int mmc_sd_init_card(struct mmc_h /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err != MMC_ERR_NONE) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err != MMC_ERR_NONE) + goto free_card; + } if (!oldcard) { /* @@ -554,7 +570,8 @@ static void mmc_sd_suspend(struct mmc_ho BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } --- g26.orig/drivers/mmc/core/sd_ops.c 2007-07-26 13:13:24.000000000 -0700 +++ g26/drivers/mmc/core/sd_ops.c 2007-07-26 14:54:35.000000000 -0700 @@ -70,6 +70,12 @@ int mmc_wait_for_app_cmd(struct mmc_host err = cmd->error; if (cmd->error == MMC_ERR_NONE) break; + + /* no point in retrying illegal commands! */ + if (mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + break; + } } return err; @@ -89,10 +95,10 @@ int mmc_app_cmd(struct mmc_host *host, s if (card) { cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; } else { cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; } err = mmc_wait_for_cmd(host, &cmd, 0); @@ -100,8 +106,8 @@ int mmc_app_cmd(struct mmc_host *host, s return err; /* Check that card supported application commands */ - if (!(cmd.resp[0] & R1_APP_CMD)) - return MMC_ERR_FAILED; + if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) + return (u32)-1; return MMC_ERR_NONE; } @@ -148,14 +154,18 @@ int mmc_send_app_op_cond(struct mmc_host cmd.opcode = SD_APP_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); if (err != MMC_ERR_NONE) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + if (mmc_host_is_spi(host)) { + /* wait until reset completes */ + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; err = MMC_ERR_TIMEOUT; @@ -182,7 +192,7 @@ int mmc_send_if_cond(struct mmc_host *ho */ cmd.opcode = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; - cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, 0); if (err != MMC_ERR_NONE) @@ -229,6 +239,8 @@ int mmc_app_send_scr(struct mmc_card *ca BUG_ON(!card->host); BUG_ON(!scr); + /* NOTE: caller guarantees scr is heap-allocated */ + err = mmc_app_cmd(card->host, card); if (err != MMC_ERR_NONE) return err; @@ -242,7 +254,7 @@ int mmc_app_send_scr(struct mmc_card *ca cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 8; data.blocks = 1; @@ -278,6 +290,8 @@ int mmc_sd_switch(struct mmc_card *card, BUG_ON(!card); BUG_ON(!card->host); + /* NOTE: caller guarantees resp is heap-allocated */ + mode = !!mode; value &= 0xF; @@ -292,7 +306,7 @@ int mmc_sd_switch(struct mmc_card *card, cmd.arg = mode << 31 | 0x00FFFFFF; cmd.arg &= ~(0xF << (group * 4)); cmd.arg |= value << (group * 4); - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 64; data.blocks = 1; ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <200707261458.55558.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 22:22 ` David Brownell @ 2007-08-01 15:02 ` Pierre Ossman [not found] ` <20070801170220.3c5ccff6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 1 sibling, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-08-01 15:02 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thu, 26 Jul 2007 14:58:54 -0700 David Brownell <david-b@pacbell.net> wrote: > > Yes we could ... but this way is IMO simpler, since it retains > a simple invariant: that the OCR parameter to attach() methods > is always valid. As one would expect! Which gives another > advantage: no surprises. > Fair enough. I'm not that attached to it. > > > > This will fail to initialise a high capacity MMC card. From the MMC > > spec: > > > > "Without the CMD58 with bits [30:29] set as "10b" in prior to the > > CMD1 a higher than 2GB of density of memory will remain in Idle > > state forever." > > The first thing mmc_attach_mmc() does is reset the card... > > Are you sure that "forever" means that reset will fail? > That would be a very foolish thing to specify. And while > I've seen strange things in specs, that would be one of > the worst that's not a vendor-specific part of a papering > over errata ... > Well, it's rather straight-forward if you think about it. As they've changed the addressing scheme, but retain the original commands, a host that does not understand the new scheme would utterly destroy the data. So the card refuses to init unless the host can present some evidence that it understands the new scheme. > I'd be inclined to leave this alone unless someone gets > such a card and notices that it doesn't work. After all, > lack of testing on those new (and-I-still-can't-find-one) > cards is a general disclaimer. > Too bad I have no SPI setup here. :( Please add a comment that we know that MMC 4.2 is broken and can be fixed once someone is able to test. > > > > The *_ops.c only contain function wrappers of protocol commands, not > > policy. So I think this is better placed where mmc_spi_set_crc() is > > called. > > You mean, have separate module params for SD and for MMC? > It seems cleaner this way... > No, that would be silly. You'd probably have to stick it in core.c and reference it from mmc.c and sd.c. The reason I complain is that seeing mmc_spi_set_crc() will look like it always activates CRC, as all other functions in *_ops.c are simple wrappers around protocol ops. > > > > "Illegal command" refers to the previous command sent (and failed). > > So this can give false negatives. > > The immediately preceding command would be MMC_APP_CMD ... ? > I didn't see any language in the specs which could let me > interpret this as anything other than APP_CMD failure: > > When an error bit is detected in “R” mode the card will > report the error in the response to the command that raised > the exception. The command will not be executed and the > associated state transition will not take place. > > What this does is to quickly abort retries of SD card ops > that were sent to MMC cards, and which always fail with > ILLEGAL_COMMAND. > I hate this part of the spec. The SD spec also claims: "Clear condition B: Always related to the previous command" But in the SPI section, they back out of that claim. So for SPI, things seems somewhat sane. (The MMC spec is even more hilarious. I lists clear condition A and B, but never explains what they mean. And looking at some older card specs, it seems that the MMC spec had the same conditions and definitions as SD *sigh*) We can proceed with your code, although I'm still a bit nervous about sticking that parsing in there. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070801170220.3c5ccff6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <20070801170220.3c5ccff6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-08-01 17:02 ` David Brownell [not found] ` <200708011002.28801.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-08-01 17:02 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Wednesday 01 August 2007, Pierre Ossman wrote: > On Thu, 26 Jul 2007 14:58:54 -0700 > David Brownell <david-b@pacbell.net> wrote: > > > > This will fail to initialise a high capacity MMC card. From the MMC > > > spec: > > > > > > "Without the CMD58 with bits [30:29] set as "10b" in prior to the > > > CMD1 a higher than 2GB of density of memory will remain in Idle > > > state forever." > > > > The first thing mmc_attach_mmc() does is reset the card... > > > > Are you sure that "forever" means that reset will fail? > > That would be a very foolish thing to specify. And while > > I've seen strange things in specs, that would be one of > > the worst that's not a vendor-specific part of a papering > > over errata ... > > > > Well, it's rather straight-forward if you think about it. As they've > changed the addressing scheme, Since I've not seen the MMC4 spec, I couldn't know. :) And the nearest approximation of MMC4 I've got (an early Samsung spec) says CMD58 has argument "none" (== 0) ... while one of the cards I've got rejected CMD58 before CMD1. So "straightforward" is not a word I could apply here... > but retain the original commands, a host > that does not understand the new scheme would utterly destroy the data. > So the card refuses to init unless the host can present some evidence > that it understands the new scheme. Right, but that doesn't answer my question: whether the card is specified to lock up "forever", or whether (as I'd expect) reinitialization (starting with reset) works the normal way. > > I'd be inclined to leave this alone unless someone gets > > such a card and notices that it doesn't work. After all, > > lack of testing on those new (and-I-still-can't-find-one) > > cards is a general disclaimer. > > > > Too bad I have no SPI setup here. :( My current setup uses a breadboard, so it can hook up to the real SPI hardware ... I started out using bitbanged SPI to a card which normally muxed to a "native" controller. Maybe one of those could work for you. > Please add a comment that we know that MMC 4.2 is broken and can be > fixed once someone is able to test. Doesn't the general disclaimer that MMC4 cards haven't been tested already cover that part? If you like, just tweak the patch comments to clarify. > > > The *_ops.c only contain function wrappers of protocol commands, not > > > policy. So I think this is better placed where mmc_spi_set_crc() is > > > called. > > > > You mean, have separate module params for SD and for MMC? > > It seems cleaner this way... > > > > No, that would be silly. You'd probably have to stick it in core.c and > reference it from mmc.c and sd.c. > > The reason I complain is that seeing mmc_spi_set_crc() will look like > it always activates CRC, as all other functions in *_ops.c are simple > wrappers around protocol ops. So, move the param and mmc_spi_set_crc() into core.c then, and leave the calls where they are? Can we do that as a separate patch? You said below we can proceed, which suggests to me that now's the time to convert to incrmentals. I don't mind a few more update patches, but it'd be easier to do them against say a git-mmc patch against 2.6.23-rc2 ... > > > "Illegal command" refers to the previous command sent (and failed). > > > So this can give false negatives. > > > > The immediately preceding command would be MMC_APP_CMD ... ? > > I didn't see any language in the specs which could let me > > interpret this as anything other than APP_CMD failure: > > > > When an error bit is detected in “R” mode the card will > > report the error in the response to the command that raised > > the exception. The command will not be executed and the > > associated state transition will not take place. > > > > What this does is to quickly abort retries of SD card ops > > that were sent to MMC cards, and which always fail with > > ILLEGAL_COMMAND. > > > > I hate this part of the spec. The SD spec also claims: > > "Clear condition B: Always related to the previous command" > > But in the SPI section, they back out of that claim. So for SPI, things > seems somewhat sane. I don't have either of those specs. "Previous command" isn't particularly clear, though maybe in context it could be ... it might mean the immediately preceding command, or the one before that, depending on usage. > (The MMC spec is even more hilarious. I lists clear condition A and B, > but never explains what they mean. And looking at some older card > specs, it seems that the MMC spec had the same conditions and > definitions as SD *sigh*) Yeech! > We can proceed with your code, although I'm still a bit nervous about > sticking that parsing in there. I don't think you need to be nervous about that. It clearly works, and to those of us who've worked this driver and had to become one with the docs we have, this hasn't raised flags. It is however *much* better not to need to map the SPI status codes into the "native" ones. As you implicitly noted above, expecting them to behave the same doesn't seem like a good idea! - Dave > Rgds > -- > -- Pierre Ossman > > Linux kernel, MMC maintainer http://www.kernel.org > PulseAudio, core developer http://pulseaudio.org > rdesktop, core developer http://www.rdesktop.org > ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200708011002.28801.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <200708011002.28801.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-08-02 12:54 ` Pierre Ossman [not found] ` <20070802145445.1118d1e7-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-08-02 12:54 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Wed, 1 Aug 2007 10:02:28 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > On Wednesday 01 August 2007, Pierre Ossman wrote: > > > > Well, it's rather straight-forward if you think about it. As they've > > changed the addressing scheme, > > Since I've not seen the MMC4 spec, I couldn't know. :) > You can see the same thing in SD with the if cond thingy. > And the nearest approximation of MMC4 I've got (an early Samsung > spec) says CMD58 has argument "none" (== 0) ... while one of the > cards I've got rejected CMD58 before CMD1. So "straightforward" > is not a word I could apply here... > We can just code it so that failure is acceptable for that initial CMD58. > > > but retain the original commands, a host > > that does not understand the new scheme would utterly destroy the > > data. So the card refuses to init unless the host can present some > > evidence that it understands the new scheme. > > Right, but that doesn't answer my question: whether the card > is specified to lock up "forever", or whether (as I'd expect) > reinitialization (starting with reset) works the normal way. > Like SDHC, it never goes out of idle mode. > > My current setup uses a breadboard, so it can hook up to the > real SPI hardware ... I started out using bitbanged SPI to a > card which normally muxed to a "native" controller. Maybe > one of those could work for you. > Well, I'd need something to do the banging. > > > Please add a comment that we know that MMC 4.2 is broken and can be > > fixed once someone is able to test. > > Doesn't the general disclaimer that MMC4 cards haven't been > tested already cover that part? If you like, just tweak the > patch comments to clarify. > The disclaimer is in the commit message. And people rarely go digging into the history for documentation. I'll add the comment before committing. > > So, move the param and mmc_spi_set_crc() into core.c then, and > leave the calls where they are? > mmc_spi_set_crc() fits quite nicely into mmc_ops.c, so no need for moving that. I was thinking more along the lines of: extern int mmc_spi_crc_enabled; mmc_spi_set_crc(host, mmc_spi_crc_enabled); > Can we do that as a separate patch? You said below we can proceed, > which suggests to me that now's the time to convert to incrmentals. > I don't mind a few more update patches, but it'd be easier to do > them against say a git-mmc patch against 2.6.23-rc2 ... > Sure. > > > > I hate this part of the spec. The SD spec also claims: > > > > "Clear condition B: Always related to the previous command" > > > > But in the SPI section, they back out of that claim. So for SPI, > > things seems somewhat sane. > > I don't have either of those specs. "Previous command" isn't > particularly clear, though maybe in context it could be ... it > might mean the immediately preceding command, or the one before > that, depending on usage. > That's from the public SD physical spec. And the wording doesn't get much clearer. Sometimes they also talk about the "last" command, which is equally ambiguous. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070802145445.1118d1e7-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI [not found] ` <20070802145445.1118d1e7-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-08-02 19:23 ` David Brownell 0 siblings, 0 replies; 47+ messages in thread From: David Brownell @ 2007-08-02 19:23 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 02 August 2007, Pierre Ossman wrote: > > > So, move the param and mmc_spi_set_crc() into core.c then, and > > leave the calls where they are? > > > > mmc_spi_set_crc() fits quite nicely into mmc_ops.c, so no need for > moving that. I was thinking more along the lines of: > > extern int mmc_spi_crc_enabled; > > mmc_spi_set_crc(host, mmc_spi_crc_enabled); OK. > > Can we do that as a separate patch? You said below we can proceed, > > which suggests to me that now's the time to convert to incrmentals. > > I don't mind a few more update patches, but it'd be easier to do > > them against say a git-mmc patch against 2.6.23-rc2 ... > > > > Sure. > ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> ` (2 preceding siblings ...) 2007-07-14 22:07 ` [patch 2.6.22-git5 3/4] MMC core " David Brownell @ 2007-07-14 22:08 ` David Brownell [not found] ` <200707141508.07555.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-16 16:48 ` [patch 2.6.22-git5 0/4] MMC-over-SPI Anton Vorontsov 4 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-14 22:08 UTC (permalink / raw) To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f Cc: Anton Vorontsov, Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, Pierre Ossman This is the latest version of the MMC-over-SPI support. It works on 2.6.22-git5, along with the preceding patches which teach the rest of the MMC stack about SPI so that this host driver can focus on doing only lowlevel SPI-specific stuff. It's been lightly tested on MMC and SD cards, reading and writing ext3 filesystems (including fsck). This includes CRC mode, which is now enabled by default. The main issue of note is that sometimes cards need to be power cycled to recover after certain faults. In some cases, it may be necessary to disable CRCs. ("modprobe mmc_core use_spi_crc=n") Changes from previous versions include more code shrinkage and cleanup, reducing the number of I/O requests needed per operation, and moving even more nuances into the MMC core code. Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> Cc: mikael.starvik-VrBV9hrLPhE@public.gmane.org, Cc: Hans-Peter Nilsson <hp-VrBV9hrLPhE@public.gmane.org> Cc: Jan Nikitenko <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Cc: Mike Lavender <mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf@public.gmane.org> --- drivers/mmc/host/Kconfig | 13 drivers/mmc/host/Makefile | 1 drivers/mmc/host/mmc_spi.c | 1416 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/spi/mmc_spi.h | 33 + 4 files changed, 1463 insertions(+) --- g26.orig/drivers/mmc/host/Kconfig 2007-07-14 14:47:11.000000000 -0700 +++ g26/drivers/mmc/host/Kconfig 2007-07-14 14:47:57.000000000 -0700 @@ -100,3 +100,16 @@ config MMC_TIFM_SD To compile this driver as a module, choose M here: the module will be called tifm_sd. +config MMC_SPI + tristate "MMC/SD over SPI" + depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL + select CRC7 + select CRC_ITU_T + help + Some systems accss MMC/SD cards using a SPI controller instead of + using a "native" MMC/SD controller. This has a disadvantage of + being relatively high overhead, but a compensating advantage of + working on many systems without dedicated MMC/SD controllers. + + If unsure, or if your system has no SPI master driver, say N. + --- g26.orig/drivers/mmc/host/Makefile 2007-07-14 14:47:11.000000000 -0700 +++ g26/drivers/mmc/host/Makefile 2007-07-14 14:47:57.000000000 -0700 @@ -15,4 +15,5 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91) += at91_mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o +obj-$(CONFIG_MMC_SPI) += mmc_spi.o --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ g26/include/linux/spi/mmc_spi.h 2007-07-14 14:47:57.000000000 -0700 @@ -0,0 +1,33 @@ +#ifndef __LINUX_SPI_MMC_SPI_H +#define __LINUX_SPI_MMC_SPI_H + +struct device; +struct mmc_host; + +/* Put this in platform_data of a device being used to manage an MMC/SD + * card slot. (Modeled after PXA mmc glue; see that for usage examples.) + * + * REVISIT This is not a spi-specific notion. Any card slot should be + * able to handle it. If the MMC core doesn't adopt this kind of notion, + * switch the "struct device *" parameters over to "struct spi_device *". + */ +struct mmc_spi_platform_data { + /* driver activation and (optional) card detect irq hookup */ + int (*init)(struct device *, + irqreturn_t (*)(int, void *), + void *); + void (*exit)(struct device *, void *); + + /* sense switch on sd cards */ + int (*get_ro)(struct device *); + + /* how long to debounce card detect, in msecs */ + u16 detect_delay; + + /* power management */ + u16 powerup_msecs; /* delay of up to 250 msec */ + u32 ocr_mask; /* available voltages */ + void (*setpower)(struct device *, unsigned int maskval); +}; + +#endif /* __LINUX_SPI_MMC_SPI_H */ --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ g26/drivers/mmc/host/mmc_spi.c 2007-07-14 14:47:57.000000000 -0700 @@ -0,0 +1,1416 @@ +/* + * mmc_spi.c - Access SD/MMC cards through SPI master controllers + * + * (C) Copyright 2005, Intec Automation, + * Mike Lavender (mike@steroidmicros) + * (C) Copyright 2006-2007, David Brownell + * (C) Copyright 2007, Axis Communications, + * Hans-Peter Nilsson (hp-VrBV9hrLPhE@public.gmane.org) + * (C) Copyright 2007, ATRON electronic GmbH, + * Jan Nikitenko <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/hrtimer.h> +#include <linux/delay.h> +#include <linux/blkdev.h> +#include <linux/dma-mapping.h> +#include <linux/crc7.h> +#include <linux/crc-itu-t.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */ + +#include <linux/spi/spi.h> +#include <linux/spi/mmc_spi.h> + +#include <asm/unaligned.h> + + +/* NOTES: + * + * - For now, we won't try to interoperate with a real mmc/sd/sdio + * controller, although some of them do have hardware support for + * SPI protocol. The main reason for such configs would be mmc-ish + * cards like DataFlash, which don't support that "native" protocol. + * + * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to + * switch between driver stacks, and in any case if "native" mode + * is available, it will be faster and hence preferable. + * + * - MMC depends on a different chipselect management policy than the + * SPI interface currently supports for shared bus segments: it needs + * to issue multiple spi_message requests with the chipselect active, + * using the results of one message to decide the next one to issue. + * + * Pending updates to the programming interface, this driver insists + * that it not share the bus with other drivers (preventing conflicts). + * + * - We tell the controller to keep the chipselect active from the + * beginning of an mmc_host_ops.request until the end. So beware + * of SPI controller drivers that mis-handle the cs_change flag! + * + * However, many cards seem OK with chipselect flapping up/down + * during that time ... at least on unshared bus segments. + */ + + +/* + * Local protocol constants, internal to data block protocols. + */ + +/* Response tokens used to ack each block written: */ +#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) +#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1) +#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1) +#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1) + +/* Read and write blocks start with these tokens and end with crc; + * on error, read tokens act like a subset of R2_SPI_* values. + */ +#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ +#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ +#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ + +#define MMC_SPI_BLOCKSIZE 512 + + +/* These fixed timeouts come from the latest SD specs, which say to ignore + * the CSD values. The R1B value is for card erase (e.g. the "I forgot the + * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after + * reads which takes nowhere near that long. Older cards may be able to use + * shorter timeouts ... but why bother? + */ +#define readblock_timeout ktime_set(0, 100 * 1000 * 1000) +#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000) +#define r1b_timeout ktime_set(3, 0) + + +/****************************************************************************/ + +/* + * Local Data Structures + */ + +/* "scratch" is per-{command,block} data exchanged with the card */ +struct scratch { + u8 status[29]; + u8 data_token; + __be16 crc_val; +}; + +struct mmc_spi_host { + struct mmc_host *mmc; + struct spi_device *spi; + + unsigned char power_mode; + u16 powerup_msecs; + + struct mmc_spi_platform_data *pdata; + + /* for bulk data transfers */ + struct spi_transfer token, t, crc, early_status; + struct spi_message m; + + /* for status readback */ + struct spi_transfer status; + struct spi_message readback; + + /* underlying DMA-aware controller, or null */ + struct device *dma_dev; + + /* buffer used for commands and for message "overhead" */ + struct scratch *data; + dma_addr_t data_dma; + + /* Specs say to write ones most of the time, even when the card + * has no need to read its input data; and many cards won't care. + * This is our source of those ones. + */ + void *ones; + dma_addr_t ones_dma; +}; + + +/****************************************************************************/ + +/* + * MMC-over-SPI protocol glue, used by the MMC stack interface + */ + +static inline int mmc_cs_off(struct mmc_spi_host *host) +{ + /* chipselect will always be inactive after setup() */ + return spi_setup(host->spi); +} + +static int +mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) +{ + int status; + + if (len > sizeof *host->data) { + WARN_ON(1); + return -EIO; + } + + host->status.len = len; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof *host->data, + DMA_FROM_DEVICE); + + status = spi_sync(host->spi, &host->readback); + if (status == 0) + status = host->readback.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof *host->data, + DMA_FROM_DEVICE); + + return status; +} + +static int +mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) +{ + u8 *cp = host->data->status; + + timeout = ktime_add(timeout, ktime_get()); + + while (1) { + int status; + unsigned i; + + status = mmc_spi_readbytes(host, n); + if (status < 0) + return status; + + for (i = 0; i < n; i++) { + if (cp[i] != byte) + return cp[i]; + } + + /* REVISIT investigate msleep() to avoid busy-wait I/O + * in at least some cases. + */ + if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0) + break; + } + return -ETIMEDOUT; +} + +static inline int +mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout) +{ + return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0); +} + +static int mmc_spi_readtoken(struct mmc_spi_host *host) +{ + return mmc_spi_skip(host, readblock_timeout, 1, 0xff); +} + + +/* + * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol + * hosts return! The low byte holds R1_SPI bits. The next byte may hold + * R2_SPI bits ... for SEND_STATUS, or after data read errors. + * + * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on + * newer cards R7 (IF_COND). + */ + +static char *maptype(struct mmc_command *cmd) +{ + switch (mmc_spi_resp_type(cmd)) { + case MMC_RSP_SPI_R1: return "R1"; + case MMC_RSP_SPI_R1B: return "R1B"; + case MMC_RSP_SPI_R2: return "R2"; + case MMC_RSP_SPI_R3: return "R3/R7"; + default: return "?"; + } +} + +/* return zero, else negative errno after setting cmd->error */ +static int mmc_spi_response_get(struct mmc_spi_host *host, + struct mmc_command *cmd, int cs_on) +{ + u8 *cp = host->data->status; + u8 *end = cp + host->t.len; + int value = 0; + char tag[32]; + + snprintf(tag, sizeof tag, " ... CMD%d response SPI_%s", + cmd->opcode, maptype(cmd)); + + /* Except for data block reads, the whole response will already + * be stored in the scratch buffer. It's somewhere after the + * command and the first byte we read after it. We ignore that + * first byte. After STOP_TRANSMISSION command it may include + * two data bits, but otherwise it's all ones. + */ + cp += 8; + while (cp < end && *cp == 0xff) + cp++; + + /* Data block reads (R1 response types) may need more data... */ + if (cp == end) { + unsigned i; + + cp = host->data->status; + + /* Card sends N(CR) (== 1..8) bytes of all-ones then one + * status byte ... and we already scanned 2 bytes. + * + * REVISIT block read paths use nasty byte-at-a-time I/O + * so it can always DMA directly into the target buffer. + * It'd probably be better to memcpy() the first chunk and + * avoid extra i/o calls... + */ + for (i = 2; i < 9; i++) { + value = mmc_spi_readbytes(host, 1); + if (value < 0) { + cmd->error = MMC_ERR_FAILED; + goto done; + } + if (*cp != 0xff) + goto checkstatus; + } + value = -ETIMEDOUT; + cmd->error = MMC_ERR_TIMEOUT; + goto done; + } + +checkstatus: + if (*cp & 0x80) { + dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n", + tag, *cp); + cmd->error = MMC_ERR_FAILED; + value = -EBADR; + goto done; + } + + cmd->resp[0] = *cp++; + cmd->error = MMC_ERR_NONE; + + /* Status byte: the entire seven-bit R1 response. */ + if (cmd->resp[0] != 0) { + if (R1_SPI_COM_CRC & cmd->resp[0]) { + cmd->error = MMC_ERR_BADCRC; + value = -EILSEQ; + } else if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS + | R1_SPI_ILLEGAL_COMMAND) + & cmd->resp[0]) { + cmd->error = MMC_ERR_INVALID; + value = -EINVAL; + } else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) + & cmd->resp[0]) { + cmd->error = MMC_ERR_FAILED; + value = -EINVAL; + } /* else R1_SPI_IDLE, "it's resetting" */ + + if (value < 0) + goto fail; + } + + switch (mmc_spi_resp_type(cmd)) { + + /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads) + * and less-common stuff like various erase operations. + */ + case MMC_RSP_SPI_R1B: + /* maybe we read all the busy tokens already */ + while (cp < end && *cp == 0) + cp++; + if (cp == end) + mmc_spi_wait_unbusy(host, r1b_timeout); + break; + + /* SPI R2 == R1 + second status byte; SEND_STATUS */ + case MMC_RSP_SPI_R2: + cmd->resp[0] |= *cp << 8; + break; + + /* SPI R3 or R7 == R1 + 4 bytes */ + case MMC_RSP_SPI_R3: + cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp)); + break; + + /* SPI R1 == just one status byte */ + case MMC_RSP_SPI_R1: + break; + + default: + dev_dbg(&host->spi->dev, "bad response type %04x\n", + mmc_spi_resp_type(cmd)); + if (value >= 0) { + cmd->error = MMC_ERR_INVALID; + value = -EINVAL; + } + } + +fail: + if (value < 0) + dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n", + tag, cmd->resp[0], cmd->resp[1]); + + /* disable chipselect on errors and some success cases */ + if (value >= 0 && cs_on) + return value; +done: + mmc_cs_off(host); + return value; +} + +/* Issue command and read its response. + * Returns zero on success, negative for error. + * + * On error, caller must cope with mmc core retry mechanism. That + * means immediate low-level resubmit, which affects the bus lock... + */ +static int +mmc_spi_command_send(struct mmc_spi_host *host, + struct mmc_request *mrq, + struct mmc_command *cmd, int cs_on) +{ + struct scratch *data = host->data; + u8 *cp = data->status; + u32 arg = cmd->arg; + int status; + struct spi_transfer *t; + + /* We can handle most commands (except block reads) in one full + * duplex I/O operation before either starting the next transfer + * (data block or command) or else deselecting the card. + * + * First, write 7 bytes: + * - an all-ones byte to ensure the card is ready + * - opcode byte (plus start and transmission bits) + * - four bytes of big-endian argument + * - crc7 (plus end bit) ... always computed, it's cheap + * + * We init the whole buffer to all-ones, which is what we need + * to write while we're reading (later) response data. + */ + memset(cp++, 0xff, sizeof(data->status)); + + *cp++ = 0x40 | cmd->opcode; + *cp++ = (u8)(arg >> 24); + *cp++ = (u8)(arg >> 16); + *cp++ = (u8)(arg >> 8); + *cp++ = (u8)arg; + *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01; + + /* Then, read up to 13 bytes (while writing all-ones): + * - N(CR) (== 1..8) bytes of all-ones + * - status byte (for all response types) + * - the rest of the response, either: + * + nothing, for R1 or R1B responses + * + second status byte, for R2 responses + * + four data bytes, for R3 and R7 responses + * + * Finally, read some more bytes ... in the nice cases we know in + * advance how many, and reading 1 more is always OK: + * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish + * - N(RC) (== 1..N) bytes of all-ones, before next command + * - N(WR) (== 1..N) bytes of all-ones, before data write + * + * So in those cases one full duplex I/O of at most 21 bytes will + * handle the whole command, leaving the card ready to receive a + * data block or new command. We do that whenever we can, shaving + * CPU and IRQ costs (especially when using DMA or FIFOs). + * + * There are two other cases, where it's not generally practical + * to rely on a single I/O: + * + * - R1B responses need at least N(EC) bytes of all-zeroes. + * + * In this case we can *try* to fit it into one I/O, then + * maybe read more data later. + * + * - Data block reads are more troublesome, since a variable + * number of padding bytes precede the token and data. + * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID + * + N(AC) (== 1..many) bytes of all-ones + * + * In this case we currently only have minimal speedups here: + * when N(CR) == 1 we can avoid I/O in response_get(). + */ + if (cs_on && (mrq->data->flags & MMC_DATA_READ)) { + cp += 2; /* min(N(CR)) + status */ + /* R1 */ + } else { + cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */ + if (cmd->flags & MMC_RSP_SPI_S2) /* R2 */ + cp++; + else if (cmd->flags & MMC_RSP_SPI_B4) /* R3, R7 */ + cp += 4; + else if (cmd->flags & MMC_RSP_BUSY) /* R1B */ + cp = data->status + sizeof(data->status); + /* else: R1 (most commands) */ + } + + dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, MMC_SPI_%s\n", + cmd->opcode, maptype(cmd)); + + /* send command, leaving chipselect active */ + spi_message_init(&host->m); + + t = &host->t; + memset(t, 0, sizeof *t); + t->tx_buf = t->rx_buf = data->status; + t->tx_dma = t->rx_dma = host->data_dma; + t->len = cp - data->status; + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + + if (host->dma_dev) { + host->m.is_dma_mapped = 1; + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof *host->data, + DMA_BIDIRECTIONAL); + } + status = spi_sync(host->spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof *host->data, + DMA_BIDIRECTIONAL); + if (status < 0) { + dev_dbg(&host->spi->dev, " ... write returned %d\n", status); + cmd->error = MMC_ERR_FAILED; + return status; + } + + /* after no-data commands and STOP_TRANSMISSION, chipselect off */ + return mmc_spi_response_get(host, cmd, cs_on); +} + +/* Build data message with up to four separate transfers. For TX, we + * start by writing the data token. And in most cases, we finish with + * a status transfer. + * + * We always provide TX data for data and CRC. The MMC/SD protocol + * requires us to write ones; but Linux defaults to writing zeroes; + * so we explicitly initialize it to all ones on RX paths. + * + * We also handle DMA mapping, so the underlying SPI controller does + * not need to (re)do it for each message. + */ +static void +mmc_spi_setup_data_message( + struct mmc_spi_host *host, + int multiple, + enum dma_data_direction direction) +{ + struct spi_transfer *t; + struct scratch *scratch = host->data; + dma_addr_t dma = host->data_dma; + + spi_message_init(&host->m); + if (dma) + host->m.is_dma_mapped = 1; + + /* for reads, readblock() skips 0xff bytes before finding + * the token; for writes, this transfer issues that token. + */ + if (direction == DMA_TO_DEVICE) { + t = &host->token; + memset(t, 0, sizeof *t); + t->len = 1; + if (multiple) + scratch->data_token = SPI_TOKEN_MULTI_WRITE; + else + scratch->data_token = SPI_TOKEN_SINGLE; + t->tx_buf = &scratch->data_token; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, data_token); + spi_message_add_tail(t, &host->m); + } + + /* Body of transfer is buffer, then CRC ... + * either TX-only, or RX with TX-ones. + */ + t = &host->t; + memset(t, 0, sizeof *t); + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + /* length and actual buffer info are written later */ + spi_message_add_tail(t, &host->m); + + t = &host->crc; + memset(t, 0, sizeof *t); + t->len = 2; + if (direction == DMA_TO_DEVICE) { + /* the actual CRC may get written later */ + t->tx_buf = &scratch->crc_val; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, crc_val); + } else { + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = &scratch->crc_val; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, crc_val); + } + spi_message_add_tail(t, &host->m); + + /* + * A single block read is followed by N(EC) [0+] all-ones bytes + * before deselect ... don't bother. + * + * Multiblock reads are followed by N(AC) [1+] all-ones bytes before + * the next block is read, or a STOP_TRANSMISSION is issued. We'll + * collect that single byte, so readblock() doesn't need to. + * + * For a write, the one-byte data response follows immediately, then + * come zero or more busy bytes, then N(WR) [1+] all-ones bytes. + * Then single block reads may deselect, and multiblock ones issue + * the next token (next data block, or STOP_TRAN). We can try to + * minimize I/O ops by using a single read to collect end-of-busy. + */ + if (multiple || direction == DMA_TO_DEVICE) { + t = &host->early_status; + memset(t, 0, sizeof *t); + t->len = (direction == DMA_TO_DEVICE) + ? sizeof(scratch->status) + : 1; + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = scratch->status; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, status); + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + } +} + +/* + * Write one block: + * - caller handled preceding N(WR) [1+] all-ones bytes + * - data block + * + token + * + data bytes + * + crc16 + * - an all-ones byte ... card writes a data-response byte + * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy' + * + * Return negative errno, else success. + */ +static int +mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status, i; + struct scratch *scratch = host->data; + + if (host->mmc->use_spi_crc) + scratch->crc_val = cpu_to_be16( + crc_itu_t(0, t->tx_buf, t->len)); + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof *scratch, + DMA_BIDIRECTIONAL); + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (status != 0) { + dev_dbg(&spi->dev, "write error (%d)\n", status); + return status; + } + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof *scratch, + DMA_BIDIRECTIONAL); + + /* + * Get the transmission data-response reply. It must follow + * immediately after the data block we transferred. This reply + * doesn't necessarily tell whether the write operation succeeded; + * it just says if the transmission was ok and whether *earlier* + * writes succeeded; see the standard. + */ + switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) { + case SPI_RESPONSE_ACCEPTED: + status = 0; + break; + case SPI_RESPONSE_CRC_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION */ + status = -EILSEQ; + break; + case SPI_RESPONSE_WRITE_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION, + * and should MMC_SEND_STATUS to sort it out + */ + status = -EIO; + break; + default: + status = -EPROTO; + break; + } + if (status != 0) { + dev_dbg(&spi->dev, "write error %02x (%d)\n", + scratch->status[0], status); + return status; + } + + t->tx_buf += t->len; + if (host->dma_dev) + t->tx_dma += t->len; + + /* Return when not busy. If we didn't collect that status yet, + * we'll need some more I/O. + */ + for (i = 1; i < sizeof scratch->status; i++) { + if (scratch->status[i] != 0) + return 0; + } + return mmc_spi_wait_unbusy(host, writeblock_timeout); +} + +/* + * Read one block: + * - skip leading all-ones bytes ... either + * + N(AC) [1..f(clock,CSD)] usually, else + * + N(CX) [0..8] when reading CSD or CID + * - data block + * + token ... if error token, no data or crc + * + data bytes + * + crc16 + * + * After single block reads, we're done; N(EC) [0+] all-ones bytes follow + * before dropping chipselect. + * + * For multiblock reads, caller either reads the next block or issues a + * STOP_TRANSMISSION command. + */ +static int +mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status; + struct scratch *scratch = host->data; + + /* At least one SD card sends an all-zeroes byte when N(CX) + * applies, before the all-ones bytes ... just cope with that. + */ + status = mmc_spi_readbytes(host, 1); + if (status < 0) + return status; + status = scratch->status[0]; + if (status == 0xff || status == 0) + status = mmc_spi_readtoken(host); + + if (status == SPI_TOKEN_SINGLE) { + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof *scratch, + DMA_BIDIRECTIONAL); + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof *scratch, + DMA_BIDIRECTIONAL); + } else { + dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); + + /* we've read extra garbage, timed out, etc */ + if (status < 0) + return status; + + /* low four bits are an R2 subset, fifth seems to be + * vendor specific ... map them all to generic error.. + */ + return -EIO; + } + + if (host->mmc->use_spi_crc) { + u16 crc = crc_itu_t(0, t->rx_buf, t->len); + + be16_to_cpus(&scratch->crc_val); + if (scratch->crc_val != crc) { + dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " + "computed=0x%04x len=%d\n", + scratch->crc_val, crc, t->len); + return -EILSEQ; + } + } + + t->rx_buf += t->len; + if (host->dma_dev) + t->rx_dma += t->len; + + return 0; +} + +/* + * An MMC/SD data stage includes one or more blocks, optional CRCs, + * and inline handshaking. That handhaking makes it unlike most + * other SPI protocol stacks. + */ +static void +mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, + struct mmc_data *data, u32 blk_size) +{ + struct spi_device *spi = host->spi; + struct device *dma_dev = host->dma_dev; + struct spi_transfer *t; + enum dma_data_direction direction; + struct scatterlist *sg; + unsigned n_sg; + int multiple = (data->blocks > 1); + + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + mmc_spi_setup_data_message(host, multiple, direction); + t = &host->t; + + /* Handle scatterlist segments one at a time, with synch for + * each 512-byte block + */ + for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) { + int status = 0; + dma_addr_t dma_addr = 0; + void *kmap_addr; + unsigned length = sg->length; + + /* set up dma mapping for controller drivers that might + * use DMA ... though they may fall back to PIO + */ + if (dma_dev) { + dma_addr = dma_map_page(dma_dev, sg->page, 0, + PAGE_SIZE, direction); + if (direction == DMA_TO_DEVICE) + t->tx_dma = dma_addr + sg->offset; + else + t->rx_dma = dma_addr + sg->offset; + } + + /* allow pio too; we don't allow highmem */ + kmap_addr = kmap(sg->page); + if (direction == DMA_TO_DEVICE) + t->tx_buf = kmap_addr + sg->offset; + else + t->rx_buf = kmap_addr + sg->offset; + + /* transfer each block, and update request status */ + while (length) { + t->len = min(length, blk_size); + + dev_dbg(&host->spi->dev, + " mmc_spi: %s block, %d bytes\n", + (direction == DMA_TO_DEVICE) + ? "write" + : "read", + t->len); + + if (direction == DMA_TO_DEVICE) + status = mmc_spi_writeblock(host, t); + else + status = mmc_spi_readblock(host, t); + if (status < 0) + break; + + data->bytes_xfered += t->len; + length -= t->len; + + if (!multiple) + break; + } + + /* discard mappings */ + if (direction == DMA_FROM_DEVICE) + flush_kernel_dcache_page(sg->page); + kunmap(sg->page); + if (dma_dev) + dma_unmap_page(dma_dev, dma_addr, + PAGE_SIZE, direction); + + if (status < 0) { + dev_dbg(&spi->dev, "%s status %d\n", + (direction == DMA_TO_DEVICE) + ? "write" : "read", + status); + if (status == -EILSEQ) + data->error = MMC_ERR_BADCRC; + else if (status == -ETIMEDOUT) + data->error = MMC_ERR_TIMEOUT; + else if (status == -EINVAL) + data->error = MMC_ERR_INVALID; + else if (data->error == MMC_ERR_NONE) + data->error = MMC_ERR_FAILED; + break; + } + } + + /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that + * can be issued before multiblock writes. Unlike its more widely + * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23), + * that can affect the STOP_TRAN logic. Complete (and current) + * MMC specs should sort that out before Linux starts using CMD23. + */ + if (direction == DMA_TO_DEVICE && multiple) { + struct scratch *scratch = host->data; + int tmp; + const unsigned statlen = sizeof(scratch->status); + + dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n"); + + /* Tweak the per-block message we set up earlier by morphing + * it to hold single buffer with the token followed by some + * all-ones bytes ... skip N(BR) (0..1), scan the rest for + * "not busy any longer" status, and leave chip selected. + */ + INIT_LIST_HEAD(&host->m.transfers); + list_add(&host->early_status.transfer_list, + &host->m.transfers); + + scratch->status[0] = SPI_TOKEN_STOP_TRAN; + memset(scratch->status + 1, 0xff, statlen - 1); + host->early_status.tx_buf = host->early_status.rx_buf; + host->early_status.tx_dma = host->early_status.rx_dma; + host->early_status.len = 1 + statlen; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof *scratch, + DMA_BIDIRECTIONAL); + + tmp = spi_sync(spi, &host->m); + if (tmp == 0) + tmp = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof *scratch, + DMA_BIDIRECTIONAL); + + if (tmp < 0) { + if (data->error == MMC_ERR_NONE) + data->error = MMC_ERR_FAILED; + return; + } + + /* Ideally we collected "not busy" status with one I/O, + * avoiding wasteful byte-at-a-time scanning... but more + * I/O is often needed. + */ + for (tmp = 2; tmp < statlen; tmp++) { + if (scratch->status[tmp] != 0) + return; + } + tmp = mmc_spi_wait_unbusy(host, writeblock_timeout); + if (tmp < 0 && data->error == MMC_ERR_NONE) { + if (tmp == -ETIMEDOUT) + data->error = MMC_ERR_TIMEOUT; + else + data->error = MMC_ERR_FAILED; + } + } +} + +/****************************************************************************/ + +/* + * MMC driver implementation -- the interface to the MMC stack + */ + +static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + int status = -EINVAL; + +#ifdef DEBUG + /* MMC core and layered drivers *MUST* issue SPI-aware commands */ + { + struct mmc_command *cmd; + int invalid = 0; + + cmd = mrq->cmd; + if (!mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus command\n"); + cmd->error = MMC_ERR_INVALID; + invalid = 1; + } + + cmd = mrq->stop; + if (cmd && !mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus STOP command\n"); + cmd->error = MMC_ERR_INVALID; + invalid = 1; + } + + if (invalid) { + dump_stack(); + mmc_request_done(host->mmc, mrq); + return; + } + } +#endif + + /* issue command; then optionally data and stop */ + status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL); + if (status == 0 && mrq->data) { + mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz); + if (mrq->stop) + status = mmc_spi_command_send(host, mrq, mrq->stop, 0); + else + mmc_cs_off(host); + } + + mmc_request_done(host->mmc, mrq); +} + +/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0" + * + * NOTE that here we can't know that the card has just been powered up; + * not all MMC/SD sockets support power switching. + * + * FIXME when the card is still in SPI mode, e.g. from a previous kernel, + * this doesn't seem to do the right thing at all... + */ +static void mmc_spi_initsequence(struct mmc_spi_host *host) +{ + /* Try to be very sure any previous command has completed; + * wait till not-busy, skip debris from any old commands. + */ + mmc_spi_wait_unbusy(host, r1b_timeout); + mmc_spi_readbytes(host, 10); + + /* + * Do a burst with chipselect active-high. We need to do this to + * meet the requirement of 74 clock cycles with both chipselect + * and CMD (MOSI) high before CMD0 ... after the card has been + * powered up to Vdd(min), and so is ready to take commands. + * + * Some cards are particularly needy of this (e.g. Viking "SD256") + * while most others don't seem to care. + * + * Note that this is one of the places MMC/SD plays games with the + * SPI protocol. Another is that when chipselect is released while + * the card returns BUSY status, the clock must issue several cycles + * with chipselect high before the card will stop driving its output. + */ + host->spi->mode |= SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Just warn; most cards work without it. */ + dev_warn(&host->spi->dev, + "can't change chip-select polarity\n"); + host->spi->mode &= ~SPI_CS_HIGH; + } else { + mmc_spi_readbytes(host, 18); + + host->spi->mode &= ~SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Wot, we can't get the same setup we had before? */ + dev_err(&host->spi->dev, + "can't restore chip-select polarity\n"); + } + } +} + +static char *mmc_powerstring(u8 power_mode) +{ + switch (power_mode) { + case MMC_POWER_OFF: return "off"; + case MMC_POWER_UP: return "up"; + case MMC_POWER_ON: return "on"; + } + return "?"; +} + +static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->power_mode != ios->power_mode) { + int canpower; + + canpower = host->pdata && host->pdata->setpower; + + dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n", + mmc_powerstring(ios->power_mode), + ios->vdd, + canpower ? ", can switch" : ""); + + /* switch power on/off if possible, accounting for + * max 250msec powerup time if needed. + */ + if (canpower) { + switch (ios->power_mode) { + case MMC_POWER_OFF: + case MMC_POWER_UP: + host->pdata->setpower(&host->spi->dev, + ios->vdd); + if (ios->power_mode == MMC_POWER_UP) + msleep(host->powerup_msecs); + } + } + + /* See 6.4.1 in the simplified SD card physical spec 2.0 */ + if (ios->power_mode == MMC_POWER_ON) + mmc_spi_initsequence(host); + + /* If powering down, ground all card inputs to avoid power + * delivery from data lines! On a shared SPI bus, this + * will probably be temporary; 6.4.2 of the simplified SD + * spec says this must last at least 1msec. + * + * - Clock low means CPOL 0, e.g. mode 0 + * - MOSI low comes from writing zero + * - Chipselect is usually active low... + */ + if (canpower && ios->power_mode == MMC_POWER_OFF) { + int mres; + + host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch to SPI mode 0 failed\n"); + + if (spi_w8r8(host->spi, 0x00) < 0) + dev_dbg(&host->spi->dev, + "put spi signals to low failed\n"); + + /* + * Now clock should be low due to spi mode 0; + * MOSI should be low because of written 0x00; + * chipselect should be low (it is active low) + * power supply is off, so now MMC is off too! + * + * FIXME no, chipselect can be high since the + * device is inactive and SPI_CS_HIGH is clear... + */ + msleep(10); + if (mres == 0) { + host->spi->mode |= (SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch back to SPI mode 3" + " failed\n"); + } + } + + host->power_mode = ios->power_mode; + } + + if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) { + int status; + + host->spi->max_speed_hz = ios->clock; + status = spi_setup(host->spi); + dev_dbg(&host->spi->dev, + "mmc_spi: clock to %d Hz, %d\n", + host->spi->max_speed_hz, status); + } +} + +static int mmc_spi_get_ro(struct mmc_host *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc->parent); + /* board doesn't support read only detection; assume writeable */ + return 0; +} + + +static const struct mmc_host_ops mmc_spi_ops = { + .request = mmc_spi_request, + .set_ios = mmc_spi_set_ios, + .get_ro = mmc_spi_get_ro, +}; + + +/****************************************************************************/ + +/* + * SPI driver implementation + */ + +static irqreturn_t +mmc_spi_detect_irq(int irq, void *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + u16 delay_msec = max(host->pdata->detect_delay, (u16)100); + + mmc_detect_change(mmc, msecs_to_jiffies(delay_msec)); + return IRQ_HANDLED; +} + +static int mmc_spi_probe(struct spi_device *spi) +{ + void *ones; + struct mmc_host *mmc; + struct mmc_spi_host *host; + int status; + + /* SanDisk and Hitachi MMC docs both show clock timing diagrams + * with clock starting low (CPOL=0) and sampling on leading edge + * (CPHA=0); clock is measured between rising edges. Sandisk SD + * docs show clock starting high (CPOL=1) and sampling on trailing + * edge (CPHA=1), measuring between falling edges. + * + * Docs are very explicit that sampling is on the rising edge, so + * SPI_MODE_0 and SPI_MODE_3 having different CPOL may not matter. + */ + spi->mode |= SPI_CPOL | SPI_CPHA; + spi->bits_per_word = 8; + + status = spi_setup(spi); + if (status < 0) { + dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n", + spi->mode, spi->max_speed_hz / 1000, + status); + return status; + } + + /* We can use the bus safely iff nobody else will interfere with + * us. That is, either we have the experimental exclusive access + * primitives ... or else there's nobody to share it with. + */ + if (spi->master->num_chipselect > 1) { + struct device *parent = spi->dev.parent; + + /* If there are multiple devices on this bus, we + * can't proceed. + */ + spin_lock(&parent->klist_children.k_lock); + if (parent->klist_children.k_list.next + != parent->klist_children.k_list.prev) + status = -EMLINK; + else + status = 0; + spin_unlock(&parent->klist_children.k_lock); + if (status < 0) { + dev_err(&spi->dev, "can't share SPI bus\n"); + return status; + } + + /* REVISIT we can't guarantee another device won't + * be added later. It's uncommon though ... for now, + * work as if this is safe. + */ + dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n"); + } + + /* We need a supply of ones to transmit. This is the only time + * the CPU touches these, so cache coherency isn't a concern. + * + * NOTE if many systems use more than one MMC-over-SPI connector + * it'd save some memory to share this. That's evidently rare. + */ + status = -ENOMEM; + ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL); + if (!ones) + goto nomem; + memset(ones, 0xff, MMC_SPI_BLOCKSIZE); + + mmc = mmc_alloc_host(sizeof *host, &spi->dev); + if (!mmc) + goto nomem; + + mmc->ops = &mmc_spi_ops; + mmc->max_blk_size = MMC_SPI_BLOCKSIZE; + + /* As long as we keep track of the number of successfully + * transmitted blocks, we're good for multiwrite. + */ + mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE; + + /* SPI doesn't need the lowspeed device identification thing for + * MMC or SD cards, since it never comes up in open drain mode. + * That's good; some SPI masters can't handle very low speeds! + * + * However, low speed SDIO cards need not handle over 400 KHz; + * that's the only reason not to use a few MHz for f_min (until + * the upper layer reads the target frequency from the CSD). + */ + mmc->f_min = 400000; + mmc->f_max = spi->max_speed_hz; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->spi = spi; + + host->ones = ones; + + /* Platform data is used to hook up things like card sensing + * and power switching gpios. + */ + host->pdata = spi->dev.platform_data; + if (host->pdata) + mmc->ocr_avail = host->pdata->ocr_mask; + if (!mmc->ocr_avail) { + dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n"); + mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + } + if (host->pdata && host->pdata->setpower) { + host->powerup_msecs = host->pdata->powerup_msecs; + if (!host->powerup_msecs || host->powerup_msecs > 250) + host->powerup_msecs = 250; + } + + dev_set_drvdata(&spi->dev, mmc); + + /* preallocate dma buffers */ + host->data = kmalloc(sizeof *host->data, GFP_KERNEL); + if (!host->data) + goto fail_nobuf1; + + if (spi->master->cdev.dev->dma_mask) { + struct device *dev = spi->master->cdev.dev; + + host->dma_dev = dev; + host->ones_dma = dma_map_single(dev, ones, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + host->data_dma = dma_map_single(dev, host->data, + sizeof *host->data, DMA_BIDIRECTIONAL); + + /* REVISIT in theory those map operations can fail... */ + + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof *host->data, + DMA_BIDIRECTIONAL); + } + + /* setup message for status/busy readback */ + spi_message_init(&host->readback); + host->readback.is_dma_mapped = (host->dma_dev != NULL); + + spi_message_add_tail(&host->status, &host->readback); + host->status.tx_buf = host->ones; + host->status.tx_dma = host->ones_dma; + host->status.rx_buf = &host->data->status; + host->status.rx_dma = host->data_dma + offsetof(struct scratch, status); + host->status.cs_change = 1; + + /* register card detect irq */ + if (host->pdata && host->pdata->init) { + status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc); + if (status != 0) + goto fail_glue_init; + } + + status = mmc_add_host(mmc); + if (status != 0) + goto fail_add_host; + + dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n", + mmc->class_dev.bus_id, + host->dma_dev ? "" : ", no DMA", + (host->pdata && host->pdata->get_ro) + ? "" : ", no WP", + (host->pdata && host->pdata->setpower) + ? "" : ", no poweroff"); + return 0; + +fail_add_host: + mmc_remove_host (mmc); +fail_glue_init: + if (host->dma_dev) + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof *host->data, DMA_BIDIRECTIONAL); + kfree(host->data); + +fail_nobuf1: + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + +nomem: + kfree(ones); + return status; +} + + +static int __devexit mmc_spi_remove(struct spi_device *spi) +{ + struct mmc_host *mmc = dev_get_drvdata(&spi->dev); + struct mmc_spi_host *host; + + if (mmc) { + host = mmc_priv(mmc); + + /* prevent new mmc_detect_change() calls */ + if (host->pdata && host->pdata->exit) + host->pdata->exit(&spi->dev, mmc); + + mmc_remove_host(mmc); + + if (host->dma_dev) { + dma_unmap_single(host->dma_dev, host->ones_dma, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof *host->data, DMA_BIDIRECTIONAL); + } + + kfree(host->data); + kfree(host->ones); + + spi->max_speed_hz = mmc->f_max; + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + } + return 0; +} + + +static struct spi_driver mmc_spi_driver = { + .driver = { + .name = "mmc_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mmc_spi_probe, + .remove = __devexit_p(mmc_spi_remove), +}; + + +static int __init mmc_spi_init(void) +{ + return spi_register_driver(&mmc_spi_driver); +} +module_init(mmc_spi_init); + + +static void __exit mmc_spi_exit(void) +{ + spi_unregister_driver(&mmc_spi_driver); +} +module_exit(mmc_spi_exit); + + +MODULE_AUTHOR("Mike Lavender, David Brownell, " + "Hans-Peter Nilsson, Jan Nikitenko"); +MODULE_DESCRIPTION("SPI SD/MMC host driver"); +MODULE_LICENSE("GPL"); ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707141508.07555.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <200707141508.07555.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-26 18:02 ` Pierre Ossman [not found] ` <20070726200202.5e5dcf62-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-07-26 18:02 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Sat, 14 Jul 2007 15:08:06 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > --- g26.orig/drivers/mmc/host/Kconfig 2007-07-14 14:47:11.000000000 -0700 > +++ g26/drivers/mmc/host/Kconfig 2007-07-14 14:47:57.000000000 -0700 > @@ -100,3 +100,16 @@ config MMC_TIFM_SD > To compile this driver as a module, choose M here: the > module will be called tifm_sd. > > +config MMC_SPI > + tristate "MMC/SD over SPI" > + depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL > + select CRC7 > + select CRC_ITU_T > + help > + Some systems accss MMC/SD cards using a SPI controller instead of > + using a "native" MMC/SD controller. This has a disadvantage of > + being relatively high overhead, but a compensating advantage of > + working on many systems without dedicated MMC/SD controllers. > + > + If unsure, or if your system has no SPI master driver, say N. > + It is customary to have "(Experimental)" in the description aswell. > + > +static int > +mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) > +{ > + int status; > + > + if (len > sizeof *host->data) { > + WARN_ON(1); > + return -EIO; > + } sizeof without parenthesis? Heathen! > + > +/* > + * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol > + * hosts return! The low byte holds R1_SPI bits. The next byte may hold > + * R2_SPI bits ... for SEND_STATUS, or after data read errors. > + * > + * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on > + * newer cards R7 (IF_COND). > + */ > + > +static char *maptype(struct mmc_command *cmd) > +{ > + switch (mmc_spi_resp_type(cmd)) { > + case MMC_RSP_SPI_R1: return "R1"; > + case MMC_RSP_SPI_R1B: return "R1B"; > + case MMC_RSP_SPI_R2: return "R2"; > + case MMC_RSP_SPI_R3: return "R3/R7"; > + default: return "?"; > + } > +} > + I'm trying to move all generic debugging code into the core, so I would prefer if you would have a look at extending that to fit your needs. That way everyone wins. > + > + /* Status byte: the entire seven-bit R1 response. */ > + if (cmd->resp[0] != 0) { > + if (R1_SPI_COM_CRC & cmd->resp[0]) { > + cmd->error = MMC_ERR_BADCRC; > + value = -EILSEQ; > + } else if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS > + | R1_SPI_ILLEGAL_COMMAND) > + & cmd->resp[0]) { > + cmd->error = MMC_ERR_INVALID; > + value = -EINVAL; > + } else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) > + & cmd->resp[0]) { > + cmd->error = MMC_ERR_FAILED; > + value = -EINVAL; > + } /* else R1_SPI_IDLE, "it's resetting" */ > + > + if (value < 0) > + goto fail; > + } I'd still preferred that you'd didn't try to decode this here. And your code demostrates why; CRC error and illegal command both signal problems with the previous command, not the current one, so this code would be failing the wrong request. > + > + switch (mmc_spi_resp_type(cmd)) { > + > + /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads) > + * and less-common stuff like various erase operations. > + */ > + case MMC_RSP_SPI_R1B: for (i = 0;i < mmc_spi_resp_size(cmd);i++) cmd->resp[i/4] |= *cp++ << (24 - (i % 4) * 8); if (cmd->flags & MMC_SPI_RSP_BUSY) mmc_spi_wait_unbusy(); That's the whole point of hacking up the response types into components, so that the host driver doesn't have to care. You can keep your design if you'd like, but I really think this is cleaner and more layered. > + > + /* We can handle most commands (except block reads) in one full > + * duplex I/O operation before either starting the next transfer > + * (data block or command) or else deselecting the card. > + * > + * First, write 7 bytes: > + * - an all-ones byte to ensure the card is ready > + * - opcode byte (plus start and transmission bits) > + * - four bytes of big-endian argument > + * - crc7 (plus end bit) ... always computed, it's cheap > + * I thought your argument against always using crc7 was that it wasn't cheap? Colour me confused. > + if (status == -EILSEQ) > + data->error = MMC_ERR_BADCRC; > + else if (status == -ETIMEDOUT) > + data->error = MMC_ERR_TIMEOUT; > + else if (status == -EINVAL) > + data->error = MMC_ERR_INVALID; > + else if (data->error == MMC_ERR_NONE) > + data->error = MMC_ERR_FAILED; > + break; > + } At least we agree on error codes. This is precisely the change I have pending in my patch set to remove the MMC_ERR_* mess. :) There are a few outstanding issues, but they are really minor so this could very soon get into my -mm branch. I need a MAINTAINERS entry aswell. I'd like to see those REVISIT things attended to before I push the stuff to Linus though. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070726200202.5e5dcf62-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <20070726200202.5e5dcf62-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-07-26 23:32 ` David Brownell [not found] ` <200707261632.37011.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-26 23:32 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 26 July 2007, Pierre Ossman wrote: > On Sat, 14 Jul 2007 15:08:06 -0700 > David Brownell <david-b@pacbell.net> wrote: > > > --- g26.orig/drivers/mmc/host/Kconfig 2007-07-14 14:47:11.000000000 -0700 > > +++ g26/drivers/mmc/host/Kconfig 2007-07-14 14:47:57.000000000 -0700 > > @@ -100,3 +100,16 @@ config MMC_TIFM_SD > > To compile this driver as a module, choose M here: the > > module will be called tifm_sd. > > > > +config MMC_SPI > > + tristate "MMC/SD over SPI" > > + depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL > > ... > > It is customary to have "(Experimental)" in the description aswell. OK ... actually "(EXPERIMENTAL)" shouting it to the rooftops. > > +static int > > +mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) > > +{ > > + int status; > > + > > + if (len > sizeof *host->data) { > > + WARN_ON(1); > > + return -EIO; > > + } > > sizeof without parenthesis? Heathen! Most style guides I've used say to do it that way; it's not a function call! It should now meet your pagan mores. > > +static char *maptype(struct mmc_command *cmd) > > +{ > > + switch (mmc_spi_resp_type(cmd)) { > > + case MMC_RSP_SPI_R1: return "R1"; > > + case MMC_RSP_SPI_R1B: return "R1B"; > > + case MMC_RSP_SPI_R2: return "R2"; > > + case MMC_RSP_SPI_R3: return "R3/R7"; > > + default: return "?"; > > + } > > +} > > + > > I'm trying to move all generic debugging code into the core, > so I would prefer if you would have a look at extending that > to fit your needs. That way everyone wins. That's not generic, it's driver-specific. :) If anything comes to mind, I'll see about doing that. In that case I'd as soon have the thing compile itself completely out of the picture on non-debug builds... > > + > > + /* Status byte: the entire seven-bit R1 response. */ > > + if (cmd->resp[0] != 0) { > > + if (R1_SPI_COM_CRC & cmd->resp[0]) { > > + cmd->error = MMC_ERR_BADCRC; > > + value = -EILSEQ; > > + } else if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS > > + | R1_SPI_ILLEGAL_COMMAND) > > + & cmd->resp[0]) { > > + cmd->error = MMC_ERR_INVALID; > > + value = -EINVAL; > > + } else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) > > + & cmd->resp[0]) { > > + cmd->error = MMC_ERR_FAILED; > > + value = -EINVAL; > > + } /* else R1_SPI_IDLE, "it's resetting" */ > > + > > + if (value < 0) > > + goto fail; > > + } > > I'd still preferred that you'd didn't try to decode this here. You said you weren't going to update the MMC core to check the status bits after every request, and I'm certainly not about to change *EVERY MMC/SD REQUEST* to adopt a radically different callling convention either!! Which leaves us needing a solution that actually works, and this seems to be the only option: continue to use the current calling convention, ->error fields report the failures. > And your code demostrates why; CRC error and illegal command > both signal problems with the previous command, not the current > one, so this code would be failing the wrong request. Not according to any docs I've got. Both of those are 'R' mode fault reports. My previous reply quoted the relevant text: When an error bit is detected in “R” mode the card will report the error in the response to the command that raised the exception. The command will not be executed and the associated state transition will not take place. Note: ** "in the response to the command that raised the exception" ** ... no mention of any delay. You're talking as if these were type "X" instead! > > > + > > + switch (mmc_spi_resp_type(cmd)) { > > + > > + /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads) > > + * and less-common stuff like various erase operations. > > + */ > > + case MMC_RSP_SPI_R1B: > > for (i = 0;i < mmc_spi_resp_size(cmd);i++) > cmd->resp[i/4] |= *cp++ << (24 - (i % 4) * 8); The test for the new MMC_SPI_RSP_BUSY could be done; I won't do it for now since it'd just take more time to finish this stuff. > if (cmd->flags & MMC_SPI_RSP_BUSY) > mmc_spi_wait_unbusy(); However, that bit looks deeply messy. You'd be splitting the OCR (and other SPI four byte responses) into two different words, for example! Or to put it differently, this way the structure that's passed up to the core is actually meaningful: one word of status, and maybe another word of data. And *never* any mixed status/data words that'd need disentangling. After all, if you really wanted to provide raw protocol data to the mmc core, cmd->resp[] would be bytes, not 32-bit words in cpu-order. > That's the whole point of hacking up the response types into > components, so that the host driver doesn't have to care. > > You can keep your design if you'd like, but I really think > this is cleaner and more layered. I guess we'll have to disagree on this for now. If it matters, it can be changed later; but I certainly couldn't call mixing data and status as an improvement!! > > + > > + /* We can handle most commands (except block reads) in one full > > + * duplex I/O operation before either starting the next transfer > > + * (data block or command) or else deselecting the card. > > + * > > + * First, write 7 bytes: > > + * - an all-ones byte to ensure the card is ready > > + * - opcode byte (plus start and transmission bits) > > + * - four bytes of big-endian argument > > + * - crc7 (plus end bit) ... always computed, it's cheap > > + * > > I thought your argument against always using crc7 was that it > wasn't cheap? Colour me confused. The data block CRC is quite expensive, yes. The CRC7 isn't; and in any case, you had pretty much demanded that it always be computed (to eliminate the #define for the crc needed in the card reset command) ... > > + if (status == -EILSEQ) > > + data->error = MMC_ERR_BADCRC; > > + else if (status == -ETIMEDOUT) > > + data->error = MMC_ERR_TIMEOUT; > > + else if (status == -EINVAL) > > + data->error = MMC_ERR_INVALID; > > + else if (data->error == MMC_ERR_NONE) > > + data->error = MMC_ERR_FAILED; > > + break; > > + } > > At least we agree on error codes. This is precisely the change > I have pending in my patch set to remove the MMC_ERR_* mess. :) I had to pick something. ;) > There are a few outstanding issues, but they are really minor so > this could very soon get into my -mm branch. Appended is a version of the mmc_spi patch with most of the issues above addressed. I'll be glad to see this get into your MM branch ... that'll mean it can more easily get to the people who will use it, and who will start shaking out the next set of issues. > I need a MAINTAINERS entry aswell. I was hoping someone would sign up for that, so I don't have to stick myself there with "Odd fixes" status... > I'd like to see those REVISIT things attended to before I push > the stuff to Linus though. In this driver? They're mostly performance tuning issues, which are normally best left till later: - Using msleep -- usleep? -- to avoid some busy-waiting. That's got to be done with caution, since it can slow things down and since card timings are all over the map. Given working HRT this should be practical. - Eliminating byte-at-a-time reads on the RX block paths, probably using some kind of bounce buffer scheme. Needs some investigation; maybe your new bouncebuffer stuff ought to help out... - Double checking that another device doesn't get added to the bus ... that's easy enough to do. (Lurking there is the need for a new SPI primitive, too.) - dma_map_single() operations could theoretically fail. Not that it'd be likely on hardware that uses this driver; but that's simple error path cleanup. More significant are the two FIXMEs related to card reset. One will require someone with relevant hardware (Jan?), the other still needs investigation. - Dave ============== CUT HERE This is the latest version of the MMC-over-SPI support. It works on 2.6.23-rc1-git, along with the preceding patches which teach the rest of the MMC stack about SPI so that this host driver can focus on doing only lowlevel SPI-specific stuff, and add CRC7 support. It's been lightly tested on MMC and SD cards, reading and writing ext3 filesystems (including fsck). This includes CRC mode, which is now enabled by default. The main issue of note is that sometimes cards need to be power cycled to recover after certain faults. In some cases, it may be necessary to disable CRCs. ("modprobe mmc_core use_spi_crc=n") Changes from previous versions include more code shrinkage and cleanup, reducing the number of I/O requests needed per operation, and moving even more nuances into the MMC core code. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: mikael.starvik@axis.com, Cc: Hans-Peter Nilsson <hp@axis.com> Cc: Jan Nikitenko <jan.nikitenko@gmail.com> Cc: Mike Lavender <mike@steroidmicros.com> --- drivers/mmc/host/Kconfig | 13 drivers/mmc/host/Makefile | 1 drivers/mmc/host/mmc_spi.c | 1416 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/spi/mmc_spi.h | 33 + 4 files changed, 1463 insertions(+) --- avr.orig/drivers/mmc/host/Kconfig 2007-07-25 22:06:46.000000000 -0700 +++ avr/drivers/mmc/host/Kconfig 2007-07-26 15:23:20.000000000 -0700 @@ -100,3 +100,16 @@ config MMC_TIFM_SD To compile this driver as a module, choose M here: the module will be called tifm_sd. +config MMC_SPI + tristate "MMC/SD over SPI (EXPERIMENTAL)" + depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL + select CRC7 + select CRC_ITU_T + help + Some systems accss MMC/SD cards using a SPI controller instead of + using a "native" MMC/SD controller. This has a disadvantage of + being relatively high overhead, but a compensating advantage of + working on many systems without dedicated MMC/SD controllers. + + If unsure, or if your system has no SPI master driver, say N. + --- avr.orig/drivers/mmc/host/Makefile 2007-07-25 22:06:46.000000000 -0700 +++ avr/drivers/mmc/host/Makefile 2007-07-25 22:19:58.000000000 -0700 @@ -15,4 +15,5 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91) += at91_mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o +obj-$(CONFIG_MMC_SPI) += mmc_spi.o --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ avr/include/linux/spi/mmc_spi.h 2007-07-25 22:19:58.000000000 -0700 @@ -0,0 +1,33 @@ +#ifndef __LINUX_SPI_MMC_SPI_H +#define __LINUX_SPI_MMC_SPI_H + +struct device; +struct mmc_host; + +/* Put this in platform_data of a device being used to manage an MMC/SD + * card slot. (Modeled after PXA mmc glue; see that for usage examples.) + * + * REVISIT This is not a spi-specific notion. Any card slot should be + * able to handle it. If the MMC core doesn't adopt this kind of notion, + * switch the "struct device *" parameters over to "struct spi_device *". + */ +struct mmc_spi_platform_data { + /* driver activation and (optional) card detect irq hookup */ + int (*init)(struct device *, + irqreturn_t (*)(int, void *), + void *); + void (*exit)(struct device *, void *); + + /* sense switch on sd cards */ + int (*get_ro)(struct device *); + + /* how long to debounce card detect, in msecs */ + u16 detect_delay; + + /* power management */ + u16 powerup_msecs; /* delay of up to 250 msec */ + u32 ocr_mask; /* available voltages */ + void (*setpower)(struct device *, unsigned int maskval); +}; + +#endif /* __LINUX_SPI_MMC_SPI_H */ --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ avr/drivers/mmc/host/mmc_spi.c 2007-07-26 15:26:27.000000000 -0700 @@ -0,0 +1,1416 @@ +/* + * mmc_spi.c - Access SD/MMC cards through SPI master controllers + * + * (C) Copyright 2005, Intec Automation, + * Mike Lavender (mike@steroidmicros) + * (C) Copyright 2006-2007, David Brownell + * (C) Copyright 2007, Axis Communications, + * Hans-Peter Nilsson (hp@axis.com) + * (C) Copyright 2007, ATRON electronic GmbH, + * Jan Nikitenko <jan.nikitenko@gmail.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/hrtimer.h> +#include <linux/delay.h> +#include <linux/blkdev.h> +#include <linux/dma-mapping.h> +#include <linux/crc7.h> +#include <linux/crc-itu-t.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */ + +#include <linux/spi/spi.h> +#include <linux/spi/mmc_spi.h> + +#include <asm/unaligned.h> + + +/* NOTES: + * + * - For now, we won't try to interoperate with a real mmc/sd/sdio + * controller, although some of them do have hardware support for + * SPI protocol. The main reason for such configs would be mmc-ish + * cards like DataFlash, which don't support that "native" protocol. + * + * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to + * switch between driver stacks, and in any case if "native" mode + * is available, it will be faster and hence preferable. + * + * - MMC depends on a different chipselect management policy than the + * SPI interface currently supports for shared bus segments: it needs + * to issue multiple spi_message requests with the chipselect active, + * using the results of one message to decide the next one to issue. + * + * Pending updates to the programming interface, this driver insists + * that it not share the bus with other drivers (preventing conflicts). + * + * - We tell the controller to keep the chipselect active from the + * beginning of an mmc_host_ops.request until the end. So beware + * of SPI controller drivers that mis-handle the cs_change flag! + * + * However, many cards seem OK with chipselect flapping up/down + * during that time ... at least on unshared bus segments. + */ + + +/* + * Local protocol constants, internal to data block protocols. + */ + +/* Response tokens used to ack each block written: */ +#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) +#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1) +#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1) +#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1) + +/* Read and write blocks start with these tokens and end with crc; + * on error, read tokens act like a subset of R2_SPI_* values. + */ +#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ +#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ +#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ + +#define MMC_SPI_BLOCKSIZE 512 + + +/* These fixed timeouts come from the latest SD specs, which say to ignore + * the CSD values. The R1B value is for card erase (e.g. the "I forgot the + * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after + * reads which takes nowhere near that long. Older cards may be able to use + * shorter timeouts ... but why bother? + */ +#define readblock_timeout ktime_set(0, 100 * 1000 * 1000) +#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000) +#define r1b_timeout ktime_set(3, 0) + + +/****************************************************************************/ + +/* + * Local Data Structures + */ + +/* "scratch" is per-{command,block} data exchanged with the card */ +struct scratch { + u8 status[29]; + u8 data_token; + __be16 crc_val; +}; + +struct mmc_spi_host { + struct mmc_host *mmc; + struct spi_device *spi; + + unsigned char power_mode; + u16 powerup_msecs; + + struct mmc_spi_platform_data *pdata; + + /* for bulk data transfers */ + struct spi_transfer token, t, crc, early_status; + struct spi_message m; + + /* for status readback */ + struct spi_transfer status; + struct spi_message readback; + + /* underlying DMA-aware controller, or null */ + struct device *dma_dev; + + /* buffer used for commands and for message "overhead" */ + struct scratch *data; + dma_addr_t data_dma; + + /* Specs say to write ones most of the time, even when the card + * has no need to read its input data; and many cards won't care. + * This is our source of those ones. + */ + void *ones; + dma_addr_t ones_dma; +}; + + +/****************************************************************************/ + +/* + * MMC-over-SPI protocol glue, used by the MMC stack interface + */ + +static inline int mmc_cs_off(struct mmc_spi_host *host) +{ + /* chipselect will always be inactive after setup() */ + return spi_setup(host->spi); +} + +static int +mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) +{ + int status; + + if (len > sizeof(*host->data)) { + WARN_ON(1); + return -EIO; + } + + host->status.len = len; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_FROM_DEVICE); + + status = spi_sync(host->spi, &host->readback); + if (status == 0) + status = host->readback.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_FROM_DEVICE); + + return status; +} + +static int +mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) +{ + u8 *cp = host->data->status; + + timeout = ktime_add(timeout, ktime_get()); + + while (1) { + int status; + unsigned i; + + status = mmc_spi_readbytes(host, n); + if (status < 0) + return status; + + for (i = 0; i < n; i++) { + if (cp[i] != byte) + return cp[i]; + } + + /* REVISIT investigate msleep() to avoid busy-wait I/O + * in at least some cases. + */ + if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0) + break; + } + return -ETIMEDOUT; +} + +static inline int +mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout) +{ + return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0); +} + +static int mmc_spi_readtoken(struct mmc_spi_host *host) +{ + return mmc_spi_skip(host, readblock_timeout, 1, 0xff); +} + + +/* + * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol + * hosts return! The low byte holds R1_SPI bits. The next byte may hold + * R2_SPI bits ... for SEND_STATUS, or after data read errors. + * + * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on + * newer cards R7 (IF_COND). + */ + +static char *maptype(struct mmc_command *cmd) +{ + switch (mmc_spi_resp_type(cmd)) { + case MMC_RSP_SPI_R1: return "R1"; + case MMC_RSP_SPI_R1B: return "R1B"; + case MMC_RSP_SPI_R2: return "R2"; + case MMC_RSP_SPI_R3: return "R3/R7"; + default: return "?"; + } +} + +/* return zero, else negative errno after setting cmd->error */ +static int mmc_spi_response_get(struct mmc_spi_host *host, + struct mmc_command *cmd, int cs_on) +{ + u8 *cp = host->data->status; + u8 *end = cp + host->t.len; + int value = 0; + char tag[32]; + + snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s", + cmd->opcode, maptype(cmd)); + + /* Except for data block reads, the whole response will already + * be stored in the scratch buffer. It's somewhere after the + * command and the first byte we read after it. We ignore that + * first byte. After STOP_TRANSMISSION command it may include + * two data bits, but otherwise it's all ones. + */ + cp += 8; + while (cp < end && *cp == 0xff) + cp++; + + /* Data block reads (R1 response types) may need more data... */ + if (cp == end) { + unsigned i; + + cp = host->data->status; + + /* Card sends N(CR) (== 1..8) bytes of all-ones then one + * status byte ... and we already scanned 2 bytes. + * + * REVISIT block read paths use nasty byte-at-a-time I/O + * so it can always DMA directly into the target buffer. + * It'd probably be better to memcpy() the first chunk and + * avoid extra i/o calls... + */ + for (i = 2; i < 9; i++) { + value = mmc_spi_readbytes(host, 1); + if (value < 0) { + cmd->error = MMC_ERR_FAILED; + goto done; + } + if (*cp != 0xff) + goto checkstatus; + } + value = -ETIMEDOUT; + cmd->error = MMC_ERR_TIMEOUT; + goto done; + } + +checkstatus: + if (*cp & 0x80) { + dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n", + tag, *cp); + cmd->error = MMC_ERR_FAILED; + value = -EBADR; + goto done; + } + + cmd->resp[0] = *cp++; + cmd->error = MMC_ERR_NONE; + + /* Status byte: the entire seven-bit R1 response. */ + if (cmd->resp[0] != 0) { + if (R1_SPI_COM_CRC & cmd->resp[0]) { + cmd->error = MMC_ERR_BADCRC; + value = -EILSEQ; + } else if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS + | R1_SPI_ILLEGAL_COMMAND) + & cmd->resp[0]) { + cmd->error = MMC_ERR_INVALID; + value = -EINVAL; + } else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) + & cmd->resp[0]) { + cmd->error = MMC_ERR_FAILED; + value = -EINVAL; + } /* else R1_SPI_IDLE, "it's resetting" */ + + if (value < 0) + goto fail; + } + + switch (mmc_spi_resp_type(cmd)) { + + /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads) + * and less-common stuff like various erase operations. + */ + case MMC_RSP_SPI_R1B: + /* maybe we read all the busy tokens already */ + while (cp < end && *cp == 0) + cp++; + if (cp == end) + mmc_spi_wait_unbusy(host, r1b_timeout); + break; + + /* SPI R2 == R1 + second status byte; SEND_STATUS */ + case MMC_RSP_SPI_R2: + cmd->resp[0] |= *cp << 8; + break; + + /* SPI R3 or R7 == R1 + 4 bytes */ + case MMC_RSP_SPI_R3: + cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp)); + break; + + /* SPI R1 == just one status byte */ + case MMC_RSP_SPI_R1: + break; + + default: + dev_dbg(&host->spi->dev, "bad response type %04x\n", + mmc_spi_resp_type(cmd)); + if (value >= 0) { + cmd->error = MMC_ERR_INVALID; + value = -EINVAL; + } + } + +fail: + if (value < 0) + dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n", + tag, cmd->resp[0], cmd->resp[1]); + + /* disable chipselect on errors and some success cases */ + if (value >= 0 && cs_on) + return value; +done: + mmc_cs_off(host); + return value; +} + +/* Issue command and read its response. + * Returns zero on success, negative for error. + * + * On error, caller must cope with mmc core retry mechanism. That + * means immediate low-level resubmit, which affects the bus lock... + */ +static int +mmc_spi_command_send(struct mmc_spi_host *host, + struct mmc_request *mrq, + struct mmc_command *cmd, int cs_on) +{ + struct scratch *data = host->data; + u8 *cp = data->status; + u32 arg = cmd->arg; + int status; + struct spi_transfer *t; + + /* We can handle most commands (except block reads) in one full + * duplex I/O operation before either starting the next transfer + * (data block or command) or else deselecting the card. + * + * First, write 7 bytes: + * - an all-ones byte to ensure the card is ready + * - opcode byte (plus start and transmission bits) + * - four bytes of big-endian argument + * - crc7 (plus end bit) ... always computed, it's cheap + * + * We init the whole buffer to all-ones, which is what we need + * to write while we're reading (later) response data. + */ + memset(cp++, 0xff, sizeof(data->status)); + + *cp++ = 0x40 | cmd->opcode; + *cp++ = (u8)(arg >> 24); + *cp++ = (u8)(arg >> 16); + *cp++ = (u8)(arg >> 8); + *cp++ = (u8)arg; + *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01; + + /* Then, read up to 13 bytes (while writing all-ones): + * - N(CR) (== 1..8) bytes of all-ones + * - status byte (for all response types) + * - the rest of the response, either: + * + nothing, for R1 or R1B responses + * + second status byte, for R2 responses + * + four data bytes, for R3 and R7 responses + * + * Finally, read some more bytes ... in the nice cases we know in + * advance how many, and reading 1 more is always OK: + * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish + * - N(RC) (== 1..N) bytes of all-ones, before next command + * - N(WR) (== 1..N) bytes of all-ones, before data write + * + * So in those cases one full duplex I/O of at most 21 bytes will + * handle the whole command, leaving the card ready to receive a + * data block or new command. We do that whenever we can, shaving + * CPU and IRQ costs (especially when using DMA or FIFOs). + * + * There are two other cases, where it's not generally practical + * to rely on a single I/O: + * + * - R1B responses need at least N(EC) bytes of all-zeroes. + * + * In this case we can *try* to fit it into one I/O, then + * maybe read more data later. + * + * - Data block reads are more troublesome, since a variable + * number of padding bytes precede the token and data. + * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID + * + N(AC) (== 1..many) bytes of all-ones + * + * In this case we currently only have minimal speedups here: + * when N(CR) == 1 we can avoid I/O in response_get(). + */ + if (cs_on && (mrq->data->flags & MMC_DATA_READ)) { + cp += 2; /* min(N(CR)) + status */ + /* R1 */ + } else { + cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */ + if (cmd->flags & MMC_RSP_SPI_S2) /* R2 */ + cp++; + else if (cmd->flags & MMC_RSP_SPI_B4) /* R3, R7 */ + cp += 4; + else if (cmd->flags & MMC_RSP_BUSY) /* R1B */ + cp = data->status + sizeof(data->status); + /* else: R1 (most commands) */ + } + + dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, MMC_SPI_%s\n", + cmd->opcode, maptype(cmd)); + + /* send command, leaving chipselect active */ + spi_message_init(&host->m); + + t = &host->t; + memset(t, 0, sizeof(*t)); + t->tx_buf = t->rx_buf = data->status; + t->tx_dma = t->rx_dma = host->data_dma; + t->len = cp - data->status; + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + + if (host->dma_dev) { + host->m.is_dma_mapped = 1; + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + } + status = spi_sync(host->spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + if (status < 0) { + dev_dbg(&host->spi->dev, " ... write returned %d\n", status); + cmd->error = MMC_ERR_FAILED; + return status; + } + + /* after no-data commands and STOP_TRANSMISSION, chipselect off */ + return mmc_spi_response_get(host, cmd, cs_on); +} + +/* Build data message with up to four separate transfers. For TX, we + * start by writing the data token. And in most cases, we finish with + * a status transfer. + * + * We always provide TX data for data and CRC. The MMC/SD protocol + * requires us to write ones; but Linux defaults to writing zeroes; + * so we explicitly initialize it to all ones on RX paths. + * + * We also handle DMA mapping, so the underlying SPI controller does + * not need to (re)do it for each message. + */ +static void +mmc_spi_setup_data_message( + struct mmc_spi_host *host, + int multiple, + enum dma_data_direction direction) +{ + struct spi_transfer *t; + struct scratch *scratch = host->data; + dma_addr_t dma = host->data_dma; + + spi_message_init(&host->m); + if (dma) + host->m.is_dma_mapped = 1; + + /* for reads, readblock() skips 0xff bytes before finding + * the token; for writes, this transfer issues that token. + */ + if (direction == DMA_TO_DEVICE) { + t = &host->token; + memset(t, 0, sizeof(*t)); + t->len = 1; + if (multiple) + scratch->data_token = SPI_TOKEN_MULTI_WRITE; + else + scratch->data_token = SPI_TOKEN_SINGLE; + t->tx_buf = &scratch->data_token; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, data_token); + spi_message_add_tail(t, &host->m); + } + + /* Body of transfer is buffer, then CRC ... + * either TX-only, or RX with TX-ones. + */ + t = &host->t; + memset(t, 0, sizeof(*t)); + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + /* length and actual buffer info are written later */ + spi_message_add_tail(t, &host->m); + + t = &host->crc; + memset(t, 0, sizeof(*t)); + t->len = 2; + if (direction == DMA_TO_DEVICE) { + /* the actual CRC may get written later */ + t->tx_buf = &scratch->crc_val; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, crc_val); + } else { + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = &scratch->crc_val; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, crc_val); + } + spi_message_add_tail(t, &host->m); + + /* + * A single block read is followed by N(EC) [0+] all-ones bytes + * before deselect ... don't bother. + * + * Multiblock reads are followed by N(AC) [1+] all-ones bytes before + * the next block is read, or a STOP_TRANSMISSION is issued. We'll + * collect that single byte, so readblock() doesn't need to. + * + * For a write, the one-byte data response follows immediately, then + * come zero or more busy bytes, then N(WR) [1+] all-ones bytes. + * Then single block reads may deselect, and multiblock ones issue + * the next token (next data block, or STOP_TRAN). We can try to + * minimize I/O ops by using a single read to collect end-of-busy. + */ + if (multiple || direction == DMA_TO_DEVICE) { + t = &host->early_status; + memset(t, 0, sizeof(*t)); + t->len = (direction == DMA_TO_DEVICE) + ? sizeof(scratch->status) + : 1; + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = scratch->status; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, status); + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + } +} + +/* + * Write one block: + * - caller handled preceding N(WR) [1+] all-ones bytes + * - data block + * + token + * + data bytes + * + crc16 + * - an all-ones byte ... card writes a data-response byte + * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy' + * + * Return negative errno, else success. + */ +static int +mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status, i; + struct scratch *scratch = host->data; + + if (host->mmc->use_spi_crc) + scratch->crc_val = cpu_to_be16( + crc_itu_t(0, t->tx_buf, t->len)); + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (status != 0) { + dev_dbg(&spi->dev, "write error (%d)\n", status); + return status; + } + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + /* + * Get the transmission data-response reply. It must follow + * immediately after the data block we transferred. This reply + * doesn't necessarily tell whether the write operation succeeded; + * it just says if the transmission was ok and whether *earlier* + * writes succeeded; see the standard. + */ + switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) { + case SPI_RESPONSE_ACCEPTED: + status = 0; + break; + case SPI_RESPONSE_CRC_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION */ + status = -EILSEQ; + break; + case SPI_RESPONSE_WRITE_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION, + * and should MMC_SEND_STATUS to sort it out + */ + status = -EIO; + break; + default: + status = -EPROTO; + break; + } + if (status != 0) { + dev_dbg(&spi->dev, "write error %02x (%d)\n", + scratch->status[0], status); + return status; + } + + t->tx_buf += t->len; + if (host->dma_dev) + t->tx_dma += t->len; + + /* Return when not busy. If we didn't collect that status yet, + * we'll need some more I/O. + */ + for (i = 1; i < sizeof(scratch->status); i++) { + if (scratch->status[i] != 0) + return 0; + } + return mmc_spi_wait_unbusy(host, writeblock_timeout); +} + +/* + * Read one block: + * - skip leading all-ones bytes ... either + * + N(AC) [1..f(clock,CSD)] usually, else + * + N(CX) [0..8] when reading CSD or CID + * - data block + * + token ... if error token, no data or crc + * + data bytes + * + crc16 + * + * After single block reads, we're done; N(EC) [0+] all-ones bytes follow + * before dropping chipselect. + * + * For multiblock reads, caller either reads the next block or issues a + * STOP_TRANSMISSION command. + */ +static int +mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status; + struct scratch *scratch = host->data; + + /* At least one SD card sends an all-zeroes byte when N(CX) + * applies, before the all-ones bytes ... just cope with that. + */ + status = mmc_spi_readbytes(host, 1); + if (status < 0) + return status; + status = scratch->status[0]; + if (status == 0xff || status == 0) + status = mmc_spi_readtoken(host); + + if (status == SPI_TOKEN_SINGLE) { + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + } else { + dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); + + /* we've read extra garbage, timed out, etc */ + if (status < 0) + return status; + + /* low four bits are an R2 subset, fifth seems to be + * vendor specific ... map them all to generic error.. + */ + return -EIO; + } + + if (host->mmc->use_spi_crc) { + u16 crc = crc_itu_t(0, t->rx_buf, t->len); + + be16_to_cpus(&scratch->crc_val); + if (scratch->crc_val != crc) { + dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " + "computed=0x%04x len=%d\n", + scratch->crc_val, crc, t->len); + return -EILSEQ; + } + } + + t->rx_buf += t->len; + if (host->dma_dev) + t->rx_dma += t->len; + + return 0; +} + +/* + * An MMC/SD data stage includes one or more blocks, optional CRCs, + * and inline handshaking. That handhaking makes it unlike most + * other SPI protocol stacks. + */ +static void +mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, + struct mmc_data *data, u32 blk_size) +{ + struct spi_device *spi = host->spi; + struct device *dma_dev = host->dma_dev; + struct spi_transfer *t; + enum dma_data_direction direction; + struct scatterlist *sg; + unsigned n_sg; + int multiple = (data->blocks > 1); + + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + mmc_spi_setup_data_message(host, multiple, direction); + t = &host->t; + + /* Handle scatterlist segments one at a time, with synch for + * each 512-byte block + */ + for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) { + int status = 0; + dma_addr_t dma_addr = 0; + void *kmap_addr; + unsigned length = sg->length; + + /* set up dma mapping for controller drivers that might + * use DMA ... though they may fall back to PIO + */ + if (dma_dev) { + dma_addr = dma_map_page(dma_dev, sg->page, 0, + PAGE_SIZE, direction); + if (direction == DMA_TO_DEVICE) + t->tx_dma = dma_addr + sg->offset; + else + t->rx_dma = dma_addr + sg->offset; + } + + /* allow pio too; we don't allow highmem */ + kmap_addr = kmap(sg->page); + if (direction == DMA_TO_DEVICE) + t->tx_buf = kmap_addr + sg->offset; + else + t->rx_buf = kmap_addr + sg->offset; + + /* transfer each block, and update request status */ + while (length) { + t->len = min(length, blk_size); + + dev_dbg(&host->spi->dev, + " mmc_spi: %s block, %d bytes\n", + (direction == DMA_TO_DEVICE) + ? "write" + : "read", + t->len); + + if (direction == DMA_TO_DEVICE) + status = mmc_spi_writeblock(host, t); + else + status = mmc_spi_readblock(host, t); + if (status < 0) + break; + + data->bytes_xfered += t->len; + length -= t->len; + + if (!multiple) + break; + } + + /* discard mappings */ + if (direction == DMA_FROM_DEVICE) + flush_kernel_dcache_page(sg->page); + kunmap(sg->page); + if (dma_dev) + dma_unmap_page(dma_dev, dma_addr, + PAGE_SIZE, direction); + + if (status < 0) { + dev_dbg(&spi->dev, "%s status %d\n", + (direction == DMA_TO_DEVICE) + ? "write" : "read", + status); + if (status == -EILSEQ) + data->error = MMC_ERR_BADCRC; + else if (status == -ETIMEDOUT) + data->error = MMC_ERR_TIMEOUT; + else if (status == -EINVAL) + data->error = MMC_ERR_INVALID; + else if (data->error == MMC_ERR_NONE) + data->error = MMC_ERR_FAILED; + break; + } + } + + /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that + * can be issued before multiblock writes. Unlike its more widely + * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23), + * that can affect the STOP_TRAN logic. Complete (and current) + * MMC specs should sort that out before Linux starts using CMD23. + */ + if (direction == DMA_TO_DEVICE && multiple) { + struct scratch *scratch = host->data; + int tmp; + const unsigned statlen = sizeof(scratch->status); + + dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n"); + + /* Tweak the per-block message we set up earlier by morphing + * it to hold single buffer with the token followed by some + * all-ones bytes ... skip N(BR) (0..1), scan the rest for + * "not busy any longer" status, and leave chip selected. + */ + INIT_LIST_HEAD(&host->m.transfers); + list_add(&host->early_status.transfer_list, + &host->m.transfers); + + scratch->status[0] = SPI_TOKEN_STOP_TRAN; + memset(scratch->status + 1, 0xff, statlen - 1); + host->early_status.tx_buf = host->early_status.rx_buf; + host->early_status.tx_dma = host->early_status.rx_dma; + host->early_status.len = 1 + statlen; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + tmp = spi_sync(spi, &host->m); + if (tmp == 0) + tmp = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + if (tmp < 0) { + if (data->error == MMC_ERR_NONE) + data->error = MMC_ERR_FAILED; + return; + } + + /* Ideally we collected "not busy" status with one I/O, + * avoiding wasteful byte-at-a-time scanning... but more + * I/O is often needed. + */ + for (tmp = 2; tmp < statlen; tmp++) { + if (scratch->status[tmp] != 0) + return; + } + tmp = mmc_spi_wait_unbusy(host, writeblock_timeout); + if (tmp < 0 && data->error == MMC_ERR_NONE) { + if (tmp == -ETIMEDOUT) + data->error = MMC_ERR_TIMEOUT; + else + data->error = MMC_ERR_FAILED; + } + } +} + +/****************************************************************************/ + +/* + * MMC driver implementation -- the interface to the MMC stack + */ + +static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + int status = -EINVAL; + +#ifdef DEBUG + /* MMC core and layered drivers *MUST* issue SPI-aware commands */ + { + struct mmc_command *cmd; + int invalid = 0; + + cmd = mrq->cmd; + if (!mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus command\n"); + cmd->error = MMC_ERR_INVALID; + invalid = 1; + } + + cmd = mrq->stop; + if (cmd && !mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus STOP command\n"); + cmd->error = MMC_ERR_INVALID; + invalid = 1; + } + + if (invalid) { + dump_stack(); + mmc_request_done(host->mmc, mrq); + return; + } + } +#endif + + /* issue command; then optionally data and stop */ + status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL); + if (status == 0 && mrq->data) { + mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz); + if (mrq->stop) + status = mmc_spi_command_send(host, mrq, mrq->stop, 0); + else + mmc_cs_off(host); + } + + mmc_request_done(host->mmc, mrq); +} + +/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0" + * + * NOTE that here we can't know that the card has just been powered up; + * not all MMC/SD sockets support power switching. + * + * FIXME when the card is still in SPI mode, e.g. from a previous kernel, + * this doesn't seem to do the right thing at all... + */ +static void mmc_spi_initsequence(struct mmc_spi_host *host) +{ + /* Try to be very sure any previous command has completed; + * wait till not-busy, skip debris from any old commands. + */ + mmc_spi_wait_unbusy(host, r1b_timeout); + mmc_spi_readbytes(host, 10); + + /* + * Do a burst with chipselect active-high. We need to do this to + * meet the requirement of 74 clock cycles with both chipselect + * and CMD (MOSI) high before CMD0 ... after the card has been + * powered up to Vdd(min), and so is ready to take commands. + * + * Some cards are particularly needy of this (e.g. Viking "SD256") + * while most others don't seem to care. + * + * Note that this is one of the places MMC/SD plays games with the + * SPI protocol. Another is that when chipselect is released while + * the card returns BUSY status, the clock must issue several cycles + * with chipselect high before the card will stop driving its output. + */ + host->spi->mode |= SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Just warn; most cards work without it. */ + dev_warn(&host->spi->dev, + "can't change chip-select polarity\n"); + host->spi->mode &= ~SPI_CS_HIGH; + } else { + mmc_spi_readbytes(host, 18); + + host->spi->mode &= ~SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Wot, we can't get the same setup we had before? */ + dev_err(&host->spi->dev, + "can't restore chip-select polarity\n"); + } + } +} + +static char *mmc_powerstring(u8 power_mode) +{ + switch (power_mode) { + case MMC_POWER_OFF: return "off"; + case MMC_POWER_UP: return "up"; + case MMC_POWER_ON: return "on"; + } + return "?"; +} + +static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->power_mode != ios->power_mode) { + int canpower; + + canpower = host->pdata && host->pdata->setpower; + + dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n", + mmc_powerstring(ios->power_mode), + ios->vdd, + canpower ? ", can switch" : ""); + + /* switch power on/off if possible, accounting for + * max 250msec powerup time if needed. + */ + if (canpower) { + switch (ios->power_mode) { + case MMC_POWER_OFF: + case MMC_POWER_UP: + host->pdata->setpower(&host->spi->dev, + ios->vdd); + if (ios->power_mode == MMC_POWER_UP) + msleep(host->powerup_msecs); + } + } + + /* See 6.4.1 in the simplified SD card physical spec 2.0 */ + if (ios->power_mode == MMC_POWER_ON) + mmc_spi_initsequence(host); + + /* If powering down, ground all card inputs to avoid power + * delivery from data lines! On a shared SPI bus, this + * will probably be temporary; 6.4.2 of the simplified SD + * spec says this must last at least 1msec. + * + * - Clock low means CPOL 0, e.g. mode 0 + * - MOSI low comes from writing zero + * - Chipselect is usually active low... + */ + if (canpower && ios->power_mode == MMC_POWER_OFF) { + int mres; + + host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch to SPI mode 0 failed\n"); + + if (spi_w8r8(host->spi, 0x00) < 0) + dev_dbg(&host->spi->dev, + "put spi signals to low failed\n"); + + /* + * Now clock should be low due to spi mode 0; + * MOSI should be low because of written 0x00; + * chipselect should be low (it is active low) + * power supply is off, so now MMC is off too! + * + * FIXME no, chipselect can be high since the + * device is inactive and SPI_CS_HIGH is clear... + */ + msleep(10); + if (mres == 0) { + host->spi->mode |= (SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch back to SPI mode 3" + " failed\n"); + } + } + + host->power_mode = ios->power_mode; + } + + if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) { + int status; + + host->spi->max_speed_hz = ios->clock; + status = spi_setup(host->spi); + dev_dbg(&host->spi->dev, + "mmc_spi: clock to %d Hz, %d\n", + host->spi->max_speed_hz, status); + } +} + +static int mmc_spi_get_ro(struct mmc_host *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc->parent); + /* board doesn't support read only detection; assume writeable */ + return 0; +} + + +static const struct mmc_host_ops mmc_spi_ops = { + .request = mmc_spi_request, + .set_ios = mmc_spi_set_ios, + .get_ro = mmc_spi_get_ro, +}; + + +/****************************************************************************/ + +/* + * SPI driver implementation + */ + +static irqreturn_t +mmc_spi_detect_irq(int irq, void *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + u16 delay_msec = max(host->pdata->detect_delay, (u16)100); + + mmc_detect_change(mmc, msecs_to_jiffies(delay_msec)); + return IRQ_HANDLED; +} + +static int mmc_spi_probe(struct spi_device *spi) +{ + void *ones; + struct mmc_host *mmc; + struct mmc_spi_host *host; + int status; + + /* SanDisk and Hitachi MMC docs both show clock timing diagrams + * with clock starting low (CPOL=0) and sampling on leading edge + * (CPHA=0); clock is measured between rising edges. Sandisk SD + * docs show clock starting high (CPOL=1) and sampling on trailing + * edge (CPHA=1), measuring between falling edges. + * + * Docs are very explicit that sampling is on the rising edge, so + * SPI_MODE_0 and SPI_MODE_3 having different CPOL may not matter. + */ + spi->mode |= SPI_CPOL | SPI_CPHA; + spi->bits_per_word = 8; + + status = spi_setup(spi); + if (status < 0) { + dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n", + spi->mode, spi->max_speed_hz / 1000, + status); + return status; + } + + /* We can use the bus safely iff nobody else will interfere with + * us. That is, either we have the experimental exclusive access + * primitives ... or else there's nobody to share it with. + */ + if (spi->master->num_chipselect > 1) { + struct device *parent = spi->dev.parent; + + /* If there are multiple devices on this bus, we + * can't proceed. + */ + spin_lock(&parent->klist_children.k_lock); + if (parent->klist_children.k_list.next + != parent->klist_children.k_list.prev) + status = -EMLINK; + else + status = 0; + spin_unlock(&parent->klist_children.k_lock); + if (status < 0) { + dev_err(&spi->dev, "can't share SPI bus\n"); + return status; + } + + /* REVISIT we can't guarantee another device won't + * be added later. It's uncommon though ... for now, + * work as if this is safe. + */ + dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n"); + } + + /* We need a supply of ones to transmit. This is the only time + * the CPU touches these, so cache coherency isn't a concern. + * + * NOTE if many systems use more than one MMC-over-SPI connector + * it'd save some memory to share this. That's evidently rare. + */ + status = -ENOMEM; + ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL); + if (!ones) + goto nomem; + memset(ones, 0xff, MMC_SPI_BLOCKSIZE); + + mmc = mmc_alloc_host(sizeof(*host), &spi->dev); + if (!mmc) + goto nomem; + + mmc->ops = &mmc_spi_ops; + mmc->max_blk_size = MMC_SPI_BLOCKSIZE; + + /* As long as we keep track of the number of successfully + * transmitted blocks, we're good for multiwrite. + */ + mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE; + + /* SPI doesn't need the lowspeed device identification thing for + * MMC or SD cards, since it never comes up in open drain mode. + * That's good; some SPI masters can't handle very low speeds! + * + * However, low speed SDIO cards need not handle over 400 KHz; + * that's the only reason not to use a few MHz for f_min (until + * the upper layer reads the target frequency from the CSD). + */ + mmc->f_min = 400000; + mmc->f_max = spi->max_speed_hz; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->spi = spi; + + host->ones = ones; + + /* Platform data is used to hook up things like card sensing + * and power switching gpios. + */ + host->pdata = spi->dev.platform_data; + if (host->pdata) + mmc->ocr_avail = host->pdata->ocr_mask; + if (!mmc->ocr_avail) { + dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n"); + mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + } + if (host->pdata && host->pdata->setpower) { + host->powerup_msecs = host->pdata->powerup_msecs; + if (!host->powerup_msecs || host->powerup_msecs > 250) + host->powerup_msecs = 250; + } + + dev_set_drvdata(&spi->dev, mmc); + + /* preallocate dma buffers */ + host->data = kmalloc(sizeof(*host->data), GFP_KERNEL); + if (!host->data) + goto fail_nobuf1; + + if (spi->master->cdev.dev->dma_mask) { + struct device *dev = spi->master->cdev.dev; + + host->dma_dev = dev; + host->ones_dma = dma_map_single(dev, ones, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + host->data_dma = dma_map_single(dev, host->data, + sizeof(*host->data), DMA_BIDIRECTIONAL); + + /* REVISIT in theory those map operations can fail... */ + + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + } + + /* setup message for status/busy readback */ + spi_message_init(&host->readback); + host->readback.is_dma_mapped = (host->dma_dev != NULL); + + spi_message_add_tail(&host->status, &host->readback); + host->status.tx_buf = host->ones; + host->status.tx_dma = host->ones_dma; + host->status.rx_buf = &host->data->status; + host->status.rx_dma = host->data_dma + offsetof(struct scratch, status); + host->status.cs_change = 1; + + /* register card detect irq */ + if (host->pdata && host->pdata->init) { + status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc); + if (status != 0) + goto fail_glue_init; + } + + status = mmc_add_host(mmc); + if (status != 0) + goto fail_add_host; + + dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n", + mmc->class_dev.bus_id, + host->dma_dev ? "" : ", no DMA", + (host->pdata && host->pdata->get_ro) + ? "" : ", no WP", + (host->pdata && host->pdata->setpower) + ? "" : ", no poweroff"); + return 0; + +fail_add_host: + mmc_remove_host (mmc); +fail_glue_init: + if (host->dma_dev) + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof(*host->data), DMA_BIDIRECTIONAL); + kfree(host->data); + +fail_nobuf1: + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + +nomem: + kfree(ones); + return status; +} + + +static int __devexit mmc_spi_remove(struct spi_device *spi) +{ + struct mmc_host *mmc = dev_get_drvdata(&spi->dev); + struct mmc_spi_host *host; + + if (mmc) { + host = mmc_priv(mmc); + + /* prevent new mmc_detect_change() calls */ + if (host->pdata && host->pdata->exit) + host->pdata->exit(&spi->dev, mmc); + + mmc_remove_host(mmc); + + if (host->dma_dev) { + dma_unmap_single(host->dma_dev, host->ones_dma, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof(*host->data), DMA_BIDIRECTIONAL); + } + + kfree(host->data); + kfree(host->ones); + + spi->max_speed_hz = mmc->f_max; + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + } + return 0; +} + + +static struct spi_driver mmc_spi_driver = { + .driver = { + .name = "mmc_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mmc_spi_probe, + .remove = __devexit_p(mmc_spi_remove), +}; + + +static int __init mmc_spi_init(void) +{ + return spi_register_driver(&mmc_spi_driver); +} +module_init(mmc_spi_init); + + +static void __exit mmc_spi_exit(void) +{ + spi_unregister_driver(&mmc_spi_driver); +} +module_exit(mmc_spi_exit); + + +MODULE_AUTHOR("Mike Lavender, David Brownell, " + "Hans-Peter Nilsson, Jan Nikitenko"); +MODULE_DESCRIPTION("SPI SD/MMC host driver"); +MODULE_LICENSE("GPL"); ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707261632.37011.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <200707261632.37011.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-08-01 15:12 ` Pierre Ossman [not found] ` <20070801171217.1478267b-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-08-01 15:12 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thu, 26 Jul 2007 16:32:36 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > You said you weren't going to update the MMC core to check > the status bits after every request, and I'm certainly not > about to change *EVERY MMC/SD REQUEST* to adopt a radically > different callling convention either!! > > Which leaves us needing a solution that actually works, and > this seems to be the only option: continue to use the current > calling convention, ->error fields report the failures. > I'm more concerned with where you check this, rather than how. If you want to apply it broadly, the request handling functions in core.c would seem more sane. > > However, that bit looks deeply messy. You'd be splitting > the OCR (and other SPI four byte responses) into two > different words, for example! > > Or to put it differently, this way the structure that's > passed up to the core is actually meaningful: one word > of status, and maybe another word of data. And *never* > any mixed status/data words that'd need disentangling. > > After all, if you really wanted to provide raw protocol > data to the mmc core, cmd->resp[] would be bytes, not > 32-bit words in cpu-order. > It should, as that's how it's used everywhere. And I'd gladly accept a patch that fixes this. > > I guess we'll have to disagree on this for now. If it > matters, it can be changed later; but I certainly couldn't > call mixing data and status as an improvement!! > >From my point of view, it's all data. :) > > The data block CRC is quite expensive, yes. The CRC7 isn't; > and in any case, you had pretty much demanded that it always > be computed (to eliminate the #define for the crc needed in > the card reset command) ... > Ah, didn't think of that distinction. Carry on. > > > > At least we agree on error codes. This is precisely the change > > I have pending in my patch set to remove the MMC_ERR_* mess. :) > > I had to pick something. ;) > I have committed that to -mm now. Could I bother you with an update of your patch to remove all MMC_ERR_ stuff? :) > > > I need a MAINTAINERS entry aswell. > > I was hoping someone would sign up for that, so I don't > have to stick myself there with "Odd fixes" status... > Have you poked someone? I don't even have any SPI hardware, so I'm definitely the wrong person. > > > I'd like to see those REVISIT things attended to before I push > > the stuff to Linus though. > > In this driver? They're mostly performance tuning issues, which > are normally best left till later: > > - dma_map_single() operations could theoretically fail. > Not that it'd be likely on hardware that uses this driver; > but that's simple error path cleanup. > This is the one I'm mostly concerned with. Dangling error paths give me the willies. > More significant are the two FIXMEs related to card reset. > One will require someone with relevant hardware (Jan?), > the other still needs investigation. > Ok. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070801171217.1478267b-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <20070801171217.1478267b-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-08-01 18:17 ` David Brownell [not found] ` <200708011117.24664.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-08-01 18:40 ` David Brownell 1 sibling, 1 reply; 47+ messages in thread From: David Brownell @ 2007-08-01 18:17 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Wednesday 01 August 2007, Pierre Ossman wrote: > On Thu, 26 Jul 2007 16:32:36 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > > > You said you weren't going to update the MMC core to check > > the status bits after every request, and I'm certainly not > > about to change *EVERY MMC/SD REQUEST* to adopt a radically > > different callling convention either!! > > > > Which leaves us needing a solution that actually works, and > > this seems to be the only option: continue to use the current > > calling convention, ->error fields report the failures. > > > > I'm more concerned with where you check this, rather than how. If you > want to apply it broadly, the request handling functions in core.c > would seem more sane. That's not how any other host controller driver works though... I'm concerned with not becoming a guinea pig for experimenting with deep MMC stack changes which are not directly related to the SPI support. > > However, that bit looks deeply messy. You'd be splitting > > the OCR (and other SPI four byte responses) into two > > different words, for example! > > > > Or to put it differently, this way the structure that's > > passed up to the core is actually meaningful: one word > > of status, and maybe another word of data. And *never* > > any mixed status/data words that'd need disentangling. > > > > After all, if you really wanted to provide raw protocol > > data to the mmc core, cmd->resp[] would be bytes, not > > 32-bit words in cpu-order. > > > > It should, as that's how it's used everywhere. And I'd gladly accept a > patch that fixes this. Erm, I don't follow. It *is* used as 32-bit words everywhere I've had occasion to check. > > I guess we'll have to disagree on this for now. If it > > matters, it can be changed later; but I certainly couldn't > > call mixing data and status as an improvement!! > > > > From my point of view, it's all data. :) Which of your points of view, though? Clearly at some point the MMC stack recognizes the different semantics associated with for example OCR vs the command response codes. Data isn't necessarily opaque ... > > The data block CRC is quite expensive, yes. The CRC7 isn't; > > and in any case, you had pretty much demanded that it always > > be computed (to eliminate the #define for the crc needed in > > the card reset command) ... > > > > Ah, didn't think of that distinction. Carry on. > > > > > > > At least we agree on error codes. This is precisely the change > > > I have pending in my patch set to remove the MMC_ERR_* mess. :) > > > > I had to pick something. ;) > > > > I have committed that to -mm now. Could I bother you with an update of > your patch to remove all MMC_ERR_ stuff? :) You mean, git-mmc.patch from 2.6.23-rc1-mm2 which I see has just come out? It really would have been easier all around if you had made those changes *after* merging at least the core parts of the SPI support. It looks like most of the SPI patches won't even apply any more, so I'm "gifted" with a needless quantity of make-work. The kind of stuff I've been trying to avoid by submitting the SPI stuff *before* any of those newer patches which jumped ahead of it in the queue ... :( > > > I'd like to see those REVISIT things attended to before I push > > > the stuff to Linus though. > > > > In this driver? They're mostly performance tuning issues, which > > are normally best left till later: > > > > - dma_map_single() operations could theoretically fail. > > Not that it'd be likely on hardware that uses this driver; > > but that's simple error path cleanup. > > > > This is the one I'm mostly concerned with. Dangling error paths give me > the willies. That will be a trivial incremental patch. You are aware that almost all DMA mapping calls in the kernel don't check for errors, right? Because the ability to return errors is quite new ... and last I checked, not even documented. So while I'm glad that the DMA API finally changed (I recall pointing out that gaping hole almost four years ago by now), this particular issue shouldn't worry much at all. > > More significant are the two FIXMEs related to card reset. > > One will require someone with relevant hardware (Jan?), > > the other still needs investigation. > > > > Ok. I can't see those getting investigated before these patches merge. - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200708011117.24664.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <200708011117.24664.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-08-02 13:06 ` Pierre Ossman [not found] ` <20070802150615.36e073c6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-08-02 13:06 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Wed, 1 Aug 2007 11:17:24 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > On Wednesday 01 August 2007, Pierre Ossman wrote: > > > > I'm more concerned with where you check this, rather than how. If > > you want to apply it broadly, the request handling functions in > > core.c would seem more sane. > > That's not how any other host controller driver works though... > Other controllers don't care at all about status bits. Except for omap, which caused it to break in fun and interesting ways. > I'm concerned with not becoming a guinea pig for experimenting > with deep MMC stack changes which are not directly related to > the SPI support. > You're the one who started poking the error handling bear ;) But we can ignore it for now. > > > After all, if you really wanted to provide raw protocol > > > data to the mmc core, cmd->resp[] would be bytes, not > > > 32-bit words in cpu-order. > > > > > > > It should, as that's how it's used everywhere. And I'd gladly > > accept a patch that fixes this. > > Erm, I don't follow. It *is* used as 32-bit words > everywhere I've had occasion to check. > The only place it is used as that is when checking status bits (in the app cmd handling). In all other places it is treated as a data buffer. Just look at the UNSTUFF_BITS macro in mmc.c and sd.c. > > > > From my point of view, it's all data. :) > > Which of your points of view, though? Clearly at some > point the MMC stack recognizes the different semantics > associated with for example OCR vs the command response > codes. Data isn't necessarily opaque ... > Right. I'm talking about the layer the host driver handles. There things should be: <header> <payload> <tail> > > > > I have committed that to -mm now. Could I bother you with an update > > of your patch to remove all MMC_ERR_ stuff? :) > > You mean, git-mmc.patch from 2.6.23-rc1-mm2 which I see has > just come out? > Unfortunately I have little insight into Andrew's schedule for producing new -mm. I push stuff to my "for-andrew" branch and he eventually pulls from that. > It really would have been easier all around if you had made > those changes *after* merging at least the core parts of the > SPI support. It looks like most of the SPI patches won't even > apply any more, so I'm "gifted" with a needless quantity of > make-work. The kind of stuff I've been trying to avoid by > submitting the SPI stuff *before* any of those newer patches > which jumped ahead of it in the queue ... :( > I don't see how it would have been easier. The only difference is that I'd get a merge problem when I applied the new stuff. So the difference is really whose lap it would have fallen in. I can fix your patches if you'd like, but you'd probably have better insight into selecting relevant error codes now that the entire errno is available. > > That will be a trivial incremental patch. You are aware > that almost all DMA mapping calls in the kernel don't check > for errors, right? Because the ability to return errors is > quite new ... and last I checked, not even documented. > Somehow, that doesn't make me feel any better. > > > More significant are the two FIXMEs related to card reset. > > > One will require someone with relevant hardware (Jan?), > > > the other still needs investigation. > > > > > > > Ok. > > I can't see those getting investigated before these patches > merge. > Sure, that's fine. -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070802150615.36e073c6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <20070802150615.36e073c6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-08-02 20:34 ` David Brownell [not found] ` <200708021334.50670.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-08-02 20:34 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thursday 02 August 2007, Pierre Ossman wrote: > On Wed, 1 Aug 2007 11:17:24 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > On Wednesday 01 August 2007, Pierre Ossman wrote: > > > > > > I'm more concerned with where you check this, rather than how. If > > > you want to apply it broadly, the request handling functions in > > > core.c would seem more sane. > > > > That's not how any other host controller driver works though... > > > > Other controllers don't care at all about status bits. Maybe not, but they *do* report failures. And in this case there's no other way to report failures ... since SPI doesn't have any integral error checks whatsoever. The only way to detect errors is to look at those bits after each transaction. (Without hardware feedback, you can't even tell if there's a device present on any given chipselect. The SPI host can fling bits out, and read back pulled-up/down bits in any quantity, without error.) > Except for omap, > which caused it to break in fun and interesting ways. I think the only time I touched that code was to teach it how to do SD ... 4wire support, writeprotect sensing, and funky block sizes. The intended design of an MMC/SD host driver has never been all that clear. It's becoming more clear with your recent work ... but it's not there yet, and there aren't even test scripts or suites for de-facto requirements (and to facilitate regression testing). > > I'm concerned with not becoming a guinea pig for experimenting > > with deep MMC stack changes which are not directly related to > > the SPI support. > > > > You're the one who started poking the error handling bear ;) Was I? Didn't think so. How was I to know that whiteboard scribbles would animate themselves? :) > But we can ignore it for now. > > > > > After all, if you really wanted to provide raw protocol > > > > data to the mmc core, cmd->resp[] would be bytes, not > > > > 32-bit words in cpu-order. > > > > > > > > > > It should, as that's how it's used everywhere. And I'd gladly > > > accept a patch that fixes this. > > > > Erm, I don't follow. It *is* used as 32-bit words > > everywhere I've had occasion to check. > > > > The only place it is used as that is when checking status bits (in the > app cmd handling). In all other places it is treated as a data buffer. > Just look at the UNSTUFF_BITS macro in mmc.c and sd.c. And it all but ignores those status bits too, which seems kind of problematic. (Relies on controller hardware to mirror protocol faults by hardware faults of some kind...) But I see what you mean about UNSTUFF_BITS. > > > From my point of view, it's all data. :) > > > > Which of your points of view, though? Clearly at some > > point the MMC stack recognizes the different semantics > > associated with for example OCR vs the command response > > codes. Data isn't necessarily opaque ... > > > > Right. I'm talking about the layer the host driver handles. There things > should be: > > <header> <payload> <tail> Fault handling being orthogonal to that. And at this time, like it or (clearly!) not, the mmc core does virtually no fault checking ... it relies on reports from host drivers. You're probably on to something with the notion that the I/O wrappers should check the status codes. But that's a substantial change from how the stack has worked, ever since it was written. > > > I have committed that to -mm now. Could I bother you with an update > > > of your patch to remove all MMC_ERR_ stuff? :) > > > > You mean, git-mmc.patch from 2.6.23-rc1-mm2 which I see has > > just come out? > > > > Unfortunately I have little insight into Andrew's schedule for > producing new -mm. I push stuff to my "for-andrew" branch and he > eventually pulls from that. That's no problem. > > It really would have been easier all around if you had made > > those changes *after* merging at least the core parts of the > > SPI support. It looks like most of the SPI patches won't even > > apply any more, so I'm "gifted" with a needless quantity of > > make-work. The kind of stuff I've been trying to avoid by > > submitting the SPI stuff *before* any of those newer patches > > which jumped ahead of it in the queue ... :( > > > > I don't see how it would have been easier. The only difference is that > I'd get a merge problem when I applied the new stuff. So the difference > is really whose lap it would have fallen in. Not exactly ... you'd have been developing that new stuff against current GIT, which would already have had some of those patches, so there wouldn't even *be* a merge problem for that stuff. > I can fix your patches if you'd like, but you'd probably have better > insight into selecting relevant error codes now that the entire errno > is available. Patches #1 and #2 were easy fixes; about 2/3 of #3 is rejected, and I've not yet looked at the details ... that's all the core changes, which haven't previously cared about much more than success-or-fault. #4 should be easy to cope with. > > That will be a trivial incremental patch. You are aware > > that almost all DMA mapping calls in the kernel don't check > > for errors, right? Because the ability to return errors is > > quite new ... and last I checked, not even documented. > > > > Somehow, that doesn't make me feel any better. It's just an indication of how seldom DMA mapping errors have ever made problems. > > > > More significant are the two FIXMEs related to card reset. > > > > One will require someone with relevant hardware (Jan?), > > > > the other still needs investigation. > > > > > > > > > > Ok. > > > > I can't see those getting investigated before these patches > > merge. > > > > Sure, that's fine. > ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200708021334.50670.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <200708021334.50670.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-08-04 13:14 ` Pierre Ossman [not found] ` <20070804151452.0efaa5a9-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-08-07 12:35 ` Pierre Ossman 1 sibling, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-08-04 13:14 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Thu, 2 Aug 2007 13:34:49 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > Except for omap, > > which caused it to break in fun and interesting ways. > > I think the only time I touched that code was to teach it > how to do SD ... 4wire support, writeprotect sensing, and > funky block sizes. > > The intended design of an MMC/SD host driver has never > been all that clear. It's becoming more clear with your > recent work ... but it's not there yet, and there aren't > even test scripts or suites for de-facto requirements > (and to facilitate regression testing). > I agree. There are still a bunch of corner cases that are fuzzy at best. Unfortunately, all difficult cases usually involve error conditions. So I haven't been able to come up with a way to test things without having a custom card that can fail requests in different exotic ways. > > Fault handling being orthogonal to that. And at this time, > like it or (clearly!) not, the mmc core does virtually no > fault checking ... it relies on reports from host drivers. > > You're probably on to something with the notion that the > I/O wrappers should check the status codes. But that's > a substantial change from how the stack has worked, ever > since it was written. > Indeed. The core lacks proper error checking on that level because those errors are so extremely rare. People are lazy and "good enough" goes a long way. I'd love to see better error handling, but with these low odds, other things get prioritized. > > > > I don't see how it would have been easier. The only difference is > > that I'd get a merge problem when I applied the new stuff. So the > > difference is really whose lap it would have fallen in. > > Not exactly ... you'd have been developing that new stuff against > current GIT, which would already have had some of those patches, > so there wouldn't even *be* a merge problem for that stuff. > I'm afraid my development is far from serial. All code that needs further testing gets its own branch, as there is still some uncertainty as to when it will be pushed upstream. > > Patches #1 and #2 were easy fixes; about 2/3 of #3 is rejected, > and I've not yet looked at the details ... that's all the core > changes, which haven't previously cared about much more than > success-or-fault. #4 should be easy to cope with. > It should just be a matter of replacing MMC_ERR_ codes with -Esomething. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070804151452.0efaa5a9-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <20070804151452.0efaa5a9-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-08-04 17:32 ` David Brownell [not found] ` <200708041032.10001.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-08-04 17:32 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Saturday 04 August 2007, Pierre Ossman wrote: > On Thu, 2 Aug 2007 13:34:49 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > The intended design of an MMC/SD host driver has never > > been all that clear. It's becoming more clear with your > > recent work ... but it's not there yet, and there aren't > > even test scripts or suites for de-facto requirements > > (and to facilitate regression testing). > > I agree. There are still a bunch of corner cases that are fuzzy at > best. Unfortunately, all difficult cases usually involve error > conditions. So I haven't been able to come up with a way to test things > without having a custom card that can fail requests in different exotic > ways. There's always writing negative tests ... i.e. issue requests that will fail, and make sure they fail "correctly". One of those might be an alternative to the current block driver. One expects that code developed outside any test framework will have fair coverage for success paths (e.g. whatever is needed to make MMC and SD memory cards work), and the most common fault paths (e.g. what's triggered during enumeration). But beyond that ... passing illegal params, reading past end of card, "unusual" write sizes, and other things are unlikely to behave consistently between drivers. > > Patches #1 and #2 were easy fixes; about 2/3 of #3 is rejected, > > and I've not yet looked at the details ... that's all the core > > changes, which haven't previously cared about much more than > > success-or-fault. #4 should be easy to cope with. > > It should just be a matter of replacing MMC_ERR_ codes with -Esomething. Or MMC_ERR_NONE with zero. Almost ... thing is, the new SDIO stuff seems to bork things in some cases, more with SD cards than MMC. - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200708041032.10001.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <200708041032.10001.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-08-04 21:32 ` Pierre Ossman 0 siblings, 0 replies; 47+ messages in thread From: Pierre Ossman @ 2007-08-04 21:32 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Sat, 4 Aug 2007 10:32:09 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > There's always writing negative tests ... i.e. issue requests > that will fail, and make sure they fail "correctly". One of > those might be an alternative to the current block driver. > I've thought about it, and the interesting cases are difficult to achieve with a standard card. If you have some ideas, I'd love to hear them. Also, a common problem is drivers that break layering. So my number one wanted test is to issue a command opcode that doesn't match what the spec says in terms of response and semantics. > One expects that code developed outside any test framework > will have fair coverage for success paths (e.g. whatever is > needed to make MMC and SD memory cards work), and the most > common fault paths (e.g. what's triggered during enumeration). > But beyond that ... passing illegal params, reading past end > of card, "unusual" write sizes, and other things are unlikely > to behave consistently between drivers. > Now if only there was time. :) > > > > It should just be a matter of replacing MMC_ERR_ codes with > > -Esomething. > > Or MMC_ERR_NONE with zero. Almost ... thing is, the new SDIO stuff > seems to bork things in some cases, more with SD cards than MMC. > Well, the sdio code so far hasn't paid any attention to sdio. Perhaps it's best to just avoid that detection on a spi host for now. -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <200708021334.50670.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-08-04 13:14 ` Pierre Ossman @ 2007-08-07 12:35 ` Pierre Ossman 1 sibling, 0 replies; 47+ messages in thread From: Pierre Ossman @ 2007-08-07 12:35 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f [-- Attachment #1: Type: text/plain, Size: 717 bytes --] On Thu, 2 Aug 2007 13:34:49 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > The intended design of an MMC/SD host driver has never > been all that clear. It's becoming more clear with your > recent work ... but it's not there yet, and there aren't > even test scripts or suites for de-facto requirements > (and to facilitate regression testing). > I got annoyed by the olpc xo and wrote some tests. Enjoy. (Not SPI enabled, but I'm sure you can make some additions ;)) -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org [-- Attachment #2: mmc-test.patch --] [-- Type: text/x-patch, Size: 12130 bytes --] commit e966ae990cd2ef3be48ece8cde0f97f04a0d6024 Author: Pierre Ossman <drzeus-p3sGCRWkH8CeZLLa646FqQ@public.gmane.org> Date: Tue Aug 7 14:27:17 2007 +0200 mmc: mmc host test driver A dummy driver that performs a series of requests that are often mis- handled by host drivers. Signed-off-by: Pierre Ossman <drzeus-p3sGCRWkH8CeZLLa646FqQ@public.gmane.org> diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index aa8a4e4..28db50d 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig @@ -32,6 +32,12 @@ config MMC_BLOCK_BOUNCE If unsure, say Y here. +config MMC_TEST + tristate "MMC host test driver" + default n + help + Dummy driver that tests that a host performs as it should. + config SDIO_UART tristate "SDIO UART/GPS class support" depends on MMC diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile index fc5a784..944447d 100644 --- a/drivers/mmc/card/Makefile +++ b/drivers/mmc/card/Makefile @@ -9,5 +9,6 @@ endif obj-$(CONFIG_MMC_BLOCK) += mmc_block.o mmc_block-objs := block.o queue.o +obj-$(CONFIG_MMC_TEST) += mmc_test.o obj-$(CONFIG_SDIO_UART) += sdio_uart.o diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c new file mode 100644 index 0000000..06c9ef2 --- /dev/null +++ b/drivers/mmc/card/mmc_test.c @@ -0,0 +1,520 @@ +/* + * linux/drivers/mmc/card/mmc_test.c + * + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include <linux/mmc/core.h> +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> + +#include <linux/scatterlist.h> + +static int set_blksize(struct mmc_card *card, unsigned size) +{ + struct mmc_command cmd; + int ret; + + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = size; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + ret = mmc_wait_for_cmd(card->host, &cmd, 5); + if (ret) + return ret; + + return 0; +} + +static int do_transfer(struct mmc_card *card, struct mmc_request *mrq, + int write, unsigned blocks, unsigned blksz) +{ + int ret, i; + u8 *buffer; + + struct scatterlist sg; + + buffer = kzalloc((blocks + 1) * blksz, GFP_KERNEL); + if (!buffer) { + ret = -ENOMEM; + goto out; + } + + if (!write) + memset(buffer, 0xDF, blocks * blksz); + + memset(mrq->data, 0, sizeof(struct mmc_data)); + + mrq->data->blksz = blksz; + mrq->data->blocks = blocks; + mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + mrq->data->sg = &sg; + mrq->data->sg_len = 1; + + sg_init_one(&sg, buffer, blocks * blksz); + + mmc_set_data_timeout(mrq->data, card, write); + + mmc_wait_for_req(card->host, mrq); + + if (!write) { + for (i = 0;i < blocks * blksz;i++) { + if (buffer[i] == 0xDF) { + ret = -EIO; + break; + } + } + + for (i = 0;i < blksz;i++) { + if (buffer[blocks * blksz + i] != 0x00) { + ret = -EIO; + break; + } + } + } + + ret = 0; + +out: + kfree(buffer); + return ret; +} + +static int do_valid_transfer(struct mmc_card *card, struct mmc_request *mrq, + int write, unsigned blocks, unsigned blksz) +{ + int ret; + + ret = set_blksize(card, blksz); + if (ret) + return ret; + + memset(mrq->cmd, 0, sizeof(struct mmc_command)); + + if (blocks > 1) + mrq->cmd->opcode = write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK; + else + mrq->cmd->opcode = write ? MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; + + mrq->cmd->arg = 0; + mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(mrq->stop, 0, sizeof(struct mmc_command)); + + if (blocks > 1) { + mrq->stop->opcode = MMC_STOP_TRANSMISSION; + mrq->stop->arg = 0; + mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC; + } else { + mrq->stop->opcode = MMC_SEND_STATUS; + mrq->stop->arg = card->rca << 16; + mrq->stop->flags = MMC_RSP_R1 | MMC_CMD_AC; + } + + return do_transfer(card, mrq, write, blocks, blksz); +} + +static int do_invalid_transfer(struct mmc_card *card, struct mmc_request *mrq, + int write, unsigned blocks, unsigned blksz) +{ + memset(mrq->cmd, 0, sizeof(struct mmc_command)); + + mrq->cmd->opcode = MMC_SEND_STATUS; + mrq->cmd->arg = card->rca << 16; + mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + memset(mrq->stop, 0, sizeof(struct mmc_command)); + + mrq->stop->opcode = MMC_SEND_STATUS; + mrq->stop->arg = card->rca << 16; + mrq->stop->flags = MMC_RSP_R1 | MMC_CMD_AC; + + return do_transfer(card, mrq, write, blocks, blksz); +} + +static int test_pow2_reads(struct mmc_card *card) +{ + int ret, i; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + printk(KERN_INFO "%s: Testing reading power of two block sizes...\n", + mmc_hostname(card->host)); + + for (i = 1;i <= 512;i <<= 1) { + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + mrq.stop = &stop; + + ret = do_valid_transfer(card, &mrq, 0, 1, i); + if (ret) + goto out; + + ret = 0; + + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != i) + ret = -EIO; + + if (ret) + break; + } + +out: + printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host), + ret ? "FAIL" : "OK"); + + return ret; +} + +static int test_pow2_writes(struct mmc_card *card) +{ + int ret, i; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + printk(KERN_INFO "%s: Testing writing power of two block sizes...\n", + mmc_hostname(card->host)); + + for (i = 1;i <= 512;i <<= 1) { + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + mrq.stop = &stop; + + ret = do_valid_transfer(card, &mrq, 1, 1, i); + if (ret) + goto out; + + ret = 0; + + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != i) + ret = -EIO; + + if (ret) + break; + } + +out: + printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host), + ret ? "FAIL" : "OK"); + + return ret; +} + +static int test_weird_reads(struct mmc_card *card) +{ + int ret, i; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + printk(KERN_INFO "%s: Testing reading unusual block sizes...\n", + mmc_hostname(card->host)); + + for (i = 3;i <= 512;i += 7) { + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + mrq.stop = &stop; + + ret = do_valid_transfer(card, &mrq, 0, 1, i); + if (ret) + goto out; + + ret = 0; + + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != i) + ret = -EIO; + + if (ret) + break; + } + +out: + printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host), + ret ? "FAIL" : "OK"); + + return ret; +} + +static int test_weird_writes(struct mmc_card *card) +{ + int ret, i; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + printk(KERN_INFO "%s: Testing writing unusual block sizes...\n", + mmc_hostname(card->host)); + + for (i = 3;i <= 512;i += 7) { + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + mrq.stop = &stop; + + ret = do_valid_transfer(card, &mrq, 1, 1, i); + if (ret) + goto out; + + ret = 0; + + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != i) + ret = -EIO; + + if (ret) + break; + } + +out: + printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host), + ret ? "FAIL" : "OK"); + + return ret; +} + +static int test_bytes_xfer_single(struct mmc_card *card) +{ + int ret; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + printk(KERN_INFO "%s: Testing correct bytes_xfered for a single block...\n", + mmc_hostname(card->host)); + + if (!(card->host->caps & MMC_CAP_MULTIWRITE)) { + printk(KERN_INFO "%s: Result: UNSUPPORTED\n", + mmc_hostname(card->host)); + return -EINVAL; + } + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + mrq.stop = &stop; + + ret = do_invalid_transfer(card, &mrq, 1, 1, 512); + if (ret) + goto out; + + ret = 0; + + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error != -ETIMEDOUT) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != 0) + ret = -EINVAL; + +out: + printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host), + ret ? "FAIL" : "OK"); + + return ret; +} + +static int test_bytes_xfer_multi(struct mmc_card *card) +{ + int ret; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + printk(KERN_INFO "%s: Testing correct bytes_xfered for multiple blocks...\n", + mmc_hostname(card->host)); + + if (!(card->host->caps & MMC_CAP_MULTIWRITE) || + (card->host->max_blk_count < 2) || + (card->host->max_req_size < 1024) || + (card->host->max_seg_size < 1024)) { + printk(KERN_INFO "%s: Result: UNSUPPORTED\n", + mmc_hostname(card->host)); + return -EINVAL; + } + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + mrq.stop = &stop; + + ret = do_invalid_transfer(card, &mrq, 1, 2, 512); + if (ret) + goto out; + + ret = 0; + + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error != -ETIMEDOUT) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != 0) + ret = -EINVAL; + +out: + printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host), + ret ? "FAIL" : "OK"); + + return ret; +} + +static int test_busy_wait(struct mmc_card *card) +{ + int ret; + + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_command stop; + struct mmc_data data; + + printk(KERN_INFO "%s: Testing that host waits for busy...\n", + mmc_hostname(card->host)); + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + mrq.stop = &stop; + + ret = do_valid_transfer(card, &mrq, 1, 10, 512); + if (ret) + goto out; + + ret = 0; + + if (!ret && cmd.error) + ret = cmd.error; + if (!ret && data.error) + ret = data.error; + if (!ret && stop.error) + ret = stop.error; + if (!ret && data.bytes_xfered != 10 * 512) + ret = -EIO; + + if (ret) + goto out; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + ret = mmc_wait_for_cmd(card->host, &cmd, 0); + if (ret) + goto out; + + if (!(cmd.resp[0] & R1_READY_FOR_DATA)) + ret = -EIO; + +out: + printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host), + ret ? "FAIL" : "OK (uncertain, test multiple cards)"); + + return ret; +} + +static int mmc_test_probe(struct mmc_card *card) +{ + mmc_claim_host(card->host); + + test_pow2_writes(card); + test_pow2_reads(card); + + test_weird_writes(card); + test_weird_reads(card); + + test_bytes_xfer_single(card); + test_bytes_xfer_multi(card); + + test_busy_wait(card); + + mmc_release_host(card->host); + + return -ENODEV; +} + +static void mmc_test_remove(struct mmc_card *card) +{ +} + +static struct mmc_driver mmc_driver = { + .drv = { + .name = "mmc_test", + }, + .probe = mmc_test_probe, + .remove = mmc_test_remove, +}; + +static int __init mmc_test_init(void) +{ + return mmc_register_driver(&mmc_driver); +} + +static void __exit mmc_test_exit(void) +{ + mmc_unregister_driver(&mmc_driver); +} + +module_init(mmc_test_init); +module_exit(mmc_test_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver"); +MODULE_AUTHOR("Pierre Ossman"); + + [-- Attachment #3: Type: text/plain, Size: 315 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ [-- Attachment #4: Type: text/plain, Size: 210 bytes --] _______________________________________________ spi-devel-general mailing list spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org https://lists.sourceforge.net/lists/listinfo/spi-devel-general ^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [patch 2.6.22-git5 4/4] mmc_spi host driver [not found] ` <20070801171217.1478267b-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-08-01 18:17 ` David Brownell @ 2007-08-01 18:40 ` David Brownell 1 sibling, 0 replies; 47+ messages in thread From: David Brownell @ 2007-08-01 18:40 UTC (permalink / raw) To: Hans-Peter Nilsson, Mike Lavender, jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Mikael Starvik, Pierre Ossman On Wednesday 01 August 2007, Pierre Ossman wrote: > > > > I need a MAINTAINERS entry aswell. > > > > I was hoping someone would sign up for that, so I don't > > have to stick myself there with "Odd fixes" status... > > > > Have you poked someone? I don't even have any SPI hardware, so I'm > definitely the wrong person. Well, I certainly asked for a volunteer with one of the earlier patchsets I posted ... as I started cleaning this up so that it could be merged. Mike, Hans-Peter, Jan ... you've all got platforms that need this driver. At least two of you even shipped products using earlier versions. Would one of you want to sign up as the maintainer for the mmc_spi host? - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> ` (3 preceding siblings ...) 2007-07-14 22:08 ` [patch 2.6.22-git5 4/4] mmc_spi host driver David Brownell @ 2007-07-16 16:48 ` Anton Vorontsov [not found] ` <20070716164837.GA18707-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 4 siblings, 1 reply; 47+ messages in thread From: Anton Vorontsov @ 2007-07-16 16:48 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman Hello David, On Sat, Jul 14, 2007 at 03:04:51PM -0700, David Brownell wrote: > Here's an updated version of the MMC-over-SPI patches, reworked to > address most of Pierre's issues (moving even more code into the MMC > core) and to clean up the I/O paths. > > To build/run these, you'll need the CRC7 patch from recent MM trees. > > - headers learn about SPI > > - mmc_block learns about SPI > > - mmc core updates > > - mmc_spi host driver > > The bits related to card lock/unlock aren't included here, since > those didn't go upstream yet. Much thanks for the patches! Though, I still have some troubles with getting MMC(SD)-over-SPI to work. I'm using slightly patched spi_mpc83xx.c driver + these four mmc patches. spi_mpc83xx.c tested only in loopback mode and using oscilloscope. It _seem_ to work fine, but as I didn't tested it on real hardware (other than MMC/SD), I can't say if it's fault of spi_mpc83xx or mmc_spi. David, can you see anything helpful in these debug messages? - - - - mmc_spi spi1.0: ASSUMING unshared SPI bus! mmc_spi spi1.0: ASSUMING 3.2-3.4 V slot power mmc0: clock 0Hz busmode 0 powermode 0 cs 0 Vdd 0 width 0 timing 0 mmc_spi spi1.0: SD/MMC host mmc0, no DMA, no WP, no poweroff mmc0: clock 0Hz busmode 2 powermode 1 cs 1 Vdd 21 width 0 timing 0 mmc_spi spi1.0: mmc_spi: power up (21) mmc0: clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 21 width 0 timing 0 mmc_spi spi1.0: mmc_spi: power on (21) mmc_spi spi1.0: mmc_spi: clock to 400000 Hz, 0 mmc0: starting CMD0 arg 00000000 flags 000000c0 mmc_spi spi1.0: mmc_spi: CMD0, MMC_SPI_R1 mmc0: req done (CMD0): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD8 arg 000001aa flags 000002f5 mmc_spi spi1.0: mmc_spi: CMD8, MMC_SPI_R3/R7 mmc_spi spi1.0: ... CMD8 response SPI_R3/R7: resp 0005 00000000 mmc0: req done (CMD8): 5/0/0: 00000005 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00000000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000000 00000000 00000000 00000000 mmc0: starting CMD58 arg 00000000 flags 00000280 mmc_spi spi1.0: mmc_spi: CMD58, MMC_SPI_R3/R7 mmc0: req done (CMD58): 0/0/0: 00000000 80ff8000 00000000 00000000 mmc0: clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 20 width 0 timing 0 mmc0: starting CMD0 arg 00000000 flags 000000c0 mmc_spi spi1.0: mmc_spi: CMD0, MMC_SPI_R1 mmc0: req done (CMD0): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD8 arg 000001aa flags 000002f5 mmc_spi spi1.0: mmc_spi: CMD8, MMC_SPI_R3/R7 mmc_spi spi1.0: ... CMD8 response SPI_R3/R7: resp 0005 00000000 mmc0: req done (CMD8): 5/0/0: 00000005 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD55 arg 00000000 flags 000000f5 mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 mmc0: starting CMD41 arg 00300000 flags 000000e1 mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 mmc0: req done (CMD41): 0/0/0: 00000000 00000000 00000000 00000000 mmc0: starting CMD59 arg 00000001 flags 00000080 mmc_spi spi1.0: mmc_spi: CMD59, MMC_SPI_R1 mmc0: req done (CMD59): 0/0/0: 00000000 00000000 00000000 00000000 mmc0: starting CMD10 arg 00000000 flags 000000b5 mmc_spi spi1.0: mmc_spi: CMD10, MMC_SPI_R1 mmc_spi spi1.0: mmc_spi: read block, 16 bytes mmc_spi spi1.0: read error f8 (248) mmc_spi spi1.0: read status -5 mmc0: req done (CMD10): 0/4/0: 00000001 00000000 00000000 00000000 mmc0: clock 0Hz busmode 2 powermode 0 cs 1 Vdd 0 width 0 timing 0 mmc_spi spi1.0: mmc_spi: power off (0) - - - - SD card is Kingston 1GB, 3.3V. Thanks! p.s. I've sent subscription request to this list, but SF still processing it. So please Cc me, just to be sure I'll not miss something. -- Anton Vorontsov email: cbou@mail.ru backup email: ya-cbou@yandex.ru irc://irc.freenode.net/bd2 ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070716164837.GA18707-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <20070716164837.GA18707-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2007-07-16 18:54 ` David Brownell [not found] ` <200707161154.54728.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-16 18:54 UTC (permalink / raw) To: avorontsov-hkdhdckH98+B+jHODAdFcQ Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Monday 16 July 2007, Anton Vorontsov wrote: > Hello David, > > On Sat, Jul 14, 2007 at 03:04:51PM -0700, David Brownell wrote: > > Here's an updated version of the MMC-over-SPI patches, reworked to > > address most of Pierre's issues (moving even more code into the MMC > > core) and to clean up the I/O paths. > > > > ... > > Much thanks for the patches! > > Though, I still have some troubles with getting MMC(SD)-over-SPI to > work. > > I'm using slightly patched spi_mpc83xx.c driver + these four mmc > patches. > > spi_mpc83xx.c tested only in loopback mode and using oscilloscope. > It _seem_ to work fine, but as I didn't tested it on real hardware > (other than MMC/SD), I can't say if it's fault of spi_mpc83xx or > mmc_spi. I can't say either, but my first thought is that it might be a card-specific quirk. I already found one in that particular place, and the messages below look fine until the very end. > David, can you see anything helpful in these debug messages? > > - - - - > mmc_spi spi1.0: ASSUMING unshared SPI bus! > mmc_spi spi1.0: ASSUMING 3.2-3.4 V slot power You should provide an ocr_mask in your platform data, saying what voltage range you can supply ... even if it's only 3V3 !! > mmc0: clock 0Hz busmode 0 powermode 0 cs 0 Vdd 0 width 0 timing 0 > mmc_spi spi1.0: SD/MMC host mmc0, no DMA, no WP, no poweroff > mmc0: clock 0Hz busmode 2 powermode 1 cs 1 Vdd 21 width 0 timing 0 > mmc_spi spi1.0: mmc_spi: power up (21) > mmc0: clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 21 width 0 timing 0 > mmc_spi spi1.0: mmc_spi: power on (21) > mmc_spi spi1.0: mmc_spi: clock to 400000 Hz, 0 > mmc0: starting CMD0 arg 00000000 flags 000000c0 > mmc_spi spi1.0: mmc_spi: CMD0, MMC_SPI_R1 > mmc0: req done (CMD0): 0/0/0: 00000001 00000000 00000000 00000000 Looks fine: reset card, R1_SPI_IDLE status is set in the status word (00000001) ... it'll be resetting for some time. > mmc0: starting CMD8 arg 000001aa flags 000002f5 > mmc_spi spi1.0: mmc_spi: CMD8, MMC_SPI_R3/R7 > mmc_spi spi1.0: ... CMD8 response SPI_R3/R7: resp 0005 00000000 > mmc0: req done (CMD8): 5/0/0: 00000005 00000000 00000000 00000000 OK, it doesn't handle SEND_EXT_CSD at all (status R1_SPI_ILLEGAL_COMMAND in addition to the idle status), so it comes as MMC_ERR_INVALID. (Or SEND_IF_COND, if this were an SD 2.0+ card...) > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 ACMD41 == SD_SEND_OP_COND, it's still resetting. Repeats.. > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00000000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000000 00000000 00000000 00000000 Finally the reset completed, R1_SPI_IDLE bit clears. > mmc0: starting CMD58 arg 00000000 flags 00000280 > mmc_spi spi1.0: mmc_spi: CMD58, MMC_SPI_R3/R7 > mmc0: req done (CMD58): 0/0/0: 00000000 80ff8000 00000000 00000000 Reads the OCR, fine. > mmc0: clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 20 width 0 timing 0 > mmc0: starting CMD0 arg 00000000 flags 000000c0 > mmc_spi spi1.0: mmc_spi: CMD0, MMC_SPI_R1 > mmc0: req done (CMD0): 0/0/0: 00000001 00000000 00000000 00000000 Restarts the enumeration, now knowing it's an SD card. > mmc0: starting CMD8 arg 000001aa flags 000002f5 > mmc_spi spi1.0: mmc_spi: CMD8, MMC_SPI_R3/R7 > mmc_spi spi1.0: ... CMD8 response SPI_R3/R7: resp 0005 00000000 > mmc0: req done (CMD8): 5/0/0: 00000005 00000000 00000000 00000000 ... so here it's trying SEND_IF_COND (still failing) ... > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD55 arg 00000000 flags 000000f5 > mmc_spi spi1.0: mmc_spi: CMD55, MMC_SPI_R1 > mmc0: req done (CMD55): 0/0/0: 00000001 00000000 00000000 00000000 > mmc0: starting CMD41 arg 00300000 flags 000000e1 > mmc_spi spi1.0: mmc_spi: CMD41, MMC_SPI_R1 > mmc0: req done (CMD41): 0/0/0: 00000000 00000000 00000000 00000000 Reset finished, IDLE status is no longer set ... > mmc0: starting CMD59 arg 00000001 flags 00000080 > mmc_spi spi1.0: mmc_spi: CMD59, MMC_SPI_R1 > mmc0: req done (CMD59): 0/0/0: 00000000 00000000 00000000 00000000 Enables CRC mode (arg == 1). > mmc0: starting CMD10 arg 00000000 flags 000000b5 > mmc_spi spi1.0: mmc_spi: CMD10, MMC_SPI_R1 > mmc_spi spi1.0: mmc_spi: read block, 16 bytes > mmc_spi spi1.0: read error f8 (248) Hmm, the data block in the MMC_SEND_CID command didn't start with a valid token ... it saw 0xf8, not 0xfe, which is a lowlevel protocol error. Maybe your scope can show whether or not this was the actual data sent by the card... or you can otherwise verify that the input data (from start of CMD10) was a bunch of 0xff values then an 0xf8... > mmc_spi spi1.0: read status -5 > mmc0: req done (CMD10): 0/4/0: 00000001 00000000 00000000 00000000 > mmc0: clock 0Hz busmode 2 powermode 0 cs 1 Vdd 0 width 0 timing 0 > mmc_spi spi1.0: mmc_spi: power off (0) Rather than retrying that command, everything shuts down. Which is annoying, but seems to be the intended behavior; if that's bug, it's not a bug in the SPI support. > - - - - > > > SD card is Kingston 1GB, 3.3V. I didn't try Kingston cards. Since everything worked fine until that last command, maybe a different card will behave better. The driver does handle one protocol quirk. A SanDisk SD card would issue an 0x00 byte right after issuing the command, in that SEND_CID case as well as the SEND_CSD case. That should be an 0xff byte ... depending on exactly where that 0xf8 showed up, maybe the mmc_spi_readblock() code should be changed to skip not just 0x00 but *ANY* non-{0xff,0xfe} byte in that slot. - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707161154.54728.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707161154.54728.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-17 15:13 ` Anton Vorontsov [not found] ` <20070717151350.GA3752-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Anton Vorontsov @ 2007-07-17 15:13 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Mon, Jul 16, 2007 at 11:54:54AM -0700, David Brownell wrote: > On Monday 16 July 2007, Anton Vorontsov wrote: > > Hello David, > > > > On Sat, Jul 14, 2007 at 03:04:51PM -0700, David Brownell wrote: > > > Here's an updated version of the MMC-over-SPI patches, reworked to > > > address most of Pierre's issues (moving even more code into the MMC > > > core) and to clean up the I/O paths. > > > > > > ... > > > > Much thanks for the patches! > > > > Though, I still have some troubles with getting MMC(SD)-over-SPI to > > work. > > > > I'm using slightly patched spi_mpc83xx.c driver + these four mmc > > patches. > > > > spi_mpc83xx.c tested only in loopback mode and using oscilloscope. > > It _seem_ to work fine, but as I didn't tested it on real hardware > > (other than MMC/SD), I can't say if it's fault of spi_mpc83xx or > > mmc_spi. > > I can't say either, but my first thought is that it might be a > card-specific quirk. I already found one in that particular place, > and the messages below look fine until the very end. Uhh.. can you believe? mmc_spi spi1.0: ASSUMING unshared SPI bus! mmc_spi spi1.0: SD/MMC host mmc0, no DMA, no WP, no poweroff mmcblk0: mmc0:0000 SD01G 1006080KiB mmcblk0: p1 root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# mount /dev/mmcblk0p1 /mnt/ EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# ls /mnt/ bin etc include lib libexec lost+found man sbin share var root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# Yup, I've turned debugging off, it's plainly working. The only change I've made is: --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1184,7 +1184,7 @@ static int mmc_spi_probe(struct spi_device *spi) * Docs are very explicit that sampling is on the rising edge, so * SPI_MODE_0 and SPI_MODE_3 having different CPOL may not matter. */ - spi->mode |= SPI_CPOL | SPI_CPHA; + spi->mode = 0; spi->bits_per_word = 8; status = spi_setup(spi); Am I understanding correctly that SPI_CPOL is: ~~~| |~~| |~~~~ | | | | 0 |_| |_| (does not work for me) While !SPI_CPOL is: |~| |~| | | | | 0 ___| |__| |____ (works great for me) Is that correct? Not vice versa? At least that is what I'm observing on oscilloscope. Maybe it's something still messed in mpc83xx_spi.c (I've already fixed a lot), or maybe something else. So, if mmc_spi modes are correct, then mpc83xx_spi having inversed values, and should be fixed. With only SPI_CPHA that thing does not work also. Today I've tested it on bunch of cards, MMC Transcend 64MB, MMC SanDisk 16MB, SD Kingston 128MB and 1GB. All of them work. Thus, despite minor issues, mmc_spi works great, much thanks! -- Anton Vorontsov email: cbou-JGs/UdohzUI@public.gmane.org backup email: ya-cbou-o+MxOtu4lMCHXe+LvDLADg@public.gmane.org irc://irc.freenode.net/bd2 ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070717151350.GA3752-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <20070717151350.GA3752-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2007-07-17 16:11 ` David Brownell [not found] ` <200707170911.16715.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-17 16:11 UTC (permalink / raw) To: avorontsov-hkdhdckH98+B+jHODAdFcQ Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Tuesday 17 July 2007, Anton Vorontsov wrote: > Uhh.. can you believe? > > mmc_spi spi1.0: ASSUMING unshared SPI bus! > mmc_spi spi1.0: SD/MMC host mmc0, no DMA, no WP, no poweroff > mmcblk0: mmc0:0000 SD01G 1006080KiB > mmcblk0: p1 > root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# mount /dev/mmcblk0p1 /mnt/ > EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended > root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# ls /mnt/ > bin etc include lib libexec lost+found man sbin share var > root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# Good! > Yup, I've turned debugging off, it's plainly working. And presumably it works with debugging enabled, too ... > The only change I've made is: > > --- a/drivers/mmc/host/mmc_spi.c > +++ b/drivers/mmc/host/mmc_spi.c > @@ -1184,7 +1184,7 @@ static int mmc_spi_probe(struct spi_device *spi) > * Docs are very explicit that sampling is on the rising edge, so > * SPI_MODE_0 and SPI_MODE_3 having different CPOL may not matter. > */ > - spi->mode |= SPI_CPOL | SPI_CPHA; > + spi->mode = 0; > spi->bits_per_word = 8; > > status = spi_setup(spi); Curious. I think it was Jan Nikitenko who reported mode 0 not working for SD, while mode 3 did work. All my recent testing used mode 3, but I started with mode 0... Ideally, someone with access to full MMC and SD specs can see what they say about the SPI clocking. The simplified SD specs omit the timing diagrams. > Am I understanding correctly that SPI_CPOL is: > > ~~~| |~~| |~~~~ > | | | | > 0 |_| |_| > (does not work for me) > > While !SPI_CPOL is: > > |~| |~| > | | | | > 0 ___| |__| |____ > (works great for me) > > Is that correct? Not vice versa? That's for the clock, I take it ... yes. There's a pretty good timing diagram at Wikipedia, which should make the two bits (CPOL, CPHA) clear: http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus CPOL=0 means the clock starts at idle=low (vs high if CPOL=1). CPHA=0 means capture on leading clock edge (vs trailing if CPHA=1). > At least that is what I'm observing on oscilloscope. Maybe it's > something still messed in mpc83xx_spi.c (I've already fixed a lot), Could you post your changes to that driver? > or maybe something else. So, if mmc_spi modes are correct, then > mpc83xx_spi having inversed values, and should be fixed. > > With only SPI_CPHA that thing does not work also. Later today two patches to mpc83xx_spi should merge into the kernel.org GIT tree but they don't look like they'd relate to this SPI mode issue. (And the CRC7 patch should also be merging...) It's not inconceivable that the SPI controller driver is a bit confused with respect to interpreting the mode bits. We've seen that problem before. > Today I've tested it on bunch of cards, MMC Transcend 64MB, > MMC SanDisk 16MB, SD Kingston 128MB and 1GB. All of them work. Presumably you tested all of them with mode 0 ... which of them work with mode 3? Does it work better in mode 3 if you use a lower clock speed ceiling in the spi board info for that card slot? > Thus, despite minor issues, mmc_spi works great, much thanks! Glad to hear it! Now, to sort out why mode 3 fails for you ... - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707170911.16715.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707170911.16715.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-18 7:35 ` Jan Nikitenko [not found] ` <469DC2BC.5070305-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2007-07-18 10:00 ` Anton Vorontsov 2007-07-18 14:44 ` Pierre Ossman 2 siblings, 1 reply; 47+ messages in thread From: Jan Nikitenko @ 2007-07-18 7:35 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman David Brownell wrote: > On Tuesday 17 July 2007, Anton Vorontsov wrote: > >> Uhh.. can you believe? >> >> mmc_spi spi1.0: ASSUMING unshared SPI bus! >> mmc_spi spi1.0: SD/MMC host mmc0, no DMA, no WP, no poweroff >> mmcblk0: mmc0:0000 SD01G 1006080KiB >> mmcblk0: p1 >> root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# mount /dev/mmcblk0p1 /mnt/ >> EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended >> root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# ls /mnt/ >> bin etc include lib libexec lost+found man sbin share var >> root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# > > Good! > > >> Yup, I've turned debugging off, it's plainly working. > > And presumably it works with debugging enabled, too ... I had the same issues with debugging on in the past, mainly if it went directly to serial console - could it be the changed timing? > > >> The only change I've made is: >> >> --- a/drivers/mmc/host/mmc_spi.c >> +++ b/drivers/mmc/host/mmc_spi.c >> @@ -1184,7 +1184,7 @@ static int mmc_spi_probe(struct spi_device *spi) >> * Docs are very explicit that sampling is on the rising edge, so >> * SPI_MODE_0 and SPI_MODE_3 having different CPOL may not matter. >> */ >> - spi->mode |= SPI_CPOL | SPI_CPHA; >> + spi->mode = 0; >> spi->bits_per_word = 8; >> >> status = spi_setup(spi); > > Curious. I think it was Jan Nikitenko who reported mode 0 not > working for SD, while mode 3 did work. All my recent testing > used mode 3, but I started with mode 0... I do not recall anything about that, I had mode 3 there since the very first version of mmc-spi patch posted by David here: http://www.google.com/search?q=cache%3Awww.gossamer-threads.com%2Flists%2Flinux%2Fkernel%2F671939#671939 Just tried mode 0 today, and it seems to work as well, if I did not overlook something (talking about some old version of mmc-spi, could not get to test the latest releases yet, sorry) > > Ideally, someone with access to full MMC and SD specs can see > what they say about the SPI clocking. The simplified SD specs > omit the timing diagrams. Someone with access to full mmc and sd specs told me, that the timing diagrams there do not show needed spi mode, because the diagrams there are like in a table form, with only CS, DataIN and DataOut signals (no clock signal at all). Jan ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <469DC2BC.5070305-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <469DC2BC.5070305-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2007-07-18 17:06 ` David Brownell 0 siblings, 0 replies; 47+ messages in thread From: David Brownell @ 2007-07-18 17:06 UTC (permalink / raw) To: Jan Nikitenko Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Wednesday 18 July 2007, Jan Nikitenko wrote: > David Brownell wrote: > > Curious. I think it was Jan Nikitenko who reported mode 0 not > > working for SD, while mode 3 did work. All my recent testing > > used mode 3, but I started with mode 0... > > I do not recall anything about that, I had mode 3 there since the very > first version of mmc-spi patch posted by David ... Well then it was somebody else. Doesn't much matter though. :) - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707170911.16715.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-18 7:35 ` Jan Nikitenko @ 2007-07-18 10:00 ` Anton Vorontsov [not found] ` <20070718100047.GA9544-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 2007-07-18 14:44 ` Pierre Ossman 2 siblings, 1 reply; 47+ messages in thread From: Anton Vorontsov @ 2007-07-18 10:00 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Tue, Jul 17, 2007 at 09:11:15AM -0700, David Brownell wrote: > On Tuesday 17 July 2007, Anton Vorontsov wrote: > > > Uhh.. can you believe? > > > > mmc_spi spi1.0: ASSUMING unshared SPI bus! > > mmc_spi spi1.0: SD/MMC host mmc0, no DMA, no WP, no poweroff > > mmcblk0: mmc0:0000 SD01G 1006080KiB > > mmcblk0: p1 > > root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# mount /dev/mmcblk0p1 /mnt/ > > EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended > > root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# ls /mnt/ > > bin etc include lib libexec lost+found man sbin share var > > root-/FxswC0nw/VuxbqukCiDuA@public.gmane.org:~# > > Good! > > > > Yup, I've turned debugging off, it's plainly working. > > And presumably it works with debugging enabled, too ... Yes, sure. I've just forgot to insert "because"; "I've turned debugging off, because it's plainly working now". Sorry for the confusion. Debugging isn't culprit. ;-) > > The only change I've made is: > > > > --- a/drivers/mmc/host/mmc_spi.c > > +++ b/drivers/mmc/host/mmc_spi.c > > @@ -1184,7 +1184,7 @@ static int mmc_spi_probe(struct spi_device *spi) > > * Docs are very explicit that sampling is on the rising edge, so > > * SPI_MODE_0 and SPI_MODE_3 having different CPOL may not matter. > > */ > > - spi->mode |= SPI_CPOL | SPI_CPHA; > > + spi->mode = 0; > > spi->bits_per_word = 8; > > > > status = spi_setup(spi); > > Curious. I think it was Jan Nikitenko who reported mode 0 not > working for SD, while mode 3 did work. All my recent testing > used mode 3, but I started with mode 0... > > Ideally, someone with access to full MMC and SD specs can see > what they say about the SPI clocking. The simplified SD specs > omit the timing diagrams. > > > > Am I understanding correctly that SPI_CPOL is: > > > > ~~~| |~~| |~~~~ > > | | | | > > 0 |_| |_| > > (does not work for me) > > > > While !SPI_CPOL is: > > > > |~| |~| > > | | | | > > 0 ___| |__| |____ > > (works great for me) > > > > Is that correct? Not vice versa? > > That's for the clock, I take it ... yes. There's a pretty > good timing diagram at Wikipedia, which should make the two > bits (CPOL, CPHA) clear: > > http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus > > CPOL=0 means the clock starts at idle=low (vs high if CPOL=1). > CPHA=0 means capture on leading clock edge (vs trailing if CPHA=1). Ok, just as I thought. That means that mpc83xx_spi.c is correct in that regard. > > At least that is what I'm observing on oscilloscope. Maybe it's > > something still messed in mpc83xx_spi.c (I've already fixed a lot), > > Could you post your changes to that driver? Sure, you'll see them shortly. Just need a bit of time. > > or maybe something else. So, if mmc_spi modes are correct, then > > mpc83xx_spi having inversed values, and should be fixed. > > > > With only SPI_CPHA that thing does not work also. > > Later today two patches to mpc83xx_spi should merge into the > kernel.org GIT tree but they don't look like they'd relate > to this SPI mode issue. (And the CRC7 patch should also be > merging...) > > It's not inconceivable that the SPI controller driver is a > bit confused with respect to interpreting the mode bits. > We've seen that problem before. > > > > Today I've tested it on bunch of cards, MMC Transcend 64MB, > > MMC SanDisk 16MB, SD Kingston 128MB and 1GB. All of them work. > > Presumably you tested all of them with mode 0 ... which of them > work with mode 3? None. > Does it work better in mode 3 if you use > a lower clock speed ceiling in the spi board info for that card > slot? Nope. > > Thus, despite minor issues, mmc_spi works great, much thanks! > > Glad to hear it! Now, to sort out why mode 3 fails for you ... > > - Dave Much thanks, -- Anton Vorontsov email: cbou-JGs/UdohzUI@public.gmane.org backup email: ya-cbou-o+MxOtu4lMCHXe+LvDLADg@public.gmane.org irc://irc.freenode.net/bd2 ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070718100047.GA9544-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <20070718100047.GA9544-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2007-07-18 14:05 ` Anton Vorontsov 0 siblings, 0 replies; 47+ messages in thread From: Anton Vorontsov @ 2007-07-18 14:05 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Wed, Jul 18, 2007 at 02:00:47PM +0400, Anton Vorontsov wrote: > > Later today two patches to mpc83xx_spi should merge into the > > kernel.org GIT tree but they don't look like they'd relate > > to this SPI mode issue. (And the CRC7 patch should also be > > merging...) [...] > > Could you post your changes to that driver? > > Sure, you'll see them shortly. Just need a bit of time. Dammit. I've done git pull from Linus' tree, and this commit already fixes most of things (major ones). - - - commit f29ba280ecb46331c1f6842b094808af01131422 Author: Joakim Tjernlund <joakim.tjernlund-SNLAxHN9vbcOP4wsBPIw7w@public.gmane.org> Date: Tue Jul 17 04:04:12 2007 -0700 spi_mpc83xx.c: support QE enabled 83xx CPU's like mpc832x Quicc Engine enabled mpc83xx CPU's has a somewhat different HW interface to the SPI controller. This patch adds a qe_mode knob that sees to that needed adaptions are performed. - - - I'm working on mpc832x too. Heh.. much time wasted... It haven't been in -mm. :-( -- Anton Vorontsov email: cbou-JGs/UdohzUI@public.gmane.org backup email: ya-cbou-o+MxOtu4lMCHXe+LvDLADg@public.gmane.org irc://irc.freenode.net/bd2 ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707170911.16715.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-18 7:35 ` Jan Nikitenko 2007-07-18 10:00 ` Anton Vorontsov @ 2007-07-18 14:44 ` Pierre Ossman [not found] ` <20070718164409.56ca0019-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2 siblings, 1 reply; 47+ messages in thread From: Pierre Ossman @ 2007-07-18 14:44 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Tue, 17 Jul 2007 09:11:15 -0700 David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > Curious. I think it was Jan Nikitenko who reported mode 0 not > working for SD, while mode 3 did work. All my recent testing > used mode 3, but I started with mode 0... > > Ideally, someone with access to full MMC and SD specs can see > what they say about the SPI clocking. The simplified SD specs > omit the timing diagrams. > I can probably help out there. According to the specs, both mode 0 and mode 3 are valid. The idle polarity simply isn't specified, only that data shall be sampled on rising edge. Hence mode 0 or 3. Rgds -- -- Pierre Ossman Linux kernel, MMC maintainer http://www.kernel.org PulseAudio, core developer http://pulseaudio.org rdesktop, core developer http://www.rdesktop.org ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070718164409.56ca0019-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <20070718164409.56ca0019-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> @ 2007-07-18 17:27 ` David Brownell [not found] ` <200707181027.17819.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-18 17:27 UTC (permalink / raw) To: Pierre Ossman Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender t, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f On Wednesday 18 July 2007, Pierre Ossman wrote: > On Tue, 17 Jul 2007 09:11:15 -0700 > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > Ideally, someone with access to full MMC and SD specs can see > > what they say about the SPI clocking. The simplified SD specs > > omit the timing diagrams. > > > > I can probably help out there. > > According to the specs, both mode 0 and mode 3 are valid. The idle > polarity simply isn't specified, only that data shall be sampled on > rising edge. Hence mode 0 or 3. Thanks. In that case, I'm thinking there *IS* a bug of some kind in the controller driver Anton is using, else mode 3 would work for him like it (evidently) works for everyone else. I'll see about making time to see if mode 0 works for me too; but even if it does, I'd prefer to leave the driver the way it is now instead of changing it to cover up for that mpc83xx bug ... plus, I just like CPHA=1 modes better because they don't need to start with that strange half-clock. ;) - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707181027.17819.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707181027.17819.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-19 16:15 ` Anton Vorontsov [not found] ` <20070719161553.GA15756-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Anton Vorontsov @ 2007-07-19 16:15 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender t, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Wed, Jul 18, 2007 at 10:27:17AM -0700, David Brownell wrote: > On Wednesday 18 July 2007, Pierre Ossman wrote: > > On Tue, 17 Jul 2007 09:11:15 -0700 > > David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote: > > > > > Ideally, someone with access to full MMC and SD specs can see > > > what they say about the SPI clocking. The simplified SD specs > > > omit the timing diagrams. > > > > > > > I can probably help out there. > > > > According to the specs, both mode 0 and mode 3 are valid. The idle > > polarity simply isn't specified, only that data shall be sampled on > > rising edge. Hence mode 0 or 3. > > Thanks. In that case, I'm thinking there *IS* a bug of some kind > in the controller driver Anton is using, else mode 3 would work > for him like it (evidently) works for everyone else. I've checked with MPC8323E reference manual, and according to it spi_mpc83xx is doing right thing. > I'll see about making time to see if mode 0 works for me too; but > even if it does, I'd prefer to leave the driver the way it is now > instead of changing it to cover up for that mpc83xx bug ... plus, > I just like CPHA=1 modes better because they don't need to start > with that strange half-clock. ;) Well. As Pierre Ossman told, it should work at any mode. That also proves that it's not mpc83xx's bug (because even if it would be a bug, and spi_mpc83xx having inversed values, it's still should work). So, it's likely depends on spi controller, maybe some timing issues or signal shapes, which distracts SD/MMC... Not sure. But then, may I ask for "alt_mode" (bool) platform data variable? Thanks! -- Anton Vorontsov email: cbou-JGs/UdohzUI@public.gmane.org backup email: ya-cbou-o+MxOtu4lMCHXe+LvDLADg@public.gmane.org irc://irc.freenode.net/bd2 ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070719161553.GA15756-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <20070719161553.GA15756-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2007-07-19 20:28 ` David Brownell [not found] ` <200707191328.18846.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-19 20:28 UTC (permalink / raw) To: avorontsov-hkdhdckH98+B+jHODAdFcQ Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Thursday 19 July 2007, Anton Vorontsov wrote: > > > > Thanks. In that case, I'm thinking there *IS* a bug of some kind > > in the controller driver Anton is using, else mode 3 would work > > for him like it (evidently) works for everyone else. > > I've checked with MPC8323E reference manual, and according to it > spi_mpc83xx is doing right thing. I notice that driver disregards the cs_change instructions in the messages ... I could imagine how that could make a big difference. If that hardware were doing the right thing, then it would work reliably! Since it's not reliable, it's doing something wrong. You seem to think it's not a hardware issue; that may be true. Recall that the first dozen or so commands worked just fine. The issue was that some byte that should have been all-ones or 0xfe reported instead an 0xf8. That's not the kind of error that can be explained by clock skew; it covers at least two bits. > > I'll see about making time to see if mode 0 works for me too; but > > even if it does, I'd prefer to leave the driver the way it is now > > instead of changing it to cover up for that mpc83xx bug ... plus, > > I just like CPHA=1 modes better because they don't need to start > > with that strange half-clock. ;) > > Well. As Pierre Ossman told, it should work at any mode. Well, either mode 0 or mode 3. And since it doesn't work in both modes, clearly something in your test system is buggy. > That also > proves that it's not mpc83xx's bug (because even if it would be a > bug, and spi_mpc83xx having inversed values, it's still should work). No way could it "prove" that!! How could it ever be possible that your system not work in mode 3, and yet that not be a bug in your test system??? The only thing "proven" is that the mmc_spi code is basically correct; otherwise neither clock mode could cause the right data transfers. (And otherewise other folk wouldn't have seen it work...) The problem is in a lower level ... maybe the SPI controller driver, or the silicon, or the board wiring. > So, it's likely depends on spi controller, maybe some timing issues > or signal shapes, which distracts SD/MMC... Not sure. What does your oscilloscope show is going on when this error triggers? Right now I'd most suspect the lack of cs_change support in that controller driver. > But then, may I ask for "alt_mode" (bool) platform data variable? Well, as already said: (a) we know mode 3 is required to work, (b) we know that on your test system it doesn't, so accordingly (c) we know there's a bug in your test system. The only reason to add such a flag would be to paper over that bug. The idea with bugs is to *FIX* them, not paper them over so they'll never get fixed. Especially if you've got a lab setup with even basic hardware debug tools, like your oscilloscope, which make it so easy to verify that the right signals are going down the wires. - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707191328.18846.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707191328.18846.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-23 14:29 ` Anton Vorontsov [not found] ` <20070723142923.GA28979-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: Anton Vorontsov @ 2007-07-23 14:29 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Thu, Jul 19, 2007 at 01:28:17PM -0700, David Brownell wrote: > On Thursday 19 July 2007, Anton Vorontsov wrote: > > > > > > Thanks. In that case, I'm thinking there *IS* a bug of some kind > > > in the controller driver Anton is using, else mode 3 would work > > > for him like it (evidently) works for everyone else. > > > > I've checked with MPC8323E reference manual, and according to it > > spi_mpc83xx is doing right thing. > > I notice that driver disregards the cs_change instructions in the > messages ... I could imagine how that could make a big difference. > > If that hardware were doing the right thing, then it would work > reliably! Since it's not reliable, it's doing something wrong. > You seem to think it's not a hardware issue; that may be true. > > Recall that the first dozen or so commands worked just fine. The > issue was that some byte that should have been all-ones or 0xfe > reported instead an 0xf8. That's not the kind of error that can > be explained by clock skew; it covers at least two bits. Yup, I've either noticed that 0xf8 and 0xfe differs by only two bits (and by three if comparing to 0xff). But I can't really explain it yet. > > > I'll see about making time to see if mode 0 works for me too; but > > > even if it does, I'd prefer to leave the driver the way it is now > > > instead of changing it to cover up for that mpc83xx bug ... plus, > > > I just like CPHA=1 modes better because they don't need to start > > > with that strange half-clock. ;) > > > > Well. As Pierre Ossman told, it should work at any mode. > > Well, either mode 0 or mode 3. And since it doesn't work in both > modes, clearly something in your test system is buggy. > > > > That also > > proves that it's not mpc83xx's bug (because even if it would be a > > bug, and spi_mpc83xx having inversed values, it's still should work). > > No way could it "prove" that!! > > How could it ever be possible that your system not work in mode 3, and > yet that not be a bug in your test system??? > > The only thing "proven" is that the mmc_spi code is basically correct; > otherwise neither clock mode could cause the right data transfers. > (And otherewise other folk wouldn't have seen it work...) > > The problem is in a lower level ... maybe the SPI controller driver, > or the silicon, or the board wiring. > > > > So, it's likely depends on spi controller, maybe some timing issues > > or signal shapes, which distracts SD/MMC... Not sure. > > What does your oscilloscope show is going on when this error triggers? Well, it's not handy to catch particular bit using my oscilloscope. It's unable to scroll in time. But as failing bits are in the last spi message, maybe I could do something. > Right now I'd most suspect the lack of cs_change support in that > controller driver. I see. Thanks for the pointer. > > But then, may I ask for "alt_mode" (bool) platform data variable? > > Well, as already said: (a) we know mode 3 is required to work, > (b) we know that on your test system it doesn't, so accordingly > (c) we know there's a bug in your test system. > > The only reason to add such a flag would be to paper over that bug. > > The idea with bugs is to *FIX* them, not paper them over so they'll > never get fixed. Especially if you've got a lab setup with even > basic hardware debug tools, like your oscilloscope, which make it > so easy to verify that the right signals are going down the wires. Yeah, you're right. And your whole reply makes a lot of sense, much thanks for explanations and ideas. -- Anton Vorontsov email: cbou@mail.ru backup email: ya-cbou@yandex.ru irc://irc.freenode.net/bd2 ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <20070723142923.GA28979-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <20070723142923.GA28979-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2007-07-23 17:33 ` David Brownell [not found] ` <200707231033.31717.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 0 siblings, 1 reply; 47+ messages in thread From: David Brownell @ 2007-07-23 17:33 UTC (permalink / raw) To: avorontsov-hkdhdckH98+B+jHODAdFcQ Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Monday 23 July 2007, Anton Vorontsov wrote: > On Thu, Jul 19, 2007 at 01:28:17PM -0700, David Brownell wrote: > > I notice that driver disregards the cs_change instructions in the > > messages ... I could imagine how that could make a big difference. For example, the extra flapping on the chipselect changes timings... > > If that hardware were doing the right thing, then it would work > > reliably! Since it's not reliable, it's doing something wrong. > > You seem to think it's not a hardware issue; that may be true. > > > > Recall that the first dozen or so commands worked just fine. The > > issue was that some byte that should have been all-ones or 0xfe > > reported instead an 0xf8. That's not the kind of error that can > > be explained by clock skew; it covers at least two bits. > > Yup, I've either noticed that 0xf8 and 0xfe differs by only two > bits (and by three if comparing to 0xff). But I can't really > explain it yet. See if fixing the cs_change handling -- so that chipselect never goes inactive except between MMC requests -- helps. Minimally, you'll notice that mode 0 adds extra delays (albeit only 1/2 clock) before the clock starts toggling; and that deslecting cards except between requests or while the card issues BUSY, falls into the "undefined behavior" category. So while that might not be able to trigger certain perversions, dropping a few clocks in some odd cases would not seem to violate the spec... - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
[parent not found: <200707231033.31717.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707231033.31717.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2007-07-24 10:23 ` Anton Vorontsov 2007-08-07 3:21 ` David Brownell 1 sibling, 0 replies; 47+ messages in thread From: Anton Vorontsov @ 2007-07-24 10:23 UTC (permalink / raw) To: David Brownell Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Mon, Jul 23, 2007 at 10:33:31AM -0700, David Brownell wrote: > On Monday 23 July 2007, Anton Vorontsov wrote: > > On Thu, Jul 19, 2007 at 01:28:17PM -0700, David Brownell wrote: > > > > I notice that driver disregards the cs_change instructions in the > > > messages ... I could imagine how that could make a big difference. > > For example, the extra flapping on the chipselect changes timings... > > > > > If that hardware were doing the right thing, then it would work > > > reliably! Since it's not reliable, it's doing something wrong. > > > You seem to think it's not a hardware issue; that may be true. > > > > > > Recall that the first dozen or so commands worked just fine. The > > > issue was that some byte that should have been all-ones or 0xfe > > > reported instead an 0xf8. That's not the kind of error that can > > > be explained by clock skew; it covers at least two bits. > > > > Yup, I've either noticed that 0xf8 and 0xfe differs by only two > > bits (and by three if comparing to 0xff). But I can't really > > explain it yet. > > See if fixing the cs_change handling -- so that chipselect never > goes inactive except between MMC requests -- helps. Okay.. I've looked into cs_change for spi_mpc83xx, and it seems bitbang framework (which is used by spi_mpc83xx driver) handle cs_change by itself. At least bitbang_work() doing very similar things done by other drivers not using bitbang library. > Minimally, > you'll notice that mode 0 adds extra delays (albeit only 1/2 clock) > before the clock starts toggling; and that deslecting cards > except between requests or while the card issues BUSY, falls into > the "undefined behavior" category. So while that might not be > able to trigger certain perversions, dropping a few clocks in > some odd cases would not seem to violate the spec... > > - Dave Thanks, -- Anton Vorontsov email: cbou-JGs/UdohzUI@public.gmane.org backup email: ya-cbou-o+MxOtu4lMCHXe+LvDLADg@public.gmane.org irc://irc.freenode.net/bd2 ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [patch 2.6.22-git5 0/4] MMC-over-SPI [not found] ` <200707231033.31717.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-24 10:23 ` Anton Vorontsov @ 2007-08-07 3:21 ` David Brownell 1 sibling, 0 replies; 47+ messages in thread From: David Brownell @ 2007-08-07 3:21 UTC (permalink / raw) To: avorontsov-hkdhdckH98+B+jHODAdFcQ Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Pierre Ossman On Monday 23 July 2007, David Brownell wrote: > > > If that hardware were doing the right thing, then it would work > > > reliably! Since it's not reliable, it's doing something wrong. > > > You seem to think it's not a hardware issue; that may be true. > > > > > > Recall that the first dozen or so commands worked just fine. The > > > issue was that some byte that should have been all-ones or 0xfe > > > reported instead an 0xf8. That's not the kind of error that can > > > be explained by clock skew; it covers at least two bits. > > > > Yup, I've either noticed that 0xf8 and 0xfe differs by only two > > bits (and by three if comparing to 0xff). But I can't really > > explain it yet. Just for the record -- on my test rig, SPI mode 3 stopped working entirely ... I'd get one-bit errors, so that CMD0 status would be "0x03" instead of "0x01" (indicating CRC error plus still-resetting). Switching to SPI mode 0 made it all work again; masking out the 0x02 bit made everything time out. So I'm thinking that *was* somehow a shift of one bit. I think this was caused by removing wires for one SPI device from that breadboard ... but it's hard to say for sure. For a while it seemed like MMC cards worked OK but not SD cards! I'm working on a more permanent rig. But I think when I send the next revision to Pierre, it'll be using SPI_MODE_0. :) I thought you might be amused, given the strange behavior you saw! - Dave ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ ^ permalink raw reply [flat|nested] 47+ messages in thread
end of thread, other threads:[~2007-08-07 12:35 UTC | newest] Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-07-14 22:04 [patch 2.6.22-git5 0/4] MMC-over-SPI David Brownell [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-14 22:05 ` [patch 2.6.22-git5 1/4] MMC headers learn about SPI David Brownell [not found] ` <200707141506.00262.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 16:31 ` Pierre Ossman [not found] ` <20070726183150.024930aa-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-07-26 16:55 ` David Brownell [not found] ` <200707260955.22967.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 18:05 ` Pierre Ossman [not found] ` <20070726200525.6a5b7d72-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-07-26 20:08 ` David Brownell 2007-07-14 22:06 ` [patch 2.6.22-git5 2/4] MMC block learns " David Brownell [not found] ` <200707141506.42880.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 16:33 ` Pierre Ossman [not found] ` <20070726183339.6631243f-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-07-26 17:00 ` David Brownell [not found] ` <200707261000.17339.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 18:06 ` Pierre Ossman [not found] ` <20070726200639.06242858-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-07-26 20:15 ` David Brownell 2007-07-14 22:07 ` [patch 2.6.22-git5 3/4] MMC core " David Brownell [not found] ` <200707141507.17484.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 17:18 ` Pierre Ossman [not found] ` <20070726191824.569542fd-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-07-26 21:58 ` David Brownell [not found] ` <200707261458.55558.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 22:22 ` David Brownell 2007-08-01 15:02 ` Pierre Ossman [not found] ` <20070801170220.3c5ccff6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-08-01 17:02 ` David Brownell [not found] ` <200708011002.28801.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-08-02 12:54 ` Pierre Ossman [not found] ` <20070802145445.1118d1e7-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-08-02 19:23 ` David Brownell 2007-07-14 22:08 ` [patch 2.6.22-git5 4/4] mmc_spi host driver David Brownell [not found] ` <200707141508.07555.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-26 18:02 ` Pierre Ossman [not found] ` <20070726200202.5e5dcf62-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-07-26 23:32 ` David Brownell [not found] ` <200707261632.37011.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-08-01 15:12 ` Pierre Ossman [not found] ` <20070801171217.1478267b-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-08-01 18:17 ` David Brownell [not found] ` <200708011117.24664.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-08-02 13:06 ` Pierre Ossman [not found] ` <20070802150615.36e073c6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-08-02 20:34 ` David Brownell [not found] ` <200708021334.50670.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-08-04 13:14 ` Pierre Ossman [not found] ` <20070804151452.0efaa5a9-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-08-04 17:32 ` David Brownell [not found] ` <200708041032.10001.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-08-04 21:32 ` Pierre Ossman 2007-08-07 12:35 ` Pierre Ossman 2007-08-01 18:40 ` David Brownell 2007-07-16 16:48 ` [patch 2.6.22-git5 0/4] MMC-over-SPI Anton Vorontsov [not found] ` <20070716164837.GA18707-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 2007-07-16 18:54 ` David Brownell [not found] ` <200707161154.54728.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-17 15:13 ` Anton Vorontsov [not found] ` <20070717151350.GA3752-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 2007-07-17 16:11 ` David Brownell [not found] ` <200707170911.16715.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-18 7:35 ` Jan Nikitenko [not found] ` <469DC2BC.5070305-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2007-07-18 17:06 ` David Brownell 2007-07-18 10:00 ` Anton Vorontsov [not found] ` <20070718100047.GA9544-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 2007-07-18 14:05 ` Anton Vorontsov 2007-07-18 14:44 ` Pierre Ossman [not found] ` <20070718164409.56ca0019-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org> 2007-07-18 17:27 ` David Brownell [not found] ` <200707181027.17819.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-19 16:15 ` Anton Vorontsov [not found] ` <20070719161553.GA15756-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 2007-07-19 20:28 ` David Brownell [not found] ` <200707191328.18846.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-23 14:29 ` Anton Vorontsov [not found] ` <20070723142923.GA28979-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 2007-07-23 17:33 ` David Brownell [not found] ` <200707231033.31717.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 2007-07-24 10:23 ` Anton Vorontsov 2007-08-07 3:21 ` David Brownell
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).