Merge patch series "ufs: Add a PCI UFS controller support"

To quote the author:

This adds a PCI UFS controller support and enables the support on
QEMU RISC-V for testing.

Requiring QEMU v8.2+.
This commit is contained in:
Tom Rini 2023-11-27 16:19:09 -05:00
commit d6e052c615
11 changed files with 97 additions and 15 deletions

View File

@ -81,5 +81,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
imply USB_XHCI_PCI imply USB_XHCI_PCI
imply USB_KEYBOARD imply USB_KEYBOARD
imply CMD_USB imply CMD_USB
imply UFS
imply UFS_PCI
endif endif

View File

@ -1520,7 +1520,7 @@ config CMD_TSI148
Turndra tsi148 device. See the command help for full details. Turndra tsi148 device. See the command help for full details.
config CMD_UFS config CMD_UFS
bool "Enable UFS - Universal Flash Subsystem commands" bool "ufs - Universal Flash Storage commands"
depends on UFS depends on UFS
help help
"This provides commands to initialise and configure universal flash "This provides commands to initialise and configure universal flash

View File

@ -32,6 +32,6 @@ static int do_ufs(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
} }
U_BOOT_CMD(ufs, 3, 1, do_ufs, U_BOOT_CMD(ufs, 3, 1, do_ufs,
"UFS sub system", "UFS sub-system",
"init [dev] - init UFS subsystem\n" "init [dev] - init UFS subsystem\n"
); );

View File

@ -131,7 +131,13 @@ An attached disk can be emulated in RISC-V virt machine by adding::
-drive if=none,file=riscv64.img,format=raw,id=mydisk \ -drive if=none,file=riscv64.img,format=raw,id=mydisk \
-device ide-hd,drive=mydisk,bus=ahci.0 -device ide-hd,drive=mydisk,bus=ahci.0
You will have to run 'scsi scan' to use it. or alternatively attach an emulated UFS::
-device ufs,id=ufs0 \
-drive if=none,file=test.img,format=raw,id=lun0 \
-device ufs-lu,drive=lun0,bus=ufs0
You will have to run 'scsi scan' to use them.
A video console can be emulated in RISC-V virt machine by removing "-nographic" A video console can be emulated in RISC-V virt machine by removing "-nographic"
and adding:: and adding::

View File

@ -15,6 +15,17 @@ config CADENCE_UFS
This selects the platform driver for the Cadence UFS host This selects the platform driver for the Cadence UFS host
controller present on present TI's J721e devices. controller present on present TI's J721e devices.
config UFS_PCI
bool "PCI bus based UFS Controller support"
depends on PCI && UFS
help
This selects the PCI UFS Host Controller Interface. Select this if
you have UFS Host Controller with PCI Interface.
If you have a controller with this interface, say Y here.
If unsure, say N.
config TI_J721E_UFS config TI_J721E_UFS
bool "Glue Layer driver for UFS on TI J721E devices" bool "Glue Layer driver for UFS on TI J721E devices"
help help

View File

@ -6,4 +6,5 @@
obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
obj-$(CONFIG_UFS_PCI) += ufs-pci.o
obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o

45
drivers/ufs/ufs-pci.c Normal file
View File

@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2023 tinylab.org
* Author: Bin Meng <bmeng@tinylab.org>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <pci.h>
#include <ufs.h>
#include <dm/device_compat.h>
#include "ufs.h"
static int ufs_pci_bind(struct udevice *dev)
{
struct udevice *scsi_dev;
return ufs_scsi_bind(dev, &scsi_dev);
}
static int ufs_pci_probe(struct udevice *dev)
{
int err;
err = ufshcd_probe(dev, NULL);
if (err)
dev_err(dev, "%s failed (ret=%d)\n", __func__, err);
return err;
}
U_BOOT_DRIVER(ufs_pci) = {
.name = "ufs_pci",
.id = UCLASS_UFS,
.bind = ufs_pci_bind,
.probe = ufs_pci_probe,
};
static struct pci_device_id ufs_supported[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_UFS) },
{},
};
U_BOOT_PCI_DEVICE(ufs_pci, ufs_supported);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/** /**
* ufs-uclass.c - Universal Flash Subsystem (UFS) Uclass driver * ufs-uclass.c - Universal Flash Storage (UFS) Uclass driver
* *
* Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/ */

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
/** /**
* ufs.c - Universal Flash Subsystem (UFS) driver * ufs.c - Universal Flash Storage (UFS) driver
* *
* Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported * Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported
* to u-boot. * to u-boot.
@ -320,7 +320,7 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)), UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
0); 0);
if (err) { if (err) {
dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d", dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d\n",
__func__, peer, i, err); __func__, peer, i, err);
break; break;
} }
@ -441,7 +441,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
ufshcd_enable_run_stop_reg(hba); ufshcd_enable_run_stop_reg(hba);
} else { } else {
dev_err(hba->dev, dev_err(hba->dev,
"Host controller not ready to process requests"); "Host controller not ready to process requests\n");
err = -EIO; err = -EIO;
goto out; goto out;
} }
@ -930,7 +930,7 @@ static int ufshcd_copy_query_response(struct ufs_hba *hba)
memcpy(hba->dev_cmd.query.descriptor, descp, resp_len); memcpy(hba->dev_cmd.query.descriptor, descp, resp_len);
} else { } else {
dev_warn(hba->dev, dev_warn(hba->dev,
"%s: Response size is bigger than buffer", "%s: Response size is bigger than buffer\n",
__func__); __func__);
return -EINVAL; return -EINVAL;
} }
@ -1179,11 +1179,11 @@ static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id,
&header_len); &header_len);
if (ret) { if (ret) {
dev_err(hba->dev, "%s: Failed to get descriptor header id %d", dev_err(hba->dev, "%s: Failed to get descriptor header id %d\n",
__func__, desc_id); __func__, desc_id);
return ret; return ret;
} else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) {
dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch", dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch\n",
__func__, header[QUERY_DESC_DESC_TYPE_OFFSET], __func__, header[QUERY_DESC_DESC_TYPE_OFFSET],
desc_id); desc_id);
ret = -EINVAL; ret = -EINVAL;
@ -1302,7 +1302,7 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
/* Sanity checks */ /* Sanity checks */
if (ret || !buff_len) { if (ret || !buff_len) {
dev_err(hba->dev, "%s: Failed to get full descriptor length", dev_err(hba->dev, "%s: Failed to get full descriptor length\n",
__func__); __func__);
return ret; return ret;
} }
@ -1323,14 +1323,14 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
&buff_len); &buff_len);
if (ret) { if (ret) {
dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n",
__func__, desc_id, desc_index, param_offset, ret); __func__, desc_id, desc_index, param_offset, ret);
goto out; goto out;
} }
/* Sanity check */ /* Sanity check */
if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header", dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n",
__func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
@ -1914,6 +1914,7 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev); struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev);
struct scsi_plat *scsi_plat; struct scsi_plat *scsi_plat;
struct udevice *scsi_dev; struct udevice *scsi_dev;
void __iomem *mmio_base;
int err; int err;
device_find_first_child(ufs_dev, &scsi_dev); device_find_first_child(ufs_dev, &scsi_dev);
@ -1927,7 +1928,14 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
hba->dev = ufs_dev; hba->dev = ufs_dev;
hba->ops = hba_ops; hba->ops = hba_ops;
hba->mmio_base = dev_read_addr_ptr(ufs_dev);
if (device_is_on_pci_bus(ufs_dev)) {
mmio_base = dm_pci_map_bar(ufs_dev, PCI_BASE_ADDRESS_0, 0, 0,
PCI_REGION_TYPE, PCI_REGION_MEM);
} else {
mmio_base = dev_read_addr_ptr(ufs_dev);
}
hba->mmio_base = mmio_base;
/* Set descriptor lengths to specification defaults */ /* Set descriptor lengths to specification defaults */
ufshcd_def_desc_sizes(hba); ufshcd_def_desc_sizes(hba);
@ -1945,7 +1953,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
hba->version != UFSHCI_VERSION_11 && hba->version != UFSHCI_VERSION_11 &&
hba->version != UFSHCI_VERSION_20 && hba->version != UFSHCI_VERSION_20 &&
hba->version != UFSHCI_VERSION_21 && hba->version != UFSHCI_VERSION_21 &&
hba->version != UFSHCI_VERSION_30) hba->version != UFSHCI_VERSION_30 &&
hba->version != UFSHCI_VERSION_31)
dev_err(hba->dev, "invalid UFS version 0x%x\n", dev_err(hba->dev, "invalid UFS version 0x%x\n",
hba->version); hba->version);

View File

@ -782,6 +782,7 @@ enum {
UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */ UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */
UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */ UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */ UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */
UFSHCI_VERSION_31 = 0x00000310, /* 3.1 */
}; };
/* Interrupt disable masks */ /* Interrupt disable masks */

View File

@ -1363,6 +1363,13 @@
#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 #define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5
#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 #define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6
/* Per https://www.qemu.org/docs/master/specs/pci-ids.html */
#define PCI_VENDOR_ID_REDHAT 0x1b36
#define PCI_DEVICE_ID_REDHAT_SDHCI 0x0007
#define PCI_DEVICE_ID_REDHAT_XHCI 0x000d
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
#define PCI_DEVICE_ID_REDHAT_UFS 0x0013
#define PCI_VENDOR_ID_INIT 0x1101 #define PCI_VENDOR_ID_INIT 0x1101
#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */ #define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */