summaryrefslogtreecommitdiff
path: root/drivers/ufs
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ufs')
-rw-r--r--drivers/ufs/Kconfig6
-rw-r--r--drivers/ufs/ufs-amd-versal2.c1
-rw-r--r--drivers/ufs/ufs-mediatek.c42
-rw-r--r--drivers/ufs/ufs-mediatek.h2
-rw-r--r--drivers/ufs/ufs-qcom.c54
-rw-r--r--drivers/ufs/ufs-renesas-rcar-gen5.c16
-rw-r--r--drivers/ufs/ufs-rockchip.c13
-rw-r--r--drivers/ufs/ufs-uclass.c10
8 files changed, 98 insertions, 46 deletions
diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
index 49472933de3..c1b84bd7559 100644
--- a/drivers/ufs/Kconfig
+++ b/drivers/ufs/Kconfig
@@ -19,12 +19,12 @@ config UFS_AMD_VERSAL2
config UFS_CADENCE
bool "Cadence platform driver for UFS"
depends on UFS
- help
+ help
This selects the platform driver for the Cadence UFS host
controller present on present TI's J721e devices.
config UFS_MEDIATEK
- tristate "MediaTek UFS Host Controller Driver"
+ bool "MediaTek UFS Host Controller Driver"
depends on UFS && ARCH_MEDIATEK
select PHY_MTK_UFS
help
@@ -51,7 +51,7 @@ config UFS_PCI
config UFS_QCOM
bool "Qualcomm Host Controller driver for UFS"
depends on UFS && ARCH_SNAPDRAGON
- help
+ help
This selects the platform driver for the UFS host
controller present on Qualcomm Snapdragon SoCs.
diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c
index 6c949b2ca76..3369d32d924 100644
--- a/drivers/ufs/ufs-amd-versal2.c
+++ b/drivers/ufs/ufs-amd-versal2.c
@@ -563,4 +563,5 @@ U_BOOT_DRIVER(ufs_versal2_pltfm) = {
.id = UCLASS_UFS,
.of_match = ufs_versal2_ids,
.probe = ufs_versal2_probe,
+ .priv_auto = sizeof(struct ufs_versal2_priv),
};
diff --git a/drivers/ufs/ufs-mediatek.c b/drivers/ufs/ufs-mediatek.c
index e860d765eea..268627d5863 100644
--- a/drivers/ufs/ufs-mediatek.c
+++ b/drivers/ufs/ufs-mediatek.c
@@ -182,19 +182,15 @@ static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
struct ufs_mtk_host *host = dev_get_priv(hba->dev);
int err = 0;
- err = generic_phy_get_by_index(hba->dev, 0, host->mphy);
+ err = generic_phy_get_by_index(hba->dev, 0, &host->mphy);
- if (IS_ERR(host->mphy)) {
- err = PTR_ERR(host->mphy);
- if (err != -ENODEV) {
- dev_info(hba->dev, "%s: Could NOT get a valid PHY %d\n", __func__,
- err);
- }
+ if (err) {
+ if (err == -ENOENT)
+ return 0; /* no PHY, nothing to do */
+ dev_err(hba->dev, "Failed to get PHY: %d.\n", err);
+ return err;
}
- if (err)
- host->mphy = NULL;
-
return err;
}
@@ -321,19 +317,35 @@ static int ufs_mtk_init(struct ufs_hba *hba)
ufs_mtk_init_reset(hba);
- // TODO: Clocking
+ err = clk_get_bulk(hba->dev, &priv->clks);
+ if (err) {
+ dev_err(hba->dev, "failed to initialize clocks, err:%d\n", err);
+ return err;
+ }
+
+ err = clk_enable_bulk(&priv->clks);
+ if (err) {
+ dev_err(hba->dev, "failed to enable clocks, err:%d\n", err);
+ goto err_clk_enable;
+ }
- err = generic_phy_power_on(priv->mphy);
+ err = generic_phy_power_on(&priv->mphy);
if (err) {
dev_err(hba->dev, "%s: phy init failed, err = %d\n",
__func__, err);
- return err;
+ goto err_phy_power_on;
}
ufs_mtk_setup_ref_clk(hba, true);
ufs_mtk_get_hw_ip_version(hba);
return 0;
+
+err_phy_power_on:
+ clk_disable_bulk(&priv->clks);
+err_clk_enable:
+ clk_release_bulk(&priv->clks);
+ return err;
}
static int ufs_mtk_device_reset(struct ufs_hba *hba)
@@ -383,7 +395,9 @@ static int ufs_mtk_probe(struct udevice *dev)
static const struct udevice_id ufs_mtk_ids[] = {
{ .compatible = "mediatek,mt6878-ufshci" },
- {},
+ { .compatible = "mediatek,mt8183-ufshci" },
+ { .compatible = "mediatek,mt8195-ufshci" },
+ { }
};
U_BOOT_DRIVER(mediatek_ufshci) = {
diff --git a/drivers/ufs/ufs-mediatek.h b/drivers/ufs/ufs-mediatek.h
index 11a83d34c5b..0ffd0483eff 100644
--- a/drivers/ufs/ufs-mediatek.h
+++ b/drivers/ufs/ufs-mediatek.h
@@ -154,7 +154,7 @@ struct ufs_mtk_mcq_intr_info {
};
struct ufs_mtk_host {
- struct phy *mphy;
+ struct phy mphy;
struct reset_ctl *unipro_reset;
struct reset_ctl *crypto_reset;
struct reset_ctl *hci_reset;
diff --git a/drivers/ufs/ufs-qcom.c b/drivers/ufs/ufs-qcom.c
index dc40ee62daf..f5f5a6eb110 100644
--- a/drivers/ufs/ufs-qcom.c
+++ b/drivers/ufs/ufs-qcom.c
@@ -30,6 +30,7 @@
#define UFS_CPU_MAX_BANDWIDTH 819200
static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable);
+static u32 ufs_qcom_get_core_clk_unipro_max_freq(struct ufs_hba *hba);
static int ufs_qcom_enable_clks(struct ufs_qcom_priv *priv)
{
@@ -47,17 +48,6 @@ static int ufs_qcom_enable_clks(struct ufs_qcom_priv *priv)
return 0;
}
-static int ufs_qcom_init_clks(struct ufs_qcom_priv *priv)
-{
- int err;
- struct udevice *dev = priv->hba->dev;
-
- err = clk_get_bulk(dev, &priv->clks);
- if (err)
- return err;
-
- return 0;
-}
static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
{
@@ -557,10 +547,45 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable)
static int ufs_qcom_init(struct ufs_hba *hba)
{
struct ufs_qcom_priv *priv = dev_get_priv(hba->dev);
+ struct udevice *dev = hba->dev;
+ struct clk clk;
+ u32 max_freq;
+ long rate;
int err;
priv->hba = hba;
+ /* Get maximum frequency for core_clk_unipro from device tree */
+ max_freq = ufs_qcom_get_core_clk_unipro_max_freq(hba);
+
+ /* Get and configure core_clk_unipro */
+ err = clk_get_by_name(dev, "core_clk_unipro", &clk);
+ if (err) {
+ dev_err(dev, "Failed to get core_clk_unipro: %d\n", err);
+ return err;
+ }
+
+ rate = clk_set_rate(&clk, max_freq);
+ if (rate < 0) {
+ dev_err(dev, "Failed to set core_clk_unipro rate to %u Hz: %ld\n",
+ max_freq, rate);
+ }
+
+ /* Get all clocks */
+ err = clk_get_bulk(dev, &priv->clks);
+ if (err) {
+ dev_err(dev, "clk_get_bulk failed: %d\n", err);
+ return err;
+ }
+
+ /* Enable clocks */
+ err = ufs_qcom_enable_clks(priv);
+ if (err) {
+ dev_err(dev, "failed to enable clocks: %d\n", err);
+ clk_release_bulk(&priv->clks);
+ return err;
+ }
+
/* setup clocks */
ufs_qcom_setup_clocks(hba, true, PRE_CHANGE);
@@ -579,14 +604,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
priv->hw_ver.minor,
priv->hw_ver.step);
- err = ufs_qcom_init_clks(priv);
- if (err) {
- dev_err(hba->dev, "failed to initialize clocks, err:%d\n", err);
- return err;
- }
-
ufs_qcom_advertise_quirks(hba);
- ufs_qcom_setup_clocks(hba, true, POST_CHANGE);
return 0;
}
diff --git a/drivers/ufs/ufs-renesas-rcar-gen5.c b/drivers/ufs/ufs-renesas-rcar-gen5.c
index a21ae3f390e..a9473cd60b1 100644
--- a/drivers/ufs/ufs-renesas-rcar-gen5.c
+++ b/drivers/ufs/ufs-renesas-rcar-gen5.c
@@ -92,14 +92,14 @@ static int ufs_renesas_pre_init(struct ufs_hba *hba)
ufs_dme_command(hba, 0x00000002, 0x81010000, 0x00000000, 0x00000005);
ufs_dme_command(hba, 0x00000002, 0x81150000, 0x00000000, 0x00000001);
ufs_dme_command(hba, 0x00000002, 0x81180000, 0x00000000, 0x00000001);
- ufs_dme_command(hba, 0x00000002, 0x80090000, 0x00000000, 0x00000000);
- ufs_dme_command(hba, 0x00000002, 0x800a0000, 0x00000000, 0x000000c8);
- ufs_dme_command(hba, 0x00000002, 0x80090001, 0x00000000, 0x00000000);
- ufs_dme_command(hba, 0x00000002, 0x800a0001, 0x00000000, 0x000000c8);
- ufs_dme_command(hba, 0x00000002, 0x800a0004, 0x00000000, 0x00000000);
- ufs_dme_command(hba, 0x00000002, 0x800b0004, 0x00000000, 0x00000064);
- ufs_dme_command(hba, 0x00000002, 0x800a0005, 0x00000000, 0x00000000);
- ufs_dme_command(hba, 0x00000002, 0x800b0005, 0x00000000, 0x00000064);
+ ufs_dme_command(hba, 0x00000002, 0x80090000, 0x00000000, 0x0000000c);
+ ufs_dme_command(hba, 0x00000002, 0x800a0000, 0x00000000, 0x00000080);
+ ufs_dme_command(hba, 0x00000002, 0x80090001, 0x00000000, 0x0000000c);
+ ufs_dme_command(hba, 0x00000002, 0x800a0001, 0x00000000, 0x00000080);
+ ufs_dme_command(hba, 0x00000002, 0x800a0004, 0x00000000, 0x00000003);
+ ufs_dme_command(hba, 0x00000002, 0x800b0004, 0x00000000, 0x000000ea);
+ ufs_dme_command(hba, 0x00000002, 0x800a0005, 0x00000000, 0x00000003);
+ ufs_dme_command(hba, 0x00000002, 0x800b0005, 0x00000000, 0x000000ea);
ufs_dme_command(hba, 0x00000002, 0xd0850000, 0x00000000, 0x00000001);
writew(0x0001, priv->phy_base + 0x20000);
diff --git a/drivers/ufs/ufs-rockchip.c b/drivers/ufs/ufs-rockchip.c
index a13236c7f76..dc4b9b5c86d 100644
--- a/drivers/ufs/ufs-rockchip.c
+++ b/drivers/ufs/ufs-rockchip.c
@@ -19,13 +19,22 @@
#include "unipro.h"
#include "ufs-rockchip.h"
+static void ufs_rockchip_controller_reset(struct ufs_rockchip_host *host)
+{
+ reset_assert_bulk(&host->rsts);
+ udelay(1);
+ reset_deassert_bulk(&host->rsts);
+}
+
static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
int err = 0;
- if (status != POST_CHANGE)
+ if (status != POST_CHANGE) {
+ ufs_rockchip_controller_reset(dev_get_priv(hba->dev));
return 0;
+ }
ufshcd_dme_reset(hba);
ufshcd_dme_enable(hba);
@@ -150,6 +159,8 @@ static int ufs_rockchip_common_init(struct ufs_hba *hba)
return err;
}
+ ufs_rockchip_controller_reset(host);
+
err = gpio_request_by_name(dev, "reset-gpios", 0, &host->device_reset,
GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
if (err) {
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index 81fd431f951..6a51f337e47 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -1751,7 +1751,15 @@ static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
goto out;
}
- buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
+ /*
+ * utf-8 is encoded using up to 4-Bytes per character,
+ * however, we only allocate such a buffer because the
+ * utf16_to_utf8() converts the entire $ascii_len worth
+ * of input characters into up to 4-Byte long utf-8
+ * characters. The rest of the function uses only up to
+ * $ascii_len bytes of that utf-8 string.
+ */
+ buff_ascii = kmalloc(ascii_len * 4, GFP_KERNEL);
if (!buff_ascii) {
err = -ENOMEM;
goto out;