drivers/usb/host/xhci-rcar.c

Source file repositories/reference/linux-study-clean/drivers/usb/host/xhci-rcar.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/xhci-rcar.c
Extension
.c
Size
8565 bytes
Lines
301
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * xHCI host controller driver for R-Car SoCs
 *
 * Copyright (C) 2014 Renesas Electronics Corporation
 */

#include <linux/firmware.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/usb/phy.h>
#include <linux/reset.h>

#include "xhci.h"
#include "xhci-plat.h"
#include "xhci-rcar-regs.h"
#include "xhci-rzg3e-regs.h"
#include "xhci-rzv2m.h"

#define XHCI_RCAR_FIRMWARE_NAME_V1	"r8a779x_usb3_v1.dlmem"
#define XHCI_RCAR_FIRMWARE_NAME_V3	"r8a779x_usb3_v3.dlmem"

/*
* - The V3 firmware is for all R-Car Gen3
* - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes
*   performance degradation. So, this driver continues to use the V1 if R-Car
*   Gen2.
* - The V1 firmware is impossible to use on R-Car Gen3.
*/
MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1);
MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);

static void xhci_rcar_start_gen2(struct usb_hcd *hcd)
{
	/* LCLK Select */
	writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK);
	/* USB3.0 Configuration */
	writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1);
	writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2);
	writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3);
	/* USB3.0 Polarity */
	writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL);
	writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
}

static int xhci_rcar_is_gen2(struct device *dev)
{
	struct device_node *node = dev->of_node;

	return of_device_is_compatible(node, "renesas,xhci-r8a7790") ||
		of_device_is_compatible(node, "renesas,xhci-r8a7791") ||
		of_device_is_compatible(node, "renesas,xhci-r8a7793") ||
		of_device_is_compatible(node, "renesas,rcar-gen2-xhci");
}

static void xhci_rcar_start(struct usb_hcd *hcd)
{
	u32 temp;

	if (hcd->regs != NULL) {
		/* Interrupt Enable */
		temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
		temp |= RCAR_USB3_INT_ENA_VAL;
		writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
		if (xhci_rcar_is_gen2(hcd->self.controller))
			xhci_rcar_start_gen2(hcd);
	}
}

static void xhci_rzg3e_start(struct usb_hcd *hcd)
{
	u32 int_en;

	if (hcd->regs) {
		/* Update the controller initial setting */
		writel(0x03130200, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(0));
		writel(0x00160200, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(1));
		writel(0x03150000, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(2));
		writel(0x03130200, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(3));
		writel(0x00180000, hcd->regs + RZG3E_USB3_HOST_U3P0PIPESC(4));

		/* Interrupt Enable */
		int_en = readl(hcd->regs + RZG3E_USB3_HOST_INTEN);
		int_en |= RZG3E_USB3_HOST_INTEN_ENA;
		writel(int_en, hcd->regs + RZG3E_USB3_HOST_INTEN);
	}
}

Annotation

Implementation Notes