123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- The U-Boot Driver Model Project
- ===============================
- MMC system analysis
- ===================
- Marek Vasut <marek.vasut@gmail.com>
- 2012-02-25
- I) Overview
- -----------
- The MMC subsystem is already quite dynamic in it's nature. It's only necessary
- to flip the subsystem to properly defined API.
- The probing process of MMC drivers start by calling "mmc_initialize()",
- implemented by MMC framework, from the architecture initialization file. The
- "mmc_initialize()" function in turn calls "board_mmc_init()" function and if
- this doesn't succeed, "cpu_mmc_init()" function is called. It is important to
- note that both of the "*_mmc_init()" functions have weak aliases to functions
- which automatically fail.
- Both of the "*_mmc_init()" functions though serve only one purpose. To call
- driver specific probe function, which in turn actually registers the driver with
- MMC subsystem. Each of the driver specific probe functions is currently done in
- very ad-hoc manner.
- The registration with the MMC subsystem is done by calling "mmc_register()",
- whose argument is a runtime configured structure of information about the MMC
- driver. Currently, the information structure is intermixed with driver's internal
- data. The description of the structure follows:
- struct mmc {
- /*
- * API: Allows this driver to be a member of the linked list of all MMC drivers
- * registered with MMC subsystem
- */
- struct list_head link;
- /* DRIVER: Name of the registered driver */
- char name[32];
- /* DRIVER: Driver's private data */
- void *priv;
- /* DRIVER: Voltages the host bus can provide */
- uint voltages;
- /* API: Version of the card */
- uint version;
- /* API: Test if the driver was already initialized */
- uint has_init;
- /* DRIVER: Minimum frequency the host bus can provide */
- uint f_min;
- /* DRIVER: Maximum frequency the host bus can provide */
- uint f_max;
- /* API: Is the card SDHC */
- int high_capacity;
- /* API: Actual width of the bus used by the current card */
- uint bus_width;
- /*
- * DRIVER: Clock frequency to be configured on the host bus, this is read-only
- * for the driver.
- */
- uint clock;
- /* API: Capabilities of the card */
- uint card_caps;
- /* DRIVER: MMC bus capabilities */
- uint host_caps;
- /* API: Configuration and ID data retrieved from the card */
- uint ocr;
- uint scr[2];
- uint csd[4];
- uint cid[4];
- ushort rca;
- /* API: Partition configuration */
- char part_config;
- /* API: Number of partitions */
- char part_num;
- /* API: Transmission speed */
- uint tran_speed;
- /* API: Read block length */
- uint read_bl_len;
- /* API: Write block length */
- uint write_bl_len;
- /* API: Erase group size */
- uint erase_grp_size;
- /* API: Capacity of the card */
- u64 capacity;
- /* API: Descriptor of this block device */
- block_dev_desc_t block_dev;
- /* DRIVER: Function used to submit command to the card */
- int (*send_cmd)(struct mmc *mmc,
- struct mmc_cmd *cmd, struct mmc_data *data);
- /* DRIVER: Function used to configure the host */
- void (*set_ios)(struct mmc *mmc);
- /* DRIVER: Function used to initialize the host */
- int (*init)(struct mmc *mmc);
- /* DRIVER: Function used to report the status of Card Detect pin */
- int (*getcd)(struct mmc *mmc);
- /*
- * DRIVER: Maximum amount of blocks sent during multiblock xfer,
- * set to 0 to autodetect.
- */
- uint b_max;
- };
- The API above is the new API used by most of the drivers. There're still drivers
- in the tree that use old, legacy API though.
- 2) Approach
- -----------
- To convert the MMC subsystem to a proper driver model, the "struct mmc"
- structure will have to be properly split in the first place. The result will
- consist of multiple parts, first will be the structure defining operations
- provided by the MMC driver:
- struct mmc_driver_ops {
- /* Function used to submit command to the card */
- int (*send_cmd)(struct mmc *mmc,
- struct mmc_cmd *cmd, struct mmc_data *data);
- /* DRIVER: Function used to configure the host */
- void (*set_ios)(struct mmc *mmc);
- /* Function used to initialize the host */
- int (*init)(struct mmc *mmc);
- /* Function used to report the status of Card Detect pin */
- int (*getcd)(struct mmc *mmc);
- }
- The second part will define the parameters of the MMC driver:
- struct mmc_driver_params {
- /* Voltages the host bus can provide */
- uint32_t voltages;
- /* Minimum frequency the host bus can provide */
- uint32_t f_min;
- /* Maximum frequency the host bus can provide */
- uint32_t f_max;
- /* MMC bus capabilities */
- uint32_t host_caps;
- /*
- * Maximum amount of blocks sent during multiblock xfer,
- * set to 0 to autodetect.
- */
- uint32_t b_max;
- }
- And finally, the internal per-card data of the MMC subsystem core:
- struct mmc_card_props {
- /* Version of the card */
- uint32_t version;
- /* Test if the driver was already initializes */
- bool has_init;
- /* Is the card SDHC */
- bool high_capacity;
- /* Actual width of the bus used by the current card */
- uint8_t bus_width;
- /* Capabilities of the card */
- uint32_t card_caps;
- /* Configuration and ID data retrieved from the card */
- uint32_t ocr;
- uint32_t scr[2];
- uint32_t csd[4];
- uint32_t cid[4];
- uint16_t rca;
- /* Partition configuration */
- uint8_t part_config;
- /* Number of partitions */
- uint8_t part_num;
- /* Transmission speed */
- uint32_t tran_speed;
- /* Read block length */
- uint32_t read_bl_len;
- /* Write block length */
- uint32_t write_bl_len;
- /* Erase group size */
- uint32_t erase_grp_size;
- /* Capacity of the card */
- uint64_t capacity;
- /* Descriptor of this block device */
- block_dev_desc_t block_dev;
- }
- The probe() function will then register the MMC driver by calling:
- mmc_device_register(struct instance *i, struct mmc_driver_ops *o,
- struct mmc_driver_params *p);
- The struct mmc_driver_params will have to be dynamic in some cases, but the
- driver shouldn't modify it's contents elsewhere than in probe() call.
- Next, since the MMC drivers will now be consistently registered into the driver
- tree from board file, the functions "board_mmc_init()" and "cpu_mmc_init()" will
- disappear altogether.
- As for the legacy drivers, these will either be converted or removed altogether.
- III) Analysis of in-tree drivers
- --------------------------------
- 1) arm_pl180_mmci.c
- -------------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 2) atmel_mci.c
- --------------
- This driver uses the legacy API and should be removed unless converted. It is
- probably possbible to replace this driver with gen_atmel_mci.c . No conversion
- will be done on this driver.
- 3) bfin_sdh.c
- -------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 4) davinci_mmc.c
- ----------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 5) fsl_esdhc.c
- --------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple, unless some problem appears due to the FDT
- component of the driver.
- 6) ftsdc010_esdhc.c
- -------------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 7) gen_atmel_mci.c
- ------------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 8) mmc_spi.c
- ------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 9) mv_sdhci.c
- -------------
- This is a component of the SDHCI support, allowing it to run on Marvell
- Kirkwood chip. It is probable the SDHCI support will have to be modified to
- allow calling functions from this file based on information passed via
- platform_data.
- 10) mxcmmc.c
- ------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 11) mxsmmc.c
- ------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 12) omap_hsmmc.c
- ----------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 13) pxa_mmc.c
- -------------
- This driver uses the legacy API and is written in a severely ad-hoc manner.
- This driver will be removed in favor of pxa_mmc_gen.c, which is proved to work
- better and is already well tested. No conversion will be done on this driver
- anymore.
- 14) pxa_mmc_gen.c
- -----------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 15) s5p_mmc.c
- -------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 16) sdhci.c
- -----------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple, though it'd be necessary to modify this driver
- to also support the Kirkwood series and probably also Tegra series of CPUs.
- See the respective parts of this section for details.
- 17) sh_mmcif.c
- --------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
- 18) tegra2_mmc.c
- ----------------
- Follows the new API and also has a good encapsulation of the whole driver. The
- conversion here will be simple.
|