• 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中。
    
    • 1
    • 2
    • 3

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204

    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);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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 */
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    一次传输可以有四种情况:
    不需要应答,不需要传输数据的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 */
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    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 */
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    三、相关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)
    电压相关的操作。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    2.判断mmc host controller能力的API


    总结

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

    reference

  • 相关阅读:
    超市的执行者-《软件方法》自测题解析024
    iOS原生应用集成Uni小程序SDK教程
    CCF CSP 201403-2 窗口 题解
    java计算机毕业设计ssm图书馆预约管理系统txke6(附源码、数据库)
    scratch保护环境 2023年5月中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析
    黑客是什么?想成为黑客需要学习什么?
    计算机视觉概述
    华为OD机试 - ABR 车路协同场景 - (Java 2023 B卷 100分)
    Springboot实现ENC加密
    【人工智能Ⅰ】7-KNN & 决策树
  • 原文地址:https://blog.csdn.net/m0_37105371/article/details/126583806