diff options
-rw-r--r-- | drivers/usb/host/Kconfig | 8 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 3 | ||||
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 19 | ||||
-rw-r--r-- | drivers/usb/host/xhci-rcar.c | 148 | ||||
-rw-r--r-- | drivers/usb/host/xhci-rcar.h | 27 |
5 files changed, 205 insertions, 0 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 03314f861bee..82800a775501 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -37,6 +37,14 @@ config USB_XHCI_MVEBU | |||
37 | Say 'Y' to enable the support for the xHCI host controller | 37 | Say 'Y' to enable the support for the xHCI host controller |
38 | found in Marvell Armada 375/38x ARM SOCs. | 38 | found in Marvell Armada 375/38x ARM SOCs. |
39 | 39 | ||
40 | config USB_XHCI_RCAR | ||
41 | tristate "xHCI support for Renesas R-Car SoCs" | ||
42 | select USB_XHCI_PLATFORM | ||
43 | depends on ARCH_SHMOBILE || COMPILE_TEST | ||
44 | ---help--- | ||
45 | Say 'Y' to enable the support for the xHCI host controller | ||
46 | found in Renesas R-Car ARM SoCs. | ||
47 | |||
40 | endif # USB_XHCI_HCD | 48 | endif # USB_XHCI_HCD |
41 | 49 | ||
42 | config USB_EHCI_HCD | 50 | config USB_EHCI_HCD |
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index af89a903d97e..144c038ef70f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -22,6 +22,9 @@ ifneq ($(CONFIG_USB_XHCI_PLATFORM), ) | |||
22 | ifneq ($(CONFIG_USB_XHCI_MVEBU), ) | 22 | ifneq ($(CONFIG_USB_XHCI_MVEBU), ) |
23 | xhci-hcd-y += xhci-mvebu.o | 23 | xhci-hcd-y += xhci-mvebu.o |
24 | endif | 24 | endif |
25 | ifneq ($(CONFIG_USB_XHCI_RCAR), ) | ||
26 | xhci-hcd-y += xhci-rcar.o | ||
27 | endif | ||
25 | endif | 28 | endif |
26 | 29 | ||
27 | obj-$(CONFIG_USB_WHCI_HCD) += whci/ | 30 | obj-$(CONFIG_USB_WHCI_HCD) += whci/ |
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 794219d8d2a9..1a0cf9f31e43 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include "xhci.h" | 22 | #include "xhci.h" |
23 | #include "xhci-mvebu.h" | 23 | #include "xhci-mvebu.h" |
24 | #include "xhci-rcar.h" | ||
24 | 25 | ||
25 | static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) | 26 | static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) |
26 | { | 27 | { |
@@ -35,11 +36,27 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) | |||
35 | /* called during probe() after chip reset completes */ | 36 | /* called during probe() after chip reset completes */ |
36 | static int xhci_plat_setup(struct usb_hcd *hcd) | 37 | static int xhci_plat_setup(struct usb_hcd *hcd) |
37 | { | 38 | { |
39 | struct device_node *of_node = hcd->self.controller->of_node; | ||
40 | int ret; | ||
41 | |||
42 | if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") || | ||
43 | of_device_is_compatible(of_node, "renesas,xhci-r8a7791")) { | ||
44 | ret = xhci_rcar_init_quirk(hcd); | ||
45 | if (ret) | ||
46 | return ret; | ||
47 | } | ||
48 | |||
38 | return xhci_gen_setup(hcd, xhci_plat_quirks); | 49 | return xhci_gen_setup(hcd, xhci_plat_quirks); |
39 | } | 50 | } |
40 | 51 | ||
41 | static int xhci_plat_start(struct usb_hcd *hcd) | 52 | static int xhci_plat_start(struct usb_hcd *hcd) |
42 | { | 53 | { |
54 | struct device_node *of_node = hcd->self.controller->of_node; | ||
55 | |||
56 | if (of_device_is_compatible(of_node, "renesas,xhci-r8a7790") || | ||
57 | of_device_is_compatible(of_node, "renesas,xhci-r8a7791")) | ||
58 | xhci_rcar_start(hcd); | ||
59 | |||
43 | return xhci_run(hcd); | 60 | return xhci_run(hcd); |
44 | } | 61 | } |
45 | 62 | ||
@@ -263,6 +280,8 @@ static const struct of_device_id usb_xhci_of_match[] = { | |||
263 | { .compatible = "xhci-platform" }, | 280 | { .compatible = "xhci-platform" }, |
264 | { .compatible = "marvell,armada-375-xhci"}, | 281 | { .compatible = "marvell,armada-375-xhci"}, |
265 | { .compatible = "marvell,armada-380-xhci"}, | 282 | { .compatible = "marvell,armada-380-xhci"}, |
283 | { .compatible = "renesas,xhci-r8a7790"}, | ||
284 | { .compatible = "renesas,xhci-r8a7791"}, | ||
266 | { }, | 285 | { }, |
267 | }; | 286 | }; |
268 | MODULE_DEVICE_TABLE(of, usb_xhci_of_match); | 287 | MODULE_DEVICE_TABLE(of, usb_xhci_of_match); |
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c new file mode 100644 index 000000000000..ff0d1b44ea58 --- /dev/null +++ b/drivers/usb/host/xhci-rcar.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * xHCI host controller driver for R-Car SoCs | ||
3 | * | ||
4 | * Copyright (C) 2014 Renesas Electronics Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/firmware.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/usb/phy.h> | ||
15 | |||
16 | #include "xhci.h" | ||
17 | #include "xhci-rcar.h" | ||
18 | |||
19 | #define FIRMWARE_NAME "r8a779x_usb3_v1.dlmem" | ||
20 | MODULE_FIRMWARE(FIRMWARE_NAME); | ||
21 | |||
22 | /*** Register Offset ***/ | ||
23 | #define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */ | ||
24 | #define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */ | ||
25 | #define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */ | ||
26 | |||
27 | #define RCAR_USB3_LCLK 0xa44 /* LCLK Select */ | ||
28 | #define RCAR_USB3_CONF1 0xa48 /* USB3.0 Configuration1 */ | ||
29 | #define RCAR_USB3_CONF2 0xa5c /* USB3.0 Configuration2 */ | ||
30 | #define RCAR_USB3_CONF3 0xaa8 /* USB3.0 Configuration3 */ | ||
31 | #define RCAR_USB3_RX_POL 0xab0 /* USB3.0 RX Polarity */ | ||
32 | #define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */ | ||
33 | |||
34 | /*** Register Settings ***/ | ||
35 | /* Interrupt Enable */ | ||
36 | #define RCAR_USB3_INT_XHC_ENA 0x00000001 | ||
37 | #define RCAR_USB3_INT_PME_ENA 0x00000002 | ||
38 | #define RCAR_USB3_INT_HSE_ENA 0x00000004 | ||
39 | #define RCAR_USB3_INT_ENA_VAL (RCAR_USB3_INT_XHC_ENA | \ | ||
40 | RCAR_USB3_INT_PME_ENA | RCAR_USB3_INT_HSE_ENA) | ||
41 | |||
42 | /* FW Download Control & Status */ | ||
43 | #define RCAR_USB3_DL_CTRL_ENABLE 0x00000001 | ||
44 | #define RCAR_USB3_DL_CTRL_FW_SUCCESS 0x00000010 | ||
45 | #define RCAR_USB3_DL_CTRL_FW_SET_DATA0 0x00000100 | ||
46 | |||
47 | /* LCLK Select */ | ||
48 | #define RCAR_USB3_LCLK_ENA_VAL 0x01030001 | ||
49 | |||
50 | /* USB3.0 Configuration */ | ||
51 | #define RCAR_USB3_CONF1_VAL 0x00030204 | ||
52 | #define RCAR_USB3_CONF2_VAL 0x00030300 | ||
53 | #define RCAR_USB3_CONF3_VAL 0x13802007 | ||
54 | |||
55 | /* USB3.0 Polarity */ | ||
56 | #define RCAR_USB3_RX_POL_VAL BIT(21) | ||
57 | #define RCAR_USB3_TX_POL_VAL BIT(4) | ||
58 | |||
59 | void xhci_rcar_start(struct usb_hcd *hcd) | ||
60 | { | ||
61 | u32 temp; | ||
62 | |||
63 | if (hcd->regs != NULL) { | ||
64 | /* Interrupt Enable */ | ||
65 | temp = readl(hcd->regs + RCAR_USB3_INT_ENA); | ||
66 | temp |= RCAR_USB3_INT_ENA_VAL; | ||
67 | writel(temp, hcd->regs + RCAR_USB3_INT_ENA); | ||
68 | /* LCLK Select */ | ||
69 | writel(RCAR_USB3_LCLK_ENA_VAL, hcd->regs + RCAR_USB3_LCLK); | ||
70 | /* USB3.0 Configuration */ | ||
71 | writel(RCAR_USB3_CONF1_VAL, hcd->regs + RCAR_USB3_CONF1); | ||
72 | writel(RCAR_USB3_CONF2_VAL, hcd->regs + RCAR_USB3_CONF2); | ||
73 | writel(RCAR_USB3_CONF3_VAL, hcd->regs + RCAR_USB3_CONF3); | ||
74 | /* USB3.0 Polarity */ | ||
75 | writel(RCAR_USB3_RX_POL_VAL, hcd->regs + RCAR_USB3_RX_POL); | ||
76 | writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static int xhci_rcar_download_firmware(struct device *dev, void __iomem *regs) | ||
81 | { | ||
82 | const struct firmware *fw; | ||
83 | int retval, index, j, time; | ||
84 | int timeout = 10000; | ||
85 | u32 data, val, temp; | ||
86 | |||
87 | /* request R-Car USB3.0 firmware */ | ||
88 | retval = request_firmware(&fw, FIRMWARE_NAME, dev); | ||
89 | if (retval) | ||
90 | return retval; | ||
91 | |||
92 | /* download R-Car USB3.0 firmware */ | ||
93 | temp = readl(regs + RCAR_USB3_DL_CTRL); | ||
94 | temp |= RCAR_USB3_DL_CTRL_ENABLE; | ||
95 | writel(temp, regs + RCAR_USB3_DL_CTRL); | ||
96 | |||
97 | for (index = 0; index < fw->size; index += 4) { | ||
98 | /* to avoid reading beyond the end of the buffer */ | ||
99 | for (data = 0, j = 3; j >= 0; j--) { | ||
100 | if ((j + index) < fw->size) | ||
101 | data |= fw->data[index + j] << (8 * j); | ||
102 | } | ||
103 | writel(data, regs + RCAR_USB3_FW_DATA0); | ||
104 | temp = readl(regs + RCAR_USB3_DL_CTRL); | ||
105 | temp |= RCAR_USB3_DL_CTRL_FW_SET_DATA0; | ||
106 | writel(temp, regs + RCAR_USB3_DL_CTRL); | ||
107 | |||
108 | for (time = 0; time < timeout; time++) { | ||
109 | val = readl(regs + RCAR_USB3_DL_CTRL); | ||
110 | if ((val & RCAR_USB3_DL_CTRL_FW_SET_DATA0) == 0) | ||
111 | break; | ||
112 | udelay(1); | ||
113 | } | ||
114 | if (time == timeout) { | ||
115 | retval = -ETIMEDOUT; | ||
116 | break; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | temp = readl(regs + RCAR_USB3_DL_CTRL); | ||
121 | temp &= ~RCAR_USB3_DL_CTRL_ENABLE; | ||
122 | writel(temp, regs + RCAR_USB3_DL_CTRL); | ||
123 | |||
124 | for (time = 0; time < timeout; time++) { | ||
125 | val = readl(regs + RCAR_USB3_DL_CTRL); | ||
126 | if (val & RCAR_USB3_DL_CTRL_FW_SUCCESS) { | ||
127 | retval = 0; | ||
128 | break; | ||
129 | } | ||
130 | udelay(1); | ||
131 | } | ||
132 | if (time == timeout) | ||
133 | retval = -ETIMEDOUT; | ||
134 | |||
135 | release_firmware(fw); | ||
136 | |||
137 | return retval; | ||
138 | } | ||
139 | |||
140 | /* This function needs to initialize a "phy" of usb before */ | ||
141 | int xhci_rcar_init_quirk(struct usb_hcd *hcd) | ||
142 | { | ||
143 | /* If hcd->regs is NULL, we don't just call the following function */ | ||
144 | if (!hcd->regs) | ||
145 | return 0; | ||
146 | |||
147 | return xhci_rcar_download_firmware(hcd->self.controller, hcd->regs); | ||
148 | } | ||
diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h new file mode 100644 index 000000000000..58501256715d --- /dev/null +++ b/drivers/usb/host/xhci-rcar.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * drivers/usb/host/xhci-rcar.h | ||
3 | * | ||
4 | * Copyright (C) 2014 Renesas Electronics Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _XHCI_RCAR_H | ||
12 | #define _XHCI_RCAR_H | ||
13 | |||
14 | #if IS_ENABLED(CONFIG_USB_XHCI_RCAR) | ||
15 | void xhci_rcar_start(struct usb_hcd *hcd); | ||
16 | int xhci_rcar_init_quirk(struct usb_hcd *hcd); | ||
17 | #else | ||
18 | static inline void xhci_rcar_start(struct usb_hcd *hcd) | ||
19 | { | ||
20 | } | ||
21 | |||
22 | static inline int xhci_rcar_init_quirk(struct usb_hcd *hcd) | ||
23 | { | ||
24 | return 0; | ||
25 | } | ||
26 | #endif | ||
27 | #endif /* _XHCI_RCAR_H */ | ||