summaryrefslogtreecommitdiff
path: root/drivers/ufs
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ufs')
-rw-r--r--drivers/ufs/Kconfig4
-rw-r--r--drivers/ufs/ufs-mediatek.c42
-rw-r--r--drivers/ufs/ufs-mediatek.h2
-rw-r--r--drivers/ufs/ufs-renesas-rcar-gen5.c16
-rw-r--r--drivers/ufs/ufs-rockchip.c44
-rw-r--r--drivers/ufs/ufs-rockchip.h1
-rw-r--r--drivers/ufs/ufs-uclass.c70
-rw-r--r--drivers/ufs/ufs.h10
8 files changed, 137 insertions, 52 deletions
diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
index 6c75bb2a079..49472933de3 100644
--- a/drivers/ufs/Kconfig
+++ b/drivers/ufs/Kconfig
@@ -76,6 +76,10 @@ config UFS_RENESAS_GEN5
config UFS_ROCKCHIP
bool "Rockchip specific hooks to UFS controller platform driver"
depends on UFS
+ depends on DM_GPIO
+ depends on RESET_ROCKCHIP
+ depends on SPL_DM_GPIO || !SPL_UFS_SUPPORT
+ depends on SPL_RESET_ROCKCHIP || !SPL_UFS_SUPPORT
help
This selects the Rockchip specific additions to UFSHCD platform driver.
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-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 643a6ffb9bc..dc4b9b5c86d 100644
--- a/drivers/ufs/ufs-rockchip.c
+++ b/drivers/ufs/ufs-rockchip.c
@@ -5,6 +5,7 @@
* Copyright (C) 2025 Rockchip Electronics Co.Ltd.
*/
+#include <asm/gpio.h>
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
@@ -18,23 +19,29 @@
#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);
- if (hba->ops->phy_initialization) {
- err = hba->ops->phy_initialization(hba);
- if (err)
- dev_err(hba->dev,
- "Phy init failed (%d)\n", err);
- }
+ err = ufshcd_ops_phy_initialization(hba);
+ if (err)
+ dev_err(hba->dev, "Phy init failed (%d)\n", err);
return err;
}
@@ -152,11 +159,33 @@ 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) {
+ dev_err(dev, "Cannot get reset GPIO\n");
+ return err;
+ }
+
host->hba = hba;
return 0;
}
+static int ufs_rockchip_device_reset(struct ufs_hba *hba)
+{
+ struct ufs_rockchip_host *host = dev_get_priv(hba->dev);
+
+ dm_gpio_set_value(&host->device_reset, true);
+ udelay(20);
+
+ dm_gpio_set_value(&host->device_reset, false);
+ udelay(20);
+
+ return 0;
+}
+
static int ufs_rockchip_rk3576_init(struct ufs_hba *hba)
{
int ret = 0;
@@ -174,6 +203,7 @@ static struct ufs_hba_ops ufs_hba_rk3576_vops = {
.init = ufs_rockchip_rk3576_init,
.phy_initialization = ufs_rockchip_rk3576_phy_init,
.hce_enable_notify = ufs_rockchip_hce_enable_notify,
+ .device_reset = ufs_rockchip_device_reset,
};
static const struct udevice_id ufs_rockchip_of_match[] = {
diff --git a/drivers/ufs/ufs-rockchip.h b/drivers/ufs/ufs-rockchip.h
index 3dcb80f5702..50c2539da78 100644
--- a/drivers/ufs/ufs-rockchip.h
+++ b/drivers/ufs/ufs-rockchip.h
@@ -72,6 +72,7 @@ struct ufs_rockchip_host {
void __iomem *ufs_sys_ctrl;
void __iomem *mphy_base;
struct reset_ctl_bulk rsts;
+ struct gpio_desc device_reset;
struct clk ref_out_clk;
uint64_t caps;
uint32_t phy_config_mode;
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index 7a80a9d5664..6a51f337e47 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -19,6 +19,7 @@
#include <dm/device-internal.h>
#include <malloc.h>
#include <hexdump.h>
+#include <phys2bus.h>
#include <scsi.h>
#include <ufs.h>
#include <asm/io.h>
@@ -127,11 +128,6 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba)
hba->pwr_info.hs_rate);
}
-static void ufshcd_device_reset(struct ufs_hba *hba)
-{
- ufshcd_vops_device_reset(hba);
-}
-
/**
* ufshcd_ready_for_uic_cmd - Check if controller is ready
* to accept UIC commands
@@ -471,13 +467,13 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
ufshcd_disable_intr_aggr(hba);
/* Configure UTRL and UTMRL base address registers */
- ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utrdl),
+ ufshcd_writel(hba, lower_32_bits(dev_phys_to_bus(hba->dev, (phys_addr_t)(uintptr_t)(hba->utrdl))),
REG_UTP_TRANSFER_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utrdl),
+ ufshcd_writel(hba, upper_32_bits(dev_phys_to_bus(hba->dev, (phys_addr_t)(uintptr_t)(hba->utrdl))),
REG_UTP_TRANSFER_REQ_LIST_BASE_H);
- ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utmrdl),
+ ufshcd_writel(hba, lower_32_bits(dev_phys_to_bus(hba->dev, (phys_addr_t)(uintptr_t)(hba->utmrdl))),
REG_UTP_TASK_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl),
+ ufshcd_writel(hba, upper_32_bits(dev_phys_to_bus(hba->dev, (phys_addr_t)(uintptr_t)(hba->utmrdl))),
REG_UTP_TASK_REQ_LIST_BASE_H);
/*
@@ -512,7 +508,9 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
int retries = DME_LINKSTARTUP_RETRIES;
do {
- ufshcd_ops_link_startup_notify(hba, PRE_CHANGE);
+ ret = ufshcd_ops_link_startup_notify(hba, PRE_CHANGE);
+ if (ret)
+ goto out;
ret = ufshcd_dme_link_startup(hba);
@@ -598,12 +596,18 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
static int ufshcd_hba_enable(struct ufs_hba *hba)
{
int retry;
+ int ret;
if (!ufshcd_is_hba_active(hba))
/* change controller state to "reset state" */
ufshcd_hba_stop(hba);
- ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE);
+ ret = ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE);
+ if (ret) {
+ dev_err(hba->dev, "Controller enable notify PRE_CHANGE failed: %i\n",
+ ret);
+ return ret;
+ }
/* start controller initialization sequence */
ufshcd_hba_start(hba);
@@ -635,7 +639,12 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
/* enable UIC related interrupts */
ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
- ufshcd_ops_hce_enable_notify(hba, POST_CHANGE);
+ ret = ufshcd_ops_hce_enable_notify(hba, POST_CHANGE);
+ if (ret) {
+ dev_err(hba->dev, "Controller enable notify POST_CHANGE failed: %i\n",
+ ret);
+ return ret;
+ }
return 0;
}
@@ -652,7 +661,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
u16 prdt_offset;
utrdlp = hba->utrdl;
- cmd_desc_dma_addr = (dma_addr_t)hba->ucdl;
+ cmd_desc_dma_addr = dev_phys_to_bus(hba->dev, (phys_addr_t)(uintptr_t)(hba->ucdl));
utrdlp->command_desc_base_addr_lo =
cpu_to_le32(lower_32_bits(cmd_desc_dma_addr));
@@ -1604,12 +1613,15 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba,
ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
}
-static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry,
+static inline void prepare_prdt_desc(struct ufs_hba *hba,
+ struct ufshcd_sg_entry *entry,
unsigned char *buf, ulong len)
{
+ dma_addr_t da = dev_phys_to_bus(hba->dev, (phys_addr_t)(uintptr_t)buf);
+
entry->size = cpu_to_le32(len) | GENMASK(1, 0);
- entry->base_addr = cpu_to_le32(lower_32_bits((unsigned long)buf));
- entry->upper_addr = cpu_to_le32(upper_32_bits((unsigned long)buf));
+ entry->base_addr = cpu_to_le32(lower_32_bits(da));
+ entry->upper_addr = cpu_to_le32(upper_32_bits(da));
}
static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
@@ -1631,13 +1643,13 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
buf = pccb->pdata;
i = table_length;
while (--i) {
- prepare_prdt_desc(&prd_table[table_length - i - 1], buf,
+ prepare_prdt_desc(hba, &prd_table[table_length - i - 1], buf,
MAX_PRDT_ENTRY - 1);
buf += MAX_PRDT_ENTRY;
datalen -= MAX_PRDT_ENTRY;
}
- prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1);
+ prepare_prdt_desc(hba, &prd_table[table_length - i - 1], buf, datalen - 1);
req_desc->prd_table_length = table_length;
ufshcd_cache_flush(prd_table, sizeof(*prd_table) * table_length);
@@ -1739,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;
@@ -2184,7 +2204,11 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
/* Set descriptor lengths to specification defaults */
ufshcd_def_desc_sizes(hba);
- ufshcd_ops_init(hba);
+ err = ufshcd_ops_init(hba);
+ if (err) {
+ dev_err(hba->dev, "Host controller init failed: %i\n", err);
+ return err;
+ }
/* Read capabilities registers */
hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
@@ -2228,7 +2252,11 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
mb(); /* flush previous writes */
/* Reset the attached device */
- ufshcd_device_reset(hba);
+ err = ufshcd_vops_device_reset(hba);
+ if (err) {
+ dev_err(hba->dev, "Failed to reset attached device: %i\n", err);
+ return err;
+ }
err = ufshcd_hba_enable(hba);
if (err) {
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index bc839a43704..0f6c93fbce7 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -509,7 +509,7 @@ struct ufs_query {
};
/**
- * struct ufs_dev_cmd - all assosiated fields with device management commands
+ * struct ufs_dev_cmd - all associated fields with device management commands
* @type: device management command type - Query, NOP OUT
* @tag_wq: wait queue until free command slot is available
*/
@@ -756,6 +756,14 @@ static inline int ufshcd_ops_link_startup_notify(struct ufs_hba *hba,
return 0;
}
+static inline int ufshcd_ops_phy_initialization(struct ufs_hba *hba)
+{
+ if (hba->ops && hba->ops->phy_initialization)
+ return hba->ops->phy_initialization(hba);
+
+ return 0;
+}
+
static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
{
if (hba->ops && hba->ops->device_reset)