mmc: rtsx: add support for sdio card
Subsystems (2)
cover mmc: rtsx: add support for sdio card
From: Micky Ching <[email protected]>
This patch is used to change transfer mode for sdio card support by SD interface.
Micky Ching (2):
mfd: rtsx: add func to split u32 into register
mmc: rtsx: add support for sdio card
drivers/mmc/host/rtsx_pci_sdmmc.c | 366 ++++++++++++++++++++++---------------- include/linux/mfd/rtsx_pci.h | 15 ++ 2 files changed, 224 insertions(+), 157 deletions(-)
Signature · 1 line
1.9.1
PATCH 1/2 mfd: rtsx: add func to split u32 into register
From: Micky Ching <[email protected]>
Add helper function to write u32 to registers, if we want to put u32 value to 4 continuous register, this can help us reduce tedious work.
--- include/linux/mfd/rtsx_pci.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
include/linux/mfd/rtsx_pci.h +15 -0
@@ -967,4 +967,19 @@ static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr)return (u8 *)(pcr->host_cmds_ptr); } +static inline void rtsx_pci_write_be32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val >>24 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val); +} + +static inline void rtsx_pci_write_le32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val >>24 ); +}#endif
Signature · 1 line
1.9.1
Re: [PATCH 1/2] mfd: rtsx: add func to split u32 into register
include/linux/mfd/rtsx_pci.h static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) · line 975
Quoted 6 lines · On Thu, Nov 27, 2014 at 10:53:58AM +0800, [email protected] wrote:
include/linux/mfd/rtsx_pci.h +6
-0+static inline void rtsx_pci_write_be32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val >>24 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val);
This assumes the cpu is little endian. First convert to big endian using cpu_to_be32() and then write it out.
__be32 be_val = cpu_to_be32() rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg, 0xFF, be_val); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, be_val >> 8); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, be_val >> 16); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, be_val >> 24);
(Written hurredly in my mail client. May be wrong).
include/linux/mfd/rtsx_pci.h static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) · line 984
Quoted 9 lines
include/linux/mfd/rtsx_pci.h +9
-0+} + +static inline void rtsx_pci_write_le32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val >>24 ); +}
We don't have a user for rtsx_pci_write_le32() so don't add it.
regards,
dan carpenter
Re: [PATCH 1/2] mfd: rtsx: add func to split u32 into register
Quoted 9 lines · Dan Carpenter
Quoted 6 lines
+static inline void
rtsx_pci_write_be32(struct rtsx_pcr *pcr, u16 reg, u32 val)include/linux/mfd/rtsx_pci.h static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) · line 975
Quoted 5 lines
include/linux/mfd/rtsx_pci.h +5
-0+{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val >>24 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val);This assumes the cpu is little endian. First convert to big endian using
cpu_to_be32()and then write it out.
Quoted 9 lines
__be32 be_val = cpu_to_be32() rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg, 0xFF, be_val); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, be_val >> 8); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, be_val >> 16); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, be_val >> 24);(Written hurredly in my mail client. May be wrong).
I think we better not use cpu_to_be32() here, leave the work to caller may be better.
eg, in sd_ops.c the cmd.arg is constructed bit by bit, we can put the right byte to the right register by shift, so the endian check is not need.
Re: [PATCH 1/2] mfd: rtsx: add func to split u32 into register
Quoted 2 lines · 敬锐
eg, in
sd_ops.cthe cmd.arg is constructed bit by bit, we can put the right byte to the right register by shift, so the endian check is not need.
I looked at drivers/mmc/core/sd_ops.c and cmd.arg seems to be cpu endian.
The new function assumes that the cpu is little endian and manually converts it to little endian. This is an endian bug. I think my fix is correct or something similar.
regards,
dan carpenter
_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
Re: [PATCH 1/2] mfd: rtsx: add func to split u32 into register
In reply to Dan CarpenterLet's take an example,
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
using "TP" name test_pattern for simplication , when we call: rtsx_pci_write_be32(pcr, SD_CMD1, cmd->arg); we should make sure TP write to SD_CMD4.
If on "be" platform, then cpu_to_be32() do nothing, and TP is write to SD_CMD1, in this case, it is wrong.
BR,
micky.
Quoted 32 lines · Dan Carpenter
include/linux/mfd/rtsx_pci.h static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) · line 975
Quoted 6 lines · On Thu, Nov 27, 2014 at 10:53:58AM +0800, [email protected] wrote:
include/linux/mfd/rtsx_pci.h +6
-0+static inline void rtsx_pci_write_be32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val >>24 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val);This assumes the cpu is little endian. First convert to big endian using
cpu_to_be32()and then write it out.__be32 be_val = cpu_to_be32() rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg, 0xFF, be_val); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, be_val >> 8); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, be_val >> 16); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, be_val >> 24);(Written hurredly in my mail client. May be wrong).
include/linux/mfd/rtsx_pci.h static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) · line 984
Quoted 9 lines
include/linux/mfd/rtsx_pci.h +9
-0+} + +static inline void rtsx_pci_write_le32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val >>24 ); +}We don't have a user for
rtsx_pci_write_le32()so don't add it.regards,
dan carpenter
Re: [PATCH 1/2] mfd: rtsx: add func to split u32 into register
Oh. You're right. I'm sorry for the noise.
regards,
dan carpenter
Re: [PATCH 1/2] mfd: rtsx: add func to split u32 into register
In reply to [email protected]Quoted 9 lines · On Thu, 27 Nov 2014, [email protected] wrote:
From: Micky Ching <[email protected]>
Add helper function to write u32 to registers, if we want to put u32 value to 4 continuous register, this can help us reduce tedious work.
Signed-off-by Micky Ching <[email protected]>--- include/linux/mfd/rtsx_pci.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
Okay, I'm happy that Dan is now satisfied.
Can I take this patch, or does patch 2 depend on it?
Quoted 24 lines
include/linux/mfd/rtsx_pci.h +15
-0@@ -967,4 +967,19 @@ static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr)return (u8 *)(pcr->host_cmds_ptr); } +static inline void rtsx_pci_write_be32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val >>24 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val); +} + +static inline void rtsx_pci_write_le32 (struct rtsx_pcr *pcr,u16 reg,u32 val) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg,0xFF , val); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +1 ,0xFF , val >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +2 ,0xFF , val >>16 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , reg +3 ,0xFF , val >>24 ); +}#endif
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org │ Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
PATCH 2/2 mmc: rtsx: add support for sdio card
In reply to [email protected]From: Micky Ching <[email protected]>
Add support for sdio card by SD interface. The main change is data transfer mode, When read data, host wait data transfer while command start. When write data, host will start data transfer after command get response. The transfer mode modify can be applied both for SD/MMC card and sdio card.
--- drivers/mmc/host/rtsx_pci_sdmmc.c | 366 ++++++++++++++++++++++---------------- 1 file changed, 209 insertions(+), 157 deletions(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +209 -157
@@ -28,6 +28,7 @@#include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> +#include <linux/mmc/sdio.h> #include <linux/mmc/card.h> #include <linux/mfd/rtsx_pci.h> #include <asm/unaligned.h>
@@ -71,30 +72,82 @@ static inline void sd_clear_error(struct realtek_pci_sdmmc *host) }#ifdef DEBUG -static void sd_print_debug_regs (struct realtek_pci_sdmmc *host) +static void dump_reg_range (struct realtek_pci_sdmmc *host,u16 start,u16 end) { -struct rtsx_pcr *pcr = host->pcr; -u16 i; -u8 *ptr; +u16 len = end - start +1 ; +int i; +u8 *data =kzalloc (8 ,GFP_KERNEL ); -/* Print SD host internal registers */ -rtsx_pci_init_cmd (pcr); -for (i =0xFDA0 ; i <=0xFDAE ; i++) -rtsx_pci_add_cmd (pcr,READ_REG_CMD , i,0 ,0 ); -for (i =0xFD52 ; i <=0xFD69 ; i++) -rtsx_pci_add_cmd (pcr,READ_REG_CMD , i,0 ,0 ); -rtsx_pci_send_cmd (pcr,100 ); - - ptr =rtsx_pci_get_cmd_data (pcr); -for (i =0xFDA0 ; i <=0xFDAE ; i++) -dev_dbg (sdmmc_dev (host),"0x%04X: 0x%02x\n" , i, *(ptr++)); -for (i =0xFD52 ; i <=0xFD69 ; i++) -dev_dbg (sdmmc_dev (host),"0x%04X: 0x%02x\n" , i, *(ptr++)); +if (!data) +return ; + +for (i =0 ; i < len; i +=8 , start +=8 ) { +int j, n =min (8 , len - i); + +for (j =0 ; j < n; j++) +rtsx_pci_read_register (host->pcr, start + j, data + j); +dev_dbg (sdmmc_dev (host),"0x%04X(%d): %8ph\n" , start, n, data); + } + +kfree (data); +} + +static void sd_print_debug_regs (struct realtek_pci_sdmmc *host) +{ +dump_reg_range (host,0xFDA0 ,0xFDB3 ); +dump_reg_range (host,0xFD52 ,0xFD69 ); }#else #define sd_print_debug_regs (host)#endif /* DEBUG */ +static int sdmmc_get_cd (struct mmc_host *mmc); +static void sd_send_cmd_get_rsp (struct realtek_pci_sdmmc *host, +struct mmc_command *cmd); + +static void sd_cmd_set_sd_cmd (struct rtsx_pcr *pcr,struct mmc_command *cmd) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD0 ,0xFF ,0x40 | cmd->opcode); +rtsx_pci_write_be32 (pcr,SD_CMD1 , cmd->arg); +} + +static void sd_cmd_set_data_len (struct rtsx_pcr *pcr,u16 blocks,u16 blksz) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_L ,0xFF , blocks); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_H ,0xFF , blocks >>8 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_L ,0xFF , blksz); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_H ,0xFF , blksz >>8 ); +} + +static int sd_response_type (struct mmc_command *cmd) +{ +switch (mmc_resp_type (cmd)) { +case MMC_RSP_NONE : +return SD_RSP_TYPE_R0 ; +case MMC_RSP_R1 : +return SD_RSP_TYPE_R1 ; +case MMC_RSP_R1 & ~MMC_RSP_CRC : +return SD_RSP_TYPE_R1 |SD_NO_CHECK_CRC7 ; +case MMC_RSP_R1B : +return SD_RSP_TYPE_R1b; +case MMC_RSP_R2 : +return SD_RSP_TYPE_R2 ; +case MMC_RSP_R3 : +return SD_RSP_TYPE_R3 ; +default : +return -EINVAL ; + } +} + +static int sd_status_index (int resp_type) +{ +if (resp_type ==SD_RSP_TYPE_R0 ) +return 0 ; +else if (resp_type ==SD_RSP_TYPE_R2 ) +return 16 ; + +return 5 ; +}/* * sd_pre_dma_transfer - do dma_map_sg() or using cookie *
@@ -166,34 +219,27 @@ static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, data->host_cookie =0 ; } -static int sd_read_data (struct realtek_pci_sdmmc *host,u8 *cmd,u16 byte_cnt, -u8 *buf,int buf_len,int timeout) +static int sd_read_data (struct realtek_pci_sdmmc *host,struct mmc_command *cmd, +u16 byte_cnt,u8 *buf,int buf_len,int timeout) {struct rtsx_pcr *pcr = host->pcr; -int err, i; +int err;u8 trans_mode; -dev_dbg (sdmmc_dev (host),"%s: SD/MMC CMD%d\n" , __func__, cmd[0 ] -0x40 ); +dev_dbg (sdmmc_dev (host),"%s: SD/MMC CMD %d, arg = 0x%08x\n" , + __func__, cmd->opcode, cmd->arg);if (!buf) buf_len =0 ; -if ((cmd[0 ] &0x3F ) ==MMC_SEND_TUNING_BLOCK ) +if (cmd->opcode ==MMC_SEND_TUNING_BLOCK ) trans_mode =SD_TM_AUTO_TUNING ;else trans_mode =SD_TM_NORMAL_READ ;rtsx_pci_init_cmd (pcr); - -for (i =0 ; i <5 ; i++) -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD0 + i,0xFF , cmd[i]); - -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_L ,0xFF , (u8 )byte_cnt); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_H , -0xFF , (u8)(byte_cnt >>8 )); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_L ,0xFF ,1 ); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_H ,0xFF ,0 ); - +sd_cmd_set_sd_cmd (pcr, cmd); +sd_cmd_set_data_len (pcr,1 , byte_cnt);rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CFG2 ,0xFF ,SD_CALCULATE_CRC7 |SD_CHECK_CRC16 |SD_NO_WAIT_BUSY_END |SD_CHECK_CRC7 |SD_RSP_LEN_6 );
@@ -226,16 +272,23 @@ static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,return 0 ; } -static int sd_write_data (struct realtek_pci_sdmmc *host,u8 *cmd,u16 byte_cnt, -u8 *buf,int buf_len,int timeout) +static int sd_write_data (struct realtek_pci_sdmmc *host, +struct mmc_command *cmd,u16 byte_cnt,u8 *buf,int buf_len, +int timeout) {struct rtsx_pcr *pcr = host->pcr; -int err, i; -u8 trans_mode; +int err; + +dev_dbg (sdmmc_dev (host),"%s: SD/MMC CMD %d, arg = 0x%08x\n" , + __func__, cmd->opcode, cmd->arg);if (!buf) buf_len =0 ; +sd_send_cmd_get_rsp (host, cmd); +if (cmd->error) +return cmd->error; +if (buf && buf_len) { err =rtsx_pci_write_ppbuf (pcr, buf, buf_len);if (err <0 ) {
@@ -245,30 +298,13 @@ static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, } } - trans_mode = cmd ?SD_TM_AUTO_WRITE_2 :SD_TM_AUTO_WRITE_3 ;rtsx_pci_init_cmd (pcr); - -if (cmd) { -dev_dbg (sdmmc_dev (host),"%s: SD/MMC CMD %d\n" , __func__, - cmd[0 ] -0x40 ); - -for (i =0 ; i <5 ; i++) -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD , -SD_CMD0 + i,0xFF , cmd[i]); - } - -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_L ,0xFF , (u8 )byte_cnt); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_H , -0xFF , (u8)(byte_cnt >>8 )); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_L ,0xFF ,1 ); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_H ,0xFF ,0 ); - +sd_cmd_set_data_len (pcr,1 , byte_cnt);rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CFG2 ,0xFF ,SD_CALCULATE_CRC7 |SD_CHECK_CRC16 | -SD_NO_WAIT_BUSY_END |SD_CHECK_CRC7 |SD_RSP_LEN_6 ); - +SD_NO_WAIT_BUSY_END |SD_CHECK_CRC7 |SD_RSP_LEN_0 );rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_TRANSFER ,0xFF , - trans_mode |SD_TRANSFER_START ); +SD_TRANSFER_START |SD_TM_AUTO_WRITE_3 );rtsx_pci_add_cmd (pcr,CHECK_REG_CMD ,SD_TRANSFER ,SD_TRANSFER_END ,SD_TRANSFER_END );
@@ -293,47 +329,15 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,int timeout =100 ;int i;u8 *ptr; -int stat_idx =0 ; -u8 rsp_type; -int rsp_len =5 ; +int rsp_type =sd_response_type (cmd); +int stat_idx =sd_status_index (rsp_type);bool clock_toggled = false;dev_dbg (sdmmc_dev (host),"%s: SD/MMC CMD %d, arg = 0x%08x\n" , __func__, cmd_idx, arg); -/* Response type: -* R0 -* R1, R5, R6, R7 -* R1b -* R2 -* R3, R4 -*/ -switch (mmc_resp_type (cmd)) { -case MMC_RSP_NONE : - rsp_type =SD_RSP_TYPE_R0 ; - rsp_len =0 ; -break ; -case MMC_RSP_R1 : - rsp_type =SD_RSP_TYPE_R1 ; -break ; -case MMC_RSP_R1 & ~MMC_RSP_CRC : - rsp_type =SD_RSP_TYPE_R1 |SD_NO_CHECK_CRC7 ; -break ; -case MMC_RSP_R1B : - rsp_type = SD_RSP_TYPE_R1b; -break ; -case MMC_RSP_R2 : - rsp_type =SD_RSP_TYPE_R2 ; - rsp_len =16 ; -break ; -case MMC_RSP_R3 : - rsp_type =SD_RSP_TYPE_R3 ; -break ; -default : -dev_dbg (sdmmc_dev (host),"cmd->flag is not valid\n" ); - err = -EINVAL ; +if (rsp_type <0 ) goto out; - }if (rsp_type == SD_RSP_TYPE_R1b) timeout =3000 ;
@@ -348,13 +352,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, }rtsx_pci_init_cmd (pcr); - -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD0 ,0xFF ,0x40 | cmd_idx); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD1 ,0xFF , (u8)(arg >>24 )); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD2 ,0xFF , (u8)(arg >>16 )); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD3 ,0xFF , (u8)(arg >>8 )); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD4 ,0xFF , (u8 )arg); - +sd_cmd_set_sd_cmd (pcr, cmd);rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CFG2 ,0xFF , rsp_type);rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,CARD_DATA_SOURCE ,0x01 ,PINGPONG_BUFFER );
@@ -368,12 +366,10 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,/* Read data from ping-pong buffer */ for (i =PPBUF_BASE2 ; i <PPBUF_BASE2 +16 ; i++)rtsx_pci_add_cmd (pcr,READ_REG_CMD , (u16 )i,0 ,0 ); - stat_idx =16 ; }else if (rsp_type !=SD_RSP_TYPE_R0 ) {/* Read data from SD_CMDx registers */ for (i =SD_CMD0 ; i <=SD_CMD4 ; i++)rtsx_pci_add_cmd (pcr,READ_REG_CMD , (u16 )i,0 ,0 ); - stat_idx =5 ; }rtsx_pci_add_cmd (pcr,READ_REG_CMD ,SD_STAT1 ,0 ,0 );
@@ -438,71 +434,112 @@ out: SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); } -static int sd_rw_multi (struct realtek_pci_sdmmc *host,struct mmc_request *mrq) +static int sd_read_long_data (struct realtek_pci_sdmmc *host, +struct mmc_request *mrq) {struct rtsx_pcr *pcr = host->pcr;struct mmc_host *mmc = host->mmc;struct mmc_card *card = mmc->card; +struct mmc_command *cmd = mrq->cmd;struct mmc_data *data = mrq->data;int uhs =mmc_card_uhs (card); -int read = (data->flags &MMC_DATA_READ ) ?1 :0 ; -u8 cfg2, trans_mode; +u8 cfg2 =0 ;int err; +int resp_type =sd_response_type (cmd);size_t data_len = data->blksz * data->blocks; -if (read) { - cfg2 =SD_CALCULATE_CRC7 |SD_CHECK_CRC16 | -SD_NO_WAIT_BUSY_END |SD_CHECK_CRC7 |SD_RSP_LEN_0 ; - trans_mode =SD_TM_AUTO_READ_3 ; - }else { - cfg2 =SD_NO_CALCULATE_CRC7 |SD_CHECK_CRC16 | -SD_NO_WAIT_BUSY_END |SD_NO_CHECK_CRC7 |SD_RSP_LEN_0 ; - trans_mode =SD_TM_AUTO_WRITE_3 ; - } +dev_dbg (sdmmc_dev (host),"%s: SD/MMC CMD %d, arg = 0x%08x\n" , + __func__, cmd->opcode, cmd->arg); + +if (resp_type <0 ) +return resp_type;if (!uhs) cfg2 |=SD_NO_CHECK_WAIT_CRC_TO ;rtsx_pci_init_cmd (pcr); - -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_L ,0xFF ,0x00 ); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BYTE_CNT_H ,0xFF ,0x02 ); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_L , -0xFF , (u8 )data->blocks); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_BLOCK_CNT_H , -0xFF , (u8)(data->blocks >>8 )); - +sd_cmd_set_sd_cmd (pcr, cmd); +sd_cmd_set_data_len (pcr, data->blocks, data->blksz);rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,IRQSTAT0 ,DMA_DONE_INT ,DMA_DONE_INT );rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC3 , -0xFF , (u8)(data_len >>24 )); +0xFF , (u8)(data_len >>24 ));rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC2 , -0xFF , (u8)(data_len >>16 )); +0xFF , (u8)(data_len >>16 ));rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC1 , -0xFF , (u8)(data_len >>8 )); +0xFF , (u8)(data_len >>8 ));rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC0 ,0xFF , (u8 )data_len); -if (read) { -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMACTL , -0x03 |DMA_PACK_SIZE_MASK , -DMA_DIR_FROM_CARD |DMA_EN |DMA_512 ); - }else { -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMACTL , -0x03 |DMA_PACK_SIZE_MASK , -DMA_DIR_TO_CARD |DMA_EN |DMA_512 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMACTL , +0x03 |DMA_PACK_SIZE_MASK , +DMA_DIR_FROM_CARD |DMA_EN |DMA_512 ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,CARD_DATA_SOURCE , +0x01 ,RING_BUFFER ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CFG2 ,0xFF , cfg2 | resp_type); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_TRANSFER ,0xFF , +SD_TRANSFER_START |SD_TM_AUTO_READ_2 ); +rtsx_pci_add_cmd (pcr,CHECK_REG_CMD ,SD_TRANSFER , +SD_TRANSFER_END ,SD_TRANSFER_END ); +rtsx_pci_send_cmd_no_wait (pcr); + + err =rtsx_pci_dma_transfer (pcr, data->sg, host->sg_count,1 ,10000 ); +if (err <0 ) { +sd_print_debug_regs (host); +sd_clear_error (host); +return err; } +return 0 ; +} + +static int sd_write_long_data (struct realtek_pci_sdmmc *host, +struct mmc_request *mrq) +{ +struct rtsx_pcr *pcr = host->pcr; +struct mmc_host *mmc = host->mmc; +struct mmc_card *card = mmc->card; +struct mmc_command *cmd = mrq->cmd; +struct mmc_data *data = mrq->data; +int uhs =mmc_card_uhs (card); +u8 cfg2; +int err; +size_t data_len = data->blksz * data->blocks; + +sd_send_cmd_get_rsp (host, cmd); +if (cmd->error) +return cmd->error; + +dev_dbg (sdmmc_dev (host),"%s: SD/MMC CMD %d, arg = 0x%08x\n" , + __func__, cmd->opcode, cmd->arg); + + cfg2 =SD_NO_CALCULATE_CRC7 |SD_CHECK_CRC16 | +SD_NO_WAIT_BUSY_END |SD_NO_CHECK_CRC7 |SD_RSP_LEN_0 ; + +if (!uhs) + cfg2 |=SD_NO_CHECK_WAIT_CRC_TO ; + +rtsx_pci_init_cmd (pcr); +sd_cmd_set_data_len (pcr, data->blocks, data->blksz); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,IRQSTAT0 , +DMA_DONE_INT ,DMA_DONE_INT ); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC3 , +0xFF , (u8)(data_len >>24 )); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC2 , +0xFF , (u8)(data_len >>16 )); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC1 , +0xFF , (u8)(data_len >>8 )); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMATC0 ,0xFF , (u8 )data_len); +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,DMACTL , +0x03 |DMA_PACK_SIZE_MASK , +DMA_DIR_TO_CARD |DMA_EN |DMA_512 );rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,CARD_DATA_SOURCE ,0x01 ,RING_BUFFER ); -rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CFG2 ,0xFF , cfg2);rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_TRANSFER ,0xFF , - trans_mode |SD_TRANSFER_START ); +SD_TRANSFER_START |SD_TM_AUTO_WRITE_3 );rtsx_pci_add_cmd (pcr,CHECK_REG_CMD ,SD_TRANSFER ,SD_TRANSFER_END ,SD_TRANSFER_END ); -rtsx_pci_send_cmd_no_wait (pcr); - - err =rtsx_pci_dma_transfer (pcr, data->sg, host->sg_count, read,10000 ); + err =rtsx_pci_dma_transfer (pcr, data->sg, host->sg_count,0 ,10000 );if (err <0 ) {sd_clear_error (host);return err;
@@ -511,6 +548,16 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)return 0 ; } +static int sd_rw_multi (struct realtek_pci_sdmmc *host,struct mmc_request *mrq) +{ +struct mmc_data *data = mrq->data; + +if (data->flags &MMC_DATA_READ ) +return sd_read_long_data (host, mrq); + +return sd_write_long_data (host, mrq); +} +static inline void sd_enable_initial_mode (struct realtek_pci_sdmmc *host) { rtsx_pci_write_register(host->pcr, SD_CFG1,
@@ -528,10 +575,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, {struct mmc_command *cmd = mrq->cmd;struct mmc_data *data = mrq->data; -u8 _cmd[5 ], *buf; - - _cmd[0 ] =0x40 | (u8 )cmd->opcode; -put_unaligned_be32 (cmd->arg, (u32 *)(&_cmd[1 ])); +u8 *buf; buf =kzalloc (data->blksz,GFP_NOIO );if (!buf) {
@@ -543,7 +587,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host,if (host->initial_mode)sd_disable_initial_mode (host); - cmd->error =sd_read_data (host, _cmd, (u16 )data->blksz, buf, + cmd->error =sd_read_data (host, cmd, (u16 )data->blksz, buf, data->blksz,200 );if (host->initial_mode)
@@ -553,7 +597,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, }else {sg_copy_to_buffer (data->sg, data->sg_len, buf, data->blksz); - cmd->error =sd_write_data (host, _cmd, (u16 )data->blksz, buf, + cmd->error =sd_write_data (host, cmd, (u16 )data->blksz, buf, data->blksz,200 ); }
@@ -653,14 +697,14 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, u8 opcode, u8 sample_point) { int err; -u8 cmd[5 ] = {0 }; +struct mmc_command cmd = {0 }; err =sd_change_phase (host, sample_point, true);if (err <0 )return err; - cmd[0 ] =0x40 | opcode; - err =sd_read_data (host, cmd,0x40 ,NULL ,0 ,100 ); + cmd.opcode = opcode; + err =sd_read_data (host, &cmd,0x40 ,NULL ,0 ,100 );if (err <0 ) {/* Wait till SD DATA IDLE */ sd_wait_data_idle (host);
@@ -727,6 +771,12 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)return 0 ; } +static inline int sdio_extblock_cmd (struct mmc_command *cmd, +struct mmc_data *data) +{ +return (cmd->opcode ==SD_IO_RW_EXTENDED ) && (data->blksz ==512 ); +} +static inline int sd_rw_cmd (struct mmc_command *cmd) { return mmc_op_multi(cmd->opcode) ||
@@ -776,17 +826,15 @@ static void sd_request(struct work_struct *work)if (mrq->data) data_size = data->blocks * data->blksz; -if (!data_size ||sd_rw_cmd (cmd)) { +if (!data_size) {sd_send_cmd_get_rsp (host, cmd); + }else if (sd_rw_cmd (cmd) ||sdio_extblock_cmd (cmd, data)) { + cmd->error =sd_rw_multi (host, mrq); +if (!host->using_cookie) +sdmmc_post_req (host->mmc, host->mrq,0 ); -if (!cmd->error && data_size) { -sd_rw_multi (host, mrq); -if (!host->using_cookie) -sdmmc_post_req (host->mmc, host->mrq,0 ); - -if (mmc_op_multi (cmd->opcode) && mrq->stop) -sd_send_cmd_get_rsp (host, mrq->stop); - } +if (mmc_op_multi (cmd->opcode) && mrq->stop) +sd_send_cmd_get_rsp (host, mrq->stop); }else {sd_normal_rw (host, mrq); }
@@ -801,8 +849,10 @@ static void sd_request(struct work_struct *work)mutex_unlock (&pcr->pcr_mutex); finish: -if (cmd->error) -dev_dbg (sdmmc_dev (host),"cmd->error = %d\n" , cmd->error); +if (cmd->error) { +dev_err (sdmmc_dev (host),"CMD %d 0x%08x error(%d)\n" , + cmd->opcode, cmd->arg, cmd->error); + }mutex_lock (&host->host_mutex); host->mrq =NULL ;
@@ -820,7 +870,7 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq;mutex_unlock (&host->host_mutex); -if (sd_rw_cmd (mrq->cmd)) +if (sd_rw_cmd (mrq->cmd) ||sdio_extblock_cmd (mrq->cmd, data)) host->using_cookie =sd_pre_dma_transfer (host, data, false);queue_work (host->workq, &host->work);
@@ -1317,6 +1367,7 @@ static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev) {struct realtek_pci_sdmmc *host =platform_get_drvdata (pdev); + host->cookie =-1 ;mmc_detect_change (host->mmc,0 ); }
@@ -1349,6 +1400,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) host->pcr = pcr; host->mmc = mmc; host->pdev = pdev; + host->cookie =-1 ; host->power_state =SDMMC_POWER_OFF ;INIT_WORK (&host->work, sd_request);platform_set_drvdata (pdev, host);
Signature · 1 line
1.9.1
drivers/mmc/host/rtsx_pci_sdmmc.c static inline void sd_clear_error(struct realtek_pci_sdmmc *host) · line 79
Quoted 10 lines
#ifdef DEBUG
drivers/mmc/host/rtsx_pci_sdmmc.c +4
-4-static void sd_print_debug_regs (struct realtek_pci_sdmmc *host) +static void dump_reg_range (struct realtek_pci_sdmmc *host,u16 start,u16 end) { -struct rtsx_pcr *pcr = host->pcr; -u16 i; -u8 *ptr; +u16 len = end - start +1 ; +int i; +u8 *data =kzalloc (8 ,GFP_KERNEL );
The zeroing should be done inside the loop so that the last partial read doesn't have old data. Just use an array on the stack here.
u8 data[8];
Quoted 8 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +0
-7-/* Print SD host internal registers */ -rtsx_pci_init_cmd (pcr); -for (i =0xFDA0 ; i <=0xFDAE ; i++) -rtsx_pci_add_cmd (pcr,READ_REG_CMD , i,0 ,0 ); -for (i =0xFD52 ; i <=0xFD69 ; i++) -rtsx_pci_add_cmd (pcr,READ_REG_CMD , i,0 ,0 ); -rtsx_pci_send_cmd (pcr,100 );
drivers/mmc/host/rtsx_pci_sdmmc.c static inline void sd_clear_error(struct realtek_pci_sdmmc *host) · line 84
Quoted 10 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +4
-6- - ptr =rtsx_pci_get_cmd_data (pcr); -for (i =0xFDA0 ; i <=0xFDAE ; i++) -dev_dbg (sdmmc_dev (host),"0x%04X: 0x%02x\n" , i, *(ptr++)); -for (i =0xFD52 ; i <=0xFD69 ; i++) -dev_dbg (sdmmc_dev (host),"0x%04X: 0x%02x\n" , i, *(ptr++)); +if (!data) +return ; + +for (i =0 ; i < len; i +=8 , start +=8 ) {
I don't like this loop. Just leave start as is and write:
rtsx_pci_read_register(host->pcr, start + i + j, data + j);
drivers/mmc/host/rtsx_pci_sdmmc.c static inline void sd_clear_error(struct realtek_pci_sdmmc *host) · line 85
Quoted 1 line
drivers/mmc/host/rtsx_pci_sdmmc.c +1
-0+int j, n =min (8 , len - i);
Put these declarations on separate lines.
The memset I mentioned earlier goes here.
memset(&data, 0, sizeof(data));
Quoted 9 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +9
-0+ +for (j =0 ; j < n; j++) +rtsx_pci_read_register (host->pcr, start + j, data + j); +dev_dbg (sdmmc_dev (host),"0x%04X(%d): %8ph\n" , start, n, data); + } + +kfree (data); +} +
drivers/mmc/host/rtsx_pci_sdmmc.c static inline void sd_clear_error(struct realtek_pci_sdmmc *host) · line 104
Quoted 10 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +5
-0+static void sd_print_debug_regs (struct realtek_pci_sdmmc *host) +{ +dump_reg_range (host,0xFDA0 ,0xFDB3 ); +dump_reg_range (host,0xFD52 ,0xFD69 ); }#else #define sd_print_debug_regs (host)#endif /* DEBUG */ +static int sdmmc_get_cd (struct mmc_host *mmc);
This forward declaration is not needed.
drivers/mmc/host/rtsx_pci_sdmmc.c static inline void sd_clear_error(struct realtek_pci_sdmmc *host) · line 106
Quoted 2 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +2
-0+static void sd_send_cmd_get_rsp (struct realtek_pci_sdmmc *host, +struct mmc_command *cmd);
It's better to move the function forward, instead of having forward declarations.
drivers/mmc/host/rtsx_pci_sdmmc.c static inline void sd_clear_error(struct realtek_pci_sdmmc *host) · line 110
Quoted 4 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +4
-0+ +static void sd_cmd_set_sd_cmd (struct rtsx_pcr *pcr,struct mmc_command *cmd) +{ +rtsx_pci_add_cmd (pcr,WRITE_REG_CMD ,SD_CMD0 ,0xFF ,0x40 | cmd->opcode);
0x40 is a magic number.
Quoted 3 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +3
-0+rtsx_pci_write_be32 (pcr,SD_CMD1 , cmd->arg); +} +
[ snip ]
drivers/mmc/host/rtsx_pci_sdmmc.c static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, · line 332
Quoted 8 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +1
-3@@ -293,47 +329,15 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,int timeout =100 ;int i;u8 *ptr; -int stat_idx =0 ; -u8 rsp_type; -int rsp_len =5 ; +int rsp_type =sd_response_type (cmd);
Don't do this assignment in the initializer. Put it next to the error handling code. First we assign it. Then we use it. Then blank line. Then we check it for errors. Spagghetttii.
drivers/mmc/host/rtsx_pci_sdmmc.c static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, · line 333
Quoted 1 line
drivers/mmc/host/rtsx_pci_sdmmc.c +1
-0+int stat_idx =sd_status_index (rsp_type);
I have always hated this terrible pointer math. 5 is relative to pcr->host_cmds_ptr + 1. It's a mess... :(
Quoted 1 line
drivers/mmc/host/rtsx_pci_sdmmc.c +0
-0bool clock_toggled = false;
[ snip ]
Quoted 5 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +2
-1-static int sd_rw_multi (struct realtek_pci_sdmmc *host,struct mmc_request *mrq) +static int sd_read_long_data (struct realtek_pci_sdmmc *host, +struct mmc_request *mrq) {struct rtsx_pcr *pcr = host->pcr;
drivers/mmc/host/rtsx_pci_sdmmc.c out: · line 448
Quoted 10 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +3
-2struct mmc_host *mmc = host->mmc;struct mmc_card *card = mmc->card; +struct mmc_command *cmd = mrq->cmd;struct mmc_data *data = mrq->data;int uhs =mmc_card_uhs (card); -int read = (data->flags &MMC_DATA_READ ) ?1 :0 ; -u8 cfg2, trans_mode; +u8 cfg2 =0 ;int err; +int resp_type =sd_response_type (cmd);
Same thing. Move this next to the error handling code.
[ snip ]
drivers/mmc/host/rtsx_pci_sdmmc.c static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, · line 700
Quoted 6 lines
drivers/mmc/host/rtsx_pci_sdmmc.c +1
-1@@ -653,14 +697,14 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, u8 opcode, u8 sample_point) {int err; -u8 cmd[5 ] = {0 }; +struct mmc_command cmd = {0 };
I like the struct mmc_command changes but these seem like cleanups and not needed for the new hardware. Send them as a separate patch instead of mixed in with everything else.
regards,
dan carpenter
Quoted 3 lines · Dan Carpenter
drivers/mmc/host/rtsx_pci_sdmmc.c static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, · line 333
Quoted 1 line
drivers/mmc/host/rtsx_pci_sdmmc.c +1
-0+int stat_idx =sd_status_index (rsp_type);I have always hated this terrible pointer math. 5 is relative to
pcr->host_cmds_ptr+ 1. It's a mess...
5 mean CRC7 offset of Response R1, see SD spec V3.01 Page 82. 4.9.1 R1 (normal response command).
And we have to +1 to skip unused/undefined data.