Linux基于renesas的emmc驱动分析

文件位于drivers/mmc/host/sh_mobile_sdhi.c

 

Probe函数:sh_mobile_sdhi_probe

  1. 分配sdhi私有数据空间、初始化结构体(clk、pinctrl)
  2. 分配host数据结构空间、初始化结构体(寄存器空间>0x400时bus_shift=2)
  3. 调用tmio的probe函数:tmio_mmc_host_probe
  4. 获取并注册中断回调:tmio_mmc_irq

 

mmc_host_ops结构体

保留部分主要函数:struct mmc_host_ops {

……

//处理mmc请求接口函数

void (*request)(struct mmc_host *host, struct mmc_request *req);

//设置时钟、电压等接口函数

void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);

//卡属性:返回0表示可读可写;1表示只读

int (*get_ro)(struct mmc_host *host);

//卡是否存在:返回0表示空槽;返回1表示有卡

int (*get_cd)(struct mmc_host *host);

//中断使能

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

//tuning

int (*execute_tuning)(struct mmc_host *host, u32 opcode);

//硬复位

void (*hw_reset)(struct mmc_host *host);

……

};

 

私有数据结构体:struct sh_mobile_sdhi

struct sh_mobile_sdhi {

struct clk *clk; //时钟

struct clk *clk_cd; //card时钟?

struct tmio_mmc_data mmc_data; //mmc数据

struct tmio_mmc_dma dma_priv; //dma私有结构体

struct pinctrl *pinctrl;

struct pinctrl_state *pins_default, *pins_uhs;

int scc_offset;

};

/*

 * data for the MMC controller

 */

struct tmio_mmc_data {

void *chan_priv_tx; //发送channel私有数据

void *chan_priv_rx; //接收channel私有数据

unsigned int hclk;

unsigned long capabilities; //能力特性

unsigned long capabilities2;

unsigned long flags;

u32 ocr_mask; /* available voltages */

unsigned int cd_gpio;

int alignment_shift; //对齐

dma_addr_t dma_rx_offset; //

void (*set_pwr)(struct platform_device *host, int state); //电源管理?

void (*set_clk_div)(struct platform_device *host, int state); //时钟分频?

};

struct tmio_mmc_dma {

enum dma_slave_buswidth dma_buswidth; //dma总线位宽

bool (*filter)(struct dma_chan *chan, void *arg); //dma通道选择?

void (*enable)(struct tmio_mmc_host *host, bool enable); //host使能

};

 

/**

 * struct dma_chan - devices supply DMA channels, clients use them

 * @device: ptr to the dma device who supplies this channel, always !%NULL

 * @cookie: last cookie value returned to client

 * @completed_cookie: last completed cookie for this channel

 * @chan_id: channel ID for sysfs

 * @dev: class device for sysfs

 * @device_node: used to add this to the device chan list

 * @local: per-cpu pointer to a struct dma_chan_percpu

 * @client_count: how many clients are using this channel

 * @table_count: number of appearances in the mem-to-mem allocation table

 * @router: pointer to the DMA router structure

 * @route_data: channel specific data for the router

 * @private: private data for certain client-channel associations

 */

struct dma_chan {

struct dma_device *device;

dma_cookie_t cookie;

dma_cookie_t completed_cookie;

 

/* sysfs */

int chan_id;

struct dma_chan_dev *dev;

 

struct list_head device_node;

struct dma_chan_percpu __percpu *local;

int client_count;

int table_count;

 

/* DMA router */

struct dma_router *router;

void *route_data;

 

void *private;

};

 

struct clk { //待确认

struct list_head node;

struct clk *parent;

struct clk **parent_table; /* list of parents to */

unsigned short parent_num; /* choose between */

unsigned char src_shift; /* source clock field in the */

unsigned char src_width; /* configuration register */

struct sh_clk_ops *ops;

 

struct list_head children;

struct list_head sibling; /* node for children */

 

int usecount;

 

unsigned long rate;

unsigned long flags;

 

void __iomem *enable_reg;

void __iomem *status_reg;

unsigned int enable_bit;

void __iomem *mapped_reg;

 

unsigned int div_mask;

unsigned long arch_flags;

void *priv;

struct clk_mapping *mapping;

struct cpufreq_frequency_table *freq_table;

unsigned int nr_freqs;

};

 

Host主体结构体:struct tmio_mmc_host

是对mmc_host的封装。

struct tmio_mmc_host {

void __iomem *ctl;

struct mmc_command      *cmd; //命令

struct mmc_request      *mrq; //请求

struct mmc_data         *data; //数据

struct mmc_host         *mmc;

 

/* Callbacks for clock / power control */

void (*set_pwr)(struct platform_device *host, int state);

void (*set_clk_div)(struct platform_device *host, int state);

 

/* pio related stuff */

struct scatterlist      *sg_ptr;

struct scatterlist      *sg_orig;

unsigned int            sg_len;

unsigned int            sg_off;

unsigned long bus_shift;

 

struct platform_device *pdev;

struct tmio_mmc_data *pdata;

struct tmio_mmc_dma *dma;

 

/* DMA support */

bool force_pio;

struct dma_chan *chan_rx;

struct dma_chan *chan_tx;

struct completion dma_dataend;

struct tasklet_struct dma_issue;

struct scatterlist bounce_sg;

u8 *bounce_buf;

 

/* Track lost interrupts */

struct delayed_work delayed_reset_work;

struct work_struct done;

 

/* Cache */

u32 sdcard_irq_mask;

u32 sdio_irq_mask;

unsigned int clk_cache;

 

spinlock_t lock; /* protect host private data */

unsigned long last_req_ts;

struct mutex ios_lock; /* protect set_ios() context */

bool native_hotplug;

bool sdio_irq_enabled;

u32 scc_tappos;

 

/* Mandatory callback */

int (*clk_enable)(struct tmio_mmc_host *host);

 

/* Optional callbacks */

unsigned int (*clk_update)(struct tmio_mmc_host *host,

   unsigned int new_clock);

void (*clk_disable)(struct tmio_mmc_host *host);

int (*multi_io_quirk)(struct mmc_card *card,

      unsigned int direction, int blk_size);

int (*card_busy)(struct mmc_host *mmc);

int (*start_signal_voltage_switch)(struct mmc_host *mmc,

   struct mmc_ios *ios);

int (*write16_hook)(struct tmio_mmc_host *host, int addr);

void (*hw_reset)(struct tmio_mmc_host *host);

void (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap);

bool (*check_scc_error)(struct tmio_mmc_host *host);

 

/*

 * Mandatory callback for tuning to occur which is optional for SDR50

 * and mandatory for SDR104.

 */

unsigned int (*init_tuning)(struct tmio_mmc_host *host);

int (*select_tuning)(struct tmio_mmc_host *host);

 

/* Tuning values: 1 for success, 0 for failure */

DECLARE_BITMAP(taps, BITS_PER_BYTE * sizeof(long));

unsigned int tap_num;

 

const struct tmio_mmc_dma_ops *dma_ops;

};

struct mmc_host {

struct device *parent;

struct device class_dev;

int index;

const struct mmc_host_ops *ops;

struct mmc_pwrseq *pwrseq;

unsigned int f_min; //最低频率

unsigned int f_max; //最高频率

unsigned int f_init; //初始化频率

//ocr寄存器相关

u32 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;

#endif

//工作电压

u32 max_current_330;

u32 max_current_300;

u32 max_current_180;

#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_3_3V_DDR (1 << 11) /* Host supports eMMC DDR 3.3V */

#define MMC_CAP_1_8V_DDR (1 << 12) /* Host supports eMMC DDR 1.8V */

#define MMC_CAP_1_2V_DDR (1 << 13) /* Host supports eMMC DDR 1.2V */

#define MMC_CAP_POWER_OFF_CARD (1 << 14) /* Can power off after boot */

#define MMC_CAP_BUS_WIDTH_TEST (1 << 15) /* CMD14/CMD19 bus width ok */

#define MMC_CAP_UHS_SDR12 (1 << 16) /* Host supports UHS SDR12 mode */

#define MMC_CAP_UHS_SDR25 (1 << 17) /* Host supports UHS SDR25 mode */

#define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */

#define MMC_CAP_UHS_SDR104 (1 << 19)/* Host supports UHS SDR104 mode */

#define MMC_CAP_UHS_DDR50 (1 << 20)/* Host supports UHS DDR50 mode */

#define MMC_CAP_NO_BOUNCE_BUFF (1 << 21) /* Disable bounce buffers on host */

#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_CD_WAKE (1 << 28) /* Enable card detect wake */

#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_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_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 */

 

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;

struct delayed_work sdio_irq_work;

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 */

 

unsigned long private[0] ____cacheline_aligned;

};

 

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 */

#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 */

};

mmc_host_ops(对上层提供的接口函数集合)

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.

 */

void (*post_req)(struct mmc_host *host, struct mmc_request *req,

    int err);

void (*pre_req)(struct mmc_host *host, struct mmc_request *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);

void (*ack_sdio_irq)(struct mmc_host *host);

 

/* 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);

};

Request请求相关结构体

struct mmc_request {

struct mmc_command *sbc; /* SET_BLOCK_COUNT for multiblock */

struct mmc_command *cmd; //命令

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;

};

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; //读写

 

#define MMC_DATA_WRITE (1 << 8)

#define MMC_DATA_READ (1 << 9)

 

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 */

};

struct mmc_command {

u32 opcode; //操作码,命令号?

u32 arg; //命令参数,follow defines for detail

#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];

unsigned int flags; /* expected response type ,follow defines for detail*/

#define MMC_RSP_PRESENT (1 << 0)

#define MMC_RSP_136 (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(第5、6位)*/

#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 */

};

tmio_mmc_dma_gen3.c文件分析

tmio_mmc_request_dma函数

  1. 初始化dma收发通道指针为:0xdeadbeaf(只为判断用;不为null表示使能!)
  2. 设置dma_tranend1:DM_CM_INFO1_DTRAEND1_BIT17
  3. 为host的dma_complete和dma_issue事件创建tasklet。
  4. 在complete事件回调中会:重新shangcha_irq函数中判断出如果数据是读来的则会将数据从bounce_buf拷贝到sg_orig(何意?上层读取接口?)。另外,如果需要可以发送stop命令终止总线传输。
  5. 在issue事件回调中会:启动dma传输(什么时候调用?)
  6. 为bounce_buf分配(1页?)空间
  7. 初始化sg(1项)

 

__tmio_mmc_dma_irq函数(DMA中断处理函数?)

  1. 读取DMA状态
  2. 如果是tranend0/1则启动上面函数设置的complete事件回调处理

 

tmio_mmc_reset_dma函数、tmio_mmc_abort_dma函数、tmio_mmc_enable_dma函数分别设置相应寄存器,完成重启、中断和使能DMA工作。

 

tmio_mmc_start_dma函数

  1. 设置DMA模式(ch0是写、ch1是读)、方向和中断掩码
  2. dma_map_sg映射dma空间。
  3. 如果地址没有8bytes对齐则启动pio方式,关闭dma
  4. 清transtate
  5. 使能dma
  6. 禁能pio中断,防止与dma中断干扰
  7. 设置dma参数:模式、传输地址

注:此DMAC一次只能处理1个sg;sg指向的数据地址必须8bytes对齐。

 

tmio_mmc_pio.c文件分析

提供tmio的通用接口export。

tmio的probe函数:tmio_mmc_host_probe

  1. 通过解析设备树获取相关caps:mmc_of_parse
  2. 初始化OCR(电压参数):tmio_mmc_init_ocr
  3. Ioremap获取寄存器基地址
  4. 填充mmc_host结构体相关成员(如cap、seg、blk size/count、frequency)
  5. 关时钟:tmio_mmc_clk_stop
  6. 软复位:tmio_mmc_reset
  7. 复位DMA:tmio_mmc_reset_dma
  8. 屏蔽所有mmc中断:tmio_mmc_disable_mmc_irqs
  9. 使能收、发及卡插入/移除检测中断
  10. DMA收发通道初始化:tmio_mmc_request_dma
  11. Pm处理(忽略)
  12. mmc_host设备注册

 

处理MMC层请求函数:tmio_mmc_request

  1. 如果请求涉及多个block,则调用tmio_mmc_start_command设置块个数。
  2. 调用tmio_mmc_start_data函数,启动数据发送。如果force_pio则unmap dma的sg。
  3. 最后调用tmio_mmc_start_command发送命令。

 

tmio_mmc_start_command函数

  1. 处理CMD12(停止)命令
  2. 根据命令flags,设置response类型(命令解释参照:https://linux.codingbelief.com/zh/storage/flash_memory/emmc/emmc_commands.html、响应解释参照:https://blog.csdn.net/lwj103862095/article/details/38338759)
  3. 分别为发送和接收情况设置相应标志位
  4. 使能mmc相关中断
  5. 设置命令参数,并“发射”命令

tmio_mmc_start_data函数

  1. 初始化sg
  2. 设置传输length和block sz
  3. 调用tmio_mmc_start_dma启动dma传输

 

中断处理函数:tmio_mmc_irq

  1. 获取中断状态
  2. 先检查是否卡插入/移除中断(相应处理)
  3. 其次检查是否是数据传输或命令完成中断(相应处理)
  4. 再次检查是否是dma中断(通过tasklet_schedule执行dma_complete相关工作)
  5. 最后检查是否为sdio中断(相应处理)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值