[v3,12/13] usb: host: xhci-tegra: Add Tegra234 XHCI support
Commit Message
From: Sing-Han Chen <singhanc@nvidia.com>
This change adds Tegra234 XUSB host mode controller support.
In Tegra234, some of the registers have moved to bar2 space.
The new soc variable has_bar2 indicates the chip with bar2
area. This patch adds new reg helper to let the driver reuse
the same code for those chips with bar2 support.
Signed-off-by: Sing-Han Chen <singhanc@nvidia.com>
Co-developed-by: Wayne Chang <waynec@nvidia.com>
Signed-off-by: Wayne Chang <waynec@nvidia.com>
---
V2 -> V3:nothing has changed
V1 -> V2:fix some issues on coding style
extract tegra_xusb_load_firmware function
refine has_bar2 and remove has_ifr/firmware on Tegra234
drivers/usb/host/xhci-tegra.c | 270 +++++++++++++++++++++++++++++-----
1 file changed, 232 insertions(+), 38 deletions(-)
Comments
On 14/11/2022 12:40, Wayne Chang wrote:
> From: Sing-Han Chen <singhanc@nvidia.com>
>
> This change adds Tegra234 XUSB host mode controller support.
>
> In Tegra234, some of the registers have moved to bar2 space.
> The new soc variable has_bar2 indicates the chip with bar2
> area. This patch adds new reg helper to let the driver reuse
> the same code for those chips with bar2 support.
>
> Signed-off-by: Sing-Han Chen <singhanc@nvidia.com>
> Co-developed-by: Wayne Chang <waynec@nvidia.com>
> Signed-off-by: Wayne Chang <waynec@nvidia.com>
> ---
> V2 -> V3:nothing has changed
> V1 -> V2:fix some issues on coding style
> extract tegra_xusb_load_firmware function
> refine has_bar2 and remove has_ifr/firmware on Tegra234
> drivers/usb/host/xhci-tegra.c | 270 +++++++++++++++++++++++++++++-----
> 1 file changed, 232 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
> index bdb776553826..b2f07eae2c93 100644
> --- a/drivers/usb/host/xhci-tegra.c
> +++ b/drivers/usb/host/xhci-tegra.c
> @@ -44,6 +44,9 @@
> #define XUSB_CFG_4 0x010
> #define XUSB_BASE_ADDR_SHIFT 15
> #define XUSB_BASE_ADDR_MASK 0x1ffff
> +#define XUSB_CFG_7 0x01c
> +#define XUSB_BASE2_ADDR_SHIFT 16
> +#define XUSB_BASE2_ADDR_MASK 0xffff
> #define XUSB_CFG_16 0x040
> #define XUSB_CFG_24 0x060
> #define XUSB_CFG_AXI_CFG 0x0f8
> @@ -75,6 +78,20 @@
> #define MBOX_SMI_INTR_FW_HANG BIT(1)
> #define MBOX_SMI_INTR_EN BIT(3)
>
> +/* BAR2 registers */
> +#define XUSB_BAR2_ARU_MBOX_CMD 0x004
> +#define XUSB_BAR2_ARU_MBOX_DATA_IN 0x008
> +#define XUSB_BAR2_ARU_MBOX_DATA_OUT 0x00c
> +#define XUSB_BAR2_ARU_MBOX_OWNER 0x010
> +#define XUSB_BAR2_ARU_SMI_INTR 0x014
> +#define XUSB_BAR2_ARU_SMI_ARU_FW_SCRATCH_DATA0 0x01c
> +#define XUSB_BAR2_ARU_IFRDMA_CFG0 0x0e0
> +#define XUSB_BAR2_ARU_IFRDMA_CFG1 0x0e4
> +#define XUSB_BAR2_ARU_IFRDMA_STREAMID_FIELD 0x0e8
> +#define XUSB_BAR2_ARU_C11_CSBRANGE 0x9c
> +#define XUSB_BAR2_ARU_FW_SCRATCH 0x1000
> +#define XUSB_BAR2_CSB_BASE_ADDR 0x2000
> +
> /* IPFS registers */
> #define IPFS_XUSB_HOST_MSI_BAR_SZ_0 0x0c0
> #define IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0 0x0c4
> @@ -111,6 +128,9 @@
> #define IMFILLRNG1_TAG_HI_SHIFT 16
> #define XUSB_FALC_IMFILLCTL 0x158
>
> +/* CSB ARU registers */
> +#define XUSB_CSB_ARU_SCRATCH0 0x100100
> +
> /* MP CSB registers */
> #define XUSB_CSB_MP_ILOAD_ATTR 0x101a00
> #define XUSB_CSB_MP_ILOAD_BASE_LO 0x101a04
> @@ -131,6 +151,9 @@
>
> #define IMEM_BLOCK_SIZE 256
>
> +#define FW_IOCTL_TYPE_SHIFT 24
> +#define FW_IOCTL_CFGTBL_READ 17
> +
> struct tegra_xusb_fw_header {
> __le32 boot_loadaddr_in_imem;
> __le32 boot_codedfi_offset;
> @@ -175,6 +198,7 @@ struct tegra_xusb_mbox_regs {
> u16 data_in;
> u16 data_out;
> u16 owner;
> + u16 smi_intr;
> };
>
> struct tegra_xusb_context_soc {
> @@ -189,6 +213,18 @@ struct tegra_xusb_context_soc {
> } fpci;
> };
>
> +struct tegra_xusb;
> +struct tegra_xusb_soc_ops {
> + u32 (*mbox_reg_readl)(struct tegra_xusb *tegra,
> + unsigned int offset);
> + void (*mbox_reg_writel)(struct tegra_xusb *tegra,
> + u32 value, unsigned int offset);
> + u32 (*csb_reg_readl)(struct tegra_xusb *tegra,
> + unsigned int offset);
> + void (*csb_reg_writel)(struct tegra_xusb *tegra,
> + u32 value, unsigned int offset);
> +};
> +
> struct tegra_xusb_soc {
> const char *firmware;
> const char * const *supply_names;
> @@ -205,11 +241,14 @@ struct tegra_xusb_soc {
> } ports;
>
> struct tegra_xusb_mbox_regs mbox;
> + const struct tegra_xusb_soc_ops *ops;
>
> bool scale_ss_clock;
> bool has_ipfs;
> bool lpm_support;
> bool otg_reset_sspi;
> +
> + bool has_bar2;
> };
>
> struct tegra_xusb_context {
> @@ -230,6 +269,8 @@ struct tegra_xusb {
>
> void __iomem *ipfs_base;
> void __iomem *fpci_base;
> + void __iomem *bar2_base;
> + struct resource *bar2;
>
> const struct tegra_xusb_soc *soc;
>
> @@ -300,7 +341,33 @@ static inline void ipfs_writel(struct tegra_xusb *tegra, u32 value,
> writel(value, tegra->ipfs_base + offset);
> }
>
> +static inline u32 bar2_readl(struct tegra_xusb *tegra, unsigned int offset)
> +{
> + return readl(tegra->bar2_base + offset);
> +}
> +
> +static inline void bar2_writel(struct tegra_xusb *tegra, u32 value,
> + unsigned int offset)
> +{
> + writel(value, tegra->bar2_base + offset);
> +}
> +
> static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset)
> +{
> + const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
> +
> + return ops->csb_reg_readl(tegra, offset);
> +}
> +
> +static void csb_writel(struct tegra_xusb *tegra, u32 value,
> + unsigned int offset)
> +{
> + const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
> +
> + ops->csb_reg_writel(tegra, value, offset);
> +}
> +
> +static u32 fpci_csb_readl(struct tegra_xusb *tegra, unsigned int offset)
> {
> u32 page = CSB_PAGE_SELECT(offset);
> u32 ofs = CSB_PAGE_OFFSET(offset);
> @@ -310,7 +377,7 @@ static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset)
> return fpci_readl(tegra, XUSB_CFG_CSB_BASE_ADDR + ofs);
> }
>
> -static void csb_writel(struct tegra_xusb *tegra, u32 value,
> +static void fpci_csb_writel(struct tegra_xusb *tegra, u32 value,
> unsigned int offset)
> {
> u32 page = CSB_PAGE_SELECT(offset);
> @@ -320,6 +387,26 @@ static void csb_writel(struct tegra_xusb *tegra, u32 value,
> fpci_writel(tegra, value, XUSB_CFG_CSB_BASE_ADDR + ofs);
> }
>
> +static u32 bar2_csb_readl(struct tegra_xusb *tegra, unsigned int offset)
> +{
> + u32 page = CSB_PAGE_SELECT(offset);
> + u32 ofs = CSB_PAGE_OFFSET(offset);
> +
> + bar2_writel(tegra, page, XUSB_BAR2_ARU_C11_CSBRANGE);
> +
> + return bar2_readl(tegra, XUSB_BAR2_CSB_BASE_ADDR + ofs);
> +}
> +
> +static void bar2_csb_writel(struct tegra_xusb *tegra, u32 value,
> + unsigned int offset)
> +{
> + u32 page = CSB_PAGE_SELECT(offset);
> + u32 ofs = CSB_PAGE_OFFSET(offset);
> +
> + bar2_writel(tegra, page, XUSB_BAR2_ARU_C11_CSBRANGE);
> + bar2_writel(tegra, value, XUSB_BAR2_CSB_BASE_ADDR + ofs);
> +}
> +
> static int tegra_xusb_set_ss_clk(struct tegra_xusb *tegra,
> unsigned long rate)
> {
> @@ -451,6 +538,7 @@ static bool tegra_xusb_mbox_cmd_requires_ack(enum tegra_xusb_mbox_cmd cmd)
> static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
> const struct tegra_xusb_mbox_msg *msg)
> {
> + const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
> bool wait_for_idle = false;
> u32 value;
>
> @@ -459,15 +547,15 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
> * ACK/NAK messages.
> */
> if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) {
> - value = fpci_readl(tegra, tegra->soc->mbox.owner);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
> if (value != MBOX_OWNER_NONE) {
> dev_err(tegra->dev, "mailbox is busy\n");
> return -EBUSY;
> }
>
> - fpci_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner);
> + ops->mbox_reg_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner);
>
> - value = fpci_readl(tegra, tegra->soc->mbox.owner);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
> if (value != MBOX_OWNER_SW) {
> dev_err(tegra->dev, "failed to acquire mailbox\n");
> return -EBUSY;
> @@ -477,17 +565,17 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
> }
>
> value = tegra_xusb_mbox_pack(msg);
> - fpci_writel(tegra, value, tegra->soc->mbox.data_in);
> + ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.data_in);
>
> - value = fpci_readl(tegra, tegra->soc->mbox.cmd);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.cmd);
> value |= MBOX_INT_EN | MBOX_DEST_FALC;
> - fpci_writel(tegra, value, tegra->soc->mbox.cmd);
> + ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.cmd);
>
> if (wait_for_idle) {
> unsigned long timeout = jiffies + msecs_to_jiffies(250);
>
> while (time_before(jiffies, timeout)) {
> - value = fpci_readl(tegra, tegra->soc->mbox.owner);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
> if (value == MBOX_OWNER_NONE)
> break;
>
> @@ -495,7 +583,7 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
> }
>
> if (time_after(jiffies, timeout))
> - value = fpci_readl(tegra, tegra->soc->mbox.owner);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
>
> if (value != MBOX_OWNER_NONE)
> return -ETIMEDOUT;
> @@ -507,11 +595,12 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
> static irqreturn_t tegra_xusb_mbox_irq(int irq, void *data)
> {
> struct tegra_xusb *tegra = data;
> + const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
> u32 value;
>
> /* clear mailbox interrupts */
> - value = fpci_readl(tegra, XUSB_CFG_ARU_SMI_INTR);
> - fpci_writel(tegra, value, XUSB_CFG_ARU_SMI_INTR);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.smi_intr);
> + ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.smi_intr);
>
> if (value & MBOX_SMI_INTR_FW_HANG)
> dev_err(tegra->dev, "controller firmware hang\n");
> @@ -664,6 +753,7 @@ static void tegra_xusb_mbox_handle(struct tegra_xusb *tegra,
> static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
> {
> struct tegra_xusb *tegra = data;
> + const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
> struct tegra_xusb_mbox_msg msg;
> u32 value;
>
> @@ -672,16 +762,16 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
> if (pm_runtime_suspended(tegra->dev) || tegra->suspended)
> goto out;
>
> - value = fpci_readl(tegra, tegra->soc->mbox.data_out);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.data_out);
> tegra_xusb_mbox_unpack(&msg, value);
>
> - value = fpci_readl(tegra, tegra->soc->mbox.cmd);
> + value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.cmd);
> value &= ~MBOX_DEST_SMI;
> - fpci_writel(tegra, value, tegra->soc->mbox.cmd);
> + ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.cmd);
>
> /* clear mailbox owner if no ACK/NAK is required */
> if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd))
> - fpci_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner);
> + ops->mbox_reg_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner);
>
> tegra_xusb_mbox_handle(tegra, &msg);
>
> @@ -709,6 +799,15 @@ static void tegra_xusb_config(struct tegra_xusb *tegra)
> value |= regs & (XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT);
> fpci_writel(tegra, value, XUSB_CFG_4);
>
> + /* Program BAR2 space */
> + if (tegra->bar2) {
> + value = fpci_readl(tegra, XUSB_CFG_7);
> + value &= ~(XUSB_BASE2_ADDR_MASK << XUSB_BASE2_ADDR_SHIFT);
> + value |= tegra->bar2->start &
> + (XUSB_BASE2_ADDR_MASK << XUSB_BASE2_ADDR_SHIFT);
> + fpci_writel(tegra, value, XUSB_CFG_7);
> + }
> +
> usleep_range(100, 200);
>
> /* Enable bus master */
> @@ -881,21 +980,36 @@ static int tegra_xusb_request_firmware(struct tegra_xusb *tegra)
> return 0;
> }
>
> -static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
> +static int tegra_xusb_wait_for_falcon(struct tegra_xusb *tegra)
> +{
> + struct xhci_cap_regs __iomem *cap_regs;
> + struct xhci_op_regs __iomem *op_regs;
> + int ret;
> + u32 value;
> +
> + cap_regs = tegra->regs;
> + op_regs = tegra->regs + HC_LENGTH(readl(&cap_regs->hc_capbase));
> +
> + ret = readl_poll_timeout(&op_regs->status, value, !(value & STS_CNR), 1000, 200000);
> +
> + if (ret)
> + dev_err(tegra->dev, "XHCI Controller not ready. Falcon state: 0x%x\n",
> + csb_readl(tegra, XUSB_FALC_CPUCTL));
> +
> + return ret;
> +}
> +
> +static int tegra_xusb_load_firmware_rom(struct tegra_xusb *tegra)
> {
> unsigned int code_tag_blocks, code_size_blocks, code_blocks;
> - struct xhci_cap_regs __iomem *cap = tegra->regs;
> struct tegra_xusb_fw_header *header;
> struct device *dev = tegra->dev;
> - struct xhci_op_regs __iomem *op;
> - unsigned long timeout;
> time64_t timestamp;
> u64 address;
> u32 value;
> int err;
>
> header = (struct tegra_xusb_fw_header *)tegra->fw.virt;
> - op = tegra->regs + HC_LENGTH(readl(&cap->hc_capbase));
>
> if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) {
> dev_info(dev, "Firmware already loaded, Falcon state %#x\n",
> @@ -968,30 +1082,55 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
> /* Boot Falcon CPU and wait for USBSTS_CNR to get cleared. */
> csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL);
>
> - timeout = jiffies + msecs_to_jiffies(200);
> + if (tegra_xusb_wait_for_falcon(tegra))
> + return -EIO;
> +
> + timestamp = le32_to_cpu(header->fwimg_created_time);
>
> - do {
> - value = readl(&op->status);
> - if ((value & STS_CNR) == 0)
> - break;
> + dev_info(dev, "Firmware timestamp: %ptTs UTC\n", ×tamp);
> +
> + return 0;
> +}
> +
> +static u32 tegra_xusb_read_firmware_header(struct tegra_xusb *tegra, u32 offset)
> +{
> + /*
> + * We only accept reading the firmware config table
> + * The offset should not exceed the fw header structure
> + */
> + if (offset >= sizeof(struct tegra_xusb_fw_header))
> + return 0;
>
> - usleep_range(1000, 2000);
> - } while (time_is_after_jiffies(timeout));
> + bar2_writel(tegra, (FW_IOCTL_CFGTBL_READ << FW_IOCTL_TYPE_SHIFT) | offset,
> + XUSB_BAR2_ARU_FW_SCRATCH);
> + return bar2_readl(tegra, XUSB_BAR2_ARU_SMI_ARU_FW_SCRATCH_DATA0);
> +}
> +
> +static int tegra_xusb_init_ifr_firmware(struct tegra_xusb *tegra)
> +{
> + time64_t timestamp;
>
> - value = readl(&op->status);
> - if (value & STS_CNR) {
> - value = csb_readl(tegra, XUSB_FALC_CPUCTL);
> - dev_err(dev, "XHCI controller not read: %#010x\n", value);
> + if (tegra_xusb_wait_for_falcon(tegra))
> return -EIO;
> - }
>
> - timestamp = le32_to_cpu(header->fwimg_created_time);
> +#define offsetof_32(X, Y) ((u8)(offsetof(X, Y) / sizeof(__le32)))
> + timestamp = tegra_xusb_read_firmware_header(tegra,
> + offsetof_32(struct tegra_xusb_fw_header,
> + fwimg_created_time) << 2);
>
> - dev_info(dev, "Firmware timestamp: %ptTs UTC\n", ×tamp);
> + dev_info(tegra->dev, "Firmware timestamp: %ptTs UTC\n", ×tamp);
>
> return 0;
> }
>
> +static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
> +{
> + if (!tegra->soc->firmware)
> + return tegra_xusb_init_ifr_firmware(tegra);
> + else
> + return tegra_xusb_load_firmware_rom(tegra);
> +}
> +
> static void tegra_xusb_powerdomain_remove(struct device *dev,
> struct tegra_xusb *tegra)
> {
> @@ -1435,6 +1574,10 @@ static int tegra_xusb_probe(struct platform_device *pdev)
> tegra->ipfs_base = devm_platform_ioremap_resource(pdev, 2);
> if (IS_ERR(tegra->ipfs_base))
> return PTR_ERR(tegra->ipfs_base);
> + } else if (tegra->soc->has_bar2) {
> + tegra->bar2_base = devm_platform_get_and_ioremap_resource(pdev, 2, &tegra->bar2);
> + if (IS_ERR(tegra->bar2_base))
> + return PTR_ERR(tegra->bar2_base);
> }
>
> tegra->xhci_irq = platform_get_irq(pdev, 0);
> @@ -1651,10 +1794,13 @@ static int tegra_xusb_probe(struct platform_device *pdev)
> goto disable_phy;
> }
>
> - err = tegra_xusb_request_firmware(tegra);
> - if (err < 0) {
> - dev_err(&pdev->dev, "failed to request firmware: %d\n", err);
> - goto disable_phy;
> + if (tegra->soc->firmware) {
> + err = tegra_xusb_request_firmware(tegra);
> + if (err < 0) {
> + dev_err(&pdev->dev,
> + "failed to request firmware: %d\n", err);
> + goto disable_phy;
> + }
> }
>
> err = tegra_xusb_unpowergate_partitions(tegra);
> @@ -2271,6 +2417,13 @@ static const struct tegra_xusb_context_soc tegra124_xusb_context = {
> },
> };
>
> +static const struct tegra_xusb_soc_ops tegra124_ops = {
> + .mbox_reg_readl = &fpci_readl,
> + .mbox_reg_writel = &fpci_writel,
> + .csb_reg_readl = &fpci_csb_readl,
> + .csb_reg_writel = &fpci_csb_writel,
> +};
> +
> static const struct tegra_xusb_soc tegra124_soc = {
> .firmware = "nvidia/tegra124/xusb.bin",
> .supply_names = tegra124_supply_names,
> @@ -2286,11 +2439,13 @@ static const struct tegra_xusb_soc tegra124_soc = {
> .scale_ss_clock = true,
> .has_ipfs = true,
> .otg_reset_sspi = false,
> + .ops = &tegra124_ops,
> .mbox = {
> .cmd = 0xe4,
> .data_in = 0xe8,
> .data_out = 0xec,
> .owner = 0xf0,
> + .smi_intr = XUSB_CFG_ARU_SMI_INTR,
> },
> };
> MODULE_FIRMWARE("nvidia/tegra124/xusb.bin");
> @@ -2322,11 +2477,13 @@ static const struct tegra_xusb_soc tegra210_soc = {
> .scale_ss_clock = false,
> .has_ipfs = true,
> .otg_reset_sspi = true,
> + .ops = &tegra124_ops,
> .mbox = {
> .cmd = 0xe4,
> .data_in = 0xe8,
> .data_out = 0xec,
> .owner = 0xf0,
> + .smi_intr = XUSB_CFG_ARU_SMI_INTR,
> },
> };
> MODULE_FIRMWARE("nvidia/tegra210/xusb.bin");
> @@ -2363,11 +2520,13 @@ static const struct tegra_xusb_soc tegra186_soc = {
> .scale_ss_clock = false,
> .has_ipfs = false,
> .otg_reset_sspi = false,
> + .ops = &tegra124_ops,
> .mbox = {
> .cmd = 0xe4,
> .data_in = 0xe8,
> .data_out = 0xec,
> .owner = 0xf0,
> + .smi_intr = XUSB_CFG_ARU_SMI_INTR,
> },
> .lpm_support = true,
> };
> @@ -2394,21 +2553,56 @@ static const struct tegra_xusb_soc tegra194_soc = {
> .scale_ss_clock = false,
> .has_ipfs = false,
> .otg_reset_sspi = false,
> + .ops = &tegra124_ops,
> .mbox = {
> .cmd = 0x68,
> .data_in = 0x6c,
> .data_out = 0x70,
> .owner = 0x74,
> + .smi_intr = XUSB_CFG_ARU_SMI_INTR,
> },
> .lpm_support = true,
> };
> MODULE_FIRMWARE("nvidia/tegra194/xusb.bin");
>
> +static const struct tegra_xusb_soc_ops tegra234_ops = {
> + .mbox_reg_readl = &bar2_readl,
> + .mbox_reg_writel = &bar2_writel,
> + .csb_reg_readl = &bar2_csb_readl,
> + .csb_reg_writel = &bar2_csb_writel,
> +};
> +
> +static const struct tegra_xusb_soc tegra234_soc = {
> + .supply_names = tegra194_supply_names,
> + .num_supplies = ARRAY_SIZE(tegra194_supply_names),
> + .phy_types = tegra194_phy_types,
> + .num_types = ARRAY_SIZE(tegra194_phy_types),
> + .context = &tegra186_xusb_context,
> + .ports = {
> + .usb3 = { .offset = 0, .count = 4, },
> + .usb2 = { .offset = 4, .count = 4, },
> + },
> + .scale_ss_clock = false,
> + .has_ipfs = false,
> + .otg_reset_sspi = false,
> + .ops = &tegra234_ops,
> + .mbox = {
> + .cmd = XUSB_BAR2_ARU_MBOX_CMD,
> + .data_in = XUSB_BAR2_ARU_MBOX_DATA_IN,
> + .data_out = XUSB_BAR2_ARU_MBOX_DATA_OUT,
> + .owner = XUSB_BAR2_ARU_MBOX_OWNER,
> + .smi_intr = XUSB_BAR2_ARU_SMI_INTR,
> + },
> + .lpm_support = true,
> + .has_bar2 = true,
> +};
> +
> static const struct of_device_id tegra_xusb_of_match[] = {
> { .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc },
> { .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc },
> { .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc },
> { .compatible = "nvidia,tegra194-xusb", .data = &tegra194_soc },
> + { .compatible = "nvidia,tegra234-xusb", .data = &tegra234_soc },
> { },
> };
> MODULE_DEVICE_TABLE(of, tegra_xusb_of_match);
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
Thanks
Jon
@@ -44,6 +44,9 @@
#define XUSB_CFG_4 0x010
#define XUSB_BASE_ADDR_SHIFT 15
#define XUSB_BASE_ADDR_MASK 0x1ffff
+#define XUSB_CFG_7 0x01c
+#define XUSB_BASE2_ADDR_SHIFT 16
+#define XUSB_BASE2_ADDR_MASK 0xffff
#define XUSB_CFG_16 0x040
#define XUSB_CFG_24 0x060
#define XUSB_CFG_AXI_CFG 0x0f8
@@ -75,6 +78,20 @@
#define MBOX_SMI_INTR_FW_HANG BIT(1)
#define MBOX_SMI_INTR_EN BIT(3)
+/* BAR2 registers */
+#define XUSB_BAR2_ARU_MBOX_CMD 0x004
+#define XUSB_BAR2_ARU_MBOX_DATA_IN 0x008
+#define XUSB_BAR2_ARU_MBOX_DATA_OUT 0x00c
+#define XUSB_BAR2_ARU_MBOX_OWNER 0x010
+#define XUSB_BAR2_ARU_SMI_INTR 0x014
+#define XUSB_BAR2_ARU_SMI_ARU_FW_SCRATCH_DATA0 0x01c
+#define XUSB_BAR2_ARU_IFRDMA_CFG0 0x0e0
+#define XUSB_BAR2_ARU_IFRDMA_CFG1 0x0e4
+#define XUSB_BAR2_ARU_IFRDMA_STREAMID_FIELD 0x0e8
+#define XUSB_BAR2_ARU_C11_CSBRANGE 0x9c
+#define XUSB_BAR2_ARU_FW_SCRATCH 0x1000
+#define XUSB_BAR2_CSB_BASE_ADDR 0x2000
+
/* IPFS registers */
#define IPFS_XUSB_HOST_MSI_BAR_SZ_0 0x0c0
#define IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0 0x0c4
@@ -111,6 +128,9 @@
#define IMFILLRNG1_TAG_HI_SHIFT 16
#define XUSB_FALC_IMFILLCTL 0x158
+/* CSB ARU registers */
+#define XUSB_CSB_ARU_SCRATCH0 0x100100
+
/* MP CSB registers */
#define XUSB_CSB_MP_ILOAD_ATTR 0x101a00
#define XUSB_CSB_MP_ILOAD_BASE_LO 0x101a04
@@ -131,6 +151,9 @@
#define IMEM_BLOCK_SIZE 256
+#define FW_IOCTL_TYPE_SHIFT 24
+#define FW_IOCTL_CFGTBL_READ 17
+
struct tegra_xusb_fw_header {
__le32 boot_loadaddr_in_imem;
__le32 boot_codedfi_offset;
@@ -175,6 +198,7 @@ struct tegra_xusb_mbox_regs {
u16 data_in;
u16 data_out;
u16 owner;
+ u16 smi_intr;
};
struct tegra_xusb_context_soc {
@@ -189,6 +213,18 @@ struct tegra_xusb_context_soc {
} fpci;
};
+struct tegra_xusb;
+struct tegra_xusb_soc_ops {
+ u32 (*mbox_reg_readl)(struct tegra_xusb *tegra,
+ unsigned int offset);
+ void (*mbox_reg_writel)(struct tegra_xusb *tegra,
+ u32 value, unsigned int offset);
+ u32 (*csb_reg_readl)(struct tegra_xusb *tegra,
+ unsigned int offset);
+ void (*csb_reg_writel)(struct tegra_xusb *tegra,
+ u32 value, unsigned int offset);
+};
+
struct tegra_xusb_soc {
const char *firmware;
const char * const *supply_names;
@@ -205,11 +241,14 @@ struct tegra_xusb_soc {
} ports;
struct tegra_xusb_mbox_regs mbox;
+ const struct tegra_xusb_soc_ops *ops;
bool scale_ss_clock;
bool has_ipfs;
bool lpm_support;
bool otg_reset_sspi;
+
+ bool has_bar2;
};
struct tegra_xusb_context {
@@ -230,6 +269,8 @@ struct tegra_xusb {
void __iomem *ipfs_base;
void __iomem *fpci_base;
+ void __iomem *bar2_base;
+ struct resource *bar2;
const struct tegra_xusb_soc *soc;
@@ -300,7 +341,33 @@ static inline void ipfs_writel(struct tegra_xusb *tegra, u32 value,
writel(value, tegra->ipfs_base + offset);
}
+static inline u32 bar2_readl(struct tegra_xusb *tegra, unsigned int offset)
+{
+ return readl(tegra->bar2_base + offset);
+}
+
+static inline void bar2_writel(struct tegra_xusb *tegra, u32 value,
+ unsigned int offset)
+{
+ writel(value, tegra->bar2_base + offset);
+}
+
static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset)
+{
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
+
+ return ops->csb_reg_readl(tegra, offset);
+}
+
+static void csb_writel(struct tegra_xusb *tegra, u32 value,
+ unsigned int offset)
+{
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
+
+ ops->csb_reg_writel(tegra, value, offset);
+}
+
+static u32 fpci_csb_readl(struct tegra_xusb *tegra, unsigned int offset)
{
u32 page = CSB_PAGE_SELECT(offset);
u32 ofs = CSB_PAGE_OFFSET(offset);
@@ -310,7 +377,7 @@ static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset)
return fpci_readl(tegra, XUSB_CFG_CSB_BASE_ADDR + ofs);
}
-static void csb_writel(struct tegra_xusb *tegra, u32 value,
+static void fpci_csb_writel(struct tegra_xusb *tegra, u32 value,
unsigned int offset)
{
u32 page = CSB_PAGE_SELECT(offset);
@@ -320,6 +387,26 @@ static void csb_writel(struct tegra_xusb *tegra, u32 value,
fpci_writel(tegra, value, XUSB_CFG_CSB_BASE_ADDR + ofs);
}
+static u32 bar2_csb_readl(struct tegra_xusb *tegra, unsigned int offset)
+{
+ u32 page = CSB_PAGE_SELECT(offset);
+ u32 ofs = CSB_PAGE_OFFSET(offset);
+
+ bar2_writel(tegra, page, XUSB_BAR2_ARU_C11_CSBRANGE);
+
+ return bar2_readl(tegra, XUSB_BAR2_CSB_BASE_ADDR + ofs);
+}
+
+static void bar2_csb_writel(struct tegra_xusb *tegra, u32 value,
+ unsigned int offset)
+{
+ u32 page = CSB_PAGE_SELECT(offset);
+ u32 ofs = CSB_PAGE_OFFSET(offset);
+
+ bar2_writel(tegra, page, XUSB_BAR2_ARU_C11_CSBRANGE);
+ bar2_writel(tegra, value, XUSB_BAR2_CSB_BASE_ADDR + ofs);
+}
+
static int tegra_xusb_set_ss_clk(struct tegra_xusb *tegra,
unsigned long rate)
{
@@ -451,6 +538,7 @@ static bool tegra_xusb_mbox_cmd_requires_ack(enum tegra_xusb_mbox_cmd cmd)
static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
const struct tegra_xusb_mbox_msg *msg)
{
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
bool wait_for_idle = false;
u32 value;
@@ -459,15 +547,15 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
* ACK/NAK messages.
*/
if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) {
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value != MBOX_OWNER_NONE) {
dev_err(tegra->dev, "mailbox is busy\n");
return -EBUSY;
}
- fpci_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner);
+ ops->mbox_reg_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner);
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value != MBOX_OWNER_SW) {
dev_err(tegra->dev, "failed to acquire mailbox\n");
return -EBUSY;
@@ -477,17 +565,17 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
}
value = tegra_xusb_mbox_pack(msg);
- fpci_writel(tegra, value, tegra->soc->mbox.data_in);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.data_in);
- value = fpci_readl(tegra, tegra->soc->mbox.cmd);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.cmd);
value |= MBOX_INT_EN | MBOX_DEST_FALC;
- fpci_writel(tegra, value, tegra->soc->mbox.cmd);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.cmd);
if (wait_for_idle) {
unsigned long timeout = jiffies + msecs_to_jiffies(250);
while (time_before(jiffies, timeout)) {
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value == MBOX_OWNER_NONE)
break;
@@ -495,7 +583,7 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
}
if (time_after(jiffies, timeout))
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value != MBOX_OWNER_NONE)
return -ETIMEDOUT;
@@ -507,11 +595,12 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
static irqreturn_t tegra_xusb_mbox_irq(int irq, void *data)
{
struct tegra_xusb *tegra = data;
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
u32 value;
/* clear mailbox interrupts */
- value = fpci_readl(tegra, XUSB_CFG_ARU_SMI_INTR);
- fpci_writel(tegra, value, XUSB_CFG_ARU_SMI_INTR);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.smi_intr);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.smi_intr);
if (value & MBOX_SMI_INTR_FW_HANG)
dev_err(tegra->dev, "controller firmware hang\n");
@@ -664,6 +753,7 @@ static void tegra_xusb_mbox_handle(struct tegra_xusb *tegra,
static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
{
struct tegra_xusb *tegra = data;
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
struct tegra_xusb_mbox_msg msg;
u32 value;
@@ -672,16 +762,16 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
if (pm_runtime_suspended(tegra->dev) || tegra->suspended)
goto out;
- value = fpci_readl(tegra, tegra->soc->mbox.data_out);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.data_out);
tegra_xusb_mbox_unpack(&msg, value);
- value = fpci_readl(tegra, tegra->soc->mbox.cmd);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.cmd);
value &= ~MBOX_DEST_SMI;
- fpci_writel(tegra, value, tegra->soc->mbox.cmd);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.cmd);
/* clear mailbox owner if no ACK/NAK is required */
if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd))
- fpci_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner);
+ ops->mbox_reg_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner);
tegra_xusb_mbox_handle(tegra, &msg);
@@ -709,6 +799,15 @@ static void tegra_xusb_config(struct tegra_xusb *tegra)
value |= regs & (XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT);
fpci_writel(tegra, value, XUSB_CFG_4);
+ /* Program BAR2 space */
+ if (tegra->bar2) {
+ value = fpci_readl(tegra, XUSB_CFG_7);
+ value &= ~(XUSB_BASE2_ADDR_MASK << XUSB_BASE2_ADDR_SHIFT);
+ value |= tegra->bar2->start &
+ (XUSB_BASE2_ADDR_MASK << XUSB_BASE2_ADDR_SHIFT);
+ fpci_writel(tegra, value, XUSB_CFG_7);
+ }
+
usleep_range(100, 200);
/* Enable bus master */
@@ -881,21 +980,36 @@ static int tegra_xusb_request_firmware(struct tegra_xusb *tegra)
return 0;
}
-static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
+static int tegra_xusb_wait_for_falcon(struct tegra_xusb *tegra)
+{
+ struct xhci_cap_regs __iomem *cap_regs;
+ struct xhci_op_regs __iomem *op_regs;
+ int ret;
+ u32 value;
+
+ cap_regs = tegra->regs;
+ op_regs = tegra->regs + HC_LENGTH(readl(&cap_regs->hc_capbase));
+
+ ret = readl_poll_timeout(&op_regs->status, value, !(value & STS_CNR), 1000, 200000);
+
+ if (ret)
+ dev_err(tegra->dev, "XHCI Controller not ready. Falcon state: 0x%x\n",
+ csb_readl(tegra, XUSB_FALC_CPUCTL));
+
+ return ret;
+}
+
+static int tegra_xusb_load_firmware_rom(struct tegra_xusb *tegra)
{
unsigned int code_tag_blocks, code_size_blocks, code_blocks;
- struct xhci_cap_regs __iomem *cap = tegra->regs;
struct tegra_xusb_fw_header *header;
struct device *dev = tegra->dev;
- struct xhci_op_regs __iomem *op;
- unsigned long timeout;
time64_t timestamp;
u64 address;
u32 value;
int err;
header = (struct tegra_xusb_fw_header *)tegra->fw.virt;
- op = tegra->regs + HC_LENGTH(readl(&cap->hc_capbase));
if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) {
dev_info(dev, "Firmware already loaded, Falcon state %#x\n",
@@ -968,30 +1082,55 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
/* Boot Falcon CPU and wait for USBSTS_CNR to get cleared. */
csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL);
- timeout = jiffies + msecs_to_jiffies(200);
+ if (tegra_xusb_wait_for_falcon(tegra))
+ return -EIO;
+
+ timestamp = le32_to_cpu(header->fwimg_created_time);
- do {
- value = readl(&op->status);
- if ((value & STS_CNR) == 0)
- break;
+ dev_info(dev, "Firmware timestamp: %ptTs UTC\n", ×tamp);
+
+ return 0;
+}
+
+static u32 tegra_xusb_read_firmware_header(struct tegra_xusb *tegra, u32 offset)
+{
+ /*
+ * We only accept reading the firmware config table
+ * The offset should not exceed the fw header structure
+ */
+ if (offset >= sizeof(struct tegra_xusb_fw_header))
+ return 0;
- usleep_range(1000, 2000);
- } while (time_is_after_jiffies(timeout));
+ bar2_writel(tegra, (FW_IOCTL_CFGTBL_READ << FW_IOCTL_TYPE_SHIFT) | offset,
+ XUSB_BAR2_ARU_FW_SCRATCH);
+ return bar2_readl(tegra, XUSB_BAR2_ARU_SMI_ARU_FW_SCRATCH_DATA0);
+}
+
+static int tegra_xusb_init_ifr_firmware(struct tegra_xusb *tegra)
+{
+ time64_t timestamp;
- value = readl(&op->status);
- if (value & STS_CNR) {
- value = csb_readl(tegra, XUSB_FALC_CPUCTL);
- dev_err(dev, "XHCI controller not read: %#010x\n", value);
+ if (tegra_xusb_wait_for_falcon(tegra))
return -EIO;
- }
- timestamp = le32_to_cpu(header->fwimg_created_time);
+#define offsetof_32(X, Y) ((u8)(offsetof(X, Y) / sizeof(__le32)))
+ timestamp = tegra_xusb_read_firmware_header(tegra,
+ offsetof_32(struct tegra_xusb_fw_header,
+ fwimg_created_time) << 2);
- dev_info(dev, "Firmware timestamp: %ptTs UTC\n", ×tamp);
+ dev_info(tegra->dev, "Firmware timestamp: %ptTs UTC\n", ×tamp);
return 0;
}
+static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
+{
+ if (!tegra->soc->firmware)
+ return tegra_xusb_init_ifr_firmware(tegra);
+ else
+ return tegra_xusb_load_firmware_rom(tegra);
+}
+
static void tegra_xusb_powerdomain_remove(struct device *dev,
struct tegra_xusb *tegra)
{
@@ -1435,6 +1574,10 @@ static int tegra_xusb_probe(struct platform_device *pdev)
tegra->ipfs_base = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(tegra->ipfs_base))
return PTR_ERR(tegra->ipfs_base);
+ } else if (tegra->soc->has_bar2) {
+ tegra->bar2_base = devm_platform_get_and_ioremap_resource(pdev, 2, &tegra->bar2);
+ if (IS_ERR(tegra->bar2_base))
+ return PTR_ERR(tegra->bar2_base);
}
tegra->xhci_irq = platform_get_irq(pdev, 0);
@@ -1651,10 +1794,13 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto disable_phy;
}
- err = tegra_xusb_request_firmware(tegra);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to request firmware: %d\n", err);
- goto disable_phy;
+ if (tegra->soc->firmware) {
+ err = tegra_xusb_request_firmware(tegra);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "failed to request firmware: %d\n", err);
+ goto disable_phy;
+ }
}
err = tegra_xusb_unpowergate_partitions(tegra);
@@ -2271,6 +2417,13 @@ static const struct tegra_xusb_context_soc tegra124_xusb_context = {
},
};
+static const struct tegra_xusb_soc_ops tegra124_ops = {
+ .mbox_reg_readl = &fpci_readl,
+ .mbox_reg_writel = &fpci_writel,
+ .csb_reg_readl = &fpci_csb_readl,
+ .csb_reg_writel = &fpci_csb_writel,
+};
+
static const struct tegra_xusb_soc tegra124_soc = {
.firmware = "nvidia/tegra124/xusb.bin",
.supply_names = tegra124_supply_names,
@@ -2286,11 +2439,13 @@ static const struct tegra_xusb_soc tegra124_soc = {
.scale_ss_clock = true,
.has_ipfs = true,
.otg_reset_sspi = false,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
.data_out = 0xec,
.owner = 0xf0,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
};
MODULE_FIRMWARE("nvidia/tegra124/xusb.bin");
@@ -2322,11 +2477,13 @@ static const struct tegra_xusb_soc tegra210_soc = {
.scale_ss_clock = false,
.has_ipfs = true,
.otg_reset_sspi = true,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
.data_out = 0xec,
.owner = 0xf0,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
};
MODULE_FIRMWARE("nvidia/tegra210/xusb.bin");
@@ -2363,11 +2520,13 @@ static const struct tegra_xusb_soc tegra186_soc = {
.scale_ss_clock = false,
.has_ipfs = false,
.otg_reset_sspi = false,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
.data_out = 0xec,
.owner = 0xf0,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
.lpm_support = true,
};
@@ -2394,21 +2553,56 @@ static const struct tegra_xusb_soc tegra194_soc = {
.scale_ss_clock = false,
.has_ipfs = false,
.otg_reset_sspi = false,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0x68,
.data_in = 0x6c,
.data_out = 0x70,
.owner = 0x74,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
.lpm_support = true,
};
MODULE_FIRMWARE("nvidia/tegra194/xusb.bin");
+static const struct tegra_xusb_soc_ops tegra234_ops = {
+ .mbox_reg_readl = &bar2_readl,
+ .mbox_reg_writel = &bar2_writel,
+ .csb_reg_readl = &bar2_csb_readl,
+ .csb_reg_writel = &bar2_csb_writel,
+};
+
+static const struct tegra_xusb_soc tegra234_soc = {
+ .supply_names = tegra194_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra194_supply_names),
+ .phy_types = tegra194_phy_types,
+ .num_types = ARRAY_SIZE(tegra194_phy_types),
+ .context = &tegra186_xusb_context,
+ .ports = {
+ .usb3 = { .offset = 0, .count = 4, },
+ .usb2 = { .offset = 4, .count = 4, },
+ },
+ .scale_ss_clock = false,
+ .has_ipfs = false,
+ .otg_reset_sspi = false,
+ .ops = &tegra234_ops,
+ .mbox = {
+ .cmd = XUSB_BAR2_ARU_MBOX_CMD,
+ .data_in = XUSB_BAR2_ARU_MBOX_DATA_IN,
+ .data_out = XUSB_BAR2_ARU_MBOX_DATA_OUT,
+ .owner = XUSB_BAR2_ARU_MBOX_OWNER,
+ .smi_intr = XUSB_BAR2_ARU_SMI_INTR,
+ },
+ .lpm_support = true,
+ .has_bar2 = true,
+};
+
static const struct of_device_id tegra_xusb_of_match[] = {
{ .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc },
{ .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc },
{ .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc },
{ .compatible = "nvidia,tegra194-xusb", .data = &tegra194_soc },
+ { .compatible = "nvidia,tegra234-xusb", .data = &tegra234_soc },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_xusb_of_match);