mmc子系统分析(二)


前言

mmc子系统的第二篇,介绍mmc host controller driver有关的知识,如果在linux kernel mmc 的框架下,编写和修改mmc控制器的驱动程序。实际上大部分芯片的mmc host controller driver已经由原厂的开发工程师写好了,我们要做的是配置设备树和在遇到问题是去排产和修改原厂的mmc host controller driver。


一、mcc host驱动介绍

mmc的host driver,是用于驱动mmc host控制器的程序,这一部分的是实现是和具体的CPU是息息相关的,位于drivers/mmc/host目录。
从流程上看,一个mmc host driver的实现,需要三步:

1、调用mmc_alloc_host,分配一个struct mmc_host类型的变量,用于描述具体的硬件controller的mmc 控制器。
2、根据mmc host控制器的硬件特性,填充struct mmc_host的各个字段,例如mmc的电压范围、mmc的工作频率、mmc操作相关的函数集等。
3、调用mmc_add_host接口,将创建的mmc host注册到mmc core中。

mmc host driver和具体的硬件controller是高度相关的,不同平台的实现是有区别的。比如全志平台的T507可以参考drivers/mmc/host/sunxi-mmc.c

二、相关数据结构

1.struct mmc_host

mmc_host结构体定义位于include/linux/mmc/host.h
mmc core使用struct mmc_host结构抽象了具体的mmc host controller,可以用来描述mmc控制器的特性、能力(host driver需要设置),也用来保存host driver运行过程中的一些状态、和参数。结合具体的代码进行说明:

struct mmc_host {
	struct device		*parent; /*指向该mmc host的父设备,一般是注册该host的platform设备*/
	struct device		class_dev; /*该mmc host在设备模型中作为一个设备的体现,该设备从属于某一个class(mmc_host_class)*/
	int			index;
	const struct mmc_host_ops *ops; /*保存了该mmc host有关的操作函数集*/
	struct mmc_pwrseq	*pwrseq; /*该mmc host电源管理有关的操作函数集*/
	unsigned int		f_min; /*mmc host支持的最小时钟频率*/
	unsigned int		f_max; /*mmc host支持的最大时钟频率*/
	unsigned int		f_init; /*mmc host支持的初始频率*/
	u32			ocr_avail; /*OCR(Operating Conditions Register)是MMC/SD/SDIO卡的一个32-bit的寄存器,其中有些bit指明了该卡的操作电压。MMC host在驱动这些卡的时候,需要和Host自身所支持的电压范围匹配之后,才能正常操作,这就是ocr_avail的存在意义。*/
	u32			ocr_avail_sdio;	/* SDIO-specific OCR */
	u32			ocr_avail_sd;	/* SD-specific OCR */
	u32			ocr_avail_mmc;	/* MMC-specific OCR */
#ifdef CONFIG_PM_SLEEP
	struct notifier_block	pm_notify; /*支持电源管理有关的notify实现*/
#endif
	u32			max_current_330; /*当工作电压3.3V时,支持的最大操作电流*/
	u32			max_current_300; /*当工作电压3V时,支持的最大操作电流*/
	u32			max_current_180; /*当工作电压1.8V时,支持的最大操作电流*/

#define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22		0x00000200	/* VDD voltage 2.1 ~ 2.2 */
#define MMC_VDD_22_23		0x00000400	/* VDD voltage 2.2 ~ 2.3 */
#define MMC_VDD_23_24		0x00000800	/* VDD voltage 2.3 ~ 2.4 */
#define MMC_VDD_24_25		0x00001000	/* VDD voltage 2.4 ~ 2.5 */
#define MMC_VDD_25_26		0x00002000	/* VDD voltage 2.5 ~ 2.6 */
#define MMC_VDD_26_27		0x00004000	/* VDD voltage 2.6 ~ 2.7 */
#define MMC_VDD_27_28		0x00008000	/* VDD voltage 2.7 ~ 2.8 */
#define MMC_VDD_28_29		0x00010000	/* VDD voltage 2.8 ~ 2.9 */
#define MMC_VDD_29_30		0x00020000	/* VDD voltage 2.9 ~ 3.0 */
#define MMC_VDD_30_31		0x00040000	/* VDD voltage 3.0 ~ 3.1 */
#define MMC_VDD_31_32		0x00080000	/* VDD voltage 3.1 ~ 3.2 */
#define MMC_VDD_32_33		0x00100000	/* VDD voltage 3.2 ~ 3.3 */
#define MMC_VDD_33_34		0x00200000	/* VDD voltage 3.3 ~ 3.4 */
#define MMC_VDD_34_35		0x00400000	/* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36		0x00800000	/* VDD voltage 3.5 ~ 3.6 */

	u32			caps;		/* Host capabilities 功能特性*/

#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
#define MMC_CAP_MMC_HIGHSPEED	(1 << 1)	/* Can do MMC high-speed timing */
#define MMC_CAP_SD_HIGHSPEED	(1 << 2)	/* Can do SD high-speed timing */
#define MMC_CAP_SDIO_IRQ	(1 << 3)	/* Can signal pending SDIO IRQs */
#define MMC_CAP_SPI		(1 << 4)	/* Talks only SPI protocols */
#define MMC_CAP_NEEDS_POLL	(1 << 5)	/* Needs polling for card-detection */
#define MMC_CAP_8_BIT_DATA	(1 << 6)	/* Can the host do 8 bit transfers */
#define MMC_CAP_AGGRESSIVE_PM	(1 << 7)	/* Suspend (e)MMC/SD at idle  */
#define MMC_CAP_NONREMOVABLE	(1 << 8)	/* Nonremovable e.g. eMMC */
#define MMC_CAP_WAIT_WHILE_BUSY	(1 << 9)	/* Waits while card is busy */
#define MMC_CAP_ERASE		(1 << 10)	/* Allow erase/trim commands */
#define MMC_CAP_1_8V_DDR	(1 << 11)	/* can support */
						/* DDR mode at 1.8V */
#define MMC_CAP_1_2V_DDR	(1 << 12)	/* can support */
						/* DDR mode at 1.2V */
#define MMC_CAP_POWER_OFF_CARD	(1 << 13)	/* Can power off after boot */
#define MMC_CAP_BUS_WIDTH_TEST	(1 << 14)	/* CMD14/CMD19 bus width ok */
#define MMC_CAP_UHS_SDR12	(1 << 15)	/* Host supports UHS SDR12 mode */
#define MMC_CAP_UHS_SDR25	(1 << 16)	/* Host supports UHS SDR25 mode */
#define MMC_CAP_UHS_SDR50	(1 << 17)	/* Host supports UHS SDR50 mode */
#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_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 */
#define MMC_CAP_CMD_DURING_TFR	(1 << 29)	/* Commands during data transfer */
#define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */
#define MMC_CAP_HW_RESET	(1 << 31)	/* Hardware reset */

	u32			caps2;		/* More host capabilities */

#define MMC_CAP2_BOOTPART_NOACC	(1 << 0)	/* Boot partition no access */
#define MMC_CAP2_FULL_PWR_CYCLE	(1 << 2)	/* Can do full power cycle */
#define MMC_CAP2_CACHE_CTRL	(1 << 1)	/* Allow cache control */
#define MMC_CAP2_HS200_1_8V_SDR	(1 << 5)        /* can support */
#define MMC_CAP2_HS200_1_2V_SDR	(1 << 6)        /* can support */
#define MMC_CAP2_HS200		(MMC_CAP2_HS200_1_8V_SDR | \
				 MMC_CAP2_HS200_1_2V_SDR)
#define MMC_CAP2_HC_ERASE_SZ	(1 << 9)	/* High-capacity erase size */
#define MMC_CAP2_CD_ACTIVE_HIGH	(1 << 10)	/* Card-detect signal active high */
#define MMC_CAP2_RO_ACTIVE_HIGH	(1 << 11)	/* Write-protect signal active high */
#define MMC_CAP2_PACKED_RD	(1 << 12)	/* Allow packed read */
#define MMC_CAP2_PACKED_WR	(1 << 13)	/* Allow packed write */
#define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
				 MMC_CAP2_PACKED_WR)
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
#define MMC_CAP2_HS400_1_8V	(1 << 15)	/* Can support HS400 1.8V */
#define MMC_CAP2_HS400_1_2V	(1 << 16)	/* Can support HS400 1.2V */
#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
				 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_NO_WRITE_PROTECT (1 << 18)	/* No physical write protect pin, assume that card is always read-write */
#define MMC_CAP2_NO_SDIO	(1 << 19)	/* Do not send SDIO commands during initialization */
#define MMC_CAP2_HS400_ES	(1 << 20)	/* Host supports enhanced strobe */
#define MMC_CAP2_NO_SD		(1 << 21)	/* Do not send SD commands during initialization */
#define MMC_CAP2_NO_MMC		(1 << 22)	/* Do not send (e)MMC commands during initialization */

#define MMC_SUNXI_CAP3_DAT3_DET	(1 << 0)
#define MMC_SUNXI_CAP3_CD_USED_24M	(1 << 1)
	u32		sunxi_caps3;


	mmc_pm_flag_t		pm_caps;	/* supported pm features */

	/* host specific block data */
	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
	unsigned short		max_segs;	/* see blk_queue_max_segments */
	unsigned short		unused;
	unsigned int		max_req_size;	/* maximum number of bytes in one req */
	unsigned int		max_blk_size;	/* maximum size of one mmc block */
	unsigned int		max_blk_count;	/* maximum number of blocks in one req */
	unsigned int		max_busy_timeout; /* max busy timeout in ms */

	/* private data */
	spinlock_t		lock;		/* lock for claim and bus ops */

	struct mmc_ios		ios;		/* current io bus settings */

	/* 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		can_retune:1;	/* re-tuning can be used */
	unsigned int		doing_retune:1;	/* re-tuning in progress */
	unsigned int		retune_now:1;	/* do re-tuning at next req */
	unsigned int		retune_paused:1; /* re-tuning is temporarily disabled */

	int			rescan_disable;	/* disable card detection */
	int			rescan_entered;	/* used with nonremovable devices */

	int			need_retune;	/* re-tuning is needed */
	int			hold_retune;	/* hold off re-tuning */
	unsigned int		retune_period;	/* re-tuning period in secs */
	struct timer_list	retune_timer;	/* for periodic re-tuning */

	bool			trigger_card_event; /* card_event necessary */

	struct mmc_card		*card;		/* device attached to this host */

	wait_queue_head_t	wq;
	struct task_struct	*claimer;	/* task that has host claimed */
	int			claim_cnt;	/* "claim" nesting count */

	struct delayed_work	detect;
	int			detect_change;	/* card detect flag */
	struct mmc_slot		slot;

	const struct mmc_bus_ops *bus_ops;	/* current bus driver */
	unsigned int		bus_refs;	/* reference counter */

	unsigned int		sdio_irqs;
	struct task_struct	*sdio_irq_thread;
	bool			sdio_irq_pending;
	atomic_t		sdio_irq_thread_abort;

	mmc_pm_flag_t		pm_flags;	/* requested pm features */

	struct led_trigger	*led;		/* activity led */

#ifdef CONFIG_REGULATOR
	bool			regulator_enabled; /* regulator state */
#endif
	struct mmc_supply	supply;

	struct dentry		*debugfs_root;

	struct mmc_async_req	*areq;		/* active async req */
	struct mmc_context_info	context_info;	/* async synchronization info */

	/* Ongoing data transfer that allows commands during transfer */
	struct mmc_request	*ongoing_mrq;

#ifdef CONFIG_FAIL_MMC_REQUEST
	struct fault_attr	fail_mmc_request;
#endif

	unsigned int		actual_clock;	/* Actual HC clock rate */

	unsigned int		slotno;	/* used for sdio acpi binding */

	int			dsr_req;	/* DSR value is valid */
	u32			dsr;	/* optional driver stage (DSR) value */

#ifdef CONFIG_MMC_EMBEDDED_SDIO
	struct {
		struct sdio_cis			*cis;
		struct sdio_cccr		*cccr;
		struct sdio_embedded_func	*funcs;
		int				num_funcs;
	} embedded_sdio_data;
#endif

#ifdef CONFIG_BLOCK
	int			latency_hist_enabled;
	struct io_latency_state io_lat_read;
	struct io_latency_state io_lat_write;
#endif

	unsigned long		private[0] ____cacheline_aligned;
};

2.struct mmc_host_ops

mmc_host_ops 抽象了mmc host controller所有的操作函数集:
代码如下(示例):

struct mmc_host_ops {
	/*
	 * It is optional for the host to implement pre_req and post_req in
	 * order to support double buffering of requests (prepare one
	 * request while another request is active).
	 * pre_req() must always be followed by a post_req().
	 * To undo a call made to pre_req(), call post_req() with
	 * a nonzero err condition.
	 */
	 /* pre_req和post_req是非必需的,host driver可以利用他们实现双buffer之类的高级功能*/
	 /* 数据传输主要是通过request */
	void	(*post_req)(struct mmc_host *host, struct mmc_request *req,
			    int err);
	void	(*pre_req)(struct mmc_host *host, struct mmc_request *req,
			   bool is_first_req);
	void	(*request)(struct mmc_host *host, struct mmc_request *req);

	/*
	 * Avoid calling the next three functions too often or in a "fast
	 * path", since underlaying controller might implement them in an
	 * expensive and/or slow way. Also note that these functions might
	 * sleep, so don't call them in the atomic contexts!
	 */
	
	/*
	 * Notes to the set_ios callback:
	 * ios->clock might be 0. For some controllers, setting 0Hz
	 * as any other frequency works. However, some controllers
	 * explicitly need to disable the clock. Otherwise e.g. voltage
	 * switching might fail because the SDCLK is not really quiet.
	 */
	/* 总线参数的设置 */
	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);

	/*
	 * Return values for the get_ro callback should be:
	 *   0 for a read/write card
	 *   1 for a read-only card
	 *   -ENOSYS when not supported (equal to NULL callback)
	 *   or a negative errno value when something bad happened
	 */
	 /* 卡状态的获取 */
	int	(*get_ro)(struct mmc_host *host);

	/*
	 * Return values for the get_cd callback should be:
	 *   0 for a absent card
	 *   1 for a present card
	 *   -ENOSYS when not supported (equal to NULL callback)
	 *   or a negative errno value when something bad happened
	 */
	 /* 检测卡的在位状态 */
	int	(*get_cd)(struct mmc_host *host);

	void	(*enable_sdio_irq)(struct mmc_host *host, int enable);

	/* optional callback for HC quirks */
	void	(*init_card)(struct mmc_host *host, struct mmc_card *card);

	int	(*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);

	/* Check if the card is pulling dat[0:3] low */
	int	(*card_busy)(struct mmc_host *host);

	/* The tuning command opcode value is different for SD and eMMC cards */
	int	(*execute_tuning)(struct mmc_host *host, u32 opcode);

	/* Prepare HS400 target operating frequency depending host driver */
	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
	/* Prepare enhanced strobe depending host driver */
	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
					 struct mmc_ios *ios);
	int	(*select_drive_strength)(struct mmc_card *card,
					 unsigned int max_dtr, int host_drv,
					 int card_drv, int *drv_type);
	void	(*hw_reset)(struct mmc_host *host);
	void	(*card_event)(struct mmc_host *host);

	/*
	 * Optional callback to support controllers with HW issues for multiple
	 * I/O. Returns the number of supported blocks for the request.
	 */
	int	(*multi_io_quirk)(struct mmc_card *card,
				  unsigned int direction, int blk_size);
};

3.struct mmc_pwrseq

power sequence是一个有意思的功能,它提供一个名称为struct mmc_pwrseq_ops的操作函数集合,集合了
power on、power off等操作函数,用于控制mmc系统的供电,struct mmc_pwrseq定义于drivers/mmc/core/pwrseq.h中

struct mmc_pwrseq_ops {
	void (*pre_power_on)(struct mmc_host *host);
	void (*post_power_on)(struct mmc_host *host);
	void (*power_off)(struct mmc_host *host);
};
struct mmc_pwrseq {
	const struct mmc_pwrseq_ops *ops;
	struct device *dev;
	struct list_head pwrseq_node;
	struct module *owner;
};

mmc core中提供了一个通用的pwrseq的管理模块位于drivers/mmc/core/pwrseq.c,以及一些简单的pwrseq策略位于drivers/mmc/core/pwrseq_simple.c 、pwrseq_emmc.c,我们可以通过dts配置就可以正确的配置mmc的供电。

4.struct mmc_ios

struct mmc_ios(include/linux/mmc/host.h)中保存了mmc总线的配置情况:

struct mmc_ios {
	unsigned int	clock;			/* clock rate */
	unsigned short	vdd;			/*卡的供电电压*/
/* vdd stores the bit number of the selected voltage range from below. */

	unsigned char	bus_mode;		/* command output mode 信号模式*/

#define MMC_BUSMODE_OPENDRAIN	1	
#define MMC_BUSMODE_PUSHPULL	2

	unsigned char	chip_select;		/* SPI chip select ,针对spi模式*/

#define MMC_CS_DONTCARE		0
#define MMC_CS_HIGH		1
#define MMC_CS_LOW		2

	unsigned char	power_mode;		/* power supply mode 电源状态*/

#define MMC_POWER_OFF		0
#define MMC_POWER_UP		1
#define MMC_POWER_ON		2
#define MMC_POWER_UNDEFINED	3

	unsigned char	bus_width;		/* data bus width 总线宽度*/

#define MMC_BUS_WIDTH_1		0
#define MMC_BUS_WIDTH_4		2
#define MMC_BUS_WIDTH_8		3

	unsigned char	timing;			/* timing specification used 总线时序*/

#define MMC_TIMING_LEGACY	0
#define MMC_TIMING_MMC_HS	1
#define MMC_TIMING_SD_HS	2
#define MMC_TIMING_UHS_SDR12	3
#define MMC_TIMING_UHS_SDR25	4
#define MMC_TIMING_UHS_SDR50	5
#define MMC_TIMING_UHS_SDR104	6
#define MMC_TIMING_UHS_DDR50	7
#define MMC_TIMING_MMC_DDR52	8
#define MMC_TIMING_MMC_HS200	9
#define MMC_TIMING_MMC_HS400	10

	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) 总线信号电压*/

#define MMC_SIGNAL_VOLTAGE_330	0
#define MMC_SIGNAL_VOLTAGE_180	1
#define MMC_SIGNAL_VOLTAGE_120	2

	unsigned char	drv_type;		/* driver type (A, B, C, D) 驱动能力*/

#define MMC_SET_DRIVER_TYPE_B	0
#define MMC_SET_DRIVER_TYPE_A	1
#define MMC_SET_DRIVER_TYPE_C	2
#define MMC_SET_DRIVER_TYPE_D	3

	bool enhanced_strobe;			/* hs400es selection */
};

5.struct mmc_supply

struct mmc_supply中保存了struct regulator指针(如下),用于控制MMC子系统有关的供电。

struct mmc_supply {
	struct regulator *vmmc;		/* Card power supply 卡的供电电压*/
	struct regulator *vqmmc;	/* Optional Vccq supply 信号线*/
	struct regulator *vdmmc;	/* Optional card detect pin supply 卡在位检测管脚电压*/
	struct regulator *vdmmc33sw;	/* SD card PMU control*/
	struct regulator *vdmmc18sw;
	struct regulator *vqmmc33sw;	/* SD card PMU control*/
	struct regulator *vqmmc18sw;
};

6.struct mmc_request

struct mmc_request(include/linux/mmc/core.h)封装了一次传输请求:

struct mmc_request {
	struct mmc_command	*sbc;		/* SET_BLOCK_COUNT for multiblock */
	struct mmc_command	*cmd;		/*Start Command,在一次传输过程中是必需的*/
	struct mmc_data		*data;		/*传输数据,不是必需的*/
	struct mmc_command	*stop;

	struct completion	completion;	/* 等待传输完成 */
	struct completion	cmd_completion;
	void			(*done)(struct mmc_request *);/* completion function 传输完成时回调,通知传输请求的发起者*/
	struct mmc_host		*host;

	/* Allow other commands during this ongoing data transfer or busy wait */
	bool			cap_cmd_during_tfr;
	ktime_t			io_start;
#ifdef CONFIG_BLOCK
	int			lat_hist_enabled;
#endif
};

一次传输可以有四种情况:
不需要应答,不需要传输数据的command;
需要应答,不需要传输数据的command;
不需要映带、需要传输数据的command;
不需要应答,不需要传输数据的command;

command token的格式只有一种,长度为48bits,包含start bit[0]、transmitter bit[1, host command]、content[38bits]、CRC checksum[7bits]、stop bit[1]

对于包含了Data token的command,有两种类型:
sequential commands,发送start command之后,数据以stream的形式传输,直到stop command为止。这种方式只支持1bit总线。
block-oriented commands,发送start command之后,数据以block的形式传输(每个block大小固定,通过CRC进行校验)

response token的格式有5种,R1/R3/R4/R5/R2,其中R1/R3/R4/5为48bits,R2为136bits

7.struct mmc_command

struct mmc_command结构体(include/linux/mmc/core.h)用于描述mmc command,定义如下:

struct mmc_command {
	u32			opcode;	/* command 操作码,用于标识命令 */
	u32			arg;	/* command 携带的参数 */
#define MMC_CMD23_ARG_REL_WR	(1 << 31)
#define MMC_CMD23_ARG_PACKED	((0 << 31) | (1 << 30))
#define MMC_CMD23_ARG_TAG_REQ	(1 << 29)
	u32			resp[4];	/* command 对应的应答 */
	unsigned int		flags;		/* expected response type */
#define MMC_RSP_PRESENT	(1 << 0)	/* 为0表示不需要应答;为1表示需要应答*/
#define MMC_RSP_136	(1 << 1)		/* 为1表示 136 bit response */
#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)		/* 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 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 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.
 */
#define MMC_RSP_NONE	(0)
#define MMC_RSP_R1	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R1B	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
#define MMC_RSP_R2	(MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
#define MMC_RSP_R3	(MMC_RSP_PRESENT)
#define MMC_RSP_R4	(MMC_RSP_PRESENT)
#define MMC_RSP_R5	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R6	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
#define MMC_RSP_R7	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)

/* Can be used by core to poll after switch to MMC HS mode */
#define MMC_RSP_R1_NO_CRC	(MMC_RSP_PRESENT|MMC_RSP_OPCODE)

#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, SD, and SDIO cards.
 * 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_R4	(MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
#define MMC_RSP_SPI_R5	(MMC_RSP_SPI_S1|MMC_RSP_SPI_S2)
#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)

	unsigned int		retries;	/* max number of retries 命令发送出错后,可重发的次数 */
	int			error;		/* command error 错误码*/

/*
 * Standard errno values are used for errors, but some have specific
 * meaning in the MMC layer:
 *
 * ETIMEDOUT    Card took too long to respond
 * EILSEQ       Basic format problem with the received or sent data
 *              (e.g. CRC check failed, incorrect opcode in response
 *              or bad end bit)
 * EINVAL       Request cannot be performed because of restrictions
 *              in hardware and/or the driver
 * ENOMEDIUM    Host can determine that the slot is empty and is
 *              actively failing requests
 */

	unsigned int		busy_timeout;	/* busy detect timeout in ms */
	/* Set this flag only for blocking sanitize request */
	bool			sanitize_busy;

	struct mmc_data		*data;		/* data segment associated with cmd */
	struct mmc_request	*mrq;		/* associated request */
};

8.struct mmc_data

struct mmc_data结构体(include/linux/mmc/core.h)包含了数据传输相关的内容,定义如下:


struct mmc_data {
	unsigned int		timeout_ns;	/* data timeout (in ns, max 80ms) */
	unsigned int		timeout_clks;	/* data timeout (in clocks) */
	unsigned int		blksz;		/* data block size */
	unsigned int		blocks;		/* number of blocks */
	int			error;		/* data error */
	unsigned int		flags;	/* 传输方向MMC_DATA_WRITE或MMC_DATA_READ */

#define MMC_DATA_WRITE	(1 << 8)
#define MMC_DATA_READ	(1 << 9)
#define MMC_DATA_STREAM	(1 << 10)

	unsigned int		bytes_xfered;

	struct mmc_command	*stop;		/* stop command */
	struct mmc_request	*mrq;		/* associated request */

	unsigned int		sg_len;		/* size of scatter list */
	int			sg_count;	/* mapped sg entries */
	struct scatterlist	*sg;		/* I/O scatter list */
	s32			host_cookie;	/* host private data */
};

三、相关API

1.提供给mmc host controller driver使用的API

struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
动态分配一个mmc_host,参数extra是私有数据的带下,可通过host->private指针访问。
void mmc_free_host(struct mmc_host *host)
释放一个host

int mmc_add_host(struct mmc_host *host)
将初始化好的host注册到kernel中。
void mmc_remove_host(struct mmc_host *host)
将注册的host移除

int mmc_of_parse(struct mmc_host *host)
接卸设备树中关于host的各项配置

void mmc_detect_change(struct mmc_host *host, unsigned long delay)
host driver检测到卡的插入和拔出是,需要调用这个借口,delay参数是延迟处理,用于给卡   的插拔动作进行去抖。

void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
当host driver处理完场一个request后,应当调用该函数。

static inline void mmc_signal_sdio_irq(struct mmc_host *host)
void sdio_run_irqs(struct mmc_host *host)
对于sdio类型总线,使用这连个函数操作SDIO irq

int mmc_regulator_get_ocrmask(struct regulator *supply)
int mmc_regulator_set_ocr(struct mmc_host *mmc,
int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
int mmc_regulator_get_supply(struct mmc_host *mmc)
电压相关的操作。

2.判断mmc host controller能力的API

#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI)
static inline int mmc_card_is_removable(struct mmc_host *host)
static inline int mmc_card_keep_power(struct mmc_host *host)
static inline int mmc_card_wake_sdio_irq(struct mmc_host *host)
static inline int mmc_host_cmd23(struct mmc_host *host)
static inline int mmc_boot_partition_access(struct mmc_host *host)
static inline int mmc_host_uhs(struct mmc_host *host)
static inline int mmc_host_packed_wr(struct mmc_host *host)
static inline int mmc_card_hs(struct mmc_card *card)
static inline int mmc_card_uhs(struct mmc_card *card)
static inline bool mmc_card_hs200(struct mmc_card *card)
static inline bool mmc_card_ddr52(struct mmc_card *card)
static inline bool mmc_card_hs400(struct mmc_card *card)
static inline void mmc_retune_needed(struct mmc_host *host)
static inline void mmc_retune_recheck(struct mmc_host *host)


总结

本章主要是对mmc host driver驱动的介绍,列出了在驱动编写过程中涉及到的各种结构体和API函数。
在实际开发中host driver的驱动基本上已经由原厂实现了,我们所做的工作大部分是在调试和适配上。

reference

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值