MMC subsystem series (in continuous update):
[MMC subsystem] concepts and frameworks
[MMC Subsystem] MMC core (chapter I)--Overview
[MMC Subsystem] MMC core (chapter II)--Description of data structure and macro definitions
[MMC Subsystem] MMC core (chapter III)--bus module description
[MMC Subsystem] MMC core (fourth chapter)--host module description
[MMC Subsystem] MMC core (fifth chapter)--card related modules (MMC type card)
[MMC Subsystem] MMC core (sixth chapter)--MMC Core Master Module
[MMC subsystem] Host (chapter I)--Overview
[MMC subsystem] host (chapter II)--SDHCI
[MMC subsystem] Host (chapter III)--SDHCI-PLTFM description
[MMC subsystem] Host (fourth chapter)--host instance (sdhci-msm description)
It is recommended to refer to the [MMC subsystem] concept and framework for a holistic understanding.
========================================================================================================== A , Description
SDHCI-MSM refers to the high-pass MMC host, which uses the standard SDHC standard. Therefore, you can use the interface of "host (chapter II)--SDHCI" and "host (chapter III)--SDHCI-PLTFM description" mentioned earlier.
The following code takes the host implementation of the msm8916 platform and the implementation of SDHCI-MSM in Linux 4.6.0 As an example, this part of the code is open source.
Because there are some register contents that require document support but we do not, so here is simply a brief introduction to design ideas and code structure. Second, DTSi node
MSM8916 has two SDHCI host, we take the first host as an example, the default is eMMC
Arch/arm64/boot/dts/qcom/msm8916.dtsi
aliases {SDHC1 = &sdhc_1;/* SDC1 EMMC slot */};
sdhc_1:sdhci@07824000 {compatible = "qcom,sdhci-msm-v4";
Will match SDHCI-MSM.C's driver reg = <0x07824900 0x11c> <0x07824000 0x800>;
Reg-names = "Hc_mem", "Core_mem"; A two-part register, HC_MEM represents the register used by the SDHCI, and Core_mem indicates that the MSM host is independent of the SDHCI standard and that it needs to use the Register//because the driver will use SDHCI-PLTFM to enter
Row parsing, so here Hc_mem must be placed in the first property of the Register, refer to "host (chapter III)--SDHCI-PLTFM description" interrupts = <0 123 0>, <0 138 0>;
Interrupt-names = "Hc_irq", "PWR_IRQ"; Two-part interrupt, HC_IRQ represents the interrupt used by SDHCI, Core_mem indicates that the MSM host detects interrupts of the host power state, is independent of the SDHCI standard//Because the driver uses SDHCI-PLTFM to perform the solution
Hc_irq the first attribute of the interrupt, refer to the "host (chapter III)--SDHCI-PLTFM description" clocks = <&GCC gcc_sdcc1_apps_clk>
<&GCC gcc_sdcc1_ahb_clk>;
Clock-names = "core", "Iface"; Two clock//CORE->GCC_SDCC1_APPS_CLK, working clock, i.e. output clock/
/IFACE->GCC_SDCC1_AHB_CLK, bus clock bus-width = <8>;
The bus width is set to 8 non-removable;
Set to non-removable status = "disabled"; };
third, data structure
1, struct sdhci_msm_host
SDHCI-MSM host driver A host structure customized to its own resources.
struct Sdhci_msm_host {
struct platform_device *pdev; The DTSi node resolves the platform device
void __iomem *core_mem;/* MSM SDCC Mapped address * //host's own register base address
struct CLK *clk;
/* main SD/MMC Bus clock * //working clock, corresponding to the
struct CLK *pclk; /* SDHC Peripheral Bus clock */
struct CLK *bus_clk; /* SDHC bus Voter clock */
struct mmc_host *mmc; Corresponding mmc_host structure, specific reference to "MMC core"
};
2, Sdhci_msm_pdata
struct Sdhci_pltfm_data type.
Provides the platform data structure used by the SDHCI-PLTFM interface, defines the Sdhci_host ops, quirks, and QUIRKS2. will be used when calling Sdhci_pltfm_init to generate Sdhci_host.
Specific reference to "host (chapter III)--SDHCI-PLTFM description"
static const struct Sdhci_pltfm_data Sdhci_msm_pdata = {
. Quirks = Sdhci_quirk_broken_card_detection |
Sdhci_quirk_single_power_write,
. Ops = &sdhci_msm_ops,
};
3, Sdhci_msm_ops
struct Sdhci_ops type.
Provides Sdhci_host with an operational set of actual hardware operation methods other than the SDHCI standard to SDHCI core.
Specific reference to "host (chapter II)--SDHCI"
static const struct Sdhci_ops sdhci_msm_ops = {
. platform_execute_tuning = sdhci_msm_execute_tuning,
. reset = Sdhci_reset,
. Set_clock = Sdhci_set_clock,
. set_bus_width = Sdhci_set_bus_width,
. set_uhs_signaling = Sdhci_set_uhs_signaling,
};
Specific later instructions. The content of this operation set is also the core content that SDHCI host will implement. Iv. Code Description 1. Device-driven model-related code
static struct Platform_driver Sdhci_msm_driver = {
. Probe = Sdhci_msm_probe, //Probe method, which is the introduction of the following code
. remove = Sdhci_msm_remove, //Remove method
. Driver = {
. Name = "Sdhci_msm",
. of_match_table = Sdhci_msm_dt_ Match,
},
};
static const struct OF_DEVICE_ID sdhci_msm_dt_match[] = {
{. compatible = "Qcom,sdhci-msm-v4"}, and/or DTSi node With
{},
};
Module_platform_driver (Sdhci_msm_driver);
2, Sdhci_msm_probe
The primary call to work calls Sdhci_pltfm_init to allocate memory for Sdhci_host, Sdhci_pltfm_host, Sdhci_msm_host, set Association Mmc_host, Sdhci_host, Sdhci_pltfm_host, Sdhci_msm_host parsing DTSi property set to Mmc_host and Sdhci_host get various clocks get host SDHCI-independent register base address call Sdhci_add_ Host registers Sdhci_host with SDHCI core, and the corresponding Mmc_host is also called into the MMC core. The registration of the host is complete.
The code is as follows
static int sdhci_msm_probe (struct platform_device *pdev) {struct sdhci_host *host;
struct Sdhci_pltfm_host *pltfm_host;
struct Sdhci_msm_host *msm_host;
struct resource *core_memres;
int ret;
U16 Host_version, Core_minor;
U32 core_version, caps;
U8 Core_major;
Host = Sdhci_pltfm_init (Pdev, &sdhci_msm_pdata, sizeof (*msm_host)); Call Sdhci_pltfm_init to allocate memory for Sdhci_host, Sdhci_pltfm_host, sdhci_msm_host, and/or set Sdhci_host, refer to host (chapter III)--sdhci-
PLTFM description "//Here the Sdhci_msm_pdata will be used to set the sdhci_host of the relevant members.
Note that because of the differences with the kernel version of the previous article, the interface here may be a bit different pltfm_host = Sdhci_priv (host);
Msm_host = Sdhci_pltfm_priv (pltfm_host);
MSM_HOST->MMC = host->mmc;
Msm_host->pdev = Pdev; The relationship between the associated Mmc_host, Sdhci_host, Sdhci_pltfm_host, sdhci_msm_host//Several structures can be referenced in the host (Chapter one)-Overview ret = Mmc_of_parse (
HOST->MMC); Call Mmc_of_parse to resolve the DTSi node property of the host, set the Caps attribute to Mmc_host//mmc_of_parse belong to the standard provided by MMC coreInterface, refer to "MMC core--host module description" Sdhci_get_of_property (Pdev); Call Sdhci_get_of_property to resolve the DTSi node property of host, set to Sdhci_host quirks and QUIRKS2 in/* Setup SDCC bus voter clock.
*/msm_host->bus_clk = Devm_clk_get (&pdev->dev, "bus");
Get bus clock/* Setup main Peripheral Bus clocks */msm_host->pclk = Devm_clk_get (&pdev->dev, "iface");
Gets the iface clock into MSM_HOST->PCLK (GCC_SDCC1_AHB_CLK) ret = clk_prepare_enable (MSM_HOST->PCLK);
/* Setup SDC MMC clock */msm_host->clk = Devm_clk_get (&pdev->dev, "core");
Get the core clock into MSM_HOST->CLK (GCC_SDCC1_AHB_CLK) core_memres = Platform_get_resource (Pdev, Ioresource_mem, 1);
Msm_host->core_mem = Devm_ioremap_resource (&pdev->dev, core_memres); Get the register base address for MSM host/* Reset the core and Enable SDHC mode */writel_relaxed (readl_relaxed (msm_host->core_mem
+ Core_power) |
Core_sw_rst, Msm_host->core_mem + core_power); //.......
The following filters the reset operation and initialization of the MSM host: ret = Sdhci_add_host (host);
Call Sdhci_add_host to register the resulting sdhci_host in SDHCI core.
return 0; }