summaryrefslogtreecommitdiff
path: root/drivers/ufs/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ufs/host')
-rw-r--r--drivers/ufs/host/cdns-pltfrm.c27
-rw-r--r--drivers/ufs/host/tc-dwc-g210-pci.c2
-rw-r--r--drivers/ufs/host/tc-dwc-g210.c32
-rw-r--r--drivers/ufs/host/ti-j721e-ufs.c2
-rw-r--r--drivers/ufs/host/ufs-mediatek.c180
-rw-r--r--drivers/ufs/host/ufs-mediatek.h33
-rw-r--r--drivers/ufs/host/ufs-qcom.c174
-rw-r--r--drivers/ufs/host/ufs-qcom.h4
-rw-r--r--drivers/ufs/host/ufs-renesas.c2
-rw-r--r--drivers/ufs/host/ufshcd-dwc.c22
-rw-r--r--drivers/ufs/host/ufshcd-pci.c3
-rw-r--r--drivers/ufs/host/ufshcd-pltfrm.c13
12 files changed, 410 insertions, 84 deletions
diff --git a/drivers/ufs/host/cdns-pltfrm.c b/drivers/ufs/host/cdns-pltfrm.c
index 26761425a76c..2491e7e87028 100644
--- a/drivers/ufs/host/cdns-pltfrm.c
+++ b/drivers/ufs/host/cdns-pltfrm.c
@@ -101,11 +101,10 @@ static void cdns_ufs_set_l4_attr(struct ufs_hba *hba)
}
/**
- * cdns_ufs_set_hclkdiv()
- * Sets HCLKDIV register value based on the core_clk
+ * cdns_ufs_set_hclkdiv() - set HCLKDIV register value based on the core_clk.
* @hba: host controller instance
*
- * Return zero for success and non-zero for failure
+ * Return: zero for success and non-zero for failure.
*/
static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba)
{
@@ -143,12 +142,11 @@ static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba)
}
/**
- * cdns_ufs_hce_enable_notify()
- * Called before and after HCE enable bit is set.
+ * cdns_ufs_hce_enable_notify() - set HCLKDIV register
* @hba: host controller instance
* @status: notify stage (pre, post change)
*
- * Return zero for success and non-zero for failure
+ * Return: zero for success and non-zero for failure.
*/
static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
@@ -160,12 +158,10 @@ static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba,
}
/**
- * cdns_ufs_hibern8_notify()
- * Called around hibern8 enter/exit.
+ * cdns_ufs_hibern8_notify() - save and restore L4 attributes.
* @hba: host controller instance
* @cmd: UIC Command
* @status: notify stage (pre, post change)
- *
*/
static void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd,
enum ufs_notify_change_status status)
@@ -177,12 +173,11 @@ static void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd,
}
/**
- * cdns_ufs_link_startup_notify()
- * Called before and after Link startup is carried out.
+ * cdns_ufs_link_startup_notify() - handle link startup.
* @hba: host controller instance
* @status: notify stage (pre, post change)
*
- * Return zero for success and non-zero for failure
+ * Return: zero for success and non-zero for failure.
*/
static int cdns_ufs_link_startup_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
@@ -212,7 +207,7 @@ static int cdns_ufs_link_startup_notify(struct ufs_hba *hba,
* cdns_ufs_init - performs additional ufs initialization
* @hba: host controller instance
*
- * Returns status of initialization
+ * Return: status of initialization.
*/
static int cdns_ufs_init(struct ufs_hba *hba)
{
@@ -235,7 +230,7 @@ static int cdns_ufs_init(struct ufs_hba *hba)
* cdns_ufs_m31_16nm_phy_initialization - performs m31 phy initialization
* @hba: host controller instance
*
- * Always returns 0
+ * Return: 0 (success).
*/
static int cdns_ufs_m31_16nm_phy_initialization(struct ufs_hba *hba)
{
@@ -284,7 +279,7 @@ MODULE_DEVICE_TABLE(of, cdns_ufs_of_match);
* cdns_ufs_pltfrm_probe - probe routine of the driver
* @pdev: pointer to platform device handle
*
- * Return zero for success and non-zero for failure
+ * Return: zero for success and non-zero for failure.
*/
static int cdns_ufs_pltfrm_probe(struct platform_device *pdev)
{
@@ -308,7 +303,7 @@ static int cdns_ufs_pltfrm_probe(struct platform_device *pdev)
* cdns_ufs_pltfrm_remove - removes the ufs driver
* @pdev: pointer to platform device handle
*
- * Always returns 0
+ * Return: 0 (success).
*/
static int cdns_ufs_pltfrm_remove(struct platform_device *pdev)
{
diff --git a/drivers/ufs/host/tc-dwc-g210-pci.c b/drivers/ufs/host/tc-dwc-g210-pci.c
index f96fe5855841..876781fd6861 100644
--- a/drivers/ufs/host/tc-dwc-g210-pci.c
+++ b/drivers/ufs/host/tc-dwc-g210-pci.c
@@ -51,7 +51,7 @@ static void tc_dwc_g210_pci_remove(struct pci_dev *pdev)
* @pdev: pointer to PCI device handle
* @id: PCI device id
*
- * Returns 0 on success, non-zero value on failure
+ * Return: 0 on success, non-zero value on failure.
*/
static int
tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ufs/host/tc-dwc-g210.c b/drivers/ufs/host/tc-dwc-g210.c
index deb93dbd83a4..0ac53cc8465e 100644
--- a/drivers/ufs/host/tc-dwc-g210.c
+++ b/drivers/ufs/host/tc-dwc-g210.c
@@ -17,11 +17,10 @@
#include "tc-dwc-g210.h"
/**
- * tc_dwc_g210_setup_40bit_rmmi()
- * This function configures Synopsys TC specific atributes (40-bit RMMI)
+ * tc_dwc_g210_setup_40bit_rmmi() - configure 40-bit RMMI.
* @hba: Pointer to drivers structure
*
- * Returns 0 on success or non-zero value on failure
+ * Return: 0 on success or non-zero value on failure.
*/
static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba)
{
@@ -81,11 +80,10 @@ static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba)
}
/**
- * tc_dwc_g210_setup_20bit_rmmi_lane0()
- * This function configures Synopsys TC 20-bit RMMI Lane 0
+ * tc_dwc_g210_setup_20bit_rmmi_lane0() - configure 20-bit RMMI Lane 0.
* @hba: Pointer to drivers structure
*
- * Returns 0 on success or non-zero value on failure
+ * Return: 0 on success or non-zero value on failure.
*/
static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba)
{
@@ -134,11 +132,10 @@ static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba)
}
/**
- * tc_dwc_g210_setup_20bit_rmmi_lane1()
- * This function configures Synopsys TC 20-bit RMMI Lane 1
+ * tc_dwc_g210_setup_20bit_rmmi_lane1() - configure 20-bit RMMI Lane 1.
* @hba: Pointer to drivers structure
*
- * Returns 0 on success or non-zero value on failure
+ * Return: 0 on success or non-zero value on failure.
*/
static int tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba *hba)
{
@@ -211,11 +208,10 @@ out:
}
/**
- * tc_dwc_g210_setup_20bit_rmmi()
- * This function configures Synopsys TC specific atributes (20-bit RMMI)
+ * tc_dwc_g210_setup_20bit_rmmi() - configure 20-bit RMMI.
* @hba: Pointer to drivers structure
*
- * Returns 0 on success or non-zero value on failure
+ * Return: 0 on success or non-zero value on failure.
*/
static int tc_dwc_g210_setup_20bit_rmmi(struct ufs_hba *hba)
{
@@ -251,12 +247,10 @@ out:
}
/**
- * tc_dwc_g210_config_40_bit()
- * This function configures Local (host) Synopsys 40-bit TC specific attributes
- *
+ * tc_dwc_g210_config_40_bit() - configure 40-bit TC specific attributes.
* @hba: Pointer to drivers structure
*
- * Returns 0 on success non-zero value on failure
+ * Return: 0 on success non-zero value on failure.
*/
int tc_dwc_g210_config_40_bit(struct ufs_hba *hba)
{
@@ -283,12 +277,10 @@ out:
EXPORT_SYMBOL(tc_dwc_g210_config_40_bit);
/**
- * tc_dwc_g210_config_20_bit()
- * This function configures Local (host) Synopsys 20-bit TC specific attributes
- *
+ * tc_dwc_g210_config_20_bit() - configure 20-bit TC specific attributes.
* @hba: Pointer to drivers structure
*
- * Returns 0 on success non-zero value on failure
+ * Return: 0 on success non-zero value on failure.
*/
int tc_dwc_g210_config_20_bit(struct ufs_hba *hba)
{
diff --git a/drivers/ufs/host/ti-j721e-ufs.c b/drivers/ufs/host/ti-j721e-ufs.c
index 122d650d0810..117eb7da92ac 100644
--- a/drivers/ufs/host/ti-j721e-ufs.c
+++ b/drivers/ufs/host/ti-j721e-ufs.c
@@ -81,6 +81,8 @@ static const struct of_device_id ti_j721e_ufs_of_match[] = {
{ },
};
+MODULE_DEVICE_TABLE(of, ti_j721e_ufs_of_match);
+
static struct platform_driver ti_j721e_ufs_driver = {
.probe = ti_j721e_ufs_probe,
.remove = ti_j721e_ufs_remove,
diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index e68b05976f9e..2383ecd88f1c 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -14,6 +14,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
@@ -27,8 +28,14 @@
#include <ufs/unipro.h>
#include "ufs-mediatek.h"
+static int ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq);
+
#define CREATE_TRACE_POINTS
#include "ufs-mediatek-trace.h"
+#undef CREATE_TRACE_POINTS
+
+#define MAX_SUPP_MAC 64
+#define MCQ_QUEUE_OFFSET(c) ((((c) >> 16) & 0xFF) * 0x200)
static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
{ .wmanufacturerid = UFS_ANY_VENDOR,
@@ -659,7 +666,7 @@ static void ufs_mtk_pwr_ctrl(struct ufs_hba *hba, bool on)
* @on: If true, enable clocks else disable them.
* @status: PRE_CHANGE or POST_CHANGE notify
*
- * Returns 0 on success, non-zero on failure.
+ * Return: 0 on success, non-zero on failure.
*/
static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
enum ufs_notify_change_status status)
@@ -840,6 +847,37 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
}
}
+static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+ struct platform_device *pdev;
+ int i;
+ int irq;
+
+ host->mcq_nr_intr = UFSHCD_MAX_Q_NR;
+ pdev = container_of(hba->dev, struct platform_device, dev);
+
+ for (i = 0; i < host->mcq_nr_intr; i++) {
+ /* irq index 0 is legacy irq, sq/cq irq start from index 1 */
+ irq = platform_get_irq(pdev, i + 1);
+ if (irq < 0) {
+ host->mcq_intr_info[i].irq = MTK_MCQ_INVALID_IRQ;
+ goto failed;
+ }
+ host->mcq_intr_info[i].hba = hba;
+ host->mcq_intr_info[i].irq = irq;
+ dev_info(hba->dev, "get platform mcq irq: %d, %d\n", i, irq);
+ }
+
+ return;
+failed:
+ /* invalidate irq info */
+ for (i = 0; i < host->mcq_nr_intr; i++)
+ host->mcq_intr_info[i].irq = MTK_MCQ_INVALID_IRQ;
+
+ host->mcq_nr_intr = 0;
+}
+
/**
* ufs_mtk_init - find other essential mmio bases
* @hba: host controller instance
@@ -847,7 +885,7 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
* Binds PHY with controller and powers up PHY enabling clocks
* and regulators.
*
- * Returns -EPROBE_DEFER if binding fails, returns negative error
+ * Return: -EPROBE_DEFER if binding fails, returns negative error
* on phy power up failure and returns zero on success.
*/
static int ufs_mtk_init(struct ufs_hba *hba)
@@ -876,6 +914,8 @@ static int ufs_mtk_init(struct ufs_hba *hba)
/* Initialize host capability */
ufs_mtk_init_host_caps(hba);
+ ufs_mtk_init_mcq_irq(hba);
+
err = ufs_mtk_bind_mphy(hba);
if (err)
goto out_variant_clear;
@@ -1173,7 +1213,17 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba)
else
return err;
- err = ufshcd_make_hba_operational(hba);
+ if (!hba->mcq_enabled) {
+ err = ufshcd_make_hba_operational(hba);
+ } else {
+ ufs_mtk_config_mcq(hba, false);
+ ufshcd_mcq_make_queues_operational(hba);
+ ufshcd_mcq_config_mac(hba, hba->nutrs);
+ /* Enable MCQ mode */
+ ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x1,
+ REG_UFS_MEM_CFG);
+ }
+
if (err)
return err;
@@ -1497,6 +1547,121 @@ static int ufs_mtk_clk_scale_notify(struct ufs_hba *hba, bool scale_up,
return 0;
}
+static int ufs_mtk_get_hba_mac(struct ufs_hba *hba)
+{
+ return MAX_SUPP_MAC;
+}
+
+static int ufs_mtk_op_runtime_config(struct ufs_hba *hba)
+{
+ struct ufshcd_mcq_opr_info_t *opr;
+ int i;
+
+ hba->mcq_opr[OPR_SQD].offset = REG_UFS_MTK_SQD;
+ hba->mcq_opr[OPR_SQIS].offset = REG_UFS_MTK_SQIS;
+ hba->mcq_opr[OPR_CQD].offset = REG_UFS_MTK_CQD;
+ hba->mcq_opr[OPR_CQIS].offset = REG_UFS_MTK_CQIS;
+
+ for (i = 0; i < OPR_MAX; i++) {
+ opr = &hba->mcq_opr[i];
+ opr->stride = REG_UFS_MCQ_STRIDE;
+ opr->base = hba->mmio_base + opr->offset;
+ }
+
+ return 0;
+}
+
+static int ufs_mtk_mcq_config_resource(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+
+ /* fail mcq initialization if interrupt is not filled properly */
+ if (!host->mcq_nr_intr) {
+ dev_info(hba->dev, "IRQs not ready. MCQ disabled.");
+ return -EINVAL;
+ }
+
+ hba->mcq_base = hba->mmio_base + MCQ_QUEUE_OFFSET(hba->mcq_capabilities);
+ return 0;
+}
+
+static irqreturn_t ufs_mtk_mcq_intr(int irq, void *__intr_info)
+{
+ struct ufs_mtk_mcq_intr_info *mcq_intr_info = __intr_info;
+ struct ufs_hba *hba = mcq_intr_info->hba;
+ struct ufs_hw_queue *hwq;
+ u32 events;
+ int qid = mcq_intr_info->qid;
+
+ hwq = &hba->uhq[qid];
+
+ events = ufshcd_mcq_read_cqis(hba, qid);
+ if (events)
+ ufshcd_mcq_write_cqis(hba, events, qid);
+
+ if (events & UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS)
+ ufshcd_mcq_poll_cqe_lock(hba, hwq);
+
+ return IRQ_HANDLED;
+}
+
+static int ufs_mtk_config_mcq_irq(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+ u32 irq, i;
+ int ret;
+
+ for (i = 0; i < host->mcq_nr_intr; i++) {
+ irq = host->mcq_intr_info[i].irq;
+ if (irq == MTK_MCQ_INVALID_IRQ) {
+ dev_err(hba->dev, "invalid irq. %d\n", i);
+ return -ENOPARAM;
+ }
+
+ host->mcq_intr_info[i].qid = i;
+ ret = devm_request_irq(hba->dev, irq, ufs_mtk_mcq_intr, 0, UFSHCD,
+ &host->mcq_intr_info[i]);
+
+ dev_dbg(hba->dev, "request irq %d intr %s\n", irq, ret ? "failed" : "");
+
+ if (ret) {
+ dev_err(hba->dev, "Cannot request irq %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+ int ret = 0;
+
+ if (!host->mcq_set_intr) {
+ /* Disable irq option register */
+ ufshcd_rmwl(hba, MCQ_INTR_EN_MSK, 0, REG_UFS_MMIO_OPT_CTRL_0);
+
+ if (irq) {
+ ret = ufs_mtk_config_mcq_irq(hba);
+ if (ret)
+ return ret;
+ }
+
+ host->mcq_set_intr = true;
+ }
+
+ ufshcd_rmwl(hba, MCQ_AH8, MCQ_AH8, REG_UFS_MMIO_OPT_CTRL_0);
+ ufshcd_rmwl(hba, MCQ_INTR_EN_MSK, MCQ_MULTI_INTR_EN, REG_UFS_MMIO_OPT_CTRL_0);
+
+ return 0;
+}
+
+static int ufs_mtk_config_esi(struct ufs_hba *hba)
+{
+ return ufs_mtk_config_mcq(hba, true);
+}
+
/*
* struct ufs_hba_mtk_vops - UFS MTK specific variant operations
*
@@ -1520,13 +1685,18 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
.event_notify = ufs_mtk_event_notify,
.config_scaling_param = ufs_mtk_config_scaling_param,
.clk_scale_notify = ufs_mtk_clk_scale_notify,
+ /* mcq vops */
+ .get_hba_mac = ufs_mtk_get_hba_mac,
+ .op_runtime_config = ufs_mtk_op_runtime_config,
+ .mcq_config_resource = ufs_mtk_mcq_config_resource,
+ .config_esi = ufs_mtk_config_esi,
};
/**
* ufs_mtk_probe - probe routine of the driver
* @pdev: pointer to Platform device handle
*
- * Return zero for success and non-zero for failure
+ * Return: zero for success and non-zero for failure.
*/
static int ufs_mtk_probe(struct platform_device *pdev)
{
@@ -1566,7 +1736,7 @@ skip_reset:
out:
if (err)
- dev_info(dev, "probe failed %d\n", err);
+ dev_err(dev, "probe failed %d\n", err);
of_node_put(reset_node);
return err;
diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h
index 2fc6d7b87694..f76e80d91729 100644
--- a/drivers/ufs/host/ufs-mediatek.h
+++ b/drivers/ufs/host/ufs-mediatek.h
@@ -11,10 +11,26 @@
#include <linux/soc/mediatek/mtk_sip_svc.h>
/*
+ * MCQ define and struct
+ */
+#define UFSHCD_MAX_Q_NR 8
+#define MTK_MCQ_INVALID_IRQ 0xFFFF
+
+/* REG_UFS_MMIO_OPT_CTRL_0 160h */
+#define EHS_EN BIT(0)
+#define PFM_IMPV BIT(1)
+#define MCQ_MULTI_INTR_EN BIT(2)
+#define MCQ_CMB_INTR_EN BIT(3)
+#define MCQ_AH8 BIT(4)
+
+#define MCQ_INTR_EN_MSK (MCQ_MULTI_INTR_EN | MCQ_CMB_INTR_EN)
+
+/*
* Vendor specific UFSHCI Registers
*/
#define REG_UFS_XOUFS_CTRL 0x140
#define REG_UFS_REFCLK_CTRL 0x144
+#define REG_UFS_MMIO_OPT_CTRL_0 0x160
#define REG_UFS_EXTREG 0x2100
#define REG_UFS_MPHYCTRL 0x2200
#define REG_UFS_MTK_IP_VER 0x2240
@@ -26,6 +42,13 @@
#define REG_UFS_DEBUG_SEL_B2 0x22D8
#define REG_UFS_DEBUG_SEL_B3 0x22DC
+#define REG_UFS_MTK_SQD 0x2800
+#define REG_UFS_MTK_SQIS 0x2814
+#define REG_UFS_MTK_CQD 0x281C
+#define REG_UFS_MTK_CQIS 0x2824
+
+#define REG_UFS_MCQ_STRIDE 0x30
+
/*
* Ref-clk control
*
@@ -136,6 +159,12 @@ struct ufs_mtk_hw_ver {
u8 major;
};
+struct ufs_mtk_mcq_intr_info {
+ struct ufs_hba *hba;
+ u32 irq;
+ u8 qid;
+};
+
struct ufs_mtk_host {
struct phy *mphy;
struct pm_qos_request pm_qos_req;
@@ -155,6 +184,10 @@ struct ufs_mtk_host {
u16 ref_clk_ungating_wait_us;
u16 ref_clk_gating_wait_us;
u32 ip_ver;
+
+ bool mcq_set_intr;
+ int mcq_nr_intr;
+ struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR];
};
/*
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index c1557d21b027..d1149b1c3ed5 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -7,6 +7,7 @@
#include <linux/time.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -46,6 +47,49 @@ enum {
TSTBUS_MAX,
};
+#define QCOM_UFS_MAX_GEAR 4
+#define QCOM_UFS_MAX_LANE 2
+
+enum {
+ MODE_MIN,
+ MODE_PWM,
+ MODE_HS_RA,
+ MODE_HS_RB,
+ MODE_MAX,
+};
+
+static const struct __ufs_qcom_bw_table {
+ u32 mem_bw;
+ u32 cfg_bw;
+} ufs_qcom_bw_table[MODE_MAX + 1][QCOM_UFS_MAX_GEAR + 1][QCOM_UFS_MAX_LANE + 1] = {
+ [MODE_MIN][0][0] = { 0, 0 }, /* Bandwidth values in KB/s */
+ [MODE_PWM][UFS_PWM_G1][UFS_LANE_1] = { 922, 1000 },
+ [MODE_PWM][UFS_PWM_G2][UFS_LANE_1] = { 1844, 1000 },
+ [MODE_PWM][UFS_PWM_G3][UFS_LANE_1] = { 3688, 1000 },
+ [MODE_PWM][UFS_PWM_G4][UFS_LANE_1] = { 7376, 1000 },
+ [MODE_PWM][UFS_PWM_G1][UFS_LANE_2] = { 1844, 1000 },
+ [MODE_PWM][UFS_PWM_G2][UFS_LANE_2] = { 3688, 1000 },
+ [MODE_PWM][UFS_PWM_G3][UFS_LANE_2] = { 7376, 1000 },
+ [MODE_PWM][UFS_PWM_G4][UFS_LANE_2] = { 14752, 1000 },
+ [MODE_HS_RA][UFS_HS_G1][UFS_LANE_1] = { 127796, 1000 },
+ [MODE_HS_RA][UFS_HS_G2][UFS_LANE_1] = { 255591, 1000 },
+ [MODE_HS_RA][UFS_HS_G3][UFS_LANE_1] = { 1492582, 102400 },
+ [MODE_HS_RA][UFS_HS_G4][UFS_LANE_1] = { 2915200, 204800 },
+ [MODE_HS_RA][UFS_HS_G1][UFS_LANE_2] = { 255591, 1000 },
+ [MODE_HS_RA][UFS_HS_G2][UFS_LANE_2] = { 511181, 1000 },
+ [MODE_HS_RA][UFS_HS_G3][UFS_LANE_2] = { 1492582, 204800 },
+ [MODE_HS_RA][UFS_HS_G4][UFS_LANE_2] = { 2915200, 409600 },
+ [MODE_HS_RB][UFS_HS_G1][UFS_LANE_1] = { 149422, 1000 },
+ [MODE_HS_RB][UFS_HS_G2][UFS_LANE_1] = { 298189, 1000 },
+ [MODE_HS_RB][UFS_HS_G3][UFS_LANE_1] = { 1492582, 102400 },
+ [MODE_HS_RB][UFS_HS_G4][UFS_LANE_1] = { 2915200, 204800 },
+ [MODE_HS_RB][UFS_HS_G1][UFS_LANE_2] = { 298189, 1000 },
+ [MODE_HS_RB][UFS_HS_G2][UFS_LANE_2] = { 596378, 1000 },
+ [MODE_HS_RB][UFS_HS_G3][UFS_LANE_2] = { 1492582, 204800 },
+ [MODE_HS_RB][UFS_HS_G4][UFS_LANE_2] = { 2915200, 409600 },
+ [MODE_MAX][0][0] = { 7643136, 307200 },
+};
+
static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
@@ -485,7 +529,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
}
/*
- * Returns zero for success and non-zero in case of a failure
+ * Return: zero for success and non-zero in case of a failure.
*/
static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
u32 hs, u32 rate, bool update_link_startup_timer)
@@ -789,6 +833,51 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
}
}
+static int ufs_qcom_icc_set_bw(struct ufs_qcom_host *host, u32 mem_bw, u32 cfg_bw)
+{
+ struct device *dev = host->hba->dev;
+ int ret;
+
+ ret = icc_set_bw(host->icc_ddr, 0, mem_bw);
+ if (ret < 0) {
+ dev_err(dev, "failed to set bandwidth request: %d\n", ret);
+ return ret;
+ }
+
+ ret = icc_set_bw(host->icc_cpu, 0, cfg_bw);
+ if (ret < 0) {
+ dev_err(dev, "failed to set bandwidth request: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct __ufs_qcom_bw_table ufs_qcom_get_bw_table(struct ufs_qcom_host *host)
+{
+ struct ufs_pa_layer_attr *p = &host->dev_req_params;
+ int gear = max_t(u32, p->gear_rx, p->gear_tx);
+ int lane = max_t(u32, p->lane_rx, p->lane_tx);
+
+ if (ufshcd_is_hs_mode(p)) {
+ if (p->hs_rate == PA_HS_MODE_B)
+ return ufs_qcom_bw_table[MODE_HS_RB][gear][lane];
+ else
+ return ufs_qcom_bw_table[MODE_HS_RA][gear][lane];
+ } else {
+ return ufs_qcom_bw_table[MODE_PWM][gear][lane];
+ }
+}
+
+static int ufs_qcom_icc_update_bw(struct ufs_qcom_host *host)
+{
+ struct __ufs_qcom_bw_table bw_table;
+
+ bw_table = ufs_qcom_get_bw_table(host);
+
+ return ufs_qcom_icc_set_bw(host, bw_table.mem_bw, bw_table.cfg_bw);
+}
+
static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status,
struct ufs_pa_layer_attr *dev_max_params,
@@ -852,6 +941,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
memcpy(&host->dev_req_params,
dev_req_params, sizeof(*dev_req_params));
+ ufs_qcom_icc_update_bw(host);
+
/* disable the device ref clock if entered PWM mode */
if (ufshcd_is_hs_mode(&hba->pwr_info) &&
!ufshcd_is_hs_mode(dev_req_params))
@@ -964,7 +1055,7 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
* @on: If true, enable clocks else disable them.
* @status: PRE_CHANGE or POST_CHANGE notify
*
- * Returns 0 on success, non-zero on failure.
+ * Return: 0 on success, non-zero on failure.
*/
static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
enum ufs_notify_change_status status)
@@ -981,7 +1072,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
switch (status) {
case PRE_CHANGE:
- if (!on) {
+ if (on) {
+ ufs_qcom_icc_update_bw(host);
+ } else {
if (!ufs_qcom_is_link_active(hba)) {
/* disable device ref_clk */
ufs_qcom_dev_ref_clk_ctrl(host, false);
@@ -993,6 +1086,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
/* enable the device ref clock for HS mode*/
if (ufshcd_is_hs_mode(&hba->pwr_info))
ufs_qcom_dev_ref_clk_ctrl(host, true);
+ } else {
+ ufs_qcom_icc_set_bw(host, ufs_qcom_bw_table[MODE_MIN][0][0].mem_bw,
+ ufs_qcom_bw_table[MODE_MIN][0][0].cfg_bw);
}
break;
}
@@ -1031,6 +1127,34 @@ static const struct reset_control_ops ufs_qcom_reset_ops = {
.deassert = ufs_qcom_reset_deassert,
};
+static int ufs_qcom_icc_init(struct ufs_qcom_host *host)
+{
+ struct device *dev = host->hba->dev;
+ int ret;
+
+ host->icc_ddr = devm_of_icc_get(dev, "ufs-ddr");
+ if (IS_ERR(host->icc_ddr))
+ return dev_err_probe(dev, PTR_ERR(host->icc_ddr),
+ "failed to acquire interconnect path\n");
+
+ host->icc_cpu = devm_of_icc_get(dev, "cpu-ufs");
+ if (IS_ERR(host->icc_cpu))
+ return dev_err_probe(dev, PTR_ERR(host->icc_cpu),
+ "failed to acquire interconnect path\n");
+
+ /*
+ * Set Maximum bandwidth vote before initializing the UFS controller and
+ * device. Ideally, a minimal interconnect vote would suffice for the
+ * initialization, but a max vote would allow faster initialization.
+ */
+ ret = ufs_qcom_icc_set_bw(host, ufs_qcom_bw_table[MODE_MAX][0][0].mem_bw,
+ ufs_qcom_bw_table[MODE_MAX][0][0].cfg_bw);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to set bandwidth request\n");
+
+ return 0;
+}
+
/**
* ufs_qcom_init - bind phy with controller
* @hba: host controller instance
@@ -1038,7 +1162,7 @@ static const struct reset_control_ops ufs_qcom_reset_ops = {
* Binds PHY with controller and powers up PHY enabling clocks
* and regulators.
*
- * Returns -EPROBE_DEFER if binding fails, returns negative error
+ * Return: -EPROBE_DEFER if binding fails, returns negative error
* on phy power up failure and returns zero on success.
*/
static int ufs_qcom_init(struct ufs_hba *hba)
@@ -1085,6 +1209,10 @@ static int ufs_qcom_init(struct ufs_hba *hba)
}
}
+ err = ufs_qcom_icc_init(host);
+ if (err)
+ goto out_variant_clear;
+
host->device_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(host->device_reset)) {
@@ -1254,6 +1382,10 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;
int err = 0;
+ /* check the host controller state before sending hibern8 cmd */
+ if (!ufshcd_is_hba_active(hba))
+ return 0;
+
if (status == PRE_CHANGE) {
err = ufshcd_uic_hibern8_enter(hba);
if (err)
@@ -1282,6 +1414,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
dev_req_params->pwr_rx,
dev_req_params->hs_rate,
false);
+ ufs_qcom_icc_update_bw(host);
ufshcd_uic_hibern8_exit(hba);
}
@@ -1483,6 +1616,7 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
struct devfreq_simple_ondemand_data *d)
{
p->polling_ms = 60;
+ p->timer = DEVFREQ_TIMER_DELAYED;
d->upthreshold = 70;
d->downdifferential = 5;
}
@@ -1643,11 +1777,12 @@ static void ufs_qcom_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
ufshcd_mcq_config_esi(hba, msg);
}
-static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *__hba)
+static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data)
{
- struct ufs_hba *hba = __hba;
- struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- u32 id = irq - host->esi_base;
+ struct msi_desc *desc = data;
+ struct device *dev = msi_desc_to_dev(desc);
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ u32 id = desc->msi_index;
struct ufs_hw_queue *hwq = &hba->uhq[id];
ufshcd_mcq_write_cqis(hba, 0x1, id);
@@ -1665,8 +1800,6 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
if (host->esi_enabled)
return 0;
- else if (host->esi_base < 0)
- return -EINVAL;
/*
* 1. We only handle CQs as of now.
@@ -1675,16 +1808,16 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
ret = platform_msi_domain_alloc_irqs(hba->dev, nr_irqs,
ufs_qcom_write_msi_msg);
- if (ret)
+ if (ret) {
+ dev_err(hba->dev, "Failed to request Platform MSI %d\n", ret);
goto out;
+ }
+ msi_lock_descs(hba->dev);
msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
- if (!desc->msi_index)
- host->esi_base = desc->irq;
-
ret = devm_request_irq(hba->dev, desc->irq,
ufs_qcom_mcq_esi_handler,
- IRQF_SHARED, "qcom-mcq-esi", hba);
+ IRQF_SHARED, "qcom-mcq-esi", desc);
if (ret) {
dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n",
__func__, desc->irq, ret);
@@ -1692,14 +1825,17 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
break;
}
}
+ msi_unlock_descs(hba->dev);
if (ret) {
/* Rewind */
+ msi_lock_descs(hba->dev);
msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
if (desc == failed_desc)
break;
devm_free_irq(hba->dev, desc->irq, hba);
}
+ msi_unlock_descs(hba->dev);
platform_msi_domain_free_irqs(hba->dev);
} else {
if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
@@ -1712,12 +1848,8 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
}
out:
- if (ret) {
- host->esi_base = -1;
- dev_warn(hba->dev, "Failed to request Platform MSI %d\n", ret);
- } else {
+ if (!ret)
host->esi_enabled = true;
- }
return ret;
}
@@ -1757,7 +1889,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
* ufs_qcom_probe - probe routine of the driver
* @pdev: pointer to Platform device handle
*
- * Return zero for success and non-zero for failure
+ * Return: zero for success and non-zero for failure.
*/
static int ufs_qcom_probe(struct platform_device *pdev)
{
diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
index 6289ad5a42d0..d6f8e74bd538 100644
--- a/drivers/ufs/host/ufs-qcom.h
+++ b/drivers/ufs/host/ufs-qcom.h
@@ -206,6 +206,9 @@ struct ufs_qcom_host {
struct clk *tx_l1_sync_clk;
bool is_lane_clks_enabled;
+ struct icc_path *icc_ddr;
+ struct icc_path *icc_cpu;
+
#ifdef CONFIG_SCSI_UFS_CRYPTO
struct qcom_ice *ice;
#endif
@@ -226,7 +229,6 @@ struct ufs_qcom_host {
u32 hs_gear;
- int esi_base;
bool esi_enabled;
};
diff --git a/drivers/ufs/host/ufs-renesas.c b/drivers/ufs/host/ufs-renesas.c
index ab0652d8705a..cc94970b86c9 100644
--- a/drivers/ufs/host/ufs-renesas.c
+++ b/drivers/ufs/host/ufs-renesas.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <ufs/ufshcd.h>
diff --git a/drivers/ufs/host/ufshcd-dwc.c b/drivers/ufs/host/ufshcd-dwc.c
index e28a67e1e314..21b1cf912dcc 100644
--- a/drivers/ufs/host/ufshcd-dwc.c
+++ b/drivers/ufs/host/ufshcd-dwc.c
@@ -34,9 +34,7 @@ int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba,
EXPORT_SYMBOL(ufshcd_dwc_dme_set_attrs);
/**
- * ufshcd_dwc_program_clk_div()
- * This function programs the clk divider value. This value is needed to
- * provide 1 microsecond tick to unipro layer.
+ * ufshcd_dwc_program_clk_div() - program clock divider.
* @hba: Private Structure pointer
* @divider_val: clock divider value to be programmed
*
@@ -47,11 +45,10 @@ static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val)
}
/**
- * ufshcd_dwc_link_is_up()
- * Check if link is up
+ * ufshcd_dwc_link_is_up() - check if link is up.
* @hba: private structure pointer
*
- * Returns 0 on success, non-zero value on failure
+ * Return: 0 on success, non-zero value on failure.
*/
static int ufshcd_dwc_link_is_up(struct ufs_hba *hba)
{
@@ -68,7 +65,9 @@ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba)
}
/**
- * ufshcd_dwc_connection_setup()
+ * ufshcd_dwc_connection_setup() - configure unipro attributes.
+ * @hba: pointer to drivers private data
+ *
* This function configures both the local side (host) and the peer side
* (device) unipro attributes to establish the connection to application/
* cport.
@@ -76,9 +75,7 @@ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba)
* have this connection setup on reset. But invoking this function does no
* harm and should be fine even working with any ufs device.
*
- * @hba: pointer to drivers private data
- *
- * Returns 0 on success non-zero value on failure
+ * Return: 0 on success non-zero value on failure.
*/
static int ufshcd_dwc_connection_setup(struct ufs_hba *hba)
{
@@ -107,12 +104,11 @@ static int ufshcd_dwc_connection_setup(struct ufs_hba *hba)
}
/**
- * ufshcd_dwc_link_startup_notify()
- * UFS Host DWC specific link startup sequence
+ * ufshcd_dwc_link_startup_notify() - program clock divider.
* @hba: private structure pointer
* @status: Callback notify status
*
- * Returns 0 on success, non-zero value on failure
+ * Return: 0 on success, non-zero value on failure.
*/
int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c
index cf3987773051..248a49e5e7f3 100644
--- a/drivers/ufs/host/ufshcd-pci.c
+++ b/drivers/ufs/host/ufshcd-pci.c
@@ -524,7 +524,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
* @pdev: pointer to PCI device handle
* @id: PCI device id
*
- * Returns 0 on success, non-zero value on failure
+ * Return: 0 on success, non-zero value on failure.
*/
static int
ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -590,6 +590,7 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
};
static const struct pci_device_id ufshcd_pci_tbl[] = {
+ { PCI_VENDOR_ID_REDHAT, 0x0013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
{ PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops },
diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c
index 0b7430033047..797a4dfe45d9 100644
--- a/drivers/ufs/host/ufshcd-pltfrm.c
+++ b/drivers/ufs/host/ufshcd-pltfrm.c
@@ -166,6 +166,8 @@ EXPORT_SYMBOL_GPL(ufshcd_populate_vreg);
* If any of the supplies are not defined it is assumed that they are always-on
* and hence return zero. If the property is defined but parsing is failed
* then return corresponding error.
+ *
+ * Return: 0 upon success; < 0 upon failure.
*/
static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
{
@@ -212,7 +214,7 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
* @dev_max: pointer to device attributes
* @agreed_pwr: returned agreed attributes
*
- * Returns 0 on success, non-zero value on failure
+ * Return: 0 on success, non-zero value on failure.
*/
int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param,
const struct ufs_pa_layer_attr *dev_max,
@@ -305,8 +307,8 @@ EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param);
void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param)
{
*dev_param = (struct ufs_dev_params){
- .tx_lanes = 2,
- .rx_lanes = 2,
+ .tx_lanes = UFS_LANE_2,
+ .rx_lanes = UFS_LANE_2,
.hs_rx_gear = UFS_HS_G3,
.hs_tx_gear = UFS_HS_G3,
.pwm_rx_gear = UFS_PWM_G4,
@@ -326,7 +328,7 @@ EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param);
* @pdev: pointer to Platform device handle
* @vops: pointer to variant ops
*
- * Returns 0 on success, non-zero value on failure
+ * Return: 0 on success, non-zero value on failure.
*/
int ufshcd_pltfrm_init(struct platform_device *pdev,
const struct ufs_hba_variant_ops *vops)
@@ -373,7 +375,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
- dev_err(dev, "Initialization failed\n");
+ dev_err_probe(dev, err, "Initialization failed with error %d\n",
+ err);
goto dealloc_host;
}