// SPDX-License-Identifier: GPL-2.0-or-later /* * Arasan Secure Digital Host Controller Interface. * Copyright (C) 2011 - 2012 Michal Simek <[email protected]> * Copyright (c) 2012 Wind River Systems, Inc. * Copyright (C) 2013 Pengutronix e.K. * Copyright (C) 2013 Xilinx Inc. * * Based on sdhci-of-esdhc.c * * Copyright (c) 2007 Freescale Semiconductor, Inc. * Copyright (c) 2009 MontaVista Software, Inc. * * Authors: Xiaobo Xie <[email protected]> * Anton Vorontsov <[email protected]> */ #include <linux/clk-provider.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> #include <linux/regmap.h> #include <linux/reset.h> #include <linux/firmware/xlnx-zynqmp.h> #include "cqhci.h" #include "sdhci-cqhci.h" #include "sdhci-pltfm.h" #define SDHCI_ARASAN_VENDOR_REGISTER … #define SDHCI_ARASAN_ITAPDLY_REGISTER … #define SDHCI_ARASAN_ITAPDLY_SEL_MASK … #define SDHCI_ARASAN_OTAPDLY_REGISTER … #define SDHCI_ARASAN_OTAPDLY_SEL_MASK … #define SDHCI_ARASAN_CQE_BASE_ADDR … #define VENDOR_ENHANCED_STROBE … #define PHY_CLK_TOO_SLOW_HZ … #define MIN_PHY_CLK_HZ … #define SDHCI_ITAPDLY_CHGWIN … #define SDHCI_ITAPDLY_ENABLE … #define SDHCI_OTAPDLY_ENABLE … #define PHY_CTRL_REG1 … #define PHY_CTRL_ITAPDLY_ENA_MASK … #define PHY_CTRL_ITAPDLY_SEL_MASK … #define PHY_CTRL_ITAPDLY_SEL_SHIFT … #define PHY_CTRL_ITAP_CHG_WIN_MASK … #define PHY_CTRL_OTAPDLY_ENA_MASK … #define PHY_CTRL_OTAPDLY_SEL_MASK … #define PHY_CTRL_OTAPDLY_SEL_SHIFT … #define PHY_CTRL_STRB_SEL_MASK … #define PHY_CTRL_STRB_SEL_SHIFT … #define PHY_CTRL_TEST_CTRL_MASK … #define PHY_CTRL_REG2 … #define PHY_CTRL_EN_DLL_MASK … #define PHY_CTRL_DLL_RDY_MASK … #define PHY_CTRL_FREQ_SEL_MASK … #define PHY_CTRL_FREQ_SEL_SHIFT … #define PHY_CTRL_SEL_DLY_TX_MASK … #define PHY_CTRL_SEL_DLY_RX_MASK … #define FREQSEL_200M_170M … #define FREQSEL_170M_140M … #define FREQSEL_140M_110M … #define FREQSEL_110M_80M … #define FREQSEL_80M_50M … #define FREQSEL_275M_250M … #define FREQSEL_250M_225M … #define FREQSEL_225M_200M … #define PHY_DLL_TIMEOUT_MS … /* Default settings for ZynqMP Clock Phases */ #define ZYNQMP_ICLK_PHASE … #define ZYNQMP_OCLK_PHASE … #define VERSAL_ICLK_PHASE … #define VERSAL_OCLK_PHASE … #define VERSAL_NET_EMMC_ICLK_PHASE … #define VERSAL_NET_EMMC_OCLK_PHASE … #define VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL … /* * On some SoCs the syscon area has a feature where the upper 16-bits of * each 32-bit register act as a write mask for the lower 16-bits. This allows * atomic updates of the register without locking. This macro is used on SoCs * that have that feature. */ #define HIWORD_UPDATE(val, mask, shift) … /** * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map * * @reg: Offset within the syscon of the register containing this field * @width: Number of bits for this field * @shift: Bit offset within @reg of this field (or -1 if not avail) */ struct sdhci_arasan_soc_ctl_field { … }; /** * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers * * @baseclkfreq: Where to find corecfg_baseclkfreq * @clockmultiplier: Where to find corecfg_clockmultiplier * @support64b: Where to find SUPPORT64B bit * @hiword_update: If true, use HIWORD_UPDATE to access the syscon * * It's up to the licensee of the Arsan IP block to make these available * somewhere if needed. Presumably these will be scattered somewhere that's * accessible via the syscon API. */ struct sdhci_arasan_soc_ctl_map { … }; /** * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller * * @sdcardclk_ops: The output clock related operations * @sampleclk_ops: The sample clock related operations */ struct sdhci_arasan_clk_ops { … }; /** * struct sdhci_arasan_clk_data - Arasan Controller Clock Data. * * @sdcardclk_hw: Struct for the clock we might provide to a PHY. * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. * @sampleclk_hw: Struct for the clock we might provide to a PHY. * @sampleclk: Pointer to normal 'struct clock' for sampleclk_hw. * @clk_phase_in: Array of Input Clock Phase Delays for all speed modes * @clk_phase_out: Array of Output Clock Phase Delays for all speed modes * @set_clk_delays: Function pointer for setting Clock Delays * @clk_of_data: Platform specific runtime clock data storage pointer */ struct sdhci_arasan_clk_data { … }; /** * struct sdhci_arasan_data - Arasan Controller Data * * @host: Pointer to the main SDHCI host structure. * @clk_ahb: Pointer to the AHB clock * @phy: Pointer to the generic phy * @is_phy_on: True if the PHY is on; false if not. * @internal_phy_reg: True if the PHY is within the Host controller. * @has_cqe: True if controller has command queuing engine. * @clk_data: Struct for the Arasan Controller Clock Data. * @clk_ops: Struct for the Arasan Controller Clock Operations. * @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers. * @soc_ctl_map: Map to get offsets into soc_ctl registers. * @quirks: Arasan deviations from spec. */ struct sdhci_arasan_data { … }; struct sdhci_arasan_of_data { … }; static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = …; static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = …; static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = …; static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = …; static void sdhci_arasan_phy_set_delaychain(struct sdhci_host *host, bool enable) { … } static int sdhci_arasan_phy_set_dll(struct sdhci_host *host, bool enable) { … } static void sdhci_arasan_phy_dll_set_freq(struct sdhci_host *host, int clock) { … } /** * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers * * @host: The sdhci_host * @fld: The field to write to * @val: The value to write * * This function allows writing to fields in sdhci_arasan_soc_ctl_map. * Note that if a field is specified as not available (shift < 0) then * this function will silently return an error code. It will be noisy * and print errors for any other (unexpected) errors. * * Return: 0 on success and error value on error */ static int sdhci_arasan_syscon_write(struct sdhci_host *host, const struct sdhci_arasan_soc_ctl_field *fld, u32 val) { … } static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) { … } static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) { … } static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) { … } static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { … } static const struct sdhci_ops sdhci_arasan_ops = …; static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) { … } static void sdhci_arasan_dumpregs(struct mmc_host *mmc) { … } static void sdhci_arasan_cqe_enable(struct mmc_host *mmc) { … } static const struct cqhci_host_ops sdhci_arasan_cqhci_ops = …; static const struct sdhci_ops sdhci_arasan_cqe_ops = …; static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = …; #ifdef CONFIG_PM_SLEEP /** * sdhci_arasan_suspend - Suspend method for the driver * @dev: Address of the device structure * * Put the device in a low power state. * * Return: 0 on success and error value on error */ static int sdhci_arasan_suspend(struct device *dev) { … } /** * sdhci_arasan_resume - Resume method for the driver * @dev: Address of the device structure * * Resume operation after suspend * * Return: 0 on success and error value on error */ static int sdhci_arasan_resume(struct device *dev) { … } #endif /* ! CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, sdhci_arasan_resume); /** * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate * * @hw: Pointer to the hardware clock structure. * @parent_rate: The parent rate (should be rate of clk_xin). * * Return the current actual rate of the SD card clock. This can be used * to communicate with out PHY. * * Return: The card clock rate. */ static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { … } static const struct clk_ops arasan_sdcardclk_ops = …; /** * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate * * @hw: Pointer to the hardware clock structure. * @parent_rate: The parent rate (should be rate of clk_xin). * * Return the current actual rate of the sampling clock. This can be used * to communicate with out PHY. * * Return: The sample clock rate. */ static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { … } static const struct clk_ops arasan_sampleclk_ops = …; /** * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays * * @hw: Pointer to the hardware clock structure. * @degrees: The clock phase shift between 0 - 359. * * Set the SD Output Clock Tap Delays for Output path * * Return: 0 on success and error value on error */ static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) { … } static const struct clk_ops zynqmp_sdcardclk_ops = …; /** * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays * * @hw: Pointer to the hardware clock structure. * @degrees: The clock phase shift between 0 - 359. * * Set the SD Input Clock Tap Delays for Input path * * Return: 0 on success and error value on error */ static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) { … } static const struct clk_ops zynqmp_sampleclk_ops = …; /** * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays * * @hw: Pointer to the hardware clock structure. * @degrees: The clock phase shift between 0 - 359. * * Set the SD Output Clock Tap Delays for Output path * * Return: 0 on success and error value on error */ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) { … } static const struct clk_ops versal_sdcardclk_ops = …; /** * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays * * @hw: Pointer to the hardware clock structure. * @degrees: The clock phase shift between 0 - 359. * * Set the SD Input Clock Tap Delays for Input path * * Return: 0 on success and error value on error */ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) { … } static const struct clk_ops versal_sampleclk_ops = …; static int sdhci_versal_net_emmc_sdcardclk_set_phase(struct clk_hw *hw, int degrees) { … } static const struct clk_ops versal_net_sdcardclk_ops = …; static int sdhci_versal_net_emmc_sampleclk_set_phase(struct clk_hw *hw, int degrees) { … } static const struct clk_ops versal_net_sampleclk_ops = …; static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid) { … } static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode) { … } /** * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier * * @host: The sdhci_host * @value: The value to write * * The corecfg_clockmultiplier is supposed to contain clock multiplier * value of programmable clock generator. * * NOTES: * - Many existing devices don't seem to do this and work fine. To keep * compatibility for old hardware where the device tree doesn't provide a * register map, this function is a noop if a soc_ctl_map hasn't been provided * for this platform. * - The value of corecfg_clockmultiplier should sync with that of corresponding * value reading from sdhci_capability_register. So this function is called * once at probe time and never called again. */ static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, u32 value) { … } /** * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq * * @host: The sdhci_host * * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This * function can be used to make that happen. * * NOTES: * - Many existing devices don't seem to do this and work fine. To keep * compatibility for old hardware where the device tree doesn't provide a * register map, this function is a noop if a soc_ctl_map hasn't been provided * for this platform. * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider * to achieve lower clock rates. That means that this function is called once * at probe time and never called again. */ static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host) { … } static void sdhci_arasan_set_clk_delays(struct sdhci_host *host) { … } static void arasan_dt_read_clk_phase(struct device *dev, struct sdhci_arasan_clk_data *clk_data, unsigned int timing, const char *prop) { … } /** * arasan_dt_parse_clk_phases - Read Clock Delay values from DT * * @dev: Pointer to our struct device. * @clk_data: Pointer to the Clock Data structure * * Called at initialization to parse the values of Clock Delays. */ static void arasan_dt_parse_clk_phases(struct device *dev, struct sdhci_arasan_clk_data *clk_data) { … } static const struct sdhci_pltfm_data sdhci_arasan_pdata = …; static const struct sdhci_arasan_clk_ops arasan_clk_ops = …; static struct sdhci_arasan_of_data sdhci_arasan_generic_data = …; static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = …; static const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = …; static const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = …; static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = …; static struct sdhci_arasan_of_data intel_lgm_emmc_data = …; static struct sdhci_arasan_of_data intel_lgm_sdxc_data = …; static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = …; static const struct sdhci_pltfm_data sdhci_arasan_versal_net_pdata = …; static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = …; static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = …; static const struct sdhci_arasan_clk_ops versal_clk_ops = …; static struct sdhci_arasan_of_data sdhci_arasan_versal_data = …; static const struct sdhci_arasan_clk_ops versal_net_clk_ops = …; static struct sdhci_arasan_of_data sdhci_arasan_versal_net_data = …; static struct sdhci_arasan_of_data intel_keembay_emmc_data = …; static struct sdhci_arasan_of_data intel_keembay_sd_data = …; static struct sdhci_arasan_of_data intel_keembay_sdio_data = …; static const struct of_device_id sdhci_arasan_of_match[] = …; MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); /** * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use * * @sdhci_arasan: Our private data structure. * @clk_xin: Pointer to the functional clock * @dev: Pointer to our struct device. * * Some PHY devices need to know what the actual card clock is. In order for * them to find out, we'll provide a clock through the common clock framework * for them to query. * * Return: 0 on success and error value on error */ static int sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, struct clk *clk_xin, struct device *dev) { … } /** * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use * * @sdhci_arasan: Our private data structure. * @clk_xin: Pointer to the functional clock * @dev: Pointer to our struct device. * * Some PHY devices need to know what the actual card clock is. In order for * them to find out, we'll provide a clock through the common clock framework * for them to query. * * Return: 0 on success and error value on error */ static int sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, struct clk *clk_xin, struct device *dev) { … } /** * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk() * * @dev: Pointer to our struct device. * * Should be called any time we're exiting and sdhci_arasan_register_sdclk() * returned success. */ static void sdhci_arasan_unregister_sdclk(struct device *dev) { … } /** * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support) * @host: The sdhci_host * @value: The value to write * * This should be set based on the System Address Bus. * 0: the Core supports only 32-bit System Address Bus. * 1: the Core supports 64-bit System Address Bus. * * NOTE: * For Keem Bay, it is required to clear this bit. Its default value is 1'b1. * Keem Bay does not support 64-bit access. */ static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value) { … } /** * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use * * @sdhci_arasan: Our private data structure. * @clk_xin: Pointer to the functional clock * @dev: Pointer to our struct device. * * Some PHY devices need to know what the actual card clock is. In order for * them to find out, we'll provide a clock through the common clock framework * for them to query. * * Note: without seriously re-architecting SDHCI's clock code and testing on * all platforms, there's no way to create a totally beautiful clock here * with all clock ops implemented. Instead, we'll just create a clock that can * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock * framework that we're doing things behind its back. This should be sufficient * to create nice clean device tree bindings and later (if needed) we can try * re-architecting SDHCI if we see some benefit to it. * * Return: 0 on success and error value on error */ static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, struct clk *clk_xin, struct device *dev) { … } static int sdhci_zynqmp_set_dynamic_config(struct device *dev, struct sdhci_arasan_data *sdhci_arasan) { … } static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan) { … } static int sdhci_arasan_probe(struct platform_device *pdev) { … } static void sdhci_arasan_remove(struct platform_device *pdev) { … } static struct platform_driver sdhci_arasan_driver = …; module_platform_driver(…) …; MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …;