368 lines
9.7 KiB
C
368 lines
9.7 KiB
C
/* 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 <linux/of_device.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/mmc/mmc.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/interconnect.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/pm_qos.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/of.h>
|
|
#include <linux/reset.h>
|
|
|
|
#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
|