Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions drivers/mmc/host/sdhci-msm.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ struct sdhci_msm_host {
/* core, iface, cal and sleep clocks */
struct clk_bulk_data bulk_clks[4];
#ifdef CONFIG_MMC_CRYPTO
struct clk *ice_clk; /* ICE clock */
struct qcom_ice *ice;
#endif
unsigned long clk_rate;
Expand Down Expand Up @@ -2703,6 +2704,17 @@ static int sdhci_msm_probe(struct platform_device *pdev)
return ret;
}

#ifdef CONFIG_MMC_CRYPTO
/* Setup ICE clock */
msm_host->ice_clk = devm_clk_get(&pdev->dev, "ice");
if (!IS_ERR(msm_host->ice_clk)) {
/* Vote for max. clk rate for max. performance */
ret = clk_set_rate(msm_host->ice_clk, INT_MAX);
if (ret)
dev_err(&pdev->dev, "ice clk set rate failed (%d)\n", ret);
}
#endif

/* Setup main peripheral bus clock */
clk = devm_clk_get(&pdev->dev, "iface");
if (IS_ERR(clk)) {
Expand Down
70 changes: 61 additions & 9 deletions drivers/ufs/host/ufs-qcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,9 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
if (!host->is_lane_clks_enabled)
return;

clk_bulk_disable_unprepare(host->num_clks, host->clks);
clk_disable_unprepare(host->rx_lane1_sync_clk);
clk_disable_unprepare(host->rx_lane0_sync_clk);
clk_disable_unprepare(host->tx_lane0_sync_clk);

host->is_lane_clks_enabled = false;
}
Expand All @@ -356,18 +358,35 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
{
int err;

err = clk_bulk_prepare_enable(host->num_clks, host->clks);
if (host->is_lane_clks_enabled)
return 0;

err = clk_prepare_enable(host->tx_lane0_sync_clk);
if (err)
return err;
goto out;

host->is_lane_clks_enabled = true;
err = clk_prepare_enable(host->rx_lane0_sync_clk);
if (err)
goto out_disable_tx_lane0;

err = clk_prepare_enable(host->rx_lane1_sync_clk);
if (err)
goto out_disable_rx_lane0;

host->is_lane_clks_enabled = true;
return 0;

out_disable_rx_lane0:
clk_disable_unprepare(host->rx_lane0_sync_clk);
out_disable_tx_lane0:
clk_disable_unprepare(host->tx_lane0_sync_clk);
out:
return err;
}

static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
{
int err;
int err, i;
struct device *dev = host->hba->dev;

if (has_acpi_companion(dev))
Expand All @@ -379,6 +398,18 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)

host->num_clks = err;

for (i = 0; i < host->num_clks; i++) {
if (!host->clks[i].id)
continue;
if (!strcmp(host->clks[i].id, "tx_lane0_sync_clk"))
host->tx_lane0_sync_clk = host->clks[i].clk;
else if (!strcmp(host->clks[i].id, "rx_lane0_sync_clk"))
host->rx_lane0_sync_clk = host->clks[i].clk;
else if (!strcmp(host->clks[i].id, "rx_lane1_sync_clk"))
if (host->hba->lanes_per_direction > 1)
host->rx_lane1_sync_clk = host->clks[i].clk;
}

return 0;
}

Expand Down Expand Up @@ -770,9 +801,17 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
if (!ufs_qcom_is_link_active(hba))
ufs_qcom_disable_lane_clks(host);


/* reset the connected UFS device during power down */
if (ufs_qcom_is_link_off(hba) && host->device_reset) {
/*
* For some UFS vendors, skip asserting device reset here.
* These vendor parts keep drawing larger current after reset
* is asserted until it is deasserted, and the 10ms delay is
* not sufficient to prevent OCP (Over Current Protection)
* on the regulator. This is for the powerdown case, so
* the device reset can be asserted later as part of the
* platform shutdown sequence.
*/
if (ufs_qcom_is_link_off(hba) && host->device_reset &&
!(hba->quirks & UFSHCD_QUIRK_SKIP_DEVICE_RESET)) {
ufs_qcom_device_reset_ctrl(hba, true);
/*
* After sending the SSU command, asserting the rst_n
Expand Down Expand Up @@ -1288,6 +1327,19 @@ static struct ufs_dev_quirk ufs_qcom_dev_fixups[] = {
static void ufs_qcom_fixup_dev_quirks(struct ufs_hba *hba)
{
ufshcd_fixup_dev_quirks(hba, ufs_qcom_dev_fixups);

/*
* Some UFS parts keep drawing larger current after reset is asserted
* until it is deasserted. The 10ms delay added after asserting HWRST
* (as done for other vendors) is not sufficient for these parts.
*
* Skip asserting device reset during UFS power down for these parts
* to prevent OCP (Over Current Protection) fault on the regulator.
* This is handled only in shutdown; the device reset will be asserted
* as part of the platform shutdown sequence.
*/
if (hba->dev_info.wmanufacturerid == UFS_VENDOR_MICRON)
hba->quirks |= UFSHCD_QUIRK_SKIP_DEVICE_RESET;
}

static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
Expand Down Expand Up @@ -2282,7 +2334,7 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
p->polling_ms = 60;
p->timer = DEVFREQ_TIMER_DELAYED;
d->upthreshold = 70;
d->downdifferential = 5;
d->downdifferential = 65;

hba->clk_scaling.suspend_on_no_request = true;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/ufs/host/ufs-qcom.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ struct ufs_qcom_host {
struct ufs_hba *hba;
struct ufs_pa_layer_attr dev_req_params;
struct clk_bulk_data *clks;
struct clk *tx_lane0_sync_clk;
struct clk *rx_lane0_sync_clk;
struct clk *rx_lane1_sync_clk;
u32 num_clks;
bool is_lane_clks_enabled;

Expand Down
15 changes: 15 additions & 0 deletions include/ufs/ufshcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,22 @@ enum ufshcd_quirks {
* (EQTR) using Adapt L0L1L2L3 length which is larger than what is
* allowed by M-PHY spec ver 6.0.
*/

UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3 = 1 << 28,
/*
* Some UFS devices keep drawing larger current after reset is
* asserted until it is deasserted. Asserting device reset
* during UFS power down causes the device firmware to wake up and
* execute its reset routine, drawing current beyond the permissible
* limit for low-power mode (LPM). This may trigger an OCP fault on
* the regulator supplying power to UFS.
*
* Enable this quirk to skip asserting device reset during UFS power
* down. This is handled only in shutdown; the device reset will be
* asserted as part of the platform shutdown sequence.
*/

UFSHCD_QUIRK_SKIP_DEVICE_RESET = 1 << 29,
};

enum ufshcd_caps {
Expand Down
Loading