forked from mirrors/linux
		
	mmc: core: support HPI send command
HPI command is defined in eMMC4.41. This feature is important for eMMC4.5 devices. Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
		
							parent
							
								
									881d1c25f7
								
							
						
					
					
						commit
						eb0d8f135b
					
				
					 7 changed files with 128 additions and 0 deletions
				
			
		| 
						 | 
					@ -379,6 +379,63 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(mmc_wait_for_req);
 | 
					EXPORT_SYMBOL(mmc_wait_for_req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	mmc_interrupt_hpi - Issue for High priority Interrupt
 | 
				
			||||||
 | 
					 *	@card: the MMC card associated with the HPI transfer
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Issued High Priority Interrupt, and check for card status
 | 
				
			||||||
 | 
					 *	util out-of prg-state.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int mmc_interrupt_hpi(struct mmc_card *card)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						u32 status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!card);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!card->ext_csd.hpi_en) {
 | 
				
			||||||
 | 
							pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mmc_claim_host(card->host);
 | 
				
			||||||
 | 
						err = mmc_send_status(card, &status);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If the card status is in PRG-state, we can send the HPI command.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * We don't know when the HPI command will finish
 | 
				
			||||||
 | 
								 * processing, so we need to resend HPI until out
 | 
				
			||||||
 | 
								 * of prg-state, and keep checking the card status
 | 
				
			||||||
 | 
								 * with SEND_STATUS.  If a timeout error occurs when
 | 
				
			||||||
 | 
								 * sending the HPI command, we are already out of
 | 
				
			||||||
 | 
								 * prg-state.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								err = mmc_send_hpi_cmd(card, &status);
 | 
				
			||||||
 | 
								if (err)
 | 
				
			||||||
 | 
									pr_debug("%s: abort HPI (%d error)\n",
 | 
				
			||||||
 | 
										 mmc_hostname(card->host), err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err = mmc_send_status(card, &status);
 | 
				
			||||||
 | 
								if (err)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						mmc_release_host(card->host);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(mmc_interrupt_hpi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 *	mmc_wait_for_cmd - start a command and wait for completion
 | 
					 *	mmc_wait_for_cmd - start a command and wait for completion
 | 
				
			||||||
 *	@host: MMC host to start command
 | 
					 *	@host: MMC host to start command
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -448,6 +448,21 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (card->ext_csd.rev >= 5) {
 | 
						if (card->ext_csd.rev >= 5) {
 | 
				
			||||||
 | 
							/* check whether the eMMC card supports HPI */
 | 
				
			||||||
 | 
							if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
 | 
				
			||||||
 | 
								card->ext_csd.hpi = 1;
 | 
				
			||||||
 | 
								if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
 | 
				
			||||||
 | 
									card->ext_csd.hpi_cmd =	MMC_STOP_TRANSMISSION;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * Indicate the maximum timeout to close
 | 
				
			||||||
 | 
								 * a command interrupted by HPI
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								card->ext_csd.out_of_int_time =
 | 
				
			||||||
 | 
									ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
 | 
							card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
 | 
				
			||||||
		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
 | 
							card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -895,6 +910,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Enable HPI feature (if supported)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (card->ext_csd.hpi) {
 | 
				
			||||||
 | 
							err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 | 
				
			||||||
 | 
								EXT_CSD_HPI_MGMT, 1, 0);
 | 
				
			||||||
 | 
							if (err && err != -EBADMSG)
 | 
				
			||||||
 | 
								goto free_card;
 | 
				
			||||||
 | 
							if (err) {
 | 
				
			||||||
 | 
								pr_warning("%s: Enabling HPI failed\n",
 | 
				
			||||||
 | 
									   mmc_hostname(card->host));
 | 
				
			||||||
 | 
								err = 0;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								card->ext_csd.hpi_en = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Compute bus speed.
 | 
						 * Compute bus speed.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -547,3 +547,34 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
 | 
				
			||||||
	err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
 | 
						err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mmc_command cmd = {0};
 | 
				
			||||||
 | 
						unsigned int opcode;
 | 
				
			||||||
 | 
						unsigned int flags;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opcode = card->ext_csd.hpi_cmd;
 | 
				
			||||||
 | 
						if (opcode == MMC_STOP_TRANSMISSION)
 | 
				
			||||||
 | 
							flags = MMC_RSP_R1 | MMC_CMD_AC;
 | 
				
			||||||
 | 
						else if (opcode == MMC_SEND_STATUS)
 | 
				
			||||||
 | 
							flags = MMC_RSP_R1 | MMC_CMD_AC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd.opcode = opcode;
 | 
				
			||||||
 | 
						cmd.arg = card->rca << 16 | 1;
 | 
				
			||||||
 | 
						cmd.flags = flags;
 | 
				
			||||||
 | 
						cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = mmc_wait_for_cmd(card->host, &cmd, 0);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							pr_warn("%s: error %d interrupting operation. "
 | 
				
			||||||
 | 
								"HPI command response %#x\n", mmc_hostname(card->host),
 | 
				
			||||||
 | 
								err, cmd.resp[0]);
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							*status = cmd.resp[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
 | 
				
			||||||
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 | 
					int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 | 
				
			||||||
int mmc_card_sleepawake(struct mmc_host *host, int sleep);
 | 
					int mmc_card_sleepawake(struct mmc_host *host, int sleep);
 | 
				
			||||||
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 | 
					int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 | 
				
			||||||
 | 
					int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,10 +69,14 @@ struct mmc_ext_csd {
 | 
				
			||||||
	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 | 
						unsigned long long	enhanced_area_offset;	/* Units: Byte */
 | 
				
			||||||
	unsigned int		enhanced_area_size;	/* Units: KB */
 | 
						unsigned int		enhanced_area_size;	/* Units: KB */
 | 
				
			||||||
	unsigned int		cache_size;		/* Units: KB */
 | 
						unsigned int		cache_size;		/* Units: KB */
 | 
				
			||||||
 | 
						bool			hpi_en;			/* HPI enablebit */
 | 
				
			||||||
 | 
						bool			hpi;			/* HPI support bit */
 | 
				
			||||||
 | 
						unsigned int		hpi_cmd;		/* cmd used as HPI */
 | 
				
			||||||
	u8			raw_partition_support;	/* 160 */
 | 
						u8			raw_partition_support;	/* 160 */
 | 
				
			||||||
	u8			raw_erased_mem_count;	/* 181 */
 | 
						u8			raw_erased_mem_count;	/* 181 */
 | 
				
			||||||
	u8			raw_ext_csd_structure;	/* 194 */
 | 
						u8			raw_ext_csd_structure;	/* 194 */
 | 
				
			||||||
	u8			raw_card_type;		/* 196 */
 | 
						u8			raw_card_type;		/* 196 */
 | 
				
			||||||
 | 
						u8			out_of_int_time;	/* 198 */
 | 
				
			||||||
	u8			raw_s_a_timeout;		/* 217 */
 | 
						u8			raw_s_a_timeout;		/* 217 */
 | 
				
			||||||
	u8			raw_hc_erase_gap_size;	/* 221 */
 | 
						u8			raw_hc_erase_gap_size;	/* 221 */
 | 
				
			||||||
	u8			raw_erase_timeout_mult;	/* 223 */
 | 
						u8			raw_erase_timeout_mult;	/* 223 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,6 +136,7 @@ struct mmc_async_req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
 | 
					extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
 | 
				
			||||||
					   struct mmc_async_req *, int *);
 | 
										   struct mmc_async_req *, int *);
 | 
				
			||||||
 | 
					extern int mmc_interrupt_hpi(struct mmc_card *);
 | 
				
			||||||
extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 | 
					extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 | 
				
			||||||
extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 | 
					extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
 | 
				
			||||||
extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
 | 
					extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,6 +276,7 @@ struct _mmc_csd {
 | 
				
			||||||
#define EXT_CSD_GP_SIZE_MULT		143	/* R/W */
 | 
					#define EXT_CSD_GP_SIZE_MULT		143	/* R/W */
 | 
				
			||||||
#define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 | 
					#define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 | 
				
			||||||
#define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 | 
					#define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 | 
				
			||||||
 | 
					#define EXT_CSD_HPI_MGMT		161	/* R/W */
 | 
				
			||||||
#define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
 | 
					#define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
 | 
				
			||||||
#define EXT_CSD_SANITIZE_START		165     /* W */
 | 
					#define EXT_CSD_SANITIZE_START		165     /* W */
 | 
				
			||||||
#define EXT_CSD_WR_REL_PARAM		166	/* RO */
 | 
					#define EXT_CSD_WR_REL_PARAM		166	/* RO */
 | 
				
			||||||
| 
						 | 
					@ -288,6 +289,7 @@ struct _mmc_csd {
 | 
				
			||||||
#define EXT_CSD_REV			192	/* RO */
 | 
					#define EXT_CSD_REV			192	/* RO */
 | 
				
			||||||
#define EXT_CSD_STRUCTURE		194	/* RO */
 | 
					#define EXT_CSD_STRUCTURE		194	/* RO */
 | 
				
			||||||
#define EXT_CSD_CARD_TYPE		196	/* RO */
 | 
					#define EXT_CSD_CARD_TYPE		196	/* RO */
 | 
				
			||||||
 | 
					#define EXT_CSD_OUT_OF_INTERRUPT_TIME	198	/* RO */
 | 
				
			||||||
#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 | 
					#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 | 
				
			||||||
#define EXT_CSD_PWR_CL_52_195		200	/* RO */
 | 
					#define EXT_CSD_PWR_CL_52_195		200	/* RO */
 | 
				
			||||||
#define EXT_CSD_PWR_CL_26_195		201	/* RO */
 | 
					#define EXT_CSD_PWR_CL_26_195		201	/* RO */
 | 
				
			||||||
| 
						 | 
					@ -311,6 +313,7 @@ struct _mmc_csd {
 | 
				
			||||||
#define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 | 
					#define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 | 
				
			||||||
#define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 | 
					#define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 | 
				
			||||||
#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
 | 
					#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
 | 
				
			||||||
 | 
					#define EXT_CSD_HPI_FEATURES		503	/* RO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * EXT_CSD field definitions
 | 
					 * EXT_CSD field definitions
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue