[mmc subsystem] host(第二章)——sdhci

來源:互聯網
上載者:User

mmc subsystem系列(持續更新中):
[mmc subsystem] 概念與架構

[mmc subsystem] mmc core(第一章)——概述
[mmc subsystem] mmc core(第二章)——資料結構和宏定義說明
[mmc subsystem] mmc core(第三章)——bus模組說明
[mmc subsystem] mmc core(第四章)——host模組說明
[mmc subsystem] mmc core(第五章)——card相關模組(mmc type card)
[mmc subsystem] mmc core(第六章)——mmc core主模組

[mmc subsystem] host(第一章)——概述
[mmc subsystem] host(第二章)——sdhci
[mmc subsystem] host(第三章)——sdhci-pltfm說明
[mmc subsystem] host(第四章)——host執行個體(sdhci-msm說明)

建議先參考《[mmc subsystem] 概念與架構》對整體有一個瞭解。

========================================================================================================== 一、sdhci core說明 1、sdhci說明

具體參考《host(第一章)——概述》
SDHC:Secure Digital(SD) Host Controller,是指一套sd host控制器的設計標準,其寄存器位移以及意義都有一定的規範,並且提供了對應的驅動程式,方便vendor進行host controller的開發。
vendor按照這套標準設計host controller之後,可以直接使用sdhci driver來實現host controller的使用,(qcom和samsung都使用了這套標準)。而vendor只需要實現平台相關的部分、如clock、pinctrl、power等等的部分即可。
關於這個標準,我們可以參考《SDHC_Ver3.00_Final_110225》。
注意,強調一下,這是一種mmc host controller的設計標準,其本質上還是屬於mmc host。並且,其相容mmc type card,而不是說只能使用於sd type card。 2、sdhci core

因為sdhci driver並不是某個特定host的driver,而是提供了一些介面和操作集方法給對應的host driver使用。
因此,我們將sdhci.c的代碼部分稱之為sdhci core用以和host driver區分。
其主要功能如下: 為host driver提供分配、釋放sdhci_host的介面 為host driver提供註冊、卸載sdhci_host的介面 實現sdhci_host和mmc_host的對接(也就是mmc core的對接) 實現host關於SDHCI標準的通用操作(sdhci_ops) 實現host的通用電源管理操作

注意,clock和pinctrl是由host driver自己管理,sdhci core並不參與。 3、代碼位置

drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h 二、資料結構 1、struct sdhci_host

sdhci core將host抽象出struct sdhci_host來進行管理和維護。 資料結構如下:

struct sdhci_host {    /* Data set by hardware interface driver */    const char *hw_name;    /* Hardware bus name */      // 名稱    unsigned int quirks;    /* Deviations from spec. */         // 癖好,可以理解為硬體sdhci controller和標準sdhci規範不符合的地方。    unsigned int quirks2;   /* More deviations from spec. */   // 癖好2,可以理解為硬體sdhci controller和標準sdhci規範不符合的地方。    int irq;        /* Device IRQ */      // sdhci的中斷    void __iomem *ioaddr;   /* Mapped address */   // sdhci寄存器的基地址    const struct sdhci_ops *ops;    /* Low level hw interface */      // 底層硬體的操作介面    struct regulator *vmmc;     /* Power regulator (vmmc) */       // sdhci core的LDO    struct regulator *vqmmc;    /* Signaling regulator (vccq) */      // 給sdhci io供電的LDO    /* Internal data */    struct mmc_host *mmc;   /* MMC structure */      // struct mmc_host,用於註冊到mmc subsystem中    u64 dma_mask;       /* custom DMA mask */    spinlock_t lock;    /* Mutex */      // 自旋鎖    int flags;      /* Host attributes */   // sdhci的一些標識    unsigned int version;   /* SDHCI spec. version */   // 當前sdhci的硬體版本    unsigned int max_clk;   /* Max possible freq (MHz) */   // 該sdhci支援的最大電壓    unsigned int timeout_clk;   /* Timeout freq (KHz) */   // 逾時頻率    unsigned int clk_mul;   /* Clock Muliplier value */   // 當前倍頻值    unsigned int clock; /* Current clock (MHz) */      // 當前工作頻率    u8 pwr;         /* Current voltage */   // 當前工作電壓    bool runtime_suspended; /* Host is runtime suspended */      // 是否處於runtime suspend狀態    struct mmc_request *mrq;    /* Current request */      // 當前正在處理的請求    struct mmc_command *cmd;    /* Current command */   // 當前的命令請求    struct mmc_data *data;  /* Current data request */      // 當前的資料請求    unsigned int data_early:1;  /* Data finished before cmd */   // 表示在CMD處理完成前,data已經處理完成    struct sg_mapping_iter sg_miter;    /* SG state for PIO */    unsigned int blocks;    /* remaining PIO blocks */    int sg_count;       /* Mapped sg entries */    u8 *adma_desc;      /* ADMA descriptor table */    u8 *align_buffer;   /* Bounce buffer */    unsigned int adma_desc_sz; /* ADMA descriptor table size */    unsigned int adma_desc_line_sz; /* ADMA descriptor line size */    unsigned int align_buf_sz; /* Bounce buffer size */    unsigned int align_bytes; /* Alignment bytes (4/8 for 32-bit/64-bit) */    unsigned int adma_max_desc; /* Max ADMA descriptos (max sg segments) */    dma_addr_t adma_addr;   /* Mapped ADMA descr. table */    dma_addr_t align_addr;  /* Mapped bounce buffer */    struct tasklet_struct card_tasklet; /* Tasklet structures */      // card tasklet,用於處理card的插入或者拔出事件    struct tasklet_struct finish_tasklet;      // finsh tasklet,用來通知上層一個請求處理完成(包括出錯的情況)    struct timer_list timer;    /* Timer for timeouts */   // 逾時定時器鏈表    u32 caps;       /* Alternative CAPABILITY_0 */   // 表示該sdhci controller的屬性    u32 caps1;      /* Alternative CAPABILITY_1 */   // 表示該sdhci controller的屬性    unsigned int            ocr_avail_sdio; /* OCR bit masks */   // 在該sdhci controller上可用的sdio card的ocr值掩碼(代表了其可用電壓)    unsigned int            ocr_avail_sd;   // 在該sdhci controller上可用的sd card的ocr值掩碼(代表了其可用電壓)     unsigned int            ocr_avail_mmc;   /// 在該sdhci controller上可用的mmc card的ocr值掩碼(代表了其可用電壓) /* 以下和mmc的tuning相關 */    wait_queue_head_t   buf_ready_int;  /* Waitqueue for Buffer Read Ready interrupt */    unsigned int        tuning_done;    /* Condition flag set when CMD19 succeeds */    unsigned int        tuning_count;   /* Timer count for re-tuning */    unsigned int        tuning_mode;    /* Re-tuning mode supported by host */#define SDHCI_TUNING_MODE_1 0    struct timer_list   tuning_timer;   /* Timer for tuning *//* 以下和sdhci的qos相關 */    struct sdhci_host_qos host_qos[SDHCI_QOS_MAX_POLICY];    enum sdhci_host_qos_policy last_qos_policy;    bool host_use_default_qos;      unsigned int pm_qos_timeout_us;         /* timeout for PM QoS request */    struct device_attribute pm_qos_tout;    struct delayed_work pm_qos_work;    struct sdhci_next next_data;    ktime_t data_start_time;    struct mutex ios_mutex;    enum sdhci_power_policy power_policy;    bool irq_enabled; /* host irq status flag */      // 表示中斷是否使能。    bool async_int_supp;  /* async support to rxv int, when clks are off */    bool disable_sdio_irq_deferred; /* status of disabling sdio irq */    u32 auto_cmd_err_sts;    struct ratelimit_state dbg_dump_rs;    int reset_wa_applied; /* reset workaround status */    ktime_t reset_wa_t; /* time when the reset workaround is applied */    int reset_wa_cnt; /* total number of times workaround is used */    unsigned long private[0] ____cacheline_aligned;      // 私人資料指標};
癖好1(sdhci_host->quirks)各個位意義如下:
/* Controller doesn't honor resets unless we touch the clock register */#define SDHCI_QUIRK_CLOCK_BEFORE_RESET            (1<<0)/* Controller has bad caps bits, but really supports DMA */#define SDHCI_QUIRK_FORCE_DMA                (1<<1)/* Controller doesn't like to be reset when there is no card inserted. */#define SDHCI_QUIRK_NO_CARD_NO_RESET            (1<<2)/* Controller doesn't like clearing the power reg before a change */#define SDHCI_QUIRK_SINGLE_POWER_WRITE            (1<<3)/* Controller has flaky internal state so reset it on each ios change */#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS        (1<<4)/* Controller has an unusable DMA engine */#define SDHCI_QUIRK_BROKEN_DMA                (1<<5)/* Controller has an unusable ADMA engine */#define SDHCI_QUIRK_BROKEN_ADMA                (1<<6)/* Controller can only DMA from 32-bit aligned addresses */#define SDHCI_QUIRK_32BIT_DMA_ADDR            (1<<7)/* Controller can only DMA chunk sizes that are a multiple of 32 bits */#define SDHCI_QUIRK_32BIT_DMA_SIZE            (1<<8)/* Controller can only ADMA chunks that are a multiple of 32 bits */#define SDHCI_QUIRK_32BIT_ADMA_SIZE            (1<<9)/* Controller needs to be reset after each request to stay stable */#define SDHCI_QUIRK_RESET_AFTER_REQUEST            (1<<10)/* Controller needs voltage and power writes to happen separately */#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER        (1<<11)/* Controller provides an incorrect timeout value for transfers */#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL            (1<<12)/* Controller has an issue with buffer bits for small transfers */#define SDHCI_QUIRK_BROKEN_SMALL_PIO            (1<<13)/* Controller does not provide transfer-complete interrupt when not busy */#define SDHCI_QUIRK_NO_BUSY_IRQ                (1<<14)/* Controller has unreliable card detection */#define SDHCI_QUIRK_BROKEN_CARD_DETECTION        (1<<15)/* Controller reports inverted write-protect state */#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT        (1<<16)/* Controller has nonstandard clock management */#define SDHCI_QUIRK_NONSTANDARD_CLOCK            (1<<17)/* Controller does not like fast PIO transfers */#define SDHCI_QUIRK_PIO_NEEDS_DELAY            (1<<18)/* Controller losing signal/interrupt enable states after reset */#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET        (1<<19)/* Controller has to be forced to use block size of 2048 bytes */#define SDHCI_QUIRK_FORCE_BLK_SZ_2048            (1<<20)/* Controller cannot do multi-block transfers */#define SDHCI_QUIRK_NO_MULTIBLOCK            (1<<21)/* Controller can only handle 1-bit data transfers */#define SDHCI_QUIRK_FORCE_1_BIT_DATA            (1<<22)/* Controller needs 10ms delay between applying power and clock */#define SDHCI_QUIRK_DELAY_AFTER_POWER            (1<<23)/* Controller uses SDCLK instead of TMCLK for data timeouts */#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK        (1<<24)/* Controller reports wrong base clock capability */#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN        (1<<25)/* Controller cannot support End Attribute in NOP ADMA descriptor */#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC        (1<<26)/* Controller is missing device caps. Use caps provided by host */#define SDHCI_QUIRK_MISSING_CAPS            (1<<27)/* Controller uses Auto CMD12 command to stop the transfer */#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12        (1<<28)/* Controller doesn't have HISPD bit field in HI-SPEED SD card */#define SDHCI_QUIRK_NO_HISPD_BIT            (1<<29)/* Controller treats ADMA descriptors with length 0000h incorrectly */#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC        (1<<30)/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */#define SDHCI_QUIRK_UNSTABLE_RO_DETECT            (1<<31)
癖好2(sdhci_host->quirks2)各個位意義如下:
#define SDHCI_QUIRK2_HOST_OFF_CARD_ON           (1<<0)#define SDHCI_QUIRK2_HOST_NO_CMD23          (1<<1)/* The system physically doesn't support 1.8v, even if the host does */#define SDHCI_QUIRK2_NO_1_8_V               (1<<2)#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN        (1<<3)/* * Read Transfer Active/ Write Transfer Active may be not * de-asserted after end of transaction. Issue reset for DAT line. */#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT         (1<<4)/* * Slow interrupt clearance at 400KHz may cause * host controller driver interrupt handler to * be called twice. */#define SDHCI_QUIRK2_SLOW_INT_CLR           (1<<5)/* * If the base clock can be scalable, then there should be no further * clock dividing as the input clock itself will be scaled down to * required frequency. */#define SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK      (1<<6)/* * Dont use the max_discard_to in sdhci driver so that the maximum discard * unit gets picked by the mmc queue. Otherwise, it takes a long time for * secure discard kind of operations to complete. */#define SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE       (1<<7)/* * Ignore data timeout error for R1B commands as there will be no * data associated and the busy timeout value for these commands * could be lager than the maximum timeout value that controller * can handle. */#define SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD     (1<<8)/* * The preset value registers are not properly initialized by * some hardware and hence preset value must not be enabled for * such controllers. */#define SDHCI_QUIRK2_BROKEN_PRESET_VALUE        (1<<9)/* * Some controllers define the usage of 0xF in data timeout counter * register (0x2E) which is actually a reserved bit as per * specification. */#define SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT       (1<<10)/* * This is applicable for controllers that advertize timeout clock * value in capabilities register (bit 5-0) as just 50MHz whereas the * base clock frequency is 200MHz. So, the controller internally * multiplies the value in timeout control register by 4 with the * assumption that driver always uses fixed timeout clock value from * capabilities register to calculate the timeout. But when the driver * uses SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK base clock frequency is directly * controller by driver and it's rate varies upto max. 200MHz. This new quirk * will be used in such cases to avoid controller mulplication when timeout is * calculated based on the base clock. */#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1 << 11)/* * Some SDHC controllers are unable to handle data-end bit error in * 1-bit mode of SDIO. */#define SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR             (1<<12)/* * Some SDHC controllers do not require data buffers alignment, skip * the bounce buffer logic when preparing data */#define SDHCI_QUIRK2_ADMA_SKIP_DATA_ALIGNMENT             (1<<13)/* Some controllers doesn't have have any LED control */#define SDHCI_QUIRK2_BROKEN_LED_CONTROL (1 << 14)/* Use reset workaround in case sdhci reset timeouts */#define SDHCI_QUIRK2_USE_RESET_WORKAROUND (1 << 15)
sdhci host的一些標識(sdhci_host->flags)如下:
#define SDHCI_USE_SDMA      (1<<0)  /* Host is SDMA capable */#define SDHCI_USE_ADMA      (1<<1)  /* Host is ADMA capable */#define SDHCI_REQ_USE_DMA   (1<<2)  /* Use DMA for this req. */#define SDHCI_DEVICE_DEAD   (1<<3)  /* Device unresponsive */#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */#define SDHCI_NEEDS_RETUNING    (1<<5)  /* Host needs retuning */#define SDHCI_AUTO_CMD12    (1<<6)  /* Auto CMD12 support */#define SDHCI_AUTO_CMD23    (1<<7)  /* Auto CMD23 support */#define SDHCI_PV_ENABLED    (1<<8)  /* Preset value enabled */#define SDHCI_SDIO_IRQ_ENABLED  (1<<9)  /* SDIO irq enabled */#define SDHCI_HS200_NEEDS_TUNING (1<<10)    /* HS200 needs tuning */#define SDHCI_USING_RETUNING_TIMER (1<<11)  /* Host is using a retuning timer for the card */#define SDHCI_HS400_NEEDS_TUNING (1<<12)    /* HS400 needs tuning */#define SDHCI_USE_ADMA_64BIT     (1<<13)/* Host is 64-bit ADMA capable */
2、struct sdhci_ops結構體

sdhci core只是提供了一些介面和符合mmc core的操作集方法給對應的host driver使用。由於各個host的硬體有所差異,所以實際和硬體互動的驅動部分還是在host driver中實現。
所以sdhci core要求host提供標準的訪問硬體的一些方法。而這些方法就被定義在了struct sdhci_ops結構體內部。
結構體如下:

struct sdhci_ops {#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS       // 表示host另外提供了一套訪問寄存器的方法,沒有定義的話,則說明使用通用的讀寫寄存器的方法    u32        (*read_l)(struct sdhci_host *host, int reg);    u16        (*read_w)(struct sdhci_host *host, int reg);    u8        (*read_b)(struct sdhci_host *host, int reg);    void        (*write_l)(struct sdhci_host *host, u32 val, int reg);    void        (*write_w)(struct sdhci_host *host, u16 val, int reg);    void        (*write_b)(struct sdhci_host *host, u8 val, int reg);#endif    void    (*set_clock)(struct sdhci_host *host, unsigned int clock);    // 設定時鐘頻率    int        (*enable_dma)(struct sdhci_host *host);    // 使能DMA    unsigned int    (*get_max_clock)(struct sdhci_host *host);    // 擷取支援的最大時鐘頻率    unsigned int    (*get_min_clock)(struct sdhci_host *host);    // 擷取支援的最小時鐘頻率    unsigned int    (*get_timeout_clock)(struct sdhci_host *host);    int        (*platform_bus_width)(struct sdhci_host *host, int width);      void (*platform_send_init_74_clocks)(struct sdhci_host *host,                         u8 power_mode);    unsigned int    (*get_ro)(struct sdhci_host *host);    // 擷取    void    (*platform_reset_enter)(struct sdhci_host *host, u8 mask);    // 進入平台複位的方法    void    (*platform_reset_exit)(struct sdhci_host *host, u8 mask);    // 退出平台複位的方法    int    (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);    // 設定uhs方式    void    (*hw_reset)(struct sdhci_host *host);    // 硬體複位的方法    void    (*platform_suspend)(struct sdhci_host *host);    // 平台host的suspend方法    void    (*platform_resume)(struct sdhci_host *host);    // 平台host的resume方法    void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);    void    (*platform_init)(struct sdhci_host *host);    // 平台host的初始化方法    void    (*check_power_status)(struct sdhci_host *host, u32 req_type);    // 檢測匯流排的電源狀態#define REQ_BUS_OFF    (1 << 0)#define REQ_BUS_ON    (1 << 1)#define REQ_IO_LOW    (1 << 2)#define REQ_IO_HIGH    (1 << 3)    int    (*execute_tuning)(struct sdhci_host *host, u32 opcode);    // 執行tuning操作的的方法    void    (*toggle_cdr)(struct sdhci_host *host, bool enable);    unsigned int    (*get_max_segments)(void);    void    (*platform_bus_voting)(struct sdhci_host *host, u32 enable);    // 平台匯流排投票的方法    void    (*disable_data_xfer)(struct sdhci_host *host);    void    (*dump_vendor_regs)(struct sdhci_host *host);    int    (*config_auto_tuning_cmd)(struct sdhci_host *host,                      bool enable,                      u32 type);    int    (*enable_controller_clock)(struct sdhci_host *host);    void    (*reset_workaround)(struct sdhci_host *host, u32 enable);};

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.