mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	mmc: core: Support UHS-II card control and access
Embed UHS-II access/control functionality into the MMC request processing flow. Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw> Message-ID: <20241018105333.4569-2-victorshihgli@gmail.com> [Ulf: A couple of cleanups and fixed sd_uhs2_power_off()] Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
		
							parent
							
								
									328bda09cc
								
							
						
					
					
						commit
						9a9f7e1395
					
				
					 8 changed files with 1103 additions and 37 deletions
				
			
		| 
						 | 
					@ -354,6 +354,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (host->uhs2_sd_tran)
 | 
				
			||||||
 | 
							mmc_uhs2_prepare_cmd(host, mrq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	led_trigger_event(host->led, LED_FULL);
 | 
						led_trigger_event(host->led, LED_FULL);
 | 
				
			||||||
	__mmc_start_request(host, mrq);
 | 
						__mmc_start_request(host, mrq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -453,6 +456,9 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out_err;
 | 
							goto out_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (host->uhs2_sd_tran)
 | 
				
			||||||
 | 
							mmc_uhs2_prepare_cmd(host, mrq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = host->cqe_ops->cqe_request(host, mrq);
 | 
						err = host->cqe_ops->cqe_request(host, mrq);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out_err;
 | 
							goto out_err;
 | 
				
			||||||
| 
						 | 
					@ -1135,7 +1141,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
 | 
						if (!mmc_card_uhs2(host) && host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
 | 
				
			||||||
		bit = ffs(ocr) - 1;
 | 
							bit = ffs(ocr) - 1;
 | 
				
			||||||
		ocr &= 3 << bit;
 | 
							ocr &= 3 << bit;
 | 
				
			||||||
		mmc_power_cycle(host, ocr);
 | 
							mmc_power_cycle(host, ocr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,7 +200,7 @@ static int mmc_decode_csd(struct mmc_card *card, bool is_sduc)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Given a 64-bit response, decode to our card SCR structure.
 | 
					 * Given a 64-bit response, decode to our card SCR structure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int mmc_decode_scr(struct mmc_card *card)
 | 
					int mmc_decode_scr(struct mmc_card *card)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sd_scr *scr = &card->scr;
 | 
						struct sd_scr *scr = &card->scr;
 | 
				
			||||||
	unsigned int scr_struct;
 | 
						unsigned int scr_struct;
 | 
				
			||||||
| 
						 | 
					@ -903,7 +903,7 @@ int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mmc_sd_get_ro(struct mmc_host *host)
 | 
					int mmc_sd_get_ro(struct mmc_host *host)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ro;
 | 
						int ro;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,8 @@ struct mmc_card;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
 | 
					int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
 | 
				
			||||||
int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc);
 | 
					int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc);
 | 
				
			||||||
 | 
					int mmc_decode_scr(struct mmc_card *card);
 | 
				
			||||||
 | 
					int mmc_sd_get_ro(struct mmc_host *host);
 | 
				
			||||||
void mmc_decode_cid(struct mmc_card *card);
 | 
					void mmc_decode_cid(struct mmc_card *card);
 | 
				
			||||||
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 | 
					int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 | 
				
			||||||
	bool reinit);
 | 
						bool reinit);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,15 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 | 
				
			||||||
	if (WARN_ON(card && card->host != host))
 | 
						if (WARN_ON(card && card->host != host))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * UHS2 packet has APP bit so only set APP_CMD flag here.
 | 
				
			||||||
 | 
						 * Will set the APP bit when assembling UHS2 packet.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (host->uhs2_sd_tran) {
 | 
				
			||||||
 | 
							host->uhs2_app_cmd = true;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd.opcode = MMC_APP_CMD;
 | 
						cmd.opcode = MMC_APP_CMD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (card) {
 | 
						if (card) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mmc_card;
 | 
					struct mmc_card;
 | 
				
			||||||
struct mmc_host;
 | 
					struct mmc_host;
 | 
				
			||||||
 | 
					struct mmc_request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mmc_app_set_bus_width(struct mmc_card *card, int width);
 | 
					int mmc_app_set_bus_width(struct mmc_card *card, int width);
 | 
				
			||||||
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 | 
					int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 | 
				
			||||||
| 
						 | 
					@ -22,6 +23,7 @@ int mmc_app_send_scr(struct mmc_card *card);
 | 
				
			||||||
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
 | 
					int mmc_app_sd_status(struct mmc_card *card, void *ssr);
 | 
				
			||||||
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
 | 
					int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
 | 
				
			||||||
int mmc_send_ext_addr(struct mmc_host *host, u32 addr);
 | 
					int mmc_send_ext_addr(struct mmc_host *host, u32 addr);
 | 
				
			||||||
 | 
					void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -11,6 +11,20 @@
 | 
				
			||||||
struct mmc_data;
 | 
					struct mmc_data;
 | 
				
			||||||
struct mmc_request;
 | 
					struct mmc_request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define UHS2_MAX_PAYLOAD_LEN 2
 | 
				
			||||||
 | 
					#define UHS2_MAX_RESP_LEN 20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct uhs2_command {
 | 
				
			||||||
 | 
						u16	header;
 | 
				
			||||||
 | 
						u16	arg;
 | 
				
			||||||
 | 
						__be32	payload[UHS2_MAX_PAYLOAD_LEN];
 | 
				
			||||||
 | 
						u8	payload_len;
 | 
				
			||||||
 | 
						u8	packet_len;
 | 
				
			||||||
 | 
						u8	tmode_half_duplex;
 | 
				
			||||||
 | 
						u8	uhs2_resp[UHS2_MAX_RESP_LEN];	/* UHS2 native cmd resp */
 | 
				
			||||||
 | 
						u8	uhs2_resp_len;			/* UHS2 native cmd resp len */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mmc_command {
 | 
					struct mmc_command {
 | 
				
			||||||
	u32			opcode;
 | 
						u32			opcode;
 | 
				
			||||||
	u32			arg;
 | 
						u32			arg;
 | 
				
			||||||
| 
						 | 
					@ -97,6 +111,8 @@ struct mmc_command {
 | 
				
			||||||
	struct mmc_data		*data;		/* data segment associated with cmd */
 | 
						struct mmc_data		*data;		/* data segment associated with cmd */
 | 
				
			||||||
	struct mmc_request	*mrq;		/* associated request */
 | 
						struct mmc_request	*mrq;		/* associated request */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct uhs2_command	*uhs2_cmd;	/* UHS2 command */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* for SDUC */
 | 
						/* for SDUC */
 | 
				
			||||||
	bool has_ext_addr;
 | 
						bool has_ext_addr;
 | 
				
			||||||
	u8 ext_addr;
 | 
						u8 ext_addr;
 | 
				
			||||||
| 
						 | 
					@ -158,6 +174,7 @@ struct mmc_request {
 | 
				
			||||||
	const struct bio_crypt_ctx *crypto_ctx;
 | 
						const struct bio_crypt_ctx *crypto_ctx;
 | 
				
			||||||
	int			crypto_key_slot;
 | 
						int			crypto_key_slot;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						struct uhs2_command	uhs2_cmd;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mmc_card;
 | 
					struct mmc_card;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,6 +127,13 @@ struct sd_uhs2_caps {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum sd_uhs2_operation {
 | 
					enum sd_uhs2_operation {
 | 
				
			||||||
 | 
						UHS2_PHY_INIT = 0,
 | 
				
			||||||
 | 
						UHS2_SET_CONFIG,
 | 
				
			||||||
 | 
						UHS2_ENABLE_INT,
 | 
				
			||||||
 | 
						UHS2_DISABLE_INT,
 | 
				
			||||||
 | 
						UHS2_ENABLE_CLK,
 | 
				
			||||||
 | 
						UHS2_DISABLE_CLK,
 | 
				
			||||||
 | 
						UHS2_CHECK_DORMANT,
 | 
				
			||||||
	UHS2_SET_IOS,
 | 
						UHS2_SET_IOS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -453,6 +460,8 @@ struct mmc_host {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#define MMC_CAP2_ALT_GPT_TEGRA	(1 << 28)	/* Host with eMMC that has GPT entry at a non-standard location */
 | 
					#define MMC_CAP2_ALT_GPT_TEGRA	(1 << 28)	/* Host with eMMC that has GPT entry at a non-standard location */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool			uhs2_sd_tran;	/* UHS-II flag for SD_TRAN state */
 | 
				
			||||||
 | 
						bool			uhs2_app_cmd;	/* UHS-II flag for APP command */
 | 
				
			||||||
	struct sd_uhs2_caps	uhs2_caps;	/* Host UHS-II capabilities */
 | 
						struct sd_uhs2_caps	uhs2_caps;	/* Host UHS-II capabilities */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int			fixed_drv_type;	/* fixed driver type for non-removable media */
 | 
						int			fixed_drv_type;	/* fixed driver type for non-removable media */
 | 
				
			||||||
| 
						 | 
					@ -714,6 +723,12 @@ static inline void mmc_debugfs_err_stats_inc(struct mmc_host *host,
 | 
				
			||||||
	host->err_stats[stat] += 1;
 | 
						host->err_stats[stat] += 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int mmc_card_uhs2_hd_mode(struct mmc_host *host)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return host->ios.timing == MMC_TIMING_UHS2_SPEED_A_HD ||
 | 
				
			||||||
 | 
						       host->ios.timing == MMC_TIMING_UHS2_SPEED_B_HD;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mmc_sd_switch(struct mmc_card *card, bool mode, int group,
 | 
					int mmc_sd_switch(struct mmc_card *card, bool mode, int group,
 | 
				
			||||||
		u8 value, u8 *resp);
 | 
							u8 value, u8 *resp);
 | 
				
			||||||
int mmc_send_status(struct mmc_card *card, u32 *status);
 | 
					int mmc_send_status(struct mmc_card *card, u32 *status);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue