文章目录
前言
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