/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013-2014,2020-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DRIVERS_MMC_SDHCI_MSM_H #define _DRIVERS_MMC_SDHCI_MSM_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sdhci-pltfm.h" #if IS_ENABLED(CONFIG_MMC_SDHCI_MSM_SCALING) #include "sdhci-msm-scaling.h" #endif #include "cqhci.h" #define MMC_CAP2_CLK_SCALE (1 << 28) /* Allow dynamic clk scaling */ /* CPU Clusters Info */ enum cpu_cluster_info { SILVER_CORE, GOLD_CORE, GOLD_PRIME_CORE, MAX_NUM_CLUSTERS, }; enum dev_state { DEV_SUSPENDING = 1, DEV_SUSPENDED, DEV_RESUMED, }; enum sdhci_msm_mmc_load { MMC_LOAD_HIGH, MMC_LOAD_LOW, }; /** * struct mmc_devfeq_clk_scaling - main context for MMC clock scaling logic * * @lock: spinlock to protect statistics * @devfreq: struct that represent mmc-host as a client for devfreq * @devfreq_profile: MMC device profile, mostly polling interval and callbacks * @ondemand_gov_data: struct supplied to ondemmand governor (thresholds) * @state: load state, can be HIGH or LOW. used to notify mmc_host_ops callback * @start_busy: timestamped armed once a data request is started * @measure_interval_start: timestamped armed once a measure interval started * @devfreq_abort: flag to sync between different contexts relevant to devfreq * @skip_clk_scale_freq_update: flag that enable/disable frequency change * @freq_table_sz: table size of frequencies supplied to devfreq * @freq_table: frequencies table supplied to devfreq * @curr_freq: current frequency * @polling_delay_ms: polling interval for status collection used by devfreq * @upthreshold: up-threshold supplied to ondemand governor * @downthreshold: down-threshold supplied to ondemand governor * @need_freq_change: flag indicating if a frequency change is required * @is_busy_started: flag indicating if a request is handled by the HW * @enable: flag indicating if the clock scaling logic is enabled for this host * @is_suspended: to make devfreq request queued when mmc is suspened */ #if IS_ENABLED(CONFIG_MMC_SDHCI_MSM_SCALING) struct sdhci_msm_mmc_devfeq_clk_scaling { spinlock_t lock; struct devfreq *devfreq; struct devfreq_dev_profile devfreq_profile; struct devfreq_simple_ondemand_data ondemand_gov_data; enum sdhci_msm_mmc_load state; ktime_t start_busy; ktime_t measure_interval_start; atomic_t devfreq_abort; bool skip_clk_scale_freq_update; int freq_table_sz; int pltfm_freq_table_sz; u32 *freq_table; u32 *pltfm_freq_table; unsigned long total_busy_time_us; unsigned long target_freq; unsigned long curr_freq; unsigned long polling_delay_ms; unsigned int upthreshold; unsigned int downthreshold; unsigned int lower_bus_speed_mode; #define MMC_SCALING_LOWER_DDR52_MODE 1 bool need_freq_change; bool is_busy_started; bool enable; bool is_suspended; }; #endif struct sdhci_msm_variant_ops { u32 (*msm_readl_relaxed)(struct sdhci_host *host, u32 offset); void (*msm_writel_relaxed)(u32 val, struct sdhci_host *host, u32 offset); }; struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; u32 core_mci_status; u32 core_mci_fifo_cnt; u32 core_mci_version; u32 core_generics; u32 core_testbus_config; u32 core_testbus_sel2_bit; u32 core_testbus_ena; u32 core_testbus_sel2; u32 core_pwrctl_status; u32 core_pwrctl_mask; u32 core_pwrctl_clear; u32 core_pwrctl_ctl; u32 core_sdcc_debug_reg; u32 core_dll_config; u32 core_dll_status; u32 core_vendor_spec; u32 core_vendor_spec_adma_err_addr0; u32 core_vendor_spec_adma_err_addr1; u32 core_vendor_spec_func2; u32 core_vendor_spec_capabilities0; u32 core_vendor_spec_capabilities1; u32 core_ddr_200_cfg; u32 core_vendor_spec3; u32 core_dll_config_2; u32 core_dll_config_3; u32 core_ddr_config_old; /* Applicable to sdcc minor ver < 0x49 */ u32 core_ddr_config; u32 core_dll_usr_ctl; /* Present on SDCC5.1 onwards */ }; /* This structure keeps information per regulator */ struct sdhci_msm_reg_data { struct sdhci_msm_host *msm_host; /* voltage regulator handle */ struct regulator *reg; /* regulator name */ const char *name; /* voltage level to be set */ u32 low_vol_level; u32 high_vol_level; /* Load values for low power and high power mode */ u32 lpm_uA; u32 hpm_uA; /* is this regulator enabled? */ bool is_enabled; /* is this regulator needs to be always on? */ bool is_always_on; /* is low power mode setting required for this regulator? */ bool lpm_sup; bool set_voltage_sup; bool is_voltage_supplied; }; /* * This structure keeps information for all the * regulators required for a SDCC slot. */ struct sdhci_msm_vreg_data { /* keeps VDD/VCC regulator info */ struct sdhci_msm_reg_data *vdd_data; /* keeps VDD IO regulator info */ struct sdhci_msm_reg_data *vdd_io_data; }; /* Per cpu cluster qos group */ struct qos_cpu_group { cpumask_t mask; /* CPU mask of cluster */ unsigned int *votes; /* Different votes for cluster */ struct dev_pm_qos_request *qos_req; /* Pointer to host qos request*/ bool voted; struct sdhci_msm_host *host; bool initialized; bool curr_vote; }; /* Per host qos request structure */ struct sdhci_msm_qos_req { struct qos_cpu_group *qcg; /* CPU group per host */ unsigned int num_groups; /* Number of groups */ unsigned int active_mask; /* Active affine irq mask */ }; enum constraint { QOS_PERF, QOS_POWER, QOS_MAX, }; struct sdhci_msm_bus_vote_data { const char *name; unsigned int num_usecase; struct msm_bus_path *usecase; unsigned int *bw_vecs; unsigned int bw_vecs_size; struct icc_path *sdhc_ddr; struct icc_path *cpu_sdhc; u32 curr_vote; }; /* * DLL registers which needs be programmed with HSR settings. * Add any new register only at the end and don't change the * sequence. */ struct sdhci_msm_dll_hsr { u32 dll_config; u32 dll_config_2; u32 dll_config_3; u32 dll_usr_ctl; u32 ddr_config; }; struct cqe_regs_restore { u32 cqe_vendor_cfg1; }; struct sdhci_msm_regs_restore { bool is_supported; bool is_valid; u32 vendor_pwrctl_mask; u32 vendor_pwrctl_ctl; u32 vendor_caps_0; u32 vendor_func; u32 vendor_func2; u32 vendor_func3; u32 hc_2c_2e; u32 hc_28_2a; u32 hc_34_36; u32 hc_38_3a; u32 hc_3c_3e; u32 hc_caps_1; u32 testbus_config; u32 dll_config; u32 dll_config2; u32 dll_config3; u32 dll_usr_ctl; }; struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ #ifdef CONFIG_MMC_CRYPTO void __iomem *ice_mem; /* MSM ICE mapped address (if available) */ #endif #if (IS_ENABLED(CONFIG_QTI_HW_KEY_MANAGER) || IS_ENABLED(CONFIG_QTI_HW_KEY_MANAGER_V1)) void __iomem *ice_hwkm_mem; #endif int pwr_irq; /* power irq */ struct clk *bus_clk; /* SDHC bus voter clock */ struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/ /* core, iface, ice, cal, sleep clocks */ struct clk_bulk_data bulk_clks[5]; unsigned long clk_rate; struct sdhci_msm_vreg_data *vreg_data; struct mmc_host *mmc; struct opp_table *opp_table; bool has_opp_table; struct cqhci_host *cq_host; bool use_14lpp_dll_reset; bool tuning_done; bool calibration_done; u8 saved_tuning_phase; bool use_cdclp533; u32 curr_pwr_state; u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; u32 caps_0; bool mci_removed; bool restore_dll_config; const struct sdhci_msm_variant_ops *var_ops; const struct sdhci_msm_offset *offset; bool use_cdr; u32 transfer_mode; bool updated_ddr_cfg; bool skip_bus_bw_voting; struct sdhci_msm_bus_vote_data *bus_vote_data; struct delayed_work bus_vote_work; struct delayed_work clk_gating_work; struct delayed_work pmqos_unvote_work; struct workqueue_struct *workq; /* QoS work queue */ struct sdhci_msm_qos_req *sdhci_qos; struct irq_affinity_notify affinity_notify; struct device_attribute clk_gating; struct device_attribute pm_qos; u32 clk_gating_delay; u32 pm_qos_delay; bool cqhci_offset_changed; bool reg_store; struct reset_control *core_reset; bool vbias_skip_wa; bool pltfm_init_done; bool fake_core_3_0v_support; bool core_3_0v_support; bool use_7nm_dll; struct sdhci_msm_dll_hsr *dll_hsr; struct sdhci_msm_regs_restore regs_restore; struct cqe_regs_restore cqe_regs; u32 *sup_ice_clk_table; unsigned char sup_ice_clk_cnt; u32 ice_clk_max; u32 ice_clk_min; u32 ice_clk_rate; bool uses_tassadar_dll; bool uses_level_shifter; bool dll_lock_bist_fail_wa; u32 dll_config; u32 ddr_config; u16 last_cmd; bool vqmmc_enabled; void *sdhci_msm_ipc_log_ctx; bool dbg_en; bool err_occurred; bool crash_on_err; #if IS_ENABLED(CONFIG_MMC_SDHCI_MSM_SCALING) struct sdhci_msm_mmc_devfeq_clk_scaling clk_scaling; #endif unsigned long clk_scaling_lowest; /* lowest scaleable * frequency. */ unsigned long clk_scaling_highest; /* highest scaleable * frequency. */ atomic_t active_reqs; unsigned int part_curr; int scale_caps; int clk_scale_init_done; int defer_clk_scaling_resume; int scaling_suspended; u8 raw_ext_csd_cmdq; u8 raw_ext_csd_cache_ctrl; u8 raw_ext_csd_bus_width; u8 raw_ext_csd_hs_timing; struct mmc_ios cached_ios; bool rst_n_disable; }; struct mmc_pwrseq_ops { void (*pre_power_on)(struct mmc_host *host); void (*post_power_on)(struct mmc_host *host); void (*power_off)(struct mmc_host *host); void (*reset)(struct mmc_host *host); }; struct mmc_pwrseq { struct mmc_pwrseq_ops *ops; struct device *dev; struct list_head pwrseq_node; struct module *owner; }; #endif