Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74f401c2 authored by Ram Prakash Gupta's avatar Ram Prakash Gupta
Browse files

mmc: sdhci-msm: Port base platform driver from 4.14 to 4.19



Port base platform driver from kernel 4.14 to 4.19.
This change brings in the base driver required to run basic
eMMC and SDCard driver and on top of this rest feature is
ported and enabled.
These files are taken from the 4.14 kernel directly, with some
feature removed, which are ported in subsequent change.

Change-Id: Ic331e507f2387a6d710b135ba96fe4565cadecbb
Signed-off-by: default avatarRam Prakash Gupta <rampraka@codeaurora.org>
parent 7747af63
Loading
Loading
Loading
Loading
+4585 −1248

File changed.

Preview size limit exceeded, changes collapsed.

+268 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 *
 */

#ifndef __SDHCI_MSM_H__
#define __SDHCI_MSM_H__

#include <linux/mmc/mmc.h>
#include <linux/pm_qos.h>
#include "sdhci-pltfm.h"

/* This structure keeps information per regulator */
struct sdhci_msm_reg_data {
	/* 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;
};

/*
 * This structure keeps information for all the
 * regulators required for a SDCC slot.
 */
struct sdhci_msm_slot_reg_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;
};

struct sdhci_msm_gpio {
	u32 no;
	const char *name;
	bool is_enabled;
};

struct sdhci_msm_gpio_data {
	struct sdhci_msm_gpio *gpio;
	u8 size;
};

struct sdhci_msm_pin_data {
	/*
	 * = 1 if controller pins are using gpios
	 * = 0 if controller has dedicated MSM pads
	 */
	u8 is_gpio;
	struct sdhci_msm_gpio_data *gpio_data;
};

struct sdhci_pinctrl_data {
	struct pinctrl          *pctrl;
	struct pinctrl_state    *pins_active;
	struct pinctrl_state    *pins_sleep;
	struct pinctrl_state    *pins_drv_type_400KHz;
	struct pinctrl_state    *pins_drv_type_50MHz;
	struct pinctrl_state    *pins_drv_type_100MHz;
	struct pinctrl_state    *pins_drv_type_200MHz;
};

struct sdhci_msm_bus_voting_data {
	struct msm_bus_scale_pdata *bus_pdata;
	unsigned int *bw_vecs;
	unsigned int bw_vecs_size;
};

struct sdhci_msm_cpu_group_map {
	int nr_groups;
	cpumask_t *mask;
};

struct sdhci_msm_pm_qos_latency {
	s32 latency[SDHCI_POWER_POLICY_NUM];
};

struct sdhci_msm_pm_qos_data {
	struct sdhci_msm_cpu_group_map cpu_group_map;
	enum pm_qos_req_type irq_req_type;
	int irq_cpu;
	struct sdhci_msm_pm_qos_latency irq_latency;
	struct sdhci_msm_pm_qos_latency *cmdq_latency;
	struct sdhci_msm_pm_qos_latency *latency;
	bool irq_valid;
	bool cmdq_valid;
	bool legacy_valid;
};

/*
 * PM QoS for group voting management - each cpu group defined is associated
 * with 1 instance of this structure.
 */
struct sdhci_msm_pm_qos_group {
	struct pm_qos_request req;
	struct delayed_work unvote_work;
	atomic_t counter;
	s32 latency;
};

/* PM QoS HW IRQ voting */
struct sdhci_msm_pm_qos_irq {
	struct pm_qos_request req;
	struct delayed_work unvote_work;
	struct device_attribute enable_attr;
	struct device_attribute status_attr;
	atomic_t counter;
	s32 latency;
	bool enabled;
};

struct sdhci_msm_pltfm_data {
	/* Supported UHS-I Modes */
	u32 caps;

	/* More capabilities */
	u32 caps2;

	unsigned long mmc_bus_width;
	struct sdhci_msm_slot_reg_data *vreg_data;
	bool nonremovable;
	bool nonhotplug;
	bool largeaddressbus;
	bool pin_cfg_sts;
	struct sdhci_msm_pin_data *pin_data;
	struct sdhci_pinctrl_data *pctrl_data;
	int status_gpio; /* card detection GPIO that is configured as IRQ */
	struct sdhci_msm_bus_voting_data *voting_data;
	u32 *sup_clk_table;
	unsigned char sup_clk_cnt;
	int sdiowakeup_irq;
	struct sdhci_msm_pm_qos_data pm_qos_data;
	u32 *bus_clk_table;
	unsigned char bus_clk_cnt;
};

struct sdhci_msm_bus_vote {
	uint32_t client_handle;
	uint32_t curr_vote;
	int min_bw_vote;
	int max_bw_vote;
	bool is_max_bw_needed;
	struct delayed_work vote_work;
	struct device_attribute max_bus_bw;
};

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;
};

/*
 * 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 sdhci_msm_debug_data {
	struct mmc_host copy_mmc;
	struct mmc_card copy_card;
	struct sdhci_host copy_host;
};

struct sdhci_msm_host {
	struct platform_device	*pdev;
	void __iomem *core_mem;    /* MSM SDCC mapped address */
	int	pwr_irq;	/* power irq */
	struct clk	 *clk;     /* main SD/MMC bus clock */
	struct clk	 *pclk;    /* SDHC peripheral bus clock */
	struct clk	 *bus_aggr_clk; /* Axi clock shared with UFS */
	struct clk	 *bus_clk; /* SDHC bus voter clock */
	struct clk	 *ff_clk; /* CDC calibration fixed feedback clock */
	struct clk	 *sleep_clk; /* CDC calibration sleep clock */
	atomic_t clks_on; /* Set if clocks are enabled */
	struct sdhci_msm_pltfm_data *pdata;
	struct mmc_host  *mmc;
	struct sdhci_msm_debug_data cached_data;
	struct sdhci_pltfm_data sdhci_msm_pdata;
	u32 curr_pwr_state;
	u32 curr_io_level;
	struct completion pwr_irq_completion;
	struct sdhci_msm_bus_vote msm_bus_vote;
	struct device_attribute	polling;
	u32 clk_rate; /* Keeps track of current clock rate that is set */
	bool tuning_done;
	bool calibration_done;
	u8 saved_tuning_phase;
	bool en_auto_cmd21;
	struct device_attribute auto_cmd21_attr;
	bool is_sdiowakeup_enabled;
	bool sdio_pending_processing;
	atomic_t controller_clock;
	bool use_cdclp533;
	bool use_updated_dll_reset;
	bool use_14lpp_dll;
	bool enhanced_strobe;
	bool rclk_delay_fix;
	u32 caps_0;
	struct sdhci_msm_pm_qos_group *pm_qos;
	int pm_qos_prev_cpu;
	struct device_attribute pm_qos_group_enable_attr;
	struct device_attribute pm_qos_group_status_attr;
	bool pm_qos_group_enable;
	struct sdhci_msm_pm_qos_irq pm_qos_irq;
	bool tuning_in_progress;
	bool mci_removed;
	const struct sdhci_msm_offset *offset;
	bool core_3_0v_support;
	bool pltfm_init_done;
	struct sdhci_msm_regs_restore regs_restore;
	bool use_7nm_dll;
	int soc_min_rev;
	struct workqueue_struct *pm_qos_wq;
	struct sdhci_msm_dll_hsr *dll_hsr;
};

extern char *saved_command_line;

void sdhci_msm_pm_qos_irq_init(struct sdhci_host *host);
void sdhci_msm_pm_qos_irq_vote(struct sdhci_host *host);
void sdhci_msm_pm_qos_irq_unvote(struct sdhci_host *host, bool async);

void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host,
		struct sdhci_msm_pm_qos_latency *latency);
void sdhci_msm_pm_qos_cpu_vote(struct sdhci_host *host,
		struct sdhci_msm_pm_qos_latency *latency, int cpu);
bool sdhci_msm_pm_qos_cpu_unvote(struct sdhci_host *host, int cpu, bool async);


#endif /* __SDHCI_MSM_H__ */
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ struct sdhci_pltfm_data {

struct sdhci_pltfm_host {
	struct clk *clk;
	void *priv; /* to handle quirks across io-accessor calls */

	/* migrate from sdhci_of_host */
	unsigned int clock;
+678 −102

File changed.

Preview size limit exceeded, changes collapsed.

+140 −3
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
#include <linux/io.h>
#include <linux/leds.h>
#include <linux/interrupt.h>

#include <linux/ratelimit.h>
#include <linux/mmc/host.h>

/*
@@ -151,12 +151,16 @@
#define  SDHCI_INT_ERROR_MASK	0xFFFF8000

#define  SDHCI_INT_CMD_MASK	(SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \
				SDHCI_INT_ACMD12ERR)

#define  SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
		SDHCI_INT_BLK_GAP)

#define SDHCI_INT_CMDQ_EN	(0x1 << 14)
#define SDHCI_INT_ALL_MASK	((unsigned int)-1)

#define SDHCI_CQE_INT_ERR_MASK ( \
@@ -167,6 +171,12 @@
#define SDHCI_CQE_INT_MASK (SDHCI_CQE_INT_ERR_MASK | SDHCI_INT_CQE)

#define SDHCI_ACMD12_ERR		0x3C
#define SDHCI_AUTO_CMD12_NOT_EXEC	0x0001
#define SDHCI_AUTO_CMD_TIMEOUT_ERR	0x0002
#define SDHCI_AUTO_CMD_CRC_ERR		0x0004
#define SDHCI_AUTO_CMD_ENDBIT_ERR	0x0008
#define SDHCI_AUTO_CMD_INDEX_ERR	0x0010
#define SDHCI_AUTO_CMD12_NOT_ISSUED	0x0080

#define SDHCI_HOST_CONTROL2		0x3E
#define  SDHCI_CTRL_UHS_MASK		0x0007
@@ -184,6 +194,7 @@
#define   SDHCI_CTRL_DRV_TYPE_D		0x0030
#define  SDHCI_CTRL_EXEC_TUNING		0x0040
#define  SDHCI_CTRL_TUNED_CLK		0x0080
#define  SDHCI_CTRL_ASYNC_INT_ENABLE	0x4000
#define  SDHCI_CTRL_PRESET_VAL_ENABLE	0x8000

#define SDHCI_CAPABILITIES	0x40
@@ -205,6 +216,7 @@
#define  SDHCI_CAN_VDD_300	0x02000000
#define  SDHCI_CAN_VDD_180	0x04000000
#define  SDHCI_CAN_64BIT	0x10000000
#define  SDHCI_CAN_ASYNC_INT	0x20000000

#define  SDHCI_SUPPORT_SDR50	0x00000001
#define  SDHCI_SUPPORT_SDR104	0x00000002
@@ -346,6 +358,12 @@ enum sdhci_cookie {
	COOKIE_MAPPED,		/* mapped by sdhci_prepare_data() */
};

enum sdhci_power_policy {
	SDHCI_PERFORMANCE_MODE,
	SDHCI_POWER_SAVE_MODE,
	SDHCI_POWER_POLICY_NUM /* Always keep this one last */
};

struct sdhci_host {
	/* Data set by hardware interface driver */
	const char *hw_name;	/* Hardware bus name */
@@ -451,6 +469,83 @@ struct sdhci_host {
 */
#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT			(1<<17)

/*
 * Read Transfer Active/ Write Transfer Active may be not
 * de-asserted after end of transaction. Issue reset for DAT line.
 */
#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT                 (1<<18)
/*
 * Slow interrupt clearance at 400KHz may cause
 * host controller driver interrupt handler to
 * be called twice.
 */
#define SDHCI_QUIRK2_SLOW_INT_CLR                       (1<<19)

/*
 * If the base clock can be scalable, then there should be no further
 * clock dividing as the input clock itself will be scaled down to
 * required frequency.
 */
#define SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK		(1<<20)

/*
 * Ignore data timeout error for R1B commands as there will be no
 * data associated and the busy timeout value for these commands
 * could be lager than the maximum timeout value that controller
 * can handle.
 */
#define SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD		(1<<21)

/*
 * The preset value registers are not properly initialized by
 * some hardware and hence preset value must not be enabled for
 * such controllers.
 */
#define SDHCI_QUIRK2_BROKEN_PRESET_VALUE		(1<<22)
/*
 * Some controllers define the usage of 0xF in data timeout counter
 * register (0x2E) which is actually a reserved bit as per
 * specification.
 */
#define SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT		(1<<23)
/*
 * This is applicable for controllers that advertize timeout clock
 * value in capabilities register (bit 5-0) as just 50MHz whereas the
 * base clock frequency is 200MHz. So, the controller internally
 * multiplies the value in timeout control register by 4 with the
 * assumption that driver always uses fixed timeout clock value from
 * capabilities register to calculate the timeout. But when the driver
 * uses SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK base clock frequency is directly
 * controller by driver and it's rate varies upto max. 200MHz. This new quirk
 * will be used in such cases to avoid controller mulplication when timeout is
 * calculated based on the base clock.
 */
#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1 << 24)

/*
 * Some SDHC controllers are unable to handle data-end bit error in
 * 1-bit mode of SDIO.
 */
#define SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR             (1<<25)

/* Use reset workaround in case sdhci reset timeouts */
#define SDHCI_QUIRK2_USE_RESET_WORKAROUND		(1<<26)

/* Some controllers doesn't have have any LED control */
#define SDHCI_QUIRK2_BROKEN_LED_CONTROL			(1<<27)

/*
 * Some controllers doesn't follow the tuning procedure as defined in spec.
 * The tuning data has to be compared from SW driver to validate the correct
 * phase.
 */
#define SDHCI_QUIRK2_NON_STANDARD_TUNING (1 << 28)
/*
 * Some controllers may use PIO mode to workaround HW issues in ADMA for
 * eMMC tuning commands.
 */
#define SDHCI_QUIRK2_USE_PIO_FOR_EMMC_TUNING (1 << 29)

	int irq;		/* Device IRQ */
	void __iomem *ioaddr;	/* Mapped address */
	char *bounce_buffer;	/* For packing SDMA reads/writes */
@@ -463,6 +558,7 @@ struct sdhci_host {
	struct mmc_host *mmc;	/* MMC structure */
	struct mmc_host_ops mmc_host_ops;	/* MMC host ops */
	u64 dma_mask;		/* custom DMA mask */
	u64 coherent_dma_mask;

#if IS_ENABLED(CONFIG_LEDS_CLASS)
	struct led_classdev led;	/* LED control */
@@ -486,6 +582,7 @@ struct sdhci_host {
#define SDHCI_SIGNALING_330	(1<<14)	/* Host is capable of 3.3V signaling */
#define SDHCI_SIGNALING_180	(1<<15)	/* Host is capable of 1.8V signaling */
#define SDHCI_SIGNALING_120	(1<<16)	/* Host is capable of 1.2V signaling */
#define SDHCI_HOST_IRQ_STATUS	(1<<17) /* host->irq status */

	unsigned int version;	/* SDHCI spec. version */

@@ -501,8 +598,10 @@ struct sdhci_host {
	bool preset_enabled;	/* Preset is enabled */
	bool pending_reset;	/* Cmd/data reset is pending */
	bool irq_wake_enabled;	/* IRQ wakeup is enabled */
	bool cdr_support;

	struct mmc_request *mrqs_done[SDHCI_MAX_MRQS];	/* Requests done */
	struct mmc_request *mrq;	/* Current request */
	struct mmc_command *cmd;	/* Current command */
	struct mmc_command *data_cmd;	/* Current data command */
	struct mmc_data *data;	/* Current data request */
@@ -565,6 +664,18 @@ struct sdhci_host {

	u64			data_timeout;

	ktime_t data_start_time;

	enum sdhci_power_policy power_policy;

	bool sdio_irq_async_status;

	u32 auto_cmd_err_sts;
	struct ratelimit_state dbg_dump_rs;
	int reset_wa_applied; /* reset workaround status */
	ktime_t reset_wa_t; /* time when the reset workaround is applied */
	int reset_wa_cnt; /* total number of times workaround is used */

	unsigned long private[0] ____cacheline_aligned;
};

@@ -601,8 +712,33 @@ struct sdhci_ops {
	void	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
	void	(*hw_reset)(struct sdhci_host *host);
	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
	unsigned int	(*get_max_segments)(void);
#define REQ_BUS_OFF     (1 << 0)
#define REQ_BUS_ON      (1 << 1)
#define REQ_IO_LOW      (1 << 2)
#define REQ_IO_HIGH     (1 << 3)
	void    (*card_event)(struct sdhci_host *host);
	int	(*enhanced_strobe)(struct sdhci_host *host);
	void    (*platform_bus_voting)(struct sdhci_host *host, u32 enable);
	void	(*toggle_cdr)(struct sdhci_host *host, bool enable);
	void    (*check_power_status)(struct sdhci_host *host, u32 req_type);
	int     (*config_auto_tuning_cmd)(struct sdhci_host *host,
					bool enable, u32 type);
	int     (*enable_controller_clock)(struct sdhci_host *host);
	void	(*clear_set_dumpregs)(struct sdhci_host *host, bool set);
	void	(*enhanced_strobe_mask)(struct sdhci_host *host, bool set);
	void    (*dump_vendor_regs)(struct sdhci_host *host);
	void	(*voltage_switch)(struct sdhci_host *host);
	int	(*select_drive_strength)(struct sdhci_host *host,
					 struct mmc_card *card,
					 unsigned int max_dtr, int host_drv,
					 int card_drv, int *drv_type);
	int	(*notify_load)(struct sdhci_host *host, enum mmc_load state);
	void	(*reset_workaround)(struct sdhci_host *host, u32 enable);
	void	(*init)(struct sdhci_host *host);
	void	(*pre_req)(struct sdhci_host *host, struct mmc_request *req);
	void	(*post_req)(struct sdhci_host *host, struct mmc_request *req);
	unsigned int	(*get_current_limit)(struct sdhci_host *host);
};

#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -753,4 +889,5 @@ void sdhci_end_tuning(struct sdhci_host *host);
void sdhci_reset_tuning(struct sdhci_host *host);
void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);

void sdhci_cfg_irq(struct sdhci_host *host, bool enable, bool sync);
#endif /* __SDHCI_HW_H */
Loading