ufs: Add Support for Cadence platform UFS driver

Add Support for the platform driver for the Cadence device present on
TI's J721e device.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
This commit is contained in:
Faiz Abbas 2019-10-15 18:24:37 +05:30 committed by Tom Rini
parent 7feafb0ae4
commit ef5fb5a84c
3 changed files with 131 additions and 0 deletions

View File

@ -6,4 +6,12 @@ config UFS
help
This selects support for Universal Flash Subsystem (UFS).
Say Y here if you want UFS Support.
config CADENCE_UFS
bool "Cadence platform driver for UFS"
depends on UFS
help
This selects the platform driver for the Cadence UFS host
controller present on present TI's J721e devices.
endmenu

View File

@ -4,3 +4,4 @@
#
obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o

122
drivers/ufs/cdns-platform.c Normal file
View File

@ -0,0 +1,122 @@
// SPDX-License-Identifier: GPL-2.0+
/**
* cdns-platform.c - Platform driver for Cadence UFSHCI device
*
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
*/
#include <clk.h>
#include <common.h>
#include <dm.h>
#include <ufs.h>
#include "ufs.h"
#define USEC_PER_SEC 1000000L
#define CDNS_UFS_REG_HCLKDIV 0xFC
#define CDNS_UFS_REG_PHY_XCFGD1 0x113C
static int cdns_ufs_link_startup_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
switch (status) {
case PRE_CHANGE:
return ufshcd_dme_set(hba,
UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE),
0);
case POST_CHANGE:
;
}
return 0;
}
static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba)
{
struct clk clk;
unsigned long core_clk_rate = 0;
u32 core_clk_div = 0;
int ret;
ret = clk_get_by_name(hba->dev, "core_clk", &clk);
if (ret) {
dev_err(hba->dev, "failed to get core_clk clock\n");
return ret;
}
core_clk_rate = clk_get_rate(&clk);
if (IS_ERR_VALUE(core_clk_rate)) {
dev_err(hba->dev, "%s: unable to find core_clk rate\n",
__func__);
return core_clk_rate;
}
core_clk_div = core_clk_rate / USEC_PER_SEC;
ufshcd_writel(hba, core_clk_div, CDNS_UFS_REG_HCLKDIV);
return 0;
}
static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
switch (status) {
case PRE_CHANGE:
return cdns_ufs_set_hclkdiv(hba);
case POST_CHANGE:
;
}
return 0;
}
static int cdns_ufs_init(struct ufs_hba *hba)
{
u32 data;
/* Increase RX_Advanced_Min_ActivateTime_Capability */
data = ufshcd_readl(hba, CDNS_UFS_REG_PHY_XCFGD1);
data |= BIT(24);
ufshcd_writel(hba, data, CDNS_UFS_REG_PHY_XCFGD1);
return 0;
}
static struct ufs_hba_ops cdns_pltfm_hba_ops = {
.init = cdns_ufs_init,
.hce_enable_notify = cdns_ufs_hce_enable_notify,
.link_startup_notify = cdns_ufs_link_startup_notify,
};
static int cdns_ufs_pltfm_probe(struct udevice *dev)
{
int err = ufshcd_probe(dev, &cdns_pltfm_hba_ops);
if (err)
dev_err(dev, "ufshcd_probe() failed %d\n", err);
return err;
}
static int cdns_ufs_pltfm_bind(struct udevice *dev)
{
struct udevice *scsi_dev;
return ufs_scsi_bind(dev, &scsi_dev);
}
static const struct udevice_id cdns_ufs_pltfm_ids[] = {
{
.compatible = "cdns,ufshc-m31-16nm",
},
{},
};
U_BOOT_DRIVER(cdns_ufs_pltfm) = {
.name = "cdns-ufs-pltfm",
.id = UCLASS_UFS,
.of_match = cdns_ufs_pltfm_ids,
.probe = cdns_ufs_pltfm_probe,
.bind = cdns_ufs_pltfm_bind,
};