@@ -262,6 +262,7 @@ struct mmc_card {
#define MMC_CARD_REMOVED (1<<4) /* card has been removed */
#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */
#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */
+#define MMC_STATE_UHSII (1<<12) /* card is in UHS-II mode */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -279,6 +280,15 @@ struct mmc_card {
#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */
#define MMC_QUIRK_BROKEN_IRQ_POLLING (1<<11) /* Polling SDIO_CCCR_INTx could create a fake interrupt */
+ u8 node_id; /* Node ID for UHS-II card */
+ u8 lane_mode;
+ u8 n_data_gap;
+ u8 max_retry_num;
+ u8 n_fcu;
+ u8 n_lss_dir;
+ u8 n_lss_syn;
+ u16 max_blklen;
+
unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
unsigned int pref_erase; /* in sectors */
@@ -423,6 +433,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_uhsii(c) ((c)->state & MMC_STATE_UHSII)
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
@@ -431,6 +442,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+#define mmc_card_set_uhsii(c) ((c)->state |= MMC_STATE_UHSII)
+#define mmc_card_clr_uhsii(c) ((c)->state &= ~MMC_STATE_UHSII)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
@@ -15,6 +15,57 @@ struct request;
struct mmc_data;
struct mmc_request;
+struct mmc_tlp_block {
+ u16 header;
+
+#define UHSII_HD_NP 0x8000
+#define UHSII_HD_TYP_MASK 0x7000
+#define UHSII_HD_TYP_CCMD (0 << 12)
+#define UHSII_HD_TYP_DCMD (1 << 12)
+#define UHSII_HD_TYP_RES (2 << 12)
+#define UHSII_HD_TYP_DATA (3 << 12)
+#define UHSII_HD_TYP_MSG (7 << 12)
+#define UHSII_HD_DID_SHIFT 8
+#define UHSII_HD_DID_MASK (0x0F << UHSII_HD_DID_SHIFT)
+#define UHSII_HD_SID_SHIFT 4
+#define UHSII_HD_SID_MASK (0x0F << UHSII_HD_SID_SHIFT)
+
+#define UHSII_HD_DID(val) ((val) << UHSII_HD_DID_SHIFT & UHSII_HD_DID_MASK)
+#define UHSII_CHK_CCMD(val) (((val) & UHSII_HD_TYP_MASK) == UHSII_HD_TYP_CCMD)
+#define UHSII_CHK_DCMD(val) (((val) & UHSII_HD_TYP_MASK) == UHSII_HD_TYP_DCMD)
+
+ u16 argument;
+#define UHSII_ARG_DIR_WRITE 0x8000
+#define UHSII_ARG_DIR_READ 0
+#define UHSII_ARG_PLEN_SHIFT 12
+#define UHSII_ARG_PLEN_MASK (0x03 << UHSII_ARG_PLEN_SHIFT)
+#define UHSII_ARG_IOADR_MASK 0x0FFF
+#define UHSII_ARG_RES_NACK 0x8000
+#define UHSII_ARG_TMODE_SHIFT 11
+#define UHSII_ARG_TMODE_MASK (0x0F << UHSII_ARG_TMODE_SHIFT)
+#define UHSII_TMODE_DM_HD 0x08
+#define UHSII_TMODE_LM_SPECIFIED 0x04
+#define UHSII_TMODE_TLUM_BYTE 0x02
+#define UHSII_TMODE_DAM_FIX 0x01
+#define UHSII_ARG_APP_CMD 0x40
+#define UHSII_ARG_CMD_INDEX_MASK 0x3F
+
+#define UHSII_PLEN_BYTES(plen) ((plen) ? 2 << (plen) : 0)
+#define UHSII_PLEN_DWORDS(plen) ((plen) == 3 ? 4 : (plen))
+
+#define UHSII_GET_PLEN(tlp_block) \
+ ((u8)(((tlp_block)->argument & UHSII_ARG_PLEN_MASK) \
+ >> UHSII_ARG_PLEN_SHIFT))
+#define UHSII_GET_TMODE(tlp_block) \
+ ((u8)(((tlp_block)->argument & UHSII_ARG_TMODE_MASK) \
+ >> UHSII_ARG_TMODE_SHIFT))
+
+ u32 payload[4];
+#define UHSII_GET_GAP(tlp_block) \
+ ((u8)(((tlp_block)->payload[0] >> SD40_GAP_SHIFT) \
+ & SD40_GAP_MASK))
+};
+
struct mmc_command {
u32 opcode;
u32 arg;
@@ -101,6 +152,10 @@ struct mmc_command {
struct mmc_data *data; /* data segment associated with cmd */
struct mmc_request *mrq; /* associated request */
+
+ struct mmc_tlp_block tlp_send;
+ bool use_tlp;
+ bool app_cmd;
};
struct mmc_data {
@@ -125,18 +180,51 @@ struct mmc_data {
s32 host_cookie; /* host private data */
};
+struct mmc_tlp {
+ struct mmc_tlp_block *tlp_send;
+ struct mmc_tlp_block *tlp_back;
+
+ u8 cmd_type;
+#define UHSII_COMMAND_NORMAL 0x00
+#define UHSII_COMMAND_GO_DORMANT 0x03
+
+ unsigned int retries; /* max number of retries */
+ int error;
+};
+
struct mmc_host;
struct mmc_request {
struct mmc_command *sbc; /* SET_BLOCK_COUNT for multiblock */
struct mmc_command *cmd;
struct mmc_data *data;
struct mmc_command *stop;
+ struct mmc_tlp *tlp;
struct completion completion;
void (*done)(struct mmc_request *);/* completion function */
struct mmc_host *host;
};
+static inline void mmc_set_mrq_error_code(struct mmc_request *mrq, int err)
+{
+ if (mrq->cmd)
+ mrq->cmd->error = err;
+ else
+ mrq->tlp->error = err;
+}
+
+static inline int mmc_get_mrq_error_code(struct mmc_request *mrq)
+{
+ int err;
+
+ if (mrq->cmd)
+ err = mrq->cmd->error;
+ else
+ err = mrq->tlp->error;
+
+ return err;
+}
+
struct mmc_card;
struct mmc_async_req;
@@ -78,6 +78,23 @@ struct mmc_ios {
#define MMC_SET_DRIVER_TYPE_D 3
};
+struct mmc_uhsii_ios {
+ u8 speed_range;
+#define SD_UHSII_SPEED_RANGE_A 0
+#define SD_UHSII_SPEED_RANGE_B 1
+
+ u8 n_fcu;
+
+ u8 pwr_ctl_mode;
+#define SD_UHSII_PWR_CTL_FAST_MODE 0
+#define SD_UHSII_PWR_CTL_LOW_PWR_MODE 1
+
+ u32 flags;
+#define SETTING_SPEED_RANGE (1 << 0)
+#define SETTING_N_FCU (1 << 1)
+#define SETTING_PWR_CTL_MODE (1 << 2)
+};
+
struct mmc_host_ops {
/*
* It is optional for the host to implement pre_req and post_req in
@@ -135,6 +152,10 @@ struct mmc_host_ops {
void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host);
+ int (*switch_uhsii_if)(struct mmc_host *host);
+ int (*exit_dormant)(struct mmc_host *host);
+ void (*set_uhsii_ios)(struct mmc_host *host,
+ struct mmc_uhsii_ios *ios);
/*
* Optional callback to support controllers with HW issues for multiple
* I/O. Returns the number of supported blocks for the request.
@@ -257,6 +278,7 @@ struct mmc_host {
#define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
#define MMC_CAP_RUNTIME_RESUME (1 << 20) /* Resume at runtime_resume. */
+#define MMC_CAP_UHSII (1 << 21) /* Host supports UHS-II mode */
#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
@@ -285,6 +307,8 @@ struct mmc_host {
MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
+#define MMC_CAP2_UHSII_RANGE_AB (1 << 18) /* Supported speed range */
+#define MMC_CAP2_UHSII_LOW_PWR (1 << 19) /* Support UHS-II low power */
mmc_pm_flag_t pm_caps; /* supported pm features */
@@ -300,6 +324,15 @@ struct mmc_host {
unsigned long clkgate_delay;
#endif
+ u8 lane_mode;
+ u8 max_gap;
+ u8 max_dap;
+ u8 n_data_gap;
+ u8 n_fcu;
+ u8 n_lss_dir;
+ u8 n_lss_syn;
+ struct mmc_uhsii_ios uhsii_ios;
+
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_segs; /* see blk_queue_max_segments */
@@ -91,4 +91,77 @@
#define SD_SWITCH_ACCESS_DEF 0
#define SD_SWITCH_ACCESS_HS 1
+#define UHSII_IOADR(base, reg) (((u16)(base) << 8) | (reg))
+#define UHSII_IOADR_BASE(arg) (((arg) >> 8) & 0x0F)
+#define UHSII_IOADR_OFFSET(arg) ((arg) & 0xFF)
+
+/* IOADR of Generic Capabilities Register (DW) */
+#define SD40_IOADR_GEN_CAP_L 0x00
+#define SD40_IOADR_GEN_CAP_H 0x01
+
+/* IOADR of PHY Capabilities Register (DW) */
+#define SD40_IOADR_PHY_CAP_L 0x02
+#define SD40_IOADR_PHY_CAP_H 0x03
+
+/* IOADR LINK/TRAN Capabilities Register (DW) */
+#define SD40_IOADR_LINK_CAP_L 0x04
+#define SD40_IOADR_LINK_CAP_H 0x05
+
+#define SD40_IOADR_GEN_SET_L 0x08
+#define SD40_IOADR_GEN_SET_H 0x09
+
+#define SD40_IOADR_PHY_SET_L 0x0A
+#define SD40_IOADR_PHY_SET_H 0x0B
+
+#define SD40_IOADR_LINK_SET_L 0x0C
+#define SD40_IOADR_LINK_SET_H 0x0D
+
+/* Node ID (First or Last) ENUMERATE */
+#define SD40_IDL_SHIFT 24
+#define SD40_IDL_MASK (0x0F << SD40_IDL_SHIFT)
+
+/* SD40 I/O Address space offset */
+#define SD40_IOADR_CFG_BASE 0x00 /*000h : 0FFh*/
+#define SD40_IOADR_INT_BASE 0x01 /*100h : 17Fh*/
+#define SD40_IOADR_ST_BASE 0x01 /*180h : 1FFh*/
+#define SD40_IOADR_CMD_BASE 0x02 /*200h : 2FFh*/
+#define SD40_IOADR_VENDOR_BASE 0x0F /*F00h : FFFh*/
+
+/* Command Register (CMD_REG). DW, Base on IOADR_CMD_BASE */
+#define SD40_FULL_RESET 0x00
+#define SD40_GO_DORMANT_STATE 0x01
+#define SD40_DEVICE_INIT 0x02
+#define SD40_ENUMERATE 0x03
+#define SD40_TRANS_ABORT 0x04
+
+/* DEVICE_INIT */
+#define SD40_GD_SHIFT 28
+#define SD40_GD_MASK (0x0F << SD40_GD_SHIFT)
+#define SD40_GAP_SHIFT 24
+#define SD40_GAP_MASK (0x0F << SD40_GAP_SHIFT)
+#define SD40_DAP_SHIFT 20
+#define SD40_DAP_MASK (0x0F << SD40_DAP_SHIFT)
+#define SD40_CF 0x80000
+
+#define SD40_GD(val) (((val) << SD40_GD_SHIFT) & SD40_GD_MASK)
+#define SD40_GAP(val) (((val) << SD40_GAP_SHIFT) & SD40_GAP_MASK)
+#define SD40_DAP(val) (((val) << SD40_DAP_SHIFT) & SD40_DAP_MASK)
+
+/* Generic Capabilities Register */
+#define SD40_LANE_MODE_SHIFT 8
+#define SD40_LANE_MODE_MASK (0x3F << SD40_LANE_MODE_SHIFT)
+#define SD40_LANE_MODE_2L_HD 0x01
+#define SD40_LANE_MODE_2D1U_FD 0x02
+#define SD40_LANE_MODE_1D2U_FD 0x04
+#define SD40_LANE_MODE_2D2U_FD 0x08
+
+#define SD40_APP_TYPE_MASK 0x07
+#define SD40_APP_TYPE_SD_MEMORY 0x01
+#define SD40_APP_TYPE_SDIO 0x02
+#define SD40_APP_TYPE_EMBEDDED 0x04
+
+/* Generic Settings Register */
+#define SD40_CONFIG_COMPLETE 0x80000000
+#define SD40_LOW_PWR_MODE 0x01
+
#endif /* LINUX_MMC_SD_H */