diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 16:14:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 16:14:02 -0400 |
commit | 4a5219edcdae52bfb5eea0dfc2a7bd575961dad7 (patch) | |
tree | 863f6efeac5fe9ba4f1f8d23b32b2947130ed510 /drivers | |
parent | 9797f6b0504122e4ad9ff047a3d0521ad6706386 (diff) | |
parent | 5420f9fd159761b88978c312c3b350546f8615bb (diff) |
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann:
"Driver updates for ARM SoCs, these contain various things that touch
the drivers/ directory but got merged through arm-soc for practical
reasons.
For the most part, this is now related to power management
controllers, which have not yet been abstracted into a separate
subsystem, and typically require some code in drivers/soc or arch/arm
to control the power domains.
Another large chunk here is a rework of the NVIDIA Tegra USB3.0
support, which was surprisingly tricky and took a long time to get
done.
Finally, reset controller handling as always gets merged through here
as well"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (97 commits)
arm-ccn: Enable building as module
soc/tegra: pmc: Add generic PM domain support
usb: xhci: tegra: Add Tegra210 support
usb: xhci: Add NVIDIA Tegra XUSB controller driver
dt-bindings: usb: xhci-tegra: Add Tegra210 XUSB controller support
dt-bindings: usb: Add NVIDIA Tegra XUSB controller binding
PCI: tegra: Support per-lane PHYs
dt-bindings: pci: tegra: Update for per-lane PHYs
phy: tegra: Add Tegra210 support
phy: Add Tegra XUSB pad controller support
dt-bindings: phy: tegra-xusb-padctl: Add Tegra210 support
dt-bindings: phy: Add NVIDIA Tegra XUSB pad controller binding
phy: core: Allow children node to be overridden
clk: tegra: Add interface to enable hardware control of SATA/XUSB PLLs
drivers: firmware: psci: make two helper functions inline
soc: renesas: rcar-sysc: Add support for R-Car H3 power areas
soc: renesas: rcar-sysc: Add support for R-Car E2 power areas
soc: renesas: rcar-sysc: Add support for R-Car M2-N power areas
soc: renesas: rcar-sysc: Add support for R-Car M2-W power areas
soc: renesas: rcar-sysc: Add support for R-Car H2 power areas
...
Diffstat (limited to 'drivers')
56 files changed, 9792 insertions, 446 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index d4a3a3133da5..c5a7de9bc783 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig | |||
@@ -48,7 +48,7 @@ config ARM_CCI5xx_PMU | |||
48 | If unsure, say Y | 48 | If unsure, say Y |
49 | 49 | ||
50 | config ARM_CCN | 50 | config ARM_CCN |
51 | bool "ARM CCN driver support" | 51 | tristate "ARM CCN driver support" |
52 | depends on ARM || ARM64 | 52 | depends on ARM || ARM64 |
53 | depends on PERF_EVENTS | 53 | depends on PERF_EVENTS |
54 | help | 54 | help |
@@ -58,6 +58,7 @@ config ARM_CCN | |||
58 | config BRCMSTB_GISB_ARB | 58 | config BRCMSTB_GISB_ARB |
59 | bool "Broadcom STB GISB bus arbiter" | 59 | bool "Broadcom STB GISB bus arbiter" |
60 | depends on ARM || MIPS | 60 | depends on ARM || MIPS |
61 | default ARCH_BRCMSTB || BMIPS_GENERIC | ||
61 | help | 62 | help |
62 | Driver for the Broadcom Set Top Box System-on-a-chip internal bus | 63 | Driver for the Broadcom Set Top Box System-on-a-chip internal bus |
63 | arbiter. This driver provides timeout and target abort error handling | 64 | arbiter. This driver provides timeout and target abort error handling |
@@ -110,7 +111,7 @@ config OMAP_OCP2SCP | |||
110 | config SIMPLE_PM_BUS | 111 | config SIMPLE_PM_BUS |
111 | bool "Simple Power-Managed Bus Driver" | 112 | bool "Simple Power-Managed Bus Driver" |
112 | depends on OF && PM | 113 | depends on OF && PM |
113 | depends on ARCH_SHMOBILE || COMPILE_TEST | 114 | depends on ARCH_RENESAS || COMPILE_TEST |
114 | help | 115 | help |
115 | Driver for transparent busses that don't need a real driver, but | 116 | Driver for transparent busses that don't need a real driver, but |
116 | where the bus controller is part of a PM domain, or under the control | 117 | where the bus controller is part of a PM domain, or under the control |
diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c index 7082c7268845..acc3eb542c74 100644 --- a/drivers/bus/arm-ccn.c +++ b/drivers/bus/arm-ccn.c | |||
@@ -1189,7 +1189,7 @@ static int arm_ccn_pmu_cpu_notifier(struct notifier_block *nb, | |||
1189 | perf_pmu_migrate_context(&dt->pmu, cpu, target); | 1189 | perf_pmu_migrate_context(&dt->pmu, cpu, target); |
1190 | cpumask_set_cpu(target, &dt->cpu); | 1190 | cpumask_set_cpu(target, &dt->cpu); |
1191 | if (ccn->irq) | 1191 | if (ccn->irq) |
1192 | WARN_ON(irq_set_affinity(ccn->irq, &dt->cpu) != 0); | 1192 | WARN_ON(irq_set_affinity_hint(ccn->irq, &dt->cpu) != 0); |
1193 | default: | 1193 | default: |
1194 | break; | 1194 | break; |
1195 | } | 1195 | } |
@@ -1278,7 +1278,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn) | |||
1278 | 1278 | ||
1279 | /* Also make sure that the overflow interrupt is handled by this CPU */ | 1279 | /* Also make sure that the overflow interrupt is handled by this CPU */ |
1280 | if (ccn->irq) { | 1280 | if (ccn->irq) { |
1281 | err = irq_set_affinity(ccn->irq, &ccn->dt.cpu); | 1281 | err = irq_set_affinity_hint(ccn->irq, &ccn->dt.cpu); |
1282 | if (err) { | 1282 | if (err) { |
1283 | dev_err(ccn->dev, "Failed to set interrupt affinity!\n"); | 1283 | dev_err(ccn->dev, "Failed to set interrupt affinity!\n"); |
1284 | goto error_set_affinity; | 1284 | goto error_set_affinity; |
@@ -1306,7 +1306,8 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn) | |||
1306 | { | 1306 | { |
1307 | int i; | 1307 | int i; |
1308 | 1308 | ||
1309 | irq_set_affinity(ccn->irq, cpu_possible_mask); | 1309 | if (ccn->irq) |
1310 | irq_set_affinity_hint(ccn->irq, NULL); | ||
1310 | unregister_cpu_notifier(&ccn->dt.cpu_nb); | 1311 | unregister_cpu_notifier(&ccn->dt.cpu_nb); |
1311 | for (i = 0; i < ccn->num_xps; i++) | 1312 | for (i = 0; i < ccn->num_xps; i++) |
1312 | writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL); | 1313 | writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL); |
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 16f7d33421d8..c45554957499 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -201,6 +201,7 @@ source "drivers/clk/bcm/Kconfig" | |||
201 | source "drivers/clk/hisilicon/Kconfig" | 201 | source "drivers/clk/hisilicon/Kconfig" |
202 | source "drivers/clk/mvebu/Kconfig" | 202 | source "drivers/clk/mvebu/Kconfig" |
203 | source "drivers/clk/qcom/Kconfig" | 203 | source "drivers/clk/qcom/Kconfig" |
204 | source "drivers/clk/renesas/Kconfig" | ||
204 | source "drivers/clk/samsung/Kconfig" | 205 | source "drivers/clk/samsung/Kconfig" |
205 | source "drivers/clk/tegra/Kconfig" | 206 | source "drivers/clk/tegra/Kconfig" |
206 | source "drivers/clk/ti/Kconfig" | 207 | source "drivers/clk/ti/Kconfig" |
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig new file mode 100644 index 000000000000..2115ce410cfb --- /dev/null +++ b/drivers/clk/renesas/Kconfig | |||
@@ -0,0 +1,16 @@ | |||
1 | config CLK_RENESAS_CPG_MSSR | ||
2 | bool | ||
3 | default y if ARCH_R8A7795 | ||
4 | |||
5 | config CLK_RENESAS_CPG_MSTP | ||
6 | bool | ||
7 | default y if ARCH_R7S72100 | ||
8 | default y if ARCH_R8A73A4 | ||
9 | default y if ARCH_R8A7740 | ||
10 | default y if ARCH_R8A7778 | ||
11 | default y if ARCH_R8A7779 | ||
12 | default y if ARCH_R8A7790 | ||
13 | default y if ARCH_R8A7791 | ||
14 | default y if ARCH_R8A7793 | ||
15 | default y if ARCH_R8A7794 | ||
16 | default y if ARCH_SH73A0 | ||
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 7e2579b30326..ead8bb843524 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile | |||
@@ -1,13 +1,15 @@ | |||
1 | obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o | 1 | obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o |
2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o clk-mstp.o | 2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o |
3 | obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-mstp.o clk-div6.o | 3 | obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-div6.o |
4 | obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-mstp.o clk-div6.o | 4 | obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-div6.o |
5 | obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o clk-mstp.o | 5 | obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o |
6 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o clk-mstp.o | 6 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o |
7 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-mstp.o clk-div6.o | 7 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-div6.o |
8 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-mstp.o clk-div6.o | 8 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-div6.o |
9 | obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-mstp.o clk-div6.o | 9 | obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-div6.o |
10 | obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-mstp.o clk-div6.o | 10 | obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-div6.o |
11 | obj-$(CONFIG_ARCH_R8A7795) += renesas-cpg-mssr.o \ | 11 | obj-$(CONFIG_ARCH_R8A7795) += r8a7795-cpg-mssr.o |
12 | r8a7795-cpg-mssr.o clk-div6.o | 12 | obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-div6.o |
13 | obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-mstp.o clk-div6.o | 13 | |
14 | obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o clk-div6.o | ||
15 | obj-$(CONFIG_CLK_RENESAS_CPG_MSTP) += clk-mstp.o | ||
diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 3d44e183aedd..8b597b9a3804 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c | |||
@@ -243,9 +243,7 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) | |||
243 | } | 243 | } |
244 | CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init); | 244 | CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init); |
245 | 245 | ||
246 | 246 | int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev) | |
247 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF | ||
248 | int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev) | ||
249 | { | 247 | { |
250 | struct device_node *np = dev->of_node; | 248 | struct device_node *np = dev->of_node; |
251 | struct of_phandle_args clkspec; | 249 | struct of_phandle_args clkspec; |
@@ -297,7 +295,7 @@ fail_put: | |||
297 | return error; | 295 | return error; |
298 | } | 296 | } |
299 | 297 | ||
300 | void cpg_mstp_detach_dev(struct generic_pm_domain *domain, struct device *dev) | 298 | void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev) |
301 | { | 299 | { |
302 | if (!list_empty(&dev->power.subsys_data->clock_list)) | 300 | if (!list_empty(&dev->power.subsys_data->clock_list)) |
303 | pm_clk_destroy(dev); | 301 | pm_clk_destroy(dev); |
@@ -326,4 +324,3 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np) | |||
326 | 324 | ||
327 | of_genpd_add_provider_simple(np, pd); | 325 | of_genpd_add_provider_simple(np, pd); |
328 | } | 326 | } |
329 | #endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */ | ||
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index b2198aef5ed4..6af7f5b6e824 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c | |||
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/bug.h> | 15 | #include <linux/bug.h> |
16 | #include <linux/clk.h> | ||
16 | #include <linux/clk-provider.h> | 17 | #include <linux/clk-provider.h> |
17 | #include <linux/device.h> | 18 | #include <linux/device.h> |
18 | #include <linux/err.h> | 19 | #include <linux/err.h> |
@@ -26,6 +27,7 @@ | |||
26 | 27 | ||
27 | #include "renesas-cpg-mssr.h" | 28 | #include "renesas-cpg-mssr.h" |
28 | 29 | ||
30 | #define CPG_RCKCR 0x240 | ||
29 | 31 | ||
30 | enum clk_ids { | 32 | enum clk_ids { |
31 | /* Core Clock Outputs exported to DT */ | 33 | /* Core Clock Outputs exported to DT */ |
@@ -50,6 +52,7 @@ enum clk_ids { | |||
50 | CLK_S3, | 52 | CLK_S3, |
51 | CLK_SDSRC, | 53 | CLK_SDSRC, |
52 | CLK_SSPSRC, | 54 | CLK_SSPSRC, |
55 | CLK_RINT, | ||
53 | 56 | ||
54 | /* Module Clocks */ | 57 | /* Module Clocks */ |
55 | MOD_CLK_BASE | 58 | MOD_CLK_BASE |
@@ -63,8 +66,12 @@ enum r8a7795_clk_types { | |||
63 | CLK_TYPE_GEN3_PLL3, | 66 | CLK_TYPE_GEN3_PLL3, |
64 | CLK_TYPE_GEN3_PLL4, | 67 | CLK_TYPE_GEN3_PLL4, |
65 | CLK_TYPE_GEN3_SD, | 68 | CLK_TYPE_GEN3_SD, |
69 | CLK_TYPE_GEN3_R, | ||
66 | }; | 70 | }; |
67 | 71 | ||
72 | #define DEF_GEN3_SD(_name, _id, _parent, _offset) \ | ||
73 | DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset) | ||
74 | |||
68 | static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { | 75 | static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { |
69 | /* External Clock Inputs */ | 76 | /* External Clock Inputs */ |
70 | DEF_INPUT("extal", CLK_EXTAL), | 77 | DEF_INPUT("extal", CLK_EXTAL), |
@@ -102,10 +109,10 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { | |||
102 | DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1), | 109 | DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1), |
103 | DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1), | 110 | DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1), |
104 | 111 | ||
105 | DEF_SD("sd0", R8A7795_CLK_SD0, CLK_PLL1_DIV2, 0x0074), | 112 | DEF_GEN3_SD("sd0", R8A7795_CLK_SD0, CLK_PLL1_DIV2, 0x0074), |
106 | DEF_SD("sd1", R8A7795_CLK_SD1, CLK_PLL1_DIV2, 0x0078), | 113 | DEF_GEN3_SD("sd1", R8A7795_CLK_SD1, CLK_PLL1_DIV2, 0x0078), |
107 | DEF_SD("sd2", R8A7795_CLK_SD2, CLK_PLL1_DIV2, 0x0268), | 114 | DEF_GEN3_SD("sd2", R8A7795_CLK_SD2, CLK_PLL1_DIV2, 0x0268), |
108 | DEF_SD("sd3", R8A7795_CLK_SD3, CLK_PLL1_DIV2, 0x026c), | 115 | DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, CLK_PLL1_DIV2, 0x026c), |
109 | 116 | ||
110 | DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1), | 117 | DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1), |
111 | DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1), | 118 | DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1), |
@@ -113,6 +120,11 @@ static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { | |||
113 | DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014), | 120 | DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014), |
114 | DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250), | 121 | DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250), |
115 | DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244), | 122 | DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244), |
123 | |||
124 | DEF_DIV6_RO("osc", R8A7795_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8), | ||
125 | DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32), | ||
126 | |||
127 | DEF_BASE("r", R8A7795_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT), | ||
116 | }; | 128 | }; |
117 | 129 | ||
118 | static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { | 130 | static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { |
@@ -139,6 +151,7 @@ static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { | |||
139 | DEF_MOD("usb3-if0", 328, R8A7795_CLK_S3D1), | 151 | DEF_MOD("usb3-if0", 328, R8A7795_CLK_S3D1), |
140 | DEF_MOD("usb-dmac0", 330, R8A7795_CLK_S3D1), | 152 | DEF_MOD("usb-dmac0", 330, R8A7795_CLK_S3D1), |
141 | DEF_MOD("usb-dmac1", 331, R8A7795_CLK_S3D1), | 153 | DEF_MOD("usb-dmac1", 331, R8A7795_CLK_S3D1), |
154 | DEF_MOD("rwdt0", 402, R8A7795_CLK_R), | ||
142 | DEF_MOD("intc-ex", 407, R8A7795_CLK_CP), | 155 | DEF_MOD("intc-ex", 407, R8A7795_CLK_CP), |
143 | DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1), | 156 | DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1), |
144 | DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4), | 157 | DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4), |
@@ -148,6 +161,7 @@ static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { | |||
148 | DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1), | 161 | DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1), |
149 | DEF_MOD("hscif1", 519, R8A7795_CLK_S3D1), | 162 | DEF_MOD("hscif1", 519, R8A7795_CLK_S3D1), |
150 | DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1), | 163 | DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1), |
164 | DEF_MOD("pwm", 523, R8A7795_CLK_S3D4), | ||
151 | DEF_MOD("fcpvd3", 600, R8A7795_CLK_S2D1), | 165 | DEF_MOD("fcpvd3", 600, R8A7795_CLK_S2D1), |
152 | DEF_MOD("fcpvd2", 601, R8A7795_CLK_S2D1), | 166 | DEF_MOD("fcpvd2", 601, R8A7795_CLK_S2D1), |
153 | DEF_MOD("fcpvd1", 602, R8A7795_CLK_S2D1), | 167 | DEF_MOD("fcpvd1", 602, R8A7795_CLK_S2D1), |
@@ -578,6 +592,18 @@ struct clk * __init r8a7795_cpg_clk_register(struct device *dev, | |||
578 | case CLK_TYPE_GEN3_SD: | 592 | case CLK_TYPE_GEN3_SD: |
579 | return cpg_sd_clk_register(core, base, __clk_get_name(parent)); | 593 | return cpg_sd_clk_register(core, base, __clk_get_name(parent)); |
580 | 594 | ||
595 | case CLK_TYPE_GEN3_R: | ||
596 | /* RINT is default. Only if EXTALR is populated, we switch to it */ | ||
597 | value = readl(base + CPG_RCKCR) & 0x3f; | ||
598 | |||
599 | if (clk_get_rate(clks[CLK_EXTALR])) { | ||
600 | parent = clks[CLK_EXTALR]; | ||
601 | value |= BIT(15); | ||
602 | } | ||
603 | |||
604 | writel(value, base + CPG_RCKCR); | ||
605 | break; | ||
606 | |||
581 | default: | 607 | default: |
582 | return ERR_PTR(-EINVAL); | 608 | return ERR_PTR(-EINVAL); |
583 | } | 609 | } |
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 58e24b326a48..1f2dc3629f0e 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/clk-provider.h> | 17 | #include <linux/clk-provider.h> |
18 | #include <linux/clk/renesas.h> | ||
18 | #include <linux/device.h> | 19 | #include <linux/device.h> |
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/mod_devicetable.h> | 21 | #include <linux/mod_devicetable.h> |
@@ -253,7 +254,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, | |||
253 | { | 254 | { |
254 | struct clk *clk = NULL, *parent; | 255 | struct clk *clk = NULL, *parent; |
255 | struct device *dev = priv->dev; | 256 | struct device *dev = priv->dev; |
256 | unsigned int id = core->id; | 257 | unsigned int id = core->id, div = core->div; |
257 | const char *parent_name; | 258 | const char *parent_name; |
258 | 259 | ||
259 | WARN_DEBUG(id >= priv->num_core_clks); | 260 | WARN_DEBUG(id >= priv->num_core_clks); |
@@ -266,6 +267,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, | |||
266 | 267 | ||
267 | case CLK_TYPE_FF: | 268 | case CLK_TYPE_FF: |
268 | case CLK_TYPE_DIV6P1: | 269 | case CLK_TYPE_DIV6P1: |
270 | case CLK_TYPE_DIV6_RO: | ||
269 | WARN_DEBUG(core->parent >= priv->num_core_clks); | 271 | WARN_DEBUG(core->parent >= priv->num_core_clks); |
270 | parent = priv->clks[core->parent]; | 272 | parent = priv->clks[core->parent]; |
271 | if (IS_ERR(parent)) { | 273 | if (IS_ERR(parent)) { |
@@ -274,13 +276,18 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, | |||
274 | } | 276 | } |
275 | 277 | ||
276 | parent_name = __clk_get_name(parent); | 278 | parent_name = __clk_get_name(parent); |
277 | if (core->type == CLK_TYPE_FF) { | 279 | |
278 | clk = clk_register_fixed_factor(NULL, core->name, | 280 | if (core->type == CLK_TYPE_DIV6_RO) |
279 | parent_name, 0, | 281 | /* Multiply with the DIV6 register value */ |
280 | core->mult, core->div); | 282 | div *= (readl(priv->base + core->offset) & 0x3f) + 1; |
281 | } else { | 283 | |
284 | if (core->type == CLK_TYPE_DIV6P1) { | ||
282 | clk = cpg_div6_register(core->name, 1, &parent_name, | 285 | clk = cpg_div6_register(core->name, 1, &parent_name, |
283 | priv->base + core->offset); | 286 | priv->base + core->offset); |
287 | } else { | ||
288 | clk = clk_register_fixed_factor(NULL, core->name, | ||
289 | parent_name, 0, | ||
290 | core->mult, div); | ||
284 | } | 291 | } |
285 | break; | 292 | break; |
286 | 293 | ||
@@ -375,8 +382,6 @@ fail: | |||
375 | kfree(clock); | 382 | kfree(clock); |
376 | } | 383 | } |
377 | 384 | ||
378 | |||
379 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF | ||
380 | struct cpg_mssr_clk_domain { | 385 | struct cpg_mssr_clk_domain { |
381 | struct generic_pm_domain genpd; | 386 | struct generic_pm_domain genpd; |
382 | struct device_node *np; | 387 | struct device_node *np; |
@@ -384,6 +389,8 @@ struct cpg_mssr_clk_domain { | |||
384 | unsigned int core_pm_clks[0]; | 389 | unsigned int core_pm_clks[0]; |
385 | }; | 390 | }; |
386 | 391 | ||
392 | static struct cpg_mssr_clk_domain *cpg_mssr_clk_domain; | ||
393 | |||
387 | static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec, | 394 | static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec, |
388 | struct cpg_mssr_clk_domain *pd) | 395 | struct cpg_mssr_clk_domain *pd) |
389 | { | 396 | { |
@@ -407,17 +414,20 @@ static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec, | |||
407 | } | 414 | } |
408 | } | 415 | } |
409 | 416 | ||
410 | static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd, | 417 | int cpg_mssr_attach_dev(struct generic_pm_domain *unused, struct device *dev) |
411 | struct device *dev) | ||
412 | { | 418 | { |
413 | struct cpg_mssr_clk_domain *pd = | 419 | struct cpg_mssr_clk_domain *pd = cpg_mssr_clk_domain; |
414 | container_of(genpd, struct cpg_mssr_clk_domain, genpd); | ||
415 | struct device_node *np = dev->of_node; | 420 | struct device_node *np = dev->of_node; |
416 | struct of_phandle_args clkspec; | 421 | struct of_phandle_args clkspec; |
417 | struct clk *clk; | 422 | struct clk *clk; |
418 | int i = 0; | 423 | int i = 0; |
419 | int error; | 424 | int error; |
420 | 425 | ||
426 | if (!pd) { | ||
427 | dev_dbg(dev, "CPG/MSSR clock domain not yet available\n"); | ||
428 | return -EPROBE_DEFER; | ||
429 | } | ||
430 | |||
421 | while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, | 431 | while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, |
422 | &clkspec)) { | 432 | &clkspec)) { |
423 | if (cpg_mssr_is_pm_clk(&clkspec, pd)) | 433 | if (cpg_mssr_is_pm_clk(&clkspec, pd)) |
@@ -457,8 +467,7 @@ fail_put: | |||
457 | return error; | 467 | return error; |
458 | } | 468 | } |
459 | 469 | ||
460 | static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd, | 470 | void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev) |
461 | struct device *dev) | ||
462 | { | 471 | { |
463 | if (!list_empty(&dev->power.subsys_data->clock_list)) | 472 | if (!list_empty(&dev->power.subsys_data->clock_list)) |
464 | pm_clk_destroy(dev); | 473 | pm_clk_destroy(dev); |
@@ -487,19 +496,11 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev, | |||
487 | pm_genpd_init(genpd, &simple_qos_governor, false); | 496 | pm_genpd_init(genpd, &simple_qos_governor, false); |
488 | genpd->attach_dev = cpg_mssr_attach_dev; | 497 | genpd->attach_dev = cpg_mssr_attach_dev; |
489 | genpd->detach_dev = cpg_mssr_detach_dev; | 498 | genpd->detach_dev = cpg_mssr_detach_dev; |
499 | cpg_mssr_clk_domain = pd; | ||
490 | 500 | ||
491 | of_genpd_add_provider_simple(np, genpd); | 501 | of_genpd_add_provider_simple(np, genpd); |
492 | return 0; | 502 | return 0; |
493 | } | 503 | } |
494 | #else | ||
495 | static inline int cpg_mssr_add_clk_domain(struct device *dev, | ||
496 | const unsigned int *core_pm_clks, | ||
497 | unsigned int num_core_pm_clks) | ||
498 | { | ||
499 | return 0; | ||
500 | } | ||
501 | #endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */ | ||
502 | |||
503 | 504 | ||
504 | static const struct of_device_id cpg_mssr_match[] = { | 505 | static const struct of_device_id cpg_mssr_match[] = { |
505 | #ifdef CONFIG_ARCH_R8A7795 | 506 | #ifdef CONFIG_ARCH_R8A7795 |
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 952b6957233b..0d1e3e811e79 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h | |||
@@ -37,6 +37,7 @@ enum clk_types { | |||
37 | CLK_TYPE_IN, /* External Clock Input */ | 37 | CLK_TYPE_IN, /* External Clock Input */ |
38 | CLK_TYPE_FF, /* Fixed Factor Clock */ | 38 | CLK_TYPE_FF, /* Fixed Factor Clock */ |
39 | CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */ | 39 | CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */ |
40 | CLK_TYPE_DIV6_RO, /* DIV6 Clock read only with extra divisor */ | ||
40 | 41 | ||
41 | /* Custom definitions start here */ | 42 | /* Custom definitions start here */ |
42 | CLK_TYPE_CUSTOM, | 43 | CLK_TYPE_CUSTOM, |
@@ -53,9 +54,8 @@ enum clk_types { | |||
53 | DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult) | 54 | DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult) |
54 | #define DEF_DIV6P1(_name, _id, _parent, _offset) \ | 55 | #define DEF_DIV6P1(_name, _id, _parent, _offset) \ |
55 | DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset) | 56 | DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset) |
56 | #define DEF_SD(_name, _id, _parent, _offset) \ | 57 | #define DEF_DIV6_RO(_name, _id, _parent, _offset, _div) \ |
57 | DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset) | 58 | DEF_BASE(_name, _id, CLK_TYPE_DIV6_RO, _parent, .offset = _offset, .div = _div, .mult = 1) |
58 | |||
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Definitions of Module Clocks | 61 | * Definitions of Module Clocks |
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 637041fd53ad..3d0edee1f9fe 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c | |||
@@ -175,6 +175,19 @@ | |||
175 | #define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) | 175 | #define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) |
176 | #define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) | 176 | #define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) |
177 | 177 | ||
178 | #define SATA_PLL_CFG0 0x490 | ||
179 | #define SATA_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0) | ||
180 | #define SATA_PLL_CFG0_PADPLL_USE_LOCKDET BIT(2) | ||
181 | #define SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ BIT(13) | ||
182 | #define SATA_PLL_CFG0_SEQ_ENABLE BIT(24) | ||
183 | |||
184 | #define XUSBIO_PLL_CFG0 0x51c | ||
185 | #define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0) | ||
186 | #define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL BIT(2) | ||
187 | #define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET BIT(6) | ||
188 | #define XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ BIT(13) | ||
189 | #define XUSBIO_PLL_CFG0_SEQ_ENABLE BIT(24) | ||
190 | |||
178 | #define UTMIPLL_HW_PWRDN_CFG0 0x52c | 191 | #define UTMIPLL_HW_PWRDN_CFG0 0x52c |
179 | #define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK BIT(31) | 192 | #define UTMIPLL_HW_PWRDN_CFG0_UTMIPLL_LOCK BIT(31) |
180 | #define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) | 193 | #define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) |
@@ -416,6 +429,51 @@ static const char *mux_pllmcp_clkm[] = { | |||
416 | #define PLLU_MISC0_WRITE_MASK 0xbfffffff | 429 | #define PLLU_MISC0_WRITE_MASK 0xbfffffff |
417 | #define PLLU_MISC1_WRITE_MASK 0x00000007 | 430 | #define PLLU_MISC1_WRITE_MASK 0x00000007 |
418 | 431 | ||
432 | void tegra210_xusb_pll_hw_control_enable(void) | ||
433 | { | ||
434 | u32 val; | ||
435 | |||
436 | val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0); | ||
437 | val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL | | ||
438 | XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL); | ||
439 | val |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET | | ||
440 | XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ; | ||
441 | writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0); | ||
442 | } | ||
443 | EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_control_enable); | ||
444 | |||
445 | void tegra210_xusb_pll_hw_sequence_start(void) | ||
446 | { | ||
447 | u32 val; | ||
448 | |||
449 | val = readl_relaxed(clk_base + XUSBIO_PLL_CFG0); | ||
450 | val |= XUSBIO_PLL_CFG0_SEQ_ENABLE; | ||
451 | writel_relaxed(val, clk_base + XUSBIO_PLL_CFG0); | ||
452 | } | ||
453 | EXPORT_SYMBOL_GPL(tegra210_xusb_pll_hw_sequence_start); | ||
454 | |||
455 | void tegra210_sata_pll_hw_control_enable(void) | ||
456 | { | ||
457 | u32 val; | ||
458 | |||
459 | val = readl_relaxed(clk_base + SATA_PLL_CFG0); | ||
460 | val &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL; | ||
461 | val |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET | | ||
462 | SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ; | ||
463 | writel_relaxed(val, clk_base + SATA_PLL_CFG0); | ||
464 | } | ||
465 | EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_control_enable); | ||
466 | |||
467 | void tegra210_sata_pll_hw_sequence_start(void) | ||
468 | { | ||
469 | u32 val; | ||
470 | |||
471 | val = readl_relaxed(clk_base + SATA_PLL_CFG0); | ||
472 | val |= SATA_PLL_CFG0_SEQ_ENABLE; | ||
473 | writel_relaxed(val, clk_base + SATA_PLL_CFG0); | ||
474 | } | ||
475 | EXPORT_SYMBOL_GPL(tegra210_sata_pll_hw_sequence_start); | ||
476 | |||
419 | static inline void _pll_misc_chk_default(void __iomem *base, | 477 | static inline void _pll_misc_chk_default(void __iomem *base, |
420 | struct tegra_clk_pll_params *params, | 478 | struct tegra_clk_pll_params *params, |
421 | u8 misc_num, u32 default_val, u32 mask) | 479 | u8 misc_num, u32 default_val, u32 mask) |
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index fa4ea22ca12e..03e04582791c 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c | |||
@@ -91,7 +91,7 @@ static inline bool psci_has_ext_power_state(void) | |||
91 | PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK; | 91 | PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK; |
92 | } | 92 | } |
93 | 93 | ||
94 | bool psci_power_state_loses_context(u32 state) | 94 | static inline bool psci_power_state_loses_context(u32 state) |
95 | { | 95 | { |
96 | const u32 mask = psci_has_ext_power_state() ? | 96 | const u32 mask = psci_has_ext_power_state() ? |
97 | PSCI_1_0_EXT_POWER_STATE_TYPE_MASK : | 97 | PSCI_1_0_EXT_POWER_STATE_TYPE_MASK : |
@@ -100,7 +100,7 @@ bool psci_power_state_loses_context(u32 state) | |||
100 | return state & mask; | 100 | return state & mask; |
101 | } | 101 | } |
102 | 102 | ||
103 | bool psci_power_state_is_valid(u32 state) | 103 | static inline bool psci_power_state_is_valid(u32 state) |
104 | { | 104 | { |
105 | const u32 valid_mask = psci_has_ext_power_state() ? | 105 | const u32 valid_mask = psci_has_ext_power_state() ? |
106 | PSCI_1_0_EXT_POWER_STATE_MASK : | 106 | PSCI_1_0_EXT_POWER_STATE_MASK : |
@@ -563,7 +563,7 @@ out_put_node: | |||
563 | return err; | 563 | return err; |
564 | } | 564 | } |
565 | 565 | ||
566 | static const struct of_device_id const psci_of_match[] __initconst = { | 566 | static const struct of_device_id psci_of_match[] __initconst = { |
567 | { .compatible = "arm,psci", .data = psci_0_1_init}, | 567 | { .compatible = "arm,psci", .data = psci_0_1_init}, |
568 | { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, | 568 | { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, |
569 | { .compatible = "arm,psci-1.0", .data = psci_0_2_init}, | 569 | { .compatible = "arm,psci-1.0", .data = psci_0_2_init}, |
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 8a10f5b7d9dc..f52d6cb24ff5 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h | |||
@@ -121,7 +121,7 @@ struct tegra_dc { | |||
121 | spinlock_t lock; | 121 | spinlock_t lock; |
122 | 122 | ||
123 | struct drm_crtc base; | 123 | struct drm_crtc base; |
124 | int powergate; | 124 | unsigned int powergate; |
125 | int pipe; | 125 | int pipe; |
126 | 126 | ||
127 | struct clk *clk; | 127 | struct clk *clk; |
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 51d5cd20c26a..c61a284133e0 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig | |||
@@ -122,6 +122,7 @@ config MTK_SMI | |||
122 | mainly help enable/disable iommu and control the power domain and | 122 | mainly help enable/disable iommu and control the power domain and |
123 | clocks for each local arbiter. | 123 | clocks for each local arbiter. |
124 | 124 | ||
125 | source "drivers/memory/samsung/Kconfig" | ||
125 | source "drivers/memory/tegra/Kconfig" | 126 | source "drivers/memory/tegra/Kconfig" |
126 | 127 | ||
127 | endif | 128 | endif |
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 890bdf402449..cb0b7a1df11a 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile | |||
@@ -17,4 +17,5 @@ obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o | |||
17 | obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o | 17 | obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o |
18 | obj-$(CONFIG_MTK_SMI) += mtk-smi.o | 18 | obj-$(CONFIG_MTK_SMI) += mtk-smi.o |
19 | 19 | ||
20 | obj-$(CONFIG_SAMSUNG_MC) += samsung/ | ||
20 | obj-$(CONFIG_TEGRA_MC) += tegra/ | 21 | obj-$(CONFIG_TEGRA_MC) += tegra/ |
diff --git a/drivers/memory/samsung/Kconfig b/drivers/memory/samsung/Kconfig new file mode 100644 index 000000000000..9de12222061c --- /dev/null +++ b/drivers/memory/samsung/Kconfig | |||
@@ -0,0 +1,13 @@ | |||
1 | config SAMSUNG_MC | ||
2 | bool "Samsung Exynos Memory Controller support" if COMPILE_TEST | ||
3 | help | ||
4 | Support for the Memory Controller (MC) devices found on | ||
5 | Samsung Exynos SoCs. | ||
6 | |||
7 | if SAMSUNG_MC | ||
8 | |||
9 | config EXYNOS_SROM | ||
10 | bool "Exynos SROM controller driver" if COMPILE_TEST | ||
11 | depends on (ARM && ARCH_EXYNOS) || (COMPILE_TEST && HAS_IOMEM) | ||
12 | |||
13 | endif | ||
diff --git a/drivers/memory/samsung/Makefile b/drivers/memory/samsung/Makefile new file mode 100644 index 000000000000..9c554d5522ad --- /dev/null +++ b/drivers/memory/samsung/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_EXYNOS_SROM) += exynos-srom.o | |||
diff --git a/drivers/memory/samsung/exynos-srom.c b/drivers/memory/samsung/exynos-srom.c new file mode 100644 index 000000000000..96756fb4d6bd --- /dev/null +++ b/drivers/memory/samsung/exynos-srom.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 Samsung Electronics Co., Ltd. | ||
3 | * http://www.samsung.com/ | ||
4 | * | ||
5 | * EXYNOS - SROM Controller support | ||
6 | * Author: Pankaj Dubey <pankaj.dubey@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/io.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include "exynos-srom.h" | ||
22 | |||
23 | static const unsigned long exynos_srom_offsets[] = { | ||
24 | /* SROM side */ | ||
25 | EXYNOS_SROM_BW, | ||
26 | EXYNOS_SROM_BC0, | ||
27 | EXYNOS_SROM_BC1, | ||
28 | EXYNOS_SROM_BC2, | ||
29 | EXYNOS_SROM_BC3, | ||
30 | }; | ||
31 | |||
32 | /** | ||
33 | * struct exynos_srom_reg_dump: register dump of SROM Controller registers. | ||
34 | * @offset: srom register offset from the controller base address. | ||
35 | * @value: the value of register under the offset. | ||
36 | */ | ||
37 | struct exynos_srom_reg_dump { | ||
38 | u32 offset; | ||
39 | u32 value; | ||
40 | }; | ||
41 | |||
42 | /** | ||
43 | * struct exynos_srom: platform data for exynos srom controller driver. | ||
44 | * @dev: platform device pointer | ||
45 | * @reg_base: srom base address | ||
46 | * @reg_offset: exynos_srom_reg_dump pointer to hold offset and its value. | ||
47 | */ | ||
48 | struct exynos_srom { | ||
49 | struct device *dev; | ||
50 | void __iomem *reg_base; | ||
51 | struct exynos_srom_reg_dump *reg_offset; | ||
52 | }; | ||
53 | |||
54 | static struct exynos_srom_reg_dump *exynos_srom_alloc_reg_dump( | ||
55 | const unsigned long *rdump, | ||
56 | unsigned long nr_rdump) | ||
57 | { | ||
58 | struct exynos_srom_reg_dump *rd; | ||
59 | unsigned int i; | ||
60 | |||
61 | rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL); | ||
62 | if (!rd) | ||
63 | return NULL; | ||
64 | |||
65 | for (i = 0; i < nr_rdump; ++i) | ||
66 | rd[i].offset = rdump[i]; | ||
67 | |||
68 | return rd; | ||
69 | } | ||
70 | |||
71 | static int exynos_srom_configure_bank(struct exynos_srom *srom, | ||
72 | struct device_node *np) | ||
73 | { | ||
74 | u32 bank, width, pmc = 0; | ||
75 | u32 timing[6]; | ||
76 | u32 cs, bw; | ||
77 | |||
78 | if (of_property_read_u32(np, "reg", &bank)) | ||
79 | return -EINVAL; | ||
80 | if (of_property_read_u32(np, "reg-io-width", &width)) | ||
81 | width = 1; | ||
82 | if (of_property_read_bool(np, "samsung,srom-page-mode")) | ||
83 | pmc = 1 << EXYNOS_SROM_BCX__PMC__SHIFT; | ||
84 | if (of_property_read_u32_array(np, "samsung,srom-timing", timing, | ||
85 | ARRAY_SIZE(timing))) | ||
86 | return -EINVAL; | ||
87 | |||
88 | bank *= 4; /* Convert bank into shift/offset */ | ||
89 | |||
90 | cs = 1 << EXYNOS_SROM_BW__BYTEENABLE__SHIFT; | ||
91 | if (width == 2) | ||
92 | cs |= 1 << EXYNOS_SROM_BW__DATAWIDTH__SHIFT; | ||
93 | |||
94 | bw = __raw_readl(srom->reg_base + EXYNOS_SROM_BW); | ||
95 | bw = (bw & ~(EXYNOS_SROM_BW__CS_MASK << bank)) | (cs << bank); | ||
96 | __raw_writel(bw, srom->reg_base + EXYNOS_SROM_BW); | ||
97 | |||
98 | __raw_writel(pmc | (timing[0] << EXYNOS_SROM_BCX__TACP__SHIFT) | | ||
99 | (timing[1] << EXYNOS_SROM_BCX__TCAH__SHIFT) | | ||
100 | (timing[2] << EXYNOS_SROM_BCX__TCOH__SHIFT) | | ||
101 | (timing[3] << EXYNOS_SROM_BCX__TACC__SHIFT) | | ||
102 | (timing[4] << EXYNOS_SROM_BCX__TCOS__SHIFT) | | ||
103 | (timing[5] << EXYNOS_SROM_BCX__TACS__SHIFT), | ||
104 | srom->reg_base + EXYNOS_SROM_BC0 + bank); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int exynos_srom_probe(struct platform_device *pdev) | ||
110 | { | ||
111 | struct device_node *np, *child; | ||
112 | struct exynos_srom *srom; | ||
113 | struct device *dev = &pdev->dev; | ||
114 | bool bad_bank_config = false; | ||
115 | |||
116 | np = dev->of_node; | ||
117 | if (!np) { | ||
118 | dev_err(&pdev->dev, "could not find device info\n"); | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | |||
122 | srom = devm_kzalloc(&pdev->dev, | ||
123 | sizeof(struct exynos_srom), GFP_KERNEL); | ||
124 | if (!srom) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | srom->dev = dev; | ||
128 | srom->reg_base = of_iomap(np, 0); | ||
129 | if (!srom->reg_base) { | ||
130 | dev_err(&pdev->dev, "iomap of exynos srom controller failed\n"); | ||
131 | return -ENOMEM; | ||
132 | } | ||
133 | |||
134 | platform_set_drvdata(pdev, srom); | ||
135 | |||
136 | srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets, | ||
137 | sizeof(exynos_srom_offsets)); | ||
138 | if (!srom->reg_offset) { | ||
139 | iounmap(srom->reg_base); | ||
140 | return -ENOMEM; | ||
141 | } | ||
142 | |||
143 | for_each_child_of_node(np, child) { | ||
144 | if (exynos_srom_configure_bank(srom, child)) { | ||
145 | dev_err(dev, | ||
146 | "Could not decode bank configuration for %s\n", | ||
147 | child->name); | ||
148 | bad_bank_config = true; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * If any bank failed to configure, we still provide suspend/resume, | ||
154 | * but do not probe child devices | ||
155 | */ | ||
156 | if (bad_bank_config) | ||
157 | return 0; | ||
158 | |||
159 | return of_platform_populate(np, NULL, NULL, dev); | ||
160 | } | ||
161 | |||
162 | static int exynos_srom_remove(struct platform_device *pdev) | ||
163 | { | ||
164 | struct exynos_srom *srom = platform_get_drvdata(pdev); | ||
165 | |||
166 | kfree(srom->reg_offset); | ||
167 | iounmap(srom->reg_base); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | #ifdef CONFIG_PM_SLEEP | ||
173 | static void exynos_srom_save(void __iomem *base, | ||
174 | struct exynos_srom_reg_dump *rd, | ||
175 | unsigned int num_regs) | ||
176 | { | ||
177 | for (; num_regs > 0; --num_regs, ++rd) | ||
178 | rd->value = readl(base + rd->offset); | ||
179 | } | ||
180 | |||
181 | static void exynos_srom_restore(void __iomem *base, | ||
182 | const struct exynos_srom_reg_dump *rd, | ||
183 | unsigned int num_regs) | ||
184 | { | ||
185 | for (; num_regs > 0; --num_regs, ++rd) | ||
186 | writel(rd->value, base + rd->offset); | ||
187 | } | ||
188 | |||
189 | static int exynos_srom_suspend(struct device *dev) | ||
190 | { | ||
191 | struct exynos_srom *srom = dev_get_drvdata(dev); | ||
192 | |||
193 | exynos_srom_save(srom->reg_base, srom->reg_offset, | ||
194 | ARRAY_SIZE(exynos_srom_offsets)); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int exynos_srom_resume(struct device *dev) | ||
199 | { | ||
200 | struct exynos_srom *srom = dev_get_drvdata(dev); | ||
201 | |||
202 | exynos_srom_restore(srom->reg_base, srom->reg_offset, | ||
203 | ARRAY_SIZE(exynos_srom_offsets)); | ||
204 | return 0; | ||
205 | } | ||
206 | #endif | ||
207 | |||
208 | static const struct of_device_id of_exynos_srom_ids[] = { | ||
209 | { | ||
210 | .compatible = "samsung,exynos4210-srom", | ||
211 | }, | ||
212 | {}, | ||
213 | }; | ||
214 | MODULE_DEVICE_TABLE(of, of_exynos_srom_ids); | ||
215 | |||
216 | static SIMPLE_DEV_PM_OPS(exynos_srom_pm_ops, exynos_srom_suspend, exynos_srom_resume); | ||
217 | |||
218 | static struct platform_driver exynos_srom_driver = { | ||
219 | .probe = exynos_srom_probe, | ||
220 | .remove = exynos_srom_remove, | ||
221 | .driver = { | ||
222 | .name = "exynos-srom", | ||
223 | .of_match_table = of_exynos_srom_ids, | ||
224 | .pm = &exynos_srom_pm_ops, | ||
225 | }, | ||
226 | }; | ||
227 | module_platform_driver(exynos_srom_driver); | ||
228 | |||
229 | MODULE_AUTHOR("Pankaj Dubey <pankaj.dubey@samsung.com>"); | ||
230 | MODULE_DESCRIPTION("Exynos SROM Controller Driver"); | ||
231 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/memory/samsung/exynos-srom.h b/drivers/memory/samsung/exynos-srom.h new file mode 100644 index 000000000000..34660c6a57a9 --- /dev/null +++ b/drivers/memory/samsung/exynos-srom.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 Samsung Electronics Co., Ltd. | ||
3 | * http://www.samsung.com | ||
4 | * | ||
5 | * Exynos SROMC register definitions | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __EXYNOS_SROM_H | ||
13 | #define __EXYNOS_SROM_H __FILE__ | ||
14 | |||
15 | #define EXYNOS_SROMREG(x) (x) | ||
16 | |||
17 | #define EXYNOS_SROM_BW EXYNOS_SROMREG(0x0) | ||
18 | #define EXYNOS_SROM_BC0 EXYNOS_SROMREG(0x4) | ||
19 | #define EXYNOS_SROM_BC1 EXYNOS_SROMREG(0x8) | ||
20 | #define EXYNOS_SROM_BC2 EXYNOS_SROMREG(0xc) | ||
21 | #define EXYNOS_SROM_BC3 EXYNOS_SROMREG(0x10) | ||
22 | #define EXYNOS_SROM_BC4 EXYNOS_SROMREG(0x14) | ||
23 | #define EXYNOS_SROM_BC5 EXYNOS_SROMREG(0x18) | ||
24 | |||
25 | /* one register BW holds 4 x 4-bit packed settings for NCS0 - NCS3 */ | ||
26 | |||
27 | #define EXYNOS_SROM_BW__DATAWIDTH__SHIFT 0 | ||
28 | #define EXYNOS_SROM_BW__ADDRMODE__SHIFT 1 | ||
29 | #define EXYNOS_SROM_BW__WAITENABLE__SHIFT 2 | ||
30 | #define EXYNOS_SROM_BW__BYTEENABLE__SHIFT 3 | ||
31 | |||
32 | #define EXYNOS_SROM_BW__CS_MASK 0xf | ||
33 | |||
34 | #define EXYNOS_SROM_BW__NCS0__SHIFT 0 | ||
35 | #define EXYNOS_SROM_BW__NCS1__SHIFT 4 | ||
36 | #define EXYNOS_SROM_BW__NCS2__SHIFT 8 | ||
37 | #define EXYNOS_SROM_BW__NCS3__SHIFT 12 | ||
38 | #define EXYNOS_SROM_BW__NCS4__SHIFT 16 | ||
39 | #define EXYNOS_SROM_BW__NCS5__SHIFT 20 | ||
40 | |||
41 | /* applies to same to BCS0 - BCS3 */ | ||
42 | |||
43 | #define EXYNOS_SROM_BCX__PMC__SHIFT 0 | ||
44 | #define EXYNOS_SROM_BCX__TACP__SHIFT 4 | ||
45 | #define EXYNOS_SROM_BCX__TCAH__SHIFT 8 | ||
46 | #define EXYNOS_SROM_BCX__TCOH__SHIFT 12 | ||
47 | #define EXYNOS_SROM_BCX__TACC__SHIFT 16 | ||
48 | #define EXYNOS_SROM_BCX__TCOS__SHIFT 24 | ||
49 | #define EXYNOS_SROM_BCX__TACS__SHIFT 28 | ||
50 | |||
51 | #endif /* __EXYNOS_SROM_H */ | ||
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 7c95a656f9e4..392f9eff5fb7 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -74,6 +74,16 @@ config MTD_PHYSMAP_OF | |||
74 | physically into the CPU's memory. The mapping description here is | 74 | physically into the CPU's memory. The mapping description here is |
75 | taken from OF device tree. | 75 | taken from OF device tree. |
76 | 76 | ||
77 | config MTD_PHYSMAP_OF_VERSATILE | ||
78 | bool "Support ARM Versatile physmap OF" | ||
79 | depends on MTD_PHYSMAP_OF | ||
80 | depends on MFD_SYSCON | ||
81 | default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || REALVIEW_DT) | ||
82 | help | ||
83 | This provides some extra DT physmap parsing for the ARM Versatile | ||
84 | platforms, basically to add a VPP (write protection) callback so | ||
85 | the flash can be taken out of write protection. | ||
86 | |||
77 | config MTD_PMC_MSP_EVM | 87 | config MTD_PMC_MSP_EVM |
78 | tristate "CFI Flash device mapped on PMC-Sierra MSP" | 88 | tristate "CFI Flash device mapped on PMC-Sierra MSP" |
79 | depends on PMC_MSP && MTD_CFI | 89 | depends on PMC_MSP && MTD_CFI |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 141c91a5b24c..644f7d36d35d 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
@@ -18,6 +18,9 @@ obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o | |||
18 | obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o | 18 | obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o |
19 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o | 19 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o |
20 | obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o | 20 | obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o |
21 | ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE | ||
22 | obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of_versatile.o | ||
23 | endif | ||
21 | obj-$(CONFIG_MTD_PISMO) += pismo.o | 24 | obj-$(CONFIG_MTD_PISMO) += pismo.o |
22 | obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o | 25 | obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o |
23 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o | 26 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o |
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 70c453144f00..22f3858c0364 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/of_address.h> | 24 | #include <linux/of_address.h> |
25 | #include <linux/of_platform.h> | 25 | #include <linux/of_platform.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include "physmap_of_versatile.h" | ||
27 | 28 | ||
28 | struct of_flash_list { | 29 | struct of_flash_list { |
29 | struct mtd_info *mtd; | 30 | struct mtd_info *mtd; |
@@ -240,6 +241,11 @@ static int of_flash_probe(struct platform_device *dev) | |||
240 | info->list[i].map.size = res_size; | 241 | info->list[i].map.size = res_size; |
241 | info->list[i].map.bankwidth = be32_to_cpup(width); | 242 | info->list[i].map.bankwidth = be32_to_cpup(width); |
242 | info->list[i].map.device_node = dp; | 243 | info->list[i].map.device_node = dp; |
244 | err = of_flash_probe_versatile(dev, dp, &info->list[i].map); | ||
245 | if (err) { | ||
246 | dev_err(&dev->dev, "Can't probe Versatile VPP\n"); | ||
247 | return err; | ||
248 | } | ||
243 | 249 | ||
244 | err = -ENOMEM; | 250 | err = -ENOMEM; |
245 | info->list[i].map.virt = ioremap(info->list[i].map.phys, | 251 | info->list[i].map.virt = ioremap(info->list[i].map.phys, |
diff --git a/drivers/mtd/maps/physmap_of_versatile.c b/drivers/mtd/maps/physmap_of_versatile.c new file mode 100644 index 000000000000..0f39b2a015f4 --- /dev/null +++ b/drivers/mtd/maps/physmap_of_versatile.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * Versatile OF physmap driver add-on | ||
3 | * | ||
4 | * Copyright (c) 2016, Linaro Limited | ||
5 | * Author: Linus Walleij <linus.walleij@linaro.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation; either version 2 of | ||
10 | * the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
20 | * MA 02111-1307 USA | ||
21 | */ | ||
22 | #include <linux/export.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/of_address.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/mtd/map.h> | ||
28 | #include <linux/mfd/syscon.h> | ||
29 | #include <linux/regmap.h> | ||
30 | #include <linux/bitops.h> | ||
31 | #include "physmap_of_versatile.h" | ||
32 | |||
33 | static struct regmap *syscon_regmap; | ||
34 | |||
35 | enum versatile_flashprot { | ||
36 | INTEGRATOR_AP_FLASHPROT, | ||
37 | INTEGRATOR_CP_FLASHPROT, | ||
38 | VERSATILE_FLASHPROT, | ||
39 | REALVIEW_FLASHPROT, | ||
40 | }; | ||
41 | |||
42 | static const struct of_device_id syscon_match[] = { | ||
43 | { | ||
44 | .compatible = "arm,integrator-ap-syscon", | ||
45 | .data = (void *)INTEGRATOR_AP_FLASHPROT, | ||
46 | }, | ||
47 | { | ||
48 | .compatible = "arm,integrator-cp-syscon", | ||
49 | .data = (void *)INTEGRATOR_CP_FLASHPROT, | ||
50 | }, | ||
51 | { | ||
52 | .compatible = "arm,core-module-versatile", | ||
53 | .data = (void *)VERSATILE_FLASHPROT, | ||
54 | }, | ||
55 | { | ||
56 | .compatible = "arm,realview-eb-syscon", | ||
57 | .data = (void *)REALVIEW_FLASHPROT, | ||
58 | }, | ||
59 | { | ||
60 | .compatible = "arm,realview-pb1176-syscon", | ||
61 | .data = (void *)REALVIEW_FLASHPROT, | ||
62 | }, | ||
63 | { | ||
64 | .compatible = "arm,realview-pb11mp-syscon", | ||
65 | .data = (void *)REALVIEW_FLASHPROT, | ||
66 | }, | ||
67 | { | ||
68 | .compatible = "arm,realview-pba8-syscon", | ||
69 | .data = (void *)REALVIEW_FLASHPROT, | ||
70 | }, | ||
71 | { | ||
72 | .compatible = "arm,realview-pbx-syscon", | ||
73 | .data = (void *)REALVIEW_FLASHPROT, | ||
74 | }, | ||
75 | {}, | ||
76 | }; | ||
77 | |||
78 | /* | ||
79 | * Flash protection handling for the Integrator/AP | ||
80 | */ | ||
81 | #define INTEGRATOR_SC_CTRLS_OFFSET 0x08 | ||
82 | #define INTEGRATOR_SC_CTRLC_OFFSET 0x0C | ||
83 | #define INTEGRATOR_SC_CTRL_FLVPPEN BIT(1) | ||
84 | #define INTEGRATOR_SC_CTRL_FLWP BIT(2) | ||
85 | |||
86 | #define INTEGRATOR_EBI_CSR1_OFFSET 0x04 | ||
87 | /* The manual says bit 2, the code says bit 3, trust the code */ | ||
88 | #define INTEGRATOR_EBI_WRITE_ENABLE BIT(3) | ||
89 | #define INTEGRATOR_EBI_LOCK_OFFSET 0x20 | ||
90 | #define INTEGRATOR_EBI_LOCK_VAL 0xA05F | ||
91 | |||
92 | static const struct of_device_id ebi_match[] = { | ||
93 | { .compatible = "arm,external-bus-interface"}, | ||
94 | { }, | ||
95 | }; | ||
96 | |||
97 | static int ap_flash_init(struct platform_device *pdev) | ||
98 | { | ||
99 | struct device_node *ebi; | ||
100 | static void __iomem *ebi_base; | ||
101 | u32 val; | ||
102 | int ret; | ||
103 | |||
104 | /* Look up the EBI */ | ||
105 | ebi = of_find_matching_node(NULL, ebi_match); | ||
106 | if (!ebi) { | ||
107 | return -ENODEV; | ||
108 | } | ||
109 | ebi_base = of_iomap(ebi, 0); | ||
110 | if (!ebi_base) | ||
111 | return -ENODEV; | ||
112 | |||
113 | /* Clear VPP and write protection bits */ | ||
114 | ret = regmap_write(syscon_regmap, | ||
115 | INTEGRATOR_SC_CTRLC_OFFSET, | ||
116 | INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP); | ||
117 | if (ret) | ||
118 | dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n"); | ||
119 | |||
120 | /* Unlock the EBI */ | ||
121 | writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); | ||
122 | |||
123 | /* Enable write cycles on the EBI, CSR1 (flash) */ | ||
124 | val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); | ||
125 | val |= INTEGRATOR_EBI_WRITE_ENABLE; | ||
126 | writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); | ||
127 | |||
128 | /* Lock the EBI again */ | ||
129 | writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); | ||
130 | iounmap(ebi_base); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static void ap_flash_set_vpp(struct map_info *map, int on) | ||
136 | { | ||
137 | int ret; | ||
138 | |||
139 | if (on) { | ||
140 | ret = regmap_write(syscon_regmap, | ||
141 | INTEGRATOR_SC_CTRLS_OFFSET, | ||
142 | INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP); | ||
143 | if (ret) | ||
144 | pr_err("error enabling AP VPP\n"); | ||
145 | } else { | ||
146 | ret = regmap_write(syscon_regmap, | ||
147 | INTEGRATOR_SC_CTRLC_OFFSET, | ||
148 | INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP); | ||
149 | if (ret) | ||
150 | pr_err("error disabling AP VPP\n"); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Flash protection handling for the Integrator/CP | ||
156 | */ | ||
157 | |||
158 | #define INTCP_FLASHPROG_OFFSET 0x04 | ||
159 | #define CINTEGRATOR_FLVPPEN BIT(0) | ||
160 | #define CINTEGRATOR_FLWREN BIT(1) | ||
161 | #define CINTEGRATOR_FLMASK BIT(0)|BIT(1) | ||
162 | |||
163 | static void cp_flash_set_vpp(struct map_info *map, int on) | ||
164 | { | ||
165 | int ret; | ||
166 | |||
167 | if (on) { | ||
168 | ret = regmap_update_bits(syscon_regmap, | ||
169 | INTCP_FLASHPROG_OFFSET, | ||
170 | CINTEGRATOR_FLMASK, | ||
171 | CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN); | ||
172 | if (ret) | ||
173 | pr_err("error setting CP VPP\n"); | ||
174 | } else { | ||
175 | ret = regmap_update_bits(syscon_regmap, | ||
176 | INTCP_FLASHPROG_OFFSET, | ||
177 | CINTEGRATOR_FLMASK, | ||
178 | 0); | ||
179 | if (ret) | ||
180 | pr_err("error setting CP VPP\n"); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Flash protection handling for the Versatiles and RealViews | ||
186 | */ | ||
187 | |||
188 | #define VERSATILE_SYS_FLASH_OFFSET 0x4C | ||
189 | |||
190 | static void versatile_flash_set_vpp(struct map_info *map, int on) | ||
191 | { | ||
192 | int ret; | ||
193 | |||
194 | ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET, | ||
195 | 0x01, !!on); | ||
196 | if (ret) | ||
197 | pr_err("error setting Versatile VPP\n"); | ||
198 | } | ||
199 | |||
200 | int of_flash_probe_versatile(struct platform_device *pdev, | ||
201 | struct device_node *np, | ||
202 | struct map_info *map) | ||
203 | { | ||
204 | struct device_node *sysnp; | ||
205 | const struct of_device_id *devid; | ||
206 | struct regmap *rmap; | ||
207 | static enum versatile_flashprot versatile_flashprot; | ||
208 | int ret; | ||
209 | |||
210 | /* Not all flash chips use this protection line */ | ||
211 | if (!of_device_is_compatible(np, "arm,versatile-flash")) | ||
212 | return 0; | ||
213 | |||
214 | /* For first chip probed, look up the syscon regmap */ | ||
215 | if (!syscon_regmap) { | ||
216 | sysnp = of_find_matching_node_and_match(NULL, | ||
217 | syscon_match, | ||
218 | &devid); | ||
219 | if (!sysnp) | ||
220 | return -ENODEV; | ||
221 | |||
222 | versatile_flashprot = (enum versatile_flashprot)devid->data; | ||
223 | rmap = syscon_node_to_regmap(sysnp); | ||
224 | if (IS_ERR(rmap)) | ||
225 | return PTR_ERR(rmap); | ||
226 | |||
227 | syscon_regmap = rmap; | ||
228 | } | ||
229 | |||
230 | switch (versatile_flashprot) { | ||
231 | case INTEGRATOR_AP_FLASHPROT: | ||
232 | ret = ap_flash_init(pdev); | ||
233 | if (ret) | ||
234 | return ret; | ||
235 | map->set_vpp = ap_flash_set_vpp; | ||
236 | dev_info(&pdev->dev, "Integrator/AP flash protection\n"); | ||
237 | break; | ||
238 | case INTEGRATOR_CP_FLASHPROT: | ||
239 | map->set_vpp = cp_flash_set_vpp; | ||
240 | dev_info(&pdev->dev, "Integrator/CP flash protection\n"); | ||
241 | break; | ||
242 | case VERSATILE_FLASHPROT: | ||
243 | case REALVIEW_FLASHPROT: | ||
244 | map->set_vpp = versatile_flash_set_vpp; | ||
245 | dev_info(&pdev->dev, "versatile/realview flash protection\n"); | ||
246 | break; | ||
247 | default: | ||
248 | dev_info(&pdev->dev, "device marked as Versatile flash " | ||
249 | "but no system controller was found\n"); | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | EXPORT_SYMBOL_GPL(of_flash_probe_versatile); | ||
diff --git a/drivers/mtd/maps/physmap_of_versatile.h b/drivers/mtd/maps/physmap_of_versatile.h new file mode 100644 index 000000000000..5b86f6dc6b3d --- /dev/null +++ b/drivers/mtd/maps/physmap_of_versatile.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #include <linux/of.h> | ||
2 | #include <linux/mtd/map.h> | ||
3 | |||
4 | #ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE | ||
5 | int of_flash_probe_versatile(struct platform_device *pdev, | ||
6 | struct device_node *np, | ||
7 | struct map_info *map); | ||
8 | #else | ||
9 | static inline | ||
10 | int of_flash_probe_versatile(struct platform_device *pdev, | ||
11 | struct device_node *np, | ||
12 | struct map_info *map) | ||
13 | { | ||
14 | return 0; | ||
15 | } | ||
16 | #endif | ||
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 68d1f41b3cbf..c388468c202a 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -295,6 +295,7 @@ struct tegra_pcie { | |||
295 | struct reset_control *afi_rst; | 295 | struct reset_control *afi_rst; |
296 | struct reset_control *pcie_xrst; | 296 | struct reset_control *pcie_xrst; |
297 | 297 | ||
298 | bool legacy_phy; | ||
298 | struct phy *phy; | 299 | struct phy *phy; |
299 | 300 | ||
300 | struct tegra_msi msi; | 301 | struct tegra_msi msi; |
@@ -311,11 +312,14 @@ struct tegra_pcie { | |||
311 | 312 | ||
312 | struct tegra_pcie_port { | 313 | struct tegra_pcie_port { |
313 | struct tegra_pcie *pcie; | 314 | struct tegra_pcie *pcie; |
315 | struct device_node *np; | ||
314 | struct list_head list; | 316 | struct list_head list; |
315 | struct resource regs; | 317 | struct resource regs; |
316 | void __iomem *base; | 318 | void __iomem *base; |
317 | unsigned int index; | 319 | unsigned int index; |
318 | unsigned int lanes; | 320 | unsigned int lanes; |
321 | |||
322 | struct phy **phys; | ||
319 | }; | 323 | }; |
320 | 324 | ||
321 | struct tegra_pcie_bus { | 325 | struct tegra_pcie_bus { |
@@ -860,6 +864,128 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) | |||
860 | return 0; | 864 | return 0; |
861 | } | 865 | } |
862 | 866 | ||
867 | static int tegra_pcie_phy_disable(struct tegra_pcie *pcie) | ||
868 | { | ||
869 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | ||
870 | u32 value; | ||
871 | |||
872 | /* disable TX/RX data */ | ||
873 | value = pads_readl(pcie, PADS_CTL); | ||
874 | value &= ~(PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L); | ||
875 | pads_writel(pcie, value, PADS_CTL); | ||
876 | |||
877 | /* override IDDQ */ | ||
878 | value = pads_readl(pcie, PADS_CTL); | ||
879 | value |= PADS_CTL_IDDQ_1L; | ||
880 | pads_writel(pcie, PADS_CTL, value); | ||
881 | |||
882 | /* reset PLL */ | ||
883 | value = pads_readl(pcie, soc->pads_pll_ctl); | ||
884 | value &= ~PADS_PLL_CTL_RST_B4SM; | ||
885 | pads_writel(pcie, value, soc->pads_pll_ctl); | ||
886 | |||
887 | usleep_range(20, 100); | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static int tegra_pcie_port_phy_power_on(struct tegra_pcie_port *port) | ||
893 | { | ||
894 | struct device *dev = port->pcie->dev; | ||
895 | unsigned int i; | ||
896 | int err; | ||
897 | |||
898 | for (i = 0; i < port->lanes; i++) { | ||
899 | err = phy_power_on(port->phys[i]); | ||
900 | if (err < 0) { | ||
901 | dev_err(dev, "failed to power on PHY#%u: %d\n", i, | ||
902 | err); | ||
903 | return err; | ||
904 | } | ||
905 | } | ||
906 | |||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port) | ||
911 | { | ||
912 | struct device *dev = port->pcie->dev; | ||
913 | unsigned int i; | ||
914 | int err; | ||
915 | |||
916 | for (i = 0; i < port->lanes; i++) { | ||
917 | err = phy_power_off(port->phys[i]); | ||
918 | if (err < 0) { | ||
919 | dev_err(dev, "failed to power off PHY#%u: %d\n", i, | ||
920 | err); | ||
921 | return err; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie) | ||
929 | { | ||
930 | struct tegra_pcie_port *port; | ||
931 | int err; | ||
932 | |||
933 | if (pcie->legacy_phy) { | ||
934 | if (pcie->phy) | ||
935 | err = phy_power_on(pcie->phy); | ||
936 | else | ||
937 | err = tegra_pcie_phy_enable(pcie); | ||
938 | |||
939 | if (err < 0) | ||
940 | dev_err(pcie->dev, "failed to power on PHY: %d\n", err); | ||
941 | |||
942 | return err; | ||
943 | } | ||
944 | |||
945 | list_for_each_entry(port, &pcie->ports, list) { | ||
946 | err = tegra_pcie_port_phy_power_on(port); | ||
947 | if (err < 0) { | ||
948 | dev_err(pcie->dev, | ||
949 | "failed to power on PCIe port %u PHY: %d\n", | ||
950 | port->index, err); | ||
951 | return err; | ||
952 | } | ||
953 | } | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie) | ||
959 | { | ||
960 | struct tegra_pcie_port *port; | ||
961 | int err; | ||
962 | |||
963 | if (pcie->legacy_phy) { | ||
964 | if (pcie->phy) | ||
965 | err = phy_power_off(pcie->phy); | ||
966 | else | ||
967 | err = tegra_pcie_phy_disable(pcie); | ||
968 | |||
969 | if (err < 0) | ||
970 | dev_err(pcie->dev, "failed to power off PHY: %d\n", | ||
971 | err); | ||
972 | |||
973 | return err; | ||
974 | } | ||
975 | |||
976 | list_for_each_entry(port, &pcie->ports, list) { | ||
977 | err = tegra_pcie_port_phy_power_off(port); | ||
978 | if (err < 0) { | ||
979 | dev_err(pcie->dev, | ||
980 | "failed to power off PCIe port %u PHY: %d\n", | ||
981 | port->index, err); | ||
982 | return err; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
863 | static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) | 989 | static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) |
864 | { | 990 | { |
865 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | 991 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; |
@@ -899,13 +1025,9 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) | |||
899 | afi_writel(pcie, value, AFI_FUSE); | 1025 | afi_writel(pcie, value, AFI_FUSE); |
900 | } | 1026 | } |
901 | 1027 | ||
902 | if (!pcie->phy) | 1028 | err = tegra_pcie_phy_power_on(pcie); |
903 | err = tegra_pcie_phy_enable(pcie); | ||
904 | else | ||
905 | err = phy_power_on(pcie->phy); | ||
906 | |||
907 | if (err < 0) { | 1029 | if (err < 0) { |
908 | dev_err(pcie->dev, "failed to power on PHY: %d\n", err); | 1030 | dev_err(pcie->dev, "failed to power on PHY(s): %d\n", err); |
909 | return err; | 1031 | return err; |
910 | } | 1032 | } |
911 | 1033 | ||
@@ -942,9 +1064,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) | |||
942 | 1064 | ||
943 | /* TODO: disable and unprepare clocks? */ | 1065 | /* TODO: disable and unprepare clocks? */ |
944 | 1066 | ||
945 | err = phy_power_off(pcie->phy); | 1067 | err = tegra_pcie_phy_power_off(pcie); |
946 | if (err < 0) | 1068 | if (err < 0) |
947 | dev_warn(pcie->dev, "failed to power off PHY: %d\n", err); | 1069 | dev_err(pcie->dev, "failed to power off PHY(s): %d\n", err); |
948 | 1070 | ||
949 | reset_control_assert(pcie->pcie_xrst); | 1071 | reset_control_assert(pcie->pcie_xrst); |
950 | reset_control_assert(pcie->afi_rst); | 1072 | reset_control_assert(pcie->afi_rst); |
@@ -1049,6 +1171,100 @@ static int tegra_pcie_resets_get(struct tegra_pcie *pcie) | |||
1049 | return 0; | 1171 | return 0; |
1050 | } | 1172 | } |
1051 | 1173 | ||
1174 | static int tegra_pcie_phys_get_legacy(struct tegra_pcie *pcie) | ||
1175 | { | ||
1176 | int err; | ||
1177 | |||
1178 | pcie->phy = devm_phy_optional_get(pcie->dev, "pcie"); | ||
1179 | if (IS_ERR(pcie->phy)) { | ||
1180 | err = PTR_ERR(pcie->phy); | ||
1181 | dev_err(pcie->dev, "failed to get PHY: %d\n", err); | ||
1182 | return err; | ||
1183 | } | ||
1184 | |||
1185 | err = phy_init(pcie->phy); | ||
1186 | if (err < 0) { | ||
1187 | dev_err(pcie->dev, "failed to initialize PHY: %d\n", err); | ||
1188 | return err; | ||
1189 | } | ||
1190 | |||
1191 | pcie->legacy_phy = true; | ||
1192 | |||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | static struct phy *devm_of_phy_optional_get_index(struct device *dev, | ||
1197 | struct device_node *np, | ||
1198 | const char *consumer, | ||
1199 | unsigned int index) | ||
1200 | { | ||
1201 | struct phy *phy; | ||
1202 | char *name; | ||
1203 | |||
1204 | name = kasprintf(GFP_KERNEL, "%s-%u", consumer, index); | ||
1205 | if (!name) | ||
1206 | return ERR_PTR(-ENOMEM); | ||
1207 | |||
1208 | phy = devm_of_phy_get(dev, np, name); | ||
1209 | kfree(name); | ||
1210 | |||
1211 | if (IS_ERR(phy) && PTR_ERR(phy) == -ENODEV) | ||
1212 | phy = NULL; | ||
1213 | |||
1214 | return phy; | ||
1215 | } | ||
1216 | |||
1217 | static int tegra_pcie_port_get_phys(struct tegra_pcie_port *port) | ||
1218 | { | ||
1219 | struct device *dev = port->pcie->dev; | ||
1220 | struct phy *phy; | ||
1221 | unsigned int i; | ||
1222 | int err; | ||
1223 | |||
1224 | port->phys = devm_kcalloc(dev, sizeof(phy), port->lanes, GFP_KERNEL); | ||
1225 | if (!port->phys) | ||
1226 | return -ENOMEM; | ||
1227 | |||
1228 | for (i = 0; i < port->lanes; i++) { | ||
1229 | phy = devm_of_phy_optional_get_index(dev, port->np, "pcie", i); | ||
1230 | if (IS_ERR(phy)) { | ||
1231 | dev_err(dev, "failed to get PHY#%u: %ld\n", i, | ||
1232 | PTR_ERR(phy)); | ||
1233 | return PTR_ERR(phy); | ||
1234 | } | ||
1235 | |||
1236 | err = phy_init(phy); | ||
1237 | if (err < 0) { | ||
1238 | dev_err(dev, "failed to initialize PHY#%u: %d\n", i, | ||
1239 | err); | ||
1240 | return err; | ||
1241 | } | ||
1242 | |||
1243 | port->phys[i] = phy; | ||
1244 | } | ||
1245 | |||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | static int tegra_pcie_phys_get(struct tegra_pcie *pcie) | ||
1250 | { | ||
1251 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | ||
1252 | struct device_node *np = pcie->dev->of_node; | ||
1253 | struct tegra_pcie_port *port; | ||
1254 | int err; | ||
1255 | |||
1256 | if (!soc->has_gen2 || of_find_property(np, "phys", NULL) != NULL) | ||
1257 | return tegra_pcie_phys_get_legacy(pcie); | ||
1258 | |||
1259 | list_for_each_entry(port, &pcie->ports, list) { | ||
1260 | err = tegra_pcie_port_get_phys(port); | ||
1261 | if (err < 0) | ||
1262 | return err; | ||
1263 | } | ||
1264 | |||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1052 | static int tegra_pcie_get_resources(struct tegra_pcie *pcie) | 1268 | static int tegra_pcie_get_resources(struct tegra_pcie *pcie) |
1053 | { | 1269 | { |
1054 | struct platform_device *pdev = to_platform_device(pcie->dev); | 1270 | struct platform_device *pdev = to_platform_device(pcie->dev); |
@@ -1067,16 +1283,9 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) | |||
1067 | return err; | 1283 | return err; |
1068 | } | 1284 | } |
1069 | 1285 | ||
1070 | pcie->phy = devm_phy_optional_get(pcie->dev, "pcie"); | 1286 | err = tegra_pcie_phys_get(pcie); |
1071 | if (IS_ERR(pcie->phy)) { | ||
1072 | err = PTR_ERR(pcie->phy); | ||
1073 | dev_err(&pdev->dev, "failed to get PHY: %d\n", err); | ||
1074 | return err; | ||
1075 | } | ||
1076 | |||
1077 | err = phy_init(pcie->phy); | ||
1078 | if (err < 0) { | 1287 | if (err < 0) { |
1079 | dev_err(&pdev->dev, "failed to initialize PHY: %d\n", err); | 1288 | dev_err(&pdev->dev, "failed to get PHYs: %d\n", err); |
1080 | return err; | 1289 | return err; |
1081 | } | 1290 | } |
1082 | 1291 | ||
@@ -1752,6 +1961,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | |||
1752 | rp->index = index; | 1961 | rp->index = index; |
1753 | rp->lanes = value; | 1962 | rp->lanes = value; |
1754 | rp->pcie = pcie; | 1963 | rp->pcie = pcie; |
1964 | rp->np = port; | ||
1755 | 1965 | ||
1756 | rp->base = devm_ioremap_resource(pcie->dev, &rp->regs); | 1966 | rp->base = devm_ioremap_resource(pcie->dev, &rp->regs); |
1757 | if (IS_ERR(rp->base)) | 1967 | if (IS_ERR(rp->base)) |
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 26566db09de0..27e5f6ee9a2a 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
@@ -421,4 +421,6 @@ config PHY_CYGNUS_PCIE | |||
421 | Enable this to support the Broadcom Cygnus PCIe PHY. | 421 | Enable this to support the Broadcom Cygnus PCIe PHY. |
422 | If unsure, say N. | 422 | If unsure, say N. |
423 | 423 | ||
424 | source "drivers/phy/tegra/Kconfig" | ||
425 | |||
424 | endmenu | 426 | endmenu |
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 24596a96a887..d4f06e69fd9a 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile | |||
@@ -52,3 +52,5 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o | |||
52 | obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o | 52 | obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o |
53 | obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o | 53 | obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o |
54 | obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o | 54 | obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o |
55 | |||
56 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ | ||
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index e7e574dc667a..b72e9a3b6429 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c | |||
@@ -141,7 +141,7 @@ static struct phy_provider *of_phy_provider_lookup(struct device_node *node) | |||
141 | if (phy_provider->dev->of_node == node) | 141 | if (phy_provider->dev->of_node == node) |
142 | return phy_provider; | 142 | return phy_provider; |
143 | 143 | ||
144 | for_each_child_of_node(phy_provider->dev->of_node, child) | 144 | for_each_child_of_node(phy_provider->children, child) |
145 | if (child == node) | 145 | if (child == node) |
146 | return phy_provider; | 146 | return phy_provider; |
147 | } | 147 | } |
@@ -811,24 +811,59 @@ EXPORT_SYMBOL_GPL(devm_phy_destroy); | |||
811 | /** | 811 | /** |
812 | * __of_phy_provider_register() - create/register phy provider with the framework | 812 | * __of_phy_provider_register() - create/register phy provider with the framework |
813 | * @dev: struct device of the phy provider | 813 | * @dev: struct device of the phy provider |
814 | * @children: device node containing children (if different from dev->of_node) | ||
814 | * @owner: the module owner containing of_xlate | 815 | * @owner: the module owner containing of_xlate |
815 | * @of_xlate: function pointer to obtain phy instance from phy provider | 816 | * @of_xlate: function pointer to obtain phy instance from phy provider |
816 | * | 817 | * |
817 | * Creates struct phy_provider from dev and of_xlate function pointer. | 818 | * Creates struct phy_provider from dev and of_xlate function pointer. |
818 | * This is used in the case of dt boot for finding the phy instance from | 819 | * This is used in the case of dt boot for finding the phy instance from |
819 | * phy provider. | 820 | * phy provider. |
821 | * | ||
822 | * If the PHY provider doesn't nest children directly but uses a separate | ||
823 | * child node to contain the individual children, the @children parameter | ||
824 | * can be used to override the default. If NULL, the default (dev->of_node) | ||
825 | * will be used. If non-NULL, the device node must be a child (or further | ||
826 | * descendant) of dev->of_node. Otherwise an ERR_PTR()-encoded -EINVAL | ||
827 | * error code is returned. | ||
820 | */ | 828 | */ |
821 | struct phy_provider *__of_phy_provider_register(struct device *dev, | 829 | struct phy_provider *__of_phy_provider_register(struct device *dev, |
822 | struct module *owner, struct phy * (*of_xlate)(struct device *dev, | 830 | struct device_node *children, struct module *owner, |
823 | struct of_phandle_args *args)) | 831 | struct phy * (*of_xlate)(struct device *dev, |
832 | struct of_phandle_args *args)) | ||
824 | { | 833 | { |
825 | struct phy_provider *phy_provider; | 834 | struct phy_provider *phy_provider; |
826 | 835 | ||
836 | /* | ||
837 | * If specified, the device node containing the children must itself | ||
838 | * be the provider's device node or a child (or further descendant) | ||
839 | * thereof. | ||
840 | */ | ||
841 | if (children) { | ||
842 | struct device_node *parent = of_node_get(children), *next; | ||
843 | |||
844 | while (parent) { | ||
845 | if (parent == dev->of_node) | ||
846 | break; | ||
847 | |||
848 | next = of_get_parent(parent); | ||
849 | of_node_put(parent); | ||
850 | parent = next; | ||
851 | } | ||
852 | |||
853 | if (!parent) | ||
854 | return ERR_PTR(-EINVAL); | ||
855 | |||
856 | of_node_put(parent); | ||
857 | } else { | ||
858 | children = dev->of_node; | ||
859 | } | ||
860 | |||
827 | phy_provider = kzalloc(sizeof(*phy_provider), GFP_KERNEL); | 861 | phy_provider = kzalloc(sizeof(*phy_provider), GFP_KERNEL); |
828 | if (!phy_provider) | 862 | if (!phy_provider) |
829 | return ERR_PTR(-ENOMEM); | 863 | return ERR_PTR(-ENOMEM); |
830 | 864 | ||
831 | phy_provider->dev = dev; | 865 | phy_provider->dev = dev; |
866 | phy_provider->children = of_node_get(children); | ||
832 | phy_provider->owner = owner; | 867 | phy_provider->owner = owner; |
833 | phy_provider->of_xlate = of_xlate; | 868 | phy_provider->of_xlate = of_xlate; |
834 | 869 | ||
@@ -854,8 +889,9 @@ EXPORT_SYMBOL_GPL(__of_phy_provider_register); | |||
854 | * on the devres data, then, devres data is freed. | 889 | * on the devres data, then, devres data is freed. |
855 | */ | 890 | */ |
856 | struct phy_provider *__devm_of_phy_provider_register(struct device *dev, | 891 | struct phy_provider *__devm_of_phy_provider_register(struct device *dev, |
857 | struct module *owner, struct phy * (*of_xlate)(struct device *dev, | 892 | struct device_node *children, struct module *owner, |
858 | struct of_phandle_args *args)) | 893 | struct phy * (*of_xlate)(struct device *dev, |
894 | struct of_phandle_args *args)) | ||
859 | { | 895 | { |
860 | struct phy_provider **ptr, *phy_provider; | 896 | struct phy_provider **ptr, *phy_provider; |
861 | 897 | ||
@@ -863,7 +899,8 @@ struct phy_provider *__devm_of_phy_provider_register(struct device *dev, | |||
863 | if (!ptr) | 899 | if (!ptr) |
864 | return ERR_PTR(-ENOMEM); | 900 | return ERR_PTR(-ENOMEM); |
865 | 901 | ||
866 | phy_provider = __of_phy_provider_register(dev, owner, of_xlate); | 902 | phy_provider = __of_phy_provider_register(dev, children, owner, |
903 | of_xlate); | ||
867 | if (!IS_ERR(phy_provider)) { | 904 | if (!IS_ERR(phy_provider)) { |
868 | *ptr = phy_provider; | 905 | *ptr = phy_provider; |
869 | devres_add(dev, ptr); | 906 | devres_add(dev, ptr); |
@@ -888,6 +925,7 @@ void of_phy_provider_unregister(struct phy_provider *phy_provider) | |||
888 | 925 | ||
889 | mutex_lock(&phy_provider_mutex); | 926 | mutex_lock(&phy_provider_mutex); |
890 | list_del(&phy_provider->list); | 927 | list_del(&phy_provider->list); |
928 | of_node_put(phy_provider->children); | ||
891 | kfree(phy_provider); | 929 | kfree(phy_provider); |
892 | mutex_unlock(&phy_provider_mutex); | 930 | mutex_unlock(&phy_provider_mutex); |
893 | } | 931 | } |
diff --git a/drivers/phy/tegra/Kconfig b/drivers/phy/tegra/Kconfig new file mode 100644 index 000000000000..a3b1de953fb7 --- /dev/null +++ b/drivers/phy/tegra/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | config PHY_TEGRA_XUSB | ||
2 | tristate "NVIDIA Tegra XUSB pad controller driver" | ||
3 | depends on ARCH_TEGRA | ||
4 | help | ||
5 | Choose this option if you have an NVIDIA Tegra SoC. | ||
6 | |||
7 | To compile this driver as a module, choose M here: the module will | ||
8 | be called phy-tegra-xusb. | ||
diff --git a/drivers/phy/tegra/Makefile b/drivers/phy/tegra/Makefile new file mode 100644 index 000000000000..898589238fd9 --- /dev/null +++ b/drivers/phy/tegra/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | obj-$(CONFIG_PHY_TEGRA_XUSB) += phy-tegra-xusb.o | ||
2 | |||
3 | phy-tegra-xusb-y += xusb.o | ||
4 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o | ||
5 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o | ||
6 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o | ||
diff --git a/drivers/phy/tegra/xusb-tegra124.c b/drivers/phy/tegra/xusb-tegra124.c new file mode 100644 index 000000000000..119957249a51 --- /dev/null +++ b/drivers/phy/tegra/xusb-tegra124.c | |||
@@ -0,0 +1,1752 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/mailbox_client.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/phy/phy.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/reset.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include <soc/tegra/fuse.h> | ||
26 | |||
27 | #include "xusb.h" | ||
28 | |||
29 | #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0) | ||
30 | #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f | ||
31 | #define FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT 13 | ||
32 | #define FUSE_SKU_CALIB_HS_IREF_CAP_MASK 0x3 | ||
33 | #define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT 11 | ||
34 | #define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK 0x3 | ||
35 | #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7 | ||
36 | #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf | ||
37 | |||
38 | #define XUSB_PADCTL_USB2_PORT_CAP 0x008 | ||
39 | #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(x) ((x) * 4) | ||
40 | #define XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK 0x3 | ||
41 | #define XUSB_PADCTL_USB2_PORT_CAP_DISABLED 0x0 | ||
42 | #define XUSB_PADCTL_USB2_PORT_CAP_HOST 0x1 | ||
43 | #define XUSB_PADCTL_USB2_PORT_CAP_DEVICE 0x2 | ||
44 | #define XUSB_PADCTL_USB2_PORT_CAP_OTG 0x3 | ||
45 | |||
46 | #define XUSB_PADCTL_SS_PORT_MAP 0x014 | ||
47 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 4) + 3)) | ||
48 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 4) | ||
49 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 4)) | ||
50 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 4)) | ||
51 | #define XUSB_PADCTL_SS_PORT_MAP_PORT_MAP_MASK 0x7 | ||
52 | |||
53 | #define XUSB_PADCTL_ELPG_PROGRAM 0x01c | ||
54 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) | ||
55 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) | ||
56 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) | ||
57 | #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4)) | ||
58 | #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(x) \ | ||
59 | (1 << (17 + (x) * 4)) | ||
60 | #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4)) | ||
61 | |||
62 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 | ||
63 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) | ||
64 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12) | ||
65 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) | ||
66 | |||
67 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 | ||
68 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) | ||
69 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) | ||
70 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) | ||
71 | |||
72 | #define XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(x) (0x058 + (x) * 4) | ||
73 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT 24 | ||
74 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK 0xff | ||
75 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_VAL 0x24 | ||
76 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT 16 | ||
77 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK 0x3f | ||
78 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT 8 | ||
79 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK 0x3f | ||
80 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT 8 | ||
81 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK 0xffff | ||
82 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_VAL 0xf070 | ||
83 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT 4 | ||
84 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK 0xf | ||
85 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_VAL 0xf | ||
86 | |||
87 | #define XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(x) (0x068 + (x) * 4) | ||
88 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT 24 | ||
89 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK 0x1f | ||
90 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT 16 | ||
91 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK 0x7f | ||
92 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_VAL 0x002008ee | ||
93 | |||
94 | #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(x) ((x) < 2 ? 0x078 + (x) * 4 : \ | ||
95 | 0x0f8 + (x) * 4) | ||
96 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT 28 | ||
97 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK 0x3 | ||
98 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_VAL 0x1 | ||
99 | |||
100 | #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(x) ((x) < 2 ? 0x090 + (x) * 4 : \ | ||
101 | 0x11c + (x) * 4) | ||
102 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN (1 << 8) | ||
103 | |||
104 | #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(x) ((x) < 2 ? 0x098 + (x) * 4 : \ | ||
105 | 0x128 + (x) * 4) | ||
106 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT 24 | ||
107 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK 0x3f | ||
108 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK 0x1f | ||
109 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK 0x7f | ||
110 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT 16 | ||
111 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK 0xff | ||
112 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z 0x21 | ||
113 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP 0x32 | ||
114 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP 0x33 | ||
115 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z 0x48 | ||
116 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z 0xa1 | ||
117 | |||
118 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x0a0 + (x) * 4) | ||
119 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 21) | ||
120 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 20) | ||
121 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 19) | ||
122 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT 14 | ||
123 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK 0x3 | ||
124 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_VAL(x) ((x) ? 0x0 : 0x3) | ||
125 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT 6 | ||
126 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK 0x3f | ||
127 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_VAL 0x0e | ||
128 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0 | ||
129 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f | ||
130 | |||
131 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x0ac + (x) * 4) | ||
132 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT 9 | ||
133 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK 0x3 | ||
134 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3 | ||
135 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0x7 | ||
136 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2) | ||
137 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1) | ||
138 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0) | ||
139 | |||
140 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0b8 | ||
141 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 12) | ||
142 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 2 | ||
143 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7 | ||
144 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x5 | ||
145 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0 | ||
146 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x3 | ||
147 | |||
148 | #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x0c0 + (x) * 4) | ||
149 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT 12 | ||
150 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK 0x7 | ||
151 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT 8 | ||
152 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK 0x7 | ||
153 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT 4 | ||
154 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK 0x7 | ||
155 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT 0 | ||
156 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK 0x7 | ||
157 | |||
158 | #define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x0c8 + (x) * 4) | ||
159 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE (1 << 10) | ||
160 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA (1 << 9) | ||
161 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE (1 << 8) | ||
162 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA (1 << 7) | ||
163 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI (1 << 5) | ||
164 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX (1 << 4) | ||
165 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX (1 << 3) | ||
166 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX (1 << 2) | ||
167 | #define XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN (1 << 0) | ||
168 | |||
169 | #define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x0d0 + (x) * 4) | ||
170 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 4 | ||
171 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0x7 | ||
172 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0 | ||
173 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0x7 | ||
174 | |||
175 | #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x0e0 | ||
176 | #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK 0x1f | ||
177 | |||
178 | #define XUSB_PADCTL_USB3_PAD_MUX 0x134 | ||
179 | #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) | ||
180 | #define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (6 + (x))) | ||
181 | |||
182 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 | ||
183 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) | ||
184 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) | ||
185 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT 20 | ||
186 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK 0x3 | ||
187 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) | ||
188 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1) | ||
189 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) | ||
190 | |||
191 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13c | ||
192 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT 20 | ||
193 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK 0xf | ||
194 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT 16 | ||
195 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK 0xf | ||
196 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN (1 << 12) | ||
197 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL (1 << 4) | ||
198 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT 0 | ||
199 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK 0x7 | ||
200 | |||
201 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 | ||
202 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS (1 << 7) | ||
203 | |||
204 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 | ||
205 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) | ||
206 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) | ||
207 | |||
208 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14c | ||
209 | |||
210 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 | ||
211 | |||
212 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15c | ||
213 | |||
214 | struct tegra124_xusb_fuse_calibration { | ||
215 | u32 hs_curr_level[3]; | ||
216 | u32 hs_iref_cap; | ||
217 | u32 hs_term_range_adj; | ||
218 | u32 hs_squelch_level; | ||
219 | }; | ||
220 | |||
221 | struct tegra124_xusb_padctl { | ||
222 | struct tegra_xusb_padctl base; | ||
223 | |||
224 | struct tegra124_xusb_fuse_calibration fuse; | ||
225 | }; | ||
226 | |||
227 | static inline struct tegra124_xusb_padctl * | ||
228 | to_tegra124_xusb_padctl(struct tegra_xusb_padctl *padctl) | ||
229 | { | ||
230 | return container_of(padctl, struct tegra124_xusb_padctl, base); | ||
231 | } | ||
232 | |||
233 | static int tegra124_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) | ||
234 | { | ||
235 | u32 value; | ||
236 | |||
237 | mutex_lock(&padctl->lock); | ||
238 | |||
239 | if (padctl->enable++ > 0) | ||
240 | goto out; | ||
241 | |||
242 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
243 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; | ||
244 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
245 | |||
246 | usleep_range(100, 200); | ||
247 | |||
248 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
249 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
250 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
251 | |||
252 | usleep_range(100, 200); | ||
253 | |||
254 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
255 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; | ||
256 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
257 | |||
258 | out: | ||
259 | mutex_unlock(&padctl->lock); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int tegra124_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) | ||
264 | { | ||
265 | u32 value; | ||
266 | |||
267 | mutex_lock(&padctl->lock); | ||
268 | |||
269 | if (WARN_ON(padctl->enable == 0)) | ||
270 | goto out; | ||
271 | |||
272 | if (--padctl->enable > 0) | ||
273 | goto out; | ||
274 | |||
275 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
276 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; | ||
277 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
278 | |||
279 | usleep_range(100, 200); | ||
280 | |||
281 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
282 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
283 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
284 | |||
285 | usleep_range(100, 200); | ||
286 | |||
287 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
288 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; | ||
289 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
290 | |||
291 | out: | ||
292 | mutex_unlock(&padctl->lock); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int tegra124_usb3_save_context(struct tegra_xusb_padctl *padctl, | ||
297 | unsigned int index) | ||
298 | { | ||
299 | struct tegra_xusb_usb3_port *port; | ||
300 | struct tegra_xusb_lane *lane; | ||
301 | u32 value, offset; | ||
302 | |||
303 | port = tegra_xusb_find_usb3_port(padctl, index); | ||
304 | if (!port) | ||
305 | return -ENODEV; | ||
306 | |||
307 | port->context_saved = true; | ||
308 | lane = port->base.lane; | ||
309 | |||
310 | if (lane->pad == padctl->pcie) | ||
311 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(lane->index); | ||
312 | else | ||
313 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6; | ||
314 | |||
315 | value = padctl_readl(padctl, offset); | ||
316 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
317 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
318 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP << | ||
319 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
320 | padctl_writel(padctl, value, offset); | ||
321 | |||
322 | value = padctl_readl(padctl, offset) >> | ||
323 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
324 | port->tap1 = value & XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK; | ||
325 | |||
326 | value = padctl_readl(padctl, offset); | ||
327 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
328 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
329 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP << | ||
330 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
331 | padctl_writel(padctl, value, offset); | ||
332 | |||
333 | value = padctl_readl(padctl, offset) >> | ||
334 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
335 | port->amp = value & XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK; | ||
336 | |||
337 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index)); | ||
338 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK << | ||
339 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
340 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK << | ||
341 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT)); | ||
342 | value |= (port->tap1 << | ||
343 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
344 | (port->amp << | ||
345 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT); | ||
346 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index)); | ||
347 | |||
348 | value = padctl_readl(padctl, offset); | ||
349 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
350 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
351 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z << | ||
352 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
353 | padctl_writel(padctl, value, offset); | ||
354 | |||
355 | value = padctl_readl(padctl, offset); | ||
356 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
357 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
358 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z << | ||
359 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
360 | padctl_writel(padctl, value, offset); | ||
361 | |||
362 | value = padctl_readl(padctl, offset) >> | ||
363 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
364 | port->ctle_g = value & | ||
365 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK; | ||
366 | |||
367 | value = padctl_readl(padctl, offset); | ||
368 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
369 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
370 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z << | ||
371 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
372 | padctl_writel(padctl, value, offset); | ||
373 | |||
374 | value = padctl_readl(padctl, offset) >> | ||
375 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
376 | port->ctle_z = value & | ||
377 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK; | ||
378 | |||
379 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
380 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK << | ||
381 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
382 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK << | ||
383 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT)); | ||
384 | value |= (port->ctle_g << | ||
385 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
386 | (port->ctle_z << | ||
387 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT); | ||
388 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int tegra124_hsic_set_idle(struct tegra_xusb_padctl *padctl, | ||
394 | unsigned int index, bool idle) | ||
395 | { | ||
396 | u32 value; | ||
397 | |||
398 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
399 | |||
400 | if (idle) | ||
401 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | | ||
402 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE; | ||
403 | else | ||
404 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | | ||
405 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE); | ||
406 | |||
407 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | #define TEGRA124_LANE(_name, _offset, _shift, _mask, _type) \ | ||
413 | { \ | ||
414 | .name = _name, \ | ||
415 | .offset = _offset, \ | ||
416 | .shift = _shift, \ | ||
417 | .mask = _mask, \ | ||
418 | .num_funcs = ARRAY_SIZE(tegra124_##_type##_functions), \ | ||
419 | .funcs = tegra124_##_type##_functions, \ | ||
420 | } | ||
421 | |||
422 | static const char * const tegra124_usb2_functions[] = { | ||
423 | "snps", | ||
424 | "xusb", | ||
425 | "uart", | ||
426 | }; | ||
427 | |||
428 | static const struct tegra_xusb_lane_soc tegra124_usb2_lanes[] = { | ||
429 | TEGRA124_LANE("usb2-0", 0x004, 0, 0x3, usb2), | ||
430 | TEGRA124_LANE("usb2-1", 0x004, 2, 0x3, usb2), | ||
431 | TEGRA124_LANE("usb2-2", 0x004, 4, 0x3, usb2), | ||
432 | }; | ||
433 | |||
434 | static struct tegra_xusb_lane * | ||
435 | tegra124_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
436 | unsigned int index) | ||
437 | { | ||
438 | struct tegra_xusb_usb2_lane *usb2; | ||
439 | int err; | ||
440 | |||
441 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
442 | if (!usb2) | ||
443 | return ERR_PTR(-ENOMEM); | ||
444 | |||
445 | INIT_LIST_HEAD(&usb2->base.list); | ||
446 | usb2->base.soc = &pad->soc->lanes[index]; | ||
447 | usb2->base.index = index; | ||
448 | usb2->base.pad = pad; | ||
449 | usb2->base.np = np; | ||
450 | |||
451 | err = tegra_xusb_lane_parse_dt(&usb2->base, np); | ||
452 | if (err < 0) { | ||
453 | kfree(usb2); | ||
454 | return ERR_PTR(err); | ||
455 | } | ||
456 | |||
457 | return &usb2->base; | ||
458 | } | ||
459 | |||
460 | static void tegra124_usb2_lane_remove(struct tegra_xusb_lane *lane) | ||
461 | { | ||
462 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
463 | |||
464 | kfree(usb2); | ||
465 | } | ||
466 | |||
467 | static const struct tegra_xusb_lane_ops tegra124_usb2_lane_ops = { | ||
468 | .probe = tegra124_usb2_lane_probe, | ||
469 | .remove = tegra124_usb2_lane_remove, | ||
470 | }; | ||
471 | |||
472 | static int tegra124_usb2_phy_init(struct phy *phy) | ||
473 | { | ||
474 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
475 | |||
476 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
477 | } | ||
478 | |||
479 | static int tegra124_usb2_phy_exit(struct phy *phy) | ||
480 | { | ||
481 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
482 | |||
483 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
484 | } | ||
485 | |||
486 | static int tegra124_usb2_phy_power_on(struct phy *phy) | ||
487 | { | ||
488 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
489 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
490 | struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); | ||
491 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
492 | struct tegra124_xusb_padctl *priv; | ||
493 | struct tegra_xusb_usb2_port *port; | ||
494 | unsigned int index = lane->index; | ||
495 | u32 value; | ||
496 | int err; | ||
497 | |||
498 | port = tegra_xusb_find_usb2_port(padctl, index); | ||
499 | if (!port) { | ||
500 | dev_err(&phy->dev, "no port found for USB2 lane %u\n", index); | ||
501 | return -ENODEV; | ||
502 | } | ||
503 | |||
504 | priv = to_tegra124_xusb_padctl(padctl); | ||
505 | |||
506 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
507 | value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK << | ||
508 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | | ||
509 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK << | ||
510 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT)); | ||
511 | value |= (priv->fuse.hs_squelch_level << | ||
512 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | | ||
513 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL << | ||
514 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT); | ||
515 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
516 | |||
517 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); | ||
518 | value &= ~(XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK << | ||
519 | XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(index)); | ||
520 | value |= XUSB_PADCTL_USB2_PORT_CAP_HOST << | ||
521 | XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(index); | ||
522 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); | ||
523 | |||
524 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
525 | value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK << | ||
526 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) | | ||
527 | (XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK << | ||
528 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT) | | ||
529 | (XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK << | ||
530 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT) | | ||
531 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD | | ||
532 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 | | ||
533 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI); | ||
534 | value |= (priv->fuse.hs_curr_level[index] + | ||
535 | usb2->hs_curr_level_offset) << | ||
536 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT; | ||
537 | value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_VAL << | ||
538 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT; | ||
539 | value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_VAL(index) << | ||
540 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT; | ||
541 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
542 | |||
543 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
544 | value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK << | ||
545 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | | ||
546 | (XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK << | ||
547 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT) | | ||
548 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR | | ||
549 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP | | ||
550 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP); | ||
551 | value |= (priv->fuse.hs_term_range_adj << | ||
552 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | | ||
553 | (priv->fuse.hs_iref_cap << | ||
554 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT); | ||
555 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
556 | |||
557 | err = regulator_enable(port->supply); | ||
558 | if (err) | ||
559 | return err; | ||
560 | |||
561 | mutex_lock(&pad->lock); | ||
562 | |||
563 | if (pad->enable++ > 0) | ||
564 | goto out; | ||
565 | |||
566 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
567 | value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; | ||
568 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
569 | |||
570 | out: | ||
571 | mutex_unlock(&pad->lock); | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int tegra124_usb2_phy_power_off(struct phy *phy) | ||
576 | { | ||
577 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
578 | struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); | ||
579 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
580 | struct tegra_xusb_usb2_port *port; | ||
581 | u32 value; | ||
582 | |||
583 | port = tegra_xusb_find_usb2_port(padctl, lane->index); | ||
584 | if (!port) { | ||
585 | dev_err(&phy->dev, "no port found for USB2 lane %u\n", | ||
586 | lane->index); | ||
587 | return -ENODEV; | ||
588 | } | ||
589 | |||
590 | mutex_lock(&pad->lock); | ||
591 | |||
592 | if (WARN_ON(pad->enable == 0)) | ||
593 | goto out; | ||
594 | |||
595 | if (--pad->enable > 0) | ||
596 | goto out; | ||
597 | |||
598 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
599 | value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; | ||
600 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
601 | |||
602 | out: | ||
603 | regulator_disable(port->supply); | ||
604 | mutex_unlock(&pad->lock); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static const struct phy_ops tegra124_usb2_phy_ops = { | ||
609 | .init = tegra124_usb2_phy_init, | ||
610 | .exit = tegra124_usb2_phy_exit, | ||
611 | .power_on = tegra124_usb2_phy_power_on, | ||
612 | .power_off = tegra124_usb2_phy_power_off, | ||
613 | .owner = THIS_MODULE, | ||
614 | }; | ||
615 | |||
616 | static struct tegra_xusb_pad * | ||
617 | tegra124_usb2_pad_probe(struct tegra_xusb_padctl *padctl, | ||
618 | const struct tegra_xusb_pad_soc *soc, | ||
619 | struct device_node *np) | ||
620 | { | ||
621 | struct tegra_xusb_usb2_pad *usb2; | ||
622 | struct tegra_xusb_pad *pad; | ||
623 | int err; | ||
624 | |||
625 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
626 | if (!usb2) | ||
627 | return ERR_PTR(-ENOMEM); | ||
628 | |||
629 | mutex_init(&usb2->lock); | ||
630 | |||
631 | pad = &usb2->base; | ||
632 | pad->ops = &tegra124_usb2_lane_ops; | ||
633 | pad->soc = soc; | ||
634 | |||
635 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
636 | if (err < 0) { | ||
637 | kfree(usb2); | ||
638 | goto out; | ||
639 | } | ||
640 | |||
641 | err = tegra_xusb_pad_register(pad, &tegra124_usb2_phy_ops); | ||
642 | if (err < 0) | ||
643 | goto unregister; | ||
644 | |||
645 | dev_set_drvdata(&pad->dev, pad); | ||
646 | |||
647 | return pad; | ||
648 | |||
649 | unregister: | ||
650 | device_unregister(&pad->dev); | ||
651 | out: | ||
652 | return ERR_PTR(err); | ||
653 | } | ||
654 | |||
655 | static void tegra124_usb2_pad_remove(struct tegra_xusb_pad *pad) | ||
656 | { | ||
657 | struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); | ||
658 | |||
659 | kfree(usb2); | ||
660 | } | ||
661 | |||
662 | static const struct tegra_xusb_pad_ops tegra124_usb2_ops = { | ||
663 | .probe = tegra124_usb2_pad_probe, | ||
664 | .remove = tegra124_usb2_pad_remove, | ||
665 | }; | ||
666 | |||
667 | static const struct tegra_xusb_pad_soc tegra124_usb2_pad = { | ||
668 | .name = "usb2", | ||
669 | .num_lanes = ARRAY_SIZE(tegra124_usb2_lanes), | ||
670 | .lanes = tegra124_usb2_lanes, | ||
671 | .ops = &tegra124_usb2_ops, | ||
672 | }; | ||
673 | |||
674 | static const char * const tegra124_ulpi_functions[] = { | ||
675 | "snps", | ||
676 | "xusb", | ||
677 | }; | ||
678 | |||
679 | static const struct tegra_xusb_lane_soc tegra124_ulpi_lanes[] = { | ||
680 | TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, ulpi), | ||
681 | }; | ||
682 | |||
683 | static struct tegra_xusb_lane * | ||
684 | tegra124_ulpi_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
685 | unsigned int index) | ||
686 | { | ||
687 | struct tegra_xusb_ulpi_lane *ulpi; | ||
688 | int err; | ||
689 | |||
690 | ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL); | ||
691 | if (!ulpi) | ||
692 | return ERR_PTR(-ENOMEM); | ||
693 | |||
694 | INIT_LIST_HEAD(&ulpi->base.list); | ||
695 | ulpi->base.soc = &pad->soc->lanes[index]; | ||
696 | ulpi->base.index = index; | ||
697 | ulpi->base.pad = pad; | ||
698 | ulpi->base.np = np; | ||
699 | |||
700 | err = tegra_xusb_lane_parse_dt(&ulpi->base, np); | ||
701 | if (err < 0) { | ||
702 | kfree(ulpi); | ||
703 | return ERR_PTR(err); | ||
704 | } | ||
705 | |||
706 | return &ulpi->base; | ||
707 | } | ||
708 | |||
709 | static void tegra124_ulpi_lane_remove(struct tegra_xusb_lane *lane) | ||
710 | { | ||
711 | struct tegra_xusb_ulpi_lane *ulpi = to_ulpi_lane(lane); | ||
712 | |||
713 | kfree(ulpi); | ||
714 | } | ||
715 | |||
716 | static const struct tegra_xusb_lane_ops tegra124_ulpi_lane_ops = { | ||
717 | .probe = tegra124_ulpi_lane_probe, | ||
718 | .remove = tegra124_ulpi_lane_remove, | ||
719 | }; | ||
720 | |||
721 | static int tegra124_ulpi_phy_init(struct phy *phy) | ||
722 | { | ||
723 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
724 | |||
725 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
726 | } | ||
727 | |||
728 | static int tegra124_ulpi_phy_exit(struct phy *phy) | ||
729 | { | ||
730 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
731 | |||
732 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
733 | } | ||
734 | |||
735 | static int tegra124_ulpi_phy_power_on(struct phy *phy) | ||
736 | { | ||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static int tegra124_ulpi_phy_power_off(struct phy *phy) | ||
741 | { | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static const struct phy_ops tegra124_ulpi_phy_ops = { | ||
746 | .init = tegra124_ulpi_phy_init, | ||
747 | .exit = tegra124_ulpi_phy_exit, | ||
748 | .power_on = tegra124_ulpi_phy_power_on, | ||
749 | .power_off = tegra124_ulpi_phy_power_off, | ||
750 | .owner = THIS_MODULE, | ||
751 | }; | ||
752 | |||
753 | static struct tegra_xusb_pad * | ||
754 | tegra124_ulpi_pad_probe(struct tegra_xusb_padctl *padctl, | ||
755 | const struct tegra_xusb_pad_soc *soc, | ||
756 | struct device_node *np) | ||
757 | { | ||
758 | struct tegra_xusb_ulpi_pad *ulpi; | ||
759 | struct tegra_xusb_pad *pad; | ||
760 | int err; | ||
761 | |||
762 | ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL); | ||
763 | if (!ulpi) | ||
764 | return ERR_PTR(-ENOMEM); | ||
765 | |||
766 | pad = &ulpi->base; | ||
767 | pad->ops = &tegra124_ulpi_lane_ops; | ||
768 | pad->soc = soc; | ||
769 | |||
770 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
771 | if (err < 0) { | ||
772 | kfree(ulpi); | ||
773 | goto out; | ||
774 | } | ||
775 | |||
776 | err = tegra_xusb_pad_register(pad, &tegra124_ulpi_phy_ops); | ||
777 | if (err < 0) | ||
778 | goto unregister; | ||
779 | |||
780 | dev_set_drvdata(&pad->dev, pad); | ||
781 | |||
782 | return pad; | ||
783 | |||
784 | unregister: | ||
785 | device_unregister(&pad->dev); | ||
786 | out: | ||
787 | return ERR_PTR(err); | ||
788 | } | ||
789 | |||
790 | static void tegra124_ulpi_pad_remove(struct tegra_xusb_pad *pad) | ||
791 | { | ||
792 | struct tegra_xusb_ulpi_pad *ulpi = to_ulpi_pad(pad); | ||
793 | |||
794 | kfree(ulpi); | ||
795 | } | ||
796 | |||
797 | static const struct tegra_xusb_pad_ops tegra124_ulpi_ops = { | ||
798 | .probe = tegra124_ulpi_pad_probe, | ||
799 | .remove = tegra124_ulpi_pad_remove, | ||
800 | }; | ||
801 | |||
802 | static const struct tegra_xusb_pad_soc tegra124_ulpi_pad = { | ||
803 | .name = "ulpi", | ||
804 | .num_lanes = ARRAY_SIZE(tegra124_ulpi_lanes), | ||
805 | .lanes = tegra124_ulpi_lanes, | ||
806 | .ops = &tegra124_ulpi_ops, | ||
807 | }; | ||
808 | |||
809 | static const char * const tegra124_hsic_functions[] = { | ||
810 | "snps", | ||
811 | "xusb", | ||
812 | }; | ||
813 | |||
814 | static const struct tegra_xusb_lane_soc tegra124_hsic_lanes[] = { | ||
815 | TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, hsic), | ||
816 | TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, hsic), | ||
817 | }; | ||
818 | |||
819 | static struct tegra_xusb_lane * | ||
820 | tegra124_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
821 | unsigned int index) | ||
822 | { | ||
823 | struct tegra_xusb_hsic_lane *hsic; | ||
824 | int err; | ||
825 | |||
826 | hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); | ||
827 | if (!hsic) | ||
828 | return ERR_PTR(-ENOMEM); | ||
829 | |||
830 | INIT_LIST_HEAD(&hsic->base.list); | ||
831 | hsic->base.soc = &pad->soc->lanes[index]; | ||
832 | hsic->base.index = index; | ||
833 | hsic->base.pad = pad; | ||
834 | hsic->base.np = np; | ||
835 | |||
836 | err = tegra_xusb_lane_parse_dt(&hsic->base, np); | ||
837 | if (err < 0) { | ||
838 | kfree(hsic); | ||
839 | return ERR_PTR(err); | ||
840 | } | ||
841 | |||
842 | return &hsic->base; | ||
843 | } | ||
844 | |||
845 | static void tegra124_hsic_lane_remove(struct tegra_xusb_lane *lane) | ||
846 | { | ||
847 | struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); | ||
848 | |||
849 | kfree(hsic); | ||
850 | } | ||
851 | |||
852 | static const struct tegra_xusb_lane_ops tegra124_hsic_lane_ops = { | ||
853 | .probe = tegra124_hsic_lane_probe, | ||
854 | .remove = tegra124_hsic_lane_remove, | ||
855 | }; | ||
856 | |||
857 | static int tegra124_hsic_phy_init(struct phy *phy) | ||
858 | { | ||
859 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
860 | |||
861 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
862 | } | ||
863 | |||
864 | static int tegra124_hsic_phy_exit(struct phy *phy) | ||
865 | { | ||
866 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
867 | |||
868 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
869 | } | ||
870 | |||
871 | static int tegra124_hsic_phy_power_on(struct phy *phy) | ||
872 | { | ||
873 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
874 | struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); | ||
875 | struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); | ||
876 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
877 | unsigned int index = lane->index; | ||
878 | u32 value; | ||
879 | int err; | ||
880 | |||
881 | err = regulator_enable(pad->supply); | ||
882 | if (err) | ||
883 | return err; | ||
884 | |||
885 | padctl_writel(padctl, hsic->strobe_trim, | ||
886 | XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL); | ||
887 | |||
888 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
889 | |||
890 | if (hsic->auto_term) | ||
891 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN; | ||
892 | else | ||
893 | value &= ~XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN; | ||
894 | |||
895 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
896 | |||
897 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
898 | value &= ~((XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK << | ||
899 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT) | | ||
900 | (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK << | ||
901 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT) | | ||
902 | (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK << | ||
903 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT) | | ||
904 | (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK << | ||
905 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT)); | ||
906 | value |= (hsic->tx_rtune_n << | ||
907 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT) | | ||
908 | (hsic->tx_rtune_p << | ||
909 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT) | | ||
910 | (hsic->tx_rslew_n << | ||
911 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT) | | ||
912 | (hsic->tx_rslew_p << | ||
913 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT); | ||
914 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
915 | |||
916 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index)); | ||
917 | value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK << | ||
918 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | | ||
919 | (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK << | ||
920 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT)); | ||
921 | value |= (hsic->rx_strobe_trim << | ||
922 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | | ||
923 | (hsic->rx_data_trim << | ||
924 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT); | ||
925 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index)); | ||
926 | |||
927 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
928 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE | | ||
929 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA | | ||
930 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX | | ||
931 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI | | ||
932 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX | | ||
933 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX); | ||
934 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | | ||
935 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE; | ||
936 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
937 | |||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | static int tegra124_hsic_phy_power_off(struct phy *phy) | ||
942 | { | ||
943 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
944 | struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); | ||
945 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
946 | unsigned int index = lane->index; | ||
947 | u32 value; | ||
948 | |||
949 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
950 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX | | ||
951 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI | | ||
952 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX | | ||
953 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX; | ||
954 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
955 | |||
956 | regulator_disable(pad->supply); | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | static const struct phy_ops tegra124_hsic_phy_ops = { | ||
962 | .init = tegra124_hsic_phy_init, | ||
963 | .exit = tegra124_hsic_phy_exit, | ||
964 | .power_on = tegra124_hsic_phy_power_on, | ||
965 | .power_off = tegra124_hsic_phy_power_off, | ||
966 | .owner = THIS_MODULE, | ||
967 | }; | ||
968 | |||
969 | static struct tegra_xusb_pad * | ||
970 | tegra124_hsic_pad_probe(struct tegra_xusb_padctl *padctl, | ||
971 | const struct tegra_xusb_pad_soc *soc, | ||
972 | struct device_node *np) | ||
973 | { | ||
974 | struct tegra_xusb_hsic_pad *hsic; | ||
975 | struct tegra_xusb_pad *pad; | ||
976 | int err; | ||
977 | |||
978 | hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); | ||
979 | if (!hsic) | ||
980 | return ERR_PTR(-ENOMEM); | ||
981 | |||
982 | pad = &hsic->base; | ||
983 | pad->ops = &tegra124_hsic_lane_ops; | ||
984 | pad->soc = soc; | ||
985 | |||
986 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
987 | if (err < 0) { | ||
988 | kfree(hsic); | ||
989 | goto out; | ||
990 | } | ||
991 | |||
992 | err = tegra_xusb_pad_register(pad, &tegra124_hsic_phy_ops); | ||
993 | if (err < 0) | ||
994 | goto unregister; | ||
995 | |||
996 | dev_set_drvdata(&pad->dev, pad); | ||
997 | |||
998 | return pad; | ||
999 | |||
1000 | unregister: | ||
1001 | device_unregister(&pad->dev); | ||
1002 | out: | ||
1003 | return ERR_PTR(err); | ||
1004 | } | ||
1005 | |||
1006 | static void tegra124_hsic_pad_remove(struct tegra_xusb_pad *pad) | ||
1007 | { | ||
1008 | struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad); | ||
1009 | |||
1010 | kfree(hsic); | ||
1011 | } | ||
1012 | |||
1013 | static const struct tegra_xusb_pad_ops tegra124_hsic_ops = { | ||
1014 | .probe = tegra124_hsic_pad_probe, | ||
1015 | .remove = tegra124_hsic_pad_remove, | ||
1016 | }; | ||
1017 | |||
1018 | static const struct tegra_xusb_pad_soc tegra124_hsic_pad = { | ||
1019 | .name = "hsic", | ||
1020 | .num_lanes = ARRAY_SIZE(tegra124_hsic_lanes), | ||
1021 | .lanes = tegra124_hsic_lanes, | ||
1022 | .ops = &tegra124_hsic_ops, | ||
1023 | }; | ||
1024 | |||
1025 | static const char * const tegra124_pcie_functions[] = { | ||
1026 | "pcie", | ||
1027 | "usb3-ss", | ||
1028 | "sata", | ||
1029 | }; | ||
1030 | |||
1031 | static const struct tegra_xusb_lane_soc tegra124_pcie_lanes[] = { | ||
1032 | TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, pcie), | ||
1033 | TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, pcie), | ||
1034 | TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, pcie), | ||
1035 | TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, pcie), | ||
1036 | TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, pcie), | ||
1037 | }; | ||
1038 | |||
1039 | static struct tegra_xusb_lane * | ||
1040 | tegra124_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
1041 | unsigned int index) | ||
1042 | { | ||
1043 | struct tegra_xusb_pcie_lane *pcie; | ||
1044 | int err; | ||
1045 | |||
1046 | pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); | ||
1047 | if (!pcie) | ||
1048 | return ERR_PTR(-ENOMEM); | ||
1049 | |||
1050 | INIT_LIST_HEAD(&pcie->base.list); | ||
1051 | pcie->base.soc = &pad->soc->lanes[index]; | ||
1052 | pcie->base.index = index; | ||
1053 | pcie->base.pad = pad; | ||
1054 | pcie->base.np = np; | ||
1055 | |||
1056 | err = tegra_xusb_lane_parse_dt(&pcie->base, np); | ||
1057 | if (err < 0) { | ||
1058 | kfree(pcie); | ||
1059 | return ERR_PTR(err); | ||
1060 | } | ||
1061 | |||
1062 | return &pcie->base; | ||
1063 | } | ||
1064 | |||
1065 | static void tegra124_pcie_lane_remove(struct tegra_xusb_lane *lane) | ||
1066 | { | ||
1067 | struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane); | ||
1068 | |||
1069 | kfree(pcie); | ||
1070 | } | ||
1071 | |||
1072 | static const struct tegra_xusb_lane_ops tegra124_pcie_lane_ops = { | ||
1073 | .probe = tegra124_pcie_lane_probe, | ||
1074 | .remove = tegra124_pcie_lane_remove, | ||
1075 | }; | ||
1076 | |||
1077 | static int tegra124_pcie_phy_init(struct phy *phy) | ||
1078 | { | ||
1079 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1080 | |||
1081 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
1082 | } | ||
1083 | |||
1084 | static int tegra124_pcie_phy_exit(struct phy *phy) | ||
1085 | { | ||
1086 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1087 | |||
1088 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
1089 | } | ||
1090 | |||
1091 | static int tegra124_pcie_phy_power_on(struct phy *phy) | ||
1092 | { | ||
1093 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1094 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1095 | unsigned long timeout; | ||
1096 | int err = -ETIMEDOUT; | ||
1097 | u32 value; | ||
1098 | |||
1099 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1100 | value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK; | ||
1101 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1102 | |||
1103 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); | ||
1104 | value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN | | ||
1105 | XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN | | ||
1106 | XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; | ||
1107 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); | ||
1108 | |||
1109 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1110 | value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; | ||
1111 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1112 | |||
1113 | timeout = jiffies + msecs_to_jiffies(50); | ||
1114 | |||
1115 | while (time_before(jiffies, timeout)) { | ||
1116 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1117 | if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) { | ||
1118 | err = 0; | ||
1119 | break; | ||
1120 | } | ||
1121 | |||
1122 | usleep_range(100, 200); | ||
1123 | } | ||
1124 | |||
1125 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1126 | value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); | ||
1127 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1128 | |||
1129 | return err; | ||
1130 | } | ||
1131 | |||
1132 | static int tegra124_pcie_phy_power_off(struct phy *phy) | ||
1133 | { | ||
1134 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1135 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1136 | u32 value; | ||
1137 | |||
1138 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1139 | value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); | ||
1140 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1141 | |||
1142 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1143 | value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; | ||
1144 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1145 | |||
1146 | return 0; | ||
1147 | } | ||
1148 | |||
1149 | static const struct phy_ops tegra124_pcie_phy_ops = { | ||
1150 | .init = tegra124_pcie_phy_init, | ||
1151 | .exit = tegra124_pcie_phy_exit, | ||
1152 | .power_on = tegra124_pcie_phy_power_on, | ||
1153 | .power_off = tegra124_pcie_phy_power_off, | ||
1154 | .owner = THIS_MODULE, | ||
1155 | }; | ||
1156 | |||
1157 | static struct tegra_xusb_pad * | ||
1158 | tegra124_pcie_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1159 | const struct tegra_xusb_pad_soc *soc, | ||
1160 | struct device_node *np) | ||
1161 | { | ||
1162 | struct tegra_xusb_pcie_pad *pcie; | ||
1163 | struct tegra_xusb_pad *pad; | ||
1164 | int err; | ||
1165 | |||
1166 | pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); | ||
1167 | if (!pcie) | ||
1168 | return ERR_PTR(-ENOMEM); | ||
1169 | |||
1170 | pad = &pcie->base; | ||
1171 | pad->ops = &tegra124_pcie_lane_ops; | ||
1172 | pad->soc = soc; | ||
1173 | |||
1174 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1175 | if (err < 0) { | ||
1176 | kfree(pcie); | ||
1177 | goto out; | ||
1178 | } | ||
1179 | |||
1180 | err = tegra_xusb_pad_register(pad, &tegra124_pcie_phy_ops); | ||
1181 | if (err < 0) | ||
1182 | goto unregister; | ||
1183 | |||
1184 | dev_set_drvdata(&pad->dev, pad); | ||
1185 | |||
1186 | return pad; | ||
1187 | |||
1188 | unregister: | ||
1189 | device_unregister(&pad->dev); | ||
1190 | out: | ||
1191 | return ERR_PTR(err); | ||
1192 | } | ||
1193 | |||
1194 | static void tegra124_pcie_pad_remove(struct tegra_xusb_pad *pad) | ||
1195 | { | ||
1196 | struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad); | ||
1197 | |||
1198 | kfree(pcie); | ||
1199 | } | ||
1200 | |||
1201 | static const struct tegra_xusb_pad_ops tegra124_pcie_ops = { | ||
1202 | .probe = tegra124_pcie_pad_probe, | ||
1203 | .remove = tegra124_pcie_pad_remove, | ||
1204 | }; | ||
1205 | |||
1206 | static const struct tegra_xusb_pad_soc tegra124_pcie_pad = { | ||
1207 | .name = "pcie", | ||
1208 | .num_lanes = ARRAY_SIZE(tegra124_pcie_lanes), | ||
1209 | .lanes = tegra124_pcie_lanes, | ||
1210 | .ops = &tegra124_pcie_ops, | ||
1211 | }; | ||
1212 | |||
1213 | static const struct tegra_xusb_lane_soc tegra124_sata_lanes[] = { | ||
1214 | TEGRA124_LANE("sata-0", 0x134, 26, 0x3, pcie), | ||
1215 | }; | ||
1216 | |||
1217 | static struct tegra_xusb_lane * | ||
1218 | tegra124_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
1219 | unsigned int index) | ||
1220 | { | ||
1221 | struct tegra_xusb_sata_lane *sata; | ||
1222 | int err; | ||
1223 | |||
1224 | sata = kzalloc(sizeof(*sata), GFP_KERNEL); | ||
1225 | if (!sata) | ||
1226 | return ERR_PTR(-ENOMEM); | ||
1227 | |||
1228 | INIT_LIST_HEAD(&sata->base.list); | ||
1229 | sata->base.soc = &pad->soc->lanes[index]; | ||
1230 | sata->base.index = index; | ||
1231 | sata->base.pad = pad; | ||
1232 | sata->base.np = np; | ||
1233 | |||
1234 | err = tegra_xusb_lane_parse_dt(&sata->base, np); | ||
1235 | if (err < 0) { | ||
1236 | kfree(sata); | ||
1237 | return ERR_PTR(err); | ||
1238 | } | ||
1239 | |||
1240 | return &sata->base; | ||
1241 | } | ||
1242 | |||
1243 | static void tegra124_sata_lane_remove(struct tegra_xusb_lane *lane) | ||
1244 | { | ||
1245 | struct tegra_xusb_sata_lane *sata = to_sata_lane(lane); | ||
1246 | |||
1247 | kfree(sata); | ||
1248 | } | ||
1249 | |||
1250 | static const struct tegra_xusb_lane_ops tegra124_sata_lane_ops = { | ||
1251 | .probe = tegra124_sata_lane_probe, | ||
1252 | .remove = tegra124_sata_lane_remove, | ||
1253 | }; | ||
1254 | |||
1255 | static int tegra124_sata_phy_init(struct phy *phy) | ||
1256 | { | ||
1257 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1258 | |||
1259 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
1260 | } | ||
1261 | |||
1262 | static int tegra124_sata_phy_exit(struct phy *phy) | ||
1263 | { | ||
1264 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1265 | |||
1266 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
1267 | } | ||
1268 | |||
1269 | static int tegra124_sata_phy_power_on(struct phy *phy) | ||
1270 | { | ||
1271 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1272 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1273 | unsigned long timeout; | ||
1274 | int err = -ETIMEDOUT; | ||
1275 | u32 value; | ||
1276 | |||
1277 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1278 | value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; | ||
1279 | value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; | ||
1280 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1281 | |||
1282 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1283 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; | ||
1284 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; | ||
1285 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1286 | |||
1287 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1288 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; | ||
1289 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1290 | |||
1291 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1292 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; | ||
1293 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1294 | |||
1295 | timeout = jiffies + msecs_to_jiffies(50); | ||
1296 | |||
1297 | while (time_before(jiffies, timeout)) { | ||
1298 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1299 | if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) { | ||
1300 | err = 0; | ||
1301 | break; | ||
1302 | } | ||
1303 | |||
1304 | usleep_range(100, 200); | ||
1305 | } | ||
1306 | |||
1307 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1308 | value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); | ||
1309 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1310 | |||
1311 | return err; | ||
1312 | } | ||
1313 | |||
1314 | static int tegra124_sata_phy_power_off(struct phy *phy) | ||
1315 | { | ||
1316 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1317 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1318 | u32 value; | ||
1319 | |||
1320 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1321 | value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); | ||
1322 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1323 | |||
1324 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1325 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; | ||
1326 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1327 | |||
1328 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1329 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; | ||
1330 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1331 | |||
1332 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1333 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; | ||
1334 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; | ||
1335 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1336 | |||
1337 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1338 | value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; | ||
1339 | value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; | ||
1340 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1341 | |||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | static const struct phy_ops tegra124_sata_phy_ops = { | ||
1346 | .init = tegra124_sata_phy_init, | ||
1347 | .exit = tegra124_sata_phy_exit, | ||
1348 | .power_on = tegra124_sata_phy_power_on, | ||
1349 | .power_off = tegra124_sata_phy_power_off, | ||
1350 | .owner = THIS_MODULE, | ||
1351 | }; | ||
1352 | |||
1353 | static struct tegra_xusb_pad * | ||
1354 | tegra124_sata_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1355 | const struct tegra_xusb_pad_soc *soc, | ||
1356 | struct device_node *np) | ||
1357 | { | ||
1358 | struct tegra_xusb_sata_pad *sata; | ||
1359 | struct tegra_xusb_pad *pad; | ||
1360 | int err; | ||
1361 | |||
1362 | sata = kzalloc(sizeof(*sata), GFP_KERNEL); | ||
1363 | if (!sata) | ||
1364 | return ERR_PTR(-ENOMEM); | ||
1365 | |||
1366 | pad = &sata->base; | ||
1367 | pad->ops = &tegra124_sata_lane_ops; | ||
1368 | pad->soc = soc; | ||
1369 | |||
1370 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1371 | if (err < 0) { | ||
1372 | kfree(sata); | ||
1373 | goto out; | ||
1374 | } | ||
1375 | |||
1376 | err = tegra_xusb_pad_register(pad, &tegra124_sata_phy_ops); | ||
1377 | if (err < 0) | ||
1378 | goto unregister; | ||
1379 | |||
1380 | dev_set_drvdata(&pad->dev, pad); | ||
1381 | |||
1382 | return pad; | ||
1383 | |||
1384 | unregister: | ||
1385 | device_unregister(&pad->dev); | ||
1386 | out: | ||
1387 | return ERR_PTR(err); | ||
1388 | } | ||
1389 | |||
1390 | static void tegra124_sata_pad_remove(struct tegra_xusb_pad *pad) | ||
1391 | { | ||
1392 | struct tegra_xusb_sata_pad *sata = to_sata_pad(pad); | ||
1393 | |||
1394 | kfree(sata); | ||
1395 | } | ||
1396 | |||
1397 | static const struct tegra_xusb_pad_ops tegra124_sata_ops = { | ||
1398 | .probe = tegra124_sata_pad_probe, | ||
1399 | .remove = tegra124_sata_pad_remove, | ||
1400 | }; | ||
1401 | |||
1402 | static const struct tegra_xusb_pad_soc tegra124_sata_pad = { | ||
1403 | .name = "sata", | ||
1404 | .num_lanes = ARRAY_SIZE(tegra124_sata_lanes), | ||
1405 | .lanes = tegra124_sata_lanes, | ||
1406 | .ops = &tegra124_sata_ops, | ||
1407 | }; | ||
1408 | |||
1409 | static const struct tegra_xusb_pad_soc *tegra124_pads[] = { | ||
1410 | &tegra124_usb2_pad, | ||
1411 | &tegra124_ulpi_pad, | ||
1412 | &tegra124_hsic_pad, | ||
1413 | &tegra124_pcie_pad, | ||
1414 | &tegra124_sata_pad, | ||
1415 | }; | ||
1416 | |||
1417 | static int tegra124_usb2_port_enable(struct tegra_xusb_port *port) | ||
1418 | { | ||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1422 | static void tegra124_usb2_port_disable(struct tegra_xusb_port *port) | ||
1423 | { | ||
1424 | } | ||
1425 | |||
1426 | static struct tegra_xusb_lane * | ||
1427 | tegra124_usb2_port_map(struct tegra_xusb_port *port) | ||
1428 | { | ||
1429 | return tegra_xusb_find_lane(port->padctl, "usb2", port->index); | ||
1430 | } | ||
1431 | |||
1432 | static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = { | ||
1433 | .enable = tegra124_usb2_port_enable, | ||
1434 | .disable = tegra124_usb2_port_disable, | ||
1435 | .map = tegra124_usb2_port_map, | ||
1436 | }; | ||
1437 | |||
1438 | static int tegra124_ulpi_port_enable(struct tegra_xusb_port *port) | ||
1439 | { | ||
1440 | return 0; | ||
1441 | } | ||
1442 | |||
1443 | static void tegra124_ulpi_port_disable(struct tegra_xusb_port *port) | ||
1444 | { | ||
1445 | } | ||
1446 | |||
1447 | static struct tegra_xusb_lane * | ||
1448 | tegra124_ulpi_port_map(struct tegra_xusb_port *port) | ||
1449 | { | ||
1450 | return tegra_xusb_find_lane(port->padctl, "ulpi", port->index); | ||
1451 | } | ||
1452 | |||
1453 | static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = { | ||
1454 | .enable = tegra124_ulpi_port_enable, | ||
1455 | .disable = tegra124_ulpi_port_disable, | ||
1456 | .map = tegra124_ulpi_port_map, | ||
1457 | }; | ||
1458 | |||
1459 | static int tegra124_hsic_port_enable(struct tegra_xusb_port *port) | ||
1460 | { | ||
1461 | return 0; | ||
1462 | } | ||
1463 | |||
1464 | static void tegra124_hsic_port_disable(struct tegra_xusb_port *port) | ||
1465 | { | ||
1466 | } | ||
1467 | |||
1468 | static struct tegra_xusb_lane * | ||
1469 | tegra124_hsic_port_map(struct tegra_xusb_port *port) | ||
1470 | { | ||
1471 | return tegra_xusb_find_lane(port->padctl, "hsic", port->index); | ||
1472 | } | ||
1473 | |||
1474 | static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = { | ||
1475 | .enable = tegra124_hsic_port_enable, | ||
1476 | .disable = tegra124_hsic_port_disable, | ||
1477 | .map = tegra124_hsic_port_map, | ||
1478 | }; | ||
1479 | |||
1480 | static int tegra124_usb3_port_enable(struct tegra_xusb_port *port) | ||
1481 | { | ||
1482 | struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port); | ||
1483 | struct tegra_xusb_padctl *padctl = port->padctl; | ||
1484 | struct tegra_xusb_lane *lane = usb3->base.lane; | ||
1485 | unsigned int index = port->index, offset; | ||
1486 | int ret = 0; | ||
1487 | u32 value; | ||
1488 | |||
1489 | value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); | ||
1490 | |||
1491 | if (!usb3->internal) | ||
1492 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); | ||
1493 | else | ||
1494 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); | ||
1495 | |||
1496 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index); | ||
1497 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port); | ||
1498 | padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); | ||
1499 | |||
1500 | /* | ||
1501 | * TODO: move this code into the PCIe/SATA PHY ->power_on() callbacks | ||
1502 | * and conditionalize based on mux function? This seems to work, but | ||
1503 | * might not be the exact proper sequence. | ||
1504 | */ | ||
1505 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
1506 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK << | ||
1507 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) | | ||
1508 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK << | ||
1509 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) | | ||
1510 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK << | ||
1511 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT)); | ||
1512 | value |= (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_VAL << | ||
1513 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) | | ||
1514 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_VAL << | ||
1515 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT) | | ||
1516 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_VAL << | ||
1517 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT); | ||
1518 | |||
1519 | if (usb3->context_saved) { | ||
1520 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK << | ||
1521 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
1522 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK << | ||
1523 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT)); | ||
1524 | value |= (usb3->ctle_g << | ||
1525 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
1526 | (usb3->ctle_z << | ||
1527 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT); | ||
1528 | } | ||
1529 | |||
1530 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
1531 | |||
1532 | value = XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_VAL; | ||
1533 | |||
1534 | if (usb3->context_saved) { | ||
1535 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK << | ||
1536 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
1537 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK << | ||
1538 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT)); | ||
1539 | value |= (usb3->tap1 << | ||
1540 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
1541 | (usb3->amp << | ||
1542 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT); | ||
1543 | } | ||
1544 | |||
1545 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index)); | ||
1546 | |||
1547 | if (lane->pad == padctl->pcie) | ||
1548 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(lane->index); | ||
1549 | else | ||
1550 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2; | ||
1551 | |||
1552 | value = padctl_readl(padctl, offset); | ||
1553 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK << | ||
1554 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT); | ||
1555 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_VAL << | ||
1556 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT; | ||
1557 | padctl_writel(padctl, value, offset); | ||
1558 | |||
1559 | if (lane->pad == padctl->pcie) | ||
1560 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(lane->index); | ||
1561 | else | ||
1562 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5; | ||
1563 | |||
1564 | value = padctl_readl(padctl, offset); | ||
1565 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN; | ||
1566 | padctl_writel(padctl, value, offset); | ||
1567 | |||
1568 | /* Enable SATA PHY when SATA lane is used */ | ||
1569 | if (lane->pad == padctl->sata) { | ||
1570 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1571 | value &= ~(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK << | ||
1572 | XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT); | ||
1573 | value |= 0x2 << | ||
1574 | XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT; | ||
1575 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1576 | |||
1577 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL2); | ||
1578 | value &= ~((XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK << | ||
1579 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) | | ||
1580 | (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK << | ||
1581 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) | | ||
1582 | (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK << | ||
1583 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) | | ||
1584 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN); | ||
1585 | value |= (0x7 << | ||
1586 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) | | ||
1587 | (0x8 << | ||
1588 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) | | ||
1589 | (0x8 << | ||
1590 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) | | ||
1591 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL; | ||
1592 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL2); | ||
1593 | |||
1594 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL3); | ||
1595 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS; | ||
1596 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL3); | ||
1597 | } | ||
1598 | |||
1599 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1600 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(index); | ||
1601 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1602 | |||
1603 | usleep_range(100, 200); | ||
1604 | |||
1605 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1606 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(index); | ||
1607 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1608 | |||
1609 | usleep_range(100, 200); | ||
1610 | |||
1611 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1612 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(index); | ||
1613 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1614 | |||
1615 | return ret; | ||
1616 | } | ||
1617 | |||
1618 | static void tegra124_usb3_port_disable(struct tegra_xusb_port *port) | ||
1619 | { | ||
1620 | struct tegra_xusb_padctl *padctl = port->padctl; | ||
1621 | u32 value; | ||
1622 | |||
1623 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1624 | value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port->index); | ||
1625 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1626 | |||
1627 | usleep_range(100, 200); | ||
1628 | |||
1629 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1630 | value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(port->index); | ||
1631 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1632 | |||
1633 | usleep_range(250, 350); | ||
1634 | |||
1635 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1636 | value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port->index); | ||
1637 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1638 | |||
1639 | value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); | ||
1640 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(port->index); | ||
1641 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->index, 0x7); | ||
1642 | padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); | ||
1643 | } | ||
1644 | |||
1645 | static const struct tegra_xusb_lane_map tegra124_usb3_map[] = { | ||
1646 | { 0, "pcie", 0 }, | ||
1647 | { 1, "pcie", 1 }, | ||
1648 | { 1, "sata", 0 }, | ||
1649 | { 0, NULL, 0 }, | ||
1650 | }; | ||
1651 | |||
1652 | static struct tegra_xusb_lane * | ||
1653 | tegra124_usb3_port_map(struct tegra_xusb_port *port) | ||
1654 | { | ||
1655 | return tegra_xusb_port_find_lane(port, tegra124_usb3_map, "usb3-ss"); | ||
1656 | } | ||
1657 | |||
1658 | static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = { | ||
1659 | .enable = tegra124_usb3_port_enable, | ||
1660 | .disable = tegra124_usb3_port_disable, | ||
1661 | .map = tegra124_usb3_port_map, | ||
1662 | }; | ||
1663 | |||
1664 | static int | ||
1665 | tegra124_xusb_read_fuse_calibration(struct tegra124_xusb_fuse_calibration *fuse) | ||
1666 | { | ||
1667 | unsigned int i; | ||
1668 | int err; | ||
1669 | u32 value; | ||
1670 | |||
1671 | err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); | ||
1672 | if (err < 0) | ||
1673 | return err; | ||
1674 | |||
1675 | for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) { | ||
1676 | fuse->hs_curr_level[i] = | ||
1677 | (value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) & | ||
1678 | FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK; | ||
1679 | } | ||
1680 | fuse->hs_iref_cap = | ||
1681 | (value >> FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT) & | ||
1682 | FUSE_SKU_CALIB_HS_IREF_CAP_MASK; | ||
1683 | fuse->hs_term_range_adj = | ||
1684 | (value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) & | ||
1685 | FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK; | ||
1686 | fuse->hs_squelch_level = | ||
1687 | (value >> FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT) & | ||
1688 | FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK; | ||
1689 | |||
1690 | return 0; | ||
1691 | } | ||
1692 | |||
1693 | static struct tegra_xusb_padctl * | ||
1694 | tegra124_xusb_padctl_probe(struct device *dev, | ||
1695 | const struct tegra_xusb_padctl_soc *soc) | ||
1696 | { | ||
1697 | struct tegra124_xusb_padctl *padctl; | ||
1698 | int err; | ||
1699 | |||
1700 | padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL); | ||
1701 | if (!padctl) | ||
1702 | return ERR_PTR(-ENOMEM); | ||
1703 | |||
1704 | padctl->base.dev = dev; | ||
1705 | padctl->base.soc = soc; | ||
1706 | |||
1707 | err = tegra124_xusb_read_fuse_calibration(&padctl->fuse); | ||
1708 | if (err < 0) | ||
1709 | return ERR_PTR(err); | ||
1710 | |||
1711 | return &padctl->base; | ||
1712 | } | ||
1713 | |||
1714 | static void tegra124_xusb_padctl_remove(struct tegra_xusb_padctl *padctl) | ||
1715 | { | ||
1716 | } | ||
1717 | |||
1718 | static const struct tegra_xusb_padctl_ops tegra124_xusb_padctl_ops = { | ||
1719 | .probe = tegra124_xusb_padctl_probe, | ||
1720 | .remove = tegra124_xusb_padctl_remove, | ||
1721 | .usb3_save_context = tegra124_usb3_save_context, | ||
1722 | .hsic_set_idle = tegra124_hsic_set_idle, | ||
1723 | }; | ||
1724 | |||
1725 | const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = { | ||
1726 | .num_pads = ARRAY_SIZE(tegra124_pads), | ||
1727 | .pads = tegra124_pads, | ||
1728 | .ports = { | ||
1729 | .usb2 = { | ||
1730 | .ops = &tegra124_usb2_port_ops, | ||
1731 | .count = 3, | ||
1732 | }, | ||
1733 | .ulpi = { | ||
1734 | .ops = &tegra124_ulpi_port_ops, | ||
1735 | .count = 1, | ||
1736 | }, | ||
1737 | .hsic = { | ||
1738 | .ops = &tegra124_hsic_port_ops, | ||
1739 | .count = 2, | ||
1740 | }, | ||
1741 | .usb3 = { | ||
1742 | .ops = &tegra124_usb3_port_ops, | ||
1743 | .count = 2, | ||
1744 | }, | ||
1745 | }, | ||
1746 | .ops = &tegra124_xusb_padctl_ops, | ||
1747 | }; | ||
1748 | EXPORT_SYMBOL_GPL(tegra124_xusb_padctl_soc); | ||
1749 | |||
1750 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
1751 | MODULE_DESCRIPTION("NVIDIA Tegra 124 XUSB Pad Controller driver"); | ||
1752 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c new file mode 100644 index 000000000000..9d0689ebd28c --- /dev/null +++ b/drivers/phy/tegra/xusb-tegra210.c | |||
@@ -0,0 +1,2045 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
3 | * Copyright (C) 2015 Google, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/clk/tegra.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/mailbox_client.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/phy/phy.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/regulator/consumer.h> | ||
25 | #include <linux/reset.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include <soc/tegra/fuse.h> | ||
29 | |||
30 | #include "xusb.h" | ||
31 | |||
32 | #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) \ | ||
33 | ((x) ? (11 + ((x) - 1) * 6) : 0) | ||
34 | #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f | ||
35 | #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7 | ||
36 | #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf | ||
37 | |||
38 | #define FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT 0 | ||
39 | #define FUSE_USB_CALIB_EXT_RPD_CTRL_MASK 0x1f | ||
40 | |||
41 | #define XUSB_PADCTL_USB2_PAD_MUX 0x004 | ||
42 | #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT 16 | ||
43 | #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK 0x3 | ||
44 | #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB 0x1 | ||
45 | #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT 18 | ||
46 | #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK 0x3 | ||
47 | #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB 0x1 | ||
48 | |||
49 | #define XUSB_PADCTL_USB2_PORT_CAP 0x008 | ||
50 | #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4)) | ||
51 | #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4)) | ||
52 | |||
53 | #define XUSB_PADCTL_SS_PORT_MAP 0x014 | ||
54 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 5) + 4)) | ||
55 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 5) | ||
56 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 5)) | ||
57 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5)) | ||
58 | |||
59 | #define XUSB_PADCTL_ELPG_PROGRAM1 0x024 | ||
60 | #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31) | ||
61 | #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30) | ||
62 | #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN (1 << 29) | ||
63 | #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(x) (1 << (2 + (x) * 3)) | ||
64 | #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(x) \ | ||
65 | (1 << (1 + (x) * 3)) | ||
66 | #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(x) (1 << ((x) * 3)) | ||
67 | |||
68 | #define XUSB_PADCTL_USB3_PAD_MUX 0x028 | ||
69 | #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) | ||
70 | #define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (8 + (x))) | ||
71 | |||
72 | #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(x) (0x084 + (x) * 0x40) | ||
73 | #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT 7 | ||
74 | #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK 0x3 | ||
75 | #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6) | ||
76 | |||
77 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x088 + (x) * 0x40) | ||
78 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 29) | ||
79 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 27) | ||
80 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 26) | ||
81 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0 | ||
82 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f | ||
83 | |||
84 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x08c + (x) * 0x40) | ||
85 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT 26 | ||
86 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK 0x1f | ||
87 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3 | ||
88 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0xf | ||
89 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2) | ||
90 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1) | ||
91 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0) | ||
92 | |||
93 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284 | ||
94 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11) | ||
95 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 3 | ||
96 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7 | ||
97 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x7 | ||
98 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0 | ||
99 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x7 | ||
100 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL 0x2 | ||
101 | |||
102 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288 | ||
103 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK (1 << 26) | ||
104 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT 19 | ||
105 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK 0x7f | ||
106 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL 0x0a | ||
107 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12 | ||
108 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f | ||
109 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e | ||
110 | |||
111 | #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20) | ||
112 | #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18) | ||
113 | #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 (1 << 17) | ||
114 | #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 (1 << 16) | ||
115 | #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE (1 << 15) | ||
116 | #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 (1 << 14) | ||
117 | #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 (1 << 13) | ||
118 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE (1 << 9) | ||
119 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 (1 << 8) | ||
120 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 (1 << 7) | ||
121 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE (1 << 6) | ||
122 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 (1 << 5) | ||
123 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 (1 << 4) | ||
124 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE (1 << 3) | ||
125 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 (1 << 2) | ||
126 | #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 (1 << 1) | ||
127 | |||
128 | #define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x304 + (x) * 0x20) | ||
129 | #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT 0 | ||
130 | #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK 0xf | ||
131 | |||
132 | #define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x308 + (x) * 0x20) | ||
133 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 8 | ||
134 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0xf | ||
135 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0 | ||
136 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0xff | ||
137 | |||
138 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL 0x340 | ||
139 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK (1 << 19) | ||
140 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT 12 | ||
141 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK 0x7f | ||
142 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL 0x0a | ||
143 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT 5 | ||
144 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK 0x7f | ||
145 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL 0x1e | ||
146 | |||
147 | #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x344 | ||
148 | |||
149 | #define XUSB_PADCTL_UPHY_PLL_P0_CTL1 0x360 | ||
150 | #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT 20 | ||
151 | #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK 0xff | ||
152 | #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL 0x19 | ||
153 | #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL 0x1e | ||
154 | #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT 16 | ||
155 | #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK 0x3 | ||
156 | #define XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS (1 << 15) | ||
157 | #define XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD (1 << 4) | ||
158 | #define XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE (1 << 3) | ||
159 | #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT 1 | ||
160 | #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK 0x3 | ||
161 | #define XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ (1 << 0) | ||
162 | |||
163 | #define XUSB_PADCTL_UPHY_PLL_P0_CTL2 0x364 | ||
164 | #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT 4 | ||
165 | #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK 0xffffff | ||
166 | #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL 0x136 | ||
167 | #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD (1 << 2) | ||
168 | #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE (1 << 1) | ||
169 | #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0) | ||
170 | |||
171 | #define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c | ||
172 | #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15) | ||
173 | #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12 | ||
174 | #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3 | ||
175 | #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL 0x2 | ||
176 | #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL 0x0 | ||
177 | #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN (1 << 8) | ||
178 | #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT 4 | ||
179 | #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK 0xf | ||
180 | |||
181 | #define XUSB_PADCTL_UPHY_PLL_P0_CTL5 0x370 | ||
182 | #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT 16 | ||
183 | #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK 0xff | ||
184 | #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL 0x2a | ||
185 | |||
186 | #define XUSB_PADCTL_UPHY_PLL_P0_CTL8 0x37c | ||
187 | #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE (1 << 31) | ||
188 | #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD (1 << 15) | ||
189 | #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN (1 << 13) | ||
190 | #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN (1 << 12) | ||
191 | |||
192 | #define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(x) (0x460 + (x) * 0x40) | ||
193 | #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT 20 | ||
194 | #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK 0x3 | ||
195 | #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL 0x1 | ||
196 | #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18) | ||
197 | #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13) | ||
198 | |||
199 | #define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860 | ||
200 | |||
201 | #define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864 | ||
202 | |||
203 | #define XUSB_PADCTL_UPHY_PLL_S0_CTL4 0x86c | ||
204 | |||
205 | #define XUSB_PADCTL_UPHY_PLL_S0_CTL5 0x870 | ||
206 | |||
207 | #define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c | ||
208 | |||
209 | #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960 | ||
210 | |||
211 | #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40) | ||
212 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16 | ||
213 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK 0x3 | ||
214 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL 0x2 | ||
215 | |||
216 | #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(x) (0xa64 + (x) * 0x40) | ||
217 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT 0 | ||
218 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK 0xffff | ||
219 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL 0x00fc | ||
220 | |||
221 | #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(x) (0xa68 + (x) * 0x40) | ||
222 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL 0xc0077f1f | ||
223 | |||
224 | #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(x) (0xa6c + (x) * 0x40) | ||
225 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT 16 | ||
226 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK 0xffff | ||
227 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL 0x01c7 | ||
228 | |||
229 | #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(x) (0xa74 + (x) * 0x40) | ||
230 | #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL 0xfcf01368 | ||
231 | |||
232 | struct tegra210_xusb_fuse_calibration { | ||
233 | u32 hs_curr_level[4]; | ||
234 | u32 hs_term_range_adj; | ||
235 | u32 rpd_ctrl; | ||
236 | }; | ||
237 | |||
238 | struct tegra210_xusb_padctl { | ||
239 | struct tegra_xusb_padctl base; | ||
240 | |||
241 | struct tegra210_xusb_fuse_calibration fuse; | ||
242 | }; | ||
243 | |||
244 | static inline struct tegra210_xusb_padctl * | ||
245 | to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl) | ||
246 | { | ||
247 | return container_of(padctl, struct tegra210_xusb_padctl, base); | ||
248 | } | ||
249 | |||
250 | /* must be called under padctl->lock */ | ||
251 | static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) | ||
252 | { | ||
253 | struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie); | ||
254 | unsigned long timeout; | ||
255 | u32 value; | ||
256 | int err; | ||
257 | |||
258 | if (pcie->enable > 0) { | ||
259 | pcie->enable++; | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | err = clk_prepare_enable(pcie->pll); | ||
264 | if (err < 0) | ||
265 | return err; | ||
266 | |||
267 | err = reset_control_deassert(pcie->rst); | ||
268 | if (err < 0) | ||
269 | goto disable; | ||
270 | |||
271 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
272 | value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK << | ||
273 | XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT); | ||
274 | value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL << | ||
275 | XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT; | ||
276 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
277 | |||
278 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL5); | ||
279 | value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK << | ||
280 | XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT); | ||
281 | value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL << | ||
282 | XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT; | ||
283 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL5); | ||
284 | |||
285 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
286 | value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; | ||
287 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
288 | |||
289 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
290 | value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; | ||
291 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
292 | |||
293 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
294 | value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; | ||
295 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
296 | |||
297 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4); | ||
298 | value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK << | ||
299 | XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) | | ||
300 | (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK << | ||
301 | XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT)); | ||
302 | value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL << | ||
303 | XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) | | ||
304 | XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN; | ||
305 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4); | ||
306 | |||
307 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
308 | value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK << | ||
309 | XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) | | ||
310 | (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK << | ||
311 | XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT)); | ||
312 | value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL << | ||
313 | XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT; | ||
314 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
315 | |||
316 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
317 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ; | ||
318 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
319 | |||
320 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
321 | value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK << | ||
322 | XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT); | ||
323 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
324 | |||
325 | usleep_range(10, 20); | ||
326 | |||
327 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4); | ||
328 | value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN; | ||
329 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4); | ||
330 | |||
331 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
332 | value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; | ||
333 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
334 | |||
335 | timeout = jiffies + msecs_to_jiffies(100); | ||
336 | |||
337 | while (time_before(jiffies, timeout)) { | ||
338 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
339 | if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE) | ||
340 | break; | ||
341 | |||
342 | usleep_range(10, 20); | ||
343 | } | ||
344 | |||
345 | if (time_after_eq(jiffies, timeout)) { | ||
346 | err = -ETIMEDOUT; | ||
347 | goto reset; | ||
348 | } | ||
349 | |||
350 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
351 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; | ||
352 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
353 | |||
354 | timeout = jiffies + msecs_to_jiffies(100); | ||
355 | |||
356 | while (time_before(jiffies, timeout)) { | ||
357 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
358 | if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)) | ||
359 | break; | ||
360 | |||
361 | usleep_range(10, 20); | ||
362 | } | ||
363 | |||
364 | if (time_after_eq(jiffies, timeout)) { | ||
365 | err = -ETIMEDOUT; | ||
366 | goto reset; | ||
367 | } | ||
368 | |||
369 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
370 | value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE; | ||
371 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
372 | |||
373 | timeout = jiffies + msecs_to_jiffies(100); | ||
374 | |||
375 | while (time_before(jiffies, timeout)) { | ||
376 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
377 | if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS) | ||
378 | break; | ||
379 | |||
380 | usleep_range(10, 20); | ||
381 | } | ||
382 | |||
383 | if (time_after_eq(jiffies, timeout)) { | ||
384 | err = -ETIMEDOUT; | ||
385 | goto reset; | ||
386 | } | ||
387 | |||
388 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
389 | value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN | | ||
390 | XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; | ||
391 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
392 | |||
393 | timeout = jiffies + msecs_to_jiffies(100); | ||
394 | |||
395 | while (time_before(jiffies, timeout)) { | ||
396 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
397 | if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE) | ||
398 | break; | ||
399 | |||
400 | usleep_range(10, 20); | ||
401 | } | ||
402 | |||
403 | if (time_after_eq(jiffies, timeout)) { | ||
404 | err = -ETIMEDOUT; | ||
405 | goto reset; | ||
406 | } | ||
407 | |||
408 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
409 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN; | ||
410 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
411 | |||
412 | timeout = jiffies + msecs_to_jiffies(100); | ||
413 | |||
414 | while (time_before(jiffies, timeout)) { | ||
415 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
416 | if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)) | ||
417 | break; | ||
418 | |||
419 | usleep_range(10, 20); | ||
420 | } | ||
421 | |||
422 | if (time_after_eq(jiffies, timeout)) { | ||
423 | err = -ETIMEDOUT; | ||
424 | goto reset; | ||
425 | } | ||
426 | |||
427 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
428 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; | ||
429 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
430 | |||
431 | tegra210_xusb_pll_hw_control_enable(); | ||
432 | |||
433 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
434 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; | ||
435 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); | ||
436 | |||
437 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
438 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; | ||
439 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); | ||
440 | |||
441 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
442 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; | ||
443 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); | ||
444 | |||
445 | usleep_range(10, 20); | ||
446 | |||
447 | tegra210_xusb_pll_hw_sequence_start(); | ||
448 | |||
449 | pcie->enable++; | ||
450 | |||
451 | return 0; | ||
452 | |||
453 | reset: | ||
454 | reset_control_assert(pcie->rst); | ||
455 | disable: | ||
456 | clk_disable_unprepare(pcie->pll); | ||
457 | return err; | ||
458 | } | ||
459 | |||
460 | static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl) | ||
461 | { | ||
462 | struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie); | ||
463 | |||
464 | mutex_lock(&padctl->lock); | ||
465 | |||
466 | if (WARN_ON(pcie->enable == 0)) | ||
467 | goto unlock; | ||
468 | |||
469 | if (--pcie->enable > 0) | ||
470 | goto unlock; | ||
471 | |||
472 | reset_control_assert(pcie->rst); | ||
473 | clk_disable_unprepare(pcie->pll); | ||
474 | |||
475 | unlock: | ||
476 | mutex_unlock(&padctl->lock); | ||
477 | } | ||
478 | |||
479 | /* must be called under padctl->lock */ | ||
480 | static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb) | ||
481 | { | ||
482 | struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata); | ||
483 | unsigned long timeout; | ||
484 | u32 value; | ||
485 | int err; | ||
486 | |||
487 | if (sata->enable > 0) { | ||
488 | sata->enable++; | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | err = clk_prepare_enable(sata->pll); | ||
493 | if (err < 0) | ||
494 | return err; | ||
495 | |||
496 | err = reset_control_deassert(sata->rst); | ||
497 | if (err < 0) | ||
498 | goto disable; | ||
499 | |||
500 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
501 | value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK << | ||
502 | XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT); | ||
503 | value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL << | ||
504 | XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT; | ||
505 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
506 | |||
507 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL5); | ||
508 | value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK << | ||
509 | XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT); | ||
510 | value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL << | ||
511 | XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT; | ||
512 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL5); | ||
513 | |||
514 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
515 | value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; | ||
516 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
517 | |||
518 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
519 | value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; | ||
520 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
521 | |||
522 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
523 | value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; | ||
524 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
525 | |||
526 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4); | ||
527 | value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK << | ||
528 | XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) | | ||
529 | (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK << | ||
530 | XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT)); | ||
531 | value |= XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN; | ||
532 | |||
533 | if (usb) | ||
534 | value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL << | ||
535 | XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT); | ||
536 | else | ||
537 | value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL << | ||
538 | XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT); | ||
539 | |||
540 | /* XXX PLL0_XDIGCLK_EN */ | ||
541 | /* | ||
542 | value &= ~(1 << 19); | ||
543 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4); | ||
544 | */ | ||
545 | |||
546 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
547 | value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK << | ||
548 | XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) | | ||
549 | (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK << | ||
550 | XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT)); | ||
551 | |||
552 | if (usb) | ||
553 | value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL << | ||
554 | XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT; | ||
555 | else | ||
556 | value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL << | ||
557 | XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT; | ||
558 | |||
559 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
560 | |||
561 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
562 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ; | ||
563 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
564 | |||
565 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
566 | value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK << | ||
567 | XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT); | ||
568 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
569 | |||
570 | usleep_range(10, 20); | ||
571 | |||
572 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4); | ||
573 | value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN; | ||
574 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4); | ||
575 | |||
576 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
577 | value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; | ||
578 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
579 | |||
580 | timeout = jiffies + msecs_to_jiffies(100); | ||
581 | |||
582 | while (time_before(jiffies, timeout)) { | ||
583 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
584 | if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE) | ||
585 | break; | ||
586 | |||
587 | usleep_range(10, 20); | ||
588 | } | ||
589 | |||
590 | if (time_after_eq(jiffies, timeout)) { | ||
591 | err = -ETIMEDOUT; | ||
592 | goto reset; | ||
593 | } | ||
594 | |||
595 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
596 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; | ||
597 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
598 | |||
599 | timeout = jiffies + msecs_to_jiffies(100); | ||
600 | |||
601 | while (time_before(jiffies, timeout)) { | ||
602 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
603 | if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)) | ||
604 | break; | ||
605 | |||
606 | usleep_range(10, 20); | ||
607 | } | ||
608 | |||
609 | if (time_after_eq(jiffies, timeout)) { | ||
610 | err = -ETIMEDOUT; | ||
611 | goto reset; | ||
612 | } | ||
613 | |||
614 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
615 | value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE; | ||
616 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
617 | |||
618 | timeout = jiffies + msecs_to_jiffies(100); | ||
619 | |||
620 | while (time_before(jiffies, timeout)) { | ||
621 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
622 | if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS) | ||
623 | break; | ||
624 | |||
625 | usleep_range(10, 20); | ||
626 | } | ||
627 | |||
628 | if (time_after_eq(jiffies, timeout)) { | ||
629 | err = -ETIMEDOUT; | ||
630 | goto reset; | ||
631 | } | ||
632 | |||
633 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
634 | value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN | | ||
635 | XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; | ||
636 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
637 | |||
638 | timeout = jiffies + msecs_to_jiffies(100); | ||
639 | |||
640 | while (time_before(jiffies, timeout)) { | ||
641 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
642 | if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE) | ||
643 | break; | ||
644 | |||
645 | usleep_range(10, 20); | ||
646 | } | ||
647 | |||
648 | if (time_after_eq(jiffies, timeout)) { | ||
649 | err = -ETIMEDOUT; | ||
650 | goto reset; | ||
651 | } | ||
652 | |||
653 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
654 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN; | ||
655 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
656 | |||
657 | timeout = jiffies + msecs_to_jiffies(100); | ||
658 | |||
659 | while (time_before(jiffies, timeout)) { | ||
660 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
661 | if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)) | ||
662 | break; | ||
663 | |||
664 | usleep_range(10, 20); | ||
665 | } | ||
666 | |||
667 | if (time_after_eq(jiffies, timeout)) { | ||
668 | err = -ETIMEDOUT; | ||
669 | goto reset; | ||
670 | } | ||
671 | |||
672 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
673 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; | ||
674 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
675 | |||
676 | tegra210_sata_pll_hw_control_enable(); | ||
677 | |||
678 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
679 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; | ||
680 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); | ||
681 | |||
682 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
683 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; | ||
684 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); | ||
685 | |||
686 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
687 | value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; | ||
688 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); | ||
689 | |||
690 | usleep_range(10, 20); | ||
691 | |||
692 | tegra210_sata_pll_hw_sequence_start(); | ||
693 | |||
694 | sata->enable++; | ||
695 | |||
696 | return 0; | ||
697 | |||
698 | reset: | ||
699 | reset_control_assert(sata->rst); | ||
700 | disable: | ||
701 | clk_disable_unprepare(sata->pll); | ||
702 | return err; | ||
703 | } | ||
704 | |||
705 | static void tegra210_sata_uphy_disable(struct tegra_xusb_padctl *padctl) | ||
706 | { | ||
707 | struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata); | ||
708 | |||
709 | mutex_lock(&padctl->lock); | ||
710 | |||
711 | if (WARN_ON(sata->enable == 0)) | ||
712 | goto unlock; | ||
713 | |||
714 | if (--sata->enable > 0) | ||
715 | goto unlock; | ||
716 | |||
717 | reset_control_assert(sata->rst); | ||
718 | clk_disable_unprepare(sata->pll); | ||
719 | |||
720 | unlock: | ||
721 | mutex_unlock(&padctl->lock); | ||
722 | } | ||
723 | |||
724 | static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) | ||
725 | { | ||
726 | u32 value; | ||
727 | |||
728 | mutex_lock(&padctl->lock); | ||
729 | |||
730 | if (padctl->enable++ > 0) | ||
731 | goto out; | ||
732 | |||
733 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
734 | value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; | ||
735 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
736 | |||
737 | usleep_range(100, 200); | ||
738 | |||
739 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
740 | value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
741 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
742 | |||
743 | usleep_range(100, 200); | ||
744 | |||
745 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
746 | value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; | ||
747 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
748 | |||
749 | out: | ||
750 | mutex_unlock(&padctl->lock); | ||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) | ||
755 | { | ||
756 | u32 value; | ||
757 | |||
758 | mutex_lock(&padctl->lock); | ||
759 | |||
760 | if (WARN_ON(padctl->enable == 0)) | ||
761 | goto out; | ||
762 | |||
763 | if (--padctl->enable > 0) | ||
764 | goto out; | ||
765 | |||
766 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
767 | value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; | ||
768 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
769 | |||
770 | usleep_range(100, 200); | ||
771 | |||
772 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
773 | value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
774 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
775 | |||
776 | usleep_range(100, 200); | ||
777 | |||
778 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
779 | value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; | ||
780 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
781 | |||
782 | out: | ||
783 | mutex_unlock(&padctl->lock); | ||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl, | ||
788 | unsigned int index, bool idle) | ||
789 | { | ||
790 | u32 value; | ||
791 | |||
792 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
793 | |||
794 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 | | ||
795 | XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 | | ||
796 | XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE); | ||
797 | |||
798 | if (idle) | ||
799 | value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 | | ||
800 | XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 | | ||
801 | XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE; | ||
802 | else | ||
803 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 | | ||
804 | XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 | | ||
805 | XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE); | ||
806 | |||
807 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl, | ||
813 | unsigned int index, bool enable) | ||
814 | { | ||
815 | struct tegra_xusb_port *port; | ||
816 | struct tegra_xusb_lane *lane; | ||
817 | u32 value, offset; | ||
818 | |||
819 | port = tegra_xusb_find_port(padctl, "usb3", index); | ||
820 | if (!port) | ||
821 | return -ENODEV; | ||
822 | |||
823 | lane = port->lane; | ||
824 | |||
825 | if (lane->pad == padctl->pcie) | ||
826 | offset = XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(lane->index); | ||
827 | else | ||
828 | offset = XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1; | ||
829 | |||
830 | value = padctl_readl(padctl, offset); | ||
831 | |||
832 | value &= ~((XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK << | ||
833 | XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) | | ||
834 | XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN | | ||
835 | XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD); | ||
836 | |||
837 | if (!enable) { | ||
838 | value |= (XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL << | ||
839 | XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) | | ||
840 | XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN | | ||
841 | XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD; | ||
842 | } | ||
843 | |||
844 | padctl_writel(padctl, value, offset); | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | #define TEGRA210_LANE(_name, _offset, _shift, _mask, _type) \ | ||
850 | { \ | ||
851 | .name = _name, \ | ||
852 | .offset = _offset, \ | ||
853 | .shift = _shift, \ | ||
854 | .mask = _mask, \ | ||
855 | .num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \ | ||
856 | .funcs = tegra210_##_type##_functions, \ | ||
857 | } | ||
858 | |||
859 | static const char *tegra210_usb2_functions[] = { | ||
860 | "snps", | ||
861 | "xusb", | ||
862 | "uart" | ||
863 | }; | ||
864 | |||
865 | static const struct tegra_xusb_lane_soc tegra210_usb2_lanes[] = { | ||
866 | TEGRA210_LANE("usb2-0", 0x004, 0, 0x3, usb2), | ||
867 | TEGRA210_LANE("usb2-1", 0x004, 2, 0x3, usb2), | ||
868 | TEGRA210_LANE("usb2-2", 0x004, 4, 0x3, usb2), | ||
869 | TEGRA210_LANE("usb2-3", 0x004, 6, 0x3, usb2), | ||
870 | }; | ||
871 | |||
872 | static struct tegra_xusb_lane * | ||
873 | tegra210_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
874 | unsigned int index) | ||
875 | { | ||
876 | struct tegra_xusb_usb2_lane *usb2; | ||
877 | int err; | ||
878 | |||
879 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
880 | if (!usb2) | ||
881 | return ERR_PTR(-ENOMEM); | ||
882 | |||
883 | INIT_LIST_HEAD(&usb2->base.list); | ||
884 | usb2->base.soc = &pad->soc->lanes[index]; | ||
885 | usb2->base.index = index; | ||
886 | usb2->base.pad = pad; | ||
887 | usb2->base.np = np; | ||
888 | |||
889 | err = tegra_xusb_lane_parse_dt(&usb2->base, np); | ||
890 | if (err < 0) { | ||
891 | kfree(usb2); | ||
892 | return ERR_PTR(err); | ||
893 | } | ||
894 | |||
895 | return &usb2->base; | ||
896 | } | ||
897 | |||
898 | static void tegra210_usb2_lane_remove(struct tegra_xusb_lane *lane) | ||
899 | { | ||
900 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
901 | |||
902 | kfree(usb2); | ||
903 | } | ||
904 | |||
905 | static const struct tegra_xusb_lane_ops tegra210_usb2_lane_ops = { | ||
906 | .probe = tegra210_usb2_lane_probe, | ||
907 | .remove = tegra210_usb2_lane_remove, | ||
908 | }; | ||
909 | |||
910 | static int tegra210_usb2_phy_init(struct phy *phy) | ||
911 | { | ||
912 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
913 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
914 | u32 value; | ||
915 | |||
916 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); | ||
917 | value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK << | ||
918 | XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT); | ||
919 | value |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB << | ||
920 | XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT; | ||
921 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); | ||
922 | |||
923 | return tegra210_xusb_padctl_enable(padctl); | ||
924 | } | ||
925 | |||
926 | static int tegra210_usb2_phy_exit(struct phy *phy) | ||
927 | { | ||
928 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
929 | |||
930 | return tegra210_xusb_padctl_disable(lane->pad->padctl); | ||
931 | } | ||
932 | |||
933 | static int tegra210_usb2_phy_power_on(struct phy *phy) | ||
934 | { | ||
935 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
936 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
937 | struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); | ||
938 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
939 | struct tegra210_xusb_padctl *priv; | ||
940 | struct tegra_xusb_usb2_port *port; | ||
941 | unsigned int index = lane->index; | ||
942 | u32 value; | ||
943 | int err; | ||
944 | |||
945 | port = tegra_xusb_find_usb2_port(padctl, index); | ||
946 | if (!port) { | ||
947 | dev_err(&phy->dev, "no port found for USB2 lane %u\n", index); | ||
948 | return -ENODEV; | ||
949 | } | ||
950 | |||
951 | priv = to_tegra210_xusb_padctl(padctl); | ||
952 | |||
953 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
954 | value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK << | ||
955 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | | ||
956 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK << | ||
957 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT)); | ||
958 | value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL << | ||
959 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT); | ||
960 | |||
961 | if (tegra_sku_info.revision < TEGRA_REVISION_A02) | ||
962 | value |= | ||
963 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL << | ||
964 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT); | ||
965 | |||
966 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
967 | |||
968 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); | ||
969 | value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index); | ||
970 | value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index); | ||
971 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); | ||
972 | |||
973 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
974 | value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK << | ||
975 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) | | ||
976 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD | | ||
977 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 | | ||
978 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI); | ||
979 | value |= (priv->fuse.hs_curr_level[index] + | ||
980 | usb2->hs_curr_level_offset) << | ||
981 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT; | ||
982 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
983 | |||
984 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
985 | value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK << | ||
986 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | | ||
987 | (XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK << | ||
988 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT) | | ||
989 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR | | ||
990 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD | | ||
991 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD); | ||
992 | value |= (priv->fuse.hs_term_range_adj << | ||
993 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | | ||
994 | (priv->fuse.rpd_ctrl << | ||
995 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT); | ||
996 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
997 | |||
998 | value = padctl_readl(padctl, | ||
999 | XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index)); | ||
1000 | value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK << | ||
1001 | XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT); | ||
1002 | value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18; | ||
1003 | padctl_writel(padctl, value, | ||
1004 | XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index)); | ||
1005 | |||
1006 | err = regulator_enable(port->supply); | ||
1007 | if (err) | ||
1008 | return err; | ||
1009 | |||
1010 | mutex_lock(&padctl->lock); | ||
1011 | |||
1012 | if (pad->enable > 0) { | ||
1013 | pad->enable++; | ||
1014 | mutex_unlock(&padctl->lock); | ||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | err = clk_prepare_enable(pad->clk); | ||
1019 | if (err) | ||
1020 | goto disable_regulator; | ||
1021 | |||
1022 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
1023 | value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK << | ||
1024 | XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | | ||
1025 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK << | ||
1026 | XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT)); | ||
1027 | value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL << | ||
1028 | XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | | ||
1029 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL << | ||
1030 | XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT); | ||
1031 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
1032 | |||
1033 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
1034 | value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; | ||
1035 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
1036 | |||
1037 | udelay(1); | ||
1038 | |||
1039 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
1040 | value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK; | ||
1041 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
1042 | |||
1043 | udelay(50); | ||
1044 | |||
1045 | clk_disable_unprepare(pad->clk); | ||
1046 | |||
1047 | pad->enable++; | ||
1048 | mutex_unlock(&padctl->lock); | ||
1049 | |||
1050 | return 0; | ||
1051 | |||
1052 | disable_regulator: | ||
1053 | regulator_disable(port->supply); | ||
1054 | mutex_unlock(&padctl->lock); | ||
1055 | return err; | ||
1056 | } | ||
1057 | |||
1058 | static int tegra210_usb2_phy_power_off(struct phy *phy) | ||
1059 | { | ||
1060 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1061 | struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); | ||
1062 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1063 | struct tegra_xusb_usb2_port *port; | ||
1064 | u32 value; | ||
1065 | |||
1066 | port = tegra_xusb_find_usb2_port(padctl, lane->index); | ||
1067 | if (!port) { | ||
1068 | dev_err(&phy->dev, "no port found for USB2 lane %u\n", | ||
1069 | lane->index); | ||
1070 | return -ENODEV; | ||
1071 | } | ||
1072 | |||
1073 | mutex_lock(&padctl->lock); | ||
1074 | |||
1075 | if (WARN_ON(pad->enable == 0)) | ||
1076 | goto out; | ||
1077 | |||
1078 | if (--pad->enable > 0) | ||
1079 | goto out; | ||
1080 | |||
1081 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
1082 | value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; | ||
1083 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
1084 | |||
1085 | out: | ||
1086 | regulator_disable(port->supply); | ||
1087 | mutex_unlock(&padctl->lock); | ||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | static const struct phy_ops tegra210_usb2_phy_ops = { | ||
1092 | .init = tegra210_usb2_phy_init, | ||
1093 | .exit = tegra210_usb2_phy_exit, | ||
1094 | .power_on = tegra210_usb2_phy_power_on, | ||
1095 | .power_off = tegra210_usb2_phy_power_off, | ||
1096 | .owner = THIS_MODULE, | ||
1097 | }; | ||
1098 | |||
1099 | static struct tegra_xusb_pad * | ||
1100 | tegra210_usb2_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1101 | const struct tegra_xusb_pad_soc *soc, | ||
1102 | struct device_node *np) | ||
1103 | { | ||
1104 | struct tegra_xusb_usb2_pad *usb2; | ||
1105 | struct tegra_xusb_pad *pad; | ||
1106 | int err; | ||
1107 | |||
1108 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
1109 | if (!usb2) | ||
1110 | return ERR_PTR(-ENOMEM); | ||
1111 | |||
1112 | pad = &usb2->base; | ||
1113 | pad->ops = &tegra210_usb2_lane_ops; | ||
1114 | pad->soc = soc; | ||
1115 | |||
1116 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1117 | if (err < 0) { | ||
1118 | kfree(usb2); | ||
1119 | goto out; | ||
1120 | } | ||
1121 | |||
1122 | usb2->clk = devm_clk_get(&pad->dev, "trk"); | ||
1123 | if (IS_ERR(usb2->clk)) { | ||
1124 | err = PTR_ERR(usb2->clk); | ||
1125 | dev_err(&pad->dev, "failed to get trk clock: %d\n", err); | ||
1126 | goto unregister; | ||
1127 | } | ||
1128 | |||
1129 | err = tegra_xusb_pad_register(pad, &tegra210_usb2_phy_ops); | ||
1130 | if (err < 0) | ||
1131 | goto unregister; | ||
1132 | |||
1133 | dev_set_drvdata(&pad->dev, pad); | ||
1134 | |||
1135 | return pad; | ||
1136 | |||
1137 | unregister: | ||
1138 | device_unregister(&pad->dev); | ||
1139 | out: | ||
1140 | return ERR_PTR(err); | ||
1141 | } | ||
1142 | |||
1143 | static void tegra210_usb2_pad_remove(struct tegra_xusb_pad *pad) | ||
1144 | { | ||
1145 | struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); | ||
1146 | |||
1147 | kfree(usb2); | ||
1148 | } | ||
1149 | |||
1150 | static const struct tegra_xusb_pad_ops tegra210_usb2_ops = { | ||
1151 | .probe = tegra210_usb2_pad_probe, | ||
1152 | .remove = tegra210_usb2_pad_remove, | ||
1153 | }; | ||
1154 | |||
1155 | static const struct tegra_xusb_pad_soc tegra210_usb2_pad = { | ||
1156 | .name = "usb2", | ||
1157 | .num_lanes = ARRAY_SIZE(tegra210_usb2_lanes), | ||
1158 | .lanes = tegra210_usb2_lanes, | ||
1159 | .ops = &tegra210_usb2_ops, | ||
1160 | }; | ||
1161 | |||
1162 | static const char *tegra210_hsic_functions[] = { | ||
1163 | "snps", | ||
1164 | "xusb", | ||
1165 | }; | ||
1166 | |||
1167 | static const struct tegra_xusb_lane_soc tegra210_hsic_lanes[] = { | ||
1168 | TEGRA210_LANE("hsic-0", 0x004, 14, 0x1, hsic), | ||
1169 | }; | ||
1170 | |||
1171 | static struct tegra_xusb_lane * | ||
1172 | tegra210_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
1173 | unsigned int index) | ||
1174 | { | ||
1175 | struct tegra_xusb_hsic_lane *hsic; | ||
1176 | int err; | ||
1177 | |||
1178 | hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); | ||
1179 | if (!hsic) | ||
1180 | return ERR_PTR(-ENOMEM); | ||
1181 | |||
1182 | INIT_LIST_HEAD(&hsic->base.list); | ||
1183 | hsic->base.soc = &pad->soc->lanes[index]; | ||
1184 | hsic->base.index = index; | ||
1185 | hsic->base.pad = pad; | ||
1186 | hsic->base.np = np; | ||
1187 | |||
1188 | err = tegra_xusb_lane_parse_dt(&hsic->base, np); | ||
1189 | if (err < 0) { | ||
1190 | kfree(hsic); | ||
1191 | return ERR_PTR(err); | ||
1192 | } | ||
1193 | |||
1194 | return &hsic->base; | ||
1195 | } | ||
1196 | |||
1197 | static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane) | ||
1198 | { | ||
1199 | struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); | ||
1200 | |||
1201 | kfree(hsic); | ||
1202 | } | ||
1203 | |||
1204 | static const struct tegra_xusb_lane_ops tegra210_hsic_lane_ops = { | ||
1205 | .probe = tegra210_hsic_lane_probe, | ||
1206 | .remove = tegra210_hsic_lane_remove, | ||
1207 | }; | ||
1208 | |||
1209 | static int tegra210_hsic_phy_init(struct phy *phy) | ||
1210 | { | ||
1211 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1212 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1213 | u32 value; | ||
1214 | |||
1215 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); | ||
1216 | value &= ~(XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK << | ||
1217 | XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT); | ||
1218 | value |= XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB << | ||
1219 | XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT; | ||
1220 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); | ||
1221 | |||
1222 | return tegra210_xusb_padctl_enable(padctl); | ||
1223 | } | ||
1224 | |||
1225 | static int tegra210_hsic_phy_exit(struct phy *phy) | ||
1226 | { | ||
1227 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1228 | |||
1229 | return tegra210_xusb_padctl_disable(lane->pad->padctl); | ||
1230 | } | ||
1231 | |||
1232 | static int tegra210_hsic_phy_power_on(struct phy *phy) | ||
1233 | { | ||
1234 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1235 | struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); | ||
1236 | struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); | ||
1237 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1238 | struct tegra210_xusb_padctl *priv; | ||
1239 | unsigned int index = lane->index; | ||
1240 | u32 value; | ||
1241 | int err; | ||
1242 | |||
1243 | priv = to_tegra210_xusb_padctl(padctl); | ||
1244 | |||
1245 | err = regulator_enable(pad->supply); | ||
1246 | if (err) | ||
1247 | return err; | ||
1248 | |||
1249 | padctl_writel(padctl, hsic->strobe_trim, | ||
1250 | XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL); | ||
1251 | |||
1252 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
1253 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK << | ||
1254 | XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT); | ||
1255 | value |= (hsic->tx_rtune_p << | ||
1256 | XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT); | ||
1257 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
1258 | |||
1259 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index)); | ||
1260 | value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK << | ||
1261 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | | ||
1262 | (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK << | ||
1263 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT)); | ||
1264 | value |= (hsic->rx_strobe_trim << | ||
1265 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | | ||
1266 | (hsic->rx_data_trim << | ||
1267 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT); | ||
1268 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index)); | ||
1269 | |||
1270 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
1271 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 | | ||
1272 | XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 | | ||
1273 | XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE | | ||
1274 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 | | ||
1275 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 | | ||
1276 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE | | ||
1277 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 | | ||
1278 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 | | ||
1279 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE | | ||
1280 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 | | ||
1281 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 | | ||
1282 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE); | ||
1283 | value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 | | ||
1284 | XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 | | ||
1285 | XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE; | ||
1286 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
1287 | |||
1288 | err = clk_prepare_enable(pad->clk); | ||
1289 | if (err) | ||
1290 | goto disable; | ||
1291 | |||
1292 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL); | ||
1293 | value &= ~((XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK << | ||
1294 | XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) | | ||
1295 | (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK << | ||
1296 | XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT)); | ||
1297 | value |= (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL << | ||
1298 | XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) | | ||
1299 | (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL << | ||
1300 | XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT); | ||
1301 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL); | ||
1302 | |||
1303 | udelay(1); | ||
1304 | |||
1305 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL); | ||
1306 | value &= ~XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK; | ||
1307 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL); | ||
1308 | |||
1309 | udelay(50); | ||
1310 | |||
1311 | clk_disable_unprepare(pad->clk); | ||
1312 | |||
1313 | return 0; | ||
1314 | |||
1315 | disable: | ||
1316 | regulator_disable(pad->supply); | ||
1317 | return err; | ||
1318 | } | ||
1319 | |||
1320 | static int tegra210_hsic_phy_power_off(struct phy *phy) | ||
1321 | { | ||
1322 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1323 | struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); | ||
1324 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1325 | unsigned int index = lane->index; | ||
1326 | u32 value; | ||
1327 | |||
1328 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
1329 | value |= XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 | | ||
1330 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 | | ||
1331 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE | | ||
1332 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 | | ||
1333 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 | | ||
1334 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE | | ||
1335 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 | | ||
1336 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 | | ||
1337 | XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE; | ||
1338 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
1339 | |||
1340 | regulator_disable(pad->supply); | ||
1341 | |||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | static const struct phy_ops tegra210_hsic_phy_ops = { | ||
1346 | .init = tegra210_hsic_phy_init, | ||
1347 | .exit = tegra210_hsic_phy_exit, | ||
1348 | .power_on = tegra210_hsic_phy_power_on, | ||
1349 | .power_off = tegra210_hsic_phy_power_off, | ||
1350 | .owner = THIS_MODULE, | ||
1351 | }; | ||
1352 | |||
1353 | static struct tegra_xusb_pad * | ||
1354 | tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1355 | const struct tegra_xusb_pad_soc *soc, | ||
1356 | struct device_node *np) | ||
1357 | { | ||
1358 | struct tegra_xusb_hsic_pad *hsic; | ||
1359 | struct tegra_xusb_pad *pad; | ||
1360 | int err; | ||
1361 | |||
1362 | hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); | ||
1363 | if (!hsic) | ||
1364 | return ERR_PTR(-ENOMEM); | ||
1365 | |||
1366 | pad = &hsic->base; | ||
1367 | pad->ops = &tegra210_hsic_lane_ops; | ||
1368 | pad->soc = soc; | ||
1369 | |||
1370 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1371 | if (err < 0) { | ||
1372 | kfree(hsic); | ||
1373 | goto out; | ||
1374 | } | ||
1375 | |||
1376 | hsic->clk = devm_clk_get(&pad->dev, "trk"); | ||
1377 | if (IS_ERR(hsic->clk)) { | ||
1378 | err = PTR_ERR(hsic->clk); | ||
1379 | dev_err(&pad->dev, "failed to get trk clock: %d\n", err); | ||
1380 | goto unregister; | ||
1381 | } | ||
1382 | |||
1383 | err = tegra_xusb_pad_register(pad, &tegra210_hsic_phy_ops); | ||
1384 | if (err < 0) | ||
1385 | goto unregister; | ||
1386 | |||
1387 | dev_set_drvdata(&pad->dev, pad); | ||
1388 | |||
1389 | return pad; | ||
1390 | |||
1391 | unregister: | ||
1392 | device_unregister(&pad->dev); | ||
1393 | out: | ||
1394 | return ERR_PTR(err); | ||
1395 | } | ||
1396 | |||
1397 | static void tegra210_hsic_pad_remove(struct tegra_xusb_pad *pad) | ||
1398 | { | ||
1399 | struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad); | ||
1400 | |||
1401 | kfree(hsic); | ||
1402 | } | ||
1403 | |||
1404 | static const struct tegra_xusb_pad_ops tegra210_hsic_ops = { | ||
1405 | .probe = tegra210_hsic_pad_probe, | ||
1406 | .remove = tegra210_hsic_pad_remove, | ||
1407 | }; | ||
1408 | |||
1409 | static const struct tegra_xusb_pad_soc tegra210_hsic_pad = { | ||
1410 | .name = "hsic", | ||
1411 | .num_lanes = ARRAY_SIZE(tegra210_hsic_lanes), | ||
1412 | .lanes = tegra210_hsic_lanes, | ||
1413 | .ops = &tegra210_hsic_ops, | ||
1414 | }; | ||
1415 | |||
1416 | static const char *tegra210_pcie_functions[] = { | ||
1417 | "pcie-x1", | ||
1418 | "usb3-ss", | ||
1419 | "sata", | ||
1420 | "pcie-x4", | ||
1421 | }; | ||
1422 | |||
1423 | static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = { | ||
1424 | TEGRA210_LANE("pcie-0", 0x028, 12, 0x3, pcie), | ||
1425 | TEGRA210_LANE("pcie-1", 0x028, 14, 0x3, pcie), | ||
1426 | TEGRA210_LANE("pcie-2", 0x028, 16, 0x3, pcie), | ||
1427 | TEGRA210_LANE("pcie-3", 0x028, 18, 0x3, pcie), | ||
1428 | TEGRA210_LANE("pcie-4", 0x028, 20, 0x3, pcie), | ||
1429 | TEGRA210_LANE("pcie-5", 0x028, 22, 0x3, pcie), | ||
1430 | TEGRA210_LANE("pcie-6", 0x028, 24, 0x3, pcie), | ||
1431 | }; | ||
1432 | |||
1433 | static struct tegra_xusb_lane * | ||
1434 | tegra210_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
1435 | unsigned int index) | ||
1436 | { | ||
1437 | struct tegra_xusb_pcie_lane *pcie; | ||
1438 | int err; | ||
1439 | |||
1440 | pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); | ||
1441 | if (!pcie) | ||
1442 | return ERR_PTR(-ENOMEM); | ||
1443 | |||
1444 | INIT_LIST_HEAD(&pcie->base.list); | ||
1445 | pcie->base.soc = &pad->soc->lanes[index]; | ||
1446 | pcie->base.index = index; | ||
1447 | pcie->base.pad = pad; | ||
1448 | pcie->base.np = np; | ||
1449 | |||
1450 | err = tegra_xusb_lane_parse_dt(&pcie->base, np); | ||
1451 | if (err < 0) { | ||
1452 | kfree(pcie); | ||
1453 | return ERR_PTR(err); | ||
1454 | } | ||
1455 | |||
1456 | return &pcie->base; | ||
1457 | } | ||
1458 | |||
1459 | static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane) | ||
1460 | { | ||
1461 | struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane); | ||
1462 | |||
1463 | kfree(pcie); | ||
1464 | } | ||
1465 | |||
1466 | static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = { | ||
1467 | .probe = tegra210_pcie_lane_probe, | ||
1468 | .remove = tegra210_pcie_lane_remove, | ||
1469 | }; | ||
1470 | |||
1471 | static int tegra210_pcie_phy_init(struct phy *phy) | ||
1472 | { | ||
1473 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1474 | |||
1475 | return tegra210_xusb_padctl_enable(lane->pad->padctl); | ||
1476 | } | ||
1477 | |||
1478 | static int tegra210_pcie_phy_exit(struct phy *phy) | ||
1479 | { | ||
1480 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1481 | |||
1482 | return tegra210_xusb_padctl_disable(lane->pad->padctl); | ||
1483 | } | ||
1484 | |||
1485 | static int tegra210_pcie_phy_power_on(struct phy *phy) | ||
1486 | { | ||
1487 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1488 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1489 | u32 value; | ||
1490 | int err; | ||
1491 | |||
1492 | mutex_lock(&padctl->lock); | ||
1493 | |||
1494 | err = tegra210_pex_uphy_enable(padctl); | ||
1495 | if (err < 0) | ||
1496 | goto unlock; | ||
1497 | |||
1498 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1499 | value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); | ||
1500 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1501 | |||
1502 | unlock: | ||
1503 | mutex_unlock(&padctl->lock); | ||
1504 | return err; | ||
1505 | } | ||
1506 | |||
1507 | static int tegra210_pcie_phy_power_off(struct phy *phy) | ||
1508 | { | ||
1509 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1510 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1511 | u32 value; | ||
1512 | |||
1513 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1514 | value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); | ||
1515 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1516 | |||
1517 | tegra210_pex_uphy_disable(padctl); | ||
1518 | |||
1519 | return 0; | ||
1520 | } | ||
1521 | |||
1522 | static const struct phy_ops tegra210_pcie_phy_ops = { | ||
1523 | .init = tegra210_pcie_phy_init, | ||
1524 | .exit = tegra210_pcie_phy_exit, | ||
1525 | .power_on = tegra210_pcie_phy_power_on, | ||
1526 | .power_off = tegra210_pcie_phy_power_off, | ||
1527 | .owner = THIS_MODULE, | ||
1528 | }; | ||
1529 | |||
1530 | static struct tegra_xusb_pad * | ||
1531 | tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1532 | const struct tegra_xusb_pad_soc *soc, | ||
1533 | struct device_node *np) | ||
1534 | { | ||
1535 | struct tegra_xusb_pcie_pad *pcie; | ||
1536 | struct tegra_xusb_pad *pad; | ||
1537 | int err; | ||
1538 | |||
1539 | pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); | ||
1540 | if (!pcie) | ||
1541 | return ERR_PTR(-ENOMEM); | ||
1542 | |||
1543 | pad = &pcie->base; | ||
1544 | pad->ops = &tegra210_pcie_lane_ops; | ||
1545 | pad->soc = soc; | ||
1546 | |||
1547 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1548 | if (err < 0) { | ||
1549 | kfree(pcie); | ||
1550 | goto out; | ||
1551 | } | ||
1552 | |||
1553 | pcie->pll = devm_clk_get(&pad->dev, "pll"); | ||
1554 | if (IS_ERR(pcie->pll)) { | ||
1555 | err = PTR_ERR(pcie->pll); | ||
1556 | dev_err(&pad->dev, "failed to get PLL: %d\n", err); | ||
1557 | goto unregister; | ||
1558 | } | ||
1559 | |||
1560 | pcie->rst = devm_reset_control_get(&pad->dev, "phy"); | ||
1561 | if (IS_ERR(pcie->rst)) { | ||
1562 | err = PTR_ERR(pcie->rst); | ||
1563 | dev_err(&pad->dev, "failed to get PCIe pad reset: %d\n", err); | ||
1564 | goto unregister; | ||
1565 | } | ||
1566 | |||
1567 | err = tegra_xusb_pad_register(pad, &tegra210_pcie_phy_ops); | ||
1568 | if (err < 0) | ||
1569 | goto unregister; | ||
1570 | |||
1571 | dev_set_drvdata(&pad->dev, pad); | ||
1572 | |||
1573 | return pad; | ||
1574 | |||
1575 | unregister: | ||
1576 | device_unregister(&pad->dev); | ||
1577 | out: | ||
1578 | return ERR_PTR(err); | ||
1579 | } | ||
1580 | |||
1581 | static void tegra210_pcie_pad_remove(struct tegra_xusb_pad *pad) | ||
1582 | { | ||
1583 | struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad); | ||
1584 | |||
1585 | kfree(pcie); | ||
1586 | } | ||
1587 | |||
1588 | static const struct tegra_xusb_pad_ops tegra210_pcie_ops = { | ||
1589 | .probe = tegra210_pcie_pad_probe, | ||
1590 | .remove = tegra210_pcie_pad_remove, | ||
1591 | }; | ||
1592 | |||
1593 | static const struct tegra_xusb_pad_soc tegra210_pcie_pad = { | ||
1594 | .name = "pcie", | ||
1595 | .num_lanes = ARRAY_SIZE(tegra210_pcie_lanes), | ||
1596 | .lanes = tegra210_pcie_lanes, | ||
1597 | .ops = &tegra210_pcie_ops, | ||
1598 | }; | ||
1599 | |||
1600 | static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = { | ||
1601 | TEGRA210_LANE("sata-0", 0x028, 30, 0x3, pcie), | ||
1602 | }; | ||
1603 | |||
1604 | static struct tegra_xusb_lane * | ||
1605 | tegra210_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
1606 | unsigned int index) | ||
1607 | { | ||
1608 | struct tegra_xusb_sata_lane *sata; | ||
1609 | int err; | ||
1610 | |||
1611 | sata = kzalloc(sizeof(*sata), GFP_KERNEL); | ||
1612 | if (!sata) | ||
1613 | return ERR_PTR(-ENOMEM); | ||
1614 | |||
1615 | INIT_LIST_HEAD(&sata->base.list); | ||
1616 | sata->base.soc = &pad->soc->lanes[index]; | ||
1617 | sata->base.index = index; | ||
1618 | sata->base.pad = pad; | ||
1619 | sata->base.np = np; | ||
1620 | |||
1621 | err = tegra_xusb_lane_parse_dt(&sata->base, np); | ||
1622 | if (err < 0) { | ||
1623 | kfree(sata); | ||
1624 | return ERR_PTR(err); | ||
1625 | } | ||
1626 | |||
1627 | return &sata->base; | ||
1628 | } | ||
1629 | |||
1630 | static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane) | ||
1631 | { | ||
1632 | struct tegra_xusb_sata_lane *sata = to_sata_lane(lane); | ||
1633 | |||
1634 | kfree(sata); | ||
1635 | } | ||
1636 | |||
1637 | static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = { | ||
1638 | .probe = tegra210_sata_lane_probe, | ||
1639 | .remove = tegra210_sata_lane_remove, | ||
1640 | }; | ||
1641 | |||
1642 | static int tegra210_sata_phy_init(struct phy *phy) | ||
1643 | { | ||
1644 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1645 | |||
1646 | return tegra210_xusb_padctl_enable(lane->pad->padctl); | ||
1647 | } | ||
1648 | |||
1649 | static int tegra210_sata_phy_exit(struct phy *phy) | ||
1650 | { | ||
1651 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1652 | |||
1653 | return tegra210_xusb_padctl_disable(lane->pad->padctl); | ||
1654 | } | ||
1655 | |||
1656 | static int tegra210_sata_phy_power_on(struct phy *phy) | ||
1657 | { | ||
1658 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1659 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1660 | u32 value; | ||
1661 | int err; | ||
1662 | |||
1663 | mutex_lock(&padctl->lock); | ||
1664 | |||
1665 | err = tegra210_sata_uphy_enable(padctl, false); | ||
1666 | if (err < 0) | ||
1667 | goto unlock; | ||
1668 | |||
1669 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1670 | value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); | ||
1671 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1672 | |||
1673 | unlock: | ||
1674 | mutex_unlock(&padctl->lock); | ||
1675 | return err; | ||
1676 | } | ||
1677 | |||
1678 | static int tegra210_sata_phy_power_off(struct phy *phy) | ||
1679 | { | ||
1680 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1681 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1682 | u32 value; | ||
1683 | |||
1684 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1685 | value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); | ||
1686 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1687 | |||
1688 | tegra210_sata_uphy_disable(lane->pad->padctl); | ||
1689 | |||
1690 | return 0; | ||
1691 | } | ||
1692 | |||
1693 | static const struct phy_ops tegra210_sata_phy_ops = { | ||
1694 | .init = tegra210_sata_phy_init, | ||
1695 | .exit = tegra210_sata_phy_exit, | ||
1696 | .power_on = tegra210_sata_phy_power_on, | ||
1697 | .power_off = tegra210_sata_phy_power_off, | ||
1698 | .owner = THIS_MODULE, | ||
1699 | }; | ||
1700 | |||
1701 | static struct tegra_xusb_pad * | ||
1702 | tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1703 | const struct tegra_xusb_pad_soc *soc, | ||
1704 | struct device_node *np) | ||
1705 | { | ||
1706 | struct tegra_xusb_sata_pad *sata; | ||
1707 | struct tegra_xusb_pad *pad; | ||
1708 | int err; | ||
1709 | |||
1710 | sata = kzalloc(sizeof(*sata), GFP_KERNEL); | ||
1711 | if (!sata) | ||
1712 | return ERR_PTR(-ENOMEM); | ||
1713 | |||
1714 | pad = &sata->base; | ||
1715 | pad->ops = &tegra210_sata_lane_ops; | ||
1716 | pad->soc = soc; | ||
1717 | |||
1718 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1719 | if (err < 0) { | ||
1720 | kfree(sata); | ||
1721 | goto out; | ||
1722 | } | ||
1723 | |||
1724 | sata->rst = devm_reset_control_get(&pad->dev, "phy"); | ||
1725 | if (IS_ERR(sata->rst)) { | ||
1726 | err = PTR_ERR(sata->rst); | ||
1727 | dev_err(&pad->dev, "failed to get SATA pad reset: %d\n", err); | ||
1728 | goto unregister; | ||
1729 | } | ||
1730 | |||
1731 | err = tegra_xusb_pad_register(pad, &tegra210_sata_phy_ops); | ||
1732 | if (err < 0) | ||
1733 | goto unregister; | ||
1734 | |||
1735 | dev_set_drvdata(&pad->dev, pad); | ||
1736 | |||
1737 | return pad; | ||
1738 | |||
1739 | unregister: | ||
1740 | device_unregister(&pad->dev); | ||
1741 | out: | ||
1742 | return ERR_PTR(err); | ||
1743 | } | ||
1744 | |||
1745 | static void tegra210_sata_pad_remove(struct tegra_xusb_pad *pad) | ||
1746 | { | ||
1747 | struct tegra_xusb_sata_pad *sata = to_sata_pad(pad); | ||
1748 | |||
1749 | kfree(sata); | ||
1750 | } | ||
1751 | |||
1752 | static const struct tegra_xusb_pad_ops tegra210_sata_ops = { | ||
1753 | .probe = tegra210_sata_pad_probe, | ||
1754 | .remove = tegra210_sata_pad_remove, | ||
1755 | }; | ||
1756 | |||
1757 | static const struct tegra_xusb_pad_soc tegra210_sata_pad = { | ||
1758 | .name = "sata", | ||
1759 | .num_lanes = ARRAY_SIZE(tegra210_sata_lanes), | ||
1760 | .lanes = tegra210_sata_lanes, | ||
1761 | .ops = &tegra210_sata_ops, | ||
1762 | }; | ||
1763 | |||
1764 | static const struct tegra_xusb_pad_soc * const tegra210_pads[] = { | ||
1765 | &tegra210_usb2_pad, | ||
1766 | &tegra210_hsic_pad, | ||
1767 | &tegra210_pcie_pad, | ||
1768 | &tegra210_sata_pad, | ||
1769 | }; | ||
1770 | |||
1771 | static int tegra210_usb2_port_enable(struct tegra_xusb_port *port) | ||
1772 | { | ||
1773 | return 0; | ||
1774 | } | ||
1775 | |||
1776 | static void tegra210_usb2_port_disable(struct tegra_xusb_port *port) | ||
1777 | { | ||
1778 | } | ||
1779 | |||
1780 | static struct tegra_xusb_lane * | ||
1781 | tegra210_usb2_port_map(struct tegra_xusb_port *port) | ||
1782 | { | ||
1783 | return tegra_xusb_find_lane(port->padctl, "usb2", port->index); | ||
1784 | } | ||
1785 | |||
1786 | static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = { | ||
1787 | .enable = tegra210_usb2_port_enable, | ||
1788 | .disable = tegra210_usb2_port_disable, | ||
1789 | .map = tegra210_usb2_port_map, | ||
1790 | }; | ||
1791 | |||
1792 | static int tegra210_hsic_port_enable(struct tegra_xusb_port *port) | ||
1793 | { | ||
1794 | return 0; | ||
1795 | } | ||
1796 | |||
1797 | static void tegra210_hsic_port_disable(struct tegra_xusb_port *port) | ||
1798 | { | ||
1799 | } | ||
1800 | |||
1801 | static struct tegra_xusb_lane * | ||
1802 | tegra210_hsic_port_map(struct tegra_xusb_port *port) | ||
1803 | { | ||
1804 | return tegra_xusb_find_lane(port->padctl, "hsic", port->index); | ||
1805 | } | ||
1806 | |||
1807 | static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = { | ||
1808 | .enable = tegra210_hsic_port_enable, | ||
1809 | .disable = tegra210_hsic_port_disable, | ||
1810 | .map = tegra210_hsic_port_map, | ||
1811 | }; | ||
1812 | |||
1813 | static int tegra210_usb3_port_enable(struct tegra_xusb_port *port) | ||
1814 | { | ||
1815 | struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port); | ||
1816 | struct tegra_xusb_padctl *padctl = port->padctl; | ||
1817 | struct tegra_xusb_lane *lane = usb3->base.lane; | ||
1818 | unsigned int index = port->index; | ||
1819 | u32 value; | ||
1820 | int err; | ||
1821 | |||
1822 | value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); | ||
1823 | |||
1824 | if (!usb3->internal) | ||
1825 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); | ||
1826 | else | ||
1827 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); | ||
1828 | |||
1829 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index); | ||
1830 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port); | ||
1831 | padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); | ||
1832 | |||
1833 | /* | ||
1834 | * TODO: move this code into the PCIe/SATA PHY ->power_on() callbacks | ||
1835 | * and conditionalize based on mux function? This seems to work, but | ||
1836 | * might not be the exact proper sequence. | ||
1837 | */ | ||
1838 | err = regulator_enable(usb3->supply); | ||
1839 | if (err < 0) | ||
1840 | return err; | ||
1841 | |||
1842 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index)); | ||
1843 | value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK << | ||
1844 | XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT); | ||
1845 | value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL << | ||
1846 | XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT; | ||
1847 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index)); | ||
1848 | |||
1849 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index)); | ||
1850 | value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK << | ||
1851 | XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT); | ||
1852 | value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL << | ||
1853 | XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT; | ||
1854 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index)); | ||
1855 | |||
1856 | padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL, | ||
1857 | XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index)); | ||
1858 | |||
1859 | value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index)); | ||
1860 | value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK << | ||
1861 | XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT); | ||
1862 | value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL << | ||
1863 | XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT; | ||
1864 | padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index)); | ||
1865 | |||
1866 | padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL, | ||
1867 | XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index)); | ||
1868 | |||
1869 | if (lane->pad == padctl->sata) | ||
1870 | err = tegra210_sata_uphy_enable(padctl, true); | ||
1871 | else | ||
1872 | err = tegra210_pex_uphy_enable(padctl); | ||
1873 | |||
1874 | if (err) { | ||
1875 | dev_err(&port->dev, "%s: failed to enable UPHY: %d\n", | ||
1876 | __func__, err); | ||
1877 | return err; | ||
1878 | } | ||
1879 | |||
1880 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1881 | value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index); | ||
1882 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1883 | |||
1884 | usleep_range(100, 200); | ||
1885 | |||
1886 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1887 | value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index); | ||
1888 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1889 | |||
1890 | usleep_range(100, 200); | ||
1891 | |||
1892 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1893 | value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index); | ||
1894 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1895 | |||
1896 | return 0; | ||
1897 | } | ||
1898 | |||
1899 | static void tegra210_usb3_port_disable(struct tegra_xusb_port *port) | ||
1900 | { | ||
1901 | struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port); | ||
1902 | struct tegra_xusb_padctl *padctl = port->padctl; | ||
1903 | struct tegra_xusb_lane *lane = port->lane; | ||
1904 | unsigned int index = port->index; | ||
1905 | u32 value; | ||
1906 | |||
1907 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1908 | value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index); | ||
1909 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1910 | |||
1911 | usleep_range(100, 200); | ||
1912 | |||
1913 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1914 | value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index); | ||
1915 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1916 | |||
1917 | usleep_range(250, 350); | ||
1918 | |||
1919 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1920 | value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index); | ||
1921 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); | ||
1922 | |||
1923 | if (lane->pad == padctl->sata) | ||
1924 | tegra210_sata_uphy_disable(padctl); | ||
1925 | else | ||
1926 | tegra210_pex_uphy_disable(padctl); | ||
1927 | |||
1928 | regulator_disable(usb3->supply); | ||
1929 | |||
1930 | value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); | ||
1931 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index); | ||
1932 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, 0x7); | ||
1933 | padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); | ||
1934 | } | ||
1935 | |||
1936 | static const struct tegra_xusb_lane_map tegra210_usb3_map[] = { | ||
1937 | { 0, "pcie", 6 }, | ||
1938 | { 1, "pcie", 5 }, | ||
1939 | { 2, "pcie", 0 }, | ||
1940 | { 2, "pcie", 3 }, | ||
1941 | { 3, "pcie", 4 }, | ||
1942 | { 3, "pcie", 4 }, | ||
1943 | { 0, NULL, 0 } | ||
1944 | }; | ||
1945 | |||
1946 | static struct tegra_xusb_lane * | ||
1947 | tegra210_usb3_port_map(struct tegra_xusb_port *port) | ||
1948 | { | ||
1949 | return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss"); | ||
1950 | } | ||
1951 | |||
1952 | static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { | ||
1953 | .enable = tegra210_usb3_port_enable, | ||
1954 | .disable = tegra210_usb3_port_disable, | ||
1955 | .map = tegra210_usb3_port_map, | ||
1956 | }; | ||
1957 | |||
1958 | static int | ||
1959 | tegra210_xusb_read_fuse_calibration(struct tegra210_xusb_fuse_calibration *fuse) | ||
1960 | { | ||
1961 | unsigned int i; | ||
1962 | u32 value; | ||
1963 | int err; | ||
1964 | |||
1965 | err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); | ||
1966 | if (err < 0) | ||
1967 | return err; | ||
1968 | |||
1969 | for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) { | ||
1970 | fuse->hs_curr_level[i] = | ||
1971 | (value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) & | ||
1972 | FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK; | ||
1973 | } | ||
1974 | |||
1975 | fuse->hs_term_range_adj = | ||
1976 | (value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) & | ||
1977 | FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK; | ||
1978 | |||
1979 | err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value); | ||
1980 | if (err < 0) | ||
1981 | return err; | ||
1982 | |||
1983 | fuse->rpd_ctrl = | ||
1984 | (value >> FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT) & | ||
1985 | FUSE_USB_CALIB_EXT_RPD_CTRL_MASK; | ||
1986 | |||
1987 | return 0; | ||
1988 | } | ||
1989 | |||
1990 | static struct tegra_xusb_padctl * | ||
1991 | tegra210_xusb_padctl_probe(struct device *dev, | ||
1992 | const struct tegra_xusb_padctl_soc *soc) | ||
1993 | { | ||
1994 | struct tegra210_xusb_padctl *padctl; | ||
1995 | int err; | ||
1996 | |||
1997 | padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL); | ||
1998 | if (!padctl) | ||
1999 | return ERR_PTR(-ENOMEM); | ||
2000 | |||
2001 | padctl->base.dev = dev; | ||
2002 | padctl->base.soc = soc; | ||
2003 | |||
2004 | err = tegra210_xusb_read_fuse_calibration(&padctl->fuse); | ||
2005 | if (err < 0) | ||
2006 | return ERR_PTR(err); | ||
2007 | |||
2008 | return &padctl->base; | ||
2009 | } | ||
2010 | |||
2011 | static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl) | ||
2012 | { | ||
2013 | } | ||
2014 | |||
2015 | static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = { | ||
2016 | .probe = tegra210_xusb_padctl_probe, | ||
2017 | .remove = tegra210_xusb_padctl_remove, | ||
2018 | .usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect, | ||
2019 | .hsic_set_idle = tegra210_hsic_set_idle, | ||
2020 | }; | ||
2021 | |||
2022 | const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = { | ||
2023 | .num_pads = ARRAY_SIZE(tegra210_pads), | ||
2024 | .pads = tegra210_pads, | ||
2025 | .ports = { | ||
2026 | .usb2 = { | ||
2027 | .ops = &tegra210_usb2_port_ops, | ||
2028 | .count = 4, | ||
2029 | }, | ||
2030 | .hsic = { | ||
2031 | .ops = &tegra210_hsic_port_ops, | ||
2032 | .count = 1, | ||
2033 | }, | ||
2034 | .usb3 = { | ||
2035 | .ops = &tegra210_usb3_port_ops, | ||
2036 | .count = 4, | ||
2037 | }, | ||
2038 | }, | ||
2039 | .ops = &tegra210_xusb_padctl_ops, | ||
2040 | }; | ||
2041 | EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc); | ||
2042 | |||
2043 | MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); | ||
2044 | MODULE_DESCRIPTION("NVIDIA Tegra 210 XUSB Pad Controller driver"); | ||
2045 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c new file mode 100644 index 000000000000..ec83dfdbc206 --- /dev/null +++ b/drivers/phy/tegra/xusb.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/mailbox_client.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_device.h> | ||
20 | #include <linux/phy/phy.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/regulator/consumer.h> | ||
23 | #include <linux/reset.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | |||
27 | #include <soc/tegra/fuse.h> | ||
28 | |||
29 | #include "xusb.h" | ||
30 | |||
31 | static struct phy *tegra_xusb_pad_of_xlate(struct device *dev, | ||
32 | struct of_phandle_args *args) | ||
33 | { | ||
34 | struct tegra_xusb_pad *pad = dev_get_drvdata(dev); | ||
35 | struct phy *phy = NULL; | ||
36 | unsigned int i; | ||
37 | |||
38 | if (args->args_count != 0) | ||
39 | return ERR_PTR(-EINVAL); | ||
40 | |||
41 | for (i = 0; i < pad->soc->num_lanes; i++) { | ||
42 | if (!pad->lanes[i]) | ||
43 | continue; | ||
44 | |||
45 | if (pad->lanes[i]->dev.of_node == args->np) { | ||
46 | phy = pad->lanes[i]; | ||
47 | break; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if (phy == NULL) | ||
52 | phy = ERR_PTR(-ENODEV); | ||
53 | |||
54 | return phy; | ||
55 | } | ||
56 | |||
57 | static const struct of_device_id tegra_xusb_padctl_of_match[] = { | ||
58 | #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) | ||
59 | { | ||
60 | .compatible = "nvidia,tegra124-xusb-padctl", | ||
61 | .data = &tegra124_xusb_padctl_soc, | ||
62 | }, | ||
63 | #endif | ||
64 | #if defined(CONFIG_ARCH_TEGRA_210_SOC) | ||
65 | { | ||
66 | .compatible = "nvidia,tegra210-xusb-padctl", | ||
67 | .data = &tegra210_xusb_padctl_soc, | ||
68 | }, | ||
69 | #endif | ||
70 | { } | ||
71 | }; | ||
72 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); | ||
73 | |||
74 | static struct device_node * | ||
75 | tegra_xusb_find_pad_node(struct tegra_xusb_padctl *padctl, const char *name) | ||
76 | { | ||
77 | /* | ||
78 | * of_find_node_by_name() drops a reference, so make sure to grab one. | ||
79 | */ | ||
80 | struct device_node *np = of_node_get(padctl->dev->of_node); | ||
81 | |||
82 | np = of_find_node_by_name(np, "pads"); | ||
83 | if (np) | ||
84 | np = of_find_node_by_name(np, name); | ||
85 | |||
86 | return np; | ||
87 | } | ||
88 | |||
89 | static struct device_node * | ||
90 | tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index) | ||
91 | { | ||
92 | /* | ||
93 | * of_find_node_by_name() drops a reference, so make sure to grab one. | ||
94 | */ | ||
95 | struct device_node *np = of_node_get(pad->dev.of_node); | ||
96 | |||
97 | np = of_find_node_by_name(np, "lanes"); | ||
98 | if (!np) | ||
99 | return NULL; | ||
100 | |||
101 | return of_find_node_by_name(np, pad->soc->lanes[index].name); | ||
102 | } | ||
103 | |||
104 | int tegra_xusb_lane_lookup_function(struct tegra_xusb_lane *lane, | ||
105 | const char *function) | ||
106 | { | ||
107 | unsigned int i; | ||
108 | |||
109 | for (i = 0; i < lane->soc->num_funcs; i++) | ||
110 | if (strcmp(function, lane->soc->funcs[i]) == 0) | ||
111 | return i; | ||
112 | |||
113 | return -EINVAL; | ||
114 | } | ||
115 | |||
116 | int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, | ||
117 | struct device_node *np) | ||
118 | { | ||
119 | struct device *dev = &lane->pad->dev; | ||
120 | const char *function; | ||
121 | int err; | ||
122 | |||
123 | err = of_property_read_string(np, "nvidia,function", &function); | ||
124 | if (err < 0) | ||
125 | return err; | ||
126 | |||
127 | err = tegra_xusb_lane_lookup_function(lane, function); | ||
128 | if (err < 0) { | ||
129 | dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n", | ||
130 | function, np->name); | ||
131 | return err; | ||
132 | } | ||
133 | |||
134 | lane->function = err; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static void tegra_xusb_lane_destroy(struct phy *phy) | ||
140 | { | ||
141 | if (phy) { | ||
142 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
143 | |||
144 | lane->pad->ops->remove(lane); | ||
145 | phy_destroy(phy); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void tegra_xusb_pad_release(struct device *dev) | ||
150 | { | ||
151 | struct tegra_xusb_pad *pad = to_tegra_xusb_pad(dev); | ||
152 | |||
153 | pad->soc->ops->remove(pad); | ||
154 | } | ||
155 | |||
156 | static struct device_type tegra_xusb_pad_type = { | ||
157 | .release = tegra_xusb_pad_release, | ||
158 | }; | ||
159 | |||
160 | int tegra_xusb_pad_init(struct tegra_xusb_pad *pad, | ||
161 | struct tegra_xusb_padctl *padctl, | ||
162 | struct device_node *np) | ||
163 | { | ||
164 | int err; | ||
165 | |||
166 | device_initialize(&pad->dev); | ||
167 | INIT_LIST_HEAD(&pad->list); | ||
168 | pad->dev.parent = padctl->dev; | ||
169 | pad->dev.type = &tegra_xusb_pad_type; | ||
170 | pad->dev.of_node = np; | ||
171 | pad->padctl = padctl; | ||
172 | |||
173 | err = dev_set_name(&pad->dev, "%s", pad->soc->name); | ||
174 | if (err < 0) | ||
175 | goto unregister; | ||
176 | |||
177 | err = device_add(&pad->dev); | ||
178 | if (err < 0) | ||
179 | goto unregister; | ||
180 | |||
181 | return 0; | ||
182 | |||
183 | unregister: | ||
184 | device_unregister(&pad->dev); | ||
185 | return err; | ||
186 | } | ||
187 | |||
188 | int tegra_xusb_pad_register(struct tegra_xusb_pad *pad, | ||
189 | const struct phy_ops *ops) | ||
190 | { | ||
191 | struct device_node *children; | ||
192 | struct phy *lane; | ||
193 | unsigned int i; | ||
194 | int err; | ||
195 | |||
196 | children = of_find_node_by_name(pad->dev.of_node, "lanes"); | ||
197 | if (!children) | ||
198 | return -ENODEV; | ||
199 | |||
200 | pad->lanes = devm_kcalloc(&pad->dev, pad->soc->num_lanes, sizeof(lane), | ||
201 | GFP_KERNEL); | ||
202 | if (!pad->lanes) { | ||
203 | of_node_put(children); | ||
204 | return -ENOMEM; | ||
205 | } | ||
206 | |||
207 | for (i = 0; i < pad->soc->num_lanes; i++) { | ||
208 | struct device_node *np = tegra_xusb_pad_find_phy_node(pad, i); | ||
209 | struct tegra_xusb_lane *lane; | ||
210 | |||
211 | /* skip disabled lanes */ | ||
212 | if (!np || !of_device_is_available(np)) { | ||
213 | of_node_put(np); | ||
214 | continue; | ||
215 | } | ||
216 | |||
217 | pad->lanes[i] = phy_create(&pad->dev, np, ops); | ||
218 | if (IS_ERR(pad->lanes[i])) { | ||
219 | err = PTR_ERR(pad->lanes[i]); | ||
220 | of_node_put(np); | ||
221 | goto remove; | ||
222 | } | ||
223 | |||
224 | lane = pad->ops->probe(pad, np, i); | ||
225 | if (IS_ERR(lane)) { | ||
226 | phy_destroy(pad->lanes[i]); | ||
227 | err = PTR_ERR(lane); | ||
228 | goto remove; | ||
229 | } | ||
230 | |||
231 | list_add_tail(&lane->list, &pad->padctl->lanes); | ||
232 | phy_set_drvdata(pad->lanes[i], lane); | ||
233 | } | ||
234 | |||
235 | pad->provider = of_phy_provider_register_full(&pad->dev, children, | ||
236 | tegra_xusb_pad_of_xlate); | ||
237 | if (IS_ERR(pad->provider)) { | ||
238 | err = PTR_ERR(pad->provider); | ||
239 | goto remove; | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | |||
244 | remove: | ||
245 | while (i--) | ||
246 | tegra_xusb_lane_destroy(pad->lanes[i]); | ||
247 | |||
248 | of_node_put(children); | ||
249 | |||
250 | return err; | ||
251 | } | ||
252 | |||
253 | void tegra_xusb_pad_unregister(struct tegra_xusb_pad *pad) | ||
254 | { | ||
255 | unsigned int i = pad->soc->num_lanes; | ||
256 | |||
257 | of_phy_provider_unregister(pad->provider); | ||
258 | |||
259 | while (i--) | ||
260 | tegra_xusb_lane_destroy(pad->lanes[i]); | ||
261 | |||
262 | device_unregister(&pad->dev); | ||
263 | } | ||
264 | |||
265 | static struct tegra_xusb_pad * | ||
266 | tegra_xusb_pad_create(struct tegra_xusb_padctl *padctl, | ||
267 | const struct tegra_xusb_pad_soc *soc) | ||
268 | { | ||
269 | struct tegra_xusb_pad *pad; | ||
270 | struct device_node *np; | ||
271 | int err; | ||
272 | |||
273 | np = tegra_xusb_find_pad_node(padctl, soc->name); | ||
274 | if (!np || !of_device_is_available(np)) | ||
275 | return NULL; | ||
276 | |||
277 | pad = soc->ops->probe(padctl, soc, np); | ||
278 | if (IS_ERR(pad)) { | ||
279 | err = PTR_ERR(pad); | ||
280 | dev_err(padctl->dev, "failed to create pad %s: %d\n", | ||
281 | soc->name, err); | ||
282 | return ERR_PTR(err); | ||
283 | } | ||
284 | |||
285 | /* XXX move this into ->probe() to avoid string comparison */ | ||
286 | if (strcmp(soc->name, "pcie") == 0) | ||
287 | padctl->pcie = pad; | ||
288 | |||
289 | if (strcmp(soc->name, "sata") == 0) | ||
290 | padctl->sata = pad; | ||
291 | |||
292 | if (strcmp(soc->name, "usb2") == 0) | ||
293 | padctl->usb2 = pad; | ||
294 | |||
295 | if (strcmp(soc->name, "ulpi") == 0) | ||
296 | padctl->ulpi = pad; | ||
297 | |||
298 | if (strcmp(soc->name, "hsic") == 0) | ||
299 | padctl->hsic = pad; | ||
300 | |||
301 | return pad; | ||
302 | } | ||
303 | |||
304 | static void __tegra_xusb_remove_pads(struct tegra_xusb_padctl *padctl) | ||
305 | { | ||
306 | struct tegra_xusb_pad *pad, *tmp; | ||
307 | |||
308 | list_for_each_entry_safe_reverse(pad, tmp, &padctl->pads, list) { | ||
309 | list_del(&pad->list); | ||
310 | tegra_xusb_pad_unregister(pad); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static void tegra_xusb_remove_pads(struct tegra_xusb_padctl *padctl) | ||
315 | { | ||
316 | mutex_lock(&padctl->lock); | ||
317 | __tegra_xusb_remove_pads(padctl); | ||
318 | mutex_unlock(&padctl->lock); | ||
319 | } | ||
320 | |||
321 | static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane) | ||
322 | { | ||
323 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
324 | const struct tegra_xusb_lane_soc *soc = lane->soc; | ||
325 | u32 value; | ||
326 | |||
327 | /* choose function */ | ||
328 | value = padctl_readl(padctl, soc->offset); | ||
329 | value &= ~(soc->mask << soc->shift); | ||
330 | value |= lane->function << soc->shift; | ||
331 | padctl_writel(padctl, value, soc->offset); | ||
332 | } | ||
333 | |||
334 | static void tegra_xusb_pad_program(struct tegra_xusb_pad *pad) | ||
335 | { | ||
336 | unsigned int i; | ||
337 | |||
338 | for (i = 0; i < pad->soc->num_lanes; i++) { | ||
339 | struct tegra_xusb_lane *lane; | ||
340 | |||
341 | if (pad->lanes[i]) { | ||
342 | lane = phy_get_drvdata(pad->lanes[i]); | ||
343 | tegra_xusb_lane_program(lane); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | static int tegra_xusb_setup_pads(struct tegra_xusb_padctl *padctl) | ||
349 | { | ||
350 | struct tegra_xusb_pad *pad; | ||
351 | unsigned int i; | ||
352 | |||
353 | mutex_lock(&padctl->lock); | ||
354 | |||
355 | for (i = 0; i < padctl->soc->num_pads; i++) { | ||
356 | const struct tegra_xusb_pad_soc *soc = padctl->soc->pads[i]; | ||
357 | int err; | ||
358 | |||
359 | pad = tegra_xusb_pad_create(padctl, soc); | ||
360 | if (IS_ERR(pad)) { | ||
361 | err = PTR_ERR(pad); | ||
362 | dev_err(padctl->dev, "failed to create pad %s: %d\n", | ||
363 | soc->name, err); | ||
364 | __tegra_xusb_remove_pads(padctl); | ||
365 | mutex_unlock(&padctl->lock); | ||
366 | return err; | ||
367 | } | ||
368 | |||
369 | if (!pad) | ||
370 | continue; | ||
371 | |||
372 | list_add_tail(&pad->list, &padctl->pads); | ||
373 | } | ||
374 | |||
375 | list_for_each_entry(pad, &padctl->pads, list) | ||
376 | tegra_xusb_pad_program(pad); | ||
377 | |||
378 | mutex_unlock(&padctl->lock); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane, | ||
383 | const char *function) | ||
384 | { | ||
385 | const char *func = lane->soc->funcs[lane->function]; | ||
386 | |||
387 | return strcmp(function, func) == 0; | ||
388 | } | ||
389 | |||
390 | struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl, | ||
391 | const char *type, | ||
392 | unsigned int index) | ||
393 | { | ||
394 | struct tegra_xusb_lane *lane, *hit = ERR_PTR(-ENODEV); | ||
395 | char *name; | ||
396 | |||
397 | name = kasprintf(GFP_KERNEL, "%s-%u", type, index); | ||
398 | if (!name) | ||
399 | return ERR_PTR(-ENOMEM); | ||
400 | |||
401 | list_for_each_entry(lane, &padctl->lanes, list) { | ||
402 | if (strcmp(lane->soc->name, name) == 0) { | ||
403 | hit = lane; | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | kfree(name); | ||
409 | return hit; | ||
410 | } | ||
411 | |||
412 | struct tegra_xusb_lane * | ||
413 | tegra_xusb_port_find_lane(struct tegra_xusb_port *port, | ||
414 | const struct tegra_xusb_lane_map *map, | ||
415 | const char *function) | ||
416 | { | ||
417 | struct tegra_xusb_lane *lane, *match = ERR_PTR(-ENODEV); | ||
418 | |||
419 | for (map = map; map->type; map++) { | ||
420 | if (port->index != map->port) | ||
421 | continue; | ||
422 | |||
423 | lane = tegra_xusb_find_lane(port->padctl, map->type, | ||
424 | map->index); | ||
425 | if (IS_ERR(lane)) | ||
426 | continue; | ||
427 | |||
428 | if (!tegra_xusb_lane_check(lane, function)) | ||
429 | continue; | ||
430 | |||
431 | if (!IS_ERR(match)) | ||
432 | dev_err(&port->dev, "conflicting match: %s-%u / %s\n", | ||
433 | map->type, map->index, match->soc->name); | ||
434 | else | ||
435 | match = lane; | ||
436 | } | ||
437 | |||
438 | return match; | ||
439 | } | ||
440 | |||
441 | static struct device_node * | ||
442 | tegra_xusb_find_port_node(struct tegra_xusb_padctl *padctl, const char *type, | ||
443 | unsigned int index) | ||
444 | { | ||
445 | /* | ||
446 | * of_find_node_by_name() drops a reference, so make sure to grab one. | ||
447 | */ | ||
448 | struct device_node *np = of_node_get(padctl->dev->of_node); | ||
449 | |||
450 | np = of_find_node_by_name(np, "ports"); | ||
451 | if (np) { | ||
452 | char *name; | ||
453 | |||
454 | name = kasprintf(GFP_KERNEL, "%s-%u", type, index); | ||
455 | np = of_find_node_by_name(np, name); | ||
456 | kfree(name); | ||
457 | } | ||
458 | |||
459 | return np; | ||
460 | } | ||
461 | |||
462 | struct tegra_xusb_port * | ||
463 | tegra_xusb_find_port(struct tegra_xusb_padctl *padctl, const char *type, | ||
464 | unsigned int index) | ||
465 | { | ||
466 | struct tegra_xusb_port *port; | ||
467 | struct device_node *np; | ||
468 | |||
469 | np = tegra_xusb_find_port_node(padctl, type, index); | ||
470 | if (!np) | ||
471 | return NULL; | ||
472 | |||
473 | list_for_each_entry(port, &padctl->ports, list) { | ||
474 | if (np == port->dev.of_node) { | ||
475 | of_node_put(np); | ||
476 | return port; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | of_node_put(np); | ||
481 | |||
482 | return NULL; | ||
483 | } | ||
484 | |||
485 | struct tegra_xusb_usb2_port * | ||
486 | tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl, unsigned int index) | ||
487 | { | ||
488 | struct tegra_xusb_port *port; | ||
489 | |||
490 | port = tegra_xusb_find_port(padctl, "usb2", index); | ||
491 | if (port) | ||
492 | return to_usb2_port(port); | ||
493 | |||
494 | return NULL; | ||
495 | } | ||
496 | |||
497 | struct tegra_xusb_usb3_port * | ||
498 | tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, unsigned int index) | ||
499 | { | ||
500 | struct tegra_xusb_port *port; | ||
501 | |||
502 | port = tegra_xusb_find_port(padctl, "usb3", index); | ||
503 | if (port) | ||
504 | return to_usb3_port(port); | ||
505 | |||
506 | return NULL; | ||
507 | } | ||
508 | |||
509 | static void tegra_xusb_port_release(struct device *dev) | ||
510 | { | ||
511 | } | ||
512 | |||
513 | static struct device_type tegra_xusb_port_type = { | ||
514 | .release = tegra_xusb_port_release, | ||
515 | }; | ||
516 | |||
517 | static int tegra_xusb_port_init(struct tegra_xusb_port *port, | ||
518 | struct tegra_xusb_padctl *padctl, | ||
519 | struct device_node *np, | ||
520 | const char *name, | ||
521 | unsigned int index) | ||
522 | { | ||
523 | int err; | ||
524 | |||
525 | INIT_LIST_HEAD(&port->list); | ||
526 | port->padctl = padctl; | ||
527 | port->index = index; | ||
528 | |||
529 | device_initialize(&port->dev); | ||
530 | port->dev.type = &tegra_xusb_port_type; | ||
531 | port->dev.of_node = of_node_get(np); | ||
532 | port->dev.parent = padctl->dev; | ||
533 | |||
534 | err = dev_set_name(&port->dev, "%s-%u", name, index); | ||
535 | if (err < 0) | ||
536 | goto unregister; | ||
537 | |||
538 | err = device_add(&port->dev); | ||
539 | if (err < 0) | ||
540 | goto unregister; | ||
541 | |||
542 | return 0; | ||
543 | |||
544 | unregister: | ||
545 | device_unregister(&port->dev); | ||
546 | return err; | ||
547 | } | ||
548 | |||
549 | static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) | ||
550 | { | ||
551 | device_unregister(&port->dev); | ||
552 | } | ||
553 | |||
554 | static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) | ||
555 | { | ||
556 | struct tegra_xusb_port *port = &usb2->base; | ||
557 | struct device_node *np = port->dev.of_node; | ||
558 | |||
559 | usb2->internal = of_property_read_bool(np, "nvidia,internal"); | ||
560 | |||
561 | usb2->supply = devm_regulator_get(&port->dev, "vbus"); | ||
562 | if (IS_ERR(usb2->supply)) | ||
563 | return PTR_ERR(usb2->supply); | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl, | ||
569 | unsigned int index) | ||
570 | { | ||
571 | struct tegra_xusb_usb2_port *usb2; | ||
572 | struct device_node *np; | ||
573 | int err = 0; | ||
574 | |||
575 | /* | ||
576 | * USB2 ports don't require additional properties, but if the port is | ||
577 | * marked as disabled there is no reason to register it. | ||
578 | */ | ||
579 | np = tegra_xusb_find_port_node(padctl, "usb2", index); | ||
580 | if (!np || !of_device_is_available(np)) | ||
581 | goto out; | ||
582 | |||
583 | usb2 = devm_kzalloc(padctl->dev, sizeof(*usb2), GFP_KERNEL); | ||
584 | if (!usb2) { | ||
585 | err = -ENOMEM; | ||
586 | goto out; | ||
587 | } | ||
588 | |||
589 | err = tegra_xusb_port_init(&usb2->base, padctl, np, "usb2", index); | ||
590 | if (err < 0) | ||
591 | goto out; | ||
592 | |||
593 | usb2->base.ops = padctl->soc->ports.usb2.ops; | ||
594 | |||
595 | usb2->base.lane = usb2->base.ops->map(&usb2->base); | ||
596 | if (IS_ERR(usb2->base.lane)) { | ||
597 | err = PTR_ERR(usb2->base.lane); | ||
598 | goto out; | ||
599 | } | ||
600 | |||
601 | err = tegra_xusb_usb2_port_parse_dt(usb2); | ||
602 | if (err < 0) { | ||
603 | tegra_xusb_port_unregister(&usb2->base); | ||
604 | goto out; | ||
605 | } | ||
606 | |||
607 | list_add_tail(&usb2->base.list, &padctl->ports); | ||
608 | |||
609 | out: | ||
610 | of_node_put(np); | ||
611 | return err; | ||
612 | } | ||
613 | |||
614 | static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi) | ||
615 | { | ||
616 | struct tegra_xusb_port *port = &ulpi->base; | ||
617 | struct device_node *np = port->dev.of_node; | ||
618 | |||
619 | ulpi->internal = of_property_read_bool(np, "nvidia,internal"); | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl, | ||
625 | unsigned int index) | ||
626 | { | ||
627 | struct tegra_xusb_ulpi_port *ulpi; | ||
628 | struct device_node *np; | ||
629 | int err = 0; | ||
630 | |||
631 | np = tegra_xusb_find_port_node(padctl, "ulpi", index); | ||
632 | if (!np || !of_device_is_available(np)) | ||
633 | goto out; | ||
634 | |||
635 | ulpi = devm_kzalloc(padctl->dev, sizeof(*ulpi), GFP_KERNEL); | ||
636 | if (!ulpi) { | ||
637 | err = -ENOMEM; | ||
638 | goto out; | ||
639 | } | ||
640 | |||
641 | err = tegra_xusb_port_init(&ulpi->base, padctl, np, "ulpi", index); | ||
642 | if (err < 0) | ||
643 | goto out; | ||
644 | |||
645 | ulpi->base.ops = padctl->soc->ports.ulpi.ops; | ||
646 | |||
647 | ulpi->base.lane = ulpi->base.ops->map(&ulpi->base); | ||
648 | if (IS_ERR(ulpi->base.lane)) { | ||
649 | err = PTR_ERR(ulpi->base.lane); | ||
650 | goto out; | ||
651 | } | ||
652 | |||
653 | err = tegra_xusb_ulpi_port_parse_dt(ulpi); | ||
654 | if (err < 0) { | ||
655 | tegra_xusb_port_unregister(&ulpi->base); | ||
656 | goto out; | ||
657 | } | ||
658 | |||
659 | list_add_tail(&ulpi->base.list, &padctl->ports); | ||
660 | |||
661 | out: | ||
662 | of_node_put(np); | ||
663 | return err; | ||
664 | } | ||
665 | |||
666 | static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic) | ||
667 | { | ||
668 | /* XXX */ | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl, | ||
673 | unsigned int index) | ||
674 | { | ||
675 | struct tegra_xusb_hsic_port *hsic; | ||
676 | struct device_node *np; | ||
677 | int err = 0; | ||
678 | |||
679 | np = tegra_xusb_find_port_node(padctl, "hsic", index); | ||
680 | if (!np || !of_device_is_available(np)) | ||
681 | goto out; | ||
682 | |||
683 | hsic = devm_kzalloc(padctl->dev, sizeof(*hsic), GFP_KERNEL); | ||
684 | if (!hsic) { | ||
685 | err = -ENOMEM; | ||
686 | goto out; | ||
687 | } | ||
688 | |||
689 | err = tegra_xusb_port_init(&hsic->base, padctl, np, "hsic", index); | ||
690 | if (err < 0) | ||
691 | goto out; | ||
692 | |||
693 | hsic->base.ops = padctl->soc->ports.hsic.ops; | ||
694 | |||
695 | hsic->base.lane = hsic->base.ops->map(&hsic->base); | ||
696 | if (IS_ERR(hsic->base.lane)) { | ||
697 | err = PTR_ERR(hsic->base.lane); | ||
698 | goto out; | ||
699 | } | ||
700 | |||
701 | err = tegra_xusb_hsic_port_parse_dt(hsic); | ||
702 | if (err < 0) { | ||
703 | tegra_xusb_port_unregister(&hsic->base); | ||
704 | goto out; | ||
705 | } | ||
706 | |||
707 | list_add_tail(&hsic->base.list, &padctl->ports); | ||
708 | |||
709 | out: | ||
710 | of_node_put(np); | ||
711 | return err; | ||
712 | } | ||
713 | |||
714 | static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3) | ||
715 | { | ||
716 | struct tegra_xusb_port *port = &usb3->base; | ||
717 | struct device_node *np = port->dev.of_node; | ||
718 | u32 value; | ||
719 | int err; | ||
720 | |||
721 | err = of_property_read_u32(np, "nvidia,usb2-companion", &value); | ||
722 | if (err < 0) { | ||
723 | dev_err(&port->dev, "failed to read port: %d\n", err); | ||
724 | return err; | ||
725 | } | ||
726 | |||
727 | usb3->port = value; | ||
728 | |||
729 | usb3->internal = of_property_read_bool(np, "nvidia,internal"); | ||
730 | |||
731 | usb3->supply = devm_regulator_get(&port->dev, "vbus"); | ||
732 | if (IS_ERR(usb3->supply)) | ||
733 | return PTR_ERR(usb3->supply); | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl, | ||
739 | unsigned int index) | ||
740 | { | ||
741 | struct tegra_xusb_usb3_port *usb3; | ||
742 | struct device_node *np; | ||
743 | int err = 0; | ||
744 | |||
745 | /* | ||
746 | * If there is no supplemental configuration in the device tree the | ||
747 | * port is unusable. But it is valid to configure only a single port, | ||
748 | * hence return 0 instead of an error to allow ports to be optional. | ||
749 | */ | ||
750 | np = tegra_xusb_find_port_node(padctl, "usb3", index); | ||
751 | if (!np || !of_device_is_available(np)) | ||
752 | goto out; | ||
753 | |||
754 | usb3 = devm_kzalloc(padctl->dev, sizeof(*usb3), GFP_KERNEL); | ||
755 | if (!usb3) { | ||
756 | err = -ENOMEM; | ||
757 | goto out; | ||
758 | } | ||
759 | |||
760 | err = tegra_xusb_port_init(&usb3->base, padctl, np, "usb3", index); | ||
761 | if (err < 0) | ||
762 | goto out; | ||
763 | |||
764 | usb3->base.ops = padctl->soc->ports.usb3.ops; | ||
765 | |||
766 | usb3->base.lane = usb3->base.ops->map(&usb3->base); | ||
767 | if (IS_ERR(usb3->base.lane)) { | ||
768 | err = PTR_ERR(usb3->base.lane); | ||
769 | goto out; | ||
770 | } | ||
771 | |||
772 | err = tegra_xusb_usb3_port_parse_dt(usb3); | ||
773 | if (err < 0) { | ||
774 | tegra_xusb_port_unregister(&usb3->base); | ||
775 | goto out; | ||
776 | } | ||
777 | |||
778 | list_add_tail(&usb3->base.list, &padctl->ports); | ||
779 | |||
780 | out: | ||
781 | of_node_put(np); | ||
782 | return err; | ||
783 | } | ||
784 | |||
785 | static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) | ||
786 | { | ||
787 | struct tegra_xusb_port *port, *tmp; | ||
788 | |||
789 | list_for_each_entry_safe_reverse(port, tmp, &padctl->ports, list) { | ||
790 | list_del(&port->list); | ||
791 | tegra_xusb_port_unregister(port); | ||
792 | } | ||
793 | } | ||
794 | |||
795 | static int tegra_xusb_setup_ports(struct tegra_xusb_padctl *padctl) | ||
796 | { | ||
797 | struct tegra_xusb_port *port; | ||
798 | unsigned int i; | ||
799 | int err = 0; | ||
800 | |||
801 | mutex_lock(&padctl->lock); | ||
802 | |||
803 | for (i = 0; i < padctl->soc->ports.usb2.count; i++) { | ||
804 | err = tegra_xusb_add_usb2_port(padctl, i); | ||
805 | if (err < 0) | ||
806 | goto remove_ports; | ||
807 | } | ||
808 | |||
809 | for (i = 0; i < padctl->soc->ports.ulpi.count; i++) { | ||
810 | err = tegra_xusb_add_ulpi_port(padctl, i); | ||
811 | if (err < 0) | ||
812 | goto remove_ports; | ||
813 | } | ||
814 | |||
815 | for (i = 0; i < padctl->soc->ports.hsic.count; i++) { | ||
816 | err = tegra_xusb_add_hsic_port(padctl, i); | ||
817 | if (err < 0) | ||
818 | goto remove_ports; | ||
819 | } | ||
820 | |||
821 | for (i = 0; i < padctl->soc->ports.usb3.count; i++) { | ||
822 | err = tegra_xusb_add_usb3_port(padctl, i); | ||
823 | if (err < 0) | ||
824 | goto remove_ports; | ||
825 | } | ||
826 | |||
827 | list_for_each_entry(port, &padctl->ports, list) { | ||
828 | err = port->ops->enable(port); | ||
829 | if (err < 0) | ||
830 | dev_err(padctl->dev, "failed to enable port %s: %d\n", | ||
831 | dev_name(&port->dev), err); | ||
832 | } | ||
833 | |||
834 | goto unlock; | ||
835 | |||
836 | remove_ports: | ||
837 | __tegra_xusb_remove_ports(padctl); | ||
838 | unlock: | ||
839 | mutex_unlock(&padctl->lock); | ||
840 | return err; | ||
841 | } | ||
842 | |||
843 | static void tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) | ||
844 | { | ||
845 | mutex_lock(&padctl->lock); | ||
846 | __tegra_xusb_remove_ports(padctl); | ||
847 | mutex_unlock(&padctl->lock); | ||
848 | } | ||
849 | |||
850 | static int tegra_xusb_padctl_probe(struct platform_device *pdev) | ||
851 | { | ||
852 | struct device_node *np = of_node_get(pdev->dev.of_node); | ||
853 | const struct tegra_xusb_padctl_soc *soc; | ||
854 | struct tegra_xusb_padctl *padctl; | ||
855 | const struct of_device_id *match; | ||
856 | struct resource *res; | ||
857 | int err; | ||
858 | |||
859 | /* for backwards compatibility with old device trees */ | ||
860 | np = of_find_node_by_name(np, "pads"); | ||
861 | if (!np) { | ||
862 | dev_warn(&pdev->dev, "deprecated DT, using legacy driver\n"); | ||
863 | return tegra_xusb_padctl_legacy_probe(pdev); | ||
864 | } | ||
865 | |||
866 | of_node_put(np); | ||
867 | |||
868 | match = of_match_node(tegra_xusb_padctl_of_match, pdev->dev.of_node); | ||
869 | soc = match->data; | ||
870 | |||
871 | padctl = soc->ops->probe(&pdev->dev, soc); | ||
872 | if (IS_ERR(padctl)) | ||
873 | return PTR_ERR(padctl); | ||
874 | |||
875 | platform_set_drvdata(pdev, padctl); | ||
876 | INIT_LIST_HEAD(&padctl->ports); | ||
877 | INIT_LIST_HEAD(&padctl->lanes); | ||
878 | INIT_LIST_HEAD(&padctl->pads); | ||
879 | mutex_init(&padctl->lock); | ||
880 | |||
881 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
882 | padctl->regs = devm_ioremap_resource(&pdev->dev, res); | ||
883 | if (IS_ERR(padctl->regs)) { | ||
884 | err = PTR_ERR(padctl->regs); | ||
885 | goto remove; | ||
886 | } | ||
887 | |||
888 | padctl->rst = devm_reset_control_get(&pdev->dev, NULL); | ||
889 | if (IS_ERR(padctl->rst)) { | ||
890 | err = PTR_ERR(padctl->rst); | ||
891 | goto remove; | ||
892 | } | ||
893 | |||
894 | err = reset_control_deassert(padctl->rst); | ||
895 | if (err < 0) | ||
896 | goto remove; | ||
897 | |||
898 | err = tegra_xusb_setup_pads(padctl); | ||
899 | if (err < 0) { | ||
900 | dev_err(&pdev->dev, "failed to setup pads: %d\n", err); | ||
901 | goto reset; | ||
902 | } | ||
903 | |||
904 | err = tegra_xusb_setup_ports(padctl); | ||
905 | if (err) { | ||
906 | dev_err(&pdev->dev, "failed to setup XUSB ports: %d\n", err); | ||
907 | goto remove_pads; | ||
908 | } | ||
909 | |||
910 | return 0; | ||
911 | |||
912 | remove_pads: | ||
913 | tegra_xusb_remove_pads(padctl); | ||
914 | reset: | ||
915 | reset_control_assert(padctl->rst); | ||
916 | remove: | ||
917 | soc->ops->remove(padctl); | ||
918 | return err; | ||
919 | } | ||
920 | |||
921 | static int tegra_xusb_padctl_remove(struct platform_device *pdev) | ||
922 | { | ||
923 | struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); | ||
924 | int err; | ||
925 | |||
926 | tegra_xusb_remove_ports(padctl); | ||
927 | tegra_xusb_remove_pads(padctl); | ||
928 | |||
929 | err = reset_control_assert(padctl->rst); | ||
930 | if (err < 0) | ||
931 | dev_err(&pdev->dev, "failed to assert reset: %d\n", err); | ||
932 | |||
933 | padctl->soc->ops->remove(padctl); | ||
934 | |||
935 | return err; | ||
936 | } | ||
937 | |||
938 | static struct platform_driver tegra_xusb_padctl_driver = { | ||
939 | .driver = { | ||
940 | .name = "tegra-xusb-padctl", | ||
941 | .of_match_table = tegra_xusb_padctl_of_match, | ||
942 | }, | ||
943 | .probe = tegra_xusb_padctl_probe, | ||
944 | .remove = tegra_xusb_padctl_remove, | ||
945 | }; | ||
946 | module_platform_driver(tegra_xusb_padctl_driver); | ||
947 | |||
948 | struct tegra_xusb_padctl *tegra_xusb_padctl_get(struct device *dev) | ||
949 | { | ||
950 | struct tegra_xusb_padctl *padctl; | ||
951 | struct platform_device *pdev; | ||
952 | struct device_node *np; | ||
953 | |||
954 | np = of_parse_phandle(dev->of_node, "nvidia,xusb-padctl", 0); | ||
955 | if (!np) | ||
956 | return ERR_PTR(-EINVAL); | ||
957 | |||
958 | /* | ||
959 | * This is slightly ugly. A better implementation would be to keep a | ||
960 | * registry of pad controllers, but since there will almost certainly | ||
961 | * only ever be one per SoC that would be a little overkill. | ||
962 | */ | ||
963 | pdev = of_find_device_by_node(np); | ||
964 | if (!pdev) { | ||
965 | of_node_put(np); | ||
966 | return ERR_PTR(-ENODEV); | ||
967 | } | ||
968 | |||
969 | of_node_put(np); | ||
970 | |||
971 | padctl = platform_get_drvdata(pdev); | ||
972 | if (!padctl) { | ||
973 | put_device(&pdev->dev); | ||
974 | return ERR_PTR(-EPROBE_DEFER); | ||
975 | } | ||
976 | |||
977 | return padctl; | ||
978 | } | ||
979 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get); | ||
980 | |||
981 | void tegra_xusb_padctl_put(struct tegra_xusb_padctl *padctl) | ||
982 | { | ||
983 | if (padctl) | ||
984 | put_device(padctl->dev); | ||
985 | } | ||
986 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_put); | ||
987 | |||
988 | int tegra_xusb_padctl_usb3_save_context(struct tegra_xusb_padctl *padctl, | ||
989 | unsigned int port) | ||
990 | { | ||
991 | if (padctl->soc->ops->usb3_save_context) | ||
992 | return padctl->soc->ops->usb3_save_context(padctl, port); | ||
993 | |||
994 | return -ENOSYS; | ||
995 | } | ||
996 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_usb3_save_context); | ||
997 | |||
998 | int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl, | ||
999 | unsigned int port, bool idle) | ||
1000 | { | ||
1001 | if (padctl->soc->ops->hsic_set_idle) | ||
1002 | return padctl->soc->ops->hsic_set_idle(padctl, port, idle); | ||
1003 | |||
1004 | return -ENOSYS; | ||
1005 | } | ||
1006 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_hsic_set_idle); | ||
1007 | |||
1008 | int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl, | ||
1009 | unsigned int port, bool enable) | ||
1010 | { | ||
1011 | if (padctl->soc->ops->usb3_set_lfps_detect) | ||
1012 | return padctl->soc->ops->usb3_set_lfps_detect(padctl, port, | ||
1013 | enable); | ||
1014 | |||
1015 | return -ENOSYS; | ||
1016 | } | ||
1017 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_usb3_set_lfps_detect); | ||
1018 | |||
1019 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
1020 | MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver"); | ||
1021 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h new file mode 100644 index 000000000000..b49dbc36efa3 --- /dev/null +++ b/drivers/phy/tegra/xusb.h | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. | ||
3 | * Copyright (c) 2015, Google Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef __PHY_TEGRA_XUSB_H | ||
16 | #define __PHY_TEGRA_XUSB_H | ||
17 | |||
18 | #include <linux/io.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | |||
22 | /* legacy entry points for backwards-compatibility */ | ||
23 | int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev); | ||
24 | int tegra_xusb_padctl_legacy_remove(struct platform_device *pdev); | ||
25 | |||
26 | struct phy; | ||
27 | struct phy_provider; | ||
28 | struct platform_device; | ||
29 | struct regulator; | ||
30 | |||
31 | /* | ||
32 | * lanes | ||
33 | */ | ||
34 | struct tegra_xusb_lane_soc { | ||
35 | const char *name; | ||
36 | |||
37 | unsigned int offset; | ||
38 | unsigned int shift; | ||
39 | unsigned int mask; | ||
40 | |||
41 | const char * const *funcs; | ||
42 | unsigned int num_funcs; | ||
43 | }; | ||
44 | |||
45 | struct tegra_xusb_lane { | ||
46 | const struct tegra_xusb_lane_soc *soc; | ||
47 | struct tegra_xusb_pad *pad; | ||
48 | struct device_node *np; | ||
49 | struct list_head list; | ||
50 | unsigned int function; | ||
51 | unsigned int index; | ||
52 | }; | ||
53 | |||
54 | int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, | ||
55 | struct device_node *np); | ||
56 | |||
57 | struct tegra_xusb_usb2_lane { | ||
58 | struct tegra_xusb_lane base; | ||
59 | |||
60 | u32 hs_curr_level_offset; | ||
61 | }; | ||
62 | |||
63 | static inline struct tegra_xusb_usb2_lane * | ||
64 | to_usb2_lane(struct tegra_xusb_lane *lane) | ||
65 | { | ||
66 | return container_of(lane, struct tegra_xusb_usb2_lane, base); | ||
67 | } | ||
68 | |||
69 | struct tegra_xusb_ulpi_lane { | ||
70 | struct tegra_xusb_lane base; | ||
71 | }; | ||
72 | |||
73 | static inline struct tegra_xusb_ulpi_lane * | ||
74 | to_ulpi_lane(struct tegra_xusb_lane *lane) | ||
75 | { | ||
76 | return container_of(lane, struct tegra_xusb_ulpi_lane, base); | ||
77 | } | ||
78 | |||
79 | struct tegra_xusb_hsic_lane { | ||
80 | struct tegra_xusb_lane base; | ||
81 | |||
82 | u32 strobe_trim; | ||
83 | u32 rx_strobe_trim; | ||
84 | u32 rx_data_trim; | ||
85 | u32 tx_rtune_n; | ||
86 | u32 tx_rtune_p; | ||
87 | u32 tx_rslew_n; | ||
88 | u32 tx_rslew_p; | ||
89 | bool auto_term; | ||
90 | }; | ||
91 | |||
92 | static inline struct tegra_xusb_hsic_lane * | ||
93 | to_hsic_lane(struct tegra_xusb_lane *lane) | ||
94 | { | ||
95 | return container_of(lane, struct tegra_xusb_hsic_lane, base); | ||
96 | } | ||
97 | |||
98 | struct tegra_xusb_pcie_lane { | ||
99 | struct tegra_xusb_lane base; | ||
100 | }; | ||
101 | |||
102 | static inline struct tegra_xusb_pcie_lane * | ||
103 | to_pcie_lane(struct tegra_xusb_lane *lane) | ||
104 | { | ||
105 | return container_of(lane, struct tegra_xusb_pcie_lane, base); | ||
106 | } | ||
107 | |||
108 | struct tegra_xusb_sata_lane { | ||
109 | struct tegra_xusb_lane base; | ||
110 | }; | ||
111 | |||
112 | static inline struct tegra_xusb_sata_lane * | ||
113 | to_sata_lane(struct tegra_xusb_lane *lane) | ||
114 | { | ||
115 | return container_of(lane, struct tegra_xusb_sata_lane, base); | ||
116 | } | ||
117 | |||
118 | struct tegra_xusb_lane_ops { | ||
119 | struct tegra_xusb_lane *(*probe)(struct tegra_xusb_pad *pad, | ||
120 | struct device_node *np, | ||
121 | unsigned int index); | ||
122 | void (*remove)(struct tegra_xusb_lane *lane); | ||
123 | }; | ||
124 | |||
125 | /* | ||
126 | * pads | ||
127 | */ | ||
128 | struct tegra_xusb_pad_soc; | ||
129 | struct tegra_xusb_padctl; | ||
130 | |||
131 | struct tegra_xusb_pad_ops { | ||
132 | struct tegra_xusb_pad *(*probe)(struct tegra_xusb_padctl *padctl, | ||
133 | const struct tegra_xusb_pad_soc *soc, | ||
134 | struct device_node *np); | ||
135 | void (*remove)(struct tegra_xusb_pad *pad); | ||
136 | }; | ||
137 | |||
138 | struct tegra_xusb_pad_soc { | ||
139 | const char *name; | ||
140 | |||
141 | const struct tegra_xusb_lane_soc *lanes; | ||
142 | unsigned int num_lanes; | ||
143 | |||
144 | const struct tegra_xusb_pad_ops *ops; | ||
145 | }; | ||
146 | |||
147 | struct tegra_xusb_pad { | ||
148 | const struct tegra_xusb_pad_soc *soc; | ||
149 | struct tegra_xusb_padctl *padctl; | ||
150 | struct phy_provider *provider; | ||
151 | struct phy **lanes; | ||
152 | struct device dev; | ||
153 | |||
154 | const struct tegra_xusb_lane_ops *ops; | ||
155 | |||
156 | struct list_head list; | ||
157 | }; | ||
158 | |||
159 | static inline struct tegra_xusb_pad *to_tegra_xusb_pad(struct device *dev) | ||
160 | { | ||
161 | return container_of(dev, struct tegra_xusb_pad, dev); | ||
162 | } | ||
163 | |||
164 | int tegra_xusb_pad_init(struct tegra_xusb_pad *pad, | ||
165 | struct tegra_xusb_padctl *padctl, | ||
166 | struct device_node *np); | ||
167 | int tegra_xusb_pad_register(struct tegra_xusb_pad *pad, | ||
168 | const struct phy_ops *ops); | ||
169 | void tegra_xusb_pad_unregister(struct tegra_xusb_pad *pad); | ||
170 | |||
171 | struct tegra_xusb_usb2_pad { | ||
172 | struct tegra_xusb_pad base; | ||
173 | |||
174 | struct clk *clk; | ||
175 | unsigned int enable; | ||
176 | struct mutex lock; | ||
177 | }; | ||
178 | |||
179 | static inline struct tegra_xusb_usb2_pad * | ||
180 | to_usb2_pad(struct tegra_xusb_pad *pad) | ||
181 | { | ||
182 | return container_of(pad, struct tegra_xusb_usb2_pad, base); | ||
183 | } | ||
184 | |||
185 | struct tegra_xusb_ulpi_pad { | ||
186 | struct tegra_xusb_pad base; | ||
187 | }; | ||
188 | |||
189 | static inline struct tegra_xusb_ulpi_pad * | ||
190 | to_ulpi_pad(struct tegra_xusb_pad *pad) | ||
191 | { | ||
192 | return container_of(pad, struct tegra_xusb_ulpi_pad, base); | ||
193 | } | ||
194 | |||
195 | struct tegra_xusb_hsic_pad { | ||
196 | struct tegra_xusb_pad base; | ||
197 | |||
198 | struct regulator *supply; | ||
199 | struct clk *clk; | ||
200 | }; | ||
201 | |||
202 | static inline struct tegra_xusb_hsic_pad * | ||
203 | to_hsic_pad(struct tegra_xusb_pad *pad) | ||
204 | { | ||
205 | return container_of(pad, struct tegra_xusb_hsic_pad, base); | ||
206 | } | ||
207 | |||
208 | struct tegra_xusb_pcie_pad { | ||
209 | struct tegra_xusb_pad base; | ||
210 | |||
211 | struct reset_control *rst; | ||
212 | struct clk *pll; | ||
213 | |||
214 | unsigned int enable; | ||
215 | }; | ||
216 | |||
217 | static inline struct tegra_xusb_pcie_pad * | ||
218 | to_pcie_pad(struct tegra_xusb_pad *pad) | ||
219 | { | ||
220 | return container_of(pad, struct tegra_xusb_pcie_pad, base); | ||
221 | } | ||
222 | |||
223 | struct tegra_xusb_sata_pad { | ||
224 | struct tegra_xusb_pad base; | ||
225 | |||
226 | struct reset_control *rst; | ||
227 | struct clk *pll; | ||
228 | |||
229 | unsigned int enable; | ||
230 | }; | ||
231 | |||
232 | static inline struct tegra_xusb_sata_pad * | ||
233 | to_sata_pad(struct tegra_xusb_pad *pad) | ||
234 | { | ||
235 | return container_of(pad, struct tegra_xusb_sata_pad, base); | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * ports | ||
240 | */ | ||
241 | struct tegra_xusb_port_ops; | ||
242 | |||
243 | struct tegra_xusb_port { | ||
244 | struct tegra_xusb_padctl *padctl; | ||
245 | struct tegra_xusb_lane *lane; | ||
246 | unsigned int index; | ||
247 | |||
248 | struct list_head list; | ||
249 | struct device dev; | ||
250 | |||
251 | const struct tegra_xusb_port_ops *ops; | ||
252 | }; | ||
253 | |||
254 | struct tegra_xusb_lane_map { | ||
255 | unsigned int port; | ||
256 | const char *type; | ||
257 | unsigned int index; | ||
258 | const char *func; | ||
259 | }; | ||
260 | |||
261 | struct tegra_xusb_lane * | ||
262 | tegra_xusb_port_find_lane(struct tegra_xusb_port *port, | ||
263 | const struct tegra_xusb_lane_map *map, | ||
264 | const char *function); | ||
265 | |||
266 | struct tegra_xusb_port * | ||
267 | tegra_xusb_find_port(struct tegra_xusb_padctl *padctl, const char *type, | ||
268 | unsigned int index); | ||
269 | |||
270 | struct tegra_xusb_usb2_port { | ||
271 | struct tegra_xusb_port base; | ||
272 | |||
273 | struct regulator *supply; | ||
274 | bool internal; | ||
275 | }; | ||
276 | |||
277 | static inline struct tegra_xusb_usb2_port * | ||
278 | to_usb2_port(struct tegra_xusb_port *port) | ||
279 | { | ||
280 | return container_of(port, struct tegra_xusb_usb2_port, base); | ||
281 | } | ||
282 | |||
283 | struct tegra_xusb_usb2_port * | ||
284 | tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl, | ||
285 | unsigned int index); | ||
286 | |||
287 | struct tegra_xusb_ulpi_port { | ||
288 | struct tegra_xusb_port base; | ||
289 | |||
290 | struct regulator *supply; | ||
291 | bool internal; | ||
292 | }; | ||
293 | |||
294 | static inline struct tegra_xusb_ulpi_port * | ||
295 | to_ulpi_port(struct tegra_xusb_port *port) | ||
296 | { | ||
297 | return container_of(port, struct tegra_xusb_ulpi_port, base); | ||
298 | } | ||
299 | |||
300 | struct tegra_xusb_hsic_port { | ||
301 | struct tegra_xusb_port base; | ||
302 | }; | ||
303 | |||
304 | static inline struct tegra_xusb_hsic_port * | ||
305 | to_hsic_port(struct tegra_xusb_port *port) | ||
306 | { | ||
307 | return container_of(port, struct tegra_xusb_hsic_port, base); | ||
308 | } | ||
309 | |||
310 | struct tegra_xusb_usb3_port { | ||
311 | struct tegra_xusb_port base; | ||
312 | struct regulator *supply; | ||
313 | bool context_saved; | ||
314 | unsigned int port; | ||
315 | bool internal; | ||
316 | |||
317 | u32 tap1; | ||
318 | u32 amp; | ||
319 | u32 ctle_z; | ||
320 | u32 ctle_g; | ||
321 | }; | ||
322 | |||
323 | static inline struct tegra_xusb_usb3_port * | ||
324 | to_usb3_port(struct tegra_xusb_port *port) | ||
325 | { | ||
326 | return container_of(port, struct tegra_xusb_usb3_port, base); | ||
327 | } | ||
328 | |||
329 | struct tegra_xusb_usb3_port * | ||
330 | tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, | ||
331 | unsigned int index); | ||
332 | |||
333 | struct tegra_xusb_port_ops { | ||
334 | int (*enable)(struct tegra_xusb_port *port); | ||
335 | void (*disable)(struct tegra_xusb_port *port); | ||
336 | struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port); | ||
337 | }; | ||
338 | |||
339 | /* | ||
340 | * pad controller | ||
341 | */ | ||
342 | struct tegra_xusb_padctl_soc; | ||
343 | |||
344 | struct tegra_xusb_padctl_ops { | ||
345 | struct tegra_xusb_padctl * | ||
346 | (*probe)(struct device *dev, | ||
347 | const struct tegra_xusb_padctl_soc *soc); | ||
348 | void (*remove)(struct tegra_xusb_padctl *padctl); | ||
349 | |||
350 | int (*usb3_save_context)(struct tegra_xusb_padctl *padctl, | ||
351 | unsigned int index); | ||
352 | int (*hsic_set_idle)(struct tegra_xusb_padctl *padctl, | ||
353 | unsigned int index, bool idle); | ||
354 | int (*usb3_set_lfps_detect)(struct tegra_xusb_padctl *padctl, | ||
355 | unsigned int index, bool enable); | ||
356 | }; | ||
357 | |||
358 | struct tegra_xusb_padctl_soc { | ||
359 | const struct tegra_xusb_pad_soc * const *pads; | ||
360 | unsigned int num_pads; | ||
361 | |||
362 | struct { | ||
363 | struct { | ||
364 | const struct tegra_xusb_port_ops *ops; | ||
365 | unsigned int count; | ||
366 | } usb2, ulpi, hsic, usb3; | ||
367 | } ports; | ||
368 | |||
369 | const struct tegra_xusb_padctl_ops *ops; | ||
370 | }; | ||
371 | |||
372 | struct tegra_xusb_padctl { | ||
373 | struct device *dev; | ||
374 | void __iomem *regs; | ||
375 | struct mutex lock; | ||
376 | struct reset_control *rst; | ||
377 | |||
378 | const struct tegra_xusb_padctl_soc *soc; | ||
379 | |||
380 | struct tegra_xusb_pad *pcie; | ||
381 | struct tegra_xusb_pad *sata; | ||
382 | struct tegra_xusb_pad *ulpi; | ||
383 | struct tegra_xusb_pad *usb2; | ||
384 | struct tegra_xusb_pad *hsic; | ||
385 | |||
386 | struct list_head ports; | ||
387 | struct list_head lanes; | ||
388 | struct list_head pads; | ||
389 | |||
390 | unsigned int enable; | ||
391 | |||
392 | struct clk *clk; | ||
393 | }; | ||
394 | |||
395 | static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, | ||
396 | unsigned long offset) | ||
397 | { | ||
398 | dev_dbg(padctl->dev, "%08lx < %08x\n", offset, value); | ||
399 | writel(value, padctl->regs + offset); | ||
400 | } | ||
401 | |||
402 | static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl, | ||
403 | unsigned long offset) | ||
404 | { | ||
405 | u32 value = readl(padctl->regs + offset); | ||
406 | dev_dbg(padctl->dev, "%08lx > %08x\n", offset, value); | ||
407 | return value; | ||
408 | } | ||
409 | |||
410 | struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl, | ||
411 | const char *name, | ||
412 | unsigned int index); | ||
413 | |||
414 | #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) | ||
415 | extern const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc; | ||
416 | #endif | ||
417 | #if defined(CONFIG_ARCH_TEGRA_210_SOC) | ||
418 | extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc; | ||
419 | #endif | ||
420 | |||
421 | #endif /* __PHY_TEGRA_XUSB_H */ | ||
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c index 2f06029c9405..946cda3fee35 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c | |||
@@ -873,7 +873,7 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = { | |||
873 | }; | 873 | }; |
874 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); | 874 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); |
875 | 875 | ||
876 | static int tegra_xusb_padctl_probe(struct platform_device *pdev) | 876 | int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev) |
877 | { | 877 | { |
878 | struct tegra_xusb_padctl *padctl; | 878 | struct tegra_xusb_padctl *padctl; |
879 | const struct of_device_id *match; | 879 | const struct of_device_id *match; |
@@ -955,8 +955,9 @@ reset: | |||
955 | reset_control_assert(padctl->rst); | 955 | reset_control_assert(padctl->rst); |
956 | return err; | 956 | return err; |
957 | } | 957 | } |
958 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_legacy_probe); | ||
958 | 959 | ||
959 | static int tegra_xusb_padctl_remove(struct platform_device *pdev) | 960 | int tegra_xusb_padctl_legacy_remove(struct platform_device *pdev) |
960 | { | 961 | { |
961 | struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); | 962 | struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); |
962 | int err; | 963 | int err; |
@@ -969,17 +970,4 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) | |||
969 | 970 | ||
970 | return err; | 971 | return err; |
971 | } | 972 | } |
972 | 973 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_legacy_remove); | |
973 | static struct platform_driver tegra_xusb_padctl_driver = { | ||
974 | .driver = { | ||
975 | .name = "tegra-xusb-padctl", | ||
976 | .of_match_table = tegra_xusb_padctl_of_match, | ||
977 | }, | ||
978 | .probe = tegra_xusb_padctl_probe, | ||
979 | .remove = tegra_xusb_padctl_remove, | ||
980 | }; | ||
981 | module_platform_driver(tegra_xusb_padctl_driver); | ||
982 | |||
983 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
984 | MODULE_DESCRIPTION("Tegra 124 XUSB Pad Control driver"); | ||
985 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index df37212a5cbd..0b2733db0e9e 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig | |||
@@ -12,5 +12,8 @@ menuconfig RESET_CONTROLLER | |||
12 | 12 | ||
13 | If unsure, say no. | 13 | If unsure, say no. |
14 | 14 | ||
15 | config RESET_OXNAS | ||
16 | bool | ||
17 | |||
15 | source "drivers/reset/sti/Kconfig" | 18 | source "drivers/reset/sti/Kconfig" |
16 | source "drivers/reset/hisilicon/Kconfig" | 19 | source "drivers/reset/hisilicon/Kconfig" |
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index a1fc8eda79f3..f173fc3847b4 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile | |||
@@ -8,3 +8,4 @@ obj-$(CONFIG_ARCH_STI) += sti/ | |||
8 | obj-$(CONFIG_ARCH_HISI) += hisilicon/ | 8 | obj-$(CONFIG_ARCH_HISI) += hisilicon/ |
9 | obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o | 9 | obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o |
10 | obj-$(CONFIG_ATH79) += reset-ath79.o | 10 | obj-$(CONFIG_ATH79) += reset-ath79.o |
11 | obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o | ||
diff --git a/drivers/reset/core.c b/drivers/reset/core.c index f15f150b79da..72b32bd15549 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | */ | 10 | */ |
11 | #include <linux/atomic.h> | ||
11 | #include <linux/device.h> | 12 | #include <linux/device.h> |
12 | #include <linux/err.h> | 13 | #include <linux/err.h> |
13 | #include <linux/export.h> | 14 | #include <linux/export.h> |
@@ -18,19 +19,27 @@ | |||
18 | #include <linux/reset-controller.h> | 19 | #include <linux/reset-controller.h> |
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | 21 | ||
21 | static DEFINE_MUTEX(reset_controller_list_mutex); | 22 | static DEFINE_MUTEX(reset_list_mutex); |
22 | static LIST_HEAD(reset_controller_list); | 23 | static LIST_HEAD(reset_controller_list); |
23 | 24 | ||
24 | /** | 25 | /** |
25 | * struct reset_control - a reset control | 26 | * struct reset_control - a reset control |
26 | * @rcdev: a pointer to the reset controller device | 27 | * @rcdev: a pointer to the reset controller device |
27 | * this reset control belongs to | 28 | * this reset control belongs to |
29 | * @list: list entry for the rcdev's reset controller list | ||
28 | * @id: ID of the reset controller in the reset | 30 | * @id: ID of the reset controller in the reset |
29 | * controller device | 31 | * controller device |
32 | * @refcnt: Number of gets of this reset_control | ||
33 | * @shared: Is this a shared (1), or an exclusive (0) reset_control? | ||
34 | * @deassert_cnt: Number of times this reset line has been deasserted | ||
30 | */ | 35 | */ |
31 | struct reset_control { | 36 | struct reset_control { |
32 | struct reset_controller_dev *rcdev; | 37 | struct reset_controller_dev *rcdev; |
38 | struct list_head list; | ||
33 | unsigned int id; | 39 | unsigned int id; |
40 | unsigned int refcnt; | ||
41 | int shared; | ||
42 | atomic_t deassert_count; | ||
34 | }; | 43 | }; |
35 | 44 | ||
36 | /** | 45 | /** |
@@ -62,9 +71,11 @@ int reset_controller_register(struct reset_controller_dev *rcdev) | |||
62 | rcdev->of_xlate = of_reset_simple_xlate; | 71 | rcdev->of_xlate = of_reset_simple_xlate; |
63 | } | 72 | } |
64 | 73 | ||
65 | mutex_lock(&reset_controller_list_mutex); | 74 | INIT_LIST_HEAD(&rcdev->reset_control_head); |
75 | |||
76 | mutex_lock(&reset_list_mutex); | ||
66 | list_add(&rcdev->list, &reset_controller_list); | 77 | list_add(&rcdev->list, &reset_controller_list); |
67 | mutex_unlock(&reset_controller_list_mutex); | 78 | mutex_unlock(&reset_list_mutex); |
68 | 79 | ||
69 | return 0; | 80 | return 0; |
70 | } | 81 | } |
@@ -76,18 +87,23 @@ EXPORT_SYMBOL_GPL(reset_controller_register); | |||
76 | */ | 87 | */ |
77 | void reset_controller_unregister(struct reset_controller_dev *rcdev) | 88 | void reset_controller_unregister(struct reset_controller_dev *rcdev) |
78 | { | 89 | { |
79 | mutex_lock(&reset_controller_list_mutex); | 90 | mutex_lock(&reset_list_mutex); |
80 | list_del(&rcdev->list); | 91 | list_del(&rcdev->list); |
81 | mutex_unlock(&reset_controller_list_mutex); | 92 | mutex_unlock(&reset_list_mutex); |
82 | } | 93 | } |
83 | EXPORT_SYMBOL_GPL(reset_controller_unregister); | 94 | EXPORT_SYMBOL_GPL(reset_controller_unregister); |
84 | 95 | ||
85 | /** | 96 | /** |
86 | * reset_control_reset - reset the controlled device | 97 | * reset_control_reset - reset the controlled device |
87 | * @rstc: reset controller | 98 | * @rstc: reset controller |
99 | * | ||
100 | * Calling this on a shared reset controller is an error. | ||
88 | */ | 101 | */ |
89 | int reset_control_reset(struct reset_control *rstc) | 102 | int reset_control_reset(struct reset_control *rstc) |
90 | { | 103 | { |
104 | if (WARN_ON(rstc->shared)) | ||
105 | return -EINVAL; | ||
106 | |||
91 | if (rstc->rcdev->ops->reset) | 107 | if (rstc->rcdev->ops->reset) |
92 | return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); | 108 | return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); |
93 | 109 | ||
@@ -98,26 +114,48 @@ EXPORT_SYMBOL_GPL(reset_control_reset); | |||
98 | /** | 114 | /** |
99 | * reset_control_assert - asserts the reset line | 115 | * reset_control_assert - asserts the reset line |
100 | * @rstc: reset controller | 116 | * @rstc: reset controller |
117 | * | ||
118 | * Calling this on an exclusive reset controller guarantees that the reset | ||
119 | * will be asserted. When called on a shared reset controller the line may | ||
120 | * still be deasserted, as long as other users keep it so. | ||
121 | * | ||
122 | * For shared reset controls a driver cannot expect the hw's registers and | ||
123 | * internal state to be reset, but must be prepared for this to happen. | ||
101 | */ | 124 | */ |
102 | int reset_control_assert(struct reset_control *rstc) | 125 | int reset_control_assert(struct reset_control *rstc) |
103 | { | 126 | { |
104 | if (rstc->rcdev->ops->assert) | 127 | if (!rstc->rcdev->ops->assert) |
105 | return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); | 128 | return -ENOTSUPP; |
106 | 129 | ||
107 | return -ENOTSUPP; | 130 | if (rstc->shared) { |
131 | if (WARN_ON(atomic_read(&rstc->deassert_count) == 0)) | ||
132 | return -EINVAL; | ||
133 | |||
134 | if (atomic_dec_return(&rstc->deassert_count) != 0) | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); | ||
108 | } | 139 | } |
109 | EXPORT_SYMBOL_GPL(reset_control_assert); | 140 | EXPORT_SYMBOL_GPL(reset_control_assert); |
110 | 141 | ||
111 | /** | 142 | /** |
112 | * reset_control_deassert - deasserts the reset line | 143 | * reset_control_deassert - deasserts the reset line |
113 | * @rstc: reset controller | 144 | * @rstc: reset controller |
145 | * | ||
146 | * After calling this function, the reset is guaranteed to be deasserted. | ||
114 | */ | 147 | */ |
115 | int reset_control_deassert(struct reset_control *rstc) | 148 | int reset_control_deassert(struct reset_control *rstc) |
116 | { | 149 | { |
117 | if (rstc->rcdev->ops->deassert) | 150 | if (!rstc->rcdev->ops->deassert) |
118 | return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); | 151 | return -ENOTSUPP; |
119 | 152 | ||
120 | return -ENOTSUPP; | 153 | if (rstc->shared) { |
154 | if (atomic_inc_return(&rstc->deassert_count) != 1) | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); | ||
121 | } | 159 | } |
122 | EXPORT_SYMBOL_GPL(reset_control_deassert); | 160 | EXPORT_SYMBOL_GPL(reset_control_deassert); |
123 | 161 | ||
@@ -136,18 +174,54 @@ int reset_control_status(struct reset_control *rstc) | |||
136 | } | 174 | } |
137 | EXPORT_SYMBOL_GPL(reset_control_status); | 175 | EXPORT_SYMBOL_GPL(reset_control_status); |
138 | 176 | ||
139 | /** | 177 | static struct reset_control *__reset_control_get( |
140 | * of_reset_control_get_by_index - Lookup and obtain a reference to a reset | 178 | struct reset_controller_dev *rcdev, |
141 | * controller by index. | 179 | unsigned int index, int shared) |
142 | * @node: device to be reset by the controller | 180 | { |
143 | * @index: index of the reset controller | 181 | struct reset_control *rstc; |
144 | * | 182 | |
145 | * This is to be used to perform a list of resets for a device or power domain | 183 | lockdep_assert_held(&reset_list_mutex); |
146 | * in whatever order. Returns a struct reset_control or IS_ERR() condition | 184 | |
147 | * containing errno. | 185 | list_for_each_entry(rstc, &rcdev->reset_control_head, list) { |
148 | */ | 186 | if (rstc->id == index) { |
149 | struct reset_control *of_reset_control_get_by_index(struct device_node *node, | 187 | if (WARN_ON(!rstc->shared || !shared)) |
150 | int index) | 188 | return ERR_PTR(-EBUSY); |
189 | |||
190 | rstc->refcnt++; | ||
191 | return rstc; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); | ||
196 | if (!rstc) | ||
197 | return ERR_PTR(-ENOMEM); | ||
198 | |||
199 | try_module_get(rcdev->owner); | ||
200 | |||
201 | rstc->rcdev = rcdev; | ||
202 | list_add(&rstc->list, &rcdev->reset_control_head); | ||
203 | rstc->id = index; | ||
204 | rstc->refcnt = 1; | ||
205 | rstc->shared = shared; | ||
206 | |||
207 | return rstc; | ||
208 | } | ||
209 | |||
210 | static void __reset_control_put(struct reset_control *rstc) | ||
211 | { | ||
212 | lockdep_assert_held(&reset_list_mutex); | ||
213 | |||
214 | if (--rstc->refcnt) | ||
215 | return; | ||
216 | |||
217 | module_put(rstc->rcdev->owner); | ||
218 | |||
219 | list_del(&rstc->list); | ||
220 | kfree(rstc); | ||
221 | } | ||
222 | |||
223 | struct reset_control *__of_reset_control_get(struct device_node *node, | ||
224 | const char *id, int index, int shared) | ||
151 | { | 225 | { |
152 | struct reset_control *rstc; | 226 | struct reset_control *rstc; |
153 | struct reset_controller_dev *r, *rcdev; | 227 | struct reset_controller_dev *r, *rcdev; |
@@ -155,12 +229,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node, | |||
155 | int rstc_id; | 229 | int rstc_id; |
156 | int ret; | 230 | int ret; |
157 | 231 | ||
232 | if (!node) | ||
233 | return ERR_PTR(-EINVAL); | ||
234 | |||
235 | if (id) { | ||
236 | index = of_property_match_string(node, | ||
237 | "reset-names", id); | ||
238 | if (index < 0) | ||
239 | return ERR_PTR(-ENOENT); | ||
240 | } | ||
241 | |||
158 | ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", | 242 | ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", |
159 | index, &args); | 243 | index, &args); |
160 | if (ret) | 244 | if (ret) |
161 | return ERR_PTR(ret); | 245 | return ERR_PTR(ret); |
162 | 246 | ||
163 | mutex_lock(&reset_controller_list_mutex); | 247 | mutex_lock(&reset_list_mutex); |
164 | rcdev = NULL; | 248 | rcdev = NULL; |
165 | list_for_each_entry(r, &reset_controller_list, list) { | 249 | list_for_each_entry(r, &reset_controller_list, list) { |
166 | if (args.np == r->of_node) { | 250 | if (args.np == r->of_node) { |
@@ -171,78 +255,29 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node, | |||
171 | of_node_put(args.np); | 255 | of_node_put(args.np); |
172 | 256 | ||
173 | if (!rcdev) { | 257 | if (!rcdev) { |
174 | mutex_unlock(&reset_controller_list_mutex); | 258 | mutex_unlock(&reset_list_mutex); |
175 | return ERR_PTR(-EPROBE_DEFER); | 259 | return ERR_PTR(-EPROBE_DEFER); |
176 | } | 260 | } |
177 | 261 | ||
178 | if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) { | 262 | if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) { |
179 | mutex_unlock(&reset_controller_list_mutex); | 263 | mutex_unlock(&reset_list_mutex); |
180 | return ERR_PTR(-EINVAL); | 264 | return ERR_PTR(-EINVAL); |
181 | } | 265 | } |
182 | 266 | ||
183 | rstc_id = rcdev->of_xlate(rcdev, &args); | 267 | rstc_id = rcdev->of_xlate(rcdev, &args); |
184 | if (rstc_id < 0) { | 268 | if (rstc_id < 0) { |
185 | mutex_unlock(&reset_controller_list_mutex); | 269 | mutex_unlock(&reset_list_mutex); |
186 | return ERR_PTR(rstc_id); | 270 | return ERR_PTR(rstc_id); |
187 | } | 271 | } |
188 | 272 | ||
189 | try_module_get(rcdev->owner); | 273 | /* reset_list_mutex also protects the rcdev's reset_control list */ |
190 | mutex_unlock(&reset_controller_list_mutex); | 274 | rstc = __reset_control_get(rcdev, rstc_id, shared); |
191 | |||
192 | rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); | ||
193 | if (!rstc) { | ||
194 | module_put(rcdev->owner); | ||
195 | return ERR_PTR(-ENOMEM); | ||
196 | } | ||
197 | 275 | ||
198 | rstc->rcdev = rcdev; | 276 | mutex_unlock(&reset_list_mutex); |
199 | rstc->id = rstc_id; | ||
200 | 277 | ||
201 | return rstc; | 278 | return rstc; |
202 | } | 279 | } |
203 | EXPORT_SYMBOL_GPL(of_reset_control_get_by_index); | 280 | EXPORT_SYMBOL_GPL(__of_reset_control_get); |
204 | |||
205 | /** | ||
206 | * of_reset_control_get - Lookup and obtain a reference to a reset controller. | ||
207 | * @node: device to be reset by the controller | ||
208 | * @id: reset line name | ||
209 | * | ||
210 | * Returns a struct reset_control or IS_ERR() condition containing errno. | ||
211 | * | ||
212 | * Use of id names is optional. | ||
213 | */ | ||
214 | struct reset_control *of_reset_control_get(struct device_node *node, | ||
215 | const char *id) | ||
216 | { | ||
217 | int index = 0; | ||
218 | |||
219 | if (id) { | ||
220 | index = of_property_match_string(node, | ||
221 | "reset-names", id); | ||
222 | if (index < 0) | ||
223 | return ERR_PTR(-ENOENT); | ||
224 | } | ||
225 | return of_reset_control_get_by_index(node, index); | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(of_reset_control_get); | ||
228 | |||
229 | /** | ||
230 | * reset_control_get - Lookup and obtain a reference to a reset controller. | ||
231 | * @dev: device to be reset by the controller | ||
232 | * @id: reset line name | ||
233 | * | ||
234 | * Returns a struct reset_control or IS_ERR() condition containing errno. | ||
235 | * | ||
236 | * Use of id names is optional. | ||
237 | */ | ||
238 | struct reset_control *reset_control_get(struct device *dev, const char *id) | ||
239 | { | ||
240 | if (!dev) | ||
241 | return ERR_PTR(-EINVAL); | ||
242 | |||
243 | return of_reset_control_get(dev->of_node, id); | ||
244 | } | ||
245 | EXPORT_SYMBOL_GPL(reset_control_get); | ||
246 | 281 | ||
247 | /** | 282 | /** |
248 | * reset_control_put - free the reset controller | 283 | * reset_control_put - free the reset controller |
@@ -254,8 +289,9 @@ void reset_control_put(struct reset_control *rstc) | |||
254 | if (IS_ERR(rstc)) | 289 | if (IS_ERR(rstc)) |
255 | return; | 290 | return; |
256 | 291 | ||
257 | module_put(rstc->rcdev->owner); | 292 | mutex_lock(&reset_list_mutex); |
258 | kfree(rstc); | 293 | __reset_control_put(rstc); |
294 | mutex_unlock(&reset_list_mutex); | ||
259 | } | 295 | } |
260 | EXPORT_SYMBOL_GPL(reset_control_put); | 296 | EXPORT_SYMBOL_GPL(reset_control_put); |
261 | 297 | ||
@@ -264,16 +300,8 @@ static void devm_reset_control_release(struct device *dev, void *res) | |||
264 | reset_control_put(*(struct reset_control **)res); | 300 | reset_control_put(*(struct reset_control **)res); |
265 | } | 301 | } |
266 | 302 | ||
267 | /** | 303 | struct reset_control *__devm_reset_control_get(struct device *dev, |
268 | * devm_reset_control_get - resource managed reset_control_get() | 304 | const char *id, int index, int shared) |
269 | * @dev: device to be reset by the controller | ||
270 | * @id: reset line name | ||
271 | * | ||
272 | * Managed reset_control_get(). For reset controllers returned from this | ||
273 | * function, reset_control_put() is called automatically on driver detach. | ||
274 | * See reset_control_get() for more information. | ||
275 | */ | ||
276 | struct reset_control *devm_reset_control_get(struct device *dev, const char *id) | ||
277 | { | 305 | { |
278 | struct reset_control **ptr, *rstc; | 306 | struct reset_control **ptr, *rstc; |
279 | 307 | ||
@@ -282,7 +310,8 @@ struct reset_control *devm_reset_control_get(struct device *dev, const char *id) | |||
282 | if (!ptr) | 310 | if (!ptr) |
283 | return ERR_PTR(-ENOMEM); | 311 | return ERR_PTR(-ENOMEM); |
284 | 312 | ||
285 | rstc = reset_control_get(dev, id); | 313 | rstc = __of_reset_control_get(dev ? dev->of_node : NULL, |
314 | id, index, shared); | ||
286 | if (!IS_ERR(rstc)) { | 315 | if (!IS_ERR(rstc)) { |
287 | *ptr = rstc; | 316 | *ptr = rstc; |
288 | devres_add(dev, ptr); | 317 | devres_add(dev, ptr); |
@@ -292,7 +321,7 @@ struct reset_control *devm_reset_control_get(struct device *dev, const char *id) | |||
292 | 321 | ||
293 | return rstc; | 322 | return rstc; |
294 | } | 323 | } |
295 | EXPORT_SYMBOL_GPL(devm_reset_control_get); | 324 | EXPORT_SYMBOL_GPL(__devm_reset_control_get); |
296 | 325 | ||
297 | /** | 326 | /** |
298 | * device_reset - find reset controller associated with the device | 327 | * device_reset - find reset controller associated with the device |
diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c index 3b8a4f5a1ff6..54cca0055171 100644 --- a/drivers/reset/reset-lpc18xx.c +++ b/drivers/reset/reset-lpc18xx.c | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | struct lpc18xx_rgu_data { | 36 | struct lpc18xx_rgu_data { |
37 | struct reset_controller_dev rcdev; | 37 | struct reset_controller_dev rcdev; |
38 | struct notifier_block restart_nb; | ||
38 | struct clk *clk_delay; | 39 | struct clk *clk_delay; |
39 | struct clk *clk_reg; | 40 | struct clk *clk_reg; |
40 | void __iomem *base; | 41 | void __iomem *base; |
@@ -44,12 +45,13 @@ struct lpc18xx_rgu_data { | |||
44 | 45 | ||
45 | #define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev) | 46 | #define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev) |
46 | 47 | ||
47 | static void __iomem *rgu_base; | 48 | static int lpc18xx_rgu_restart(struct notifier_block *nb, unsigned long mode, |
48 | |||
49 | static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode, | ||
50 | void *cmd) | 49 | void *cmd) |
51 | { | 50 | { |
52 | writel(BIT(LPC18XX_RGU_CORE_RST), rgu_base + LPC18XX_RGU_CTRL0); | 51 | struct lpc18xx_rgu_data *rc = container_of(nb, struct lpc18xx_rgu_data, |
52 | restart_nb); | ||
53 | |||
54 | writel(BIT(LPC18XX_RGU_CORE_RST), rc->base + LPC18XX_RGU_CTRL0); | ||
53 | mdelay(2000); | 55 | mdelay(2000); |
54 | 56 | ||
55 | pr_emerg("%s: unable to restart system\n", __func__); | 57 | pr_emerg("%s: unable to restart system\n", __func__); |
@@ -57,11 +59,6 @@ static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode, | |||
57 | return NOTIFY_DONE; | 59 | return NOTIFY_DONE; |
58 | } | 60 | } |
59 | 61 | ||
60 | static struct notifier_block lpc18xx_rgu_restart_nb = { | ||
61 | .notifier_call = lpc18xx_rgu_restart, | ||
62 | .priority = 192, | ||
63 | }; | ||
64 | |||
65 | /* | 62 | /* |
66 | * The LPC18xx RGU has mostly self-deasserting resets except for the | 63 | * The LPC18xx RGU has mostly self-deasserting resets except for the |
67 | * two reset lines going to the internal Cortex-M0 cores. | 64 | * two reset lines going to the internal Cortex-M0 cores. |
@@ -205,8 +202,9 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev) | |||
205 | goto dis_clks; | 202 | goto dis_clks; |
206 | } | 203 | } |
207 | 204 | ||
208 | rgu_base = rc->base; | 205 | rc->restart_nb.priority = 192, |
209 | ret = register_restart_handler(&lpc18xx_rgu_restart_nb); | 206 | rc->restart_nb.notifier_call = lpc18xx_rgu_restart, |
207 | ret = register_restart_handler(&rc->restart_nb); | ||
210 | if (ret) | 208 | if (ret) |
211 | dev_warn(&pdev->dev, "failed to register restart handler\n"); | 209 | dev_warn(&pdev->dev, "failed to register restart handler\n"); |
212 | 210 | ||
@@ -225,7 +223,7 @@ static int lpc18xx_rgu_remove(struct platform_device *pdev) | |||
225 | struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev); | 223 | struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev); |
226 | int ret; | 224 | int ret; |
227 | 225 | ||
228 | ret = unregister_restart_handler(&lpc18xx_rgu_restart_nb); | 226 | ret = unregister_restart_handler(&rc->restart_nb); |
229 | if (ret) | 227 | if (ret) |
230 | dev_warn(&pdev->dev, "failed to unregister restart handler\n"); | 228 | dev_warn(&pdev->dev, "failed to unregister restart handler\n"); |
231 | 229 | ||
diff --git a/drivers/reset/reset-oxnas.c b/drivers/reset/reset-oxnas.c new file mode 100644 index 000000000000..c60fb2dace3e --- /dev/null +++ b/drivers/reset/reset-oxnas.c | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * drivers/reset/reset-oxnas.c | ||
3 | * | ||
4 | * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> | ||
5 | * Copyright (C) 2014 Ma Haijun <mahaijuns@gmail.com> | ||
6 | * Copyright (C) 2009 Oxford Semiconductor Ltd | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/reset-controller.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/regmap.h> | ||
29 | #include <linux/mfd/syscon.h> | ||
30 | |||
31 | /* Regmap offsets */ | ||
32 | #define RST_SET_REGOFFSET 0x34 | ||
33 | #define RST_CLR_REGOFFSET 0x38 | ||
34 | |||
35 | struct oxnas_reset { | ||
36 | struct regmap *regmap; | ||
37 | struct reset_controller_dev rcdev; | ||
38 | }; | ||
39 | |||
40 | static int oxnas_reset_reset(struct reset_controller_dev *rcdev, | ||
41 | unsigned long id) | ||
42 | { | ||
43 | struct oxnas_reset *data = | ||
44 | container_of(rcdev, struct oxnas_reset, rcdev); | ||
45 | |||
46 | regmap_write(data->regmap, RST_SET_REGOFFSET, BIT(id)); | ||
47 | msleep(50); | ||
48 | regmap_write(data->regmap, RST_CLR_REGOFFSET, BIT(id)); | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int oxnas_reset_assert(struct reset_controller_dev *rcdev, | ||
54 | unsigned long id) | ||
55 | { | ||
56 | struct oxnas_reset *data = | ||
57 | container_of(rcdev, struct oxnas_reset, rcdev); | ||
58 | |||
59 | regmap_write(data->regmap, RST_SET_REGOFFSET, BIT(id)); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int oxnas_reset_deassert(struct reset_controller_dev *rcdev, | ||
65 | unsigned long id) | ||
66 | { | ||
67 | struct oxnas_reset *data = | ||
68 | container_of(rcdev, struct oxnas_reset, rcdev); | ||
69 | |||
70 | regmap_write(data->regmap, RST_CLR_REGOFFSET, BIT(id)); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static const struct reset_control_ops oxnas_reset_ops = { | ||
76 | .reset = oxnas_reset_reset, | ||
77 | .assert = oxnas_reset_assert, | ||
78 | .deassert = oxnas_reset_deassert, | ||
79 | }; | ||
80 | |||
81 | static const struct of_device_id oxnas_reset_dt_ids[] = { | ||
82 | { .compatible = "oxsemi,ox810se-reset", }, | ||
83 | { /* sentinel */ }, | ||
84 | }; | ||
85 | MODULE_DEVICE_TABLE(of, oxnas_reset_dt_ids); | ||
86 | |||
87 | static int oxnas_reset_probe(struct platform_device *pdev) | ||
88 | { | ||
89 | struct oxnas_reset *data; | ||
90 | struct device *parent; | ||
91 | |||
92 | parent = pdev->dev.parent; | ||
93 | if (!parent) { | ||
94 | dev_err(&pdev->dev, "no parent\n"); | ||
95 | return -ENODEV; | ||
96 | } | ||
97 | |||
98 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
99 | if (!data) | ||
100 | return -ENOMEM; | ||
101 | |||
102 | data->regmap = syscon_node_to_regmap(parent->of_node); | ||
103 | if (IS_ERR(data->regmap)) { | ||
104 | dev_err(&pdev->dev, "failed to get parent regmap\n"); | ||
105 | return PTR_ERR(data->regmap); | ||
106 | } | ||
107 | |||
108 | platform_set_drvdata(pdev, data); | ||
109 | |||
110 | data->rcdev.owner = THIS_MODULE; | ||
111 | data->rcdev.nr_resets = 32; | ||
112 | data->rcdev.ops = &oxnas_reset_ops; | ||
113 | data->rcdev.of_node = pdev->dev.of_node; | ||
114 | |||
115 | return reset_controller_register(&data->rcdev); | ||
116 | } | ||
117 | |||
118 | static int oxnas_reset_remove(struct platform_device *pdev) | ||
119 | { | ||
120 | struct oxnas_reset *data = platform_get_drvdata(pdev); | ||
121 | |||
122 | reset_controller_unregister(&data->rcdev); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static struct platform_driver oxnas_reset_driver = { | ||
128 | .probe = oxnas_reset_probe, | ||
129 | .remove = oxnas_reset_remove, | ||
130 | .driver = { | ||
131 | .name = "oxnas-reset", | ||
132 | .of_match_table = oxnas_reset_dt_ids, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | module_platform_driver(oxnas_reset_driver); | ||
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 5ade71306ee1..380230f03874 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile | |||
@@ -9,7 +9,8 @@ obj-$(CONFIG_MACH_DOVE) += dove/ | |||
9 | obj-y += fsl/ | 9 | obj-y += fsl/ |
10 | obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ | 10 | obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ |
11 | obj-$(CONFIG_ARCH_QCOM) += qcom/ | 11 | obj-$(CONFIG_ARCH_QCOM) += qcom/ |
12 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 12 | obj-$(CONFIG_ARCH_RENESAS) += renesas/ |
13 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | ||
13 | obj-$(CONFIG_SOC_SAMSUNG) += samsung/ | 14 | obj-$(CONFIG_SOC_SAMSUNG) += samsung/ |
14 | obj-$(CONFIG_ARCH_SUNXI) += sunxi/ | 15 | obj-$(CONFIG_ARCH_SUNXI) += sunxi/ |
15 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ | 16 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ |
diff --git a/drivers/soc/brcmstb/Kconfig b/drivers/soc/brcmstb/Kconfig index 39cab3bd544d..7fec3b4c80a1 100644 --- a/drivers/soc/brcmstb/Kconfig +++ b/drivers/soc/brcmstb/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | menuconfig SOC_BRCMSTB | 1 | menuconfig SOC_BRCMSTB |
2 | bool "Broadcom STB SoC drivers" | 2 | bool "Broadcom STB SoC drivers" |
3 | depends on ARM | 3 | depends on ARM |
4 | select SOC_BUS | ||
4 | help | 5 | help |
5 | Enables drivers for the Broadcom Set-Top Box (STB) series of chips. | 6 | Enables drivers for the Broadcom Set-Top Box (STB) series of chips. |
6 | This option alone enables only some support code, while the drivers | 7 | This option alone enables only some support code, while the drivers |
diff --git a/drivers/soc/brcmstb/common.c b/drivers/soc/brcmstb/common.c index c262c029b1b8..94e7335553f4 100644 --- a/drivers/soc/brcmstb/common.c +++ b/drivers/soc/brcmstb/common.c | |||
@@ -12,10 +12,18 @@ | |||
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/io.h> | ||
15 | #include <linux/of.h> | 16 | #include <linux/of.h> |
17 | #include <linux/of_address.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/soc/brcmstb/brcmstb.h> | ||
20 | #include <linux/sys_soc.h> | ||
16 | 21 | ||
17 | #include <soc/brcmstb/common.h> | 22 | #include <soc/brcmstb/common.h> |
18 | 23 | ||
24 | static u32 family_id; | ||
25 | static u32 product_id; | ||
26 | |||
19 | static const struct of_device_id brcmstb_machine_match[] = { | 27 | static const struct of_device_id brcmstb_machine_match[] = { |
20 | { .compatible = "brcm,brcmstb", }, | 28 | { .compatible = "brcm,brcmstb", }, |
21 | { } | 29 | { } |
@@ -31,3 +39,61 @@ bool soc_is_brcmstb(void) | |||
31 | 39 | ||
32 | return of_match_node(brcmstb_machine_match, root) != NULL; | 40 | return of_match_node(brcmstb_machine_match, root) != NULL; |
33 | } | 41 | } |
42 | |||
43 | static const struct of_device_id sun_top_ctrl_match[] = { | ||
44 | { .compatible = "brcm,brcmstb-sun-top-ctrl", }, | ||
45 | { } | ||
46 | }; | ||
47 | |||
48 | static int __init brcmstb_soc_device_init(void) | ||
49 | { | ||
50 | struct soc_device_attribute *soc_dev_attr; | ||
51 | struct soc_device *soc_dev; | ||
52 | struct device_node *sun_top_ctrl; | ||
53 | void __iomem *sun_top_ctrl_base; | ||
54 | int ret = 0; | ||
55 | |||
56 | sun_top_ctrl = of_find_matching_node(NULL, sun_top_ctrl_match); | ||
57 | if (!sun_top_ctrl) | ||
58 | return -ENODEV; | ||
59 | |||
60 | sun_top_ctrl_base = of_iomap(sun_top_ctrl, 0); | ||
61 | if (!sun_top_ctrl_base) | ||
62 | return -ENODEV; | ||
63 | |||
64 | family_id = readl(sun_top_ctrl_base); | ||
65 | product_id = readl(sun_top_ctrl_base + 0x4); | ||
66 | |||
67 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | ||
68 | if (!soc_dev_attr) { | ||
69 | ret = -ENOMEM; | ||
70 | goto out; | ||
71 | } | ||
72 | |||
73 | soc_dev_attr->family = kasprintf(GFP_KERNEL, "%x", | ||
74 | family_id >> 28 ? | ||
75 | family_id >> 16 : family_id >> 8); | ||
76 | soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%x", | ||
77 | product_id >> 28 ? | ||
78 | product_id >> 16 : product_id >> 8); | ||
79 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c%d", | ||
80 | ((product_id & 0xf0) >> 4) + 'A', | ||
81 | product_id & 0xf); | ||
82 | |||
83 | soc_dev = soc_device_register(soc_dev_attr); | ||
84 | if (IS_ERR(soc_dev)) { | ||
85 | kfree(soc_dev_attr->family); | ||
86 | kfree(soc_dev_attr->soc_id); | ||
87 | kfree(soc_dev_attr->revision); | ||
88 | kfree(soc_dev_attr); | ||
89 | ret = -ENODEV; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | return 0; | ||
94 | |||
95 | out: | ||
96 | iounmap(sun_top_ctrl_base); | ||
97 | return ret; | ||
98 | } | ||
99 | arch_initcall(brcmstb_soc_device_init); | ||
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 0d9b19a78d27..3c3e56df526e 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #define PWRAP_DEW_WRITE_TEST_VAL 0xa55a | 52 | #define PWRAP_DEW_WRITE_TEST_VAL 0xa55a |
53 | 53 | ||
54 | /* macro for manual command */ | 54 | /* macro for manual command */ |
55 | #define PWRAP_MAN_CMD_SPI_WRITE_NEW (1 << 14) | ||
55 | #define PWRAP_MAN_CMD_SPI_WRITE (1 << 13) | 56 | #define PWRAP_MAN_CMD_SPI_WRITE (1 << 13) |
56 | #define PWRAP_MAN_CMD_OP_CSH (0x0 << 8) | 57 | #define PWRAP_MAN_CMD_OP_CSH (0x0 << 8) |
57 | #define PWRAP_MAN_CMD_OP_CSL (0x1 << 8) | 58 | #define PWRAP_MAN_CMD_OP_CSL (0x1 << 8) |
@@ -69,33 +70,75 @@ | |||
69 | PWRAP_WDT_SRC_EN_HARB_STAUPD_DLE | \ | 70 | PWRAP_WDT_SRC_EN_HARB_STAUPD_DLE | \ |
70 | PWRAP_WDT_SRC_EN_HARB_STAUPD_ALE) | 71 | PWRAP_WDT_SRC_EN_HARB_STAUPD_ALE) |
71 | 72 | ||
72 | /* macro for slave device wrapper registers */ | 73 | /* defines for slave device wrapper registers */ |
73 | #define PWRAP_DEW_BASE 0xbc00 | 74 | enum dew_regs { |
74 | #define PWRAP_DEW_EVENT_OUT_EN (PWRAP_DEW_BASE + 0x0) | 75 | PWRAP_DEW_BASE, |
75 | #define PWRAP_DEW_DIO_EN (PWRAP_DEW_BASE + 0x2) | 76 | PWRAP_DEW_DIO_EN, |
76 | #define PWRAP_DEW_EVENT_SRC_EN (PWRAP_DEW_BASE + 0x4) | 77 | PWRAP_DEW_READ_TEST, |
77 | #define PWRAP_DEW_EVENT_SRC (PWRAP_DEW_BASE + 0x6) | 78 | PWRAP_DEW_WRITE_TEST, |
78 | #define PWRAP_DEW_EVENT_FLAG (PWRAP_DEW_BASE + 0x8) | 79 | PWRAP_DEW_CRC_EN, |
79 | #define PWRAP_DEW_READ_TEST (PWRAP_DEW_BASE + 0xa) | 80 | PWRAP_DEW_CRC_VAL, |
80 | #define PWRAP_DEW_WRITE_TEST (PWRAP_DEW_BASE + 0xc) | 81 | PWRAP_DEW_MON_GRP_SEL, |
81 | #define PWRAP_DEW_CRC_EN (PWRAP_DEW_BASE + 0xe) | 82 | PWRAP_DEW_CIPHER_KEY_SEL, |
82 | #define PWRAP_DEW_CRC_VAL (PWRAP_DEW_BASE + 0x10) | 83 | PWRAP_DEW_CIPHER_IV_SEL, |
83 | #define PWRAP_DEW_MON_GRP_SEL (PWRAP_DEW_BASE + 0x12) | 84 | PWRAP_DEW_CIPHER_RDY, |
84 | #define PWRAP_DEW_MON_FLAG_SEL (PWRAP_DEW_BASE + 0x14) | 85 | PWRAP_DEW_CIPHER_MODE, |
85 | #define PWRAP_DEW_EVENT_TEST (PWRAP_DEW_BASE + 0x16) | 86 | PWRAP_DEW_CIPHER_SWRST, |
86 | #define PWRAP_DEW_CIPHER_KEY_SEL (PWRAP_DEW_BASE + 0x18) | 87 | |
87 | #define PWRAP_DEW_CIPHER_IV_SEL (PWRAP_DEW_BASE + 0x1a) | 88 | /* MT6397 only regs */ |
88 | #define PWRAP_DEW_CIPHER_LOAD (PWRAP_DEW_BASE + 0x1c) | 89 | PWRAP_DEW_EVENT_OUT_EN, |
89 | #define PWRAP_DEW_CIPHER_START (PWRAP_DEW_BASE + 0x1e) | 90 | PWRAP_DEW_EVENT_SRC_EN, |
90 | #define PWRAP_DEW_CIPHER_RDY (PWRAP_DEW_BASE + 0x20) | 91 | PWRAP_DEW_EVENT_SRC, |
91 | #define PWRAP_DEW_CIPHER_MODE (PWRAP_DEW_BASE + 0x22) | 92 | PWRAP_DEW_EVENT_FLAG, |
92 | #define PWRAP_DEW_CIPHER_SWRST (PWRAP_DEW_BASE + 0x24) | 93 | PWRAP_DEW_MON_FLAG_SEL, |
93 | #define PWRAP_MT8173_DEW_CIPHER_IV0 (PWRAP_DEW_BASE + 0x26) | 94 | PWRAP_DEW_EVENT_TEST, |
94 | #define PWRAP_MT8173_DEW_CIPHER_IV1 (PWRAP_DEW_BASE + 0x28) | 95 | PWRAP_DEW_CIPHER_LOAD, |
95 | #define PWRAP_MT8173_DEW_CIPHER_IV2 (PWRAP_DEW_BASE + 0x2a) | 96 | PWRAP_DEW_CIPHER_START, |
96 | #define PWRAP_MT8173_DEW_CIPHER_IV3 (PWRAP_DEW_BASE + 0x2c) | 97 | |
97 | #define PWRAP_MT8173_DEW_CIPHER_IV4 (PWRAP_DEW_BASE + 0x2e) | 98 | /* MT6323 only regs */ |
98 | #define PWRAP_MT8173_DEW_CIPHER_IV5 (PWRAP_DEW_BASE + 0x30) | 99 | PWRAP_DEW_CIPHER_EN, |
100 | PWRAP_DEW_RDDMY_NO, | ||
101 | }; | ||
102 | |||
103 | static const u32 mt6323_regs[] = { | ||
104 | [PWRAP_DEW_BASE] = 0x0000, | ||
105 | [PWRAP_DEW_DIO_EN] = 0x018a, | ||
106 | [PWRAP_DEW_READ_TEST] = 0x018c, | ||
107 | [PWRAP_DEW_WRITE_TEST] = 0x018e, | ||
108 | [PWRAP_DEW_CRC_EN] = 0x0192, | ||
109 | [PWRAP_DEW_CRC_VAL] = 0x0194, | ||
110 | [PWRAP_DEW_MON_GRP_SEL] = 0x0196, | ||
111 | [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0198, | ||
112 | [PWRAP_DEW_CIPHER_IV_SEL] = 0x019a, | ||
113 | [PWRAP_DEW_CIPHER_EN] = 0x019c, | ||
114 | [PWRAP_DEW_CIPHER_RDY] = 0x019e, | ||
115 | [PWRAP_DEW_CIPHER_MODE] = 0x01a0, | ||
116 | [PWRAP_DEW_CIPHER_SWRST] = 0x01a2, | ||
117 | [PWRAP_DEW_RDDMY_NO] = 0x01a4, | ||
118 | }; | ||
119 | |||
120 | static const u32 mt6397_regs[] = { | ||
121 | [PWRAP_DEW_BASE] = 0xbc00, | ||
122 | [PWRAP_DEW_EVENT_OUT_EN] = 0xbc00, | ||
123 | [PWRAP_DEW_DIO_EN] = 0xbc02, | ||
124 | [PWRAP_DEW_EVENT_SRC_EN] = 0xbc04, | ||
125 | [PWRAP_DEW_EVENT_SRC] = 0xbc06, | ||
126 | [PWRAP_DEW_EVENT_FLAG] = 0xbc08, | ||
127 | [PWRAP_DEW_READ_TEST] = 0xbc0a, | ||
128 | [PWRAP_DEW_WRITE_TEST] = 0xbc0c, | ||
129 | [PWRAP_DEW_CRC_EN] = 0xbc0e, | ||
130 | [PWRAP_DEW_CRC_VAL] = 0xbc10, | ||
131 | [PWRAP_DEW_MON_GRP_SEL] = 0xbc12, | ||
132 | [PWRAP_DEW_MON_FLAG_SEL] = 0xbc14, | ||
133 | [PWRAP_DEW_EVENT_TEST] = 0xbc16, | ||
134 | [PWRAP_DEW_CIPHER_KEY_SEL] = 0xbc18, | ||
135 | [PWRAP_DEW_CIPHER_IV_SEL] = 0xbc1a, | ||
136 | [PWRAP_DEW_CIPHER_LOAD] = 0xbc1c, | ||
137 | [PWRAP_DEW_CIPHER_START] = 0xbc1e, | ||
138 | [PWRAP_DEW_CIPHER_RDY] = 0xbc20, | ||
139 | [PWRAP_DEW_CIPHER_MODE] = 0xbc22, | ||
140 | [PWRAP_DEW_CIPHER_SWRST] = 0xbc24, | ||
141 | }; | ||
99 | 142 | ||
100 | enum pwrap_regs { | 143 | enum pwrap_regs { |
101 | PWRAP_MUX_SEL, | 144 | PWRAP_MUX_SEL, |
@@ -158,6 +201,13 @@ enum pwrap_regs { | |||
158 | PWRAP_DCM_EN, | 201 | PWRAP_DCM_EN, |
159 | PWRAP_DCM_DBC_PRD, | 202 | PWRAP_DCM_DBC_PRD, |
160 | 203 | ||
204 | /* MT2701 only regs */ | ||
205 | PWRAP_ADC_CMD_ADDR, | ||
206 | PWRAP_PWRAP_ADC_CMD, | ||
207 | PWRAP_ADC_RDY_ADDR, | ||
208 | PWRAP_ADC_RDATA_ADDR1, | ||
209 | PWRAP_ADC_RDATA_ADDR2, | ||
210 | |||
161 | /* MT8135 only regs */ | 211 | /* MT8135 only regs */ |
162 | PWRAP_CSHEXT, | 212 | PWRAP_CSHEXT, |
163 | PWRAP_EVENT_IN_EN, | 213 | PWRAP_EVENT_IN_EN, |
@@ -194,6 +244,92 @@ enum pwrap_regs { | |||
194 | PWRAP_CIPHER_EN, | 244 | PWRAP_CIPHER_EN, |
195 | }; | 245 | }; |
196 | 246 | ||
247 | static int mt2701_regs[] = { | ||
248 | [PWRAP_MUX_SEL] = 0x0, | ||
249 | [PWRAP_WRAP_EN] = 0x4, | ||
250 | [PWRAP_DIO_EN] = 0x8, | ||
251 | [PWRAP_SIDLY] = 0xc, | ||
252 | [PWRAP_RDDMY] = 0x18, | ||
253 | [PWRAP_SI_CK_CON] = 0x1c, | ||
254 | [PWRAP_CSHEXT_WRITE] = 0x20, | ||
255 | [PWRAP_CSHEXT_READ] = 0x24, | ||
256 | [PWRAP_CSLEXT_START] = 0x28, | ||
257 | [PWRAP_CSLEXT_END] = 0x2c, | ||
258 | [PWRAP_STAUPD_PRD] = 0x30, | ||
259 | [PWRAP_STAUPD_GRPEN] = 0x34, | ||
260 | [PWRAP_STAUPD_MAN_TRIG] = 0x38, | ||
261 | [PWRAP_STAUPD_STA] = 0x3c, | ||
262 | [PWRAP_WRAP_STA] = 0x44, | ||
263 | [PWRAP_HARB_INIT] = 0x48, | ||
264 | [PWRAP_HARB_HPRIO] = 0x4c, | ||
265 | [PWRAP_HIPRIO_ARB_EN] = 0x50, | ||
266 | [PWRAP_HARB_STA0] = 0x54, | ||
267 | [PWRAP_HARB_STA1] = 0x58, | ||
268 | [PWRAP_MAN_EN] = 0x5c, | ||
269 | [PWRAP_MAN_CMD] = 0x60, | ||
270 | [PWRAP_MAN_RDATA] = 0x64, | ||
271 | [PWRAP_MAN_VLDCLR] = 0x68, | ||
272 | [PWRAP_WACS0_EN] = 0x6c, | ||
273 | [PWRAP_INIT_DONE0] = 0x70, | ||
274 | [PWRAP_WACS0_CMD] = 0x74, | ||
275 | [PWRAP_WACS0_RDATA] = 0x78, | ||
276 | [PWRAP_WACS0_VLDCLR] = 0x7c, | ||
277 | [PWRAP_WACS1_EN] = 0x80, | ||
278 | [PWRAP_INIT_DONE1] = 0x84, | ||
279 | [PWRAP_WACS1_CMD] = 0x88, | ||
280 | [PWRAP_WACS1_RDATA] = 0x8c, | ||
281 | [PWRAP_WACS1_VLDCLR] = 0x90, | ||
282 | [PWRAP_WACS2_EN] = 0x94, | ||
283 | [PWRAP_INIT_DONE2] = 0x98, | ||
284 | [PWRAP_WACS2_CMD] = 0x9c, | ||
285 | [PWRAP_WACS2_RDATA] = 0xa0, | ||
286 | [PWRAP_WACS2_VLDCLR] = 0xa4, | ||
287 | [PWRAP_INT_EN] = 0xa8, | ||
288 | [PWRAP_INT_FLG_RAW] = 0xac, | ||
289 | [PWRAP_INT_FLG] = 0xb0, | ||
290 | [PWRAP_INT_CLR] = 0xb4, | ||
291 | [PWRAP_SIG_ADR] = 0xb8, | ||
292 | [PWRAP_SIG_MODE] = 0xbc, | ||
293 | [PWRAP_SIG_VALUE] = 0xc0, | ||
294 | [PWRAP_SIG_ERRVAL] = 0xc4, | ||
295 | [PWRAP_CRC_EN] = 0xc8, | ||
296 | [PWRAP_TIMER_EN] = 0xcc, | ||
297 | [PWRAP_TIMER_STA] = 0xd0, | ||
298 | [PWRAP_WDT_UNIT] = 0xd4, | ||
299 | [PWRAP_WDT_SRC_EN] = 0xd8, | ||
300 | [PWRAP_WDT_FLG] = 0xdc, | ||
301 | [PWRAP_DEBUG_INT_SEL] = 0xe0, | ||
302 | [PWRAP_DVFS_ADR0] = 0xe4, | ||
303 | [PWRAP_DVFS_WDATA0] = 0xe8, | ||
304 | [PWRAP_DVFS_ADR1] = 0xec, | ||
305 | [PWRAP_DVFS_WDATA1] = 0xf0, | ||
306 | [PWRAP_DVFS_ADR2] = 0xf4, | ||
307 | [PWRAP_DVFS_WDATA2] = 0xf8, | ||
308 | [PWRAP_DVFS_ADR3] = 0xfc, | ||
309 | [PWRAP_DVFS_WDATA3] = 0x100, | ||
310 | [PWRAP_DVFS_ADR4] = 0x104, | ||
311 | [PWRAP_DVFS_WDATA4] = 0x108, | ||
312 | [PWRAP_DVFS_ADR5] = 0x10c, | ||
313 | [PWRAP_DVFS_WDATA5] = 0x110, | ||
314 | [PWRAP_DVFS_ADR6] = 0x114, | ||
315 | [PWRAP_DVFS_WDATA6] = 0x118, | ||
316 | [PWRAP_DVFS_ADR7] = 0x11c, | ||
317 | [PWRAP_DVFS_WDATA7] = 0x120, | ||
318 | [PWRAP_CIPHER_KEY_SEL] = 0x124, | ||
319 | [PWRAP_CIPHER_IV_SEL] = 0x128, | ||
320 | [PWRAP_CIPHER_EN] = 0x12c, | ||
321 | [PWRAP_CIPHER_RDY] = 0x130, | ||
322 | [PWRAP_CIPHER_MODE] = 0x134, | ||
323 | [PWRAP_CIPHER_SWRST] = 0x138, | ||
324 | [PWRAP_DCM_EN] = 0x13c, | ||
325 | [PWRAP_DCM_DBC_PRD] = 0x140, | ||
326 | [PWRAP_ADC_CMD_ADDR] = 0x144, | ||
327 | [PWRAP_PWRAP_ADC_CMD] = 0x148, | ||
328 | [PWRAP_ADC_RDY_ADDR] = 0x14c, | ||
329 | [PWRAP_ADC_RDATA_ADDR1] = 0x150, | ||
330 | [PWRAP_ADC_RDATA_ADDR2] = 0x154, | ||
331 | }; | ||
332 | |||
197 | static int mt8173_regs[] = { | 333 | static int mt8173_regs[] = { |
198 | [PWRAP_MUX_SEL] = 0x0, | 334 | [PWRAP_MUX_SEL] = 0x0, |
199 | [PWRAP_WRAP_EN] = 0x4, | 335 | [PWRAP_WRAP_EN] = 0x4, |
@@ -349,36 +485,28 @@ static int mt8135_regs[] = { | |||
349 | [PWRAP_DCM_DBC_PRD] = 0x160, | 485 | [PWRAP_DCM_DBC_PRD] = 0x160, |
350 | }; | 486 | }; |
351 | 487 | ||
488 | enum pmic_type { | ||
489 | PMIC_MT6323, | ||
490 | PMIC_MT6397, | ||
491 | }; | ||
492 | |||
352 | enum pwrap_type { | 493 | enum pwrap_type { |
494 | PWRAP_MT2701, | ||
353 | PWRAP_MT8135, | 495 | PWRAP_MT8135, |
354 | PWRAP_MT8173, | 496 | PWRAP_MT8173, |
355 | }; | 497 | }; |
356 | 498 | ||
357 | struct pmic_wrapper_type { | 499 | struct pwrap_slv_type { |
358 | int *regs; | 500 | const u32 *dew_regs; |
359 | enum pwrap_type type; | 501 | enum pmic_type type; |
360 | u32 arb_en_all; | ||
361 | }; | ||
362 | |||
363 | static struct pmic_wrapper_type pwrap_mt8135 = { | ||
364 | .regs = mt8135_regs, | ||
365 | .type = PWRAP_MT8135, | ||
366 | .arb_en_all = 0x1ff, | ||
367 | }; | ||
368 | |||
369 | static struct pmic_wrapper_type pwrap_mt8173 = { | ||
370 | .regs = mt8173_regs, | ||
371 | .type = PWRAP_MT8173, | ||
372 | .arb_en_all = 0x3f, | ||
373 | }; | 502 | }; |
374 | 503 | ||
375 | struct pmic_wrapper { | 504 | struct pmic_wrapper { |
376 | struct device *dev; | 505 | struct device *dev; |
377 | void __iomem *base; | 506 | void __iomem *base; |
378 | struct regmap *regmap; | 507 | struct regmap *regmap; |
379 | int *regs; | 508 | const struct pmic_wrapper_type *master; |
380 | enum pwrap_type type; | 509 | const struct pwrap_slv_type *slave; |
381 | u32 arb_en_all; | ||
382 | struct clk *clk_spi; | 510 | struct clk *clk_spi; |
383 | struct clk *clk_wrap; | 511 | struct clk *clk_wrap; |
384 | struct reset_control *rstc; | 512 | struct reset_control *rstc; |
@@ -387,24 +515,26 @@ struct pmic_wrapper { | |||
387 | void __iomem *bridge_base; | 515 | void __iomem *bridge_base; |
388 | }; | 516 | }; |
389 | 517 | ||
390 | static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp) | 518 | struct pmic_wrapper_type { |
391 | { | 519 | int *regs; |
392 | return wrp->type == PWRAP_MT8135; | 520 | enum pwrap_type type; |
393 | } | 521 | u32 arb_en_all; |
394 | 522 | u32 int_en_all; | |
395 | static inline int pwrap_is_mt8173(struct pmic_wrapper *wrp) | 523 | u32 spi_w; |
396 | { | 524 | u32 wdt_src; |
397 | return wrp->type == PWRAP_MT8173; | 525 | int has_bridge:1; |
398 | } | 526 | int (*init_reg_clock)(struct pmic_wrapper *wrp); |
527 | int (*init_soc_specific)(struct pmic_wrapper *wrp); | ||
528 | }; | ||
399 | 529 | ||
400 | static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg) | 530 | static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg) |
401 | { | 531 | { |
402 | return readl(wrp->base + wrp->regs[reg]); | 532 | return readl(wrp->base + wrp->master->regs[reg]); |
403 | } | 533 | } |
404 | 534 | ||
405 | static void pwrap_writel(struct pmic_wrapper *wrp, u32 val, enum pwrap_regs reg) | 535 | static void pwrap_writel(struct pmic_wrapper *wrp, u32 val, enum pwrap_regs reg) |
406 | { | 536 | { |
407 | writel(val, wrp->base + wrp->regs[reg]); | 537 | writel(val, wrp->base + wrp->master->regs[reg]); |
408 | } | 538 | } |
409 | 539 | ||
410 | static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp) | 540 | static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp) |
@@ -522,15 +652,15 @@ static int pwrap_reset_spislave(struct pmic_wrapper *wrp) | |||
522 | pwrap_writel(wrp, 1, PWRAP_MAN_EN); | 652 | pwrap_writel(wrp, 1, PWRAP_MAN_EN); |
523 | pwrap_writel(wrp, 0, PWRAP_DIO_EN); | 653 | pwrap_writel(wrp, 0, PWRAP_DIO_EN); |
524 | 654 | ||
525 | pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_CSL, | 655 | pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSL, |
526 | PWRAP_MAN_CMD); | 656 | PWRAP_MAN_CMD); |
527 | pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_OUTS, | 657 | pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS, |
528 | PWRAP_MAN_CMD); | 658 | PWRAP_MAN_CMD); |
529 | pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_CSH, | 659 | pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSH, |
530 | PWRAP_MAN_CMD); | 660 | PWRAP_MAN_CMD); |
531 | 661 | ||
532 | for (i = 0; i < 4; i++) | 662 | for (i = 0; i < 4; i++) |
533 | pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_OUTS, | 663 | pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS, |
534 | PWRAP_MAN_CMD); | 664 | PWRAP_MAN_CMD); |
535 | 665 | ||
536 | ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle); | 666 | ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle); |
@@ -562,7 +692,8 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp) | |||
562 | 692 | ||
563 | for (i = 0; i < 4; i++) { | 693 | for (i = 0; i < 4; i++) { |
564 | pwrap_writel(wrp, i, PWRAP_SIDLY); | 694 | pwrap_writel(wrp, i, PWRAP_SIDLY); |
565 | pwrap_read(wrp, PWRAP_DEW_READ_TEST, &rdata); | 695 | pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_READ_TEST], |
696 | &rdata); | ||
566 | if (rdata == PWRAP_DEW_READ_TEST_VAL) { | 697 | if (rdata == PWRAP_DEW_READ_TEST_VAL) { |
567 | dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i); | 698 | dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i); |
568 | pass |= 1 << i; | 699 | pass |= 1 << i; |
@@ -580,19 +711,47 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp) | |||
580 | return 0; | 711 | return 0; |
581 | } | 712 | } |
582 | 713 | ||
583 | static int pwrap_init_reg_clock(struct pmic_wrapper *wrp) | 714 | static int pwrap_mt8135_init_reg_clock(struct pmic_wrapper *wrp) |
715 | { | ||
716 | pwrap_writel(wrp, 0x4, PWRAP_CSHEXT); | ||
717 | pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); | ||
718 | pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); | ||
719 | pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START); | ||
720 | pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END); | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static int pwrap_mt8173_init_reg_clock(struct pmic_wrapper *wrp) | ||
584 | { | 726 | { |
585 | if (pwrap_is_mt8135(wrp)) { | 727 | pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); |
586 | pwrap_writel(wrp, 0x4, PWRAP_CSHEXT); | 728 | pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); |
587 | pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); | 729 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_START); |
588 | pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); | 730 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_END); |
589 | pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START); | 731 | |
590 | pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END); | 732 | return 0; |
591 | } else { | 733 | } |
592 | pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); | 734 | |
593 | pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); | 735 | static int pwrap_mt2701_init_reg_clock(struct pmic_wrapper *wrp) |
736 | { | ||
737 | switch (wrp->slave->type) { | ||
738 | case PMIC_MT6397: | ||
739 | pwrap_writel(wrp, 0xc, PWRAP_RDDMY); | ||
740 | pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_WRITE); | ||
741 | pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_READ); | ||
742 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_START); | ||
743 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_END); | ||
744 | break; | ||
745 | |||
746 | case PMIC_MT6323: | ||
747 | pwrap_writel(wrp, 0x8, PWRAP_RDDMY); | ||
748 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_RDDMY_NO], | ||
749 | 0x8); | ||
750 | pwrap_writel(wrp, 0x5, PWRAP_CSHEXT_WRITE); | ||
751 | pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_READ); | ||
594 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_START); | 752 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_START); |
595 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_END); | 753 | pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_END); |
754 | break; | ||
596 | } | 755 | } |
597 | 756 | ||
598 | return 0; | 757 | return 0; |
@@ -608,7 +767,8 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp) | |||
608 | u32 rdata; | 767 | u32 rdata; |
609 | int ret; | 768 | int ret; |
610 | 769 | ||
611 | ret = pwrap_read(wrp, PWRAP_DEW_CIPHER_RDY, &rdata); | 770 | ret = pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_RDY], |
771 | &rdata); | ||
612 | if (ret) | 772 | if (ret) |
613 | return 0; | 773 | return 0; |
614 | 774 | ||
@@ -625,20 +785,37 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) | |||
625 | pwrap_writel(wrp, 0x1, PWRAP_CIPHER_KEY_SEL); | 785 | pwrap_writel(wrp, 0x1, PWRAP_CIPHER_KEY_SEL); |
626 | pwrap_writel(wrp, 0x2, PWRAP_CIPHER_IV_SEL); | 786 | pwrap_writel(wrp, 0x2, PWRAP_CIPHER_IV_SEL); |
627 | 787 | ||
628 | if (pwrap_is_mt8135(wrp)) { | 788 | switch (wrp->master->type) { |
789 | case PWRAP_MT8135: | ||
629 | pwrap_writel(wrp, 1, PWRAP_CIPHER_LOAD); | 790 | pwrap_writel(wrp, 1, PWRAP_CIPHER_LOAD); |
630 | pwrap_writel(wrp, 1, PWRAP_CIPHER_START); | 791 | pwrap_writel(wrp, 1, PWRAP_CIPHER_START); |
631 | } else { | 792 | break; |
793 | case PWRAP_MT2701: | ||
794 | case PWRAP_MT8173: | ||
632 | pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); | 795 | pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); |
796 | break; | ||
633 | } | 797 | } |
634 | 798 | ||
635 | /* Config cipher mode @PMIC */ | 799 | /* Config cipher mode @PMIC */ |
636 | pwrap_write(wrp, PWRAP_DEW_CIPHER_SWRST, 0x1); | 800 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x1); |
637 | pwrap_write(wrp, PWRAP_DEW_CIPHER_SWRST, 0x0); | 801 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0); |
638 | pwrap_write(wrp, PWRAP_DEW_CIPHER_KEY_SEL, 0x1); | 802 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1); |
639 | pwrap_write(wrp, PWRAP_DEW_CIPHER_IV_SEL, 0x2); | 803 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2); |
640 | pwrap_write(wrp, PWRAP_DEW_CIPHER_LOAD, 0x1); | 804 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], 0x1); |
641 | pwrap_write(wrp, PWRAP_DEW_CIPHER_START, 0x1); | 805 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], 0x1); |
806 | |||
807 | switch (wrp->slave->type) { | ||
808 | case PMIC_MT6397: | ||
809 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], | ||
810 | 0x1); | ||
811 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], | ||
812 | 0x1); | ||
813 | break; | ||
814 | case PMIC_MT6323: | ||
815 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN], | ||
816 | 0x1); | ||
817 | break; | ||
818 | } | ||
642 | 819 | ||
643 | /* wait for cipher data ready@AP */ | 820 | /* wait for cipher data ready@AP */ |
644 | ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready); | 821 | ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready); |
@@ -655,7 +832,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) | |||
655 | } | 832 | } |
656 | 833 | ||
657 | /* wait for cipher mode idle */ | 834 | /* wait for cipher mode idle */ |
658 | pwrap_write(wrp, PWRAP_DEW_CIPHER_MODE, 0x1); | 835 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_MODE], 0x1); |
659 | ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle); | 836 | ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle); |
660 | if (ret) { | 837 | if (ret) { |
661 | dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret); | 838 | dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret); |
@@ -665,9 +842,11 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) | |||
665 | pwrap_writel(wrp, 1, PWRAP_CIPHER_MODE); | 842 | pwrap_writel(wrp, 1, PWRAP_CIPHER_MODE); |
666 | 843 | ||
667 | /* Write Test */ | 844 | /* Write Test */ |
668 | if (pwrap_write(wrp, PWRAP_DEW_WRITE_TEST, PWRAP_DEW_WRITE_TEST_VAL) || | 845 | if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_WRITE_TEST], |
669 | pwrap_read(wrp, PWRAP_DEW_WRITE_TEST, &rdata) || | 846 | PWRAP_DEW_WRITE_TEST_VAL) || |
670 | (rdata != PWRAP_DEW_WRITE_TEST_VAL)) { | 847 | pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_WRITE_TEST], |
848 | &rdata) || | ||
849 | (rdata != PWRAP_DEW_WRITE_TEST_VAL)) { | ||
671 | dev_err(wrp->dev, "rdata=0x%04X\n", rdata); | 850 | dev_err(wrp->dev, "rdata=0x%04X\n", rdata); |
672 | return -EFAULT; | 851 | return -EFAULT; |
673 | } | 852 | } |
@@ -675,6 +854,63 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) | |||
675 | return 0; | 854 | return 0; |
676 | } | 855 | } |
677 | 856 | ||
857 | static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp) | ||
858 | { | ||
859 | /* enable pwrap events and pwrap bridge in AP side */ | ||
860 | pwrap_writel(wrp, 0x1, PWRAP_EVENT_IN_EN); | ||
861 | pwrap_writel(wrp, 0xffff, PWRAP_EVENT_DST_EN); | ||
862 | writel(0x7f, wrp->bridge_base + PWRAP_MT8135_BRIDGE_IORD_ARB_EN); | ||
863 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS3_EN); | ||
864 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS4_EN); | ||
865 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_UNIT); | ||
866 | writel(0xffff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_SRC_EN); | ||
867 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_TIMER_EN); | ||
868 | writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN); | ||
869 | |||
870 | /* enable PMIC event out and sources */ | ||
871 | if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_OUT_EN], | ||
872 | 0x1) || | ||
873 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_SRC_EN], | ||
874 | 0xffff)) { | ||
875 | dev_err(wrp->dev, "enable dewrap fail\n"); | ||
876 | return -EFAULT; | ||
877 | } | ||
878 | |||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp) | ||
883 | { | ||
884 | /* PMIC_DEWRAP enables */ | ||
885 | if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_OUT_EN], | ||
886 | 0x1) || | ||
887 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_SRC_EN], | ||
888 | 0xffff)) { | ||
889 | dev_err(wrp->dev, "enable dewrap fail\n"); | ||
890 | return -EFAULT; | ||
891 | } | ||
892 | |||
893 | return 0; | ||
894 | } | ||
895 | |||
896 | static int pwrap_mt2701_init_soc_specific(struct pmic_wrapper *wrp) | ||
897 | { | ||
898 | /* GPS_INTF initialization */ | ||
899 | switch (wrp->slave->type) { | ||
900 | case PMIC_MT6323: | ||
901 | pwrap_writel(wrp, 0x076c, PWRAP_ADC_CMD_ADDR); | ||
902 | pwrap_writel(wrp, 0x8000, PWRAP_PWRAP_ADC_CMD); | ||
903 | pwrap_writel(wrp, 0x072c, PWRAP_ADC_RDY_ADDR); | ||
904 | pwrap_writel(wrp, 0x072e, PWRAP_ADC_RDATA_ADDR1); | ||
905 | pwrap_writel(wrp, 0x0730, PWRAP_ADC_RDATA_ADDR2); | ||
906 | break; | ||
907 | default: | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | return 0; | ||
912 | } | ||
913 | |||
678 | static int pwrap_init(struct pmic_wrapper *wrp) | 914 | static int pwrap_init(struct pmic_wrapper *wrp) |
679 | { | 915 | { |
680 | int ret; | 916 | int ret; |
@@ -684,7 +920,7 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
684 | if (wrp->rstc_bridge) | 920 | if (wrp->rstc_bridge) |
685 | reset_control_reset(wrp->rstc_bridge); | 921 | reset_control_reset(wrp->rstc_bridge); |
686 | 922 | ||
687 | if (pwrap_is_mt8173(wrp)) { | 923 | if (wrp->master->type == PWRAP_MT8173) { |
688 | /* Enable DCM */ | 924 | /* Enable DCM */ |
689 | pwrap_writel(wrp, 3, PWRAP_DCM_EN); | 925 | pwrap_writel(wrp, 3, PWRAP_DCM_EN); |
690 | pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD); | 926 | pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD); |
@@ -697,11 +933,11 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
697 | 933 | ||
698 | pwrap_writel(wrp, 1, PWRAP_WRAP_EN); | 934 | pwrap_writel(wrp, 1, PWRAP_WRAP_EN); |
699 | 935 | ||
700 | pwrap_writel(wrp, wrp->arb_en_all, PWRAP_HIPRIO_ARB_EN); | 936 | pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN); |
701 | 937 | ||
702 | pwrap_writel(wrp, 1, PWRAP_WACS2_EN); | 938 | pwrap_writel(wrp, 1, PWRAP_WACS2_EN); |
703 | 939 | ||
704 | ret = pwrap_init_reg_clock(wrp); | 940 | ret = wrp->master->init_reg_clock(wrp); |
705 | if (ret) | 941 | if (ret) |
706 | return ret; | 942 | return ret; |
707 | 943 | ||
@@ -711,7 +947,7 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
711 | return ret; | 947 | return ret; |
712 | 948 | ||
713 | /* Enable dual IO mode */ | 949 | /* Enable dual IO mode */ |
714 | pwrap_write(wrp, PWRAP_DEW_DIO_EN, 1); | 950 | pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_DIO_EN], 1); |
715 | 951 | ||
716 | /* Check IDLE & INIT_DONE in advance */ | 952 | /* Check IDLE & INIT_DONE in advance */ |
717 | ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle); | 953 | ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle); |
@@ -723,7 +959,7 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
723 | pwrap_writel(wrp, 1, PWRAP_DIO_EN); | 959 | pwrap_writel(wrp, 1, PWRAP_DIO_EN); |
724 | 960 | ||
725 | /* Read Test */ | 961 | /* Read Test */ |
726 | pwrap_read(wrp, PWRAP_DEW_READ_TEST, &rdata); | 962 | pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_READ_TEST], &rdata); |
727 | if (rdata != PWRAP_DEW_READ_TEST_VAL) { | 963 | if (rdata != PWRAP_DEW_READ_TEST_VAL) { |
728 | dev_err(wrp->dev, "Read test failed after switch to DIO mode: 0x%04x != 0x%04x\n", | 964 | dev_err(wrp->dev, "Read test failed after switch to DIO mode: 0x%04x != 0x%04x\n", |
729 | PWRAP_DEW_READ_TEST_VAL, rdata); | 965 | PWRAP_DEW_READ_TEST_VAL, rdata); |
@@ -736,15 +972,16 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
736 | return ret; | 972 | return ret; |
737 | 973 | ||
738 | /* Signature checking - using CRC */ | 974 | /* Signature checking - using CRC */ |
739 | if (pwrap_write(wrp, PWRAP_DEW_CRC_EN, 0x1)) | 975 | if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1)) |
740 | return -EFAULT; | 976 | return -EFAULT; |
741 | 977 | ||
742 | pwrap_writel(wrp, 0x1, PWRAP_CRC_EN); | 978 | pwrap_writel(wrp, 0x1, PWRAP_CRC_EN); |
743 | pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE); | 979 | pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE); |
744 | pwrap_writel(wrp, PWRAP_DEW_CRC_VAL, PWRAP_SIG_ADR); | 980 | pwrap_writel(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_VAL], |
745 | pwrap_writel(wrp, wrp->arb_en_all, PWRAP_HIPRIO_ARB_EN); | 981 | PWRAP_SIG_ADR); |
982 | pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN); | ||
746 | 983 | ||
747 | if (pwrap_is_mt8135(wrp)) | 984 | if (wrp->master->type == PWRAP_MT8135) |
748 | pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN); | 985 | pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN); |
749 | 986 | ||
750 | pwrap_writel(wrp, 0x1, PWRAP_WACS0_EN); | 987 | pwrap_writel(wrp, 0x1, PWRAP_WACS0_EN); |
@@ -753,31 +990,10 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
753 | pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD); | 990 | pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD); |
754 | pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN); | 991 | pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN); |
755 | 992 | ||
756 | if (pwrap_is_mt8135(wrp)) { | 993 | if (wrp->master->init_soc_specific) { |
757 | /* enable pwrap events and pwrap bridge in AP side */ | 994 | ret = wrp->master->init_soc_specific(wrp); |
758 | pwrap_writel(wrp, 0x1, PWRAP_EVENT_IN_EN); | 995 | if (ret) |
759 | pwrap_writel(wrp, 0xffff, PWRAP_EVENT_DST_EN); | 996 | return ret; |
760 | writel(0x7f, wrp->bridge_base + PWRAP_MT8135_BRIDGE_IORD_ARB_EN); | ||
761 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS3_EN); | ||
762 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS4_EN); | ||
763 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_UNIT); | ||
764 | writel(0xffff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_SRC_EN); | ||
765 | writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_TIMER_EN); | ||
766 | writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN); | ||
767 | |||
768 | /* enable PMIC event out and sources */ | ||
769 | if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) || | ||
770 | pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) { | ||
771 | dev_err(wrp->dev, "enable dewrap fail\n"); | ||
772 | return -EFAULT; | ||
773 | } | ||
774 | } else { | ||
775 | /* PMIC_DEWRAP enables */ | ||
776 | if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) || | ||
777 | pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) { | ||
778 | dev_err(wrp->dev, "enable dewrap fail\n"); | ||
779 | return -EFAULT; | ||
780 | } | ||
781 | } | 997 | } |
782 | 998 | ||
783 | /* Setup the init done registers */ | 999 | /* Setup the init done registers */ |
@@ -785,7 +1001,7 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
785 | pwrap_writel(wrp, 1, PWRAP_INIT_DONE0); | 1001 | pwrap_writel(wrp, 1, PWRAP_INIT_DONE0); |
786 | pwrap_writel(wrp, 1, PWRAP_INIT_DONE1); | 1002 | pwrap_writel(wrp, 1, PWRAP_INIT_DONE1); |
787 | 1003 | ||
788 | if (pwrap_is_mt8135(wrp)) { | 1004 | if (wrp->master->has_bridge) { |
789 | writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3); | 1005 | writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3); |
790 | writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4); | 1006 | writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4); |
791 | } | 1007 | } |
@@ -816,8 +1032,70 @@ static const struct regmap_config pwrap_regmap_config = { | |||
816 | .max_register = 0xffff, | 1032 | .max_register = 0xffff, |
817 | }; | 1033 | }; |
818 | 1034 | ||
1035 | static const struct pwrap_slv_type pmic_mt6323 = { | ||
1036 | .dew_regs = mt6323_regs, | ||
1037 | .type = PMIC_MT6323, | ||
1038 | }; | ||
1039 | |||
1040 | static const struct pwrap_slv_type pmic_mt6397 = { | ||
1041 | .dew_regs = mt6397_regs, | ||
1042 | .type = PMIC_MT6397, | ||
1043 | }; | ||
1044 | |||
1045 | static const struct of_device_id of_slave_match_tbl[] = { | ||
1046 | { | ||
1047 | .compatible = "mediatek,mt6323", | ||
1048 | .data = &pmic_mt6323, | ||
1049 | }, { | ||
1050 | .compatible = "mediatek,mt6397", | ||
1051 | .data = &pmic_mt6397, | ||
1052 | }, { | ||
1053 | /* sentinel */ | ||
1054 | } | ||
1055 | }; | ||
1056 | MODULE_DEVICE_TABLE(of, of_slave_match_tbl); | ||
1057 | |||
1058 | static const struct pmic_wrapper_type pwrap_mt2701 = { | ||
1059 | .regs = mt2701_regs, | ||
1060 | .type = PWRAP_MT2701, | ||
1061 | .arb_en_all = 0x3f, | ||
1062 | .int_en_all = ~(BIT(31) | BIT(2)), | ||
1063 | .spi_w = PWRAP_MAN_CMD_SPI_WRITE_NEW, | ||
1064 | .wdt_src = PWRAP_WDT_SRC_MASK_ALL, | ||
1065 | .has_bridge = 0, | ||
1066 | .init_reg_clock = pwrap_mt2701_init_reg_clock, | ||
1067 | .init_soc_specific = pwrap_mt2701_init_soc_specific, | ||
1068 | }; | ||
1069 | |||
1070 | static struct pmic_wrapper_type pwrap_mt8135 = { | ||
1071 | .regs = mt8135_regs, | ||
1072 | .type = PWRAP_MT8135, | ||
1073 | .arb_en_all = 0x1ff, | ||
1074 | .int_en_all = ~(BIT(31) | BIT(1)), | ||
1075 | .spi_w = PWRAP_MAN_CMD_SPI_WRITE, | ||
1076 | .wdt_src = PWRAP_WDT_SRC_MASK_ALL, | ||
1077 | .has_bridge = 1, | ||
1078 | .init_reg_clock = pwrap_mt8135_init_reg_clock, | ||
1079 | .init_soc_specific = pwrap_mt8135_init_soc_specific, | ||
1080 | }; | ||
1081 | |||
1082 | static struct pmic_wrapper_type pwrap_mt8173 = { | ||
1083 | .regs = mt8173_regs, | ||
1084 | .type = PWRAP_MT8173, | ||
1085 | .arb_en_all = 0x3f, | ||
1086 | .int_en_all = ~(BIT(31) | BIT(1)), | ||
1087 | .spi_w = PWRAP_MAN_CMD_SPI_WRITE, | ||
1088 | .wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD, | ||
1089 | .has_bridge = 0, | ||
1090 | .init_reg_clock = pwrap_mt8173_init_reg_clock, | ||
1091 | .init_soc_specific = pwrap_mt8173_init_soc_specific, | ||
1092 | }; | ||
1093 | |||
819 | static struct of_device_id of_pwrap_match_tbl[] = { | 1094 | static struct of_device_id of_pwrap_match_tbl[] = { |
820 | { | 1095 | { |
1096 | .compatible = "mediatek,mt2701-pwrap", | ||
1097 | .data = &pwrap_mt2701, | ||
1098 | }, { | ||
821 | .compatible = "mediatek,mt8135-pwrap", | 1099 | .compatible = "mediatek,mt8135-pwrap", |
822 | .data = &pwrap_mt8135, | 1100 | .data = &pwrap_mt8135, |
823 | }, { | 1101 | }, { |
@@ -831,24 +1109,30 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl); | |||
831 | 1109 | ||
832 | static int pwrap_probe(struct platform_device *pdev) | 1110 | static int pwrap_probe(struct platform_device *pdev) |
833 | { | 1111 | { |
834 | int ret, irq, wdt_src; | 1112 | int ret, irq; |
835 | struct pmic_wrapper *wrp; | 1113 | struct pmic_wrapper *wrp; |
836 | struct device_node *np = pdev->dev.of_node; | 1114 | struct device_node *np = pdev->dev.of_node; |
837 | const struct of_device_id *of_id = | 1115 | const struct of_device_id *of_id = |
838 | of_match_device(of_pwrap_match_tbl, &pdev->dev); | 1116 | of_match_device(of_pwrap_match_tbl, &pdev->dev); |
839 | const struct pmic_wrapper_type *type; | 1117 | const struct of_device_id *of_slave_id = NULL; |
840 | struct resource *res; | 1118 | struct resource *res; |
841 | 1119 | ||
1120 | if (pdev->dev.of_node->child) | ||
1121 | of_slave_id = of_match_node(of_slave_match_tbl, | ||
1122 | pdev->dev.of_node->child); | ||
1123 | if (!of_slave_id) { | ||
1124 | dev_dbg(&pdev->dev, "slave pmic should be defined in dts\n"); | ||
1125 | return -EINVAL; | ||
1126 | } | ||
1127 | |||
842 | wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL); | 1128 | wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL); |
843 | if (!wrp) | 1129 | if (!wrp) |
844 | return -ENOMEM; | 1130 | return -ENOMEM; |
845 | 1131 | ||
846 | platform_set_drvdata(pdev, wrp); | 1132 | platform_set_drvdata(pdev, wrp); |
847 | 1133 | ||
848 | type = of_id->data; | 1134 | wrp->master = of_id->data; |
849 | wrp->regs = type->regs; | 1135 | wrp->slave = of_slave_id->data; |
850 | wrp->type = type->type; | ||
851 | wrp->arb_en_all = type->arb_en_all; | ||
852 | wrp->dev = &pdev->dev; | 1136 | wrp->dev = &pdev->dev; |
853 | 1137 | ||
854 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap"); | 1138 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap"); |
@@ -863,7 +1147,7 @@ static int pwrap_probe(struct platform_device *pdev) | |||
863 | return ret; | 1147 | return ret; |
864 | } | 1148 | } |
865 | 1149 | ||
866 | if (pwrap_is_mt8135(wrp)) { | 1150 | if (wrp->master->has_bridge) { |
867 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 1151 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
868 | "pwrap-bridge"); | 1152 | "pwrap-bridge"); |
869 | wrp->bridge_base = devm_ioremap_resource(wrp->dev, res); | 1153 | wrp->bridge_base = devm_ioremap_resource(wrp->dev, res); |
@@ -925,11 +1209,9 @@ static int pwrap_probe(struct platform_device *pdev) | |||
925 | * Since STAUPD was not used on mt8173 platform, | 1209 | * Since STAUPD was not used on mt8173 platform, |
926 | * so STAUPD of WDT_SRC which should be turned off | 1210 | * so STAUPD of WDT_SRC which should be turned off |
927 | */ | 1211 | */ |
928 | wdt_src = pwrap_is_mt8173(wrp) ? | 1212 | pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN); |
929 | PWRAP_WDT_SRC_MASK_NO_STAUPD : PWRAP_WDT_SRC_MASK_ALL; | ||
930 | pwrap_writel(wrp, wdt_src, PWRAP_WDT_SRC_EN); | ||
931 | pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); | 1213 | pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); |
932 | pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN); | 1214 | pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN); |
933 | 1215 | ||
934 | irq = platform_get_irq(pdev, 0); | 1216 | irq = platform_get_irq(pdev, 0); |
935 | ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH, | 1217 | ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH, |
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile new file mode 100644 index 000000000000..151fcd3f025b --- /dev/null +++ b/drivers/soc/renesas/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o | ||
2 | obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o | ||
3 | obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o | ||
4 | # R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. | ||
5 | obj-$(CONFIG_ARCH_R8A7793) += rcar-sysc.o r8a7791-sysc.o | ||
6 | obj-$(CONFIG_ARCH_R8A7794) += rcar-sysc.o r8a7794-sysc.o | ||
7 | obj-$(CONFIG_ARCH_R8A7795) += rcar-sysc.o r8a7795-sysc.o | ||
diff --git a/drivers/soc/renesas/r8a7779-sysc.c b/drivers/soc/renesas/r8a7779-sysc.c new file mode 100644 index 000000000000..9e8e6b7faa04 --- /dev/null +++ b/drivers/soc/renesas/r8a7779-sysc.c | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Renesas R-Car H1 System Controller | ||
3 | * | ||
4 | * Copyright (C) 2016 Glider bvba | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | #include <linux/bug.h> | ||
12 | #include <linux/kernel.h> | ||
13 | |||
14 | #include <dt-bindings/power/r8a7779-sysc.h> | ||
15 | |||
16 | #include "rcar-sysc.h" | ||
17 | |||
18 | static const struct rcar_sysc_area r8a7779_areas[] __initconst = { | ||
19 | { "always-on", 0, 0, R8A7779_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, | ||
20 | { "arm1", 0x40, 1, R8A7779_PD_ARM1, R8A7779_PD_ALWAYS_ON, | ||
21 | PD_CPU_CR }, | ||
22 | { "arm2", 0x40, 2, R8A7779_PD_ARM2, R8A7779_PD_ALWAYS_ON, | ||
23 | PD_CPU_CR }, | ||
24 | { "arm3", 0x40, 3, R8A7779_PD_ARM3, R8A7779_PD_ALWAYS_ON, | ||
25 | PD_CPU_CR }, | ||
26 | { "sgx", 0xc0, 0, R8A7779_PD_SGX, R8A7779_PD_ALWAYS_ON }, | ||
27 | { "vdp", 0x100, 0, R8A7779_PD_VDP, R8A7779_PD_ALWAYS_ON }, | ||
28 | { "imp", 0x140, 0, R8A7779_PD_IMP, R8A7779_PD_ALWAYS_ON }, | ||
29 | }; | ||
30 | |||
31 | const struct rcar_sysc_info r8a7779_sysc_info __initconst = { | ||
32 | .areas = r8a7779_areas, | ||
33 | .num_areas = ARRAY_SIZE(r8a7779_areas), | ||
34 | }; | ||
diff --git a/drivers/soc/renesas/r8a7790-sysc.c b/drivers/soc/renesas/r8a7790-sysc.c new file mode 100644 index 000000000000..7a567ad0ff73 --- /dev/null +++ b/drivers/soc/renesas/r8a7790-sysc.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Renesas R-Car H2 System Controller | ||
3 | * | ||
4 | * Copyright (C) 2016 Glider bvba | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | #include <linux/bug.h> | ||
12 | #include <linux/kernel.h> | ||
13 | |||
14 | #include <dt-bindings/power/r8a7790-sysc.h> | ||
15 | |||
16 | #include "rcar-sysc.h" | ||
17 | |||
18 | static const struct rcar_sysc_area r8a7790_areas[] __initconst = { | ||
19 | { "always-on", 0, 0, R8A7790_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, | ||
20 | { "ca15-scu", 0x180, 0, R8A7790_PD_CA15_SCU, R8A7790_PD_ALWAYS_ON, | ||
21 | PD_SCU }, | ||
22 | { "ca15-cpu0", 0x40, 0, R8A7790_PD_CA15_CPU0, R8A7790_PD_CA15_SCU, | ||
23 | PD_CPU_NOCR }, | ||
24 | { "ca15-cpu1", 0x40, 1, R8A7790_PD_CA15_CPU1, R8A7790_PD_CA15_SCU, | ||
25 | PD_CPU_NOCR }, | ||
26 | { "ca15-cpu2", 0x40, 2, R8A7790_PD_CA15_CPU2, R8A7790_PD_CA15_SCU, | ||
27 | PD_CPU_NOCR }, | ||
28 | { "ca15-cpu3", 0x40, 3, R8A7790_PD_CA15_CPU3, R8A7790_PD_CA15_SCU, | ||
29 | PD_CPU_NOCR }, | ||
30 | { "ca7-scu", 0x100, 0, R8A7790_PD_CA7_SCU, R8A7790_PD_ALWAYS_ON, | ||
31 | PD_SCU }, | ||
32 | { "ca7-cpu0", 0x1c0, 0, R8A7790_PD_CA7_CPU0, R8A7790_PD_CA7_SCU, | ||
33 | PD_CPU_NOCR }, | ||
34 | { "ca7-cpu1", 0x1c0, 1, R8A7790_PD_CA7_CPU1, R8A7790_PD_CA7_SCU, | ||
35 | PD_CPU_NOCR }, | ||
36 | { "ca7-cpu2", 0x1c0, 2, R8A7790_PD_CA7_CPU2, R8A7790_PD_CA7_SCU, | ||
37 | PD_CPU_NOCR }, | ||
38 | { "ca7-cpu3", 0x1c0, 3, R8A7790_PD_CA7_CPU3, R8A7790_PD_CA7_SCU, | ||
39 | PD_CPU_NOCR }, | ||
40 | { "sh-4a", 0x80, 0, R8A7790_PD_SH_4A, R8A7790_PD_ALWAYS_ON }, | ||
41 | { "rgx", 0xc0, 0, R8A7790_PD_RGX, R8A7790_PD_ALWAYS_ON }, | ||
42 | { "imp", 0x140, 0, R8A7790_PD_IMP, R8A7790_PD_ALWAYS_ON }, | ||
43 | }; | ||
44 | |||
45 | const struct rcar_sysc_info r8a7790_sysc_info __initconst = { | ||
46 | .areas = r8a7790_areas, | ||
47 | .num_areas = ARRAY_SIZE(r8a7790_areas), | ||
48 | }; | ||
diff --git a/drivers/soc/renesas/r8a7791-sysc.c b/drivers/soc/renesas/r8a7791-sysc.c new file mode 100644 index 000000000000..03b9f41a34e6 --- /dev/null +++ b/drivers/soc/renesas/r8a7791-sysc.c | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Renesas R-Car M2-W/N System Controller | ||
3 | * | ||
4 | * Copyright (C) 2016 Glider bvba | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | #include <linux/bug.h> | ||
12 | #include <linux/kernel.h> | ||
13 | |||
14 | #include <dt-bindings/power/r8a7791-sysc.h> | ||
15 | |||
16 | #include "rcar-sysc.h" | ||
17 | |||
18 | static const struct rcar_sysc_area r8a7791_areas[] __initconst = { | ||
19 | { "always-on", 0, 0, R8A7791_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, | ||
20 | { "ca15-scu", 0x180, 0, R8A7791_PD_CA15_SCU, R8A7791_PD_ALWAYS_ON, | ||
21 | PD_SCU }, | ||
22 | { "ca15-cpu0", 0x40, 0, R8A7791_PD_CA15_CPU0, R8A7791_PD_CA15_SCU, | ||
23 | PD_CPU_NOCR }, | ||
24 | { "ca15-cpu1", 0x40, 1, R8A7791_PD_CA15_CPU1, R8A7791_PD_CA15_SCU, | ||
25 | PD_CPU_NOCR }, | ||
26 | { "sh-4a", 0x80, 0, R8A7791_PD_SH_4A, R8A7791_PD_ALWAYS_ON }, | ||
27 | { "sgx", 0xc0, 0, R8A7791_PD_SGX, R8A7791_PD_ALWAYS_ON }, | ||
28 | }; | ||
29 | |||
30 | const struct rcar_sysc_info r8a7791_sysc_info __initconst = { | ||
31 | .areas = r8a7791_areas, | ||
32 | .num_areas = ARRAY_SIZE(r8a7791_areas), | ||
33 | }; | ||
diff --git a/drivers/soc/renesas/r8a7794-sysc.c b/drivers/soc/renesas/r8a7794-sysc.c new file mode 100644 index 000000000000..c4da2941e06c --- /dev/null +++ b/drivers/soc/renesas/r8a7794-sysc.c | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Renesas R-Car E2 System Controller | ||
3 | * | ||
4 | * Copyright (C) 2016 Glider bvba | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | #include <linux/bug.h> | ||
12 | #include <linux/kernel.h> | ||
13 | |||
14 | #include <dt-bindings/power/r8a7794-sysc.h> | ||
15 | |||
16 | #include "rcar-sysc.h" | ||
17 | |||
18 | static const struct rcar_sysc_area r8a7794_areas[] __initconst = { | ||
19 | { "always-on", 0, 0, R8A7794_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, | ||
20 | { "ca7-scu", 0x100, 0, R8A7794_PD_CA7_SCU, R8A7794_PD_ALWAYS_ON, | ||
21 | PD_SCU }, | ||
22 | { "ca7-cpu0", 0x1c0, 0, R8A7794_PD_CA7_CPU0, R8A7794_PD_CA7_SCU, | ||
23 | PD_CPU_NOCR }, | ||
24 | { "ca7-cpu1", 0x1c0, 1, R8A7794_PD_CA7_CPU1, R8A7794_PD_CA7_SCU, | ||
25 | PD_CPU_NOCR }, | ||
26 | { "sh-4a", 0x80, 0, R8A7794_PD_SH_4A, R8A7794_PD_ALWAYS_ON }, | ||
27 | { "sgx", 0xc0, 0, R8A7794_PD_SGX, R8A7794_PD_ALWAYS_ON }, | ||
28 | }; | ||
29 | |||
30 | const struct rcar_sysc_info r8a7794_sysc_info __initconst = { | ||
31 | .areas = r8a7794_areas, | ||
32 | .num_areas = ARRAY_SIZE(r8a7794_areas), | ||
33 | }; | ||
diff --git a/drivers/soc/renesas/r8a7795-sysc.c b/drivers/soc/renesas/r8a7795-sysc.c new file mode 100644 index 000000000000..5e7537c96f7b --- /dev/null +++ b/drivers/soc/renesas/r8a7795-sysc.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Renesas R-Car H3 System Controller | ||
3 | * | ||
4 | * Copyright (C) 2016 Glider bvba | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | #include <linux/bug.h> | ||
12 | #include <linux/kernel.h> | ||
13 | |||
14 | #include <dt-bindings/power/r8a7795-sysc.h> | ||
15 | |||
16 | #include "rcar-sysc.h" | ||
17 | |||
18 | static const struct rcar_sysc_area r8a7795_areas[] __initconst = { | ||
19 | { "always-on", 0, 0, R8A7795_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, | ||
20 | { "ca57-scu", 0x1c0, 0, R8A7795_PD_CA57_SCU, R8A7795_PD_ALWAYS_ON, | ||
21 | PD_SCU }, | ||
22 | { "ca57-cpu0", 0x80, 0, R8A7795_PD_CA57_CPU0, R8A7795_PD_CA57_SCU, | ||
23 | PD_CPU_NOCR }, | ||
24 | { "ca57-cpu1", 0x80, 1, R8A7795_PD_CA57_CPU1, R8A7795_PD_CA57_SCU, | ||
25 | PD_CPU_NOCR }, | ||
26 | { "ca57-cpu2", 0x80, 2, R8A7795_PD_CA57_CPU2, R8A7795_PD_CA57_SCU, | ||
27 | PD_CPU_NOCR }, | ||
28 | { "ca57-cpu3", 0x80, 3, R8A7795_PD_CA57_CPU3, R8A7795_PD_CA57_SCU, | ||
29 | PD_CPU_NOCR }, | ||
30 | { "ca53-scu", 0x140, 0, R8A7795_PD_CA53_SCU, R8A7795_PD_ALWAYS_ON, | ||
31 | PD_SCU }, | ||
32 | { "ca53-cpu0", 0x200, 0, R8A7795_PD_CA53_CPU0, R8A7795_PD_CA53_SCU, | ||
33 | PD_CPU_NOCR }, | ||
34 | { "ca53-cpu1", 0x200, 1, R8A7795_PD_CA53_CPU1, R8A7795_PD_CA53_SCU, | ||
35 | PD_CPU_NOCR }, | ||
36 | { "ca53-cpu2", 0x200, 2, R8A7795_PD_CA53_CPU2, R8A7795_PD_CA53_SCU, | ||
37 | PD_CPU_NOCR }, | ||
38 | { "ca53-cpu3", 0x200, 3, R8A7795_PD_CA53_CPU3, R8A7795_PD_CA53_SCU, | ||
39 | PD_CPU_NOCR }, | ||
40 | { "a3vp", 0x340, 0, R8A7795_PD_A3VP, R8A7795_PD_ALWAYS_ON }, | ||
41 | { "cr7", 0x240, 0, R8A7795_PD_CR7, R8A7795_PD_ALWAYS_ON }, | ||
42 | { "a3vc", 0x380, 0, R8A7795_PD_A3VC, R8A7795_PD_ALWAYS_ON }, | ||
43 | { "a2vc0", 0x3c0, 0, R8A7795_PD_A2VC0, R8A7795_PD_A3VC }, | ||
44 | { "a2vc1", 0x3c0, 1, R8A7795_PD_A2VC1, R8A7795_PD_A3VC }, | ||
45 | { "3dg-a", 0x100, 0, R8A7795_PD_3DG_A, R8A7795_PD_ALWAYS_ON }, | ||
46 | { "3dg-b", 0x100, 1, R8A7795_PD_3DG_B, R8A7795_PD_3DG_A }, | ||
47 | { "3dg-c", 0x100, 2, R8A7795_PD_3DG_C, R8A7795_PD_3DG_B }, | ||
48 | { "3dg-d", 0x100, 3, R8A7795_PD_3DG_D, R8A7795_PD_3DG_C }, | ||
49 | { "3dg-e", 0x100, 4, R8A7795_PD_3DG_E, R8A7795_PD_3DG_D }, | ||
50 | { "a3ir", 0x180, 0, R8A7795_PD_A3IR, R8A7795_PD_ALWAYS_ON }, | ||
51 | }; | ||
52 | |||
53 | const struct rcar_sysc_info r8a7795_sysc_info __initconst = { | ||
54 | .areas = r8a7795_areas, | ||
55 | .num_areas = ARRAY_SIZE(r8a7795_areas), | ||
56 | }; | ||
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c new file mode 100644 index 000000000000..79dbc770895f --- /dev/null +++ b/drivers/soc/renesas/rcar-sysc.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * R-Car SYSC Power management support | ||
3 | * | ||
4 | * Copyright (C) 2014 Magnus Damm | ||
5 | * Copyright (C) 2015-2016 Glider bvba | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk/renesas.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/pm_domain.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/soc/renesas/rcar-sysc.h> | ||
22 | |||
23 | #include "rcar-sysc.h" | ||
24 | |||
25 | /* SYSC Common */ | ||
26 | #define SYSCSR 0x00 /* SYSC Status Register */ | ||
27 | #define SYSCISR 0x04 /* Interrupt Status Register */ | ||
28 | #define SYSCISCR 0x08 /* Interrupt Status Clear Register */ | ||
29 | #define SYSCIER 0x0c /* Interrupt Enable Register */ | ||
30 | #define SYSCIMR 0x10 /* Interrupt Mask Register */ | ||
31 | |||
32 | /* SYSC Status Register */ | ||
33 | #define SYSCSR_PONENB 1 /* Ready for power resume requests */ | ||
34 | #define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */ | ||
35 | |||
36 | /* | ||
37 | * Power Control Register Offsets inside the register block for each domain | ||
38 | * Note: The "CR" registers for ARM cores exist on H1 only | ||
39 | * Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2 | ||
40 | * Use PSCI on R-Car Gen3 | ||
41 | */ | ||
42 | #define PWRSR_OFFS 0x00 /* Power Status Register */ | ||
43 | #define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */ | ||
44 | #define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */ | ||
45 | #define PWRONCR_OFFS 0x0c /* Power Resume Control Register */ | ||
46 | #define PWRONSR_OFFS 0x10 /* Power Resume Status Register */ | ||
47 | #define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ | ||
48 | |||
49 | |||
50 | #define SYSCSR_RETRIES 100 | ||
51 | #define SYSCSR_DELAY_US 1 | ||
52 | |||
53 | #define PWRER_RETRIES 100 | ||
54 | #define PWRER_DELAY_US 1 | ||
55 | |||
56 | #define SYSCISR_RETRIES 1000 | ||
57 | #define SYSCISR_DELAY_US 1 | ||
58 | |||
59 | #define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */ | ||
60 | |||
61 | static void __iomem *rcar_sysc_base; | ||
62 | static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */ | ||
63 | |||
64 | static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) | ||
65 | { | ||
66 | unsigned int sr_bit, reg_offs; | ||
67 | int k; | ||
68 | |||
69 | if (on) { | ||
70 | sr_bit = SYSCSR_PONENB; | ||
71 | reg_offs = PWRONCR_OFFS; | ||
72 | } else { | ||
73 | sr_bit = SYSCSR_POFFENB; | ||
74 | reg_offs = PWROFFCR_OFFS; | ||
75 | } | ||
76 | |||
77 | /* Wait until SYSC is ready to accept a power request */ | ||
78 | for (k = 0; k < SYSCSR_RETRIES; k++) { | ||
79 | if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit)) | ||
80 | break; | ||
81 | udelay(SYSCSR_DELAY_US); | ||
82 | } | ||
83 | |||
84 | if (k == SYSCSR_RETRIES) | ||
85 | return -EAGAIN; | ||
86 | |||
87 | /* Submit power shutoff or power resume request */ | ||
88 | iowrite32(BIT(sysc_ch->chan_bit), | ||
89 | rcar_sysc_base + sysc_ch->chan_offs + reg_offs); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) | ||
95 | { | ||
96 | unsigned int isr_mask = BIT(sysc_ch->isr_bit); | ||
97 | unsigned int chan_mask = BIT(sysc_ch->chan_bit); | ||
98 | unsigned int status; | ||
99 | unsigned long flags; | ||
100 | int ret = 0; | ||
101 | int k; | ||
102 | |||
103 | spin_lock_irqsave(&rcar_sysc_lock, flags); | ||
104 | |||
105 | iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); | ||
106 | |||
107 | /* Submit power shutoff or resume request until it was accepted */ | ||
108 | for (k = 0; k < PWRER_RETRIES; k++) { | ||
109 | ret = rcar_sysc_pwr_on_off(sysc_ch, on); | ||
110 | if (ret) | ||
111 | goto out; | ||
112 | |||
113 | status = ioread32(rcar_sysc_base + | ||
114 | sysc_ch->chan_offs + PWRER_OFFS); | ||
115 | if (!(status & chan_mask)) | ||
116 | break; | ||
117 | |||
118 | udelay(PWRER_DELAY_US); | ||
119 | } | ||
120 | |||
121 | if (k == PWRER_RETRIES) { | ||
122 | ret = -EIO; | ||
123 | goto out; | ||
124 | } | ||
125 | |||
126 | /* Wait until the power shutoff or resume request has completed * */ | ||
127 | for (k = 0; k < SYSCISR_RETRIES; k++) { | ||
128 | if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask) | ||
129 | break; | ||
130 | udelay(SYSCISR_DELAY_US); | ||
131 | } | ||
132 | |||
133 | if (k == SYSCISR_RETRIES) | ||
134 | ret = -EIO; | ||
135 | |||
136 | iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); | ||
137 | |||
138 | out: | ||
139 | spin_unlock_irqrestore(&rcar_sysc_lock, flags); | ||
140 | |||
141 | pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", | ||
142 | sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) | ||
147 | { | ||
148 | return rcar_sysc_power(sysc_ch, false); | ||
149 | } | ||
150 | |||
151 | int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) | ||
152 | { | ||
153 | return rcar_sysc_power(sysc_ch, true); | ||
154 | } | ||
155 | |||
156 | static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch) | ||
157 | { | ||
158 | unsigned int st; | ||
159 | |||
160 | st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS); | ||
161 | if (st & BIT(sysc_ch->chan_bit)) | ||
162 | return true; | ||
163 | |||
164 | return false; | ||
165 | } | ||
166 | |||
167 | void __iomem *rcar_sysc_init(phys_addr_t base) | ||
168 | { | ||
169 | rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE); | ||
170 | if (!rcar_sysc_base) | ||
171 | panic("unable to ioremap R-Car SYSC hardware block\n"); | ||
172 | |||
173 | return rcar_sysc_base; | ||
174 | } | ||
175 | |||
176 | struct rcar_sysc_pd { | ||
177 | struct generic_pm_domain genpd; | ||
178 | struct rcar_sysc_ch ch; | ||
179 | unsigned int flags; | ||
180 | char name[0]; | ||
181 | }; | ||
182 | |||
183 | static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d) | ||
184 | { | ||
185 | return container_of(d, struct rcar_sysc_pd, genpd); | ||
186 | } | ||
187 | |||
188 | static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd) | ||
189 | { | ||
190 | struct rcar_sysc_pd *pd = to_rcar_pd(genpd); | ||
191 | |||
192 | pr_debug("%s: %s\n", __func__, genpd->name); | ||
193 | |||
194 | if (pd->flags & PD_NO_CR) { | ||
195 | pr_debug("%s: Cannot control %s\n", __func__, genpd->name); | ||
196 | return -EBUSY; | ||
197 | } | ||
198 | |||
199 | if (pd->flags & PD_BUSY) { | ||
200 | pr_debug("%s: %s busy\n", __func__, genpd->name); | ||
201 | return -EBUSY; | ||
202 | } | ||
203 | |||
204 | return rcar_sysc_power_down(&pd->ch); | ||
205 | } | ||
206 | |||
207 | static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) | ||
208 | { | ||
209 | struct rcar_sysc_pd *pd = to_rcar_pd(genpd); | ||
210 | |||
211 | pr_debug("%s: %s\n", __func__, genpd->name); | ||
212 | |||
213 | if (pd->flags & PD_NO_CR) { | ||
214 | pr_debug("%s: Cannot control %s\n", __func__, genpd->name); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | return rcar_sysc_power_up(&pd->ch); | ||
219 | } | ||
220 | |||
221 | static bool has_cpg_mstp; | ||
222 | |||
223 | static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) | ||
224 | { | ||
225 | struct generic_pm_domain *genpd = &pd->genpd; | ||
226 | const char *name = pd->genpd.name; | ||
227 | struct dev_power_governor *gov = &simple_qos_governor; | ||
228 | |||
229 | if (pd->flags & PD_CPU) { | ||
230 | /* | ||
231 | * This domain contains a CPU core and therefore it should | ||
232 | * only be turned off if the CPU is not in use. | ||
233 | */ | ||
234 | pr_debug("PM domain %s contains %s\n", name, "CPU"); | ||
235 | pd->flags |= PD_BUSY; | ||
236 | gov = &pm_domain_always_on_gov; | ||
237 | } else if (pd->flags & PD_SCU) { | ||
238 | /* | ||
239 | * This domain contains an SCU and cache-controller, and | ||
240 | * therefore it should only be turned off if the CPU cores are | ||
241 | * not in use. | ||
242 | */ | ||
243 | pr_debug("PM domain %s contains %s\n", name, "SCU"); | ||
244 | pd->flags |= PD_BUSY; | ||
245 | gov = &pm_domain_always_on_gov; | ||
246 | } else if (pd->flags & PD_NO_CR) { | ||
247 | /* | ||
248 | * This domain cannot be turned off. | ||
249 | */ | ||
250 | pd->flags |= PD_BUSY; | ||
251 | gov = &pm_domain_always_on_gov; | ||
252 | } | ||
253 | |||
254 | if (!(pd->flags & (PD_CPU | PD_SCU))) { | ||
255 | /* Enable Clock Domain for I/O devices */ | ||
256 | genpd->flags = GENPD_FLAG_PM_CLK; | ||
257 | if (has_cpg_mstp) { | ||
258 | genpd->attach_dev = cpg_mstp_attach_dev; | ||
259 | genpd->detach_dev = cpg_mstp_detach_dev; | ||
260 | } else { | ||
261 | genpd->attach_dev = cpg_mssr_attach_dev; | ||
262 | genpd->detach_dev = cpg_mssr_detach_dev; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | genpd->power_off = rcar_sysc_pd_power_off; | ||
267 | genpd->power_on = rcar_sysc_pd_power_on; | ||
268 | |||
269 | if (pd->flags & (PD_CPU | PD_NO_CR)) { | ||
270 | /* Skip CPUs (handled by SMP code) and areas without control */ | ||
271 | pr_debug("%s: Not touching %s\n", __func__, genpd->name); | ||
272 | goto finalize; | ||
273 | } | ||
274 | |||
275 | if (!rcar_sysc_power_is_off(&pd->ch)) { | ||
276 | pr_debug("%s: %s is already powered\n", __func__, genpd->name); | ||
277 | goto finalize; | ||
278 | } | ||
279 | |||
280 | rcar_sysc_power_up(&pd->ch); | ||
281 | |||
282 | finalize: | ||
283 | pm_genpd_init(genpd, gov, false); | ||
284 | } | ||
285 | |||
286 | static const struct of_device_id rcar_sysc_matches[] = { | ||
287 | #ifdef CONFIG_ARCH_R8A7779 | ||
288 | { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, | ||
289 | #endif | ||
290 | #ifdef CONFIG_ARCH_R8A7790 | ||
291 | { .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info }, | ||
292 | #endif | ||
293 | #ifdef CONFIG_ARCH_R8A7791 | ||
294 | { .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info }, | ||
295 | #endif | ||
296 | #ifdef CONFIG_ARCH_R8A7793 | ||
297 | /* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */ | ||
298 | { .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info }, | ||
299 | #endif | ||
300 | #ifdef CONFIG_ARCH_R8A7794 | ||
301 | { .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info }, | ||
302 | #endif | ||
303 | #ifdef CONFIG_ARCH_R8A7795 | ||
304 | { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info }, | ||
305 | #endif | ||
306 | { /* sentinel */ } | ||
307 | }; | ||
308 | |||
309 | struct rcar_pm_domains { | ||
310 | struct genpd_onecell_data onecell_data; | ||
311 | struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1]; | ||
312 | }; | ||
313 | |||
314 | static int __init rcar_sysc_pd_init(void) | ||
315 | { | ||
316 | const struct rcar_sysc_info *info; | ||
317 | const struct of_device_id *match; | ||
318 | struct rcar_pm_domains *domains; | ||
319 | struct device_node *np; | ||
320 | u32 syscier, syscimr; | ||
321 | void __iomem *base; | ||
322 | unsigned int i; | ||
323 | int error; | ||
324 | |||
325 | np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match); | ||
326 | if (!np) | ||
327 | return -ENODEV; | ||
328 | |||
329 | info = match->data; | ||
330 | |||
331 | has_cpg_mstp = of_find_compatible_node(NULL, NULL, | ||
332 | "renesas,cpg-mstp-clocks"); | ||
333 | |||
334 | base = of_iomap(np, 0); | ||
335 | if (!base) { | ||
336 | pr_warn("%s: Cannot map regs\n", np->full_name); | ||
337 | error = -ENOMEM; | ||
338 | goto out_put; | ||
339 | } | ||
340 | |||
341 | rcar_sysc_base = base; | ||
342 | |||
343 | domains = kzalloc(sizeof(*domains), GFP_KERNEL); | ||
344 | if (!domains) { | ||
345 | error = -ENOMEM; | ||
346 | goto out_put; | ||
347 | } | ||
348 | |||
349 | domains->onecell_data.domains = domains->domains; | ||
350 | domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); | ||
351 | |||
352 | for (i = 0, syscier = 0; i < info->num_areas; i++) | ||
353 | syscier |= BIT(info->areas[i].isr_bit); | ||
354 | |||
355 | /* | ||
356 | * Mask all interrupt sources to prevent the CPU from receiving them. | ||
357 | * Make sure not to clear reserved bits that were set before. | ||
358 | */ | ||
359 | syscimr = ioread32(base + SYSCIMR); | ||
360 | syscimr |= syscier; | ||
361 | pr_debug("%s: syscimr = 0x%08x\n", np->full_name, syscimr); | ||
362 | iowrite32(syscimr, base + SYSCIMR); | ||
363 | |||
364 | /* | ||
365 | * SYSC needs all interrupt sources enabled to control power. | ||
366 | */ | ||
367 | pr_debug("%s: syscier = 0x%08x\n", np->full_name, syscier); | ||
368 | iowrite32(syscier, base + SYSCIER); | ||
369 | |||
370 | for (i = 0; i < info->num_areas; i++) { | ||
371 | const struct rcar_sysc_area *area = &info->areas[i]; | ||
372 | struct rcar_sysc_pd *pd; | ||
373 | |||
374 | pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL); | ||
375 | if (!pd) { | ||
376 | error = -ENOMEM; | ||
377 | goto out_put; | ||
378 | } | ||
379 | |||
380 | strcpy(pd->name, area->name); | ||
381 | pd->genpd.name = pd->name; | ||
382 | pd->ch.chan_offs = area->chan_offs; | ||
383 | pd->ch.chan_bit = area->chan_bit; | ||
384 | pd->ch.isr_bit = area->isr_bit; | ||
385 | pd->flags = area->flags; | ||
386 | |||
387 | rcar_sysc_pd_setup(pd); | ||
388 | if (area->parent >= 0) | ||
389 | pm_genpd_add_subdomain(domains->domains[area->parent], | ||
390 | &pd->genpd); | ||
391 | |||
392 | domains->domains[area->isr_bit] = &pd->genpd; | ||
393 | } | ||
394 | |||
395 | of_genpd_add_provider_onecell(np, &domains->onecell_data); | ||
396 | |||
397 | out_put: | ||
398 | of_node_put(np); | ||
399 | return error; | ||
400 | } | ||
401 | early_initcall(rcar_sysc_pd_init); | ||
diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h new file mode 100644 index 000000000000..5e766174c2f4 --- /dev/null +++ b/drivers/soc/renesas/rcar-sysc.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Renesas R-Car System Controller | ||
3 | * | ||
4 | * Copyright (C) 2016 Glider bvba | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | #ifndef __SOC_RENESAS_RCAR_SYSC_H__ | ||
11 | #define __SOC_RENESAS_RCAR_SYSC_H__ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | |||
15 | |||
16 | /* | ||
17 | * Power Domain flags | ||
18 | */ | ||
19 | #define PD_CPU BIT(0) /* Area contains main CPU core */ | ||
20 | #define PD_SCU BIT(1) /* Area contains SCU and L2 cache */ | ||
21 | #define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */ | ||
22 | |||
23 | #define PD_BUSY BIT(3) /* Busy, for internal use only */ | ||
24 | |||
25 | #define PD_CPU_CR PD_CPU /* CPU area has CR (R-Car H1) */ | ||
26 | #define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR (R-Car Gen2/3) */ | ||
27 | #define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ | ||
28 | |||
29 | |||
30 | /* | ||
31 | * Description of a Power Area | ||
32 | */ | ||
33 | |||
34 | struct rcar_sysc_area { | ||
35 | const char *name; | ||
36 | u16 chan_offs; /* Offset of PWRSR register for this area */ | ||
37 | u8 chan_bit; /* Bit in PWR* (except for PWRUP in PWRSR) */ | ||
38 | u8 isr_bit; /* Bit in SYSCI*R */ | ||
39 | int parent; /* -1 if none */ | ||
40 | unsigned int flags; /* See PD_* */ | ||
41 | }; | ||
42 | |||
43 | |||
44 | /* | ||
45 | * SoC-specific Power Area Description | ||
46 | */ | ||
47 | |||
48 | struct rcar_sysc_info { | ||
49 | const struct rcar_sysc_area *areas; | ||
50 | unsigned int num_areas; | ||
51 | }; | ||
52 | |||
53 | extern const struct rcar_sysc_info r8a7779_sysc_info; | ||
54 | extern const struct rcar_sysc_info r8a7790_sysc_info; | ||
55 | extern const struct rcar_sysc_info r8a7791_sysc_info; | ||
56 | extern const struct rcar_sysc_info r8a7794_sysc_info; | ||
57 | extern const struct rcar_sysc_info r8a7795_sysc_info; | ||
58 | #endif /* __SOC_RENESAS_RCAR_SYSC_H__ */ | ||
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 43155e1f97b9..44842a205e4b 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/mfd/syscon.h> | 19 | #include <linux/mfd/syscon.h> |
20 | #include <dt-bindings/power/rk3288-power.h> | 20 | #include <dt-bindings/power/rk3288-power.h> |
21 | #include <dt-bindings/power/rk3368-power.h> | 21 | #include <dt-bindings/power/rk3368-power.h> |
22 | #include <dt-bindings/power/rk3399-power.h> | ||
22 | 23 | ||
23 | struct rockchip_domain_info { | 24 | struct rockchip_domain_info { |
24 | int pwr_mask; | 25 | int pwr_mask; |
@@ -45,10 +46,20 @@ struct rockchip_pmu_info { | |||
45 | const struct rockchip_domain_info *domain_info; | 46 | const struct rockchip_domain_info *domain_info; |
46 | }; | 47 | }; |
47 | 48 | ||
49 | #define MAX_QOS_REGS_NUM 5 | ||
50 | #define QOS_PRIORITY 0x08 | ||
51 | #define QOS_MODE 0x0c | ||
52 | #define QOS_BANDWIDTH 0x10 | ||
53 | #define QOS_SATURATION 0x14 | ||
54 | #define QOS_EXTCONTROL 0x18 | ||
55 | |||
48 | struct rockchip_pm_domain { | 56 | struct rockchip_pm_domain { |
49 | struct generic_pm_domain genpd; | 57 | struct generic_pm_domain genpd; |
50 | const struct rockchip_domain_info *info; | 58 | const struct rockchip_domain_info *info; |
51 | struct rockchip_pmu *pmu; | 59 | struct rockchip_pmu *pmu; |
60 | int num_qos; | ||
61 | struct regmap **qos_regmap; | ||
62 | u32 *qos_save_regs[MAX_QOS_REGS_NUM]; | ||
52 | int num_clks; | 63 | int num_clks; |
53 | struct clk *clks[]; | 64 | struct clk *clks[]; |
54 | }; | 65 | }; |
@@ -66,11 +77,11 @@ struct rockchip_pmu { | |||
66 | 77 | ||
67 | #define DOMAIN(pwr, status, req, idle, ack) \ | 78 | #define DOMAIN(pwr, status, req, idle, ack) \ |
68 | { \ | 79 | { \ |
69 | .pwr_mask = BIT(pwr), \ | 80 | .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \ |
70 | .status_mask = BIT(status), \ | 81 | .status_mask = (status >= 0) ? BIT(status) : 0, \ |
71 | .req_mask = BIT(req), \ | 82 | .req_mask = (req >= 0) ? BIT(req) : 0, \ |
72 | .idle_mask = BIT(idle), \ | 83 | .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ |
73 | .ack_mask = BIT(ack), \ | 84 | .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ |
74 | } | 85 | } |
75 | 86 | ||
76 | #define DOMAIN_RK3288(pwr, status, req) \ | 87 | #define DOMAIN_RK3288(pwr, status, req) \ |
@@ -79,6 +90,9 @@ struct rockchip_pmu { | |||
79 | #define DOMAIN_RK3368(pwr, status, req) \ | 90 | #define DOMAIN_RK3368(pwr, status, req) \ |
80 | DOMAIN(pwr, status, req, (req) + 16, req) | 91 | DOMAIN(pwr, status, req, (req) + 16, req) |
81 | 92 | ||
93 | #define DOMAIN_RK3399(pwr, status, req) \ | ||
94 | DOMAIN(pwr, status, req, req, req) | ||
95 | |||
82 | static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) | 96 | static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) |
83 | { | 97 | { |
84 | struct rockchip_pmu *pmu = pd->pmu; | 98 | struct rockchip_pmu *pmu = pd->pmu; |
@@ -96,6 +110,9 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, | |||
96 | struct rockchip_pmu *pmu = pd->pmu; | 110 | struct rockchip_pmu *pmu = pd->pmu; |
97 | unsigned int val; | 111 | unsigned int val; |
98 | 112 | ||
113 | if (pd_info->req_mask == 0) | ||
114 | return 0; | ||
115 | |||
99 | regmap_update_bits(pmu->regmap, pmu->info->req_offset, | 116 | regmap_update_bits(pmu->regmap, pmu->info->req_offset, |
100 | pd_info->req_mask, idle ? -1U : 0); | 117 | pd_info->req_mask, idle ? -1U : 0); |
101 | 118 | ||
@@ -111,11 +128,64 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, | |||
111 | return 0; | 128 | return 0; |
112 | } | 129 | } |
113 | 130 | ||
131 | static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) | ||
132 | { | ||
133 | int i; | ||
134 | |||
135 | for (i = 0; i < pd->num_qos; i++) { | ||
136 | regmap_read(pd->qos_regmap[i], | ||
137 | QOS_PRIORITY, | ||
138 | &pd->qos_save_regs[0][i]); | ||
139 | regmap_read(pd->qos_regmap[i], | ||
140 | QOS_MODE, | ||
141 | &pd->qos_save_regs[1][i]); | ||
142 | regmap_read(pd->qos_regmap[i], | ||
143 | QOS_BANDWIDTH, | ||
144 | &pd->qos_save_regs[2][i]); | ||
145 | regmap_read(pd->qos_regmap[i], | ||
146 | QOS_SATURATION, | ||
147 | &pd->qos_save_regs[3][i]); | ||
148 | regmap_read(pd->qos_regmap[i], | ||
149 | QOS_EXTCONTROL, | ||
150 | &pd->qos_save_regs[4][i]); | ||
151 | } | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd) | ||
156 | { | ||
157 | int i; | ||
158 | |||
159 | for (i = 0; i < pd->num_qos; i++) { | ||
160 | regmap_write(pd->qos_regmap[i], | ||
161 | QOS_PRIORITY, | ||
162 | pd->qos_save_regs[0][i]); | ||
163 | regmap_write(pd->qos_regmap[i], | ||
164 | QOS_MODE, | ||
165 | pd->qos_save_regs[1][i]); | ||
166 | regmap_write(pd->qos_regmap[i], | ||
167 | QOS_BANDWIDTH, | ||
168 | pd->qos_save_regs[2][i]); | ||
169 | regmap_write(pd->qos_regmap[i], | ||
170 | QOS_SATURATION, | ||
171 | pd->qos_save_regs[3][i]); | ||
172 | regmap_write(pd->qos_regmap[i], | ||
173 | QOS_EXTCONTROL, | ||
174 | pd->qos_save_regs[4][i]); | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
114 | static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) | 180 | static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) |
115 | { | 181 | { |
116 | struct rockchip_pmu *pmu = pd->pmu; | 182 | struct rockchip_pmu *pmu = pd->pmu; |
117 | unsigned int val; | 183 | unsigned int val; |
118 | 184 | ||
185 | /* check idle status for idle-only domains */ | ||
186 | if (pd->info->status_mask == 0) | ||
187 | return !rockchip_pmu_domain_is_idle(pd); | ||
188 | |||
119 | regmap_read(pmu->regmap, pmu->info->status_offset, &val); | 189 | regmap_read(pmu->regmap, pmu->info->status_offset, &val); |
120 | 190 | ||
121 | /* 1'b0: power on, 1'b1: power off */ | 191 | /* 1'b0: power on, 1'b1: power off */ |
@@ -127,6 +197,9 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, | |||
127 | { | 197 | { |
128 | struct rockchip_pmu *pmu = pd->pmu; | 198 | struct rockchip_pmu *pmu = pd->pmu; |
129 | 199 | ||
200 | if (pd->info->pwr_mask == 0) | ||
201 | return; | ||
202 | |||
130 | regmap_update_bits(pmu->regmap, pmu->info->pwr_offset, | 203 | regmap_update_bits(pmu->regmap, pmu->info->pwr_offset, |
131 | pd->info->pwr_mask, on ? 0 : -1U); | 204 | pd->info->pwr_mask, on ? 0 : -1U); |
132 | 205 | ||
@@ -147,7 +220,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) | |||
147 | clk_enable(pd->clks[i]); | 220 | clk_enable(pd->clks[i]); |
148 | 221 | ||
149 | if (!power_on) { | 222 | if (!power_on) { |
150 | /* FIXME: add code to save AXI_QOS */ | 223 | rockchip_pmu_save_qos(pd); |
151 | 224 | ||
152 | /* if powering down, idle request to NIU first */ | 225 | /* if powering down, idle request to NIU first */ |
153 | rockchip_pmu_set_idle_request(pd, true); | 226 | rockchip_pmu_set_idle_request(pd, true); |
@@ -159,7 +232,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) | |||
159 | /* if powering up, leave idle mode */ | 232 | /* if powering up, leave idle mode */ |
160 | rockchip_pmu_set_idle_request(pd, false); | 233 | rockchip_pmu_set_idle_request(pd, false); |
161 | 234 | ||
162 | /* FIXME: add code to restore AXI_QOS */ | 235 | rockchip_pmu_restore_qos(pd); |
163 | } | 236 | } |
164 | 237 | ||
165 | for (i = pd->num_clks - 1; i >= 0; i--) | 238 | for (i = pd->num_clks - 1; i >= 0; i--) |
@@ -227,9 +300,10 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, | |||
227 | { | 300 | { |
228 | const struct rockchip_domain_info *pd_info; | 301 | const struct rockchip_domain_info *pd_info; |
229 | struct rockchip_pm_domain *pd; | 302 | struct rockchip_pm_domain *pd; |
303 | struct device_node *qos_node; | ||
230 | struct clk *clk; | 304 | struct clk *clk; |
231 | int clk_cnt; | 305 | int clk_cnt; |
232 | int i; | 306 | int i, j; |
233 | u32 id; | 307 | u32 id; |
234 | int error; | 308 | int error; |
235 | 309 | ||
@@ -289,6 +363,45 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, | |||
289 | clk, node->name); | 363 | clk, node->name); |
290 | } | 364 | } |
291 | 365 | ||
366 | pd->num_qos = of_count_phandle_with_args(node, "pm_qos", | ||
367 | NULL); | ||
368 | |||
369 | if (pd->num_qos > 0) { | ||
370 | pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos, | ||
371 | sizeof(*pd->qos_regmap), | ||
372 | GFP_KERNEL); | ||
373 | if (!pd->qos_regmap) { | ||
374 | error = -ENOMEM; | ||
375 | goto err_out; | ||
376 | } | ||
377 | |||
378 | for (j = 0; j < MAX_QOS_REGS_NUM; j++) { | ||
379 | pd->qos_save_regs[j] = devm_kcalloc(pmu->dev, | ||
380 | pd->num_qos, | ||
381 | sizeof(u32), | ||
382 | GFP_KERNEL); | ||
383 | if (!pd->qos_save_regs[j]) { | ||
384 | error = -ENOMEM; | ||
385 | goto err_out; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | for (j = 0; j < pd->num_qos; j++) { | ||
390 | qos_node = of_parse_phandle(node, "pm_qos", j); | ||
391 | if (!qos_node) { | ||
392 | error = -ENODEV; | ||
393 | goto err_out; | ||
394 | } | ||
395 | pd->qos_regmap[j] = syscon_node_to_regmap(qos_node); | ||
396 | if (IS_ERR(pd->qos_regmap[j])) { | ||
397 | error = -ENODEV; | ||
398 | of_node_put(qos_node); | ||
399 | goto err_out; | ||
400 | } | ||
401 | of_node_put(qos_node); | ||
402 | } | ||
403 | } | ||
404 | |||
292 | error = rockchip_pd_power(pd, true); | 405 | error = rockchip_pd_power(pd, true); |
293 | if (error) { | 406 | if (error) { |
294 | dev_err(pmu->dev, | 407 | dev_err(pmu->dev, |
@@ -360,6 +473,61 @@ static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu, | |||
360 | regmap_write(pmu->regmap, domain_reg_offset + 4, count); | 473 | regmap_write(pmu->regmap, domain_reg_offset + 4, count); |
361 | } | 474 | } |
362 | 475 | ||
476 | static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, | ||
477 | struct device_node *parent) | ||
478 | { | ||
479 | struct device_node *np; | ||
480 | struct generic_pm_domain *child_domain, *parent_domain; | ||
481 | int error; | ||
482 | |||
483 | for_each_child_of_node(parent, np) { | ||
484 | u32 idx; | ||
485 | |||
486 | error = of_property_read_u32(parent, "reg", &idx); | ||
487 | if (error) { | ||
488 | dev_err(pmu->dev, | ||
489 | "%s: failed to retrieve domain id (reg): %d\n", | ||
490 | parent->name, error); | ||
491 | goto err_out; | ||
492 | } | ||
493 | parent_domain = pmu->genpd_data.domains[idx]; | ||
494 | |||
495 | error = rockchip_pm_add_one_domain(pmu, np); | ||
496 | if (error) { | ||
497 | dev_err(pmu->dev, "failed to handle node %s: %d\n", | ||
498 | np->name, error); | ||
499 | goto err_out; | ||
500 | } | ||
501 | |||
502 | error = of_property_read_u32(np, "reg", &idx); | ||
503 | if (error) { | ||
504 | dev_err(pmu->dev, | ||
505 | "%s: failed to retrieve domain id (reg): %d\n", | ||
506 | np->name, error); | ||
507 | goto err_out; | ||
508 | } | ||
509 | child_domain = pmu->genpd_data.domains[idx]; | ||
510 | |||
511 | error = pm_genpd_add_subdomain(parent_domain, child_domain); | ||
512 | if (error) { | ||
513 | dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n", | ||
514 | parent_domain->name, child_domain->name, error); | ||
515 | goto err_out; | ||
516 | } else { | ||
517 | dev_dbg(pmu->dev, "%s add subdomain: %s\n", | ||
518 | parent_domain->name, child_domain->name); | ||
519 | } | ||
520 | |||
521 | rockchip_pm_add_subdomain(pmu, np); | ||
522 | } | ||
523 | |||
524 | return 0; | ||
525 | |||
526 | err_out: | ||
527 | of_node_put(np); | ||
528 | return error; | ||
529 | } | ||
530 | |||
363 | static int rockchip_pm_domain_probe(struct platform_device *pdev) | 531 | static int rockchip_pm_domain_probe(struct platform_device *pdev) |
364 | { | 532 | { |
365 | struct device *dev = &pdev->dev; | 533 | struct device *dev = &pdev->dev; |
@@ -406,6 +574,10 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) | |||
406 | } | 574 | } |
407 | 575 | ||
408 | pmu->regmap = syscon_node_to_regmap(parent->of_node); | 576 | pmu->regmap = syscon_node_to_regmap(parent->of_node); |
577 | if (IS_ERR(pmu->regmap)) { | ||
578 | dev_err(dev, "no regmap available\n"); | ||
579 | return PTR_ERR(pmu->regmap); | ||
580 | } | ||
409 | 581 | ||
410 | /* | 582 | /* |
411 | * Configure power up and down transition delays for CORE | 583 | * Configure power up and down transition delays for CORE |
@@ -426,6 +598,14 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) | |||
426 | of_node_put(node); | 598 | of_node_put(node); |
427 | goto err_out; | 599 | goto err_out; |
428 | } | 600 | } |
601 | |||
602 | error = rockchip_pm_add_subdomain(pmu, node); | ||
603 | if (error < 0) { | ||
604 | dev_err(dev, "failed to handle subdomain node %s: %d\n", | ||
605 | node->name, error); | ||
606 | of_node_put(node); | ||
607 | goto err_out; | ||
608 | } | ||
429 | } | 609 | } |
430 | 610 | ||
431 | if (error) { | 611 | if (error) { |
@@ -457,6 +637,36 @@ static const struct rockchip_domain_info rk3368_pm_domains[] = { | |||
457 | [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2), | 637 | [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2), |
458 | }; | 638 | }; |
459 | 639 | ||
640 | static const struct rockchip_domain_info rk3399_pm_domains[] = { | ||
641 | [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1), | ||
642 | [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1), | ||
643 | [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1), | ||
644 | [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15), | ||
645 | [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16), | ||
646 | [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1), | ||
647 | [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2), | ||
648 | [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14), | ||
649 | [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17), | ||
650 | [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0), | ||
651 | [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3), | ||
652 | [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4), | ||
653 | [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5), | ||
654 | [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6), | ||
655 | [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1), | ||
656 | [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7), | ||
657 | [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8), | ||
658 | [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9), | ||
659 | [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10), | ||
660 | [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11), | ||
661 | [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23), | ||
662 | [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24), | ||
663 | [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12), | ||
664 | [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22), | ||
665 | [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27), | ||
666 | [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28), | ||
667 | [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29), | ||
668 | }; | ||
669 | |||
460 | static const struct rockchip_pmu_info rk3288_pmu = { | 670 | static const struct rockchip_pmu_info rk3288_pmu = { |
461 | .pwr_offset = 0x08, | 671 | .pwr_offset = 0x08, |
462 | .status_offset = 0x0c, | 672 | .status_offset = 0x0c, |
@@ -491,6 +701,23 @@ static const struct rockchip_pmu_info rk3368_pmu = { | |||
491 | .domain_info = rk3368_pm_domains, | 701 | .domain_info = rk3368_pm_domains, |
492 | }; | 702 | }; |
493 | 703 | ||
704 | static const struct rockchip_pmu_info rk3399_pmu = { | ||
705 | .pwr_offset = 0x14, | ||
706 | .status_offset = 0x18, | ||
707 | .req_offset = 0x60, | ||
708 | .idle_offset = 0x64, | ||
709 | .ack_offset = 0x68, | ||
710 | |||
711 | .core_pwrcnt_offset = 0x9c, | ||
712 | .gpu_pwrcnt_offset = 0xa4, | ||
713 | |||
714 | .core_power_transition_time = 24, | ||
715 | .gpu_power_transition_time = 24, | ||
716 | |||
717 | .num_domains = ARRAY_SIZE(rk3399_pm_domains), | ||
718 | .domain_info = rk3399_pm_domains, | ||
719 | }; | ||
720 | |||
494 | static const struct of_device_id rockchip_pm_domain_dt_match[] = { | 721 | static const struct of_device_id rockchip_pm_domain_dt_match[] = { |
495 | { | 722 | { |
496 | .compatible = "rockchip,rk3288-power-controller", | 723 | .compatible = "rockchip,rk3288-power-controller", |
@@ -500,6 +727,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { | |||
500 | .compatible = "rockchip,rk3368-power-controller", | 727 | .compatible = "rockchip,rk3368-power-controller", |
501 | .data = (void *)&rk3368_pmu, | 728 | .data = (void *)&rk3368_pmu, |
502 | }, | 729 | }, |
730 | { | ||
731 | .compatible = "rockchip,rk3399-power-controller", | ||
732 | .data = (void *)&rk3399_pmu, | ||
733 | }, | ||
503 | { /* sentinel */ }, | 734 | { /* sentinel */ }, |
504 | }; | 735 | }; |
505 | 736 | ||
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index bc34cf7482fb..bb173456bbff 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c | |||
@@ -28,12 +28,16 @@ | |||
28 | #include <linux/export.h> | 28 | #include <linux/export.h> |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/io.h> | 30 | #include <linux/io.h> |
31 | #include <linux/iopoll.h> | ||
31 | #include <linux/of.h> | 32 | #include <linux/of.h> |
32 | #include <linux/of_address.h> | 33 | #include <linux/of_address.h> |
34 | #include <linux/of_platform.h> | ||
33 | #include <linux/platform_device.h> | 35 | #include <linux/platform_device.h> |
36 | #include <linux/pm_domain.h> | ||
34 | #include <linux/reboot.h> | 37 | #include <linux/reboot.h> |
35 | #include <linux/reset.h> | 38 | #include <linux/reset.h> |
36 | #include <linux/seq_file.h> | 39 | #include <linux/seq_file.h> |
40 | #include <linux/slab.h> | ||
37 | #include <linux/spinlock.h> | 41 | #include <linux/spinlock.h> |
38 | 42 | ||
39 | #include <soc/tegra/common.h> | 43 | #include <soc/tegra/common.h> |
@@ -101,6 +105,16 @@ | |||
101 | 105 | ||
102 | #define GPU_RG_CNTRL 0x2d4 | 106 | #define GPU_RG_CNTRL 0x2d4 |
103 | 107 | ||
108 | struct tegra_powergate { | ||
109 | struct generic_pm_domain genpd; | ||
110 | struct tegra_pmc *pmc; | ||
111 | unsigned int id; | ||
112 | struct clk **clks; | ||
113 | unsigned int num_clks; | ||
114 | struct reset_control **resets; | ||
115 | unsigned int num_resets; | ||
116 | }; | ||
117 | |||
104 | struct tegra_pmc_soc { | 118 | struct tegra_pmc_soc { |
105 | unsigned int num_powergates; | 119 | unsigned int num_powergates; |
106 | const char *const *powergates; | 120 | const char *const *powergates; |
@@ -113,8 +127,11 @@ struct tegra_pmc_soc { | |||
113 | 127 | ||
114 | /** | 128 | /** |
115 | * struct tegra_pmc - NVIDIA Tegra PMC | 129 | * struct tegra_pmc - NVIDIA Tegra PMC |
130 | * @dev: pointer to PMC device structure | ||
116 | * @base: pointer to I/O remapped register region | 131 | * @base: pointer to I/O remapped register region |
117 | * @clk: pointer to pclk clock | 132 | * @clk: pointer to pclk clock |
133 | * @soc: pointer to SoC data structure | ||
134 | * @debugfs: pointer to debugfs entry | ||
118 | * @rate: currently configured rate of pclk | 135 | * @rate: currently configured rate of pclk |
119 | * @suspend_mode: lowest suspend mode available | 136 | * @suspend_mode: lowest suspend mode available |
120 | * @cpu_good_time: CPU power good time (in microseconds) | 137 | * @cpu_good_time: CPU power good time (in microseconds) |
@@ -128,12 +145,14 @@ struct tegra_pmc_soc { | |||
128 | * @cpu_pwr_good_en: CPU power good signal is enabled | 145 | * @cpu_pwr_good_en: CPU power good signal is enabled |
129 | * @lp0_vec_phys: physical base address of the LP0 warm boot code | 146 | * @lp0_vec_phys: physical base address of the LP0 warm boot code |
130 | * @lp0_vec_size: size of the LP0 warm boot code | 147 | * @lp0_vec_size: size of the LP0 warm boot code |
148 | * @powergates_available: Bitmap of available power gates | ||
131 | * @powergates_lock: mutex for power gate register access | 149 | * @powergates_lock: mutex for power gate register access |
132 | */ | 150 | */ |
133 | struct tegra_pmc { | 151 | struct tegra_pmc { |
134 | struct device *dev; | 152 | struct device *dev; |
135 | void __iomem *base; | 153 | void __iomem *base; |
136 | struct clk *clk; | 154 | struct clk *clk; |
155 | struct dentry *debugfs; | ||
137 | 156 | ||
138 | const struct tegra_pmc_soc *soc; | 157 | const struct tegra_pmc_soc *soc; |
139 | 158 | ||
@@ -151,6 +170,7 @@ struct tegra_pmc { | |||
151 | bool cpu_pwr_good_en; | 170 | bool cpu_pwr_good_en; |
152 | u32 lp0_vec_phys; | 171 | u32 lp0_vec_phys; |
153 | u32 lp0_vec_size; | 172 | u32 lp0_vec_size; |
173 | DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); | ||
154 | 174 | ||
155 | struct mutex powergates_lock; | 175 | struct mutex powergates_lock; |
156 | }; | 176 | }; |
@@ -160,6 +180,12 @@ static struct tegra_pmc *pmc = &(struct tegra_pmc) { | |||
160 | .suspend_mode = TEGRA_SUSPEND_NONE, | 180 | .suspend_mode = TEGRA_SUSPEND_NONE, |
161 | }; | 181 | }; |
162 | 182 | ||
183 | static inline struct tegra_powergate * | ||
184 | to_powergate(struct generic_pm_domain *domain) | ||
185 | { | ||
186 | return container_of(domain, struct tegra_powergate, genpd); | ||
187 | } | ||
188 | |||
163 | static u32 tegra_pmc_readl(unsigned long offset) | 189 | static u32 tegra_pmc_readl(unsigned long offset) |
164 | { | 190 | { |
165 | return readl(pmc->base + offset); | 191 | return readl(pmc->base + offset); |
@@ -170,38 +196,287 @@ static void tegra_pmc_writel(u32 value, unsigned long offset) | |||
170 | writel(value, pmc->base + offset); | 196 | writel(value, pmc->base + offset); |
171 | } | 197 | } |
172 | 198 | ||
199 | static inline bool tegra_powergate_state(int id) | ||
200 | { | ||
201 | if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) | ||
202 | return (tegra_pmc_readl(GPU_RG_CNTRL) & 0x1) == 0; | ||
203 | else | ||
204 | return (tegra_pmc_readl(PWRGATE_STATUS) & BIT(id)) != 0; | ||
205 | } | ||
206 | |||
207 | static inline bool tegra_powergate_is_valid(int id) | ||
208 | { | ||
209 | return (pmc->soc && pmc->soc->powergates[id]); | ||
210 | } | ||
211 | |||
212 | static inline bool tegra_powergate_is_available(int id) | ||
213 | { | ||
214 | return test_bit(id, pmc->powergates_available); | ||
215 | } | ||
216 | |||
217 | static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) | ||
218 | { | ||
219 | unsigned int i; | ||
220 | |||
221 | if (!pmc || !pmc->soc || !name) | ||
222 | return -EINVAL; | ||
223 | |||
224 | for (i = 0; i < pmc->soc->num_powergates; i++) { | ||
225 | if (!tegra_powergate_is_valid(i)) | ||
226 | continue; | ||
227 | |||
228 | if (!strcmp(name, pmc->soc->powergates[i])) | ||
229 | return i; | ||
230 | } | ||
231 | |||
232 | dev_err(pmc->dev, "powergate %s not found\n", name); | ||
233 | |||
234 | return -ENODEV; | ||
235 | } | ||
236 | |||
173 | /** | 237 | /** |
174 | * tegra_powergate_set() - set the state of a partition | 238 | * tegra_powergate_set() - set the state of a partition |
175 | * @id: partition ID | 239 | * @id: partition ID |
176 | * @new_state: new state of the partition | 240 | * @new_state: new state of the partition |
177 | */ | 241 | */ |
178 | static int tegra_powergate_set(int id, bool new_state) | 242 | static int tegra_powergate_set(unsigned int id, bool new_state) |
179 | { | 243 | { |
180 | bool status; | 244 | bool status; |
245 | int err; | ||
181 | 246 | ||
182 | mutex_lock(&pmc->powergates_lock); | 247 | if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) |
248 | return -EINVAL; | ||
183 | 249 | ||
184 | status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); | 250 | mutex_lock(&pmc->powergates_lock); |
185 | 251 | ||
186 | if (status == new_state) { | 252 | if (tegra_powergate_state(id) == new_state) { |
187 | mutex_unlock(&pmc->powergates_lock); | 253 | mutex_unlock(&pmc->powergates_lock); |
188 | return 0; | 254 | return 0; |
189 | } | 255 | } |
190 | 256 | ||
191 | tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); | 257 | tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); |
192 | 258 | ||
259 | err = readx_poll_timeout(tegra_powergate_state, id, status, | ||
260 | status == new_state, 10, 100000); | ||
261 | |||
262 | mutex_unlock(&pmc->powergates_lock); | ||
263 | |||
264 | return err; | ||
265 | } | ||
266 | |||
267 | static int __tegra_powergate_remove_clamping(unsigned int id) | ||
268 | { | ||
269 | u32 mask; | ||
270 | |||
271 | mutex_lock(&pmc->powergates_lock); | ||
272 | |||
273 | /* | ||
274 | * On Tegra124 and later, the clamps for the GPU are controlled by a | ||
275 | * separate register (with different semantics). | ||
276 | */ | ||
277 | if (id == TEGRA_POWERGATE_3D) { | ||
278 | if (pmc->soc->has_gpu_clamps) { | ||
279 | tegra_pmc_writel(0, GPU_RG_CNTRL); | ||
280 | goto out; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Tegra 2 has a bug where PCIE and VDE clamping masks are | ||
286 | * swapped relatively to the partition ids | ||
287 | */ | ||
288 | if (id == TEGRA_POWERGATE_VDEC) | ||
289 | mask = (1 << TEGRA_POWERGATE_PCIE); | ||
290 | else if (id == TEGRA_POWERGATE_PCIE) | ||
291 | mask = (1 << TEGRA_POWERGATE_VDEC); | ||
292 | else | ||
293 | mask = (1 << id); | ||
294 | |||
295 | tegra_pmc_writel(mask, REMOVE_CLAMPING); | ||
296 | |||
297 | out: | ||
193 | mutex_unlock(&pmc->powergates_lock); | 298 | mutex_unlock(&pmc->powergates_lock); |
194 | 299 | ||
195 | return 0; | 300 | return 0; |
196 | } | 301 | } |
197 | 302 | ||
303 | static void tegra_powergate_disable_clocks(struct tegra_powergate *pg) | ||
304 | { | ||
305 | unsigned int i; | ||
306 | |||
307 | for (i = 0; i < pg->num_clks; i++) | ||
308 | clk_disable_unprepare(pg->clks[i]); | ||
309 | } | ||
310 | |||
311 | static int tegra_powergate_enable_clocks(struct tegra_powergate *pg) | ||
312 | { | ||
313 | unsigned int i; | ||
314 | int err; | ||
315 | |||
316 | for (i = 0; i < pg->num_clks; i++) { | ||
317 | err = clk_prepare_enable(pg->clks[i]); | ||
318 | if (err) | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | |||
324 | out: | ||
325 | while (i--) | ||
326 | clk_disable_unprepare(pg->clks[i]); | ||
327 | |||
328 | return err; | ||
329 | } | ||
330 | |||
331 | static int tegra_powergate_reset_assert(struct tegra_powergate *pg) | ||
332 | { | ||
333 | unsigned int i; | ||
334 | int err; | ||
335 | |||
336 | for (i = 0; i < pg->num_resets; i++) { | ||
337 | err = reset_control_assert(pg->resets[i]); | ||
338 | if (err) | ||
339 | return err; | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int tegra_powergate_reset_deassert(struct tegra_powergate *pg) | ||
346 | { | ||
347 | unsigned int i; | ||
348 | int err; | ||
349 | |||
350 | for (i = 0; i < pg->num_resets; i++) { | ||
351 | err = reset_control_deassert(pg->resets[i]); | ||
352 | if (err) | ||
353 | return err; | ||
354 | } | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int tegra_powergate_power_up(struct tegra_powergate *pg, | ||
360 | bool disable_clocks) | ||
361 | { | ||
362 | int err; | ||
363 | |||
364 | err = tegra_powergate_reset_assert(pg); | ||
365 | if (err) | ||
366 | return err; | ||
367 | |||
368 | usleep_range(10, 20); | ||
369 | |||
370 | err = tegra_powergate_set(pg->id, true); | ||
371 | if (err < 0) | ||
372 | return err; | ||
373 | |||
374 | usleep_range(10, 20); | ||
375 | |||
376 | err = tegra_powergate_enable_clocks(pg); | ||
377 | if (err) | ||
378 | goto disable_clks; | ||
379 | |||
380 | usleep_range(10, 20); | ||
381 | |||
382 | err = __tegra_powergate_remove_clamping(pg->id); | ||
383 | if (err) | ||
384 | goto disable_clks; | ||
385 | |||
386 | usleep_range(10, 20); | ||
387 | |||
388 | err = tegra_powergate_reset_deassert(pg); | ||
389 | if (err) | ||
390 | goto powergate_off; | ||
391 | |||
392 | usleep_range(10, 20); | ||
393 | |||
394 | if (disable_clocks) | ||
395 | tegra_powergate_disable_clocks(pg); | ||
396 | |||
397 | return 0; | ||
398 | |||
399 | disable_clks: | ||
400 | tegra_powergate_disable_clocks(pg); | ||
401 | usleep_range(10, 20); | ||
402 | powergate_off: | ||
403 | tegra_powergate_set(pg->id, false); | ||
404 | |||
405 | return err; | ||
406 | } | ||
407 | |||
408 | static int tegra_powergate_power_down(struct tegra_powergate *pg) | ||
409 | { | ||
410 | int err; | ||
411 | |||
412 | err = tegra_powergate_enable_clocks(pg); | ||
413 | if (err) | ||
414 | return err; | ||
415 | |||
416 | usleep_range(10, 20); | ||
417 | |||
418 | err = tegra_powergate_reset_assert(pg); | ||
419 | if (err) | ||
420 | goto disable_clks; | ||
421 | |||
422 | usleep_range(10, 20); | ||
423 | |||
424 | tegra_powergate_disable_clocks(pg); | ||
425 | |||
426 | usleep_range(10, 20); | ||
427 | |||
428 | err = tegra_powergate_set(pg->id, false); | ||
429 | if (err) | ||
430 | goto assert_resets; | ||
431 | |||
432 | return 0; | ||
433 | |||
434 | assert_resets: | ||
435 | tegra_powergate_enable_clocks(pg); | ||
436 | usleep_range(10, 20); | ||
437 | tegra_powergate_reset_deassert(pg); | ||
438 | usleep_range(10, 20); | ||
439 | disable_clks: | ||
440 | tegra_powergate_disable_clocks(pg); | ||
441 | |||
442 | return err; | ||
443 | } | ||
444 | |||
445 | static int tegra_genpd_power_on(struct generic_pm_domain *domain) | ||
446 | { | ||
447 | struct tegra_powergate *pg = to_powergate(domain); | ||
448 | struct tegra_pmc *pmc = pg->pmc; | ||
449 | int err; | ||
450 | |||
451 | err = tegra_powergate_power_up(pg, true); | ||
452 | if (err) | ||
453 | dev_err(pmc->dev, "failed to turn on PM domain %s: %d\n", | ||
454 | pg->genpd.name, err); | ||
455 | |||
456 | return err; | ||
457 | } | ||
458 | |||
459 | static int tegra_genpd_power_off(struct generic_pm_domain *domain) | ||
460 | { | ||
461 | struct tegra_powergate *pg = to_powergate(domain); | ||
462 | struct tegra_pmc *pmc = pg->pmc; | ||
463 | int err; | ||
464 | |||
465 | err = tegra_powergate_power_down(pg); | ||
466 | if (err) | ||
467 | dev_err(pmc->dev, "failed to turn off PM domain %s: %d\n", | ||
468 | pg->genpd.name, err); | ||
469 | |||
470 | return err; | ||
471 | } | ||
472 | |||
198 | /** | 473 | /** |
199 | * tegra_powergate_power_on() - power on partition | 474 | * tegra_powergate_power_on() - power on partition |
200 | * @id: partition ID | 475 | * @id: partition ID |
201 | */ | 476 | */ |
202 | int tegra_powergate_power_on(int id) | 477 | int tegra_powergate_power_on(unsigned int id) |
203 | { | 478 | { |
204 | if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) | 479 | if (!tegra_powergate_is_available(id)) |
205 | return -EINVAL; | 480 | return -EINVAL; |
206 | 481 | ||
207 | return tegra_powergate_set(id, true); | 482 | return tegra_powergate_set(id, true); |
@@ -211,9 +486,9 @@ int tegra_powergate_power_on(int id) | |||
211 | * tegra_powergate_power_off() - power off partition | 486 | * tegra_powergate_power_off() - power off partition |
212 | * @id: partition ID | 487 | * @id: partition ID |
213 | */ | 488 | */ |
214 | int tegra_powergate_power_off(int id) | 489 | int tegra_powergate_power_off(unsigned int id) |
215 | { | 490 | { |
216 | if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) | 491 | if (!tegra_powergate_is_available(id)) |
217 | return -EINVAL; | 492 | return -EINVAL; |
218 | 493 | ||
219 | return tegra_powergate_set(id, false); | 494 | return tegra_powergate_set(id, false); |
@@ -224,53 +499,30 @@ EXPORT_SYMBOL(tegra_powergate_power_off); | |||
224 | * tegra_powergate_is_powered() - check if partition is powered | 499 | * tegra_powergate_is_powered() - check if partition is powered |
225 | * @id: partition ID | 500 | * @id: partition ID |
226 | */ | 501 | */ |
227 | int tegra_powergate_is_powered(int id) | 502 | int tegra_powergate_is_powered(unsigned int id) |
228 | { | 503 | { |
229 | u32 status; | 504 | int status; |
230 | 505 | ||
231 | if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) | 506 | if (!tegra_powergate_is_valid(id)) |
232 | return -EINVAL; | 507 | return -EINVAL; |
233 | 508 | ||
234 | status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); | 509 | mutex_lock(&pmc->powergates_lock); |
235 | return !!status; | 510 | status = tegra_powergate_state(id); |
511 | mutex_unlock(&pmc->powergates_lock); | ||
512 | |||
513 | return status; | ||
236 | } | 514 | } |
237 | 515 | ||
238 | /** | 516 | /** |
239 | * tegra_powergate_remove_clamping() - remove power clamps for partition | 517 | * tegra_powergate_remove_clamping() - remove power clamps for partition |
240 | * @id: partition ID | 518 | * @id: partition ID |
241 | */ | 519 | */ |
242 | int tegra_powergate_remove_clamping(int id) | 520 | int tegra_powergate_remove_clamping(unsigned int id) |
243 | { | 521 | { |
244 | u32 mask; | 522 | if (!tegra_powergate_is_available(id)) |
245 | |||
246 | if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) | ||
247 | return -EINVAL; | 523 | return -EINVAL; |
248 | 524 | ||
249 | /* | 525 | return __tegra_powergate_remove_clamping(id); |
250 | * On Tegra124 and later, the clamps for the GPU are controlled by a | ||
251 | * separate register (with different semantics). | ||
252 | */ | ||
253 | if (id == TEGRA_POWERGATE_3D) { | ||
254 | if (pmc->soc->has_gpu_clamps) { | ||
255 | tegra_pmc_writel(0, GPU_RG_CNTRL); | ||
256 | return 0; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Tegra 2 has a bug where PCIE and VDE clamping masks are | ||
262 | * swapped relatively to the partition ids | ||
263 | */ | ||
264 | if (id == TEGRA_POWERGATE_VDEC) | ||
265 | mask = (1 << TEGRA_POWERGATE_PCIE); | ||
266 | else if (id == TEGRA_POWERGATE_PCIE) | ||
267 | mask = (1 << TEGRA_POWERGATE_VDEC); | ||
268 | else | ||
269 | mask = (1 << id); | ||
270 | |||
271 | tegra_pmc_writel(mask, REMOVE_CLAMPING); | ||
272 | |||
273 | return 0; | ||
274 | } | 526 | } |
275 | EXPORT_SYMBOL(tegra_powergate_remove_clamping); | 527 | EXPORT_SYMBOL(tegra_powergate_remove_clamping); |
276 | 528 | ||
@@ -282,38 +534,23 @@ EXPORT_SYMBOL(tegra_powergate_remove_clamping); | |||
282 | * | 534 | * |
283 | * Must be called with clk disabled, and returns with clk enabled. | 535 | * Must be called with clk disabled, and returns with clk enabled. |
284 | */ | 536 | */ |
285 | int tegra_powergate_sequence_power_up(int id, struct clk *clk, | 537 | int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, |
286 | struct reset_control *rst) | 538 | struct reset_control *rst) |
287 | { | 539 | { |
288 | int ret; | 540 | struct tegra_powergate pg; |
289 | 541 | int err; | |
290 | reset_control_assert(rst); | ||
291 | |||
292 | ret = tegra_powergate_power_on(id); | ||
293 | if (ret) | ||
294 | goto err_power; | ||
295 | |||
296 | ret = clk_prepare_enable(clk); | ||
297 | if (ret) | ||
298 | goto err_clk; | ||
299 | |||
300 | usleep_range(10, 20); | ||
301 | |||
302 | ret = tegra_powergate_remove_clamping(id); | ||
303 | if (ret) | ||
304 | goto err_clamp; | ||
305 | 542 | ||
306 | usleep_range(10, 20); | 543 | pg.id = id; |
307 | reset_control_deassert(rst); | 544 | pg.clks = &clk; |
545 | pg.num_clks = 1; | ||
546 | pg.resets = &rst; | ||
547 | pg.num_resets = 1; | ||
308 | 548 | ||
309 | return 0; | 549 | err = tegra_powergate_power_up(&pg, false); |
550 | if (err) | ||
551 | pr_err("failed to turn on partition %d: %d\n", id, err); | ||
310 | 552 | ||
311 | err_clamp: | 553 | return err; |
312 | clk_disable_unprepare(clk); | ||
313 | err_clk: | ||
314 | tegra_powergate_power_off(id); | ||
315 | err_power: | ||
316 | return ret; | ||
317 | } | 554 | } |
318 | EXPORT_SYMBOL(tegra_powergate_sequence_power_up); | 555 | EXPORT_SYMBOL(tegra_powergate_sequence_power_up); |
319 | 556 | ||
@@ -325,9 +562,9 @@ EXPORT_SYMBOL(tegra_powergate_sequence_power_up); | |||
325 | * Returns the partition ID corresponding to the CPU partition ID or a | 562 | * Returns the partition ID corresponding to the CPU partition ID or a |
326 | * negative error code on failure. | 563 | * negative error code on failure. |
327 | */ | 564 | */ |
328 | static int tegra_get_cpu_powergate_id(int cpuid) | 565 | static int tegra_get_cpu_powergate_id(unsigned int cpuid) |
329 | { | 566 | { |
330 | if (pmc->soc && cpuid > 0 && cpuid < pmc->soc->num_cpu_powergates) | 567 | if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates) |
331 | return pmc->soc->cpu_powergates[cpuid]; | 568 | return pmc->soc->cpu_powergates[cpuid]; |
332 | 569 | ||
333 | return -EINVAL; | 570 | return -EINVAL; |
@@ -337,7 +574,7 @@ static int tegra_get_cpu_powergate_id(int cpuid) | |||
337 | * tegra_pmc_cpu_is_powered() - check if CPU partition is powered | 574 | * tegra_pmc_cpu_is_powered() - check if CPU partition is powered |
338 | * @cpuid: CPU partition ID | 575 | * @cpuid: CPU partition ID |
339 | */ | 576 | */ |
340 | bool tegra_pmc_cpu_is_powered(int cpuid) | 577 | bool tegra_pmc_cpu_is_powered(unsigned int cpuid) |
341 | { | 578 | { |
342 | int id; | 579 | int id; |
343 | 580 | ||
@@ -352,7 +589,7 @@ bool tegra_pmc_cpu_is_powered(int cpuid) | |||
352 | * tegra_pmc_cpu_power_on() - power on CPU partition | 589 | * tegra_pmc_cpu_power_on() - power on CPU partition |
353 | * @cpuid: CPU partition ID | 590 | * @cpuid: CPU partition ID |
354 | */ | 591 | */ |
355 | int tegra_pmc_cpu_power_on(int cpuid) | 592 | int tegra_pmc_cpu_power_on(unsigned int cpuid) |
356 | { | 593 | { |
357 | int id; | 594 | int id; |
358 | 595 | ||
@@ -367,7 +604,7 @@ int tegra_pmc_cpu_power_on(int cpuid) | |||
367 | * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition | 604 | * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition |
368 | * @cpuid: CPU partition ID | 605 | * @cpuid: CPU partition ID |
369 | */ | 606 | */ |
370 | int tegra_pmc_cpu_remove_clamping(int cpuid) | 607 | int tegra_pmc_cpu_remove_clamping(unsigned int cpuid) |
371 | { | 608 | { |
372 | int id; | 609 | int id; |
373 | 610 | ||
@@ -416,16 +653,18 @@ static struct notifier_block tegra_pmc_restart_handler = { | |||
416 | static int powergate_show(struct seq_file *s, void *data) | 653 | static int powergate_show(struct seq_file *s, void *data) |
417 | { | 654 | { |
418 | unsigned int i; | 655 | unsigned int i; |
656 | int status; | ||
419 | 657 | ||
420 | seq_printf(s, " powergate powered\n"); | 658 | seq_printf(s, " powergate powered\n"); |
421 | seq_printf(s, "------------------\n"); | 659 | seq_printf(s, "------------------\n"); |
422 | 660 | ||
423 | for (i = 0; i < pmc->soc->num_powergates; i++) { | 661 | for (i = 0; i < pmc->soc->num_powergates; i++) { |
424 | if (!pmc->soc->powergates[i]) | 662 | status = tegra_powergate_is_powered(i); |
663 | if (status < 0) | ||
425 | continue; | 664 | continue; |
426 | 665 | ||
427 | seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], | 666 | seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], |
428 | tegra_powergate_is_powered(i) ? "yes" : "no"); | 667 | status ? "yes" : "no"); |
429 | } | 668 | } |
430 | 669 | ||
431 | return 0; | 670 | return 0; |
@@ -445,17 +684,164 @@ static const struct file_operations powergate_fops = { | |||
445 | 684 | ||
446 | static int tegra_powergate_debugfs_init(void) | 685 | static int tegra_powergate_debugfs_init(void) |
447 | { | 686 | { |
448 | struct dentry *d; | 687 | pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, |
688 | &powergate_fops); | ||
689 | if (!pmc->debugfs) | ||
690 | return -ENOMEM; | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, | ||
696 | struct device_node *np) | ||
697 | { | ||
698 | struct clk *clk; | ||
699 | unsigned int i, count; | ||
700 | int err; | ||
701 | |||
702 | count = of_count_phandle_with_args(np, "clocks", "#clock-cells"); | ||
703 | if (count == 0) | ||
704 | return -ENODEV; | ||
705 | |||
706 | pg->clks = kcalloc(count, sizeof(clk), GFP_KERNEL); | ||
707 | if (!pg->clks) | ||
708 | return -ENOMEM; | ||
709 | |||
710 | for (i = 0; i < count; i++) { | ||
711 | pg->clks[i] = of_clk_get(np, i); | ||
712 | if (IS_ERR(pg->clks[i])) { | ||
713 | err = PTR_ERR(pg->clks[i]); | ||
714 | goto err; | ||
715 | } | ||
716 | } | ||
717 | |||
718 | pg->num_clks = count; | ||
719 | |||
720 | return 0; | ||
721 | |||
722 | err: | ||
723 | while (i--) | ||
724 | clk_put(pg->clks[i]); | ||
725 | kfree(pg->clks); | ||
726 | |||
727 | return err; | ||
728 | } | ||
729 | |||
730 | static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, | ||
731 | struct device_node *np) | ||
732 | { | ||
733 | struct reset_control *rst; | ||
734 | unsigned int i, count; | ||
735 | int err; | ||
736 | |||
737 | count = of_count_phandle_with_args(np, "resets", "#reset-cells"); | ||
738 | if (count == 0) | ||
739 | return -ENODEV; | ||
449 | 740 | ||
450 | d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, | 741 | pg->resets = kcalloc(count, sizeof(rst), GFP_KERNEL); |
451 | &powergate_fops); | 742 | if (!pg->resets) |
452 | if (!d) | ||
453 | return -ENOMEM; | 743 | return -ENOMEM; |
454 | 744 | ||
745 | for (i = 0; i < count; i++) { | ||
746 | pg->resets[i] = of_reset_control_get_by_index(np, i); | ||
747 | if (IS_ERR(pg->resets[i])) { | ||
748 | err = PTR_ERR(pg->resets[i]); | ||
749 | goto error; | ||
750 | } | ||
751 | } | ||
752 | |||
753 | pg->num_resets = count; | ||
754 | |||
455 | return 0; | 755 | return 0; |
756 | |||
757 | error: | ||
758 | while (i--) | ||
759 | reset_control_put(pg->resets[i]); | ||
760 | kfree(pg->resets); | ||
761 | |||
762 | return err; | ||
763 | } | ||
764 | |||
765 | static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) | ||
766 | { | ||
767 | struct tegra_powergate *pg; | ||
768 | bool off; | ||
769 | int id; | ||
770 | |||
771 | pg = kzalloc(sizeof(*pg), GFP_KERNEL); | ||
772 | if (!pg) | ||
773 | goto error; | ||
774 | |||
775 | id = tegra_powergate_lookup(pmc, np->name); | ||
776 | if (id < 0) | ||
777 | goto free_mem; | ||
778 | |||
779 | /* | ||
780 | * Clear the bit for this powergate so it cannot be managed | ||
781 | * directly via the legacy APIs for controlling powergates. | ||
782 | */ | ||
783 | clear_bit(id, pmc->powergates_available); | ||
784 | |||
785 | pg->id = id; | ||
786 | pg->genpd.name = np->name; | ||
787 | pg->genpd.power_off = tegra_genpd_power_off; | ||
788 | pg->genpd.power_on = tegra_genpd_power_on; | ||
789 | pg->pmc = pmc; | ||
790 | |||
791 | if (tegra_powergate_of_get_clks(pg, np)) | ||
792 | goto set_available; | ||
793 | |||
794 | if (tegra_powergate_of_get_resets(pg, np)) | ||
795 | goto remove_clks; | ||
796 | |||
797 | off = !tegra_powergate_is_powered(pg->id); | ||
798 | |||
799 | pm_genpd_init(&pg->genpd, NULL, off); | ||
800 | |||
801 | if (of_genpd_add_provider_simple(np, &pg->genpd)) | ||
802 | goto remove_resets; | ||
803 | |||
804 | dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); | ||
805 | |||
806 | return; | ||
807 | |||
808 | remove_resets: | ||
809 | while (pg->num_resets--) | ||
810 | reset_control_put(pg->resets[pg->num_resets]); | ||
811 | kfree(pg->resets); | ||
812 | |||
813 | remove_clks: | ||
814 | while (pg->num_clks--) | ||
815 | clk_put(pg->clks[pg->num_clks]); | ||
816 | kfree(pg->clks); | ||
817 | |||
818 | set_available: | ||
819 | set_bit(id, pmc->powergates_available); | ||
820 | |||
821 | free_mem: | ||
822 | kfree(pg); | ||
823 | |||
824 | error: | ||
825 | dev_err(pmc->dev, "failed to create power domain for %s\n", np->name); | ||
826 | } | ||
827 | |||
828 | static void tegra_powergate_init(struct tegra_pmc *pmc) | ||
829 | { | ||
830 | struct device_node *np, *child; | ||
831 | |||
832 | np = of_get_child_by_name(pmc->dev->of_node, "powergates"); | ||
833 | if (!np) | ||
834 | return; | ||
835 | |||
836 | for_each_child_of_node(np, child) { | ||
837 | tegra_powergate_add(pmc, child); | ||
838 | of_node_put(child); | ||
839 | } | ||
840 | |||
841 | of_node_put(np); | ||
456 | } | 842 | } |
457 | 843 | ||
458 | static int tegra_io_rail_prepare(int id, unsigned long *request, | 844 | static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, |
459 | unsigned long *status, unsigned int *bit) | 845 | unsigned long *status, unsigned int *bit) |
460 | { | 846 | { |
461 | unsigned long rate, value; | 847 | unsigned long rate, value; |
@@ -512,15 +898,17 @@ static void tegra_io_rail_unprepare(void) | |||
512 | tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); | 898 | tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); |
513 | } | 899 | } |
514 | 900 | ||
515 | int tegra_io_rail_power_on(int id) | 901 | int tegra_io_rail_power_on(unsigned int id) |
516 | { | 902 | { |
517 | unsigned long request, status, value; | 903 | unsigned long request, status, value; |
518 | unsigned int bit, mask; | 904 | unsigned int bit, mask; |
519 | int err; | 905 | int err; |
520 | 906 | ||
907 | mutex_lock(&pmc->powergates_lock); | ||
908 | |||
521 | err = tegra_io_rail_prepare(id, &request, &status, &bit); | 909 | err = tegra_io_rail_prepare(id, &request, &status, &bit); |
522 | if (err < 0) | 910 | if (err) |
523 | return err; | 911 | goto error; |
524 | 912 | ||
525 | mask = 1 << bit; | 913 | mask = 1 << bit; |
526 | 914 | ||
@@ -531,27 +919,32 @@ int tegra_io_rail_power_on(int id) | |||
531 | tegra_pmc_writel(value, request); | 919 | tegra_pmc_writel(value, request); |
532 | 920 | ||
533 | err = tegra_io_rail_poll(status, mask, 0, 250); | 921 | err = tegra_io_rail_poll(status, mask, 0, 250); |
534 | if (err < 0) { | 922 | if (err) { |
535 | pr_info("tegra_io_rail_poll() failed: %d\n", err); | 923 | pr_info("tegra_io_rail_poll() failed: %d\n", err); |
536 | return err; | 924 | goto error; |
537 | } | 925 | } |
538 | 926 | ||
539 | tegra_io_rail_unprepare(); | 927 | tegra_io_rail_unprepare(); |
540 | 928 | ||
541 | return 0; | 929 | error: |
930 | mutex_unlock(&pmc->powergates_lock); | ||
931 | |||
932 | return err; | ||
542 | } | 933 | } |
543 | EXPORT_SYMBOL(tegra_io_rail_power_on); | 934 | EXPORT_SYMBOL(tegra_io_rail_power_on); |
544 | 935 | ||
545 | int tegra_io_rail_power_off(int id) | 936 | int tegra_io_rail_power_off(unsigned int id) |
546 | { | 937 | { |
547 | unsigned long request, status, value; | 938 | unsigned long request, status, value; |
548 | unsigned int bit, mask; | 939 | unsigned int bit, mask; |
549 | int err; | 940 | int err; |
550 | 941 | ||
942 | mutex_lock(&pmc->powergates_lock); | ||
943 | |||
551 | err = tegra_io_rail_prepare(id, &request, &status, &bit); | 944 | err = tegra_io_rail_prepare(id, &request, &status, &bit); |
552 | if (err < 0) { | 945 | if (err) { |
553 | pr_info("tegra_io_rail_prepare() failed: %d\n", err); | 946 | pr_info("tegra_io_rail_prepare() failed: %d\n", err); |
554 | return err; | 947 | goto error; |
555 | } | 948 | } |
556 | 949 | ||
557 | mask = 1 << bit; | 950 | mask = 1 << bit; |
@@ -563,12 +956,15 @@ int tegra_io_rail_power_off(int id) | |||
563 | tegra_pmc_writel(value, request); | 956 | tegra_pmc_writel(value, request); |
564 | 957 | ||
565 | err = tegra_io_rail_poll(status, mask, mask, 250); | 958 | err = tegra_io_rail_poll(status, mask, mask, 250); |
566 | if (err < 0) | 959 | if (err) |
567 | return err; | 960 | goto error; |
568 | 961 | ||
569 | tegra_io_rail_unprepare(); | 962 | tegra_io_rail_unprepare(); |
570 | 963 | ||
571 | return 0; | 964 | error: |
965 | mutex_unlock(&pmc->powergates_lock); | ||
966 | |||
967 | return err; | ||
572 | } | 968 | } |
573 | EXPORT_SYMBOL(tegra_io_rail_power_off); | 969 | EXPORT_SYMBOL(tegra_io_rail_power_off); |
574 | 970 | ||
@@ -727,7 +1123,7 @@ static void tegra_pmc_init(struct tegra_pmc *pmc) | |||
727 | tegra_pmc_writel(value, PMC_CNTRL); | 1123 | tegra_pmc_writel(value, PMC_CNTRL); |
728 | } | 1124 | } |
729 | 1125 | ||
730 | void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) | 1126 | static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) |
731 | { | 1127 | { |
732 | static const char disabled[] = "emergency thermal reset disabled"; | 1128 | static const char disabled[] = "emergency thermal reset disabled"; |
733 | u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux; | 1129 | u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux; |
@@ -805,7 +1201,7 @@ out: | |||
805 | 1201 | ||
806 | static int tegra_pmc_probe(struct platform_device *pdev) | 1202 | static int tegra_pmc_probe(struct platform_device *pdev) |
807 | { | 1203 | { |
808 | void __iomem *base = pmc->base; | 1204 | void __iomem *base; |
809 | struct resource *res; | 1205 | struct resource *res; |
810 | int err; | 1206 | int err; |
811 | 1207 | ||
@@ -815,11 +1211,9 @@ static int tegra_pmc_probe(struct platform_device *pdev) | |||
815 | 1211 | ||
816 | /* take over the memory region from the early initialization */ | 1212 | /* take over the memory region from the early initialization */ |
817 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1213 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
818 | pmc->base = devm_ioremap_resource(&pdev->dev, res); | 1214 | base = devm_ioremap_resource(&pdev->dev, res); |
819 | if (IS_ERR(pmc->base)) | 1215 | if (IS_ERR(base)) |
820 | return PTR_ERR(pmc->base); | 1216 | return PTR_ERR(base); |
821 | |||
822 | iounmap(base); | ||
823 | 1217 | ||
824 | pmc->clk = devm_clk_get(&pdev->dev, "pclk"); | 1218 | pmc->clk = devm_clk_get(&pdev->dev, "pclk"); |
825 | if (IS_ERR(pmc->clk)) { | 1219 | if (IS_ERR(pmc->clk)) { |
@@ -842,11 +1236,19 @@ static int tegra_pmc_probe(struct platform_device *pdev) | |||
842 | 1236 | ||
843 | err = register_restart_handler(&tegra_pmc_restart_handler); | 1237 | err = register_restart_handler(&tegra_pmc_restart_handler); |
844 | if (err) { | 1238 | if (err) { |
1239 | debugfs_remove(pmc->debugfs); | ||
845 | dev_err(&pdev->dev, "unable to register restart handler, %d\n", | 1240 | dev_err(&pdev->dev, "unable to register restart handler, %d\n", |
846 | err); | 1241 | err); |
847 | return err; | 1242 | return err; |
848 | } | 1243 | } |
849 | 1244 | ||
1245 | tegra_powergate_init(pmc); | ||
1246 | |||
1247 | mutex_lock(&pmc->powergates_lock); | ||
1248 | iounmap(pmc->base); | ||
1249 | pmc->base = base; | ||
1250 | mutex_unlock(&pmc->powergates_lock); | ||
1251 | |||
850 | return 0; | 1252 | return 0; |
851 | } | 1253 | } |
852 | 1254 | ||
@@ -964,7 +1366,6 @@ static const char * const tegra124_powergates[] = { | |||
964 | [TEGRA_POWERGATE_VENC] = "venc", | 1366 | [TEGRA_POWERGATE_VENC] = "venc", |
965 | [TEGRA_POWERGATE_PCIE] = "pcie", | 1367 | [TEGRA_POWERGATE_PCIE] = "pcie", |
966 | [TEGRA_POWERGATE_VDEC] = "vdec", | 1368 | [TEGRA_POWERGATE_VDEC] = "vdec", |
967 | [TEGRA_POWERGATE_L2] = "l2", | ||
968 | [TEGRA_POWERGATE_MPE] = "mpe", | 1369 | [TEGRA_POWERGATE_MPE] = "mpe", |
969 | [TEGRA_POWERGATE_HEG] = "heg", | 1370 | [TEGRA_POWERGATE_HEG] = "heg", |
970 | [TEGRA_POWERGATE_SATA] = "sata", | 1371 | [TEGRA_POWERGATE_SATA] = "sata", |
@@ -1006,17 +1407,13 @@ static const char * const tegra210_powergates[] = { | |||
1006 | [TEGRA_POWERGATE_3D] = "3d", | 1407 | [TEGRA_POWERGATE_3D] = "3d", |
1007 | [TEGRA_POWERGATE_VENC] = "venc", | 1408 | [TEGRA_POWERGATE_VENC] = "venc", |
1008 | [TEGRA_POWERGATE_PCIE] = "pcie", | 1409 | [TEGRA_POWERGATE_PCIE] = "pcie", |
1009 | [TEGRA_POWERGATE_L2] = "l2", | ||
1010 | [TEGRA_POWERGATE_MPE] = "mpe", | 1410 | [TEGRA_POWERGATE_MPE] = "mpe", |
1011 | [TEGRA_POWERGATE_HEG] = "heg", | ||
1012 | [TEGRA_POWERGATE_SATA] = "sata", | 1411 | [TEGRA_POWERGATE_SATA] = "sata", |
1013 | [TEGRA_POWERGATE_CPU1] = "cpu1", | 1412 | [TEGRA_POWERGATE_CPU1] = "cpu1", |
1014 | [TEGRA_POWERGATE_CPU2] = "cpu2", | 1413 | [TEGRA_POWERGATE_CPU2] = "cpu2", |
1015 | [TEGRA_POWERGATE_CPU3] = "cpu3", | 1414 | [TEGRA_POWERGATE_CPU3] = "cpu3", |
1016 | [TEGRA_POWERGATE_CELP] = "celp", | ||
1017 | [TEGRA_POWERGATE_CPU0] = "cpu0", | 1415 | [TEGRA_POWERGATE_CPU0] = "cpu0", |
1018 | [TEGRA_POWERGATE_C0NC] = "c0nc", | 1416 | [TEGRA_POWERGATE_C0NC] = "c0nc", |
1019 | [TEGRA_POWERGATE_C1NC] = "c1nc", | ||
1020 | [TEGRA_POWERGATE_SOR] = "sor", | 1417 | [TEGRA_POWERGATE_SOR] = "sor", |
1021 | [TEGRA_POWERGATE_DIS] = "dis", | 1418 | [TEGRA_POWERGATE_DIS] = "dis", |
1022 | [TEGRA_POWERGATE_DISB] = "disb", | 1419 | [TEGRA_POWERGATE_DISB] = "disb", |
@@ -1080,6 +1477,7 @@ static int __init tegra_pmc_early_init(void) | |||
1080 | const struct of_device_id *match; | 1477 | const struct of_device_id *match; |
1081 | struct device_node *np; | 1478 | struct device_node *np; |
1082 | struct resource regs; | 1479 | struct resource regs; |
1480 | unsigned int i; | ||
1083 | bool invert; | 1481 | bool invert; |
1084 | u32 value; | 1482 | u32 value; |
1085 | 1483 | ||
@@ -1129,6 +1527,11 @@ static int __init tegra_pmc_early_init(void) | |||
1129 | return -ENXIO; | 1527 | return -ENXIO; |
1130 | } | 1528 | } |
1131 | 1529 | ||
1530 | /* Create a bit-map of the available and valid partitions */ | ||
1531 | for (i = 0; i < pmc->soc->num_powergates; i++) | ||
1532 | if (pmc->soc->powergates[i]) | ||
1533 | set_bit(i, pmc->powergates_available); | ||
1534 | |||
1132 | mutex_init(&pmc->powergates_lock); | 1535 | mutex_init(&pmc->powergates_lock); |
1133 | 1536 | ||
1134 | /* | 1537 | /* |
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3050b18b2447..6acac6201af0 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -69,6 +69,15 @@ config USB_XHCI_RCAR | |||
69 | Say 'Y' to enable the support for the xHCI host controller | 69 | Say 'Y' to enable the support for the xHCI host controller |
70 | found in Renesas R-Car ARM SoCs. | 70 | found in Renesas R-Car ARM SoCs. |
71 | 71 | ||
72 | config USB_XHCI_TEGRA | ||
73 | tristate "xHCI support for NVIDIA Tegra SoCs" | ||
74 | depends on PHY_TEGRA_XUSB | ||
75 | depends on RESET_CONTROLLER | ||
76 | select FW_LOADER | ||
77 | ---help--- | ||
78 | Say 'Y' to enable the support for the xHCI host controller | ||
79 | found in NVIDIA Tegra124 and later SoCs. | ||
80 | |||
72 | endif # USB_XHCI_HCD | 81 | endif # USB_XHCI_HCD |
73 | 82 | ||
74 | config USB_EHCI_HCD | 83 | config USB_EHCI_HCD |
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index a9ddd3c9ec94..6ef785b0ea8f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -68,6 +68,7 @@ obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o | |||
68 | obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o | 68 | obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o |
69 | obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o | 69 | obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o |
70 | obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o | 70 | obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o |
71 | obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o | ||
71 | obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o | 72 | obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o |
72 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o | 73 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o |
73 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o | 74 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o |
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c new file mode 100644 index 000000000000..0f53ae0f464e --- /dev/null +++ b/drivers/usb/host/xhci-tegra.c | |||
@@ -0,0 +1,1331 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra xHCI host controller driver | ||
3 | * | ||
4 | * Copyright (C) 2014 NVIDIA Corporation | ||
5 | * Copyright (C) 2014 Google, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/firmware.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of_device.h> | ||
20 | #include <linux/phy/phy.h> | ||
21 | #include <linux/phy/tegra/xusb.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/pm.h> | ||
24 | #include <linux/regulator/consumer.h> | ||
25 | #include <linux/reset.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include "xhci.h" | ||
29 | |||
30 | #define TEGRA_XHCI_SS_HIGH_SPEED 120000000 | ||
31 | #define TEGRA_XHCI_SS_LOW_SPEED 12000000 | ||
32 | |||
33 | /* FPCI CFG registers */ | ||
34 | #define XUSB_CFG_1 0x004 | ||
35 | #define XUSB_IO_SPACE_EN BIT(0) | ||
36 | #define XUSB_MEM_SPACE_EN BIT(1) | ||
37 | #define XUSB_BUS_MASTER_EN BIT(2) | ||
38 | #define XUSB_CFG_4 0x010 | ||
39 | #define XUSB_BASE_ADDR_SHIFT 15 | ||
40 | #define XUSB_BASE_ADDR_MASK 0x1ffff | ||
41 | #define XUSB_CFG_ARU_C11_CSBRANGE 0x41c | ||
42 | #define XUSB_CFG_CSB_BASE_ADDR 0x800 | ||
43 | |||
44 | /* FPCI mailbox registers */ | ||
45 | #define XUSB_CFG_ARU_MBOX_CMD 0x0e4 | ||
46 | #define MBOX_DEST_FALC BIT(27) | ||
47 | #define MBOX_DEST_PME BIT(28) | ||
48 | #define MBOX_DEST_SMI BIT(29) | ||
49 | #define MBOX_DEST_XHCI BIT(30) | ||
50 | #define MBOX_INT_EN BIT(31) | ||
51 | #define XUSB_CFG_ARU_MBOX_DATA_IN 0x0e8 | ||
52 | #define CMD_DATA_SHIFT 0 | ||
53 | #define CMD_DATA_MASK 0xffffff | ||
54 | #define CMD_TYPE_SHIFT 24 | ||
55 | #define CMD_TYPE_MASK 0xff | ||
56 | #define XUSB_CFG_ARU_MBOX_DATA_OUT 0x0ec | ||
57 | #define XUSB_CFG_ARU_MBOX_OWNER 0x0f0 | ||
58 | #define MBOX_OWNER_NONE 0 | ||
59 | #define MBOX_OWNER_FW 1 | ||
60 | #define MBOX_OWNER_SW 2 | ||
61 | #define XUSB_CFG_ARU_SMI_INTR 0x428 | ||
62 | #define MBOX_SMI_INTR_FW_HANG BIT(1) | ||
63 | #define MBOX_SMI_INTR_EN BIT(3) | ||
64 | |||
65 | /* IPFS registers */ | ||
66 | #define IPFS_XUSB_HOST_CONFIGURATION_0 0x180 | ||
67 | #define IPFS_EN_FPCI BIT(0) | ||
68 | #define IPFS_XUSB_HOST_INTR_MASK_0 0x188 | ||
69 | #define IPFS_IP_INT_MASK BIT(16) | ||
70 | #define IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0 0x1bc | ||
71 | |||
72 | #define CSB_PAGE_SELECT_MASK 0x7fffff | ||
73 | #define CSB_PAGE_SELECT_SHIFT 9 | ||
74 | #define CSB_PAGE_OFFSET_MASK 0x1ff | ||
75 | #define CSB_PAGE_SELECT(addr) ((addr) >> (CSB_PAGE_SELECT_SHIFT) & \ | ||
76 | CSB_PAGE_SELECT_MASK) | ||
77 | #define CSB_PAGE_OFFSET(addr) ((addr) & CSB_PAGE_OFFSET_MASK) | ||
78 | |||
79 | /* Falcon CSB registers */ | ||
80 | #define XUSB_FALC_CPUCTL 0x100 | ||
81 | #define CPUCTL_STARTCPU BIT(1) | ||
82 | #define CPUCTL_STATE_HALTED BIT(4) | ||
83 | #define CPUCTL_STATE_STOPPED BIT(5) | ||
84 | #define XUSB_FALC_BOOTVEC 0x104 | ||
85 | #define XUSB_FALC_DMACTL 0x10c | ||
86 | #define XUSB_FALC_IMFILLRNG1 0x154 | ||
87 | #define IMFILLRNG1_TAG_MASK 0xffff | ||
88 | #define IMFILLRNG1_TAG_LO_SHIFT 0 | ||
89 | #define IMFILLRNG1_TAG_HI_SHIFT 16 | ||
90 | #define XUSB_FALC_IMFILLCTL 0x158 | ||
91 | |||
92 | /* MP CSB registers */ | ||
93 | #define XUSB_CSB_MP_ILOAD_ATTR 0x101a00 | ||
94 | #define XUSB_CSB_MP_ILOAD_BASE_LO 0x101a04 | ||
95 | #define XUSB_CSB_MP_ILOAD_BASE_HI 0x101a08 | ||
96 | #define XUSB_CSB_MP_L2IMEMOP_SIZE 0x101a10 | ||
97 | #define L2IMEMOP_SIZE_SRC_OFFSET_SHIFT 8 | ||
98 | #define L2IMEMOP_SIZE_SRC_OFFSET_MASK 0x3ff | ||
99 | #define L2IMEMOP_SIZE_SRC_COUNT_SHIFT 24 | ||
100 | #define L2IMEMOP_SIZE_SRC_COUNT_MASK 0xff | ||
101 | #define XUSB_CSB_MP_L2IMEMOP_TRIG 0x101a14 | ||
102 | #define L2IMEMOP_ACTION_SHIFT 24 | ||
103 | #define L2IMEMOP_INVALIDATE_ALL (0x40 << L2IMEMOP_ACTION_SHIFT) | ||
104 | #define L2IMEMOP_LOAD_LOCKED_RESULT (0x11 << L2IMEMOP_ACTION_SHIFT) | ||
105 | #define XUSB_CSB_MP_APMAP 0x10181c | ||
106 | #define APMAP_BOOTPATH BIT(31) | ||
107 | |||
108 | #define IMEM_BLOCK_SIZE 256 | ||
109 | |||
110 | struct tegra_xusb_fw_header { | ||
111 | u32 boot_loadaddr_in_imem; | ||
112 | u32 boot_codedfi_offset; | ||
113 | u32 boot_codetag; | ||
114 | u32 boot_codesize; | ||
115 | u32 phys_memaddr; | ||
116 | u16 reqphys_memsize; | ||
117 | u16 alloc_phys_memsize; | ||
118 | u32 rodata_img_offset; | ||
119 | u32 rodata_section_start; | ||
120 | u32 rodata_section_end; | ||
121 | u32 main_fnaddr; | ||
122 | u32 fwimg_cksum; | ||
123 | u32 fwimg_created_time; | ||
124 | u32 imem_resident_start; | ||
125 | u32 imem_resident_end; | ||
126 | u32 idirect_start; | ||
127 | u32 idirect_end; | ||
128 | u32 l2_imem_start; | ||
129 | u32 l2_imem_end; | ||
130 | u32 version_id; | ||
131 | u8 init_ddirect; | ||
132 | u8 reserved[3]; | ||
133 | u32 phys_addr_log_buffer; | ||
134 | u32 total_log_entries; | ||
135 | u32 dequeue_ptr; | ||
136 | u32 dummy_var[2]; | ||
137 | u32 fwimg_len; | ||
138 | u8 magic[8]; | ||
139 | u32 ss_low_power_entry_timeout; | ||
140 | u8 num_hsic_port; | ||
141 | u8 padding[139]; /* Pad to 256 bytes */ | ||
142 | }; | ||
143 | |||
144 | struct tegra_xusb_phy_type { | ||
145 | const char *name; | ||
146 | unsigned int num; | ||
147 | }; | ||
148 | |||
149 | struct tegra_xusb_soc { | ||
150 | const char *firmware; | ||
151 | const char * const *supply_names; | ||
152 | unsigned int num_supplies; | ||
153 | const struct tegra_xusb_phy_type *phy_types; | ||
154 | unsigned int num_types; | ||
155 | |||
156 | struct { | ||
157 | struct { | ||
158 | unsigned int offset; | ||
159 | unsigned int count; | ||
160 | } usb2, ulpi, hsic, usb3; | ||
161 | } ports; | ||
162 | |||
163 | bool scale_ss_clock; | ||
164 | }; | ||
165 | |||
166 | struct tegra_xusb { | ||
167 | struct device *dev; | ||
168 | void __iomem *regs; | ||
169 | struct usb_hcd *hcd; | ||
170 | |||
171 | struct mutex lock; | ||
172 | |||
173 | int xhci_irq; | ||
174 | int mbox_irq; | ||
175 | |||
176 | void __iomem *ipfs_base; | ||
177 | void __iomem *fpci_base; | ||
178 | |||
179 | const struct tegra_xusb_soc *soc; | ||
180 | |||
181 | struct regulator_bulk_data *supplies; | ||
182 | |||
183 | struct tegra_xusb_padctl *padctl; | ||
184 | |||
185 | struct clk *host_clk; | ||
186 | struct clk *falcon_clk; | ||
187 | struct clk *ss_clk; | ||
188 | struct clk *ss_src_clk; | ||
189 | struct clk *hs_src_clk; | ||
190 | struct clk *fs_src_clk; | ||
191 | struct clk *pll_u_480m; | ||
192 | struct clk *clk_m; | ||
193 | struct clk *pll_e; | ||
194 | |||
195 | struct reset_control *host_rst; | ||
196 | struct reset_control *ss_rst; | ||
197 | |||
198 | struct phy **phys; | ||
199 | unsigned int num_phys; | ||
200 | |||
201 | /* Firmware loading related */ | ||
202 | struct { | ||
203 | size_t size; | ||
204 | void *virt; | ||
205 | dma_addr_t phys; | ||
206 | } fw; | ||
207 | }; | ||
208 | |||
209 | static struct hc_driver __read_mostly tegra_xhci_hc_driver; | ||
210 | |||
211 | static inline u32 fpci_readl(struct tegra_xusb *tegra, unsigned int offset) | ||
212 | { | ||
213 | return readl(tegra->fpci_base + offset); | ||
214 | } | ||
215 | |||
216 | static inline void fpci_writel(struct tegra_xusb *tegra, u32 value, | ||
217 | unsigned int offset) | ||
218 | { | ||
219 | writel(value, tegra->fpci_base + offset); | ||
220 | } | ||
221 | |||
222 | static inline u32 ipfs_readl(struct tegra_xusb *tegra, unsigned int offset) | ||
223 | { | ||
224 | return readl(tegra->ipfs_base + offset); | ||
225 | } | ||
226 | |||
227 | static inline void ipfs_writel(struct tegra_xusb *tegra, u32 value, | ||
228 | unsigned int offset) | ||
229 | { | ||
230 | writel(value, tegra->ipfs_base + offset); | ||
231 | } | ||
232 | |||
233 | static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset) | ||
234 | { | ||
235 | u32 page = CSB_PAGE_SELECT(offset); | ||
236 | u32 ofs = CSB_PAGE_OFFSET(offset); | ||
237 | |||
238 | fpci_writel(tegra, page, XUSB_CFG_ARU_C11_CSBRANGE); | ||
239 | |||
240 | return fpci_readl(tegra, XUSB_CFG_CSB_BASE_ADDR + ofs); | ||
241 | } | ||
242 | |||
243 | static void csb_writel(struct tegra_xusb *tegra, u32 value, | ||
244 | unsigned int offset) | ||
245 | { | ||
246 | u32 page = CSB_PAGE_SELECT(offset); | ||
247 | u32 ofs = CSB_PAGE_OFFSET(offset); | ||
248 | |||
249 | fpci_writel(tegra, page, XUSB_CFG_ARU_C11_CSBRANGE); | ||
250 | fpci_writel(tegra, value, XUSB_CFG_CSB_BASE_ADDR + ofs); | ||
251 | } | ||
252 | |||
253 | static int tegra_xusb_set_ss_clk(struct tegra_xusb *tegra, | ||
254 | unsigned long rate) | ||
255 | { | ||
256 | unsigned long new_parent_rate, old_parent_rate; | ||
257 | struct clk *clk = tegra->ss_src_clk; | ||
258 | unsigned int div; | ||
259 | int err; | ||
260 | |||
261 | if (clk_get_rate(clk) == rate) | ||
262 | return 0; | ||
263 | |||
264 | switch (rate) { | ||
265 | case TEGRA_XHCI_SS_HIGH_SPEED: | ||
266 | /* | ||
267 | * Reparent to PLLU_480M. Set divider first to avoid | ||
268 | * overclocking. | ||
269 | */ | ||
270 | old_parent_rate = clk_get_rate(clk_get_parent(clk)); | ||
271 | new_parent_rate = clk_get_rate(tegra->pll_u_480m); | ||
272 | div = new_parent_rate / rate; | ||
273 | |||
274 | err = clk_set_rate(clk, old_parent_rate / div); | ||
275 | if (err) | ||
276 | return err; | ||
277 | |||
278 | err = clk_set_parent(clk, tegra->pll_u_480m); | ||
279 | if (err) | ||
280 | return err; | ||
281 | |||
282 | /* | ||
283 | * The rate should already be correct, but set it again just | ||
284 | * to be sure. | ||
285 | */ | ||
286 | err = clk_set_rate(clk, rate); | ||
287 | if (err) | ||
288 | return err; | ||
289 | |||
290 | break; | ||
291 | |||
292 | case TEGRA_XHCI_SS_LOW_SPEED: | ||
293 | /* Reparent to CLK_M */ | ||
294 | err = clk_set_parent(clk, tegra->clk_m); | ||
295 | if (err) | ||
296 | return err; | ||
297 | |||
298 | err = clk_set_rate(clk, rate); | ||
299 | if (err) | ||
300 | return err; | ||
301 | |||
302 | break; | ||
303 | |||
304 | default: | ||
305 | dev_err(tegra->dev, "Invalid SS rate: %lu Hz\n", rate); | ||
306 | return -EINVAL; | ||
307 | } | ||
308 | |||
309 | if (clk_get_rate(clk) != rate) { | ||
310 | dev_err(tegra->dev, "SS clock doesn't match requested rate\n"); | ||
311 | return -EINVAL; | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static unsigned long extract_field(u32 value, unsigned int start, | ||
318 | unsigned int count) | ||
319 | { | ||
320 | return (value >> start) & ((1 << count) - 1); | ||
321 | } | ||
322 | |||
323 | /* Command requests from the firmware */ | ||
324 | enum tegra_xusb_mbox_cmd { | ||
325 | MBOX_CMD_MSG_ENABLED = 1, | ||
326 | MBOX_CMD_INC_FALC_CLOCK, | ||
327 | MBOX_CMD_DEC_FALC_CLOCK, | ||
328 | MBOX_CMD_INC_SSPI_CLOCK, | ||
329 | MBOX_CMD_DEC_SSPI_CLOCK, | ||
330 | MBOX_CMD_SET_BW, /* no ACK/NAK required */ | ||
331 | MBOX_CMD_SET_SS_PWR_GATING, | ||
332 | MBOX_CMD_SET_SS_PWR_UNGATING, | ||
333 | MBOX_CMD_SAVE_DFE_CTLE_CTX, | ||
334 | MBOX_CMD_AIRPLANE_MODE_ENABLED, /* unused */ | ||
335 | MBOX_CMD_AIRPLANE_MODE_DISABLED, /* unused */ | ||
336 | MBOX_CMD_START_HSIC_IDLE, | ||
337 | MBOX_CMD_STOP_HSIC_IDLE, | ||
338 | MBOX_CMD_DBC_WAKE_STACK, /* unused */ | ||
339 | MBOX_CMD_HSIC_PRETEND_CONNECT, | ||
340 | MBOX_CMD_RESET_SSPI, | ||
341 | MBOX_CMD_DISABLE_SS_LFPS_DETECTION, | ||
342 | MBOX_CMD_ENABLE_SS_LFPS_DETECTION, | ||
343 | |||
344 | MBOX_CMD_MAX, | ||
345 | |||
346 | /* Response message to above commands */ | ||
347 | MBOX_CMD_ACK = 128, | ||
348 | MBOX_CMD_NAK | ||
349 | }; | ||
350 | |||
351 | static const char * const mbox_cmd_name[] = { | ||
352 | [ 1] = "MSG_ENABLE", | ||
353 | [ 2] = "INC_FALCON_CLOCK", | ||
354 | [ 3] = "DEC_FALCON_CLOCK", | ||
355 | [ 4] = "INC_SSPI_CLOCK", | ||
356 | [ 5] = "DEC_SSPI_CLOCK", | ||
357 | [ 6] = "SET_BW", | ||
358 | [ 7] = "SET_SS_PWR_GATING", | ||
359 | [ 8] = "SET_SS_PWR_UNGATING", | ||
360 | [ 9] = "SAVE_DFE_CTLE_CTX", | ||
361 | [ 10] = "AIRPLANE_MODE_ENABLED", | ||
362 | [ 11] = "AIRPLANE_MODE_DISABLED", | ||
363 | [ 12] = "START_HSIC_IDLE", | ||
364 | [ 13] = "STOP_HSIC_IDLE", | ||
365 | [ 14] = "DBC_WAKE_STACK", | ||
366 | [ 15] = "HSIC_PRETEND_CONNECT", | ||
367 | [ 16] = "RESET_SSPI", | ||
368 | [ 17] = "DISABLE_SS_LFPS_DETECTION", | ||
369 | [ 18] = "ENABLE_SS_LFPS_DETECTION", | ||
370 | [128] = "ACK", | ||
371 | [129] = "NAK", | ||
372 | }; | ||
373 | |||
374 | struct tegra_xusb_mbox_msg { | ||
375 | u32 cmd; | ||
376 | u32 data; | ||
377 | }; | ||
378 | |||
379 | static inline u32 tegra_xusb_mbox_pack(const struct tegra_xusb_mbox_msg *msg) | ||
380 | { | ||
381 | return (msg->cmd & CMD_TYPE_MASK) << CMD_TYPE_SHIFT | | ||
382 | (msg->data & CMD_DATA_MASK) << CMD_DATA_SHIFT; | ||
383 | } | ||
384 | static inline void tegra_xusb_mbox_unpack(struct tegra_xusb_mbox_msg *msg, | ||
385 | u32 value) | ||
386 | { | ||
387 | msg->cmd = (value >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK; | ||
388 | msg->data = (value >> CMD_DATA_SHIFT) & CMD_DATA_MASK; | ||
389 | } | ||
390 | |||
391 | static bool tegra_xusb_mbox_cmd_requires_ack(enum tegra_xusb_mbox_cmd cmd) | ||
392 | { | ||
393 | switch (cmd) { | ||
394 | case MBOX_CMD_SET_BW: | ||
395 | case MBOX_CMD_ACK: | ||
396 | case MBOX_CMD_NAK: | ||
397 | return false; | ||
398 | |||
399 | default: | ||
400 | return true; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | static int tegra_xusb_mbox_send(struct tegra_xusb *tegra, | ||
405 | const struct tegra_xusb_mbox_msg *msg) | ||
406 | { | ||
407 | bool wait_for_idle = false; | ||
408 | u32 value; | ||
409 | |||
410 | /* | ||
411 | * Acquire the mailbox. The firmware still owns the mailbox for | ||
412 | * ACK/NAK messages. | ||
413 | */ | ||
414 | if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) { | ||
415 | value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); | ||
416 | if (value != MBOX_OWNER_NONE) { | ||
417 | dev_err(tegra->dev, "mailbox is busy\n"); | ||
418 | return -EBUSY; | ||
419 | } | ||
420 | |||
421 | fpci_writel(tegra, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER); | ||
422 | |||
423 | value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); | ||
424 | if (value != MBOX_OWNER_SW) { | ||
425 | dev_err(tegra->dev, "failed to acquire mailbox\n"); | ||
426 | return -EBUSY; | ||
427 | } | ||
428 | |||
429 | wait_for_idle = true; | ||
430 | } | ||
431 | |||
432 | value = tegra_xusb_mbox_pack(msg); | ||
433 | fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_DATA_IN); | ||
434 | |||
435 | value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); | ||
436 | value |= MBOX_INT_EN | MBOX_DEST_FALC; | ||
437 | fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); | ||
438 | |||
439 | if (wait_for_idle) { | ||
440 | unsigned long timeout = jiffies + msecs_to_jiffies(250); | ||
441 | |||
442 | while (time_before(jiffies, timeout)) { | ||
443 | value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); | ||
444 | if (value == MBOX_OWNER_NONE) | ||
445 | break; | ||
446 | |||
447 | usleep_range(10, 20); | ||
448 | } | ||
449 | |||
450 | if (time_after(jiffies, timeout)) | ||
451 | value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); | ||
452 | |||
453 | if (value != MBOX_OWNER_NONE) | ||
454 | return -ETIMEDOUT; | ||
455 | } | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static irqreturn_t tegra_xusb_mbox_irq(int irq, void *data) | ||
461 | { | ||
462 | struct tegra_xusb *tegra = data; | ||
463 | u32 value; | ||
464 | |||
465 | /* clear mailbox interrupts */ | ||
466 | value = fpci_readl(tegra, XUSB_CFG_ARU_SMI_INTR); | ||
467 | fpci_writel(tegra, value, XUSB_CFG_ARU_SMI_INTR); | ||
468 | |||
469 | if (value & MBOX_SMI_INTR_FW_HANG) | ||
470 | dev_err(tegra->dev, "controller firmware hang\n"); | ||
471 | |||
472 | return IRQ_WAKE_THREAD; | ||
473 | } | ||
474 | |||
475 | static void tegra_xusb_mbox_handle(struct tegra_xusb *tegra, | ||
476 | const struct tegra_xusb_mbox_msg *msg) | ||
477 | { | ||
478 | struct tegra_xusb_padctl *padctl = tegra->padctl; | ||
479 | const struct tegra_xusb_soc *soc = tegra->soc; | ||
480 | struct device *dev = tegra->dev; | ||
481 | struct tegra_xusb_mbox_msg rsp; | ||
482 | unsigned long mask; | ||
483 | unsigned int port; | ||
484 | bool idle, enable; | ||
485 | int err; | ||
486 | |||
487 | memset(&rsp, 0, sizeof(rsp)); | ||
488 | |||
489 | switch (msg->cmd) { | ||
490 | case MBOX_CMD_INC_FALC_CLOCK: | ||
491 | case MBOX_CMD_DEC_FALC_CLOCK: | ||
492 | rsp.data = clk_get_rate(tegra->falcon_clk) / 1000; | ||
493 | if (rsp.data != msg->data) | ||
494 | rsp.cmd = MBOX_CMD_NAK; | ||
495 | else | ||
496 | rsp.cmd = MBOX_CMD_ACK; | ||
497 | |||
498 | break; | ||
499 | |||
500 | case MBOX_CMD_INC_SSPI_CLOCK: | ||
501 | case MBOX_CMD_DEC_SSPI_CLOCK: | ||
502 | if (tegra->soc->scale_ss_clock) { | ||
503 | err = tegra_xusb_set_ss_clk(tegra, msg->data * 1000); | ||
504 | if (err < 0) | ||
505 | rsp.cmd = MBOX_CMD_NAK; | ||
506 | else | ||
507 | rsp.cmd = MBOX_CMD_ACK; | ||
508 | |||
509 | rsp.data = clk_get_rate(tegra->ss_src_clk) / 1000; | ||
510 | } else { | ||
511 | rsp.cmd = MBOX_CMD_ACK; | ||
512 | rsp.data = msg->data; | ||
513 | } | ||
514 | |||
515 | break; | ||
516 | |||
517 | case MBOX_CMD_SET_BW: | ||
518 | /* | ||
519 | * TODO: Request bandwidth once EMC scaling is supported. | ||
520 | * Ignore for now since ACK/NAK is not required for SET_BW | ||
521 | * messages. | ||
522 | */ | ||
523 | break; | ||
524 | |||
525 | case MBOX_CMD_SAVE_DFE_CTLE_CTX: | ||
526 | err = tegra_xusb_padctl_usb3_save_context(padctl, msg->data); | ||
527 | if (err < 0) { | ||
528 | dev_err(dev, "failed to save context for USB3#%u: %d\n", | ||
529 | msg->data, err); | ||
530 | rsp.cmd = MBOX_CMD_NAK; | ||
531 | } else { | ||
532 | rsp.cmd = MBOX_CMD_ACK; | ||
533 | } | ||
534 | |||
535 | rsp.data = msg->data; | ||
536 | break; | ||
537 | |||
538 | case MBOX_CMD_START_HSIC_IDLE: | ||
539 | case MBOX_CMD_STOP_HSIC_IDLE: | ||
540 | if (msg->cmd == MBOX_CMD_STOP_HSIC_IDLE) | ||
541 | idle = false; | ||
542 | else | ||
543 | idle = true; | ||
544 | |||
545 | mask = extract_field(msg->data, 1 + soc->ports.hsic.offset, | ||
546 | soc->ports.hsic.count); | ||
547 | |||
548 | for_each_set_bit(port, &mask, 32) { | ||
549 | err = tegra_xusb_padctl_hsic_set_idle(padctl, port, | ||
550 | idle); | ||
551 | if (err < 0) | ||
552 | break; | ||
553 | } | ||
554 | |||
555 | if (err < 0) { | ||
556 | dev_err(dev, "failed to set HSIC#%u %s: %d\n", port, | ||
557 | idle ? "idle" : "busy", err); | ||
558 | rsp.cmd = MBOX_CMD_NAK; | ||
559 | } else { | ||
560 | rsp.cmd = MBOX_CMD_ACK; | ||
561 | } | ||
562 | |||
563 | rsp.data = msg->data; | ||
564 | break; | ||
565 | |||
566 | case MBOX_CMD_DISABLE_SS_LFPS_DETECTION: | ||
567 | case MBOX_CMD_ENABLE_SS_LFPS_DETECTION: | ||
568 | if (msg->cmd == MBOX_CMD_DISABLE_SS_LFPS_DETECTION) | ||
569 | enable = false; | ||
570 | else | ||
571 | enable = true; | ||
572 | |||
573 | mask = extract_field(msg->data, 1 + soc->ports.usb3.offset, | ||
574 | soc->ports.usb3.count); | ||
575 | |||
576 | for_each_set_bit(port, &mask, soc->ports.usb3.count) { | ||
577 | err = tegra_xusb_padctl_usb3_set_lfps_detect(padctl, | ||
578 | port, | ||
579 | enable); | ||
580 | if (err < 0) | ||
581 | break; | ||
582 | } | ||
583 | |||
584 | if (err < 0) { | ||
585 | dev_err(dev, | ||
586 | "failed to %s LFPS detection on USB3#%u: %d\n", | ||
587 | enable ? "enable" : "disable", port, err); | ||
588 | rsp.cmd = MBOX_CMD_NAK; | ||
589 | } else { | ||
590 | rsp.cmd = MBOX_CMD_ACK; | ||
591 | } | ||
592 | |||
593 | rsp.data = msg->data; | ||
594 | break; | ||
595 | |||
596 | default: | ||
597 | dev_warn(dev, "unknown message: %#x\n", msg->cmd); | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | if (rsp.cmd) { | ||
602 | const char *cmd = (rsp.cmd == MBOX_CMD_ACK) ? "ACK" : "NAK"; | ||
603 | |||
604 | err = tegra_xusb_mbox_send(tegra, &rsp); | ||
605 | if (err < 0) | ||
606 | dev_err(dev, "failed to send %s: %d\n", cmd, err); | ||
607 | } | ||
608 | } | ||
609 | |||
610 | static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data) | ||
611 | { | ||
612 | struct tegra_xusb *tegra = data; | ||
613 | struct tegra_xusb_mbox_msg msg; | ||
614 | u32 value; | ||
615 | |||
616 | mutex_lock(&tegra->lock); | ||
617 | |||
618 | value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_DATA_OUT); | ||
619 | tegra_xusb_mbox_unpack(&msg, value); | ||
620 | |||
621 | value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); | ||
622 | value &= ~MBOX_DEST_SMI; | ||
623 | fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); | ||
624 | |||
625 | /* clear mailbox owner if no ACK/NAK is required */ | ||
626 | if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd)) | ||
627 | fpci_writel(tegra, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER); | ||
628 | |||
629 | tegra_xusb_mbox_handle(tegra, &msg); | ||
630 | |||
631 | mutex_unlock(&tegra->lock); | ||
632 | return IRQ_HANDLED; | ||
633 | } | ||
634 | |||
635 | static void tegra_xusb_ipfs_config(struct tegra_xusb *tegra, | ||
636 | struct resource *regs) | ||
637 | { | ||
638 | u32 value; | ||
639 | |||
640 | value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0); | ||
641 | value |= IPFS_EN_FPCI; | ||
642 | ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0); | ||
643 | |||
644 | usleep_range(10, 20); | ||
645 | |||
646 | /* Program BAR0 space */ | ||
647 | value = fpci_readl(tegra, XUSB_CFG_4); | ||
648 | value &= ~(XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT); | ||
649 | value |= regs->start & (XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT); | ||
650 | fpci_writel(tegra, value, XUSB_CFG_4); | ||
651 | |||
652 | usleep_range(100, 200); | ||
653 | |||
654 | /* Enable bus master */ | ||
655 | value = fpci_readl(tegra, XUSB_CFG_1); | ||
656 | value |= XUSB_IO_SPACE_EN | XUSB_MEM_SPACE_EN | XUSB_BUS_MASTER_EN; | ||
657 | fpci_writel(tegra, value, XUSB_CFG_1); | ||
658 | |||
659 | /* Enable interrupt assertion */ | ||
660 | value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0); | ||
661 | value |= IPFS_IP_INT_MASK; | ||
662 | ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0); | ||
663 | |||
664 | /* Set hysteresis */ | ||
665 | ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0); | ||
666 | } | ||
667 | |||
668 | static int tegra_xusb_clk_enable(struct tegra_xusb *tegra) | ||
669 | { | ||
670 | int err; | ||
671 | |||
672 | err = clk_prepare_enable(tegra->pll_e); | ||
673 | if (err < 0) | ||
674 | return err; | ||
675 | |||
676 | err = clk_prepare_enable(tegra->host_clk); | ||
677 | if (err < 0) | ||
678 | goto disable_plle; | ||
679 | |||
680 | err = clk_prepare_enable(tegra->ss_clk); | ||
681 | if (err < 0) | ||
682 | goto disable_host; | ||
683 | |||
684 | err = clk_prepare_enable(tegra->falcon_clk); | ||
685 | if (err < 0) | ||
686 | goto disable_ss; | ||
687 | |||
688 | err = clk_prepare_enable(tegra->fs_src_clk); | ||
689 | if (err < 0) | ||
690 | goto disable_falc; | ||
691 | |||
692 | err = clk_prepare_enable(tegra->hs_src_clk); | ||
693 | if (err < 0) | ||
694 | goto disable_fs_src; | ||
695 | |||
696 | if (tegra->soc->scale_ss_clock) { | ||
697 | err = tegra_xusb_set_ss_clk(tegra, TEGRA_XHCI_SS_HIGH_SPEED); | ||
698 | if (err < 0) | ||
699 | goto disable_hs_src; | ||
700 | } | ||
701 | |||
702 | return 0; | ||
703 | |||
704 | disable_hs_src: | ||
705 | clk_disable_unprepare(tegra->hs_src_clk); | ||
706 | disable_fs_src: | ||
707 | clk_disable_unprepare(tegra->fs_src_clk); | ||
708 | disable_falc: | ||
709 | clk_disable_unprepare(tegra->falcon_clk); | ||
710 | disable_ss: | ||
711 | clk_disable_unprepare(tegra->ss_clk); | ||
712 | disable_host: | ||
713 | clk_disable_unprepare(tegra->host_clk); | ||
714 | disable_plle: | ||
715 | clk_disable_unprepare(tegra->pll_e); | ||
716 | return err; | ||
717 | } | ||
718 | |||
719 | static void tegra_xusb_clk_disable(struct tegra_xusb *tegra) | ||
720 | { | ||
721 | clk_disable_unprepare(tegra->pll_e); | ||
722 | clk_disable_unprepare(tegra->host_clk); | ||
723 | clk_disable_unprepare(tegra->ss_clk); | ||
724 | clk_disable_unprepare(tegra->falcon_clk); | ||
725 | clk_disable_unprepare(tegra->fs_src_clk); | ||
726 | clk_disable_unprepare(tegra->hs_src_clk); | ||
727 | } | ||
728 | |||
729 | static int tegra_xusb_phy_enable(struct tegra_xusb *tegra) | ||
730 | { | ||
731 | unsigned int i; | ||
732 | int err; | ||
733 | |||
734 | for (i = 0; i < tegra->num_phys; i++) { | ||
735 | err = phy_init(tegra->phys[i]); | ||
736 | if (err) | ||
737 | goto disable_phy; | ||
738 | |||
739 | err = phy_power_on(tegra->phys[i]); | ||
740 | if (err) { | ||
741 | phy_exit(tegra->phys[i]); | ||
742 | goto disable_phy; | ||
743 | } | ||
744 | } | ||
745 | |||
746 | return 0; | ||
747 | |||
748 | disable_phy: | ||
749 | while (i--) { | ||
750 | phy_power_off(tegra->phys[i]); | ||
751 | phy_exit(tegra->phys[i]); | ||
752 | } | ||
753 | |||
754 | return err; | ||
755 | } | ||
756 | |||
757 | static void tegra_xusb_phy_disable(struct tegra_xusb *tegra) | ||
758 | { | ||
759 | unsigned int i; | ||
760 | |||
761 | for (i = 0; i < tegra->num_phys; i++) { | ||
762 | phy_power_off(tegra->phys[i]); | ||
763 | phy_exit(tegra->phys[i]); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) | ||
768 | { | ||
769 | unsigned int code_tag_blocks, code_size_blocks, code_blocks; | ||
770 | struct tegra_xusb_fw_header *header; | ||
771 | struct device *dev = tegra->dev; | ||
772 | const struct firmware *fw; | ||
773 | unsigned long timeout; | ||
774 | time_t timestamp; | ||
775 | struct tm time; | ||
776 | u64 address; | ||
777 | u32 value; | ||
778 | int err; | ||
779 | |||
780 | err = request_firmware(&fw, tegra->soc->firmware, tegra->dev); | ||
781 | if (err < 0) { | ||
782 | dev_err(tegra->dev, "failed to request firmware: %d\n", err); | ||
783 | return err; | ||
784 | } | ||
785 | |||
786 | /* Load Falcon controller with its firmware. */ | ||
787 | header = (struct tegra_xusb_fw_header *)fw->data; | ||
788 | tegra->fw.size = le32_to_cpu(header->fwimg_len); | ||
789 | |||
790 | tegra->fw.virt = dma_alloc_coherent(tegra->dev, tegra->fw.size, | ||
791 | &tegra->fw.phys, GFP_KERNEL); | ||
792 | if (!tegra->fw.virt) { | ||
793 | dev_err(tegra->dev, "failed to allocate memory for firmware\n"); | ||
794 | release_firmware(fw); | ||
795 | return -ENOMEM; | ||
796 | } | ||
797 | |||
798 | header = (struct tegra_xusb_fw_header *)tegra->fw.virt; | ||
799 | memcpy(tegra->fw.virt, fw->data, tegra->fw.size); | ||
800 | release_firmware(fw); | ||
801 | |||
802 | if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) { | ||
803 | dev_info(dev, "Firmware already loaded, Falcon state %#x\n", | ||
804 | csb_readl(tegra, XUSB_FALC_CPUCTL)); | ||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | /* Program the size of DFI into ILOAD_ATTR. */ | ||
809 | csb_writel(tegra, tegra->fw.size, XUSB_CSB_MP_ILOAD_ATTR); | ||
810 | |||
811 | /* | ||
812 | * Boot code of the firmware reads the ILOAD_BASE registers | ||
813 | * to get to the start of the DFI in system memory. | ||
814 | */ | ||
815 | address = tegra->fw.phys + sizeof(*header); | ||
816 | csb_writel(tegra, address >> 32, XUSB_CSB_MP_ILOAD_BASE_HI); | ||
817 | csb_writel(tegra, address, XUSB_CSB_MP_ILOAD_BASE_LO); | ||
818 | |||
819 | /* Set BOOTPATH to 1 in APMAP. */ | ||
820 | csb_writel(tegra, APMAP_BOOTPATH, XUSB_CSB_MP_APMAP); | ||
821 | |||
822 | /* Invalidate L2IMEM. */ | ||
823 | csb_writel(tegra, L2IMEMOP_INVALIDATE_ALL, XUSB_CSB_MP_L2IMEMOP_TRIG); | ||
824 | |||
825 | /* | ||
826 | * Initiate fetch of bootcode from system memory into L2IMEM. | ||
827 | * Program bootcode location and size in system memory. | ||
828 | */ | ||
829 | code_tag_blocks = DIV_ROUND_UP(le32_to_cpu(header->boot_codetag), | ||
830 | IMEM_BLOCK_SIZE); | ||
831 | code_size_blocks = DIV_ROUND_UP(le32_to_cpu(header->boot_codesize), | ||
832 | IMEM_BLOCK_SIZE); | ||
833 | code_blocks = code_tag_blocks + code_size_blocks; | ||
834 | |||
835 | value = ((code_tag_blocks & L2IMEMOP_SIZE_SRC_OFFSET_MASK) << | ||
836 | L2IMEMOP_SIZE_SRC_OFFSET_SHIFT) | | ||
837 | ((code_size_blocks & L2IMEMOP_SIZE_SRC_COUNT_MASK) << | ||
838 | L2IMEMOP_SIZE_SRC_COUNT_SHIFT); | ||
839 | csb_writel(tegra, value, XUSB_CSB_MP_L2IMEMOP_SIZE); | ||
840 | |||
841 | /* Trigger L2IMEM load operation. */ | ||
842 | csb_writel(tegra, L2IMEMOP_LOAD_LOCKED_RESULT, | ||
843 | XUSB_CSB_MP_L2IMEMOP_TRIG); | ||
844 | |||
845 | /* Setup Falcon auto-fill. */ | ||
846 | csb_writel(tegra, code_size_blocks, XUSB_FALC_IMFILLCTL); | ||
847 | |||
848 | value = ((code_tag_blocks & IMFILLRNG1_TAG_MASK) << | ||
849 | IMFILLRNG1_TAG_LO_SHIFT) | | ||
850 | ((code_blocks & IMFILLRNG1_TAG_MASK) << | ||
851 | IMFILLRNG1_TAG_HI_SHIFT); | ||
852 | csb_writel(tegra, value, XUSB_FALC_IMFILLRNG1); | ||
853 | |||
854 | csb_writel(tegra, 0, XUSB_FALC_DMACTL); | ||
855 | |||
856 | msleep(50); | ||
857 | |||
858 | csb_writel(tegra, le32_to_cpu(header->boot_codetag), | ||
859 | XUSB_FALC_BOOTVEC); | ||
860 | |||
861 | /* Boot Falcon CPU and wait for it to enter the STOPPED (idle) state. */ | ||
862 | timeout = jiffies + msecs_to_jiffies(5); | ||
863 | |||
864 | csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL); | ||
865 | |||
866 | while (time_before(jiffies, timeout)) { | ||
867 | if (csb_readl(tegra, XUSB_FALC_CPUCTL) == CPUCTL_STATE_STOPPED) | ||
868 | break; | ||
869 | |||
870 | usleep_range(100, 200); | ||
871 | } | ||
872 | |||
873 | if (csb_readl(tegra, XUSB_FALC_CPUCTL) != CPUCTL_STATE_STOPPED) { | ||
874 | dev_err(dev, "Falcon failed to start, state: %#x\n", | ||
875 | csb_readl(tegra, XUSB_FALC_CPUCTL)); | ||
876 | return -EIO; | ||
877 | } | ||
878 | |||
879 | timestamp = le32_to_cpu(header->fwimg_created_time); | ||
880 | time_to_tm(timestamp, 0, &time); | ||
881 | |||
882 | dev_info(dev, "Firmware timestamp: %ld-%02d-%02d %02d:%02d:%02d UTC\n", | ||
883 | time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, | ||
884 | time.tm_hour, time.tm_min, time.tm_sec); | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static int tegra_xusb_probe(struct platform_device *pdev) | ||
890 | { | ||
891 | struct tegra_xusb_mbox_msg msg; | ||
892 | struct resource *res, *regs; | ||
893 | struct tegra_xusb *tegra; | ||
894 | struct xhci_hcd *xhci; | ||
895 | unsigned int i, j, k; | ||
896 | struct phy *phy; | ||
897 | int err; | ||
898 | |||
899 | BUILD_BUG_ON(sizeof(struct tegra_xusb_fw_header) != 256); | ||
900 | |||
901 | tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); | ||
902 | if (!tegra) | ||
903 | return -ENOMEM; | ||
904 | |||
905 | tegra->soc = of_device_get_match_data(&pdev->dev); | ||
906 | mutex_init(&tegra->lock); | ||
907 | tegra->dev = &pdev->dev; | ||
908 | |||
909 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
910 | tegra->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
911 | if (IS_ERR(tegra->regs)) | ||
912 | return PTR_ERR(tegra->regs); | ||
913 | |||
914 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
915 | tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res); | ||
916 | if (IS_ERR(tegra->fpci_base)) | ||
917 | return PTR_ERR(tegra->fpci_base); | ||
918 | |||
919 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); | ||
920 | tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res); | ||
921 | if (IS_ERR(tegra->ipfs_base)) | ||
922 | return PTR_ERR(tegra->ipfs_base); | ||
923 | |||
924 | tegra->xhci_irq = platform_get_irq(pdev, 0); | ||
925 | if (tegra->xhci_irq < 0) | ||
926 | return tegra->xhci_irq; | ||
927 | |||
928 | tegra->mbox_irq = platform_get_irq(pdev, 1); | ||
929 | if (tegra->mbox_irq < 0) | ||
930 | return tegra->mbox_irq; | ||
931 | |||
932 | tegra->padctl = tegra_xusb_padctl_get(&pdev->dev); | ||
933 | if (IS_ERR(tegra->padctl)) | ||
934 | return PTR_ERR(tegra->padctl); | ||
935 | |||
936 | tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host"); | ||
937 | if (IS_ERR(tegra->host_rst)) { | ||
938 | err = PTR_ERR(tegra->host_rst); | ||
939 | dev_err(&pdev->dev, "failed to get xusb_host reset: %d\n", err); | ||
940 | goto put_padctl; | ||
941 | } | ||
942 | |||
943 | tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss"); | ||
944 | if (IS_ERR(tegra->ss_rst)) { | ||
945 | err = PTR_ERR(tegra->ss_rst); | ||
946 | dev_err(&pdev->dev, "failed to get xusb_ss reset: %d\n", err); | ||
947 | goto put_padctl; | ||
948 | } | ||
949 | |||
950 | tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host"); | ||
951 | if (IS_ERR(tegra->host_clk)) { | ||
952 | err = PTR_ERR(tegra->host_clk); | ||
953 | dev_err(&pdev->dev, "failed to get xusb_host: %d\n", err); | ||
954 | goto put_padctl; | ||
955 | } | ||
956 | |||
957 | tegra->falcon_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src"); | ||
958 | if (IS_ERR(tegra->falcon_clk)) { | ||
959 | err = PTR_ERR(tegra->falcon_clk); | ||
960 | dev_err(&pdev->dev, "failed to get xusb_falcon_src: %d\n", err); | ||
961 | goto put_padctl; | ||
962 | } | ||
963 | |||
964 | tegra->ss_clk = devm_clk_get(&pdev->dev, "xusb_ss"); | ||
965 | if (IS_ERR(tegra->ss_clk)) { | ||
966 | err = PTR_ERR(tegra->ss_clk); | ||
967 | dev_err(&pdev->dev, "failed to get xusb_ss: %d\n", err); | ||
968 | goto put_padctl; | ||
969 | } | ||
970 | |||
971 | tegra->ss_src_clk = devm_clk_get(&pdev->dev, "xusb_ss_src"); | ||
972 | if (IS_ERR(tegra->ss_src_clk)) { | ||
973 | err = PTR_ERR(tegra->ss_src_clk); | ||
974 | dev_err(&pdev->dev, "failed to get xusb_ss_src: %d\n", err); | ||
975 | goto put_padctl; | ||
976 | } | ||
977 | |||
978 | tegra->hs_src_clk = devm_clk_get(&pdev->dev, "xusb_hs_src"); | ||
979 | if (IS_ERR(tegra->hs_src_clk)) { | ||
980 | err = PTR_ERR(tegra->hs_src_clk); | ||
981 | dev_err(&pdev->dev, "failed to get xusb_hs_src: %d\n", err); | ||
982 | goto put_padctl; | ||
983 | } | ||
984 | |||
985 | tegra->fs_src_clk = devm_clk_get(&pdev->dev, "xusb_fs_src"); | ||
986 | if (IS_ERR(tegra->fs_src_clk)) { | ||
987 | err = PTR_ERR(tegra->fs_src_clk); | ||
988 | dev_err(&pdev->dev, "failed to get xusb_fs_src: %d\n", err); | ||
989 | goto put_padctl; | ||
990 | } | ||
991 | |||
992 | tegra->pll_u_480m = devm_clk_get(&pdev->dev, "pll_u_480m"); | ||
993 | if (IS_ERR(tegra->pll_u_480m)) { | ||
994 | err = PTR_ERR(tegra->pll_u_480m); | ||
995 | dev_err(&pdev->dev, "failed to get pll_u_480m: %d\n", err); | ||
996 | goto put_padctl; | ||
997 | } | ||
998 | |||
999 | tegra->clk_m = devm_clk_get(&pdev->dev, "clk_m"); | ||
1000 | if (IS_ERR(tegra->clk_m)) { | ||
1001 | err = PTR_ERR(tegra->clk_m); | ||
1002 | dev_err(&pdev->dev, "failed to get clk_m: %d\n", err); | ||
1003 | goto put_padctl; | ||
1004 | } | ||
1005 | |||
1006 | tegra->pll_e = devm_clk_get(&pdev->dev, "pll_e"); | ||
1007 | if (IS_ERR(tegra->pll_e)) { | ||
1008 | err = PTR_ERR(tegra->pll_e); | ||
1009 | dev_err(&pdev->dev, "failed to get pll_e: %d\n", err); | ||
1010 | goto put_padctl; | ||
1011 | } | ||
1012 | |||
1013 | tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, | ||
1014 | sizeof(*tegra->supplies), GFP_KERNEL); | ||
1015 | if (!tegra->supplies) { | ||
1016 | err = -ENOMEM; | ||
1017 | goto put_padctl; | ||
1018 | } | ||
1019 | |||
1020 | for (i = 0; i < tegra->soc->num_supplies; i++) | ||
1021 | tegra->supplies[i].supply = tegra->soc->supply_names[i]; | ||
1022 | |||
1023 | err = devm_regulator_bulk_get(&pdev->dev, tegra->soc->num_supplies, | ||
1024 | tegra->supplies); | ||
1025 | if (err) { | ||
1026 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); | ||
1027 | goto put_padctl; | ||
1028 | } | ||
1029 | |||
1030 | for (i = 0; i < tegra->soc->num_types; i++) | ||
1031 | tegra->num_phys += tegra->soc->phy_types[i].num; | ||
1032 | |||
1033 | tegra->phys = devm_kcalloc(&pdev->dev, tegra->num_phys, | ||
1034 | sizeof(*tegra->phys), GFP_KERNEL); | ||
1035 | if (!tegra->phys) { | ||
1036 | dev_err(&pdev->dev, "failed to allocate PHY array\n"); | ||
1037 | err = -ENOMEM; | ||
1038 | goto put_padctl; | ||
1039 | } | ||
1040 | |||
1041 | for (i = 0, k = 0; i < tegra->soc->num_types; i++) { | ||
1042 | char prop[8]; | ||
1043 | |||
1044 | for (j = 0; j < tegra->soc->phy_types[i].num; j++) { | ||
1045 | snprintf(prop, sizeof(prop), "%s-%d", | ||
1046 | tegra->soc->phy_types[i].name, j); | ||
1047 | |||
1048 | phy = devm_phy_optional_get(&pdev->dev, prop); | ||
1049 | if (IS_ERR(phy)) { | ||
1050 | dev_err(&pdev->dev, | ||
1051 | "failed to get PHY %s: %ld\n", prop, | ||
1052 | PTR_ERR(phy)); | ||
1053 | err = PTR_ERR(phy); | ||
1054 | goto put_padctl; | ||
1055 | } | ||
1056 | |||
1057 | tegra->phys[k++] = phy; | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | err = tegra_xusb_clk_enable(tegra); | ||
1062 | if (err) { | ||
1063 | dev_err(&pdev->dev, "failed to enable clocks: %d\n", err); | ||
1064 | goto put_padctl; | ||
1065 | } | ||
1066 | |||
1067 | err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies); | ||
1068 | if (err) { | ||
1069 | dev_err(&pdev->dev, "failed to enable regulators: %d\n", err); | ||
1070 | goto disable_clk; | ||
1071 | } | ||
1072 | |||
1073 | err = tegra_xusb_phy_enable(tegra); | ||
1074 | if (err < 0) { | ||
1075 | dev_err(&pdev->dev, "failed to enable PHYs: %d\n", err); | ||
1076 | goto disable_regulator; | ||
1077 | } | ||
1078 | |||
1079 | tegra_xusb_ipfs_config(tegra, regs); | ||
1080 | |||
1081 | err = tegra_xusb_load_firmware(tegra); | ||
1082 | if (err < 0) { | ||
1083 | dev_err(&pdev->dev, "failed to load firmware: %d\n", err); | ||
1084 | goto disable_phy; | ||
1085 | } | ||
1086 | |||
1087 | tegra->hcd = usb_create_hcd(&tegra_xhci_hc_driver, &pdev->dev, | ||
1088 | dev_name(&pdev->dev)); | ||
1089 | if (!tegra->hcd) { | ||
1090 | err = -ENOMEM; | ||
1091 | goto disable_phy; | ||
1092 | } | ||
1093 | |||
1094 | /* | ||
1095 | * This must happen after usb_create_hcd(), because usb_create_hcd() | ||
1096 | * will overwrite the drvdata of the device with the hcd it creates. | ||
1097 | */ | ||
1098 | platform_set_drvdata(pdev, tegra); | ||
1099 | |||
1100 | tegra->hcd->regs = tegra->regs; | ||
1101 | tegra->hcd->rsrc_start = regs->start; | ||
1102 | tegra->hcd->rsrc_len = resource_size(regs); | ||
1103 | |||
1104 | err = usb_add_hcd(tegra->hcd, tegra->xhci_irq, IRQF_SHARED); | ||
1105 | if (err < 0) { | ||
1106 | dev_err(&pdev->dev, "failed to add USB HCD: %d\n", err); | ||
1107 | goto put_usb2; | ||
1108 | } | ||
1109 | |||
1110 | device_wakeup_enable(tegra->hcd->self.controller); | ||
1111 | |||
1112 | xhci = hcd_to_xhci(tegra->hcd); | ||
1113 | |||
1114 | xhci->shared_hcd = usb_create_shared_hcd(&tegra_xhci_hc_driver, | ||
1115 | &pdev->dev, | ||
1116 | dev_name(&pdev->dev), | ||
1117 | tegra->hcd); | ||
1118 | if (!xhci->shared_hcd) { | ||
1119 | dev_err(&pdev->dev, "failed to create shared HCD\n"); | ||
1120 | goto remove_usb2; | ||
1121 | } | ||
1122 | |||
1123 | err = usb_add_hcd(xhci->shared_hcd, tegra->xhci_irq, IRQF_SHARED); | ||
1124 | if (err < 0) { | ||
1125 | dev_err(&pdev->dev, "failed to add shared HCD: %d\n", err); | ||
1126 | goto put_usb3; | ||
1127 | } | ||
1128 | |||
1129 | mutex_lock(&tegra->lock); | ||
1130 | |||
1131 | /* Enable firmware messages from controller. */ | ||
1132 | msg.cmd = MBOX_CMD_MSG_ENABLED; | ||
1133 | msg.data = 0; | ||
1134 | |||
1135 | err = tegra_xusb_mbox_send(tegra, &msg); | ||
1136 | if (err < 0) { | ||
1137 | dev_err(&pdev->dev, "failed to enable messages: %d\n", err); | ||
1138 | mutex_unlock(&tegra->lock); | ||
1139 | goto remove_usb3; | ||
1140 | } | ||
1141 | |||
1142 | mutex_unlock(&tegra->lock); | ||
1143 | |||
1144 | err = devm_request_threaded_irq(&pdev->dev, tegra->mbox_irq, | ||
1145 | tegra_xusb_mbox_irq, | ||
1146 | tegra_xusb_mbox_thread, 0, | ||
1147 | dev_name(&pdev->dev), tegra); | ||
1148 | if (err < 0) { | ||
1149 | dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); | ||
1150 | goto remove_usb3; | ||
1151 | } | ||
1152 | |||
1153 | return 0; | ||
1154 | |||
1155 | remove_usb3: | ||
1156 | usb_remove_hcd(xhci->shared_hcd); | ||
1157 | put_usb3: | ||
1158 | usb_put_hcd(xhci->shared_hcd); | ||
1159 | remove_usb2: | ||
1160 | usb_remove_hcd(tegra->hcd); | ||
1161 | put_usb2: | ||
1162 | usb_put_hcd(tegra->hcd); | ||
1163 | disable_phy: | ||
1164 | tegra_xusb_phy_disable(tegra); | ||
1165 | disable_regulator: | ||
1166 | regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies); | ||
1167 | disable_clk: | ||
1168 | tegra_xusb_clk_disable(tegra); | ||
1169 | put_padctl: | ||
1170 | tegra_xusb_padctl_put(tegra->padctl); | ||
1171 | return err; | ||
1172 | } | ||
1173 | |||
1174 | static int tegra_xusb_remove(struct platform_device *pdev) | ||
1175 | { | ||
1176 | struct tegra_xusb *tegra = platform_get_drvdata(pdev); | ||
1177 | struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); | ||
1178 | |||
1179 | usb_remove_hcd(xhci->shared_hcd); | ||
1180 | usb_put_hcd(xhci->shared_hcd); | ||
1181 | usb_remove_hcd(tegra->hcd); | ||
1182 | usb_put_hcd(tegra->hcd); | ||
1183 | |||
1184 | dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt, | ||
1185 | tegra->fw.phys); | ||
1186 | |||
1187 | tegra_xusb_phy_disable(tegra); | ||
1188 | regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies); | ||
1189 | tegra_xusb_clk_disable(tegra); | ||
1190 | |||
1191 | tegra_xusb_padctl_put(tegra->padctl); | ||
1192 | |||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | #ifdef CONFIG_PM_SLEEP | ||
1197 | static int tegra_xusb_suspend(struct device *dev) | ||
1198 | { | ||
1199 | struct tegra_xusb *tegra = dev_get_drvdata(dev); | ||
1200 | struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); | ||
1201 | bool wakeup = device_may_wakeup(dev); | ||
1202 | |||
1203 | /* TODO: Powergate controller across suspend/resume. */ | ||
1204 | return xhci_suspend(xhci, wakeup); | ||
1205 | } | ||
1206 | |||
1207 | static int tegra_xusb_resume(struct device *dev) | ||
1208 | { | ||
1209 | struct tegra_xusb *tegra = dev_get_drvdata(dev); | ||
1210 | struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); | ||
1211 | |||
1212 | return xhci_resume(xhci, 0); | ||
1213 | } | ||
1214 | #endif | ||
1215 | |||
1216 | static const struct dev_pm_ops tegra_xusb_pm_ops = { | ||
1217 | SET_SYSTEM_SLEEP_PM_OPS(tegra_xusb_suspend, tegra_xusb_resume) | ||
1218 | }; | ||
1219 | |||
1220 | static const char * const tegra124_supply_names[] = { | ||
1221 | "avddio-pex", | ||
1222 | "dvddio-pex", | ||
1223 | "avdd-usb", | ||
1224 | "avdd-pll-utmip", | ||
1225 | "avdd-pll-erefe", | ||
1226 | "avdd-usb-ss-pll", | ||
1227 | "hvdd-usb-ss", | ||
1228 | "hvdd-usb-ss-pll-e", | ||
1229 | }; | ||
1230 | |||
1231 | static const struct tegra_xusb_phy_type tegra124_phy_types[] = { | ||
1232 | { .name = "usb3", .num = 2, }, | ||
1233 | { .name = "usb2", .num = 3, }, | ||
1234 | { .name = "hsic", .num = 2, }, | ||
1235 | }; | ||
1236 | |||
1237 | static const struct tegra_xusb_soc tegra124_soc = { | ||
1238 | .firmware = "nvidia/tegra124/xusb.bin", | ||
1239 | .supply_names = tegra124_supply_names, | ||
1240 | .num_supplies = ARRAY_SIZE(tegra124_supply_names), | ||
1241 | .phy_types = tegra124_phy_types, | ||
1242 | .num_types = ARRAY_SIZE(tegra124_phy_types), | ||
1243 | .ports = { | ||
1244 | .usb2 = { .offset = 4, .count = 4, }, | ||
1245 | .hsic = { .offset = 6, .count = 2, }, | ||
1246 | .usb3 = { .offset = 0, .count = 2, }, | ||
1247 | }, | ||
1248 | .scale_ss_clock = true, | ||
1249 | }; | ||
1250 | MODULE_FIRMWARE("nvidia/tegra124/xusb.bin"); | ||
1251 | |||
1252 | static const char * const tegra210_supply_names[] = { | ||
1253 | "dvddio-pex", | ||
1254 | "hvddio-pex", | ||
1255 | "avdd-usb", | ||
1256 | "avdd-pll-utmip", | ||
1257 | "avdd-pll-uerefe", | ||
1258 | "dvdd-pex-pll", | ||
1259 | "hvdd-pex-pll-e", | ||
1260 | }; | ||
1261 | |||
1262 | static const struct tegra_xusb_phy_type tegra210_phy_types[] = { | ||
1263 | { .name = "usb3", .num = 4, }, | ||
1264 | { .name = "usb2", .num = 4, }, | ||
1265 | { .name = "hsic", .num = 1, }, | ||
1266 | }; | ||
1267 | |||
1268 | static const struct tegra_xusb_soc tegra210_soc = { | ||
1269 | .firmware = "nvidia/tegra210/xusb.bin", | ||
1270 | .supply_names = tegra210_supply_names, | ||
1271 | .num_supplies = ARRAY_SIZE(tegra210_supply_names), | ||
1272 | .phy_types = tegra210_phy_types, | ||
1273 | .num_types = ARRAY_SIZE(tegra210_phy_types), | ||
1274 | .ports = { | ||
1275 | .usb2 = { .offset = 4, .count = 4, }, | ||
1276 | .hsic = { .offset = 8, .count = 1, }, | ||
1277 | .usb3 = { .offset = 0, .count = 4, }, | ||
1278 | }, | ||
1279 | .scale_ss_clock = false, | ||
1280 | }; | ||
1281 | MODULE_FIRMWARE("nvidia/tegra210/xusb.bin"); | ||
1282 | |||
1283 | static const struct of_device_id tegra_xusb_of_match[] = { | ||
1284 | { .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc }, | ||
1285 | { .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc }, | ||
1286 | { }, | ||
1287 | }; | ||
1288 | MODULE_DEVICE_TABLE(of, tegra_xusb_of_match); | ||
1289 | |||
1290 | static struct platform_driver tegra_xusb_driver = { | ||
1291 | .probe = tegra_xusb_probe, | ||
1292 | .remove = tegra_xusb_remove, | ||
1293 | .driver = { | ||
1294 | .name = "tegra-xusb", | ||
1295 | .pm = &tegra_xusb_pm_ops, | ||
1296 | .of_match_table = tegra_xusb_of_match, | ||
1297 | }, | ||
1298 | }; | ||
1299 | |||
1300 | static void tegra_xhci_quirks(struct device *dev, struct xhci_hcd *xhci) | ||
1301 | { | ||
1302 | xhci->quirks |= XHCI_PLAT; | ||
1303 | } | ||
1304 | |||
1305 | static int tegra_xhci_setup(struct usb_hcd *hcd) | ||
1306 | { | ||
1307 | return xhci_gen_setup(hcd, tegra_xhci_quirks); | ||
1308 | } | ||
1309 | |||
1310 | static const struct xhci_driver_overrides tegra_xhci_overrides __initconst = { | ||
1311 | .extra_priv_size = sizeof(struct xhci_hcd), | ||
1312 | .reset = tegra_xhci_setup, | ||
1313 | }; | ||
1314 | |||
1315 | static int __init tegra_xusb_init(void) | ||
1316 | { | ||
1317 | xhci_init_driver(&tegra_xhci_hc_driver, &tegra_xhci_overrides); | ||
1318 | |||
1319 | return platform_driver_register(&tegra_xusb_driver); | ||
1320 | } | ||
1321 | module_init(tegra_xusb_init); | ||
1322 | |||
1323 | static void __exit tegra_xusb_exit(void) | ||
1324 | { | ||
1325 | platform_driver_unregister(&tegra_xusb_driver); | ||
1326 | } | ||
1327 | module_exit(tegra_xusb_exit); | ||
1328 | |||
1329 | MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); | ||
1330 | MODULE_DESCRIPTION("NVIDIA Tegra XUSB xHCI host-controller driver"); | ||
1331 | MODULE_LICENSE("GPL v2"); | ||