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 | |
| 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
...
99 files changed, 11511 insertions, 975 deletions
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt index 02c27004d4a8..a74b37b07e5c 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt | |||
| @@ -1,16 +1,20 @@ | |||
| 1 | NVIDIA Tegra Power Management Controller (PMC) | 1 | NVIDIA Tegra Power Management Controller (PMC) |
| 2 | 2 | ||
| 3 | == Power Management Controller Node == | ||
| 4 | |||
| 3 | The PMC block interacts with an external Power Management Unit. The PMC | 5 | The PMC block interacts with an external Power Management Unit. The PMC |
| 4 | mostly controls the entry and exit of the system from different sleep | 6 | mostly controls the entry and exit of the system from different sleep |
| 5 | modes. It provides power-gating controllers for SoC and CPU power-islands. | 7 | modes. It provides power-gating controllers for SoC and CPU power-islands. |
| 6 | 8 | ||
| 7 | Required properties: | 9 | Required properties: |
| 8 | - name : Should be pmc | 10 | - name : Should be pmc |
| 9 | - compatible : For Tegra20, must contain "nvidia,tegra20-pmc". For Tegra30, | 11 | - compatible : Should contain one of the following: |
| 10 | must contain "nvidia,tegra30-pmc". For Tegra114, must contain | 12 | For Tegra20 must contain "nvidia,tegra20-pmc". |
| 11 | "nvidia,tegra114-pmc". For Tegra124, must contain "nvidia,tegra124-pmc". | 13 | For Tegra30 must contain "nvidia,tegra30-pmc". |
| 12 | Otherwise, must contain "nvidia,<chip>-pmc", plus at least one of the | 14 | For Tegra114 must contain "nvidia,tegra114-pmc" |
| 13 | above, where <chip> is tegra132. | 15 | For Tegra124 must contain "nvidia,tegra124-pmc" |
| 16 | For Tegra132 must contain "nvidia,tegra124-pmc" | ||
| 17 | For Tegra210 must contain "nvidia,tegra210-pmc" | ||
| 14 | - reg : Offset and length of the register set for the device | 18 | - reg : Offset and length of the register set for the device |
| 15 | - clocks : Must contain an entry for each entry in clock-names. | 19 | - clocks : Must contain an entry for each entry in clock-names. |
| 16 | See ../clocks/clock-bindings.txt for details. | 20 | See ../clocks/clock-bindings.txt for details. |
| @@ -68,6 +72,11 @@ Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip' | |||
| 68 | Defaults to 0. Valid values are described in section 12.5.2 | 72 | Defaults to 0. Valid values are described in section 12.5.2 |
| 69 | "Pinmux Support" of the Tegra4 Technical Reference Manual. | 73 | "Pinmux Support" of the Tegra4 Technical Reference Manual. |
| 70 | 74 | ||
| 75 | Optional nodes: | ||
| 76 | - powergates : This node contains a hierarchy of power domain nodes, which | ||
| 77 | should match the powergates on the Tegra SoC. See "Powergate | ||
| 78 | Nodes" below. | ||
| 79 | |||
| 71 | Example: | 80 | Example: |
| 72 | 81 | ||
| 73 | / SoC dts including file | 82 | / SoC dts including file |
| @@ -113,3 +122,76 @@ pmc@7000f400 { | |||
| 113 | }; | 122 | }; |
| 114 | ... | 123 | ... |
| 115 | }; | 124 | }; |
| 125 | |||
| 126 | |||
| 127 | == Powergate Nodes == | ||
| 128 | |||
| 129 | Each of the powergate nodes represents a power-domain on the Tegra SoC | ||
| 130 | that can be power-gated by the Tegra PMC. The name of the powergate node | ||
| 131 | should be one of the below. Note that not every powergate is applicable | ||
| 132 | to all Tegra devices and the following list shows which powergates are | ||
| 133 | applicable to which devices. Please refer to the Tegra TRM for more | ||
| 134 | details on the various powergates. | ||
| 135 | |||
| 136 | Name Description Devices Applicable | ||
| 137 | 3d 3D Graphics Tegra20/114/124/210 | ||
| 138 | 3d0 3D Graphics 0 Tegra30 | ||
| 139 | 3d1 3D Graphics 1 Tegra30 | ||
| 140 | aud Audio Tegra210 | ||
| 141 | dfd Debug Tegra210 | ||
| 142 | dis Display A Tegra114/124/210 | ||
| 143 | disb Display B Tegra114/124/210 | ||
| 144 | heg 2D Graphics Tegra30/114/124/210 | ||
| 145 | iram Internal RAM Tegra124/210 | ||
| 146 | mpe MPEG Encode All | ||
| 147 | nvdec NVIDIA Video Decode Engine Tegra210 | ||
| 148 | nvjpg NVIDIA JPEG Engine Tegra210 | ||
| 149 | pcie PCIE Tegra20/30/124/210 | ||
| 150 | sata SATA Tegra30/124/210 | ||
| 151 | sor Display interfaces Tegra124/210 | ||
| 152 | ve2 Video Encode Engine 2 Tegra210 | ||
| 153 | venc Video Encode Engine All | ||
| 154 | vdec Video Decode Engine Tegra20/30/114/124 | ||
| 155 | vic Video Imaging Compositor Tegra124/210 | ||
| 156 | xusba USB Partition A Tegra114/124/210 | ||
| 157 | xusbb USB Partition B Tegra114/124/210 | ||
| 158 | xusbc USB Partition C Tegra114/124/210 | ||
| 159 | |||
| 160 | Required properties: | ||
| 161 | - clocks: Must contain an entry for each clock required by the PMC for | ||
| 162 | controlling a power-gate. See ../clocks/clock-bindings.txt for details. | ||
| 163 | - resets: Must contain an entry for each reset required by the PMC for | ||
| 164 | controlling a power-gate. See ../reset/reset.txt for details. | ||
| 165 | - #power-domain-cells: Must be 0. | ||
| 166 | |||
| 167 | Example: | ||
| 168 | |||
| 169 | pmc: pmc@7000e400 { | ||
| 170 | compatible = "nvidia,tegra210-pmc"; | ||
| 171 | reg = <0x0 0x7000e400 0x0 0x400>; | ||
| 172 | clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; | ||
| 173 | clock-names = "pclk", "clk32k_in"; | ||
| 174 | |||
| 175 | powergates { | ||
| 176 | pd_audio: aud { | ||
| 177 | clocks = <&tegra_car TEGRA210_CLK_APE>, | ||
| 178 | <&tegra_car TEGRA210_CLK_APB2APE>; | ||
| 179 | resets = <&tegra_car 198>; | ||
| 180 | #power-domain-cells = <0>; | ||
| 181 | }; | ||
| 182 | }; | ||
| 183 | }; | ||
| 184 | |||
| 185 | |||
| 186 | == Powergate Clients == | ||
| 187 | |||
| 188 | Hardware blocks belonging to a power domain should contain a "power-domains" | ||
| 189 | property that is a phandle pointing to the corresponding powergate node. | ||
| 190 | |||
| 191 | Example: | ||
| 192 | |||
| 193 | adma: adma@702e2000 { | ||
| 194 | ... | ||
| 195 | power-domains = <&pd_audio>; | ||
| 196 | ... | ||
| 197 | }; | ||
diff --git a/Documentation/devicetree/bindings/memory-controllers/exynos-srom.txt b/Documentation/devicetree/bindings/memory-controllers/exynos-srom.txt new file mode 100644 index 000000000000..f633b5d0f8ca --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/exynos-srom.txt | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | SAMSUNG Exynos SoCs SROM Controller driver. | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : Should contain "samsung,exynos4210-srom". | ||
| 5 | |||
| 6 | - reg: offset and length of the register set | ||
| 7 | |||
| 8 | Optional properties: | ||
| 9 | The SROM controller can be used to attach external peripherals. In this case | ||
| 10 | extra properties, describing the bus behind it, should be specified as below: | ||
| 11 | |||
| 12 | - #address-cells: Must be set to 2 to allow device address translation. | ||
| 13 | Address is specified as (bank#, offset). | ||
| 14 | |||
| 15 | - #size-cells: Must be set to 1 to allow device size passing | ||
| 16 | |||
| 17 | - ranges: Must be set up to reflect the memory layout with four integer values | ||
| 18 | per bank: | ||
| 19 | <bank-number> 0 <parent address of bank> <size> | ||
| 20 | |||
| 21 | Sub-nodes: | ||
| 22 | The actual device nodes should be added as subnodes to the SROMc node. These | ||
| 23 | subnodes, in addition to regular device specification, should contain the following | ||
| 24 | properties, describing configuration of the relevant SROM bank: | ||
| 25 | |||
| 26 | Required properties: | ||
| 27 | - reg: bank number, base address (relative to start of the bank) and size of | ||
| 28 | the memory mapped for the device. Note that base address will be | ||
| 29 | typically 0 as this is the start of the bank. | ||
| 30 | |||
| 31 | - samsung,srom-timing : array of 6 integers, specifying bank timings in the | ||
| 32 | following order: Tacp, Tcah, Tcoh, Tacc, Tcos, Tacs. | ||
| 33 | Each value is specified in cycles and has the following | ||
| 34 | meaning and valid range: | ||
| 35 | Tacp : Page mode access cycle at Page mode (0 - 15) | ||
| 36 | Tcah : Address holding time after CSn (0 - 15) | ||
| 37 | Tcoh : Chip selection hold on OEn (0 - 15) | ||
| 38 | Tacc : Access cycle (0 - 31, the actual time is N + 1) | ||
| 39 | Tcos : Chip selection set-up before OEn (0 - 15) | ||
| 40 | Tacs : Address set-up before CSn (0 - 15) | ||
| 41 | |||
| 42 | Optional properties: | ||
| 43 | - reg-io-width : data width in bytes (1 or 2). If omitted, default of 1 is used. | ||
| 44 | |||
| 45 | - samsung,srom-page-mode : if page mode is set, 4 data page mode will be configured, | ||
| 46 | else normal (1 data) page mode will be set. | ||
| 47 | |||
| 48 | Example: basic definition, no banks are configured | ||
| 49 | memory-controller@12570000 { | ||
| 50 | compatible = "samsung,exynos4210-srom"; | ||
| 51 | reg = <0x12570000 0x14>; | ||
| 52 | }; | ||
| 53 | |||
| 54 | Example: SROMc with SMSC911x ethernet chip on bank 3 | ||
| 55 | memory-controller@12570000 { | ||
| 56 | #address-cells = <2>; | ||
| 57 | #size-cells = <1>; | ||
| 58 | ranges = <0 0 0x04000000 0x20000 // Bank0 | ||
| 59 | 1 0 0x05000000 0x20000 // Bank1 | ||
| 60 | 2 0 0x06000000 0x20000 // Bank2 | ||
| 61 | 3 0 0x07000000 0x20000>; // Bank3 | ||
| 62 | |||
| 63 | compatible = "samsung,exynos4210-srom"; | ||
| 64 | reg = <0x12570000 0x14>; | ||
| 65 | |||
| 66 | ethernet@3,0 { | ||
| 67 | compatible = "smsc,lan9115"; | ||
| 68 | reg = <3 0 0x10000>; // Bank 3, offset = 0 | ||
| 69 | phy-mode = "mii"; | ||
| 70 | interrupt-parent = <&gpx0>; | ||
| 71 | interrupts = <5 8>; | ||
| 72 | reg-io-width = <2>; | ||
| 73 | smsc,irq-push-pull; | ||
| 74 | smsc,force-internal-phy; | ||
| 75 | |||
| 76 | samsung,srom-page-mode; | ||
| 77 | samsung,srom-timing = <9 12 1 9 1 1>; | ||
| 78 | }; | ||
| 79 | }; | ||
diff --git a/Documentation/devicetree/bindings/mtd/arm-versatile.txt b/Documentation/devicetree/bindings/mtd/arm-versatile.txt index beace4b89daa..4ec28796a3c0 100644 --- a/Documentation/devicetree/bindings/mtd/arm-versatile.txt +++ b/Documentation/devicetree/bindings/mtd/arm-versatile.txt | |||
| @@ -1,8 +1,26 @@ | |||
| 1 | Flash device on ARM Versatile board | 1 | Flash device on ARM Versatile board |
| 2 | 2 | ||
| 3 | These flash chips are found in the ARM reference designs like Integrator, | ||
| 4 | Versatile, RealView, Versatile Express etc. | ||
| 5 | |||
| 6 | They are regular CFI compatible (Intel or AMD extended) flash chips with | ||
| 7 | some special write protect/VPP bits that can be controlled by the machine's | ||
| 8 | system controller. | ||
| 9 | |||
| 3 | Required properties: | 10 | Required properties: |
| 4 | - compatible : must be "arm,versatile-flash"; | 11 | - compatible : must be "arm,versatile-flash", "cfi-flash"; |
| 12 | - reg : memory address for the flash chip | ||
| 5 | - bank-width : width in bytes of flash interface. | 13 | - bank-width : width in bytes of flash interface. |
| 6 | 14 | ||
| 15 | For the rest of the properties, see mtd-physmap.txt. | ||
| 16 | |||
| 7 | The device tree may optionally contain sub-nodes describing partitions of the | 17 | The device tree may optionally contain sub-nodes describing partitions of the |
| 8 | address space. See partition.txt for more detail. | 18 | address space. See partition.txt for more detail. |
| 19 | |||
| 20 | Example: | ||
| 21 | |||
| 22 | flash@34000000 { | ||
| 23 | compatible = "arm,versatile-flash", "cfi-flash"; | ||
| 24 | reg = <0x34000000 0x4000000>; | ||
| 25 | bank-width = <4>; | ||
| 26 | }; | ||
diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index 75321ae23c08..b8cc395fffea 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt | |||
| @@ -60,11 +60,14 @@ Required properties: | |||
| 60 | - afi | 60 | - afi |
| 61 | - pcie_x | 61 | - pcie_x |
| 62 | 62 | ||
| 63 | Required properties on Tegra124 and later: | 63 | Required properties on Tegra124 and later (deprecated): |
| 64 | - phys: Must contain an entry for each entry in phy-names. | 64 | - phys: Must contain an entry for each entry in phy-names. |
| 65 | - phy-names: Must include the following entries: | 65 | - phy-names: Must include the following entries: |
| 66 | - pcie | 66 | - pcie |
| 67 | 67 | ||
| 68 | These properties are deprecated in favour of per-lane PHYs define in each of | ||
| 69 | the root ports (see below). | ||
| 70 | |||
| 68 | Power supplies for Tegra20: | 71 | Power supplies for Tegra20: |
| 69 | - avdd-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V. | 72 | - avdd-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V. |
| 70 | - vdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. | 73 | - vdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. |
| @@ -122,11 +125,22 @@ Required properties: | |||
| 122 | - Root port 0 uses 4 lanes, root port 1 is unused. | 125 | - Root port 0 uses 4 lanes, root port 1 is unused. |
| 123 | - Both root ports use 2 lanes. | 126 | - Both root ports use 2 lanes. |
| 124 | 127 | ||
| 125 | Example: | 128 | Required properties for Tegra124 and later: |
| 129 | - phys: Must contain an phandle to a PHY for each entry in phy-names. | ||
| 130 | - phy-names: Must include an entry for each active lane. Note that the number | ||
| 131 | of entries does not have to (though usually will) be equal to the specified | ||
| 132 | number of lanes in the nvidia,num-lanes property. Entries are of the form | ||
| 133 | "pcie-N": where N ranges from 0 to the value specified in nvidia,num-lanes. | ||
| 134 | |||
| 135 | Examples: | ||
| 136 | ========= | ||
| 137 | |||
| 138 | Tegra20: | ||
| 139 | -------- | ||
| 126 | 140 | ||
| 127 | SoC DTSI: | 141 | SoC DTSI: |
| 128 | 142 | ||
| 129 | pcie-controller { | 143 | pcie-controller@80003000 { |
| 130 | compatible = "nvidia,tegra20-pcie"; | 144 | compatible = "nvidia,tegra20-pcie"; |
| 131 | device_type = "pci"; | 145 | device_type = "pci"; |
| 132 | reg = <0x80003000 0x00000800 /* PADS registers */ | 146 | reg = <0x80003000 0x00000800 /* PADS registers */ |
| @@ -186,10 +200,9 @@ SoC DTSI: | |||
| 186 | }; | 200 | }; |
| 187 | }; | 201 | }; |
| 188 | 202 | ||
| 189 | |||
| 190 | Board DTS: | 203 | Board DTS: |
| 191 | 204 | ||
| 192 | pcie-controller { | 205 | pcie-controller@80003000 { |
| 193 | status = "okay"; | 206 | status = "okay"; |
| 194 | 207 | ||
| 195 | vdd-supply = <&pci_vdd_reg>; | 208 | vdd-supply = <&pci_vdd_reg>; |
| @@ -222,3 +235,204 @@ if a device on the PCI bus provides a non-probeable bus such as I2C or SPI, | |||
| 222 | device nodes need to be added in order to allow the bus' children to be | 235 | device nodes need to be added in order to allow the bus' children to be |
| 223 | instantiated at the proper location in the operating system's device tree (as | 236 | instantiated at the proper location in the operating system's device tree (as |
| 224 | illustrated by the optional nodes in the example above). | 237 | illustrated by the optional nodes in the example above). |
| 238 | |||
| 239 | Tegra30: | ||
| 240 | -------- | ||
| 241 | |||
| 242 | SoC DTSI: | ||
| 243 | |||
| 244 | pcie-controller@00003000 { | ||
| 245 | compatible = "nvidia,tegra30-pcie"; | ||
| 246 | device_type = "pci"; | ||
| 247 | reg = <0x00003000 0x00000800 /* PADS registers */ | ||
| 248 | 0x00003800 0x00000200 /* AFI registers */ | ||
| 249 | 0x10000000 0x10000000>; /* configuration space */ | ||
| 250 | reg-names = "pads", "afi", "cs"; | ||
| 251 | interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH /* controller interrupt */ | ||
| 252 | GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */ | ||
| 253 | interrupt-names = "intr", "msi"; | ||
| 254 | |||
| 255 | #interrupt-cells = <1>; | ||
| 256 | interrupt-map-mask = <0 0 0 0>; | ||
| 257 | interrupt-map = <0 0 0 0 &intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; | ||
| 258 | |||
| 259 | bus-range = <0x00 0xff>; | ||
| 260 | #address-cells = <3>; | ||
| 261 | #size-cells = <2>; | ||
| 262 | |||
| 263 | ranges = <0x82000000 0 0x00000000 0x00000000 0 0x00001000 /* port 0 configuration space */ | ||
| 264 | 0x82000000 0 0x00001000 0x00001000 0 0x00001000 /* port 1 configuration space */ | ||
| 265 | 0x82000000 0 0x00004000 0x00004000 0 0x00001000 /* port 2 configuration space */ | ||
| 266 | 0x81000000 0 0 0x02000000 0 0x00010000 /* downstream I/O */ | ||
| 267 | 0x82000000 0 0x20000000 0x20000000 0 0x08000000 /* non-prefetchable memory */ | ||
| 268 | 0xc2000000 0 0x28000000 0x28000000 0 0x18000000>; /* prefetchable memory */ | ||
| 269 | |||
| 270 | clocks = <&tegra_car TEGRA30_CLK_PCIE>, | ||
| 271 | <&tegra_car TEGRA30_CLK_AFI>, | ||
| 272 | <&tegra_car TEGRA30_CLK_PLL_E>, | ||
| 273 | <&tegra_car TEGRA30_CLK_CML0>; | ||
| 274 | clock-names = "pex", "afi", "pll_e", "cml"; | ||
| 275 | resets = <&tegra_car 70>, | ||
| 276 | <&tegra_car 72>, | ||
| 277 | <&tegra_car 74>; | ||
| 278 | reset-names = "pex", "afi", "pcie_x"; | ||
| 279 | status = "disabled"; | ||
| 280 | |||
| 281 | pci@1,0 { | ||
| 282 | device_type = "pci"; | ||
| 283 | assigned-addresses = <0x82000800 0 0x00000000 0 0x1000>; | ||
| 284 | reg = <0x000800 0 0 0 0>; | ||
| 285 | status = "disabled"; | ||
| 286 | |||
| 287 | #address-cells = <3>; | ||
| 288 | #size-cells = <2>; | ||
| 289 | ranges; | ||
| 290 | |||
| 291 | nvidia,num-lanes = <2>; | ||
| 292 | }; | ||
| 293 | |||
| 294 | pci@2,0 { | ||
| 295 | device_type = "pci"; | ||
| 296 | assigned-addresses = <0x82001000 0 0x00001000 0 0x1000>; | ||
| 297 | reg = <0x001000 0 0 0 0>; | ||
| 298 | status = "disabled"; | ||
| 299 | |||
| 300 | #address-cells = <3>; | ||
| 301 | #size-cells = <2>; | ||
| 302 | ranges; | ||
| 303 | |||
| 304 | nvidia,num-lanes = <2>; | ||
| 305 | }; | ||
| 306 | |||
| 307 | pci@3,0 { | ||
| 308 | device_type = "pci"; | ||
| 309 | assigned-addresses = <0x82001800 0 0x00004000 0 0x1000>; | ||
| 310 | reg = <0x001800 0 0 0 0>; | ||
| 311 | status = "disabled"; | ||
| 312 | |||
| 313 | #address-cells = <3>; | ||
| 314 | #size-cells = <2>; | ||
| 315 | ranges; | ||
| 316 | |||
| 317 | nvidia,num-lanes = <2>; | ||
| 318 | }; | ||
| 319 | }; | ||
| 320 | |||
| 321 | Board DTS: | ||
| 322 | |||
| 323 | pcie-controller@00003000 { | ||
| 324 | status = "okay"; | ||
| 325 | |||
| 326 | avdd-pexa-supply = <&ldo1_reg>; | ||
| 327 | vdd-pexa-supply = <&ldo1_reg>; | ||
| 328 | avdd-pexb-supply = <&ldo1_reg>; | ||
| 329 | vdd-pexb-supply = <&ldo1_reg>; | ||
| 330 | avdd-pex-pll-supply = <&ldo1_reg>; | ||
| 331 | avdd-plle-supply = <&ldo1_reg>; | ||
| 332 | vddio-pex-ctl-supply = <&sys_3v3_reg>; | ||
| 333 | hvdd-pex-supply = <&sys_3v3_pexs_reg>; | ||
| 334 | |||
| 335 | pci@1,0 { | ||
| 336 | status = "okay"; | ||
| 337 | }; | ||
| 338 | |||
| 339 | pci@3,0 { | ||
| 340 | status = "okay"; | ||
| 341 | }; | ||
| 342 | }; | ||
| 343 | |||
| 344 | Tegra124: | ||
| 345 | --------- | ||
| 346 | |||
| 347 | SoC DTSI: | ||
| 348 | |||
| 349 | pcie-controller@01003000 { | ||
| 350 | compatible = "nvidia,tegra124-pcie"; | ||
| 351 | device_type = "pci"; | ||
| 352 | reg = <0x0 0x01003000 0x0 0x00000800 /* PADS registers */ | ||
| 353 | 0x0 0x01003800 0x0 0x00000800 /* AFI registers */ | ||
| 354 | 0x0 0x02000000 0x0 0x10000000>; /* configuration space */ | ||
| 355 | reg-names = "pads", "afi", "cs"; | ||
| 356 | interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */ | ||
| 357 | <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */ | ||
| 358 | interrupt-names = "intr", "msi"; | ||
| 359 | |||
| 360 | #interrupt-cells = <1>; | ||
| 361 | interrupt-map-mask = <0 0 0 0>; | ||
| 362 | interrupt-map = <0 0 0 0 &gic GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; | ||
| 363 | |||
| 364 | bus-range = <0x00 0xff>; | ||
| 365 | #address-cells = <3>; | ||
| 366 | #size-cells = <2>; | ||
| 367 | |||
| 368 | ranges = <0x82000000 0 0x01000000 0x0 0x01000000 0 0x00001000 /* port 0 configuration space */ | ||
| 369 | 0x82000000 0 0x01001000 0x0 0x01001000 0 0x00001000 /* port 1 configuration space */ | ||
| 370 | 0x81000000 0 0x0 0x0 0x12000000 0 0x00010000 /* downstream I/O (64 KiB) */ | ||
| 371 | 0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000 /* non-prefetchable memory (208 MiB) */ | ||
| 372 | 0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */ | ||
| 373 | |||
| 374 | clocks = <&tegra_car TEGRA124_CLK_PCIE>, | ||
| 375 | <&tegra_car TEGRA124_CLK_AFI>, | ||
| 376 | <&tegra_car TEGRA124_CLK_PLL_E>, | ||
| 377 | <&tegra_car TEGRA124_CLK_CML0>; | ||
| 378 | clock-names = "pex", "afi", "pll_e", "cml"; | ||
| 379 | resets = <&tegra_car 70>, | ||
| 380 | <&tegra_car 72>, | ||
| 381 | <&tegra_car 74>; | ||
| 382 | reset-names = "pex", "afi", "pcie_x"; | ||
| 383 | status = "disabled"; | ||
| 384 | |||
| 385 | pci@1,0 { | ||
| 386 | device_type = "pci"; | ||
| 387 | assigned-addresses = <0x82000800 0 0x01000000 0 0x1000>; | ||
| 388 | reg = <0x000800 0 0 0 0>; | ||
| 389 | status = "disabled"; | ||
| 390 | |||
| 391 | #address-cells = <3>; | ||
| 392 | #size-cells = <2>; | ||
| 393 | ranges; | ||
| 394 | |||
| 395 | nvidia,num-lanes = <2>; | ||
| 396 | }; | ||
| 397 | |||
| 398 | pci@2,0 { | ||
| 399 | device_type = "pci"; | ||
| 400 | assigned-addresses = <0x82001000 0 0x01001000 0 0x1000>; | ||
| 401 | reg = <0x001000 0 0 0 0>; | ||
| 402 | status = "disabled"; | ||
| 403 | |||
| 404 | #address-cells = <3>; | ||
| 405 | #size-cells = <2>; | ||
| 406 | ranges; | ||
| 407 | |||
| 408 | nvidia,num-lanes = <1>; | ||
| 409 | }; | ||
| 410 | }; | ||
| 411 | |||
| 412 | Board DTS: | ||
| 413 | |||
| 414 | pcie-controller@01003000 { | ||
| 415 | status = "okay"; | ||
| 416 | |||
| 417 | avddio-pex-supply = <&vdd_1v05_run>; | ||
| 418 | dvddio-pex-supply = <&vdd_1v05_run>; | ||
| 419 | avdd-pex-pll-supply = <&vdd_1v05_run>; | ||
| 420 | hvdd-pex-supply = <&vdd_3v3_lp0>; | ||
| 421 | hvdd-pex-pll-e-supply = <&vdd_3v3_lp0>; | ||
| 422 | vddio-pex-ctl-supply = <&vdd_3v3_lp0>; | ||
| 423 | avdd-pll-erefe-supply = <&avdd_1v05_run>; | ||
| 424 | |||
| 425 | /* Mini PCIe */ | ||
| 426 | pci@1,0 { | ||
| 427 | phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-4}>; | ||
| 428 | phy-names = "pcie-0"; | ||
| 429 | status = "okay"; | ||
| 430 | }; | ||
| 431 | |||
| 432 | /* Gigabit Ethernet */ | ||
| 433 | pci@2,0 { | ||
| 434 | phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>; | ||
| 435 | phy-names = "pcie-0"; | ||
| 436 | status = "okay"; | ||
| 437 | }; | ||
| 438 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt new file mode 100644 index 000000000000..0bf1ae243552 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt | |||
| @@ -0,0 +1,733 @@ | |||
| 1 | Device tree binding for NVIDIA Tegra XUSB pad controller | ||
| 2 | ======================================================== | ||
| 3 | |||
| 4 | The Tegra XUSB pad controller manages a set of I/O lanes (with differential | ||
| 5 | signals) which connect directly to pins/pads on the SoC package. Each lane | ||
| 6 | is controlled by a HW block referred to as a "pad" in the Tegra hardware | ||
| 7 | documentation. Each such "pad" may control either one or multiple lanes, | ||
| 8 | and thus contains any logic common to all its lanes. Each lane can be | ||
| 9 | separately configured and powered up. | ||
| 10 | |||
| 11 | Some of the lanes are high-speed lanes, which can be used for PCIe, SATA or | ||
| 12 | super-speed USB. Other lanes are for various types of low-speed, full-speed | ||
| 13 | or high-speed USB (such as UTMI, ULPI and HSIC). The XUSB pad controller | ||
| 14 | contains a software-configurable mux that sits between the I/O controller | ||
| 15 | ports (e.g. PCIe) and the lanes. | ||
| 16 | |||
| 17 | In addition to per-lane configuration, USB 3.0 ports may require additional | ||
| 18 | settings on a per-board basis. | ||
| 19 | |||
| 20 | Pads will be represented as children of the top-level XUSB pad controller | ||
| 21 | device tree node. Each lane exposed by the pad will be represented by its | ||
| 22 | own subnode and can be referenced by users of the lane using the standard | ||
| 23 | PHY bindings, as described by the phy-bindings.txt file in this directory. | ||
| 24 | |||
| 25 | The Tegra hardware documentation refers to the connection between the XUSB | ||
| 26 | pad controller and the XUSB controller as "ports". This is confusing since | ||
| 27 | "port" is typically used to denote the physical USB receptacle. The device | ||
| 28 | tree binding in this document uses the term "port" to refer to the logical | ||
| 29 | abstraction of the signals that are routed to a USB receptacle (i.e. a PHY | ||
| 30 | for the USB signal, the VBUS power supply, the USB 2.0 companion port for | ||
| 31 | USB 3.0 receptacles, ...). | ||
| 32 | |||
| 33 | Required properties: | ||
| 34 | -------------------- | ||
| 35 | - compatible: Must be: | ||
| 36 | - Tegra124: "nvidia,tegra124-xusb-padctl" | ||
| 37 | - Tegra132: "nvidia,tegra132-xusb-padctl", "nvidia,tegra124-xusb-padctl" | ||
| 38 | - Tegra210: "nvidia,tegra210-xusb-padctl" | ||
| 39 | - reg: Physical base address and length of the controller's registers. | ||
| 40 | - resets: Must contain an entry for each entry in reset-names. | ||
| 41 | - reset-names: Must include the following entries: | ||
| 42 | - "padctl" | ||
| 43 | |||
| 44 | |||
| 45 | Pad nodes: | ||
| 46 | ========== | ||
| 47 | |||
| 48 | A required child node named "pads" contains a list of subnodes, one for each | ||
| 49 | of the pads exposed by the XUSB pad controller. Each pad may need additional | ||
| 50 | resources that can be referenced in its pad node. | ||
| 51 | |||
| 52 | The "status" property is used to enable or disable the use of a pad. If set | ||
| 53 | to "disabled", the pad will not be used on the given board. In order to use | ||
| 54 | the pad and any of its lanes, this property must be set to "okay". | ||
| 55 | |||
| 56 | For Tegra124 and Tegra132, the following pads exist: usb2, ulpi, hsic, pcie | ||
| 57 | and sata. No extra resources are required for operation of these pads. | ||
| 58 | |||
| 59 | For Tegra210, the following pads exist: usb2, hsic, pcie and sata. Below is | ||
| 60 | a description of the properties of each pad. | ||
| 61 | |||
| 62 | UTMI pad: | ||
| 63 | --------- | ||
| 64 | |||
| 65 | Required properties: | ||
| 66 | - clocks: Must contain an entry for each entry in clock-names. | ||
| 67 | - clock-names: Must contain the following entries: | ||
| 68 | - "trk": phandle and specifier referring to the USB2 tracking clock | ||
| 69 | |||
| 70 | HSIC pad: | ||
| 71 | --------- | ||
| 72 | |||
| 73 | Required properties: | ||
| 74 | - clocks: Must contain an entry for each entry in clock-names. | ||
| 75 | - clock-names: Must contain the following entries: | ||
| 76 | - "trk": phandle and specifier referring to the HSIC tracking clock | ||
| 77 | |||
| 78 | PCIe pad: | ||
| 79 | --------- | ||
| 80 | |||
| 81 | Required properties: | ||
| 82 | - clocks: Must contain an entry for each entry in clock-names. | ||
| 83 | - clock-names: Must contain the following entries: | ||
| 84 | - "pll": phandle and specifier referring to the PLLE | ||
| 85 | - resets: Must contain an entry for each entry in reset-names. | ||
| 86 | - reset-names: Must contain the following entries: | ||
| 87 | - "phy": reset for the PCIe UPHY block | ||
| 88 | |||
| 89 | SATA pad: | ||
| 90 | --------- | ||
| 91 | |||
| 92 | Required properties: | ||
| 93 | - resets: Must contain an entry for each entry in reset-names. | ||
| 94 | - reset-names: Must contain the following entries: | ||
| 95 | - "phy": reset for the SATA UPHY block | ||
| 96 | |||
| 97 | |||
| 98 | PHY nodes: | ||
| 99 | ========== | ||
| 100 | |||
| 101 | Each pad node has a child named "lanes" that contains one or more children of | ||
| 102 | its own, each representing one of the lanes controlled by the pad. | ||
| 103 | |||
| 104 | Required properties: | ||
| 105 | -------------------- | ||
| 106 | - status: Defines the operation status of the PHY. Valid values are: | ||
| 107 | - "disabled": the PHY is disabled | ||
| 108 | - "okay": the PHY is enabled | ||
| 109 | - #phy-cells: Should be 0. Since each lane represents a single PHY, there is | ||
| 110 | no need for an additional specifier. | ||
| 111 | - nvidia,function: The output function of the PHY. See below for a list of | ||
| 112 | valid functions per SoC generation. | ||
| 113 | |||
| 114 | For Tegra124 and Tegra132, the list of valid PHY nodes is given below: | ||
| 115 | - usb2: usb2-0, usb2-1, usb2-2 | ||
| 116 | - functions: "snps", "xusb", "uart" | ||
| 117 | - ulpi: ulpi-0 | ||
| 118 | - functions: "snps", "xusb" | ||
| 119 | - hsic: hsic-0, hsic-1 | ||
| 120 | - functions: "snps", "xusb" | ||
| 121 | - pcie: pcie-0, pcie-1, pcie-2, pcie-3, pcie-4 | ||
| 122 | - functions: "pcie", "usb3-ss" | ||
| 123 | - sata: sata-0 | ||
| 124 | - functions: "usb3-ss", "sata" | ||
| 125 | |||
| 126 | For Tegra210, the list of valid PHY nodes is given below: | ||
| 127 | - utmi: utmi-0, utmi-1, utmi-2, utmi-3 | ||
| 128 | - functions: "snps", "xusb", "uart" | ||
| 129 | - hsic: hsic-0, hsic-1 | ||
| 130 | - functions: "snps", "xusb" | ||
| 131 | - pcie: pcie-0, pcie-1, pcie-2, pcie-3, pcie-4, pcie-5, pcie-6 | ||
| 132 | - functions: "pcie-x1", "usb3-ss", "pcie-x4" | ||
| 133 | - sata: sata-0 | ||
| 134 | - functions: "usb3-ss", "sata" | ||
| 135 | |||
| 136 | |||
| 137 | Port nodes: | ||
| 138 | =========== | ||
| 139 | |||
| 140 | A required child node named "ports" contains a list of all the ports exposed | ||
| 141 | by the XUSB pad controller. Per-port configuration is only required for USB. | ||
| 142 | |||
| 143 | USB2 ports: | ||
| 144 | ----------- | ||
| 145 | |||
| 146 | Required properties: | ||
| 147 | - status: Defines the operation status of the port. Valid values are: | ||
| 148 | - "disabled": the port is disabled | ||
| 149 | - "okay": the port is enabled | ||
| 150 | - mode: A string that determines the mode in which to run the port. Valid | ||
| 151 | values are: | ||
| 152 | - "host": for USB host mode | ||
| 153 | - "device": for USB device mode | ||
| 154 | - "otg": for USB OTG mode | ||
| 155 | |||
| 156 | Optional properties: | ||
| 157 | - nvidia,internal: A boolean property whose presence determines that a port | ||
| 158 | is internal. In the absence of this property the port is considered to be | ||
| 159 | external. | ||
| 160 | - vbus-supply: phandle to a regulator supplying the VBUS voltage. | ||
| 161 | |||
| 162 | ULPI ports: | ||
| 163 | ----------- | ||
| 164 | |||
| 165 | Optional properties: | ||
| 166 | - status: Defines the operation status of the port. Valid values are: | ||
| 167 | - "disabled": the port is disabled | ||
| 168 | - "okay": the port is enabled | ||
| 169 | - nvidia,internal: A boolean property whose presence determines that a port | ||
| 170 | is internal. In the absence of this property the port is considered to be | ||
| 171 | external. | ||
| 172 | - vbus-supply: phandle to a regulator supplying the VBUS voltage. | ||
| 173 | |||
| 174 | HSIC ports: | ||
| 175 | ----------- | ||
| 176 | |||
| 177 | Required properties: | ||
| 178 | - status: Defines the operation status of the port. Valid values are: | ||
| 179 | - "disabled": the port is disabled | ||
| 180 | - "okay": the port is enabled | ||
| 181 | |||
| 182 | Optional properties: | ||
| 183 | - vbus-supply: phandle to a regulator supplying the VBUS voltage. | ||
| 184 | |||
| 185 | Super-speed USB ports: | ||
| 186 | ---------------------- | ||
| 187 | |||
| 188 | Required properties: | ||
| 189 | - status: Defines the operation status of the port. Valid values are: | ||
| 190 | - "disabled": the port is disabled | ||
| 191 | - "okay": the port is enabled | ||
| 192 | - nvidia,usb2-companion: A single cell that specifies the physical port number | ||
| 193 | to map this super-speed USB port to. The range of valid port numbers varies | ||
| 194 | with the SoC generation: | ||
| 195 | - 0-2: for Tegra124 and Tegra132 | ||
| 196 | - 0-3: for Tegra210 | ||
| 197 | |||
| 198 | Optional properties: | ||
| 199 | - nvidia,internal: A boolean property whose presence determines that a port | ||
| 200 | is internal. In the absence of this property the port is considered to be | ||
| 201 | external. | ||
| 202 | |||
| 203 | For Tegra124 and Tegra132, the XUSB pad controller exposes the following | ||
| 204 | ports: | ||
| 205 | - 3x USB2: usb2-0, usb2-1, usb2-2 | ||
| 206 | - 1x ULPI: ulpi-0 | ||
| 207 | - 2x HSIC: hsic-0, hsic-1 | ||
| 208 | - 2x super-speed USB: usb3-0, usb3-1 | ||
| 209 | |||
| 210 | For Tegra210, the XUSB pad controller exposes the following ports: | ||
| 211 | - 4x USB2: usb2-0, usb2-1, usb2-2, usb2-3 | ||
| 212 | - 2x HSIC: hsic-0, hsic-1 | ||
| 213 | - 4x super-speed USB: usb3-0, usb3-1, usb3-2, usb3-3 | ||
| 214 | |||
| 215 | |||
| 216 | Examples: | ||
| 217 | ========= | ||
| 218 | |||
| 219 | Tegra124 and Tegra132: | ||
| 220 | ---------------------- | ||
| 221 | |||
| 222 | SoC include: | ||
| 223 | |||
| 224 | padctl@7009f000 { | ||
| 225 | /* for Tegra124 */ | ||
| 226 | compatible = "nvidia,tegra124-xusb-padctl"; | ||
| 227 | /* for Tegra132 */ | ||
| 228 | compatible = "nvidia,tegra132-xusb-padctl", | ||
| 229 | "nvidia,tegra124-xusb-padctl"; | ||
| 230 | reg = <0x0 0x7009f000 0x0 0x1000>; | ||
| 231 | resets = <&tegra_car 142>; | ||
| 232 | reset-names = "padctl"; | ||
| 233 | |||
| 234 | pads { | ||
| 235 | usb2 { | ||
| 236 | status = "disabled"; | ||
| 237 | |||
| 238 | lanes { | ||
| 239 | usb2-0 { | ||
| 240 | status = "disabled"; | ||
| 241 | #phy-cells = <0>; | ||
| 242 | }; | ||
| 243 | |||
| 244 | usb2-1 { | ||
| 245 | status = "disabled"; | ||
| 246 | #phy-cells = <0>; | ||
| 247 | }; | ||
| 248 | |||
| 249 | usb2-2 { | ||
| 250 | status = "disabled"; | ||
| 251 | #phy-cells = <0>; | ||
| 252 | }; | ||
| 253 | }; | ||
| 254 | }; | ||
| 255 | |||
| 256 | ulpi { | ||
| 257 | status = "disabled"; | ||
| 258 | |||
| 259 | lanes { | ||
| 260 | ulpi-0 { | ||
| 261 | status = "disabled"; | ||
| 262 | #phy-cells = <0>; | ||
| 263 | }; | ||
| 264 | }; | ||
| 265 | }; | ||
| 266 | |||
| 267 | hsic { | ||
| 268 | status = "disabled"; | ||
| 269 | |||
| 270 | lanes { | ||
| 271 | hsic-0 { | ||
| 272 | status = "disabled"; | ||
| 273 | #phy-cells = <0>; | ||
| 274 | }; | ||
| 275 | |||
| 276 | hsic-1 { | ||
| 277 | status = "disabled"; | ||
| 278 | #phy-cells = <0>; | ||
| 279 | }; | ||
| 280 | }; | ||
| 281 | }; | ||
| 282 | |||
| 283 | pcie { | ||
| 284 | status = "disabled"; | ||
| 285 | |||
| 286 | lanes { | ||
| 287 | pcie-0 { | ||
| 288 | status = "disabled"; | ||
| 289 | #phy-cells = <0>; | ||
| 290 | }; | ||
| 291 | |||
| 292 | pcie-1 { | ||
| 293 | status = "disabled"; | ||
| 294 | #phy-cells = <0>; | ||
| 295 | }; | ||
| 296 | |||
| 297 | pcie-2 { | ||
| 298 | status = "disabled"; | ||
| 299 | #phy-cells = <0>; | ||
| 300 | }; | ||
| 301 | |||
| 302 | pcie-3 { | ||
| 303 | status = "disabled"; | ||
| 304 | #phy-cells = <0>; | ||
| 305 | }; | ||
| 306 | |||
| 307 | pcie-4 { | ||
| 308 | status = "disabled"; | ||
| 309 | #phy-cells = <0>; | ||
| 310 | }; | ||
| 311 | }; | ||
| 312 | }; | ||
| 313 | |||
| 314 | sata { | ||
| 315 | status = "disabled"; | ||
| 316 | |||
| 317 | lanes { | ||
| 318 | sata-0 { | ||
| 319 | status = "disabled"; | ||
| 320 | #phy-cells = <0>; | ||
| 321 | }; | ||
| 322 | }; | ||
| 323 | }; | ||
| 324 | }; | ||
| 325 | |||
| 326 | ports { | ||
| 327 | usb2-0 { | ||
| 328 | status = "disabled"; | ||
| 329 | }; | ||
| 330 | |||
| 331 | usb2-1 { | ||
| 332 | status = "disabled"; | ||
| 333 | }; | ||
| 334 | |||
| 335 | usb2-2 { | ||
| 336 | status = "disabled"; | ||
| 337 | }; | ||
| 338 | |||
| 339 | ulpi-0 { | ||
| 340 | status = "disabled"; | ||
| 341 | }; | ||
| 342 | |||
| 343 | hsic-0 { | ||
| 344 | status = "disabled"; | ||
| 345 | }; | ||
| 346 | |||
| 347 | hsic-1 { | ||
| 348 | status = "disabled"; | ||
| 349 | }; | ||
| 350 | |||
| 351 | usb3-0 { | ||
| 352 | status = "disabled"; | ||
| 353 | }; | ||
| 354 | |||
| 355 | usb3-1 { | ||
| 356 | status = "disabled"; | ||
| 357 | }; | ||
| 358 | }; | ||
| 359 | }; | ||
| 360 | |||
| 361 | Board file: | ||
| 362 | |||
| 363 | padctl@7009f000 { | ||
| 364 | status = "okay"; | ||
| 365 | |||
| 366 | pads { | ||
| 367 | usb2 { | ||
| 368 | status = "okay"; | ||
| 369 | |||
| 370 | lanes { | ||
| 371 | usb2-0 { | ||
| 372 | nvidia,function = "xusb"; | ||
| 373 | status = "okay"; | ||
| 374 | }; | ||
| 375 | |||
| 376 | usb2-1 { | ||
| 377 | nvidia,function = "xusb"; | ||
| 378 | status = "okay"; | ||
| 379 | }; | ||
| 380 | |||
| 381 | usb2-2 { | ||
| 382 | nvidia,function = "xusb"; | ||
| 383 | status = "okay"; | ||
| 384 | }; | ||
| 385 | }; | ||
| 386 | }; | ||
| 387 | |||
| 388 | pcie { | ||
| 389 | status = "okay"; | ||
| 390 | |||
| 391 | lanes { | ||
| 392 | pcie-0 { | ||
| 393 | nvidia,function = "usb3-ss"; | ||
| 394 | status = "okay"; | ||
| 395 | }; | ||
| 396 | |||
| 397 | pcie-2 { | ||
| 398 | nvidia,function = "pcie"; | ||
| 399 | status = "okay"; | ||
| 400 | }; | ||
| 401 | |||
| 402 | pcie-4 { | ||
| 403 | nvidia,function = "pcie"; | ||
| 404 | status = "okay"; | ||
| 405 | }; | ||
| 406 | }; | ||
| 407 | }; | ||
| 408 | |||
| 409 | sata { | ||
| 410 | status = "okay"; | ||
| 411 | |||
| 412 | lanes { | ||
| 413 | sata-0 { | ||
| 414 | nvidia,function = "sata"; | ||
| 415 | status = "okay"; | ||
| 416 | }; | ||
| 417 | }; | ||
| 418 | }; | ||
| 419 | }; | ||
| 420 | |||
| 421 | ports { | ||
| 422 | /* Micro A/B */ | ||
| 423 | usb2-0 { | ||
| 424 | status = "okay"; | ||
| 425 | mode = "otg"; | ||
| 426 | }; | ||
| 427 | |||
| 428 | /* Mini PCIe */ | ||
| 429 | usb2-1 { | ||
| 430 | status = "okay"; | ||
| 431 | mode = "host"; | ||
| 432 | }; | ||
| 433 | |||
| 434 | /* USB3 */ | ||
| 435 | usb2-2 { | ||
| 436 | status = "okay"; | ||
| 437 | mode = "host"; | ||
| 438 | |||
| 439 | vbus-supply = <&vdd_usb3_vbus>; | ||
| 440 | }; | ||
| 441 | |||
| 442 | usb3-0 { | ||
| 443 | nvidia,port = <2>; | ||
| 444 | status = "okay"; | ||
| 445 | }; | ||
| 446 | }; | ||
| 447 | }; | ||
| 448 | |||
| 449 | Tegra210: | ||
| 450 | --------- | ||
| 451 | |||
| 452 | SoC include: | ||
| 453 | |||
| 454 | padctl@7009f000 { | ||
| 455 | compatible = "nvidia,tegra210-xusb-padctl"; | ||
| 456 | reg = <0x0 0x7009f000 0x0 0x1000>; | ||
| 457 | resets = <&tegra_car 142>; | ||
| 458 | reset-names = "padctl"; | ||
| 459 | |||
| 460 | status = "disabled"; | ||
| 461 | |||
| 462 | pads { | ||
| 463 | usb2 { | ||
| 464 | clocks = <&tegra_car TEGRA210_CLK_USB2_TRK>; | ||
| 465 | clock-names = "trk"; | ||
| 466 | status = "disabled"; | ||
| 467 | |||
| 468 | lanes { | ||
| 469 | usb2-0 { | ||
| 470 | status = "disabled"; | ||
| 471 | #phy-cells = <0>; | ||
| 472 | }; | ||
| 473 | |||
| 474 | usb2-1 { | ||
| 475 | status = "disabled"; | ||
| 476 | #phy-cells = <0>; | ||
| 477 | }; | ||
| 478 | |||
| 479 | usb2-2 { | ||
| 480 | status = "disabled"; | ||
| 481 | #phy-cells = <0>; | ||
| 482 | }; | ||
| 483 | |||
| 484 | usb2-3 { | ||
| 485 | status = "disabled"; | ||
| 486 | #phy-cells = <0>; | ||
| 487 | }; | ||
| 488 | }; | ||
| 489 | }; | ||
| 490 | |||
| 491 | hsic { | ||
| 492 | clocks = <&tegra_car TEGRA210_CLK_HSIC_TRK>; | ||
| 493 | clock-names = "trk"; | ||
| 494 | status = "disabled"; | ||
| 495 | |||
| 496 | lanes { | ||
| 497 | hsic-0 { | ||
| 498 | status = "disabled"; | ||
| 499 | #phy-cells = <0>; | ||
| 500 | }; | ||
| 501 | |||
| 502 | hsic-1 { | ||
| 503 | status = "disabled"; | ||
| 504 | #phy-cells = <0>; | ||
| 505 | }; | ||
| 506 | }; | ||
| 507 | }; | ||
| 508 | |||
| 509 | pcie { | ||
| 510 | clocks = <&tegra_car TEGRA210_CLK_PLL_E>; | ||
| 511 | clock-names = "pll"; | ||
| 512 | resets = <&tegra_car 205>; | ||
| 513 | reset-names = "phy"; | ||
| 514 | status = "disabled"; | ||
| 515 | |||
| 516 | lanes { | ||
| 517 | pcie-0 { | ||
| 518 | status = "disabled"; | ||
| 519 | #phy-cells = <0>; | ||
| 520 | }; | ||
| 521 | |||
| 522 | pcie-1 { | ||
| 523 | status = "disabled"; | ||
| 524 | #phy-cells = <0>; | ||
| 525 | }; | ||
| 526 | |||
| 527 | pcie-2 { | ||
| 528 | status = "disabled"; | ||
| 529 | #phy-cells = <0>; | ||
| 530 | }; | ||
| 531 | |||
| 532 | pcie-3 { | ||
| 533 | status = "disabled"; | ||
| 534 | #phy-cells = <0>; | ||
| 535 | }; | ||
| 536 | |||
| 537 | pcie-4 { | ||
| 538 | status = "disabled"; | ||
| 539 | #phy-cells = <0>; | ||
| 540 | }; | ||
| 541 | |||
| 542 | pcie-5 { | ||
| 543 | status = "disabled"; | ||
| 544 | #phy-cells = <0>; | ||
| 545 | }; | ||
| 546 | |||
| 547 | pcie-6 { | ||
| 548 | status = "disabled"; | ||
| 549 | #phy-cells = <0>; | ||
| 550 | }; | ||
| 551 | }; | ||
| 552 | }; | ||
| 553 | |||
| 554 | sata { | ||
| 555 | clocks = <&tegra_car TEGRA210_CLK_PLL_E>; | ||
| 556 | clock-names = "pll"; | ||
| 557 | resets = <&tegra_car 204>; | ||
| 558 | reset-names = "phy"; | ||
| 559 | status = "disabled"; | ||
| 560 | |||
| 561 | lanes { | ||
| 562 | sata-0 { | ||
| 563 | status = "disabled"; | ||
| 564 | #phy-cells = <0>; | ||
| 565 | }; | ||
| 566 | }; | ||
| 567 | }; | ||
| 568 | }; | ||
| 569 | |||
| 570 | ports { | ||
| 571 | usb2-0 { | ||
| 572 | status = "disabled"; | ||
| 573 | }; | ||
| 574 | |||
| 575 | usb2-1 { | ||
| 576 | status = "disabled"; | ||
| 577 | }; | ||
| 578 | |||
| 579 | usb2-2 { | ||
| 580 | status = "disabled"; | ||
| 581 | }; | ||
| 582 | |||
| 583 | usb2-3 { | ||
| 584 | status = "disabled"; | ||
| 585 | }; | ||
| 586 | |||
| 587 | hsic-0 { | ||
| 588 | status = "disabled"; | ||
| 589 | }; | ||
| 590 | |||
| 591 | hsic-1 { | ||
| 592 | status = "disabled"; | ||
| 593 | }; | ||
| 594 | |||
| 595 | usb3-0 { | ||
| 596 | status = "disabled"; | ||
| 597 | }; | ||
| 598 | |||
| 599 | usb3-1 { | ||
| 600 | status = "disabled"; | ||
| 601 | }; | ||
| 602 | |||
| 603 | usb3-2 { | ||
| 604 | status = "disabled"; | ||
| 605 | }; | ||
| 606 | |||
| 607 | usb3-3 { | ||
| 608 | status = "disabled"; | ||
| 609 | }; | ||
| 610 | }; | ||
| 611 | }; | ||
| 612 | |||
| 613 | Board file: | ||
| 614 | |||
| 615 | padctl@7009f000 { | ||
| 616 | status = "okay"; | ||
| 617 | |||
| 618 | pads { | ||
| 619 | usb2 { | ||
| 620 | status = "okay"; | ||
| 621 | |||
| 622 | lanes { | ||
| 623 | usb2-0 { | ||
| 624 | nvidia,function = "xusb"; | ||
| 625 | status = "okay"; | ||
| 626 | }; | ||
| 627 | |||
| 628 | usb2-1 { | ||
| 629 | nvidia,function = "xusb"; | ||
| 630 | status = "okay"; | ||
| 631 | }; | ||
| 632 | |||
| 633 | usb2-2 { | ||
| 634 | nvidia,function = "xusb"; | ||
| 635 | status = "okay"; | ||
| 636 | }; | ||
| 637 | |||
| 638 | usb2-3 { | ||
| 639 | nvidia,function = "xusb"; | ||
| 640 | status = "okay"; | ||
| 641 | }; | ||
| 642 | }; | ||
| 643 | }; | ||
| 644 | |||
| 645 | pcie { | ||
| 646 | status = "okay"; | ||
| 647 | |||
| 648 | lanes { | ||
| 649 | pcie-0 { | ||
| 650 | nvidia,function = "pcie-x1"; | ||
| 651 | status = "okay"; | ||
| 652 | }; | ||
| 653 | |||
| 654 | pcie-1 { | ||
| 655 | nvidia,function = "pcie-x4"; | ||
| 656 | status = "okay"; | ||
| 657 | }; | ||
| 658 | |||
| 659 | pcie-2 { | ||
| 660 | nvidia,function = "pcie-x4"; | ||
| 661 | status = "okay"; | ||
| 662 | }; | ||
| 663 | |||
| 664 | pcie-3 { | ||
| 665 | nvidia,function = "pcie-x4"; | ||
| 666 | status = "okay"; | ||
| 667 | }; | ||
| 668 | |||
| 669 | pcie-4 { | ||
| 670 | nvidia,function = "pcie-x4"; | ||
| 671 | status = "okay"; | ||
| 672 | }; | ||
| 673 | |||
| 674 | pcie-5 { | ||
| 675 | nvidia,function = "usb3-ss"; | ||
| 676 | status = "okay"; | ||
| 677 | }; | ||
| 678 | |||
| 679 | pcie-6 { | ||
| 680 | nvidia,function = "usb3-ss"; | ||
| 681 | status = "okay"; | ||
| 682 | }; | ||
| 683 | }; | ||
| 684 | }; | ||
| 685 | |||
| 686 | sata { | ||
| 687 | status = "okay"; | ||
| 688 | |||
| 689 | lanes { | ||
| 690 | sata-0 { | ||
| 691 | nvidia,function = "sata"; | ||
| 692 | status = "okay"; | ||
| 693 | }; | ||
| 694 | }; | ||
| 695 | }; | ||
| 696 | }; | ||
| 697 | |||
| 698 | ports { | ||
| 699 | usb2-0 { | ||
| 700 | status = "okay"; | ||
| 701 | mode = "otg"; | ||
| 702 | }; | ||
| 703 | |||
| 704 | usb2-1 { | ||
| 705 | status = "okay"; | ||
| 706 | vbus-supply = <&vdd_5v0_rtl>; | ||
| 707 | mode = "host"; | ||
| 708 | }; | ||
| 709 | |||
| 710 | usb2-2 { | ||
| 711 | status = "okay"; | ||
| 712 | vbus-supply = <&vdd_usb_vbus>; | ||
| 713 | mode = "host"; | ||
| 714 | }; | ||
| 715 | |||
| 716 | usb2-3 { | ||
| 717 | status = "okay"; | ||
| 718 | mode = "host"; | ||
| 719 | }; | ||
| 720 | |||
| 721 | usb3-0 { | ||
| 722 | status = "okay"; | ||
| 723 | nvidia,lanes = "pcie-6"; | ||
| 724 | nvidia,port = <1>; | ||
| 725 | }; | ||
| 726 | |||
| 727 | usb3-1 { | ||
| 728 | status = "okay"; | ||
| 729 | nvidia,lanes = "pcie-5"; | ||
| 730 | nvidia,port = <2>; | ||
| 731 | }; | ||
| 732 | }; | ||
| 733 | }; | ||
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt index 30676ded85bb..8a6223dbc143 100644 --- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt | |||
| @@ -1,6 +1,12 @@ | |||
| 1 | Device tree binding for NVIDIA Tegra XUSB pad controller | 1 | Device tree binding for NVIDIA Tegra XUSB pad controller |
| 2 | ======================================================== | 2 | ======================================================== |
| 3 | 3 | ||
| 4 | NOTE: It turns out that this binding isn't an accurate description of the XUSB | ||
| 5 | pad controller. While the description is good enough for the functional subset | ||
| 6 | required for PCIe and SATA, it lacks the flexibility to represent the features | ||
| 7 | needed for USB. For the new binding, see ../phy/nvidia,tegra-xusb-padctl.txt. | ||
| 8 | The binding described in this file is deprecated and should not be used. | ||
| 9 | |||
| 4 | The Tegra XUSB pad controller manages a set of lanes, each of which can be | 10 | The Tegra XUSB pad controller manages a set of lanes, each of which can be |
| 5 | assigned to one out of a set of different pads. Some of these pads have an | 11 | assigned to one out of a set of different pads. Some of these pads have an |
| 6 | associated PHY that must be powered up before the pad can be used. | 12 | associated PHY that must be powered up before the pad can be used. |
diff --git a/Documentation/devicetree/bindings/reset/oxnas,reset.txt b/Documentation/devicetree/bindings/reset/oxnas,reset.txt new file mode 100644 index 000000000000..6f06db930030 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/oxnas,reset.txt | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | Oxford Semiconductor OXNAS SoC Family RESET Controller | ||
| 2 | ================================================ | ||
| 3 | |||
| 4 | Please also refer to reset.txt in this directory for common reset | ||
| 5 | controller binding usage. | ||
| 6 | |||
| 7 | Required properties: | ||
| 8 | - compatible: Should be "oxsemi,ox810se-reset" | ||
| 9 | - #reset-cells: 1, see below | ||
| 10 | |||
| 11 | Parent node should have the following properties : | ||
| 12 | - compatible: Should be "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd" | ||
| 13 | |||
| 14 | For OX810SE, the indices are : | ||
| 15 | - 0 : ARM | ||
| 16 | - 1 : COPRO | ||
| 17 | - 2 : Reserved | ||
| 18 | - 3 : Reserved | ||
| 19 | - 4 : USBHS | ||
| 20 | - 5 : USBHSPHY | ||
| 21 | - 6 : MAC | ||
| 22 | - 7 : PCI | ||
| 23 | - 8 : DMA | ||
| 24 | - 9 : DPE | ||
| 25 | - 10 : DDR | ||
| 26 | - 11 : SATA | ||
| 27 | - 12 : SATA_LINK | ||
| 28 | - 13 : SATA_PHY | ||
| 29 | - 14 : Reserved | ||
| 30 | - 15 : NAND | ||
| 31 | - 16 : GPIO | ||
| 32 | - 17 : UART1 | ||
| 33 | - 18 : UART2 | ||
| 34 | - 19 : MISC | ||
| 35 | - 20 : I2S | ||
| 36 | - 21 : AHB_MON | ||
| 37 | - 22 : UART3 | ||
| 38 | - 23 : UART4 | ||
| 39 | - 24 : SGDMA | ||
| 40 | - 25 : Reserved | ||
| 41 | - 26 : Reserved | ||
| 42 | - 27 : Reserved | ||
| 43 | - 28 : Reserved | ||
| 44 | - 29 : Reserved | ||
| 45 | - 30 : Reserved | ||
| 46 | - 31 : BUS | ||
| 47 | |||
| 48 | example: | ||
| 49 | |||
| 50 | sys: sys-ctrl@000000 { | ||
| 51 | compatible = "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd"; | ||
| 52 | reg = <0x000000 0x100000>; | ||
| 53 | |||
| 54 | reset: reset-controller { | ||
| 55 | compatible = "oxsemi,ox810se-reset"; | ||
| 56 | #reset-cells = <1>; | ||
| 57 | }; | ||
| 58 | }; | ||
diff --git a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt index 13dc6a3fdb4a..f909ce06afc4 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt +++ b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt | |||
| @@ -7,6 +7,7 @@ Required properties for power domain controller: | |||
| 7 | - compatible: Should be one of the following. | 7 | - compatible: Should be one of the following. |
| 8 | "rockchip,rk3288-power-controller" - for RK3288 SoCs. | 8 | "rockchip,rk3288-power-controller" - for RK3288 SoCs. |
| 9 | "rockchip,rk3368-power-controller" - for RK3368 SoCs. | 9 | "rockchip,rk3368-power-controller" - for RK3368 SoCs. |
| 10 | "rockchip,rk3399-power-controller" - for RK3399 SoCs. | ||
| 10 | - #power-domain-cells: Number of cells in a power-domain specifier. | 11 | - #power-domain-cells: Number of cells in a power-domain specifier. |
| 11 | Should be 1 for multiple PM domains. | 12 | Should be 1 for multiple PM domains. |
| 12 | - #address-cells: Should be 1. | 13 | - #address-cells: Should be 1. |
| @@ -16,8 +17,18 @@ Required properties for power domain sub nodes: | |||
| 16 | - reg: index of the power domain, should use macros in: | 17 | - reg: index of the power domain, should use macros in: |
| 17 | "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. | 18 | "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. |
| 18 | "include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain. | 19 | "include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain. |
| 20 | "include/dt-bindings/power/rk3399-power.h" - for RK3399 type power domain. | ||
| 19 | - clocks (optional): phandles to clocks which need to be enabled while power domain | 21 | - clocks (optional): phandles to clocks which need to be enabled while power domain |
| 20 | switches state. | 22 | switches state. |
| 23 | - pm_qos (optional): phandles to qos blocks which need to be saved and restored | ||
| 24 | while power domain switches state. | ||
| 25 | |||
| 26 | Qos Example: | ||
| 27 | |||
| 28 | qos_gpu: qos_gpu@ffaf0000 { | ||
| 29 | compatible ="syscon"; | ||
| 30 | reg = <0x0 0xffaf0000 0x0 0x20>; | ||
| 31 | }; | ||
| 21 | 32 | ||
| 22 | Example: | 33 | Example: |
| 23 | 34 | ||
| @@ -30,6 +41,7 @@ Example: | |||
| 30 | pd_gpu { | 41 | pd_gpu { |
| 31 | reg = <RK3288_PD_GPU>; | 42 | reg = <RK3288_PD_GPU>; |
| 32 | clocks = <&cru ACLK_GPU>; | 43 | clocks = <&cru ACLK_GPU>; |
| 44 | pm_qos = <&qos_gpu>; | ||
| 33 | }; | 45 | }; |
| 34 | }; | 46 | }; |
| 35 | 47 | ||
| @@ -45,12 +57,41 @@ Example: | |||
| 45 | }; | 57 | }; |
| 46 | }; | 58 | }; |
| 47 | 59 | ||
| 60 | Example 2: | ||
| 61 | power: power-controller { | ||
| 62 | compatible = "rockchip,rk3399-power-controller"; | ||
| 63 | #power-domain-cells = <1>; | ||
| 64 | #address-cells = <1>; | ||
| 65 | #size-cells = <0>; | ||
| 66 | |||
| 67 | pd_vio { | ||
| 68 | #address-cells = <1>; | ||
| 69 | #size-cells = <0>; | ||
| 70 | reg = <RK3399_PD_VIO>; | ||
| 71 | |||
| 72 | pd_vo { | ||
| 73 | #address-cells = <1>; | ||
| 74 | #size-cells = <0>; | ||
| 75 | reg = <RK3399_PD_VO>; | ||
| 76 | |||
| 77 | pd_vopb { | ||
| 78 | reg = <RK3399_PD_VOPB>; | ||
| 79 | }; | ||
| 80 | |||
| 81 | pd_vopl { | ||
| 82 | reg = <RK3399_PD_VOPL>; | ||
| 83 | }; | ||
| 84 | }; | ||
| 85 | }; | ||
| 86 | }; | ||
| 87 | |||
| 48 | Node of a device using power domains must have a power-domains property, | 88 | Node of a device using power domains must have a power-domains property, |
| 49 | containing a phandle to the power device node and an index specifying which | 89 | containing a phandle to the power device node and an index specifying which |
| 50 | power domain to use. | 90 | power domain to use. |
| 51 | The index should use macros in: | 91 | The index should use macros in: |
| 52 | "include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain. | 92 | "include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain. |
| 53 | "include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain. | 93 | "include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain. |
| 94 | "include/dt-bindings/power/rk3399-power.h" - for rk3399 type power domain. | ||
| 54 | 95 | ||
| 55 | Example of the node using power domain: | 96 | Example of the node using power domain: |
| 56 | 97 | ||
| @@ -65,3 +106,9 @@ Example of the node using power domain: | |||
| 65 | power-domains = <&power RK3368_PD_GPU_1>; | 106 | power-domains = <&power RK3368_PD_GPU_1>; |
| 66 | /* ... */ | 107 | /* ... */ |
| 67 | }; | 108 | }; |
| 109 | |||
| 110 | node { | ||
| 111 | /* ... */ | ||
| 112 | power-domains = <&power RK3399_PD_VOPB>; | ||
| 113 | /* ... */ | ||
| 114 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt new file mode 100644 index 000000000000..d28295a3e55f --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | NVIDIA Tegra xHCI controller | ||
| 2 | ============================ | ||
| 3 | |||
| 4 | The Tegra xHCI controller supports both USB2 and USB3 interfaces exposed by | ||
| 5 | the Tegra XUSB pad controller. | ||
| 6 | |||
| 7 | Required properties: | ||
| 8 | -------------------- | ||
| 9 | - compatible: Must be: | ||
| 10 | - Tegra124: "nvidia,tegra124-xusb" | ||
| 11 | - Tegra132: "nvidia,tegra132-xusb", "nvidia,tegra124-xusb" | ||
| 12 | - Tegra210: "nvidia,tegra210-xusb" | ||
| 13 | - reg: Must contain the base and length of the xHCI host registers, XUSB FPCI | ||
| 14 | registers and XUSB IPFS registers. | ||
| 15 | - reg-names: Must contain the following entries: | ||
| 16 | - "hcd" | ||
| 17 | - "fpci" | ||
| 18 | - "ipfs" | ||
| 19 | - interrupts: Must contain the xHCI host interrupt and the mailbox interrupt. | ||
| 20 | - clocks: Must contain an entry for each entry in clock-names. | ||
| 21 | See ../clock/clock-bindings.txt for details. | ||
| 22 | - clock-names: Must include the following entries: | ||
| 23 | - xusb_host | ||
| 24 | - xusb_host_src | ||
| 25 | - xusb_falcon_src | ||
| 26 | - xusb_ss | ||
| 27 | - xusb_ss_src | ||
| 28 | - xusb_ss_div2 | ||
| 29 | - xusb_hs_src | ||
| 30 | - xusb_fs_src | ||
| 31 | - pll_u_480m | ||
| 32 | - clk_m | ||
| 33 | - pll_e | ||
| 34 | - resets: Must contain an entry for each entry in reset-names. | ||
| 35 | See ../reset/reset.txt for details. | ||
| 36 | - reset-names: Must include the following entries: | ||
| 37 | - xusb_host | ||
| 38 | - xusb_ss | ||
| 39 | - xusb_src | ||
| 40 | Note that xusb_src is the shared reset for xusb_{ss,hs,fs,falcon,host}_src. | ||
| 41 | - nvidia,xusb-padctl: phandle to the XUSB pad controller that is used to | ||
| 42 | configure the USB pads used by the XHCI controller | ||
| 43 | |||
| 44 | For Tegra124 and Tegra132: | ||
| 45 | - avddio-pex-supply: PCIe/USB3 analog logic power supply. Must supply 1.05 V. | ||
| 46 | - dvddio-pex-supply: PCIe/USB3 digital logic power supply. Must supply 1.05 V. | ||
| 47 | - avdd-usb-supply: USB controller power supply. Must supply 3.3 V. | ||
| 48 | - avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V. | ||
| 49 | - avdd-pll-erefe-supply: PLLE reference PLL power supply. Must supply 1.05 V. | ||
| 50 | - avdd-usb-ss-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V. | ||
| 51 | - hvdd-usb-ss-supply: High-voltage PCIe/USB3 power supply. Must supply 3.3 V. | ||
| 52 | - hvdd-usb-ss-pll-e-supply: High-voltage PLLE power supply. Must supply 3.3 V. | ||
| 53 | |||
| 54 | For Tegra210: | ||
| 55 | - dvddio-pex-supply: PCIe/USB3 analog logic power supply. Must supply 1.05 V. | ||
| 56 | - hvddio-pex-supply: High-voltage PCIe/USB3 power supply. Must supply 1.8 V. | ||
| 57 | - avdd-usb-supply: USB controller power supply. Must supply 3.3 V. | ||
| 58 | - avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V. | ||
| 59 | - avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V. | ||
| 60 | - dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V. | ||
| 61 | - hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V. | ||
| 62 | |||
| 63 | Optional properties: | ||
| 64 | -------------------- | ||
| 65 | - phys: Must contain an entry for each entry in phy-names. | ||
| 66 | See ../phy/phy-bindings.txt for details. | ||
| 67 | - phy-names: Should include an entry for each PHY used by the controller. The | ||
| 68 | following PHYs are available: | ||
| 69 | - Tegra124: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1 | ||
| 70 | - Tegra132: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1 | ||
| 71 | - Tegra210: usb2-0, usb2-1, usb2-2, usb2-3, hsic-0, usb3-0, usb3-1, usb3-2, | ||
| 72 | usb3-3 | ||
| 73 | |||
| 74 | Example: | ||
| 75 | -------- | ||
| 76 | |||
| 77 | usb@0,70090000 { | ||
| 78 | compatible = "nvidia,tegra124-xusb"; | ||
| 79 | reg = <0x0 0x70090000 0x0 0x8000>, | ||
| 80 | <0x0 0x70098000 0x0 0x1000>, | ||
| 81 | <0x0 0x70099000 0x0 0x1000>; | ||
| 82 | reg-names = "hcd", "fpci", "ipfs"; | ||
| 83 | |||
| 84 | interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>, | ||
| 85 | <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; | ||
| 86 | |||
| 87 | clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>, | ||
| 88 | <&tegra_car TEGRA124_CLK_XUSB_HOST_SRC>, | ||
| 89 | <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>, | ||
| 90 | <&tegra_car TEGRA124_CLK_XUSB_SS>, | ||
| 91 | <&tegra_car TEGRA124_CLK_XUSB_SS_DIV2>, | ||
| 92 | <&tegra_car TEGRA124_CLK_XUSB_SS_SRC>, | ||
| 93 | <&tegra_car TEGRA124_CLK_XUSB_HS_SRC>, | ||
| 94 | <&tegra_car TEGRA124_CLK_XUSB_FS_SRC>, | ||
| 95 | <&tegra_car TEGRA124_CLK_PLL_U_480M>, | ||
| 96 | <&tegra_car TEGRA124_CLK_CLK_M>, | ||
| 97 | <&tegra_car TEGRA124_CLK_PLL_E>; | ||
| 98 | clock-names = "xusb_host", "xusb_host_src", "xusb_falcon_src", | ||
| 99 | "xusb_ss", "xusb_ss_div2", "xusb_ss_src", | ||
| 100 | "xusb_hs_src", "xusb_fs_src", "pll_u_480m", | ||
| 101 | "clk_m", "pll_e"; | ||
| 102 | resets = <&tegra_car 89>, <&tegra_car 156>, <&tegra_car 143>; | ||
| 103 | reset-names = "xusb_host", "xusb_ss", "xusb_src"; | ||
| 104 | |||
| 105 | nvidia,xusb-padctl = <&padctl>; | ||
| 106 | |||
| 107 | phys = <&{/padctl@0,7009f000/pads/usb2/usb2-1}>, /* mini-PCIe USB */ | ||
| 108 | <&{/padctl@0,7009f000/pads/usb2/usb2-2}>, /* USB A */ | ||
| 109 | <&{/padctl@0,7009f000/pads/pcie/pcie-0}>; /* USB A */ | ||
| 110 | phy-names = "utmi-1", "utmi-2", "usb3-0"; | ||
| 111 | |||
| 112 | avddio-pex-supply = <&vdd_1v05_run>; | ||
| 113 | dvddio-pex-supply = <&vdd_1v05_run>; | ||
| 114 | avdd-usb-supply = <&vdd_3v3_lp0>; | ||
| 115 | avdd-pll-utmip-supply = <&vddio_1v8>; | ||
| 116 | avdd-pll-erefe-supply = <&avdd_1v05_run>; | ||
| 117 | avdd-usb-ss-pll-supply = <&vdd_1v05_run>; | ||
| 118 | hvdd-usb-ss-supply = <&vdd_3v3_lp0>; | ||
| 119 | hvdd-usb-ss-pll-e-supply = <&vdd_3v3_lp0>; | ||
| 120 | }; | ||
diff --git a/Documentation/phy.txt b/Documentation/phy.txt index b388c5af9e72..0aa994bd9a91 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt | |||
| @@ -31,16 +31,28 @@ should provide its own implementation of of_xlate. of_xlate is used only for | |||
| 31 | dt boot case. | 31 | dt boot case. |
| 32 | 32 | ||
| 33 | #define of_phy_provider_register(dev, xlate) \ | 33 | #define of_phy_provider_register(dev, xlate) \ |
| 34 | __of_phy_provider_register((dev), THIS_MODULE, (xlate)) | 34 | __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate)) |
| 35 | 35 | ||
| 36 | #define devm_of_phy_provider_register(dev, xlate) \ | 36 | #define devm_of_phy_provider_register(dev, xlate) \ |
| 37 | __devm_of_phy_provider_register((dev), THIS_MODULE, (xlate)) | 37 | __devm_of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate)) |
| 38 | 38 | ||
| 39 | of_phy_provider_register and devm_of_phy_provider_register macros can be used to | 39 | of_phy_provider_register and devm_of_phy_provider_register macros can be used to |
| 40 | register the phy_provider and it takes device and of_xlate as | 40 | register the phy_provider and it takes device and of_xlate as |
| 41 | arguments. For the dt boot case, all PHY providers should use one of the above | 41 | arguments. For the dt boot case, all PHY providers should use one of the above |
| 42 | 2 macros to register the PHY provider. | 42 | 2 macros to register the PHY provider. |
| 43 | 43 | ||
| 44 | Often the device tree nodes associated with a PHY provider will contain a set | ||
| 45 | of children that each represent a single PHY. Some bindings may nest the child | ||
| 46 | nodes within extra levels for context and extensibility, in which case the low | ||
| 47 | level of_phy_provider_register_full() and devm_of_phy_provider_register_full() | ||
| 48 | macros can be used to override the node containing the children. | ||
| 49 | |||
| 50 | #define of_phy_provider_register_full(dev, children, xlate) \ | ||
| 51 | __of_phy_provider_register(dev, children, THIS_MODULE, xlate) | ||
| 52 | |||
| 53 | #define devm_of_phy_provider_register_full(dev, children, xlate) \ | ||
| 54 | __devm_of_phy_provider_register_full(dev, children, THIS_MODULE, xlate) | ||
| 55 | |||
| 44 | void devm_of_phy_provider_unregister(struct device *dev, | 56 | void devm_of_phy_provider_unregister(struct device *dev, |
| 45 | struct phy_provider *phy_provider); | 57 | struct phy_provider *phy_provider); |
| 46 | void of_phy_provider_unregister(struct phy_provider *phy_provider); | 58 | void of_phy_provider_unregister(struct phy_provider *phy_provider); |
diff --git a/MAINTAINERS b/MAINTAINERS index 578e3f0214f6..804bc4fd154f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -1535,6 +1535,8 @@ Q: http://patchwork.kernel.org/project/linux-renesas-soc/list/ | |||
| 1535 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git next | 1535 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git next |
| 1536 | S: Supported | 1536 | S: Supported |
| 1537 | F: arch/arm64/boot/dts/renesas/ | 1537 | F: arch/arm64/boot/dts/renesas/ |
| 1538 | F: drivers/soc/renesas/ | ||
| 1539 | F: include/linux/soc/renesas/ | ||
| 1538 | 1540 | ||
| 1539 | ARM/RISCPC ARCHITECTURE | 1541 | ARM/RISCPC ARCHITECTURE |
| 1540 | M: Russell King <linux@armlinux.org.uk> | 1542 | M: Russell King <linux@armlinux.org.uk> |
| @@ -1584,6 +1586,7 @@ F: arch/arm/mach-s5p*/ | |||
| 1584 | F: arch/arm/mach-exynos*/ | 1586 | F: arch/arm/mach-exynos*/ |
| 1585 | F: drivers/*/*s3c2410* | 1587 | F: drivers/*/*s3c2410* |
| 1586 | F: drivers/*/*/*s3c2410* | 1588 | F: drivers/*/*/*s3c2410* |
| 1589 | F: drivers/memory/samsung/* | ||
| 1587 | F: drivers/soc/samsung/* | 1590 | F: drivers/soc/samsung/* |
| 1588 | F: drivers/spi/spi-s3c* | 1591 | F: drivers/spi/spi-s3c* |
| 1589 | F: sound/soc/samsung/* | 1592 | F: sound/soc/samsung/* |
| @@ -1648,6 +1651,8 @@ F: arch/arm/configs/shmobile_defconfig | |||
| 1648 | F: arch/arm/include/debug/renesas-scif.S | 1651 | F: arch/arm/include/debug/renesas-scif.S |
| 1649 | F: arch/arm/mach-shmobile/ | 1652 | F: arch/arm/mach-shmobile/ |
| 1650 | F: drivers/sh/ | 1653 | F: drivers/sh/ |
| 1654 | F: drivers/soc/renesas/ | ||
| 1655 | F: include/linux/soc/renesas/ | ||
| 1651 | 1656 | ||
| 1652 | ARM/SOCFPGA ARCHITECTURE | 1657 | ARM/SOCFPGA ARCHITECTURE |
| 1653 | M: Dinh Nguyen <dinguyen@opensource.altera.com> | 1658 | M: Dinh Nguyen <dinguyen@opensource.altera.com> |
diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index b82f0e6d9a63..6fe0dd1d3541 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi | |||
| @@ -52,8 +52,9 @@ | |||
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | flash@24000000 { | 54 | flash@24000000 { |
| 55 | compatible = "cfi-flash"; | 55 | compatible = "arm,versatile-flash", "cfi-flash"; |
| 56 | reg = <0x24000000 0x02000000>; | 56 | reg = <0x24000000 0x02000000>; |
| 57 | bank-width = <4>; | ||
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 59 | fpga { | 60 | fpga { |
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts index d23320af5ea7..409e069b3a84 100644 --- a/arch/arm/boot/dts/versatile-ab.dts +++ b/arch/arm/boot/dts/versatile-ab.dts | |||
| @@ -119,8 +119,9 @@ | |||
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | flash@34000000 { | 121 | flash@34000000 { |
| 122 | compatible = "arm,versatile-flash"; | 122 | /* 64 MiB NOR flash in non-interleaved chips */ |
| 123 | reg = <0x34000000 0x4000000>; | 123 | compatible = "arm,versatile-flash", "cfi-flash"; |
| 124 | reg = <0x34000000 0x04000000>; | ||
| 124 | bank-width = <4>; | 125 | bank-width = <4>; |
| 125 | }; | 126 | }; |
| 126 | 127 | ||
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 7ef121472cdd..68ab6412392a 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig | |||
| @@ -173,12 +173,12 @@ config ARCH_BRCMSTB | |||
| 173 | select ARM_GIC | 173 | select ARM_GIC |
| 174 | select ARM_ERRATA_798181 if SMP | 174 | select ARM_ERRATA_798181 if SMP |
| 175 | select HAVE_ARM_ARCH_TIMER | 175 | select HAVE_ARM_ARCH_TIMER |
| 176 | select BRCMSTB_GISB_ARB | ||
| 177 | select BRCMSTB_L2_IRQ | 176 | select BRCMSTB_L2_IRQ |
| 178 | select BCM7120_L2_IRQ | 177 | select BCM7120_L2_IRQ |
| 179 | select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE | 178 | select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE |
| 180 | select ARCH_WANT_OPTIONAL_GPIOLIB | 179 | select ARCH_WANT_OPTIONAL_GPIOLIB |
| 181 | select SOC_BRCMSTB | 180 | select SOC_BRCMSTB |
| 181 | select SOC_BUS | ||
| 182 | help | 182 | help |
| 183 | Say Y if you intend to run the kernel on a Broadcom ARM-based STB | 183 | Say Y if you intend to run the kernel on a Broadcom ARM-based STB |
| 184 | chipset. | 184 | chipset. |
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 207fa2c737a6..e65aa7d11b20 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig | |||
| @@ -18,6 +18,7 @@ menuconfig ARCH_EXYNOS | |||
| 18 | select COMMON_CLK_SAMSUNG | 18 | select COMMON_CLK_SAMSUNG |
| 19 | select EXYNOS_THERMAL | 19 | select EXYNOS_THERMAL |
| 20 | select EXYNOS_PMU | 20 | select EXYNOS_PMU |
| 21 | select EXYNOS_SROM | ||
| 21 | select HAVE_ARM_SCU if SMP | 22 | select HAVE_ARM_SCU if SMP |
| 22 | select HAVE_S3C2410_I2C if I2C | 23 | select HAVE_S3C2410_I2C if I2C |
| 23 | select HAVE_S3C2410_WATCHDOG if WATCHDOG | 24 | select HAVE_S3C2410_WATCHDOG if WATCHDOG |
| @@ -26,11 +27,13 @@ menuconfig ARCH_EXYNOS | |||
| 26 | select PINCTRL_EXYNOS | 27 | select PINCTRL_EXYNOS |
| 27 | select PM_GENERIC_DOMAINS if PM | 28 | select PM_GENERIC_DOMAINS if PM |
| 28 | select S5P_DEV_MFC | 29 | select S5P_DEV_MFC |
| 30 | select SAMSUNG_MC | ||
| 29 | select SOC_SAMSUNG | 31 | select SOC_SAMSUNG |
| 30 | select SRAM | 32 | select SRAM |
| 31 | select THERMAL | 33 | select THERMAL |
| 32 | select THERMAL_OF | 34 | select THERMAL_OF |
| 33 | select MFD_SYSCON | 35 | select MFD_SYSCON |
| 36 | select MEMORY | ||
| 34 | select CLKSRC_EXYNOS_MCT | 37 | select CLKSRC_EXYNOS_MCT |
| 35 | select POWER_RESET | 38 | select POWER_RESET |
| 36 | select POWER_RESET_SYSCON | 39 | select POWER_RESET_SYSCON |
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 4d3b056fd786..52ccf247e079 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c | |||
| @@ -31,11 +31,6 @@ | |||
| 31 | 31 | ||
| 32 | static struct map_desc exynos4_iodesc[] __initdata = { | 32 | static struct map_desc exynos4_iodesc[] __initdata = { |
| 33 | { | 33 | { |
| 34 | .virtual = (unsigned long)S5P_VA_SROMC, | ||
| 35 | .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC), | ||
| 36 | .length = SZ_4K, | ||
| 37 | .type = MT_DEVICE, | ||
| 38 | }, { | ||
| 39 | .virtual = (unsigned long)S5P_VA_CMU, | 34 | .virtual = (unsigned long)S5P_VA_CMU, |
| 40 | .pfn = __phys_to_pfn(EXYNOS4_PA_CMU), | 35 | .pfn = __phys_to_pfn(EXYNOS4_PA_CMU), |
| 41 | .length = SZ_128K, | 36 | .length = SZ_128K, |
| @@ -58,15 +53,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { | |||
| 58 | }, | 53 | }, |
| 59 | }; | 54 | }; |
| 60 | 55 | ||
| 61 | static struct map_desc exynos5_iodesc[] __initdata = { | ||
| 62 | { | ||
| 63 | .virtual = (unsigned long)S5P_VA_SROMC, | ||
| 64 | .pfn = __phys_to_pfn(EXYNOS5_PA_SROMC), | ||
| 65 | .length = SZ_4K, | ||
| 66 | .type = MT_DEVICE, | ||
| 67 | }, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static struct platform_device exynos_cpuidle = { | 56 | static struct platform_device exynos_cpuidle = { |
| 71 | .name = "exynos_cpuidle", | 57 | .name = "exynos_cpuidle", |
| 72 | #ifdef CONFIG_ARM_EXYNOS_CPUIDLE | 58 | #ifdef CONFIG_ARM_EXYNOS_CPUIDLE |
| @@ -138,9 +124,6 @@ static void __init exynos_map_io(void) | |||
| 138 | { | 124 | { |
| 139 | if (soc_is_exynos4()) | 125 | if (soc_is_exynos4()) |
| 140 | iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc)); | 126 | iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc)); |
| 141 | |||
| 142 | if (soc_is_exynos5()) | ||
| 143 | iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc)); | ||
| 144 | } | 127 | } |
| 145 | 128 | ||
| 146 | static void __init exynos_init_io(void) | 129 | static void __init exynos_init_io(void) |
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index c88325d56743..c48ba4fbdfd2 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h | |||
| @@ -25,7 +25,4 @@ | |||
| 25 | 25 | ||
| 26 | #define EXYNOS4_PA_COREPERI 0x10500000 | 26 | #define EXYNOS4_PA_COREPERI 0x10500000 |
| 27 | 27 | ||
| 28 | #define EXYNOS4_PA_SROMC 0x12570000 | ||
| 29 | #define EXYNOS5_PA_SROMC 0x12250000 | ||
| 30 | |||
| 31 | #endif /* __ASM_ARCH_MAP_H */ | 28 | #endif /* __ASM_ARCH_MAP_H */ |
diff --git a/arch/arm/mach-exynos/regs-srom.h b/arch/arm/mach-exynos/regs-srom.h deleted file mode 100644 index 5c4d4427db7b..000000000000 --- a/arch/arm/mach-exynos/regs-srom.h +++ /dev/null | |||
| @@ -1,53 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 3 | * http://www.samsung.com | ||
| 4 | * | ||
| 5 | * S5P 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 __PLAT_SAMSUNG_REGS_SROM_H | ||
| 13 | #define __PLAT_SAMSUNG_REGS_SROM_H __FILE__ | ||
| 14 | |||
| 15 | #include <mach/map.h> | ||
| 16 | |||
| 17 | #define S5P_SROMREG(x) (S5P_VA_SROMC + (x)) | ||
| 18 | |||
| 19 | #define S5P_SROM_BW S5P_SROMREG(0x0) | ||
| 20 | #define S5P_SROM_BC0 S5P_SROMREG(0x4) | ||
| 21 | #define S5P_SROM_BC1 S5P_SROMREG(0x8) | ||
| 22 | #define S5P_SROM_BC2 S5P_SROMREG(0xc) | ||
| 23 | #define S5P_SROM_BC3 S5P_SROMREG(0x10) | ||
| 24 | #define S5P_SROM_BC4 S5P_SROMREG(0x14) | ||
| 25 | #define S5P_SROM_BC5 S5P_SROMREG(0x18) | ||
| 26 | |||
| 27 | /* one register BW holds 4 x 4-bit packed settings for NCS0 - NCS3 */ | ||
| 28 | |||
| 29 | #define S5P_SROM_BW__DATAWIDTH__SHIFT 0 | ||
| 30 | #define S5P_SROM_BW__ADDRMODE__SHIFT 1 | ||
| 31 | #define S5P_SROM_BW__WAITENABLE__SHIFT 2 | ||
| 32 | #define S5P_SROM_BW__BYTEENABLE__SHIFT 3 | ||
| 33 | |||
| 34 | #define S5P_SROM_BW__CS_MASK 0xf | ||
| 35 | |||
| 36 | #define S5P_SROM_BW__NCS0__SHIFT 0 | ||
| 37 | #define S5P_SROM_BW__NCS1__SHIFT 4 | ||
| 38 | #define S5P_SROM_BW__NCS2__SHIFT 8 | ||
| 39 | #define S5P_SROM_BW__NCS3__SHIFT 12 | ||
| 40 | #define S5P_SROM_BW__NCS4__SHIFT 16 | ||
| 41 | #define S5P_SROM_BW__NCS5__SHIFT 20 | ||
| 42 | |||
| 43 | /* applies to same to BCS0 - BCS3 */ | ||
| 44 | |||
| 45 | #define S5P_SROM_BCX__PMC__SHIFT 0 | ||
| 46 | #define S5P_SROM_BCX__TACP__SHIFT 4 | ||
| 47 | #define S5P_SROM_BCX__TCAH__SHIFT 8 | ||
| 48 | #define S5P_SROM_BCX__TCOH__SHIFT 12 | ||
| 49 | #define S5P_SROM_BCX__TACC__SHIFT 16 | ||
| 50 | #define S5P_SROM_BCX__TCOS__SHIFT 24 | ||
| 51 | #define S5P_SROM_BCX__TACS__SHIFT 28 | ||
| 52 | |||
| 53 | #endif /* __PLAT_SAMSUNG_REGS_SROM_H */ | ||
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index fee2b003e662..f21690937b7d 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c | |||
| @@ -34,10 +34,11 @@ | |||
| 34 | #include <asm/smp_scu.h> | 34 | #include <asm/smp_scu.h> |
| 35 | #include <asm/suspend.h> | 35 | #include <asm/suspend.h> |
| 36 | 36 | ||
| 37 | #include <mach/map.h> | ||
| 38 | |||
| 37 | #include <plat/pm-common.h> | 39 | #include <plat/pm-common.h> |
| 38 | 40 | ||
| 39 | #include "common.h" | 41 | #include "common.h" |
| 40 | #include "regs-srom.h" | ||
| 41 | 42 | ||
| 42 | #define REG_TABLE_END (-1U) | 43 | #define REG_TABLE_END (-1U) |
| 43 | 44 | ||
| @@ -53,15 +54,6 @@ struct exynos_wkup_irq { | |||
| 53 | u32 mask; | 54 | u32 mask; |
| 54 | }; | 55 | }; |
| 55 | 56 | ||
| 56 | static struct sleep_save exynos_core_save[] = { | ||
| 57 | /* SROM side */ | ||
| 58 | SAVE_ITEM(S5P_SROM_BW), | ||
| 59 | SAVE_ITEM(S5P_SROM_BC0), | ||
| 60 | SAVE_ITEM(S5P_SROM_BC1), | ||
| 61 | SAVE_ITEM(S5P_SROM_BC2), | ||
| 62 | SAVE_ITEM(S5P_SROM_BC3), | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct exynos_pm_data { | 57 | struct exynos_pm_data { |
| 66 | const struct exynos_wkup_irq *wkup_irq; | 58 | const struct exynos_wkup_irq *wkup_irq; |
| 67 | unsigned int wake_disable_mask; | 59 | unsigned int wake_disable_mask; |
| @@ -343,8 +335,6 @@ static void exynos_pm_prepare(void) | |||
| 343 | /* Set wake-up mask registers */ | 335 | /* Set wake-up mask registers */ |
| 344 | exynos_pm_set_wakeup_mask(); | 336 | exynos_pm_set_wakeup_mask(); |
| 345 | 337 | ||
| 346 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
| 347 | |||
| 348 | exynos_pm_enter_sleep_mode(); | 338 | exynos_pm_enter_sleep_mode(); |
| 349 | 339 | ||
| 350 | /* ensure at least INFORM0 has the resume address */ | 340 | /* ensure at least INFORM0 has the resume address */ |
| @@ -375,8 +365,6 @@ static void exynos5420_pm_prepare(void) | |||
| 375 | /* Set wake-up mask registers */ | 365 | /* Set wake-up mask registers */ |
| 376 | exynos_pm_set_wakeup_mask(); | 366 | exynos_pm_set_wakeup_mask(); |
| 377 | 367 | ||
| 378 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
| 379 | |||
| 380 | exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); | 368 | exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); |
| 381 | /* | 369 | /* |
| 382 | * The cpu state needs to be saved and restored so that the | 370 | * The cpu state needs to be saved and restored so that the |
| @@ -467,8 +455,6 @@ static void exynos_pm_resume(void) | |||
| 467 | /* For release retention */ | 455 | /* For release retention */ |
| 468 | exynos_pm_release_retention(); | 456 | exynos_pm_release_retention(); |
| 469 | 457 | ||
| 470 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
| 471 | |||
| 472 | if (cpuid == ARM_CPU_PART_CORTEX_A9) | 458 | if (cpuid == ARM_CPU_PART_CORTEX_A9) |
| 473 | scu_enable(S5P_VA_SCU); | 459 | scu_enable(S5P_VA_SCU); |
| 474 | 460 | ||
| @@ -535,8 +521,6 @@ static void exynos5420_pm_resume(void) | |||
| 535 | 521 | ||
| 536 | pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3); | 522 | pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3); |
| 537 | 523 | ||
| 538 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
| 539 | |||
| 540 | early_wakeup: | 524 | early_wakeup: |
| 541 | 525 | ||
| 542 | tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); | 526 | tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); |
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 5b0e363fe5ba..2b118f20c62c 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c | |||
| @@ -29,7 +29,6 @@ | |||
| 29 | #include <linux/amba/kmi.h> | 29 | #include <linux/amba/kmi.h> |
| 30 | #include <linux/io.h> | 30 | #include <linux/io.h> |
| 31 | #include <linux/irqchip.h> | 31 | #include <linux/irqchip.h> |
| 32 | #include <linux/mtd/physmap.h> | ||
| 33 | #include <linux/platform_data/clk-integrator.h> | 32 | #include <linux/platform_data/clk-integrator.h> |
| 34 | #include <linux/of_irq.h> | 33 | #include <linux/of_irq.h> |
| 35 | #include <linux/of_address.h> | 34 | #include <linux/of_address.h> |
| @@ -147,65 +146,6 @@ static int __init irq_syscore_init(void) | |||
| 147 | device_initcall(irq_syscore_init); | 146 | device_initcall(irq_syscore_init); |
| 148 | 147 | ||
| 149 | /* | 148 | /* |
| 150 | * Flash handling. | ||
| 151 | */ | ||
| 152 | static int ap_flash_init(struct platform_device *dev) | ||
| 153 | { | ||
| 154 | u32 tmp; | ||
| 155 | |||
| 156 | writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, | ||
| 157 | ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); | ||
| 158 | |||
| 159 | tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) | | ||
| 160 | INTEGRATOR_EBI_WRITE_ENABLE; | ||
| 161 | writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); | ||
| 162 | |||
| 163 | if (!(readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) | ||
| 164 | & INTEGRATOR_EBI_WRITE_ENABLE)) { | ||
| 165 | writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); | ||
| 166 | writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); | ||
| 167 | writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); | ||
| 168 | } | ||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | static void ap_flash_exit(struct platform_device *dev) | ||
| 173 | { | ||
| 174 | u32 tmp; | ||
| 175 | |||
| 176 | writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, | ||
| 177 | ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); | ||
| 178 | |||
| 179 | tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) & | ||
| 180 | ~INTEGRATOR_EBI_WRITE_ENABLE; | ||
| 181 | writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); | ||
| 182 | |||
| 183 | if (readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) & | ||
| 184 | INTEGRATOR_EBI_WRITE_ENABLE) { | ||
| 185 | writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); | ||
| 186 | writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); | ||
| 187 | writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | static void ap_flash_set_vpp(struct platform_device *pdev, int on) | ||
| 192 | { | ||
| 193 | if (on) | ||
| 194 | writel(INTEGRATOR_SC_CTRL_nFLVPPEN, | ||
| 195 | ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET); | ||
| 196 | else | ||
| 197 | writel(INTEGRATOR_SC_CTRL_nFLVPPEN, | ||
| 198 | ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); | ||
| 199 | } | ||
| 200 | |||
| 201 | static struct physmap_flash_data ap_flash_data = { | ||
| 202 | .width = 4, | ||
| 203 | .init = ap_flash_init, | ||
| 204 | .exit = ap_flash_exit, | ||
| 205 | .set_vpp = ap_flash_set_vpp, | ||
| 206 | }; | ||
| 207 | |||
| 208 | /* | ||
| 209 | * For the PL010 found in the Integrator/AP some of the UART control is | 149 | * For the PL010 found in the Integrator/AP some of the UART control is |
| 210 | * implemented in the system controller and accessed using a callback | 150 | * implemented in the system controller and accessed using a callback |
| 211 | * from the driver. | 151 | * from the driver. |
| @@ -266,8 +206,6 @@ static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = { | |||
| 266 | "kmi0", NULL), | 206 | "kmi0", NULL), |
| 267 | OF_DEV_AUXDATA("arm,primecell", KMI1_BASE, | 207 | OF_DEV_AUXDATA("arm,primecell", KMI1_BASE, |
| 268 | "kmi1", NULL), | 208 | "kmi1", NULL), |
| 269 | OF_DEV_AUXDATA("cfi-flash", INTEGRATOR_FLASH_BASE, | ||
| 270 | "physmap-flash", &ap_flash_data), | ||
| 271 | { /* sentinel */ }, | 209 | { /* sentinel */ }, |
| 272 | }; | 210 | }; |
| 273 | 211 | ||
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index b5fb71a36ee6..6f6b051e81e0 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 24 | #include <linux/irqchip.h> | 24 | #include <linux/irqchip.h> |
| 25 | #include <linux/gfp.h> | 25 | #include <linux/gfp.h> |
| 26 | #include <linux/mtd/physmap.h> | ||
| 27 | #include <linux/of_irq.h> | 26 | #include <linux/of_irq.h> |
| 28 | #include <linux/of_address.h> | 27 | #include <linux/of_address.h> |
| 29 | #include <linux/of_platform.h> | 28 | #include <linux/of_platform.h> |
| @@ -43,14 +42,8 @@ | |||
| 43 | /* Base address to the CP controller */ | 42 | /* Base address to the CP controller */ |
| 44 | static void __iomem *intcp_con_base; | 43 | static void __iomem *intcp_con_base; |
| 45 | 44 | ||
| 46 | #define INTCP_PA_FLASH_BASE 0x24000000 | ||
| 47 | |||
| 48 | #define INTCP_PA_CLCD_BASE 0xc0000000 | 45 | #define INTCP_PA_CLCD_BASE 0xc0000000 |
| 49 | 46 | ||
| 50 | #define INTCP_FLASHPROG 0x04 | ||
| 51 | #define CINTEGRATOR_FLASHPROG_FLVPPEN (1 << 0) | ||
| 52 | #define CINTEGRATOR_FLASHPROG_FLWREN (1 << 1) | ||
| 53 | |||
| 54 | /* | 47 | /* |
| 55 | * Logical Physical | 48 | * Logical Physical |
| 56 | * f1000000 10000000 Core module registers | 49 | * f1000000 10000000 Core module registers |
| @@ -108,48 +101,6 @@ static void __init intcp_map_io(void) | |||
| 108 | } | 101 | } |
| 109 | 102 | ||
| 110 | /* | 103 | /* |
| 111 | * Flash handling. | ||
| 112 | */ | ||
| 113 | static int intcp_flash_init(struct platform_device *dev) | ||
| 114 | { | ||
| 115 | u32 val; | ||
| 116 | |||
| 117 | val = readl(intcp_con_base + INTCP_FLASHPROG); | ||
| 118 | val |= CINTEGRATOR_FLASHPROG_FLWREN; | ||
| 119 | writel(val, intcp_con_base + INTCP_FLASHPROG); | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | static void intcp_flash_exit(struct platform_device *dev) | ||
| 125 | { | ||
| 126 | u32 val; | ||
| 127 | |||
| 128 | val = readl(intcp_con_base + INTCP_FLASHPROG); | ||
| 129 | val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN); | ||
| 130 | writel(val, intcp_con_base + INTCP_FLASHPROG); | ||
| 131 | } | ||
| 132 | |||
| 133 | static void intcp_flash_set_vpp(struct platform_device *pdev, int on) | ||
| 134 | { | ||
| 135 | u32 val; | ||
| 136 | |||
| 137 | val = readl(intcp_con_base + INTCP_FLASHPROG); | ||
| 138 | if (on) | ||
| 139 | val |= CINTEGRATOR_FLASHPROG_FLVPPEN; | ||
| 140 | else | ||
| 141 | val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN; | ||
| 142 | writel(val, intcp_con_base + INTCP_FLASHPROG); | ||
| 143 | } | ||
| 144 | |||
| 145 | static struct physmap_flash_data intcp_flash_data = { | ||
| 146 | .width = 4, | ||
| 147 | .init = intcp_flash_init, | ||
| 148 | .exit = intcp_flash_exit, | ||
| 149 | .set_vpp = intcp_flash_set_vpp, | ||
| 150 | }; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * It seems that the card insertion interrupt remains active after | 104 | * It seems that the card insertion interrupt remains active after |
| 154 | * we've acknowledged it. We therefore ignore the interrupt, and | 105 | * we've acknowledged it. We therefore ignore the interrupt, and |
| 155 | * rely on reading it from the SIC. This also means that we must | 106 | * rely on reading it from the SIC. This also means that we must |
| @@ -260,8 +211,6 @@ static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = { | |||
| 260 | "aaci", &mmc_data), | 211 | "aaci", &mmc_data), |
| 261 | OF_DEV_AUXDATA("arm,primecell", INTCP_PA_CLCD_BASE, | 212 | OF_DEV_AUXDATA("arm,primecell", INTCP_PA_CLCD_BASE, |
| 262 | "clcd", &clcd_data), | 213 | "clcd", &clcd_data), |
| 263 | OF_DEV_AUXDATA("cfi-flash", INTCP_PA_FLASH_BASE, | ||
| 264 | "physmap-flash", &intcp_flash_data), | ||
| 265 | { /* sentinel */ }, | 214 | { /* sentinel */ }, |
| 266 | }; | 215 | }; |
| 267 | 216 | ||
diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c index 9c2e38d30f47..a6e3c98b95ed 100644 --- a/arch/arm/mach-mediatek/mediatek.c +++ b/arch/arm/mach-mediatek/mediatek.c | |||
| @@ -29,6 +29,7 @@ static void __init mediatek_timer_init(void) | |||
| 29 | void __iomem *gpt_base; | 29 | void __iomem *gpt_base; |
| 30 | 30 | ||
| 31 | if (of_machine_is_compatible("mediatek,mt6589") || | 31 | if (of_machine_is_compatible("mediatek,mt6589") || |
| 32 | of_machine_is_compatible("mediatek,mt7623") || | ||
| 32 | of_machine_is_compatible("mediatek,mt8135") || | 33 | of_machine_is_compatible("mediatek,mt8135") || |
| 33 | of_machine_is_compatible("mediatek,mt8127")) { | 34 | of_machine_is_compatible("mediatek,mt8127")) { |
| 34 | /* turn on GPT6 which ungates arch timer clocks */ | 35 | /* turn on GPT6 which ungates arch timer clocks */ |
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index f2bc5c353119..fe4ccb52f921 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig | |||
| @@ -4,11 +4,6 @@ config ARCH_SHMOBILE | |||
| 4 | config ARCH_SHMOBILE_MULTI | 4 | config ARCH_SHMOBILE_MULTI |
| 5 | bool | 5 | bool |
| 6 | 6 | ||
| 7 | config PM_RCAR | ||
| 8 | bool | ||
| 9 | select PM | ||
| 10 | select PM_GENERIC_DOMAINS | ||
| 11 | |||
| 12 | config PM_RMOBILE | 7 | config PM_RMOBILE |
| 13 | bool | 8 | bool |
| 14 | select PM | 9 | select PM |
| @@ -16,13 +11,15 @@ config PM_RMOBILE | |||
| 16 | 11 | ||
| 17 | config ARCH_RCAR_GEN1 | 12 | config ARCH_RCAR_GEN1 |
| 18 | bool | 13 | bool |
| 19 | select PM_RCAR | 14 | select PM |
| 15 | select PM_GENERIC_DOMAINS | ||
| 20 | select RENESAS_INTC_IRQPIN | 16 | select RENESAS_INTC_IRQPIN |
| 21 | select SYS_SUPPORTS_SH_TMU | 17 | select SYS_SUPPORTS_SH_TMU |
| 22 | 18 | ||
| 23 | config ARCH_RCAR_GEN2 | 19 | config ARCH_RCAR_GEN2 |
| 24 | bool | 20 | bool |
| 25 | select PM_RCAR | 21 | select PM |
| 22 | select PM_GENERIC_DOMAINS | ||
| 26 | select RENESAS_IRQC | 23 | select RENESAS_IRQC |
| 27 | select SYS_SUPPORTS_SH_CMT | 24 | select SYS_SUPPORTS_SH_CMT |
| 28 | select PCI_DOMAINS if PCI | 25 | select PCI_DOMAINS if PCI |
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index c9ea0e6ff4f9..fc95f7bd2dd9 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile | |||
| @@ -38,7 +38,6 @@ smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o platsmp-scu.o | |||
| 38 | 38 | ||
| 39 | # PM objects | 39 | # PM objects |
| 40 | obj-$(CONFIG_SUSPEND) += suspend.o | 40 | obj-$(CONFIG_SUSPEND) += suspend.o |
| 41 | obj-$(CONFIG_PM_RCAR) += pm-rcar.o | ||
| 42 | obj-$(CONFIG_PM_RMOBILE) += pm-rmobile.o | 41 | obj-$(CONFIG_PM_RMOBILE) += pm-rmobile.o |
| 43 | obj-$(CONFIG_ARCH_RCAR_GEN2) += pm-rcar-gen2.o | 42 | obj-$(CONFIG_ARCH_RCAR_GEN2) += pm-rcar-gen2.o |
| 44 | 43 | ||
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c index 14c42a1bdf1e..4174cbcbc467 100644 --- a/arch/arm/mach-shmobile/pm-r8a7779.c +++ b/arch/arm/mach-shmobile/pm-r8a7779.c | |||
| @@ -9,9 +9,10 @@ | |||
| 9 | * for more details. | 9 | * for more details. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/soc/renesas/rcar-sysc.h> | ||
| 13 | |||
| 12 | #include <asm/io.h> | 14 | #include <asm/io.h> |
| 13 | 15 | ||
| 14 | #include "pm-rcar.h" | ||
| 15 | #include "r8a7779.h" | 16 | #include "r8a7779.h" |
| 16 | 17 | ||
| 17 | /* SYSC */ | 18 | /* SYSC */ |
diff --git a/arch/arm/mach-shmobile/pm-rcar-gen2.c b/arch/arm/mach-shmobile/pm-rcar-gen2.c index 6815781ad116..691ac166a277 100644 --- a/arch/arm/mach-shmobile/pm-rcar-gen2.c +++ b/arch/arm/mach-shmobile/pm-rcar-gen2.c | |||
| @@ -13,9 +13,9 @@ | |||
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
| 15 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
| 16 | #include <linux/soc/renesas/rcar-sysc.h> | ||
| 16 | #include <asm/io.h> | 17 | #include <asm/io.h> |
| 17 | #include "common.h" | 18 | #include "common.h" |
| 18 | #include "pm-rcar.h" | ||
| 19 | #include "rcar-gen2.h" | 19 | #include "rcar-gen2.h" |
| 20 | 20 | ||
| 21 | /* RST */ | 21 | /* RST */ |
diff --git a/arch/arm/mach-shmobile/pm-rcar.c b/arch/arm/mach-shmobile/pm-rcar.c deleted file mode 100644 index 0af05d288b09..000000000000 --- a/arch/arm/mach-shmobile/pm-rcar.c +++ /dev/null | |||
| @@ -1,164 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * R-Car SYSC Power management support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Magnus Damm | ||
| 5 | * | ||
| 6 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 7 | * License. See the file "COPYING" in the main directory of this archive | ||
| 8 | * for more details. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/err.h> | ||
| 13 | #include <linux/mm.h> | ||
| 14 | #include <linux/spinlock.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include "pm-rcar.h" | ||
| 17 | |||
| 18 | /* SYSC Common */ | ||
| 19 | #define SYSCSR 0x00 /* SYSC Status Register */ | ||
| 20 | #define SYSCISR 0x04 /* Interrupt Status Register */ | ||
| 21 | #define SYSCISCR 0x08 /* Interrupt Status Clear Register */ | ||
| 22 | #define SYSCIER 0x0c /* Interrupt Enable Register */ | ||
| 23 | #define SYSCIMR 0x10 /* Interrupt Mask Register */ | ||
| 24 | |||
| 25 | /* SYSC Status Register */ | ||
| 26 | #define SYSCSR_PONENB 1 /* Ready for power resume requests */ | ||
| 27 | #define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */ | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Power Control Register Offsets inside the register block for each domain | ||
| 31 | * Note: The "CR" registers for ARM cores exist on H1 only | ||
| 32 | * Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2 | ||
| 33 | */ | ||
| 34 | #define PWRSR_OFFS 0x00 /* Power Status Register */ | ||
| 35 | #define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */ | ||
| 36 | #define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */ | ||
| 37 | #define PWRONCR_OFFS 0x0c /* Power Resume Control Register */ | ||
| 38 | #define PWRONSR_OFFS 0x10 /* Power Resume Status Register */ | ||
| 39 | #define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ | ||
| 40 | |||
| 41 | |||
| 42 | #define SYSCSR_RETRIES 100 | ||
| 43 | #define SYSCSR_DELAY_US 1 | ||
| 44 | |||
| 45 | #define PWRER_RETRIES 100 | ||
| 46 | #define PWRER_DELAY_US 1 | ||
| 47 | |||
| 48 | #define SYSCISR_RETRIES 1000 | ||
| 49 | #define SYSCISR_DELAY_US 1 | ||
| 50 | |||
| 51 | static void __iomem *rcar_sysc_base; | ||
| 52 | static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */ | ||
| 53 | |||
| 54 | static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) | ||
| 55 | { | ||
| 56 | unsigned int sr_bit, reg_offs; | ||
| 57 | int k; | ||
| 58 | |||
| 59 | if (on) { | ||
| 60 | sr_bit = SYSCSR_PONENB; | ||
| 61 | reg_offs = PWRONCR_OFFS; | ||
| 62 | } else { | ||
| 63 | sr_bit = SYSCSR_POFFENB; | ||
| 64 | reg_offs = PWROFFCR_OFFS; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* Wait until SYSC is ready to accept a power request */ | ||
| 68 | for (k = 0; k < SYSCSR_RETRIES; k++) { | ||
| 69 | if (ioread32(rcar_sysc_base + SYSCSR) & BIT(sr_bit)) | ||
| 70 | break; | ||
| 71 | udelay(SYSCSR_DELAY_US); | ||
| 72 | } | ||
| 73 | |||
| 74 | if (k == SYSCSR_RETRIES) | ||
| 75 | return -EAGAIN; | ||
| 76 | |||
| 77 | /* Submit power shutoff or power resume request */ | ||
| 78 | iowrite32(BIT(sysc_ch->chan_bit), | ||
| 79 | rcar_sysc_base + sysc_ch->chan_offs + reg_offs); | ||
| 80 | |||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) | ||
| 85 | { | ||
| 86 | unsigned int isr_mask = BIT(sysc_ch->isr_bit); | ||
| 87 | unsigned int chan_mask = BIT(sysc_ch->chan_bit); | ||
| 88 | unsigned int status; | ||
| 89 | unsigned long flags; | ||
| 90 | int ret = 0; | ||
| 91 | int k; | ||
| 92 | |||
| 93 | spin_lock_irqsave(&rcar_sysc_lock, flags); | ||
| 94 | |||
| 95 | iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); | ||
| 96 | |||
| 97 | /* Submit power shutoff or resume request until it was accepted */ | ||
| 98 | for (k = 0; k < PWRER_RETRIES; k++) { | ||
| 99 | ret = rcar_sysc_pwr_on_off(sysc_ch, on); | ||
| 100 | if (ret) | ||
| 101 | goto out; | ||
| 102 | |||
| 103 | status = ioread32(rcar_sysc_base + | ||
| 104 | sysc_ch->chan_offs + PWRER_OFFS); | ||
| 105 | if (!(status & chan_mask)) | ||
| 106 | break; | ||
| 107 | |||
| 108 | udelay(PWRER_DELAY_US); | ||
| 109 | } | ||
| 110 | |||
| 111 | if (k == PWRER_RETRIES) { | ||
| 112 | ret = -EIO; | ||
| 113 | goto out; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* Wait until the power shutoff or resume request has completed * */ | ||
| 117 | for (k = 0; k < SYSCISR_RETRIES; k++) { | ||
| 118 | if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask) | ||
| 119 | break; | ||
| 120 | udelay(SYSCISR_DELAY_US); | ||
| 121 | } | ||
| 122 | |||
| 123 | if (k == SYSCISR_RETRIES) | ||
| 124 | ret = -EIO; | ||
| 125 | |||
| 126 | iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); | ||
| 127 | |||
| 128 | out: | ||
| 129 | spin_unlock_irqrestore(&rcar_sysc_lock, flags); | ||
| 130 | |||
| 131 | pr_debug("sysc power domain %d: %08x -> %d\n", | ||
| 132 | sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret); | ||
| 133 | return ret; | ||
| 134 | } | ||
| 135 | |||
| 136 | int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) | ||
| 137 | { | ||
| 138 | return rcar_sysc_power(sysc_ch, false); | ||
| 139 | } | ||
| 140 | |||
| 141 | int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) | ||
| 142 | { | ||
| 143 | return rcar_sysc_power(sysc_ch, true); | ||
| 144 | } | ||
| 145 | |||
| 146 | bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch) | ||
| 147 | { | ||
| 148 | unsigned int st; | ||
| 149 | |||
| 150 | st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS); | ||
| 151 | if (st & BIT(sysc_ch->chan_bit)) | ||
| 152 | return true; | ||
| 153 | |||
| 154 | return false; | ||
| 155 | } | ||
| 156 | |||
| 157 | void __iomem *rcar_sysc_init(phys_addr_t base) | ||
| 158 | { | ||
| 159 | rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE); | ||
| 160 | if (!rcar_sysc_base) | ||
| 161 | panic("unable to ioremap R-Car SYSC hardware block\n"); | ||
| 162 | |||
| 163 | return rcar_sysc_base; | ||
| 164 | } | ||
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index f5c31fbc10b2..c6951ee24588 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c | |||
| @@ -19,13 +19,13 @@ | |||
| 19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
| 20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
| 21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
| 22 | #include <linux/soc/renesas/rcar-sysc.h> | ||
| 22 | 23 | ||
| 23 | #include <asm/cacheflush.h> | 24 | #include <asm/cacheflush.h> |
| 24 | #include <asm/smp_plat.h> | 25 | #include <asm/smp_plat.h> |
| 25 | #include <asm/smp_scu.h> | 26 | #include <asm/smp_scu.h> |
| 26 | 27 | ||
| 27 | #include "common.h" | 28 | #include "common.h" |
| 28 | #include "pm-rcar.h" | ||
| 29 | #include "r8a7779.h" | 29 | #include "r8a7779.h" |
| 30 | 30 | ||
| 31 | #define AVECR IOMEM(0xfe700040) | 31 | #define AVECR IOMEM(0xfe700040) |
diff --git a/arch/arm/mach-shmobile/smp-r8a7790.c b/arch/arm/mach-shmobile/smp-r8a7790.c index f6426c6fdefc..28f26d5362d8 100644 --- a/arch/arm/mach-shmobile/smp-r8a7790.c +++ b/arch/arm/mach-shmobile/smp-r8a7790.c | |||
| @@ -17,12 +17,12 @@ | |||
| 17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 18 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
| 19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
| 20 | #include <linux/soc/renesas/rcar-sysc.h> | ||
| 20 | 21 | ||
| 21 | #include <asm/smp_plat.h> | 22 | #include <asm/smp_plat.h> |
| 22 | 23 | ||
| 23 | #include "common.h" | 24 | #include "common.h" |
| 24 | #include "platsmp-apmu.h" | 25 | #include "platsmp-apmu.h" |
| 25 | #include "pm-rcar.h" | ||
| 26 | #include "rcar-gen2.h" | 26 | #include "rcar-gen2.h" |
| 27 | #include "r8a7790.h" | 27 | #include "r8a7790.h" |
| 28 | 28 | ||
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index f3f61dbbda97..75620ae73913 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c | |||
| @@ -108,19 +108,9 @@ static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
| 108 | * be un-gated by un-toggling the power gate register | 108 | * be un-gated by un-toggling the power gate register |
| 109 | * manually. | 109 | * manually. |
| 110 | */ | 110 | */ |
| 111 | if (!tegra_pmc_cpu_is_powered(cpu)) { | 111 | ret = tegra_pmc_cpu_power_on(cpu); |
| 112 | ret = tegra_pmc_cpu_power_on(cpu); | 112 | if (ret) |
| 113 | if (ret) | 113 | return ret; |
| 114 | return ret; | ||
| 115 | |||
| 116 | /* Wait for the power to come up. */ | ||
| 117 | timeout = jiffies + msecs_to_jiffies(100); | ||
| 118 | while (!tegra_pmc_cpu_is_powered(cpu)) { | ||
| 119 | if (time_after(jiffies, timeout)) | ||
| 120 | return -ETIMEDOUT; | ||
| 121 | udelay(10); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | 114 | ||
| 125 | remove_clamps: | 115 | remove_clamps: |
| 126 | /* CPU partition is powered. Enable the CPU clock. */ | 116 | /* CPU partition is powered. Enable the CPU clock. */ |
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c index dff1c0595b67..d643b9210dbd 100644 --- a/arch/arm/mach-versatile/versatile_dt.c +++ b/arch/arm/mach-versatile/versatile_dt.c | |||
| @@ -32,7 +32,6 @@ | |||
| 32 | #include <linux/amba/clcd.h> | 32 | #include <linux/amba/clcd.h> |
| 33 | #include <linux/platform_data/video-clcd-versatile.h> | 33 | #include <linux/platform_data/video-clcd-versatile.h> |
| 34 | #include <linux/amba/mmci.h> | 34 | #include <linux/amba/mmci.h> |
| 35 | #include <linux/mtd/physmap.h> | ||
| 36 | #include <asm/mach-types.h> | 35 | #include <asm/mach-types.h> |
| 37 | #include <asm/mach/arch.h> | 36 | #include <asm/mach/arch.h> |
| 38 | #include <asm/mach/map.h> | 37 | #include <asm/mach/map.h> |
| @@ -42,27 +41,15 @@ | |||
| 42 | #define __io_address(n) ((void __iomem __force *)IO_ADDRESS(n)) | 41 | #define __io_address(n) ((void __iomem __force *)IO_ADDRESS(n)) |
| 43 | 42 | ||
| 44 | /* | 43 | /* |
| 45 | * Memory definitions | ||
| 46 | */ | ||
| 47 | #define VERSATILE_FLASH_BASE 0x34000000 | ||
| 48 | #define VERSATILE_FLASH_SIZE SZ_64M | ||
| 49 | |||
| 50 | /* | ||
| 51 | * ------------------------------------------------------------------------ | 44 | * ------------------------------------------------------------------------ |
| 52 | * Versatile Registers | 45 | * Versatile Registers |
| 53 | * ------------------------------------------------------------------------ | 46 | * ------------------------------------------------------------------------ |
| 54 | */ | 47 | */ |
| 55 | #define VERSATILE_SYS_PCICTL_OFFSET 0x44 | 48 | #define VERSATILE_SYS_PCICTL_OFFSET 0x44 |
| 56 | #define VERSATILE_SYS_MCI_OFFSET 0x48 | 49 | #define VERSATILE_SYS_MCI_OFFSET 0x48 |
| 57 | #define VERSATILE_SYS_FLASH_OFFSET 0x4C | ||
| 58 | #define VERSATILE_SYS_CLCD_OFFSET 0x50 | 50 | #define VERSATILE_SYS_CLCD_OFFSET 0x50 |
| 59 | 51 | ||
| 60 | /* | 52 | /* |
| 61 | * VERSATILE_SYS_FLASH | ||
| 62 | */ | ||
| 63 | #define VERSATILE_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */ | ||
| 64 | |||
| 65 | /* | ||
| 66 | * VERSATILE peripheral addresses | 53 | * VERSATILE peripheral addresses |
| 67 | */ | 54 | */ |
| 68 | #define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */ | 55 | #define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */ |
| @@ -86,39 +73,6 @@ | |||
| 86 | static void __iomem *versatile_sys_base; | 73 | static void __iomem *versatile_sys_base; |
| 87 | static void __iomem *versatile_ib2_ctrl; | 74 | static void __iomem *versatile_ib2_ctrl; |
| 88 | 75 | ||
| 89 | static void versatile_flash_set_vpp(struct platform_device *pdev, int on) | ||
| 90 | { | ||
| 91 | u32 val; | ||
| 92 | |||
| 93 | val = readl(versatile_sys_base + VERSATILE_SYS_FLASH_OFFSET); | ||
| 94 | if (on) | ||
| 95 | val |= VERSATILE_FLASHPROG_FLVPPEN; | ||
| 96 | else | ||
| 97 | val &= ~VERSATILE_FLASHPROG_FLVPPEN; | ||
| 98 | writel(val, versatile_sys_base + VERSATILE_SYS_FLASH_OFFSET); | ||
| 99 | } | ||
| 100 | |||
| 101 | static struct physmap_flash_data versatile_flash_data = { | ||
| 102 | .width = 4, | ||
| 103 | .set_vpp = versatile_flash_set_vpp, | ||
| 104 | }; | ||
| 105 | |||
| 106 | static struct resource versatile_flash_resource = { | ||
| 107 | .start = VERSATILE_FLASH_BASE, | ||
| 108 | .end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE - 1, | ||
| 109 | .flags = IORESOURCE_MEM, | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct platform_device versatile_flash_device = { | ||
| 113 | .name = "physmap-flash", | ||
| 114 | .id = 0, | ||
| 115 | .dev = { | ||
| 116 | .platform_data = &versatile_flash_data, | ||
| 117 | }, | ||
| 118 | .num_resources = 1, | ||
| 119 | .resource = &versatile_flash_resource, | ||
| 120 | }; | ||
| 121 | |||
| 122 | unsigned int mmc_status(struct device *dev) | 76 | unsigned int mmc_status(struct device *dev) |
| 123 | { | 77 | { |
| 124 | struct amba_device *adev = container_of(dev, struct amba_device, dev); | 78 | struct amba_device *adev = container_of(dev, struct amba_device, dev); |
| @@ -390,7 +344,6 @@ static void __init versatile_dt_init(void) | |||
| 390 | 344 | ||
| 391 | versatile_dt_pci_init(); | 345 | versatile_dt_pci_init(); |
| 392 | 346 | ||
| 393 | platform_device_register(&versatile_flash_device); | ||
| 394 | of_platform_populate(NULL, of_default_bus_match_table, | 347 | of_platform_populate(NULL, of_default_bus_match_table, |
| 395 | versatile_auxdata_lookup, NULL); | 348 | versatile_auxdata_lookup, NULL); |
| 396 | } | 349 | } |
diff --git a/arch/arm/plat-samsung/include/plat/map-s5p.h b/arch/arm/plat-samsung/include/plat/map-s5p.h index 4ec9a7050185..b63aeebb93f3 100644 --- a/arch/arm/plat-samsung/include/plat/map-s5p.h +++ b/arch/arm/plat-samsung/include/plat/map-s5p.h | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | #define S5P_VA_DMC0 S3C_ADDR(0x02440000) | 19 | #define S5P_VA_DMC0 S3C_ADDR(0x02440000) |
| 20 | #define S5P_VA_DMC1 S3C_ADDR(0x02480000) | 20 | #define S5P_VA_DMC1 S3C_ADDR(0x02480000) |
| 21 | #define S5P_VA_SROMC S3C_ADDR(0x024C0000) | ||
| 22 | 21 | ||
| 23 | #define S5P_VA_COREPERI_BASE S3C_ADDR(0x02800000) | 22 | #define S5P_VA_COREPERI_BASE S3C_ADDR(0x02800000) |
| 24 | #define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x)) | 23 | #define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x)) |
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"); | ||
diff --git a/include/dt-bindings/power/rk3399-power.h b/include/dt-bindings/power/rk3399-power.h new file mode 100644 index 000000000000..168b3bfbd6f5 --- /dev/null +++ b/include/dt-bindings/power/rk3399-power.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | #ifndef __DT_BINDINGS_POWER_RK3399_POWER_H__ | ||
| 2 | #define __DT_BINDINGS_POWER_RK3399_POWER_H__ | ||
| 3 | |||
| 4 | /* VD_CORE_L */ | ||
| 5 | #define RK3399_PD_A53_L0 0 | ||
| 6 | #define RK3399_PD_A53_L1 1 | ||
| 7 | #define RK3399_PD_A53_L2 2 | ||
| 8 | #define RK3399_PD_A53_L3 3 | ||
| 9 | #define RK3399_PD_SCU_L 4 | ||
| 10 | |||
| 11 | /* VD_CORE_B */ | ||
| 12 | #define RK3399_PD_A72_B0 5 | ||
| 13 | #define RK3399_PD_A72_B1 6 | ||
| 14 | #define RK3399_PD_SCU_B 7 | ||
| 15 | |||
| 16 | /* VD_LOGIC */ | ||
| 17 | #define RK3399_PD_TCPD0 8 | ||
| 18 | #define RK3399_PD_TCPD1 9 | ||
| 19 | #define RK3399_PD_CCI 10 | ||
| 20 | #define RK3399_PD_CCI0 11 | ||
| 21 | #define RK3399_PD_CCI1 12 | ||
| 22 | #define RK3399_PD_PERILP 13 | ||
| 23 | #define RK3399_PD_PERIHP 14 | ||
| 24 | #define RK3399_PD_VIO 15 | ||
| 25 | #define RK3399_PD_VO 16 | ||
| 26 | #define RK3399_PD_VOPB 17 | ||
| 27 | #define RK3399_PD_VOPL 18 | ||
| 28 | #define RK3399_PD_ISP0 19 | ||
| 29 | #define RK3399_PD_ISP1 20 | ||
| 30 | #define RK3399_PD_HDCP 21 | ||
| 31 | #define RK3399_PD_GMAC 22 | ||
| 32 | #define RK3399_PD_EMMC 23 | ||
| 33 | #define RK3399_PD_USB3 24 | ||
| 34 | #define RK3399_PD_EDP 25 | ||
| 35 | #define RK3399_PD_GIC 26 | ||
| 36 | #define RK3399_PD_SD 27 | ||
| 37 | #define RK3399_PD_SDIOAUDIO 28 | ||
| 38 | #define RK3399_PD_ALIVE 29 | ||
| 39 | |||
| 40 | /* VD_CENTER */ | ||
| 41 | #define RK3399_PD_CENTER 30 | ||
| 42 | #define RK3399_PD_VCODEC 31 | ||
| 43 | #define RK3399_PD_VDU 32 | ||
| 44 | #define RK3399_PD_RGA 33 | ||
| 45 | #define RK3399_PD_IEP 34 | ||
| 46 | |||
| 47 | /* VD_GPU */ | ||
| 48 | #define RK3399_PD_GPU 35 | ||
| 49 | |||
| 50 | /* VD_PMU */ | ||
| 51 | #define RK3399_PD_PMU 36 | ||
| 52 | |||
| 53 | #endif | ||
diff --git a/include/linux/clk/renesas.h b/include/linux/clk/renesas.h index 7adfd80fbf55..ba6fa4148515 100644 --- a/include/linux/clk/renesas.h +++ b/include/linux/clk/renesas.h | |||
| @@ -24,12 +24,20 @@ void r8a7778_clocks_init(u32 mode); | |||
| 24 | void r8a7779_clocks_init(u32 mode); | 24 | void r8a7779_clocks_init(u32 mode); |
| 25 | void rcar_gen2_clocks_init(u32 mode); | 25 | void rcar_gen2_clocks_init(u32 mode); |
| 26 | 26 | ||
| 27 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF | ||
| 28 | void cpg_mstp_add_clk_domain(struct device_node *np); | 27 | void cpg_mstp_add_clk_domain(struct device_node *np); |
| 29 | int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev); | 28 | #ifdef CONFIG_CLK_RENESAS_CPG_MSTP |
| 30 | void cpg_mstp_detach_dev(struct generic_pm_domain *domain, struct device *dev); | 29 | int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev); |
| 30 | void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev); | ||
| 31 | #else | 31 | #else |
| 32 | static inline void cpg_mstp_add_clk_domain(struct device_node *np) {} | 32 | #define cpg_mstp_attach_dev NULL |
| 33 | #define cpg_mstp_detach_dev NULL | ||
| 33 | #endif | 34 | #endif |
| 34 | 35 | ||
| 36 | #ifdef CONFIG_CLK_RENESAS_CPG_MSSR | ||
| 37 | int cpg_mssr_attach_dev(struct generic_pm_domain *unused, struct device *dev); | ||
| 38 | void cpg_mssr_detach_dev(struct generic_pm_domain *unused, struct device *dev); | ||
| 39 | #else | ||
| 40 | #define cpg_mssr_attach_dev NULL | ||
| 41 | #define cpg_mssr_detach_dev NULL | ||
| 42 | #endif | ||
| 35 | #endif | 43 | #endif |
diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 57bf7aab4516..7007a5f48080 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h | |||
| @@ -121,4 +121,9 @@ static inline void tegra_cpu_clock_resume(void) | |||
| 121 | } | 121 | } |
| 122 | #endif | 122 | #endif |
| 123 | 123 | ||
| 124 | extern void tegra210_xusb_pll_hw_control_enable(void); | ||
| 125 | extern void tegra210_xusb_pll_hw_sequence_start(void); | ||
| 126 | extern void tegra210_sata_pll_hw_control_enable(void); | ||
| 127 | extern void tegra210_sata_pll_hw_sequence_start(void); | ||
| 128 | |||
| 124 | #endif /* __LINUX_CLK_TEGRA_H_ */ | 129 | #endif /* __LINUX_CLK_TEGRA_H_ */ |
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 8cf05e341cff..a810f2a18842 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h | |||
| @@ -77,6 +77,7 @@ struct phy { | |||
| 77 | */ | 77 | */ |
| 78 | struct phy_provider { | 78 | struct phy_provider { |
| 79 | struct device *dev; | 79 | struct device *dev; |
| 80 | struct device_node *children; | ||
| 80 | struct module *owner; | 81 | struct module *owner; |
| 81 | struct list_head list; | 82 | struct list_head list; |
| 82 | struct phy * (*of_xlate)(struct device *dev, | 83 | struct phy * (*of_xlate)(struct device *dev, |
| @@ -93,10 +94,16 @@ struct phy_lookup { | |||
| 93 | #define to_phy(a) (container_of((a), struct phy, dev)) | 94 | #define to_phy(a) (container_of((a), struct phy, dev)) |
| 94 | 95 | ||
| 95 | #define of_phy_provider_register(dev, xlate) \ | 96 | #define of_phy_provider_register(dev, xlate) \ |
| 96 | __of_phy_provider_register((dev), THIS_MODULE, (xlate)) | 97 | __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate)) |
| 97 | 98 | ||
| 98 | #define devm_of_phy_provider_register(dev, xlate) \ | 99 | #define devm_of_phy_provider_register(dev, xlate) \ |
| 99 | __devm_of_phy_provider_register((dev), THIS_MODULE, (xlate)) | 100 | __devm_of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate)) |
| 101 | |||
| 102 | #define of_phy_provider_register_full(dev, children, xlate) \ | ||
| 103 | __of_phy_provider_register(dev, children, THIS_MODULE, xlate) | ||
| 104 | |||
| 105 | #define devm_of_phy_provider_register_full(dev, children, xlate) \ | ||
| 106 | __devm_of_phy_provider_register(dev, children, THIS_MODULE, xlate) | ||
| 100 | 107 | ||
| 101 | static inline void phy_set_drvdata(struct phy *phy, void *data) | 108 | static inline void phy_set_drvdata(struct phy *phy, void *data) |
| 102 | { | 109 | { |
| @@ -147,11 +154,13 @@ struct phy *devm_phy_create(struct device *dev, struct device_node *node, | |||
| 147 | void phy_destroy(struct phy *phy); | 154 | void phy_destroy(struct phy *phy); |
| 148 | void devm_phy_destroy(struct device *dev, struct phy *phy); | 155 | void devm_phy_destroy(struct device *dev, struct phy *phy); |
| 149 | struct phy_provider *__of_phy_provider_register(struct device *dev, | 156 | struct phy_provider *__of_phy_provider_register(struct device *dev, |
| 150 | struct module *owner, struct phy * (*of_xlate)(struct device *dev, | 157 | struct device_node *children, struct module *owner, |
| 151 | struct of_phandle_args *args)); | 158 | struct phy * (*of_xlate)(struct device *dev, |
| 159 | struct of_phandle_args *args)); | ||
| 152 | struct phy_provider *__devm_of_phy_provider_register(struct device *dev, | 160 | struct phy_provider *__devm_of_phy_provider_register(struct device *dev, |
| 153 | struct module *owner, struct phy * (*of_xlate)(struct device *dev, | 161 | struct device_node *children, struct module *owner, |
| 154 | struct of_phandle_args *args)); | 162 | struct phy * (*of_xlate)(struct device *dev, |
| 163 | struct of_phandle_args *args)); | ||
| 155 | void of_phy_provider_unregister(struct phy_provider *phy_provider); | 164 | void of_phy_provider_unregister(struct phy_provider *phy_provider); |
| 156 | void devm_of_phy_provider_unregister(struct device *dev, | 165 | void devm_of_phy_provider_unregister(struct device *dev, |
| 157 | struct phy_provider *phy_provider); | 166 | struct phy_provider *phy_provider); |
| @@ -312,15 +321,17 @@ static inline void devm_phy_destroy(struct device *dev, struct phy *phy) | |||
| 312 | } | 321 | } |
| 313 | 322 | ||
| 314 | static inline struct phy_provider *__of_phy_provider_register( | 323 | static inline struct phy_provider *__of_phy_provider_register( |
| 315 | struct device *dev, struct module *owner, struct phy * (*of_xlate)( | 324 | struct device *dev, struct device_node *children, struct module *owner, |
| 316 | struct device *dev, struct of_phandle_args *args)) | 325 | struct phy * (*of_xlate)(struct device *dev, |
| 326 | struct of_phandle_args *args)) | ||
| 317 | { | 327 | { |
| 318 | return ERR_PTR(-ENOSYS); | 328 | return ERR_PTR(-ENOSYS); |
| 319 | } | 329 | } |
| 320 | 330 | ||
| 321 | static inline struct phy_provider *__devm_of_phy_provider_register(struct device | 331 | static inline struct phy_provider *__devm_of_phy_provider_register(struct device |
| 322 | *dev, struct module *owner, struct phy * (*of_xlate)(struct device *dev, | 332 | *dev, struct device_node *children, struct module *owner, |
| 323 | struct of_phandle_args *args)) | 333 | struct phy * (*of_xlate)(struct device *dev, |
| 334 | struct of_phandle_args *args)) | ||
| 324 | { | 335 | { |
| 325 | return ERR_PTR(-ENOSYS); | 336 | return ERR_PTR(-ENOSYS); |
| 326 | } | 337 | } |
diff --git a/include/linux/phy/tegra/xusb.h b/include/linux/phy/tegra/xusb.h new file mode 100644 index 000000000000..8e1a57a78d9f --- /dev/null +++ b/include/linux/phy/tegra/xusb.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2016, 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 | #ifndef PHY_TEGRA_XUSB_H | ||
| 15 | #define PHY_TEGRA_XUSB_H | ||
| 16 | |||
| 17 | struct tegra_xusb_padctl; | ||
| 18 | struct device; | ||
| 19 | |||
| 20 | struct tegra_xusb_padctl *tegra_xusb_padctl_get(struct device *dev); | ||
| 21 | void tegra_xusb_padctl_put(struct tegra_xusb_padctl *padctl); | ||
| 22 | |||
| 23 | int tegra_xusb_padctl_usb3_save_context(struct tegra_xusb_padctl *padctl, | ||
| 24 | unsigned int port); | ||
| 25 | int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl, | ||
| 26 | unsigned int port, bool idle); | ||
| 27 | int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl, | ||
| 28 | unsigned int port, bool enable); | ||
| 29 | |||
| 30 | #endif /* PHY_TEGRA_XUSB_H */ | ||
diff --git a/include/linux/psci.h b/include/linux/psci.h index 393efe2edf9a..bdea1cb5e1db 100644 --- a/include/linux/psci.h +++ b/include/linux/psci.h | |||
| @@ -21,8 +21,6 @@ | |||
| 21 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 | 21 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 |
| 22 | 22 | ||
| 23 | bool psci_tos_resident_on(int cpu); | 23 | bool psci_tos_resident_on(int cpu); |
| 24 | bool psci_power_state_loses_context(u32 state); | ||
| 25 | bool psci_power_state_is_valid(u32 state); | ||
| 26 | 24 | ||
| 27 | int psci_cpu_init_idle(unsigned int cpu); | 25 | int psci_cpu_init_idle(unsigned int cpu); |
| 28 | int psci_cpu_suspend_enter(unsigned long index); | 26 | int psci_cpu_suspend_enter(unsigned long index); |
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h index a3a5bcdb1d02..b91ba932bbd4 100644 --- a/include/linux/reset-controller.h +++ b/include/linux/reset-controller.h | |||
| @@ -31,6 +31,7 @@ struct of_phandle_args; | |||
| 31 | * @ops: a pointer to device specific struct reset_control_ops | 31 | * @ops: a pointer to device specific struct reset_control_ops |
| 32 | * @owner: kernel module of the reset controller driver | 32 | * @owner: kernel module of the reset controller driver |
| 33 | * @list: internal list of reset controller devices | 33 | * @list: internal list of reset controller devices |
| 34 | * @reset_control_head: head of internal list of requested reset controls | ||
| 34 | * @of_node: corresponding device tree node as phandle target | 35 | * @of_node: corresponding device tree node as phandle target |
| 35 | * @of_reset_n_cells: number of cells in reset line specifiers | 36 | * @of_reset_n_cells: number of cells in reset line specifiers |
| 36 | * @of_xlate: translation function to translate from specifier as found in the | 37 | * @of_xlate: translation function to translate from specifier as found in the |
| @@ -41,6 +42,7 @@ struct reset_controller_dev { | |||
| 41 | const struct reset_control_ops *ops; | 42 | const struct reset_control_ops *ops; |
| 42 | struct module *owner; | 43 | struct module *owner; |
| 43 | struct list_head list; | 44 | struct list_head list; |
| 45 | struct list_head reset_control_head; | ||
| 44 | struct device_node *of_node; | 46 | struct device_node *of_node; |
| 45 | int of_reset_n_cells; | 47 | int of_reset_n_cells; |
| 46 | int (*of_xlate)(struct reset_controller_dev *rcdev, | 48 | int (*of_xlate)(struct reset_controller_dev *rcdev, |
diff --git a/include/linux/reset.h b/include/linux/reset.h index c4c097de0ba9..ec0306ce7b92 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | #ifndef _LINUX_RESET_H_ | 1 | #ifndef _LINUX_RESET_H_ |
| 2 | #define _LINUX_RESET_H_ | 2 | #define _LINUX_RESET_H_ |
| 3 | 3 | ||
| 4 | struct device; | 4 | #include <linux/device.h> |
| 5 | struct device_node; | 5 | |
| 6 | struct reset_control; | 6 | struct reset_control; |
| 7 | 7 | ||
| 8 | #ifdef CONFIG_RESET_CONTROLLER | 8 | #ifdef CONFIG_RESET_CONTROLLER |
| @@ -12,9 +12,11 @@ int reset_control_assert(struct reset_control *rstc); | |||
| 12 | int reset_control_deassert(struct reset_control *rstc); | 12 | int reset_control_deassert(struct reset_control *rstc); |
| 13 | int reset_control_status(struct reset_control *rstc); | 13 | int reset_control_status(struct reset_control *rstc); |
| 14 | 14 | ||
| 15 | struct reset_control *reset_control_get(struct device *dev, const char *id); | 15 | struct reset_control *__of_reset_control_get(struct device_node *node, |
| 16 | const char *id, int index, int shared); | ||
| 16 | void reset_control_put(struct reset_control *rstc); | 17 | void reset_control_put(struct reset_control *rstc); |
| 17 | struct reset_control *devm_reset_control_get(struct device *dev, const char *id); | 18 | struct reset_control *__devm_reset_control_get(struct device *dev, |
| 19 | const char *id, int index, int shared); | ||
| 18 | 20 | ||
| 19 | int __must_check device_reset(struct device *dev); | 21 | int __must_check device_reset(struct device *dev); |
| 20 | 22 | ||
| @@ -23,24 +25,6 @@ static inline int device_reset_optional(struct device *dev) | |||
| 23 | return device_reset(dev); | 25 | return device_reset(dev); |
| 24 | } | 26 | } |
| 25 | 27 | ||
| 26 | static inline struct reset_control *reset_control_get_optional( | ||
| 27 | struct device *dev, const char *id) | ||
| 28 | { | ||
| 29 | return reset_control_get(dev, id); | ||
| 30 | } | ||
| 31 | |||
| 32 | static inline struct reset_control *devm_reset_control_get_optional( | ||
| 33 | struct device *dev, const char *id) | ||
| 34 | { | ||
| 35 | return devm_reset_control_get(dev, id); | ||
| 36 | } | ||
| 37 | |||
| 38 | struct reset_control *of_reset_control_get(struct device_node *node, | ||
| 39 | const char *id); | ||
| 40 | |||
| 41 | struct reset_control *of_reset_control_get_by_index( | ||
| 42 | struct device_node *node, int index); | ||
| 43 | |||
| 44 | #else | 28 | #else |
| 45 | 29 | ||
| 46 | static inline int reset_control_reset(struct reset_control *rstc) | 30 | static inline int reset_control_reset(struct reset_control *rstc) |
| @@ -72,49 +56,191 @@ static inline void reset_control_put(struct reset_control *rstc) | |||
| 72 | WARN_ON(1); | 56 | WARN_ON(1); |
| 73 | } | 57 | } |
| 74 | 58 | ||
| 59 | static inline int __must_check device_reset(struct device *dev) | ||
| 60 | { | ||
| 61 | WARN_ON(1); | ||
| 62 | return -ENOTSUPP; | ||
| 63 | } | ||
| 64 | |||
| 75 | static inline int device_reset_optional(struct device *dev) | 65 | static inline int device_reset_optional(struct device *dev) |
| 76 | { | 66 | { |
| 77 | return -ENOTSUPP; | 67 | return -ENOTSUPP; |
| 78 | } | 68 | } |
| 79 | 69 | ||
| 80 | static inline struct reset_control *__must_check reset_control_get( | 70 | static inline struct reset_control *__of_reset_control_get( |
| 81 | struct device *dev, const char *id) | 71 | struct device_node *node, |
| 72 | const char *id, int index, int shared) | ||
| 82 | { | 73 | { |
| 83 | WARN_ON(1); | ||
| 84 | return ERR_PTR(-EINVAL); | 74 | return ERR_PTR(-EINVAL); |
| 85 | } | 75 | } |
| 86 | 76 | ||
| 87 | static inline struct reset_control *__must_check devm_reset_control_get( | 77 | static inline struct reset_control *__devm_reset_control_get( |
| 78 | struct device *dev, | ||
| 79 | const char *id, int index, int shared) | ||
| 80 | { | ||
| 81 | return ERR_PTR(-EINVAL); | ||
| 82 | } | ||
| 83 | |||
| 84 | #endif /* CONFIG_RESET_CONTROLLER */ | ||
| 85 | |||
| 86 | /** | ||
| 87 | * reset_control_get - Lookup and obtain an exclusive reference to a | ||
| 88 | * reset controller. | ||
| 89 | * @dev: device to be reset by the controller | ||
| 90 | * @id: reset line name | ||
| 91 | * | ||
| 92 | * Returns a struct reset_control or IS_ERR() condition containing errno. | ||
| 93 | * If this function is called more then once for the same reset_control it will | ||
| 94 | * return -EBUSY. | ||
| 95 | * | ||
| 96 | * See reset_control_get_shared for details on shared references to | ||
| 97 | * reset-controls. | ||
| 98 | * | ||
| 99 | * Use of id names is optional. | ||
| 100 | */ | ||
| 101 | static inline struct reset_control *__must_check reset_control_get( | ||
| 88 | struct device *dev, const char *id) | 102 | struct device *dev, const char *id) |
| 89 | { | 103 | { |
| 104 | #ifndef CONFIG_RESET_CONTROLLER | ||
| 90 | WARN_ON(1); | 105 | WARN_ON(1); |
| 91 | return ERR_PTR(-EINVAL); | 106 | #endif |
| 107 | return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0); | ||
| 92 | } | 108 | } |
| 93 | 109 | ||
| 94 | static inline struct reset_control *reset_control_get_optional( | 110 | static inline struct reset_control *reset_control_get_optional( |
| 95 | struct device *dev, const char *id) | 111 | struct device *dev, const char *id) |
| 96 | { | 112 | { |
| 97 | return ERR_PTR(-ENOTSUPP); | 113 | return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0); |
| 98 | } | 114 | } |
| 99 | 115 | ||
| 100 | static inline struct reset_control *devm_reset_control_get_optional( | 116 | /** |
| 117 | * reset_control_get_shared - Lookup and obtain a shared reference to a | ||
| 118 | * reset controller. | ||
| 119 | * @dev: device to be reset by the controller | ||
| 120 | * @id: reset line name | ||
| 121 | * | ||
| 122 | * Returns a struct reset_control or IS_ERR() condition containing errno. | ||
| 123 | * This function is intended for use with reset-controls which are shared | ||
| 124 | * between hardware-blocks. | ||
| 125 | * | ||
| 126 | * When a reset-control is shared, the behavior of reset_control_assert / | ||
| 127 | * deassert is changed, the reset-core will keep track of a deassert_count | ||
| 128 | * and only (re-)assert the reset after reset_control_assert has been called | ||
| 129 | * as many times as reset_control_deassert was called. Also see the remark | ||
| 130 | * about shared reset-controls in the reset_control_assert docs. | ||
| 131 | * | ||
| 132 | * Calling reset_control_assert without first calling reset_control_deassert | ||
| 133 | * is not allowed on a shared reset control. Calling reset_control_reset is | ||
| 134 | * also not allowed on a shared reset control. | ||
| 135 | * | ||
| 136 | * Use of id names is optional. | ||
| 137 | */ | ||
| 138 | static inline struct reset_control *reset_control_get_shared( | ||
| 101 | struct device *dev, const char *id) | 139 | struct device *dev, const char *id) |
| 102 | { | 140 | { |
| 103 | return ERR_PTR(-ENOTSUPP); | 141 | return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 1); |
| 104 | } | 142 | } |
| 105 | 143 | ||
| 144 | /** | ||
| 145 | * of_reset_control_get - Lookup and obtain an exclusive reference to a | ||
| 146 | * reset controller. | ||
| 147 | * @node: device to be reset by the controller | ||
| 148 | * @id: reset line name | ||
| 149 | * | ||
| 150 | * Returns a struct reset_control or IS_ERR() condition containing errno. | ||
| 151 | * | ||
| 152 | * Use of id names is optional. | ||
| 153 | */ | ||
| 106 | static inline struct reset_control *of_reset_control_get( | 154 | static inline struct reset_control *of_reset_control_get( |
| 107 | struct device_node *node, const char *id) | 155 | struct device_node *node, const char *id) |
| 108 | { | 156 | { |
| 109 | return ERR_PTR(-ENOTSUPP); | 157 | return __of_reset_control_get(node, id, 0, 0); |
| 110 | } | 158 | } |
| 111 | 159 | ||
| 160 | /** | ||
| 161 | * of_reset_control_get_by_index - Lookup and obtain an exclusive reference to | ||
| 162 | * a reset controller by index. | ||
| 163 | * @node: device to be reset by the controller | ||
| 164 | * @index: index of the reset controller | ||
| 165 | * | ||
| 166 | * This is to be used to perform a list of resets for a device or power domain | ||
| 167 | * in whatever order. Returns a struct reset_control or IS_ERR() condition | ||
| 168 | * containing errno. | ||
| 169 | */ | ||
| 112 | static inline struct reset_control *of_reset_control_get_by_index( | 170 | static inline struct reset_control *of_reset_control_get_by_index( |
| 113 | struct device_node *node, int index) | 171 | struct device_node *node, int index) |
| 114 | { | 172 | { |
| 115 | return ERR_PTR(-ENOTSUPP); | 173 | return __of_reset_control_get(node, NULL, index, 0); |
| 116 | } | 174 | } |
| 117 | 175 | ||
| 118 | #endif /* CONFIG_RESET_CONTROLLER */ | 176 | /** |
| 177 | * devm_reset_control_get - resource managed reset_control_get() | ||
| 178 | * @dev: device to be reset by the controller | ||
| 179 | * @id: reset line name | ||
| 180 | * | ||
| 181 | * Managed reset_control_get(). For reset controllers returned from this | ||
| 182 | * function, reset_control_put() is called automatically on driver detach. | ||
| 183 | * See reset_control_get() for more information. | ||
| 184 | */ | ||
| 185 | static inline struct reset_control *__must_check devm_reset_control_get( | ||
| 186 | struct device *dev, const char *id) | ||
| 187 | { | ||
| 188 | #ifndef CONFIG_RESET_CONTROLLER | ||
| 189 | WARN_ON(1); | ||
| 190 | #endif | ||
| 191 | return __devm_reset_control_get(dev, id, 0, 0); | ||
| 192 | } | ||
| 193 | |||
| 194 | static inline struct reset_control *devm_reset_control_get_optional( | ||
| 195 | struct device *dev, const char *id) | ||
| 196 | { | ||
| 197 | return __devm_reset_control_get(dev, id, 0, 0); | ||
| 198 | } | ||
| 199 | |||
| 200 | /** | ||
| 201 | * devm_reset_control_get_by_index - resource managed reset_control_get | ||
| 202 | * @dev: device to be reset by the controller | ||
| 203 | * @index: index of the reset controller | ||
| 204 | * | ||
| 205 | * Managed reset_control_get(). For reset controllers returned from this | ||
| 206 | * function, reset_control_put() is called automatically on driver detach. | ||
| 207 | * See reset_control_get() for more information. | ||
| 208 | */ | ||
| 209 | static inline struct reset_control *devm_reset_control_get_by_index( | ||
| 210 | struct device *dev, int index) | ||
| 211 | { | ||
| 212 | return __devm_reset_control_get(dev, NULL, index, 0); | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | ||
| 216 | * devm_reset_control_get_shared - resource managed reset_control_get_shared() | ||
| 217 | * @dev: device to be reset by the controller | ||
| 218 | * @id: reset line name | ||
| 219 | * | ||
| 220 | * Managed reset_control_get_shared(). For reset controllers returned from | ||
| 221 | * this function, reset_control_put() is called automatically on driver detach. | ||
| 222 | * See reset_control_get_shared() for more information. | ||
| 223 | */ | ||
| 224 | static inline struct reset_control *devm_reset_control_get_shared( | ||
| 225 | struct device *dev, const char *id) | ||
| 226 | { | ||
| 227 | return __devm_reset_control_get(dev, id, 0, 1); | ||
| 228 | } | ||
| 229 | |||
| 230 | /** | ||
| 231 | * devm_reset_control_get_shared_by_index - resource managed | ||
| 232 | * reset_control_get_shared | ||
| 233 | * @dev: device to be reset by the controller | ||
| 234 | * @index: index of the reset controller | ||
| 235 | * | ||
| 236 | * Managed reset_control_get_shared(). For reset controllers returned from | ||
| 237 | * this function, reset_control_put() is called automatically on driver detach. | ||
| 238 | * See reset_control_get_shared() for more information. | ||
| 239 | */ | ||
| 240 | static inline struct reset_control *devm_reset_control_get_shared_by_index( | ||
| 241 | struct device *dev, int index) | ||
| 242 | { | ||
| 243 | return __devm_reset_control_get(dev, NULL, index, 1); | ||
| 244 | } | ||
| 119 | 245 | ||
| 120 | #endif | 246 | #endif |
diff --git a/arch/arm/mach-shmobile/pm-rcar.h b/include/linux/soc/renesas/rcar-sysc.h index 1b901db4a24c..92fc613ab23d 100644 --- a/arch/arm/mach-shmobile/pm-rcar.h +++ b/include/linux/soc/renesas/rcar-sysc.h | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | #ifndef PM_RCAR_H | 1 | #ifndef __LINUX_SOC_RENESAS_RCAR_SYSC_H__ |
| 2 | #define PM_RCAR_H | 2 | #define __LINUX_SOC_RENESAS_RCAR_SYSC_H__ |
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 3 | 5 | ||
| 4 | struct rcar_sysc_ch { | 6 | struct rcar_sysc_ch { |
| 5 | u16 chan_offs; | 7 | u16 chan_offs; |
| @@ -9,7 +11,6 @@ struct rcar_sysc_ch { | |||
| 9 | 11 | ||
| 10 | int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch); | 12 | int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch); |
| 11 | int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch); | 13 | int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch); |
| 12 | bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch); | ||
| 13 | void __iomem *rcar_sysc_init(phys_addr_t base); | 14 | void __iomem *rcar_sysc_init(phys_addr_t base); |
| 14 | 15 | ||
| 15 | #endif /* PM_RCAR_H */ | 16 | #endif /* __LINUX_SOC_RENESAS_RCAR_SYSC_H__ */ |
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 961b821b6a46..b4c9219e7f95 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #define TEGRA_FUSE_SKU_CALIB_0 0xf0 | 27 | #define TEGRA_FUSE_SKU_CALIB_0 0xf0 |
| 28 | #define TEGRA30_FUSE_SATA_CALIB 0x124 | 28 | #define TEGRA30_FUSE_SATA_CALIB 0x124 |
| 29 | #define TEGRA_FUSE_USB_CALIB_EXT_0 0x250 | ||
| 29 | 30 | ||
| 30 | #ifndef __ASSEMBLY__ | 31 | #ifndef __ASSEMBLY__ |
| 31 | 32 | ||
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index d18efe402ff1..e9e53473a63e 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h | |||
| @@ -33,9 +33,9 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode); | |||
| 33 | #endif /* CONFIG_PM_SLEEP */ | 33 | #endif /* CONFIG_PM_SLEEP */ |
| 34 | 34 | ||
| 35 | #ifdef CONFIG_SMP | 35 | #ifdef CONFIG_SMP |
| 36 | bool tegra_pmc_cpu_is_powered(int cpuid); | 36 | bool tegra_pmc_cpu_is_powered(unsigned int cpuid); |
| 37 | int tegra_pmc_cpu_power_on(int cpuid); | 37 | int tegra_pmc_cpu_power_on(unsigned int cpuid); |
| 38 | int tegra_pmc_cpu_remove_clamping(int cpuid); | 38 | int tegra_pmc_cpu_remove_clamping(unsigned int cpuid); |
| 39 | #endif /* CONFIG_SMP */ | 39 | #endif /* CONFIG_SMP */ |
| 40 | 40 | ||
| 41 | /* | 41 | /* |
| @@ -72,6 +72,7 @@ int tegra_pmc_cpu_remove_clamping(int cpuid); | |||
| 72 | #define TEGRA_POWERGATE_AUD 27 | 72 | #define TEGRA_POWERGATE_AUD 27 |
| 73 | #define TEGRA_POWERGATE_DFD 28 | 73 | #define TEGRA_POWERGATE_DFD 28 |
| 74 | #define TEGRA_POWERGATE_VE2 29 | 74 | #define TEGRA_POWERGATE_VE2 29 |
| 75 | #define TEGRA_POWERGATE_MAX TEGRA_POWERGATE_VE2 | ||
| 75 | 76 | ||
| 76 | #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D | 77 | #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D |
| 77 | 78 | ||
| @@ -108,50 +109,51 @@ int tegra_pmc_cpu_remove_clamping(int cpuid); | |||
| 108 | #define TEGRA_IO_RAIL_SYS_DDC 58 | 109 | #define TEGRA_IO_RAIL_SYS_DDC 58 |
| 109 | 110 | ||
| 110 | #ifdef CONFIG_ARCH_TEGRA | 111 | #ifdef CONFIG_ARCH_TEGRA |
| 111 | int tegra_powergate_is_powered(int id); | 112 | int tegra_powergate_is_powered(unsigned int id); |
| 112 | int tegra_powergate_power_on(int id); | 113 | int tegra_powergate_power_on(unsigned int id); |
| 113 | int tegra_powergate_power_off(int id); | 114 | int tegra_powergate_power_off(unsigned int id); |
| 114 | int tegra_powergate_remove_clamping(int id); | 115 | int tegra_powergate_remove_clamping(unsigned int id); |
| 115 | 116 | ||
| 116 | /* Must be called with clk disabled, and returns with clk enabled */ | 117 | /* Must be called with clk disabled, and returns with clk enabled */ |
| 117 | int tegra_powergate_sequence_power_up(int id, struct clk *clk, | 118 | int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, |
| 118 | struct reset_control *rst); | 119 | struct reset_control *rst); |
| 119 | 120 | ||
| 120 | int tegra_io_rail_power_on(int id); | 121 | int tegra_io_rail_power_on(unsigned int id); |
| 121 | int tegra_io_rail_power_off(int id); | 122 | int tegra_io_rail_power_off(unsigned int id); |
| 122 | #else | 123 | #else |
| 123 | static inline int tegra_powergate_is_powered(int id) | 124 | static inline int tegra_powergate_is_powered(unsigned int id) |
| 124 | { | 125 | { |
| 125 | return -ENOSYS; | 126 | return -ENOSYS; |
| 126 | } | 127 | } |
| 127 | 128 | ||
| 128 | static inline int tegra_powergate_power_on(int id) | 129 | static inline int tegra_powergate_power_on(unsigned int id) |
| 129 | { | 130 | { |
| 130 | return -ENOSYS; | 131 | return -ENOSYS; |
| 131 | } | 132 | } |
| 132 | 133 | ||
| 133 | static inline int tegra_powergate_power_off(int id) | 134 | static inline int tegra_powergate_power_off(unsigned int id) |
| 134 | { | 135 | { |
| 135 | return -ENOSYS; | 136 | return -ENOSYS; |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 138 | static inline int tegra_powergate_remove_clamping(int id) | 139 | static inline int tegra_powergate_remove_clamping(unsigned int id) |
| 139 | { | 140 | { |
| 140 | return -ENOSYS; | 141 | return -ENOSYS; |
| 141 | } | 142 | } |
| 142 | 143 | ||
| 143 | static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk, | 144 | static inline int tegra_powergate_sequence_power_up(unsigned int id, |
| 145 | struct clk *clk, | ||
| 144 | struct reset_control *rst) | 146 | struct reset_control *rst) |
| 145 | { | 147 | { |
| 146 | return -ENOSYS; | 148 | return -ENOSYS; |
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | static inline int tegra_io_rail_power_on(int id) | 151 | static inline int tegra_io_rail_power_on(unsigned int id) |
| 150 | { | 152 | { |
| 151 | return -ENOSYS; | 153 | return -ENOSYS; |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 154 | static inline int tegra_io_rail_power_off(int id) | 156 | static inline int tegra_io_rail_power_off(unsigned int id) |
| 155 | { | 157 | { |
| 156 | return -ENOSYS; | 158 | return -ENOSYS; |
| 157 | } | 159 | } |
