diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-08 14:34:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-08 14:34:32 -0400 |
commit | 10c8e0562057b5d64ea170feab148e1550420030 (patch) | |
tree | cfd387208c85e893c93d24e324d147eb6e9abfc9 | |
parent | d4e1f5a14e17d4f0e8034c0967511884bcb12fba (diff) | |
parent | 3e528cb7bae00ba0d73def6645d0f2fa906ee3e8 (diff) |
Merge tag 'drivers-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver changes from Olof Johansson:
"A handful of driver-related changes. We've had a bunch of them going
in through other branches as well, so it's only a part of what we
really have this release.
Larger pieces are:
- Removal of a now unused PWM driver for atmel
[ This includes AVR32 changes that have been appropriately acked ]
- Performance counter support for the arm CCN interconnect
- OMAP mailbox driver cleanups and consolidation
- PCI and SATA PHY drivers for SPEAr 13xx platforms
- Redefinition (with backwards compatibility!) of PCI DT bindings for
Tegra to better model regulators/power"
Note: this merge also fixes up the semantic conflict with the new
calling convention for devm_phy_create(), see commit f0ed817638b5 ("phy:
core: Let node ptr of PHY point to PHY and not of PHY provider") that
came in through Greg's USB tree.
Semantic merge patch by Stephen Rothwell <sfr@canb.auug.org.au> through
the next tree.
* tag 'drivers-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (38 commits)
bus: arm-ccn: Fix error handling at event allocation
mailbox/omap: add a parent structure for every IP instance
mailbox/omap: remove the private mailbox structure
mailbox/omap: consolidate OMAP mailbox driver
mailbox/omap: simplify the fifo assignment by using macros
mailbox/omap: remove omap_mbox_type_t from mailbox ops
mailbox/omap: remove OMAP1 mailbox driver
mailbox/omap: use devm_* interfaces
bus: ARM CCN: add PERF_EVENTS dependency
bus: ARM CCN PMU driver
PCI: spear: Remove spear13xx_pcie_remove()
PCI: spear: Fix Section mismatch compilation warning for probe()
ARM: tegra: Remove legacy PCIe power supply properties
PCI: tegra: Remove deprecated power supply properties
PCI: tegra: Implement accurate power supply scheme
ARM: SPEAr13xx: Update defconfigs
ARM: SPEAr13xx: Add pcie and miphy DT nodes
ARM: SPEAr13xx: Add bindings and dt node for misc block
ARM: SPEAr13xx: Fix static mapping table
phy: Add drivers for PCIe and SATA phy on SPEAr13xx
...
74 files changed, 3452 insertions, 2023 deletions
diff --git a/Documentation/arm/CCN.txt b/Documentation/arm/CCN.txt new file mode 100644 index 000000000000..0632b3aad83e --- /dev/null +++ b/Documentation/arm/CCN.txt | |||
@@ -0,0 +1,52 @@ | |||
1 | ARM Cache Coherent Network | ||
2 | ========================== | ||
3 | |||
4 | CCN-504 is a ring-bus interconnect consisting of 11 crosspoints | ||
5 | (XPs), with each crosspoint supporting up to two device ports, | ||
6 | so nodes (devices) 0 and 1 are connected to crosspoint 0, | ||
7 | nodes 2 and 3 to crosspoint 1 etc. | ||
8 | |||
9 | PMU (perf) driver | ||
10 | ----------------- | ||
11 | |||
12 | The CCN driver registers a perf PMU driver, which provides | ||
13 | description of available events and configuration options | ||
14 | in sysfs, see /sys/bus/event_source/devices/ccn*. | ||
15 | |||
16 | The "format" directory describes format of the config, config1 | ||
17 | and config2 fields of the perf_event_attr structure. The "events" | ||
18 | directory provides configuration templates for all documented | ||
19 | events, that can be used with perf tool. For example "xp_valid_flit" | ||
20 | is an equivalent of "type=0x8,event=0x4". Other parameters must be | ||
21 | explicitly specified. For events originating from device, "node" | ||
22 | defines its index. All crosspoint events require "xp" (index), | ||
23 | "port" (device port number) and "vc" (virtual channel ID) and | ||
24 | "dir" (direction). Watchpoints (special "event" value 0xfe) also | ||
25 | require comparator values ("cmp_l" and "cmp_h") and "mask", being | ||
26 | index of the comparator mask. | ||
27 | |||
28 | Masks are defined separately from the event description | ||
29 | (due to limited number of the config values) in the "cmp_mask" | ||
30 | directory, with first 8 configurable by user and additional | ||
31 | 4 hardcoded for the most frequent use cases. | ||
32 | |||
33 | Cycle counter is described by a "type" value 0xff and does | ||
34 | not require any other settings. | ||
35 | |||
36 | Example of perf tool use: | ||
37 | |||
38 | / # perf list | grep ccn | ||
39 | ccn/cycles/ [Kernel PMU event] | ||
40 | <...> | ||
41 | ccn/xp_valid_flit/ [Kernel PMU event] | ||
42 | <...> | ||
43 | |||
44 | / # perf stat -C 0 -e ccn/cycles/,ccn/xp_valid_flit,xp=1,port=0,vc=1,dir=1/ \ | ||
45 | sleep 1 | ||
46 | |||
47 | The driver does not support sampling, therefore "perf record" will | ||
48 | not work. Also notice that only single cpu is being selected | ||
49 | ("-C 0") - this is because perf framework does not support | ||
50 | "non-CPU related" counters (yet?) so system-wide session ("-a") | ||
51 | would try (and in most cases fail) to set up the same event | ||
52 | per each CPU. | ||
diff --git a/Documentation/devicetree/bindings/arm/ccn.txt b/Documentation/devicetree/bindings/arm/ccn.txt new file mode 100644 index 000000000000..b100d3847d88 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/ccn.txt | |||
@@ -0,0 +1,21 @@ | |||
1 | * ARM CCN (Cache Coherent Network) | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: (standard compatible string) should be one of: | ||
6 | "arm,ccn-504" | ||
7 | "arm,ccn-508" | ||
8 | |||
9 | - reg: (standard registers property) physical address and size | ||
10 | (16MB) of the configuration registers block | ||
11 | |||
12 | - interrupts: (standard interrupt property) single interrupt | ||
13 | generated by the control block | ||
14 | |||
15 | Example: | ||
16 | |||
17 | ccn@0x2000000000 { | ||
18 | compatible = "arm,ccn-504"; | ||
19 | reg = <0x20 0x00000000 0 0x1000000>; | ||
20 | interrupts = <0 181 4>; | ||
21 | }; | ||
diff --git a/Documentation/devicetree/bindings/arm/spear-misc.txt b/Documentation/devicetree/bindings/arm/spear-misc.txt new file mode 100644 index 000000000000..cf649827ffcd --- /dev/null +++ b/Documentation/devicetree/bindings/arm/spear-misc.txt | |||
@@ -0,0 +1,9 @@ | |||
1 | SPEAr Misc configuration | ||
2 | =========================== | ||
3 | SPEAr SOCs have some miscellaneous registers which are used to configure | ||
4 | few properties of different peripheral controllers. | ||
5 | |||
6 | misc node required properties: | ||
7 | |||
8 | - compatible Should be "st,spear1340-misc", "syscon". | ||
9 | - reg: Address range of misc space upto 8K | ||
diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index c300391e8d3e..0823362548dc 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt | |||
@@ -14,9 +14,6 @@ Required properties: | |||
14 | - interrupt-names: Must include the following entries: | 14 | - interrupt-names: Must include the following entries: |
15 | "intr": The Tegra interrupt that is asserted for controller interrupts | 15 | "intr": The Tegra interrupt that is asserted for controller interrupts |
16 | "msi": The Tegra interrupt that is asserted when an MSI is received | 16 | "msi": The Tegra interrupt that is asserted when an MSI is received |
17 | - pex-clk-supply: Supply voltage for internal reference clock | ||
18 | - vdd-supply: Power supply for controller (1.05V) | ||
19 | - avdd-supply: Power supply for controller (1.05V) (not required for Tegra20) | ||
20 | - bus-range: Range of bus numbers associated with this controller | 17 | - bus-range: Range of bus numbers associated with this controller |
21 | - #address-cells: Address representation for root ports (must be 3) | 18 | - #address-cells: Address representation for root ports (must be 3) |
22 | - cell 0 specifies the bus and device numbers of the root port: | 19 | - cell 0 specifies the bus and device numbers of the root port: |
@@ -60,6 +57,33 @@ Required properties: | |||
60 | - afi | 57 | - afi |
61 | - pcie_x | 58 | - pcie_x |
62 | 59 | ||
60 | Power supplies for Tegra20: | ||
61 | - avdd-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V. | ||
62 | - vdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. | ||
63 | - avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must | ||
64 | supply 1.05 V. | ||
65 | - avdd-plle-supply: Power supply for PLLE, which is shared with SATA. Must | ||
66 | supply 1.05 V. | ||
67 | - vddio-pex-clk-supply: Power supply for PCIe clock. Must supply 3.3 V. | ||
68 | |||
69 | Power supplies for Tegra30: | ||
70 | - Required: | ||
71 | - avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must | ||
72 | supply 1.05 V. | ||
73 | - avdd-plle-supply: Power supply for PLLE, which is shared with SATA. Must | ||
74 | supply 1.05 V. | ||
75 | - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must | ||
76 | supply 1.8 V. | ||
77 | - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks. | ||
78 | Must supply 3.3 V. | ||
79 | - Optional: | ||
80 | - If lanes 0 to 3 are used: | ||
81 | - avdd-pexa-supply: Power supply for analog PCIe logic. Must supply 1.05 V. | ||
82 | - vdd-pexa-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. | ||
83 | - If lanes 4 or 5 are used: | ||
84 | - avdd-pexb-supply: Power supply for analog PCIe logic. Must supply 1.05 V. | ||
85 | - vdd-pexb-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. | ||
86 | |||
63 | Root ports are defined as subnodes of the PCIe controller node. | 87 | Root ports are defined as subnodes of the PCIe controller node. |
64 | 88 | ||
65 | Required properties: | 89 | Required properties: |
diff --git a/Documentation/devicetree/bindings/pci/spear13xx-pcie.txt b/Documentation/devicetree/bindings/pci/spear13xx-pcie.txt new file mode 100644 index 000000000000..49ea76da7718 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/spear13xx-pcie.txt | |||
@@ -0,0 +1,14 @@ | |||
1 | SPEAr13XX PCIe DT detail: | ||
2 | ================================ | ||
3 | |||
4 | SPEAr13XX uses synopsis designware PCIe controller and ST MiPHY as phy | ||
5 | controller. | ||
6 | |||
7 | Required properties: | ||
8 | - compatible : should be "st,spear1340-pcie", "snps,dw-pcie". | ||
9 | - phys : phandle to phy node associated with pcie controller | ||
10 | - phy-names : must be "pcie-phy" | ||
11 | - All other definitions as per generic PCI bindings | ||
12 | |||
13 | Optional properties: | ||
14 | - st,pcie-is-gen1 indicates that forced gen1 initialization is needed. | ||
diff --git a/Documentation/devicetree/bindings/phy/st-spear-miphy.txt b/Documentation/devicetree/bindings/phy/st-spear-miphy.txt new file mode 100644 index 000000000000..2a6bfdcc09b3 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/st-spear-miphy.txt | |||
@@ -0,0 +1,15 @@ | |||
1 | ST SPEAr miphy DT details | ||
2 | ========================= | ||
3 | |||
4 | ST Microelectronics SPEAr miphy is a phy controller supporting PCIe and SATA. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible : should be "st,spear1310-miphy" or "st,spear1340-miphy" | ||
8 | - reg : offset and length of the PHY register set. | ||
9 | - misc: phandle for the syscon node to access misc registers | ||
10 | - #phy-cells : from the generic PHY bindings, must be 1. | ||
11 | - cell[1]: 0 if phy used for SATA, 1 for PCIe. | ||
12 | |||
13 | Optional properties: | ||
14 | - phy-id: Instance id of the phy. Only required when there are multiple phys | ||
15 | present on a implementation. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 20cd746d1933..e065c3881626 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -6902,6 +6902,12 @@ S: Maintained | |||
6902 | F: Documentation/devicetree/bindings/pci/host-generic-pci.txt | 6902 | F: Documentation/devicetree/bindings/pci/host-generic-pci.txt |
6903 | F: drivers/pci/host/pci-host-generic.c | 6903 | F: drivers/pci/host/pci-host-generic.c |
6904 | 6904 | ||
6905 | PCIE DRIVER FOR ST SPEAR13XX | ||
6906 | M: Mohit Kumar <mohit.kumar@st.com> | ||
6907 | L: linux-pci@vger.kernel.org | ||
6908 | S: Maintained | ||
6909 | F: drivers/pci/host/*spear* | ||
6910 | |||
6905 | PCMCIA SUBSYSTEM | 6911 | PCMCIA SUBSYSTEM |
6906 | P: Linux PCMCIA Team | 6912 | P: Linux PCMCIA Team |
6907 | L: linux-pcmcia@lists.infradead.org | 6913 | L: linux-pcmcia@lists.infradead.org |
diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index b56a801e42a2..d42c84b1df8d 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts | |||
@@ -106,6 +106,10 @@ | |||
106 | status = "okay"; | 106 | status = "okay"; |
107 | }; | 107 | }; |
108 | 108 | ||
109 | miphy@eb800000 { | ||
110 | status = "okay"; | ||
111 | }; | ||
112 | |||
109 | cf@b2800000 { | 113 | cf@b2800000 { |
110 | status = "okay"; | 114 | status = "okay"; |
111 | }; | 115 | }; |
diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi index 122ae94076c8..fa5f2bb5f106 100644 --- a/arch/arm/boot/dts/spear1310.dtsi +++ b/arch/arm/boot/dts/spear1310.dtsi | |||
@@ -29,24 +29,111 @@ | |||
29 | #gpio-cells = <2>; | 29 | #gpio-cells = <2>; |
30 | }; | 30 | }; |
31 | 31 | ||
32 | ahci@b1000000 { | 32 | miphy0: miphy@eb800000 { |
33 | compatible = "st,spear1310-miphy"; | ||
34 | reg = <0xeb800000 0x4000>; | ||
35 | misc = <&misc>; | ||
36 | phy-id = <0>; | ||
37 | #phy-cells = <1>; | ||
38 | status = "disabled"; | ||
39 | }; | ||
40 | |||
41 | miphy1: miphy@eb804000 { | ||
42 | compatible = "st,spear1310-miphy"; | ||
43 | reg = <0xeb804000 0x4000>; | ||
44 | misc = <&misc>; | ||
45 | phy-id = <1>; | ||
46 | #phy-cells = <1>; | ||
47 | status = "disabled"; | ||
48 | }; | ||
49 | |||
50 | miphy2: miphy@eb808000 { | ||
51 | compatible = "st,spear1310-miphy"; | ||
52 | reg = <0xeb808000 0x4000>; | ||
53 | misc = <&misc>; | ||
54 | phy-id = <2>; | ||
55 | #phy-cells = <1>; | ||
56 | status = "disabled"; | ||
57 | }; | ||
58 | |||
59 | ahci0: ahci@b1000000 { | ||
33 | compatible = "snps,spear-ahci"; | 60 | compatible = "snps,spear-ahci"; |
34 | reg = <0xb1000000 0x10000>; | 61 | reg = <0xb1000000 0x10000>; |
35 | interrupts = <0 68 0x4>; | 62 | interrupts = <0 68 0x4>; |
63 | phys = <&miphy0 0>; | ||
64 | phy-names = "sata-phy"; | ||
36 | status = "disabled"; | 65 | status = "disabled"; |
37 | }; | 66 | }; |
38 | 67 | ||
39 | ahci@b1800000 { | 68 | ahci1: ahci@b1800000 { |
40 | compatible = "snps,spear-ahci"; | 69 | compatible = "snps,spear-ahci"; |
41 | reg = <0xb1800000 0x10000>; | 70 | reg = <0xb1800000 0x10000>; |
42 | interrupts = <0 69 0x4>; | 71 | interrupts = <0 69 0x4>; |
72 | phys = <&miphy1 0>; | ||
73 | phy-names = "sata-phy"; | ||
43 | status = "disabled"; | 74 | status = "disabled"; |
44 | }; | 75 | }; |
45 | 76 | ||
46 | ahci@b4000000 { | 77 | ahci2: ahci@b4000000 { |
47 | compatible = "snps,spear-ahci"; | 78 | compatible = "snps,spear-ahci"; |
48 | reg = <0xb4000000 0x10000>; | 79 | reg = <0xb4000000 0x10000>; |
49 | interrupts = <0 70 0x4>; | 80 | interrupts = <0 70 0x4>; |
81 | phys = <&miphy2 0>; | ||
82 | phy-names = "sata-phy"; | ||
83 | status = "disabled"; | ||
84 | }; | ||
85 | |||
86 | pcie0: pcie@b1000000 { | ||
87 | compatible = "st,spear1340-pcie", "snps,dw-pcie"; | ||
88 | reg = <0xb1000000 0x4000>; | ||
89 | interrupts = <0 68 0x4>; | ||
90 | interrupt-map-mask = <0 0 0 0>; | ||
91 | interrupt-map = <0x0 0 &gic 0 68 0x4>; | ||
92 | num-lanes = <1>; | ||
93 | phys = <&miphy0 1>; | ||
94 | phy-names = "pcie-phy"; | ||
95 | #address-cells = <3>; | ||
96 | #size-cells = <2>; | ||
97 | device_type = "pci"; | ||
98 | ranges = <0x00000800 0 0x80000000 0x80000000 0 0x00020000 /* configuration space */ | ||
99 | 0x81000000 0 0 0x80020000 0 0x00010000 /* downstream I/O */ | ||
100 | 0x82000000 0 0x80030000 0xc0030000 0 0x0ffd0000>; /* non-prefetchable memory */ | ||
101 | status = "disabled"; | ||
102 | }; | ||
103 | |||
104 | pcie1: pcie@b1800000 { | ||
105 | compatible = "st,spear1340-pcie", "snps,dw-pcie"; | ||
106 | reg = <0xb1800000 0x4000>; | ||
107 | interrupts = <0 69 0x4>; | ||
108 | interrupt-map-mask = <0 0 0 0>; | ||
109 | interrupt-map = <0x0 0 &gic 0 69 0x4>; | ||
110 | num-lanes = <1>; | ||
111 | phys = <&miphy1 1>; | ||
112 | phy-names = "pcie-phy"; | ||
113 | #address-cells = <3>; | ||
114 | #size-cells = <2>; | ||
115 | device_type = "pci"; | ||
116 | ranges = <0x00000800 0 0x90000000 0x90000000 0 0x00020000 /* configuration space */ | ||
117 | 0x81000000 0 0 0x90020000 0 0x00010000 /* downstream I/O */ | ||
118 | 0x82000000 0 0x90030000 0x90030000 0 0x0ffd0000>; /* non-prefetchable memory */ | ||
119 | status = "disabled"; | ||
120 | }; | ||
121 | |||
122 | pcie2: pcie@b4000000 { | ||
123 | compatible = "st,spear1340-pcie", "snps,dw-pcie"; | ||
124 | reg = <0xb4000000 0x4000>; | ||
125 | interrupts = <0 70 0x4>; | ||
126 | interrupt-map-mask = <0 0 0 0>; | ||
127 | interrupt-map = <0x0 0 &gic 0 70 0x4>; | ||
128 | num-lanes = <1>; | ||
129 | phys = <&miphy2 1>; | ||
130 | phy-names = "pcie-phy"; | ||
131 | #address-cells = <3>; | ||
132 | #size-cells = <2>; | ||
133 | device_type = "pci"; | ||
134 | ranges = <0x00000800 0 0xc0000000 0xc0000000 0 0x00020000 /* configuration space */ | ||
135 | 0x81000000 0 0 0xc0020000 0 0x00010000 /* downstream I/O */ | ||
136 | 0x82000000 0 0xc0030000 0xc0030000 0 0x0ffd0000>; /* non-prefetchable memory */ | ||
50 | status = "disabled"; | 137 | status = "disabled"; |
51 | }; | 138 | }; |
52 | 139 | ||
diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index d6c30ae0a8d7..b23e05ed1d60 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts | |||
@@ -122,6 +122,10 @@ | |||
122 | status = "okay"; | 122 | status = "okay"; |
123 | }; | 123 | }; |
124 | 124 | ||
125 | miphy@eb800000 { | ||
126 | status = "okay"; | ||
127 | }; | ||
128 | |||
125 | dma@ea800000 { | 129 | dma@ea800000 { |
126 | status = "okay"; | 130 | status = "okay"; |
127 | }; | 131 | }; |
diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index 54d128d35681..e71df0f2cb52 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi | |||
@@ -31,10 +31,38 @@ | |||
31 | status = "disabled"; | 31 | status = "disabled"; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | ahci@b1000000 { | 34 | miphy0: miphy@eb800000 { |
35 | compatible = "st,spear1340-miphy"; | ||
36 | reg = <0xeb800000 0x4000>; | ||
37 | misc = <&misc>; | ||
38 | #phy-cells = <1>; | ||
39 | status = "disabled"; | ||
40 | }; | ||
41 | |||
42 | ahci0: ahci@b1000000 { | ||
35 | compatible = "snps,spear-ahci"; | 43 | compatible = "snps,spear-ahci"; |
36 | reg = <0xb1000000 0x10000>; | 44 | reg = <0xb1000000 0x10000>; |
37 | interrupts = <0 72 0x4>; | 45 | interrupts = <0 72 0x4>; |
46 | phys = <&miphy0 0>; | ||
47 | phy-names = "sata-phy"; | ||
48 | status = "disabled"; | ||
49 | }; | ||
50 | |||
51 | pcie0: pcie@b1000000 { | ||
52 | compatible = "st,spear1340-pcie", "snps,dw-pcie"; | ||
53 | reg = <0xb1000000 0x4000>; | ||
54 | interrupts = <0 68 0x4>; | ||
55 | interrupt-map-mask = <0 0 0 0>; | ||
56 | interrupt-map = <0x0 0 &gic 0 68 0x4>; | ||
57 | num-lanes = <1>; | ||
58 | phys = <&miphy0 1>; | ||
59 | phy-names = "pcie-phy"; | ||
60 | #address-cells = <3>; | ||
61 | #size-cells = <2>; | ||
62 | device_type = "pci"; | ||
63 | ranges = <0x00000800 0 0x80000000 0x80000000 0 0x00020000 /* configuration space */ | ||
64 | 0x81000000 0 0 0x80020000 0 0x00010000 /* downstream I/O */ | ||
65 | 0x82000000 0 0x80030000 0xc0030000 0 0x0ffd0000>; /* non-prefetchable memory */ | ||
38 | status = "disabled"; | 66 | status = "disabled"; |
39 | }; | 67 | }; |
40 | 68 | ||
diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index 4382547df58a..a6eb5436d26d 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi | |||
@@ -83,8 +83,8 @@ | |||
83 | #size-cells = <1>; | 83 | #size-cells = <1>; |
84 | compatible = "simple-bus"; | 84 | compatible = "simple-bus"; |
85 | ranges = <0x50000000 0x50000000 0x10000000 | 85 | ranges = <0x50000000 0x50000000 0x10000000 |
86 | 0xb0000000 0xb0000000 0x10000000 | 86 | 0x80000000 0x80000000 0x20000000 |
87 | 0xd0000000 0xd0000000 0x02000000 | 87 | 0xb0000000 0xb0000000 0x22000000 |
88 | 0xd8000000 0xd8000000 0x01000000 | 88 | 0xd8000000 0xd8000000 0x01000000 |
89 | 0xe0000000 0xe0000000 0x10000000>; | 89 | 0xe0000000 0xe0000000 0x10000000>; |
90 | 90 | ||
@@ -220,6 +220,11 @@ | |||
220 | 0xd8000000 0xd8000000 0x01000000 | 220 | 0xd8000000 0xd8000000 0x01000000 |
221 | 0xe0000000 0xe0000000 0x10000000>; | 221 | 0xe0000000 0xe0000000 0x10000000>; |
222 | 222 | ||
223 | misc: syscon@e0700000 { | ||
224 | compatible = "st,spear1340-misc", "syscon"; | ||
225 | reg = <0xe0700000 0x1000>; | ||
226 | }; | ||
227 | |||
223 | gpio0: gpio@e0600000 { | 228 | gpio0: gpio@e0600000 { |
224 | compatible = "arm,pl061", "arm,primecell"; | 229 | compatible = "arm,pl061", "arm,primecell"; |
225 | reg = <0xe0600000 0x1000>; | 230 | reg = <0xe0600000 0x1000>; |
diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index f45aad688d9b..a37279af687c 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts | |||
@@ -562,10 +562,14 @@ | |||
562 | }; | 562 | }; |
563 | 563 | ||
564 | pcie-controller@80003000 { | 564 | pcie-controller@80003000 { |
565 | pex-clk-supply = <&pci_clk_reg>; | ||
566 | vdd-supply = <&pci_vdd_reg>; | ||
567 | status = "okay"; | 565 | status = "okay"; |
568 | 566 | ||
567 | avdd-pex-supply = <&pci_vdd_reg>; | ||
568 | vdd-pex-supply = <&pci_vdd_reg>; | ||
569 | avdd-pex-pll-supply = <&pci_vdd_reg>; | ||
570 | avdd-plle-supply = <&pci_vdd_reg>; | ||
571 | vddio-pex-clk-supply = <&pci_clk_reg>; | ||
572 | |||
569 | pci@1,0 { | 573 | pci@1,0 { |
570 | status = "okay"; | 574 | status = "okay"; |
571 | }; | 575 | }; |
diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi index 9c8318538a11..80e7d386ce34 100644 --- a/arch/arm/boot/dts/tegra20-tamonten.dtsi +++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi | |||
@@ -474,8 +474,11 @@ | |||
474 | }; | 474 | }; |
475 | 475 | ||
476 | pcie-controller@80003000 { | 476 | pcie-controller@80003000 { |
477 | pex-clk-supply = <&pci_clk_reg>; | 477 | avdd-pex-supply = <&pci_vdd_reg>; |
478 | vdd-supply = <&pci_vdd_reg>; | 478 | vdd-pex-supply = <&pci_vdd_reg>; |
479 | avdd-pex-pll-supply = <&pci_vdd_reg>; | ||
480 | avdd-plle-supply = <&pci_vdd_reg>; | ||
481 | vddio-pex-clk-supply = <&pci_clk_reg>; | ||
479 | }; | 482 | }; |
480 | 483 | ||
481 | usb@c5008000 { | 484 | usb@c5008000 { |
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index 216fa6d50c65..5ad87979ab13 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts | |||
@@ -318,8 +318,12 @@ | |||
318 | 318 | ||
319 | pcie-controller@80003000 { | 319 | pcie-controller@80003000 { |
320 | status = "okay"; | 320 | status = "okay"; |
321 | pex-clk-supply = <&pci_clk_reg>; | 321 | |
322 | vdd-supply = <&pci_vdd_reg>; | 322 | avdd-pex-supply = <&pci_vdd_reg>; |
323 | vdd-pex-supply = <&pci_vdd_reg>; | ||
324 | avdd-pex-pll-supply = <&pci_vdd_reg>; | ||
325 | avdd-plle-supply = <&pci_vdd_reg>; | ||
326 | vddio-pex-clk-supply = <&pci_clk_reg>; | ||
323 | 327 | ||
324 | pci@1,0 { | 328 | pci@1,0 { |
325 | status = "okay"; | 329 | status = "okay"; |
diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts index 3189791a9289..cee8f2246fdb 100644 --- a/arch/arm/boot/dts/tegra30-beaver.dts +++ b/arch/arm/boot/dts/tegra30-beaver.dts | |||
@@ -17,9 +17,15 @@ | |||
17 | 17 | ||
18 | pcie-controller@00003000 { | 18 | pcie-controller@00003000 { |
19 | status = "okay"; | 19 | status = "okay"; |
20 | pex-clk-supply = <&sys_3v3_pexs_reg>; | 20 | |
21 | vdd-supply = <&ldo1_reg>; | 21 | avdd-pexa-supply = <&ldo1_reg>; |
22 | avdd-supply = <&ldo2_reg>; | 22 | vdd-pexa-supply = <&ldo1_reg>; |
23 | avdd-pexb-supply = <&ldo1_reg>; | ||
24 | vdd-pexb-supply = <&ldo1_reg>; | ||
25 | avdd-pex-pll-supply = <&ldo1_reg>; | ||
26 | avdd-plle-supply = <&ldo1_reg>; | ||
27 | vddio-pex-ctl-supply = <&sys_3v3_reg>; | ||
28 | hvdd-pex-supply = <&sys_3v3_pexs_reg>; | ||
23 | 29 | ||
24 | pci@1,0 { | 30 | pci@1,0 { |
25 | status = "okay"; | 31 | status = "okay"; |
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index 0cf0848a82d8..206379546244 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi | |||
@@ -38,9 +38,14 @@ | |||
38 | 38 | ||
39 | pcie-controller@00003000 { | 39 | pcie-controller@00003000 { |
40 | status = "okay"; | 40 | status = "okay"; |
41 | pex-clk-supply = <&pex_hvdd_3v3_reg>; | 41 | |
42 | vdd-supply = <&ldo1_reg>; | 42 | /* AVDD_PEXA and VDD_PEXA inputs are grounded on Cardhu. */ |
43 | avdd-supply = <&ldo2_reg>; | 43 | avdd-pexb-supply = <&ldo1_reg>; |
44 | vdd-pexb-supply = <&ldo1_reg>; | ||
45 | avdd-pex-pll-supply = <&ldo1_reg>; | ||
46 | hvdd-pex-supply = <&pex_hvdd_3v3_reg>; | ||
47 | vddio-pex-ctl-supply = <&sys_3v3_reg>; | ||
48 | avdd-plle-supply = <&ldo2_reg>; | ||
44 | 49 | ||
45 | pci@1,0 { | 50 | pci@1,0 { |
46 | nvidia,num-lanes = <4>; | 51 | nvidia,num-lanes = <4>; |
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index ce541bb3c2de..115cda9f3260 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig | |||
@@ -26,8 +26,6 @@ CONFIG_ARCH_OMAP=y | |||
26 | CONFIG_ARCH_OMAP1=y | 26 | CONFIG_ARCH_OMAP1=y |
27 | CONFIG_OMAP_RESET_CLOCKS=y | 27 | CONFIG_OMAP_RESET_CLOCKS=y |
28 | # CONFIG_OMAP_MUX is not set | 28 | # CONFIG_OMAP_MUX is not set |
29 | CONFIG_MAILBOX=y | ||
30 | CONFIG_OMAP1_MBOX=y | ||
31 | CONFIG_OMAP_32K_TIMER=y | 29 | CONFIG_OMAP_32K_TIMER=y |
32 | CONFIG_OMAP_DM_TIMER=y | 30 | CONFIG_OMAP_DM_TIMER=y |
33 | CONFIG_ARCH_OMAP730=y | 31 | CONFIG_ARCH_OMAP730=y |
diff --git a/arch/arm/configs/spear13xx_defconfig b/arch/arm/configs/spear13xx_defconfig index 82eaa552ed14..d271b263f35d 100644 --- a/arch/arm/configs/spear13xx_defconfig +++ b/arch/arm/configs/spear13xx_defconfig | |||
@@ -11,13 +11,24 @@ CONFIG_ARCH_SPEAR13XX=y | |||
11 | CONFIG_MACH_SPEAR1310=y | 11 | CONFIG_MACH_SPEAR1310=y |
12 | CONFIG_MACH_SPEAR1340=y | 12 | CONFIG_MACH_SPEAR1340=y |
13 | # CONFIG_SWP_EMULATE is not set | 13 | # CONFIG_SWP_EMULATE is not set |
14 | CONFIG_PCI=y | ||
15 | CONFIG_PCI_MSI=y | ||
16 | CONFIG_PCIE_SPEAR13XX=y | ||
14 | CONFIG_SMP=y | 17 | CONFIG_SMP=y |
15 | # CONFIG_SMP_ON_UP is not set | 18 | # CONFIG_SMP_ON_UP is not set |
16 | # CONFIG_ARM_CPU_TOPOLOGY is not set | 19 | # CONFIG_ARM_CPU_TOPOLOGY is not set |
20 | CONFIG_AEABI=y | ||
17 | CONFIG_ARM_APPENDED_DTB=y | 21 | CONFIG_ARM_APPENDED_DTB=y |
18 | CONFIG_ARM_ATAG_DTB_COMPAT=y | 22 | CONFIG_ARM_ATAG_DTB_COMPAT=y |
23 | CONFIG_VFP=y | ||
19 | CONFIG_BINFMT_MISC=y | 24 | CONFIG_BINFMT_MISC=y |
20 | CONFIG_NET=y | 25 | CONFIG_NET=y |
26 | CONFIG_UNIX=y | ||
27 | CONFIG_INET=y | ||
28 | CONFIG_IP_PNP=y | ||
29 | CONFIG_IP_PNP_DHCP=y | ||
30 | CONFIG_IP_PNP_BOOTP=y | ||
31 | CONFIG_NET_IPIP=y | ||
21 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | 32 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" |
22 | CONFIG_MTD=y | 33 | CONFIG_MTD=y |
23 | CONFIG_MTD_OF_PARTS=y | 34 | CONFIG_MTD_OF_PARTS=y |
@@ -27,6 +38,7 @@ CONFIG_MTD_NAND=y | |||
27 | CONFIG_MTD_NAND_FSMC=y | 38 | CONFIG_MTD_NAND_FSMC=y |
28 | CONFIG_BLK_DEV_RAM=y | 39 | CONFIG_BLK_DEV_RAM=y |
29 | CONFIG_BLK_DEV_RAM_SIZE=16384 | 40 | CONFIG_BLK_DEV_RAM_SIZE=16384 |
41 | CONFIG_BLK_DEV_SD=y | ||
30 | CONFIG_ATA=y | 42 | CONFIG_ATA=y |
31 | # CONFIG_SATA_PMP is not set | 43 | # CONFIG_SATA_PMP is not set |
32 | CONFIG_SATA_AHCI_PLATFORM=y | 44 | CONFIG_SATA_AHCI_PLATFORM=y |
@@ -66,6 +78,7 @@ CONFIG_USB=y | |||
66 | # CONFIG_USB_DEVICE_CLASS is not set | 78 | # CONFIG_USB_DEVICE_CLASS is not set |
67 | CONFIG_USB_EHCI_HCD=y | 79 | CONFIG_USB_EHCI_HCD=y |
68 | CONFIG_USB_OHCI_HCD=y | 80 | CONFIG_USB_OHCI_HCD=y |
81 | CONFIG_USB_STORAGE=y | ||
69 | CONFIG_MMC=y | 82 | CONFIG_MMC=y |
70 | CONFIG_MMC_SDHCI=y | 83 | CONFIG_MMC_SDHCI=y |
71 | CONFIG_MMC_SDHCI_SPEAR=y | 84 | CONFIG_MMC_SDHCI_SPEAR=y |
@@ -79,11 +92,14 @@ CONFIG_EXT2_FS_SECURITY=y | |||
79 | CONFIG_EXT3_FS=y | 92 | CONFIG_EXT3_FS=y |
80 | CONFIG_EXT3_FS_SECURITY=y | 93 | CONFIG_EXT3_FS_SECURITY=y |
81 | CONFIG_AUTOFS4_FS=m | 94 | CONFIG_AUTOFS4_FS=m |
95 | CONFIG_FUSE_FS=y | ||
82 | CONFIG_MSDOS_FS=m | 96 | CONFIG_MSDOS_FS=m |
83 | CONFIG_VFAT_FS=m | 97 | CONFIG_VFAT_FS=m |
84 | CONFIG_FAT_DEFAULT_IOCHARSET="ascii" | 98 | CONFIG_FAT_DEFAULT_IOCHARSET="ascii" |
85 | CONFIG_TMPFS=y | 99 | CONFIG_TMPFS=y |
86 | CONFIG_JFFS2_FS=y | 100 | CONFIG_JFFS2_FS=y |
101 | CONFIG_NFS_FS=y | ||
102 | CONFIG_ROOT_NFS=y | ||
87 | CONFIG_NLS_DEFAULT="utf8" | 103 | CONFIG_NLS_DEFAULT="utf8" |
88 | CONFIG_NLS_CODEPAGE_437=y | 104 | CONFIG_NLS_CODEPAGE_437=y |
89 | CONFIG_NLS_ASCII=m | 105 | CONFIG_NLS_ASCII=m |
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index c07465361947..810fa5f15a51 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c | |||
@@ -200,6 +200,7 @@ static struct clk_lookup periph_clocks_lookups[] = { | |||
200 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), | 200 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), |
201 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), | 201 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), |
202 | CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk), | 202 | CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk), |
203 | CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk), | ||
203 | /* fake hclk clock */ | 204 | /* fake hclk clock */ |
204 | CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), | 205 | CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), |
205 | CLKDEV_CON_ID("pioA", &pioA_clk), | 206 | CLKDEV_CON_ID("pioA", &pioA_clk), |
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 309390d8e2f8..cef0e2f57068 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c | |||
@@ -1131,9 +1131,7 @@ static void __init at91_add_device_watchdog(void) {} | |||
1131 | * PWM | 1131 | * PWM |
1132 | * --------------------------------------------------------------------*/ | 1132 | * --------------------------------------------------------------------*/ |
1133 | 1133 | ||
1134 | #if defined(CONFIG_ATMEL_PWM) | 1134 | #if IS_ENABLED(CONFIG_PWM_ATMEL) |
1135 | static u32 pwm_mask; | ||
1136 | |||
1137 | static struct resource pwm_resources[] = { | 1135 | static struct resource pwm_resources[] = { |
1138 | [0] = { | 1136 | [0] = { |
1139 | .start = AT91SAM9263_BASE_PWMC, | 1137 | .start = AT91SAM9263_BASE_PWMC, |
@@ -1148,11 +1146,8 @@ static struct resource pwm_resources[] = { | |||
1148 | }; | 1146 | }; |
1149 | 1147 | ||
1150 | static struct platform_device at91sam9263_pwm0_device = { | 1148 | static struct platform_device at91sam9263_pwm0_device = { |
1151 | .name = "atmel_pwm", | 1149 | .name = "at91sam9rl-pwm", |
1152 | .id = -1, | 1150 | .id = -1, |
1153 | .dev = { | ||
1154 | .platform_data = &pwm_mask, | ||
1155 | }, | ||
1156 | .resource = pwm_resources, | 1151 | .resource = pwm_resources, |
1157 | .num_resources = ARRAY_SIZE(pwm_resources), | 1152 | .num_resources = ARRAY_SIZE(pwm_resources), |
1158 | }; | 1153 | }; |
@@ -1171,8 +1166,6 @@ void __init at91_add_device_pwm(u32 mask) | |||
1171 | if (mask & (1 << AT91_PWM3)) | 1166 | if (mask & (1 << AT91_PWM3)) |
1172 | at91_set_B_periph(AT91_PIN_PB29, 1); /* enable PWM3 */ | 1167 | at91_set_B_periph(AT91_PIN_PB29, 1); /* enable PWM3 */ |
1173 | 1168 | ||
1174 | pwm_mask = mask; | ||
1175 | |||
1176 | platform_device_register(&at91sam9263_pwm0_device); | 1169 | platform_device_register(&at91sam9263_pwm0_device); |
1177 | } | 1170 | } |
1178 | #else | 1171 | #else |
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 0d5d85797cd6..9d45496e4932 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c | |||
@@ -252,6 +252,7 @@ static struct clk_lookup periph_clocks_lookups[] = { | |||
252 | CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk), | 252 | CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk), |
253 | CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk), | 253 | CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk), |
254 | CLKDEV_CON_DEV_ID(NULL, "atmel_aes", &aestdessha_clk), | 254 | CLKDEV_CON_DEV_ID(NULL, "atmel_aes", &aestdessha_clk), |
255 | CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk), | ||
255 | /* more usart lookup table for DT entries */ | 256 | /* more usart lookup table for DT entries */ |
256 | CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck), | 257 | CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck), |
257 | CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk), | 258 | CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk), |
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 391ab6bb536a..21ab782cc8e9 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c | |||
@@ -1334,9 +1334,7 @@ static void __init at91_add_device_watchdog(void) {} | |||
1334 | * PWM | 1334 | * PWM |
1335 | * --------------------------------------------------------------------*/ | 1335 | * --------------------------------------------------------------------*/ |
1336 | 1336 | ||
1337 | #if defined(CONFIG_ATMEL_PWM) || defined(CONFIG_ATMEL_PWM_MODULE) | 1337 | #if IS_ENABLED(CONFIG_PWM_ATMEL) |
1338 | static u32 pwm_mask; | ||
1339 | |||
1340 | static struct resource pwm_resources[] = { | 1338 | static struct resource pwm_resources[] = { |
1341 | [0] = { | 1339 | [0] = { |
1342 | .start = AT91SAM9G45_BASE_PWMC, | 1340 | .start = AT91SAM9G45_BASE_PWMC, |
@@ -1351,11 +1349,8 @@ static struct resource pwm_resources[] = { | |||
1351 | }; | 1349 | }; |
1352 | 1350 | ||
1353 | static struct platform_device at91sam9g45_pwm0_device = { | 1351 | static struct platform_device at91sam9g45_pwm0_device = { |
1354 | .name = "atmel_pwm", | 1352 | .name = "at91sam9rl-pwm", |
1355 | .id = -1, | 1353 | .id = -1, |
1356 | .dev = { | ||
1357 | .platform_data = &pwm_mask, | ||
1358 | }, | ||
1359 | .resource = pwm_resources, | 1354 | .resource = pwm_resources, |
1360 | .num_resources = ARRAY_SIZE(pwm_resources), | 1355 | .num_resources = ARRAY_SIZE(pwm_resources), |
1361 | }; | 1356 | }; |
@@ -1374,8 +1369,6 @@ void __init at91_add_device_pwm(u32 mask) | |||
1374 | if (mask & (1 << AT91_PWM3)) | 1369 | if (mask & (1 << AT91_PWM3)) |
1375 | at91_set_B_periph(AT91_PIN_PD0, 1); /* enable PWM3 */ | 1370 | at91_set_B_periph(AT91_PIN_PD0, 1); /* enable PWM3 */ |
1376 | 1371 | ||
1377 | pwm_mask = mask; | ||
1378 | |||
1379 | platform_device_register(&at91sam9g45_pwm0_device); | 1372 | platform_device_register(&at91sam9g45_pwm0_device); |
1380 | } | 1373 | } |
1381 | #else | 1374 | #else |
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index a79960f57e6a..878d5015daab 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c | |||
@@ -200,6 +200,7 @@ static struct clk_lookup periph_clocks_lookups[] = { | |||
200 | CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc1_clk), | 200 | CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc1_clk), |
201 | CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk), | 201 | CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk), |
202 | CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk), | 202 | CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk), |
203 | CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk), | ||
203 | CLKDEV_CON_ID("pioA", &pioA_clk), | 204 | CLKDEV_CON_ID("pioA", &pioA_clk), |
204 | CLKDEV_CON_ID("pioB", &pioB_clk), | 205 | CLKDEV_CON_ID("pioB", &pioB_clk), |
205 | CLKDEV_CON_ID("pioC", &pioC_clk), | 206 | CLKDEV_CON_ID("pioC", &pioC_clk), |
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index 0b1d71a7d9bf..37d1c9ed4562 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c | |||
@@ -799,9 +799,7 @@ static void __init at91_add_device_watchdog(void) {} | |||
799 | * PWM | 799 | * PWM |
800 | * --------------------------------------------------------------------*/ | 800 | * --------------------------------------------------------------------*/ |
801 | 801 | ||
802 | #if defined(CONFIG_ATMEL_PWM) | 802 | #if IS_ENABLED(CONFIG_PWM_ATMEL) |
803 | static u32 pwm_mask; | ||
804 | |||
805 | static struct resource pwm_resources[] = { | 803 | static struct resource pwm_resources[] = { |
806 | [0] = { | 804 | [0] = { |
807 | .start = AT91SAM9RL_BASE_PWMC, | 805 | .start = AT91SAM9RL_BASE_PWMC, |
@@ -816,11 +814,8 @@ static struct resource pwm_resources[] = { | |||
816 | }; | 814 | }; |
817 | 815 | ||
818 | static struct platform_device at91sam9rl_pwm0_device = { | 816 | static struct platform_device at91sam9rl_pwm0_device = { |
819 | .name = "atmel_pwm", | 817 | .name = "at91sam9rl-pwm", |
820 | .id = -1, | 818 | .id = -1, |
821 | .dev = { | ||
822 | .platform_data = &pwm_mask, | ||
823 | }, | ||
824 | .resource = pwm_resources, | 819 | .resource = pwm_resources, |
825 | .num_resources = ARRAY_SIZE(pwm_resources), | 820 | .num_resources = ARRAY_SIZE(pwm_resources), |
826 | }; | 821 | }; |
@@ -839,8 +834,6 @@ void __init at91_add_device_pwm(u32 mask) | |||
839 | if (mask & (1 << AT91_PWM3)) | 834 | if (mask & (1 << AT91_PWM3)) |
840 | at91_set_B_periph(AT91_PIN_PD8, 1); /* enable PWM3 */ | 835 | at91_set_B_periph(AT91_PIN_PD8, 1); /* enable PWM3 */ |
841 | 836 | ||
842 | pwm_mask = mask; | ||
843 | |||
844 | platform_device_register(&at91sam9rl_pwm0_device); | 837 | platform_device_register(&at91sam9rl_pwm0_device); |
845 | } | 838 | } |
846 | #else | 839 | #else |
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index cd2726ee5add..fc446097f410 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/gpio_keys.h> | 32 | #include <linux/gpio_keys.h> |
33 | #include <linux/input.h> | 33 | #include <linux/input.h> |
34 | #include <linux/leds.h> | 34 | #include <linux/leds.h> |
35 | #include <linux/pwm.h> | ||
36 | #include <linux/leds_pwm.h> | ||
35 | 37 | ||
36 | #include <video/atmel_lcdc.h> | 38 | #include <video/atmel_lcdc.h> |
37 | 39 | ||
@@ -369,21 +371,47 @@ static struct gpio_led ek_leds[] = { | |||
369 | .name = "ds3", | 371 | .name = "ds3", |
370 | .gpio = AT91_PIN_PB7, | 372 | .gpio = AT91_PIN_PB7, |
371 | .default_trigger = "heartbeat", | 373 | .default_trigger = "heartbeat", |
374 | }, | ||
375 | #if !IS_ENABLED(CONFIG_LEDS_PWM) | ||
376 | { | ||
377 | .name = "ds1", | ||
378 | .gpio = AT91_PIN_PB8, | ||
379 | .active_low = 1, | ||
380 | .default_trigger = "none", | ||
372 | } | 381 | } |
382 | #endif | ||
373 | }; | 383 | }; |
374 | 384 | ||
375 | /* | 385 | /* |
376 | * PWM Leds | 386 | * PWM Leds |
377 | */ | 387 | */ |
378 | static struct gpio_led ek_pwm_led[] = { | 388 | static struct pwm_lookup pwm_lookup[] = { |
379 | /* For now only DS1 is PWM-driven (by pwm1) */ | 389 | PWM_LOOKUP("at91sam9rl-pwm", 1, "leds_pwm", "ds1", |
390 | 5000, PWM_POLARITY_INVERSED), | ||
391 | }; | ||
392 | |||
393 | #if IS_ENABLED(CONFIG_LEDS_PWM) | ||
394 | static struct led_pwm pwm_leds[] = { | ||
380 | { | 395 | { |
381 | .name = "ds1", | 396 | .name = "ds1", |
382 | .gpio = 1, /* is PWM channel number */ | 397 | .max_brightness = 255, |
383 | .active_low = 1, | 398 | }, |
384 | .default_trigger = "none", | 399 | }; |
385 | } | 400 | |
401 | static struct led_pwm_platform_data pwm_data = { | ||
402 | .num_leds = ARRAY_SIZE(pwm_leds), | ||
403 | .leds = pwm_leds, | ||
404 | }; | ||
405 | |||
406 | static struct platform_device leds_pwm = { | ||
407 | .name = "leds_pwm", | ||
408 | .id = -1, | ||
409 | .dev = { | ||
410 | .platform_data = &pwm_data, | ||
411 | }, | ||
386 | }; | 412 | }; |
413 | #endif | ||
414 | |||
387 | 415 | ||
388 | /* | 416 | /* |
389 | * CAN | 417 | * CAN |
@@ -403,6 +431,12 @@ static struct at91_can_data ek_can_data = { | |||
403 | .transceiver_switch = sam9263ek_transceiver_switch, | 431 | .transceiver_switch = sam9263ek_transceiver_switch, |
404 | }; | 432 | }; |
405 | 433 | ||
434 | static struct platform_device *devices[] __initdata = { | ||
435 | #if IS_ENABLED(CONFIG_LEDS_PWM) | ||
436 | &leds_pwm, | ||
437 | #endif | ||
438 | }; | ||
439 | |||
406 | static void __init ek_board_init(void) | 440 | static void __init ek_board_init(void) |
407 | { | 441 | { |
408 | /* Serial */ | 442 | /* Serial */ |
@@ -437,9 +471,14 @@ static void __init ek_board_init(void) | |||
437 | at91_add_device_ac97(&ek_ac97_data); | 471 | at91_add_device_ac97(&ek_ac97_data); |
438 | /* LEDs */ | 472 | /* LEDs */ |
439 | at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); | 473 | at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); |
440 | at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led)); | 474 | pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup)); |
475 | #if IS_ENABLED(CONFIG_LEDS_PWM) | ||
476 | at91_add_device_pwm(1 << AT91_PWM1); | ||
477 | #endif | ||
441 | /* CAN */ | 478 | /* CAN */ |
442 | at91_add_device_can(&ek_can_data); | 479 | at91_add_device_can(&ek_can_data); |
480 | /* Other platform devices */ | ||
481 | platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
443 | } | 482 | } |
444 | 483 | ||
445 | MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK") | 484 | MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK") |
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index 1ea61328f30d..b227732b0c83 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/leds.h> | 26 | #include <linux/leds.h> |
27 | #include <linux/atmel-mci.h> | 27 | #include <linux/atmel-mci.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/pwm.h> | ||
30 | #include <linux/leds_pwm.h> | ||
29 | 31 | ||
30 | #include <linux/platform_data/at91_adc.h> | 32 | #include <linux/platform_data/at91_adc.h> |
31 | 33 | ||
@@ -416,7 +418,7 @@ static struct gpio_led ek_leds[] = { | |||
416 | .active_low = 1, | 418 | .active_low = 1, |
417 | .default_trigger = "nand-disk", | 419 | .default_trigger = "nand-disk", |
418 | }, | 420 | }, |
419 | #if !(defined(CONFIG_LEDS_ATMEL_PWM) || defined(CONFIG_LEDS_ATMEL_PWM_MODULE)) | 421 | #if !IS_ENABLED(CONFIG_LEDS_PWM) |
420 | { /* "right" led, green, userled1, pwm1 */ | 422 | { /* "right" led, green, userled1, pwm1 */ |
421 | .name = "d7", | 423 | .name = "d7", |
422 | .gpio = AT91_PIN_PD31, | 424 | .gpio = AT91_PIN_PD31, |
@@ -430,22 +432,41 @@ static struct gpio_led ek_leds[] = { | |||
430 | /* | 432 | /* |
431 | * PWM Leds | 433 | * PWM Leds |
432 | */ | 434 | */ |
433 | static struct gpio_led ek_pwm_led[] = { | 435 | static struct pwm_lookup pwm_lookup[] = { |
434 | #if defined(CONFIG_LEDS_ATMEL_PWM) || defined(CONFIG_LEDS_ATMEL_PWM_MODULE) | 436 | PWM_LOOKUP("at91sam9rl-pwm", 1, "leds_pwm", "d7", |
437 | 5000, PWM_POLARITY_INVERSED), | ||
438 | }; | ||
439 | |||
440 | #if IS_ENABLED(CONFIG_LEDS_PWM) | ||
441 | static struct led_pwm pwm_leds[] = { | ||
435 | { /* "right" led, green, userled1, pwm1 */ | 442 | { /* "right" led, green, userled1, pwm1 */ |
436 | .name = "d7", | 443 | .name = "d7", |
437 | .gpio = 1, /* is PWM channel number */ | 444 | .max_brightness = 255, |
438 | .active_low = 1, | ||
439 | .default_trigger = "none", | ||
440 | }, | 445 | }, |
441 | #endif | ||
442 | }; | 446 | }; |
443 | 447 | ||
448 | static struct led_pwm_platform_data pwm_data = { | ||
449 | .num_leds = ARRAY_SIZE(pwm_leds), | ||
450 | .leds = pwm_leds, | ||
451 | }; | ||
452 | |||
453 | static struct platform_device leds_pwm = { | ||
454 | .name = "leds_pwm", | ||
455 | .id = -1, | ||
456 | .dev = { | ||
457 | .platform_data = &pwm_data, | ||
458 | }, | ||
459 | }; | ||
460 | #endif | ||
461 | |||
444 | static struct platform_device *devices[] __initdata = { | 462 | static struct platform_device *devices[] __initdata = { |
445 | #if defined(CONFIG_SOC_CAMERA_OV2640) || \ | 463 | #if defined(CONFIG_SOC_CAMERA_OV2640) || \ |
446 | defined(CONFIG_SOC_CAMERA_OV2640_MODULE) | 464 | defined(CONFIG_SOC_CAMERA_OV2640_MODULE) |
447 | &isi_ov2640, | 465 | &isi_ov2640, |
448 | #endif | 466 | #endif |
467 | #if IS_ENABLED(CONFIG_LEDS_PWM) | ||
468 | &leds_pwm, | ||
469 | #endif | ||
449 | }; | 470 | }; |
450 | 471 | ||
451 | static void __init ek_board_init(void) | 472 | static void __init ek_board_init(void) |
@@ -486,7 +507,10 @@ static void __init ek_board_init(void) | |||
486 | at91_add_device_ac97(&ek_ac97_data); | 507 | at91_add_device_ac97(&ek_ac97_data); |
487 | /* LEDs */ | 508 | /* LEDs */ |
488 | at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); | 509 | at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); |
489 | at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led)); | 510 | pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup)); |
511 | #if IS_ENABLED(CONFIG_LEDS_PWM) | ||
512 | at91_add_device_pwm(1 << AT91_PWM1); | ||
513 | #endif | ||
490 | /* Other platform devices */ | 514 | /* Other platform devices */ |
491 | platform_add_devices(devices, ARRAY_SIZE(devices)); | 515 | platform_add_devices(devices, ARRAY_SIZE(devices)); |
492 | } | 516 | } |
diff --git a/arch/arm/mach-at91/board.h b/arch/arm/mach-at91/board.h index 4e773b55bc2d..836e9a537e0c 100644 --- a/arch/arm/mach-at91/board.h +++ b/arch/arm/mach-at91/board.h | |||
@@ -123,6 +123,5 @@ extern void __init at91_add_device_can(struct at91_can_data *data); | |||
123 | 123 | ||
124 | /* LEDs */ | 124 | /* LEDs */ |
125 | extern void __init at91_gpio_leds(struct gpio_led *leds, int nr); | 125 | extern void __init at91_gpio_leds(struct gpio_led *leds, int nr); |
126 | extern void __init at91_pwm_leds(struct gpio_led *leds, int nr); | ||
127 | 126 | ||
128 | #endif | 127 | #endif |
diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c index 77c4d8fd03fd..eb22e3357e87 100644 --- a/arch/arm/mach-at91/leds.c +++ b/arch/arm/mach-at91/leds.c | |||
@@ -54,40 +54,3 @@ void __init at91_gpio_leds(struct gpio_led *leds, int nr) | |||
54 | void __init at91_gpio_leds(struct gpio_led *leds, int nr) {} | 54 | void __init at91_gpio_leds(struct gpio_led *leds, int nr) {} |
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | |||
58 | /* ------------------------------------------------------------------------- */ | ||
59 | |||
60 | #if defined (CONFIG_LEDS_ATMEL_PWM) | ||
61 | |||
62 | /* | ||
63 | * PWM Leds | ||
64 | */ | ||
65 | |||
66 | static struct gpio_led_platform_data pwm_led_data; | ||
67 | |||
68 | static struct platform_device at91_pwm_leds_device = { | ||
69 | .name = "leds-atmel-pwm", | ||
70 | .id = -1, | ||
71 | .dev.platform_data = &pwm_led_data, | ||
72 | }; | ||
73 | |||
74 | void __init at91_pwm_leds(struct gpio_led *leds, int nr) | ||
75 | { | ||
76 | int i; | ||
77 | u32 pwm_mask = 0; | ||
78 | |||
79 | if (!nr) | ||
80 | return; | ||
81 | |||
82 | for (i = 0; i < nr; i++) | ||
83 | pwm_mask |= (1 << leds[i].gpio); | ||
84 | |||
85 | pwm_led_data.leds = leds; | ||
86 | pwm_led_data.num_leds = nr; | ||
87 | |||
88 | at91_add_device_pwm(pwm_mask); | ||
89 | platform_device_register(&at91_pwm_leds_device); | ||
90 | } | ||
91 | #else | ||
92 | void __init at91_pwm_leds(struct gpio_led *leds, int nr){} | ||
93 | #endif | ||
diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig index 90df2022276a..6fd4dc88160b 100644 --- a/arch/arm/mach-spear/Kconfig +++ b/arch/arm/mach-spear/Kconfig | |||
@@ -19,6 +19,8 @@ config ARCH_SPEAR13XX | |||
19 | select HAVE_ARM_SCU if SMP | 19 | select HAVE_ARM_SCU if SMP |
20 | select HAVE_ARM_TWD if SMP | 20 | select HAVE_ARM_TWD if SMP |
21 | select PINCTRL | 21 | select PINCTRL |
22 | select MFD_SYSCON | ||
23 | select MIGHT_HAVE_PCI | ||
22 | help | 24 | help |
23 | Supports for ARM's SPEAR13XX family | 25 | Supports for ARM's SPEAR13XX family |
24 | 26 | ||
@@ -27,12 +29,14 @@ if ARCH_SPEAR13XX | |||
27 | config MACH_SPEAR1310 | 29 | config MACH_SPEAR1310 |
28 | bool "SPEAr1310 Machine support with Device Tree" | 30 | bool "SPEAr1310 Machine support with Device Tree" |
29 | select PINCTRL_SPEAR1310 | 31 | select PINCTRL_SPEAR1310 |
32 | select PHY_ST_SPEAR1310_MIPHY | ||
30 | help | 33 | help |
31 | Supports ST SPEAr1310 machine configured via the device-tree | 34 | Supports ST SPEAr1310 machine configured via the device-tree |
32 | 35 | ||
33 | config MACH_SPEAR1340 | 36 | config MACH_SPEAR1340 |
34 | bool "SPEAr1340 Machine support with Device Tree" | 37 | bool "SPEAr1340 Machine support with Device Tree" |
35 | select PINCTRL_SPEAR1340 | 38 | select PINCTRL_SPEAR1340 |
39 | select PHY_ST_SPEAR1340_MIPHY | ||
36 | help | 40 | help |
37 | Supports ST SPEAr1340 machine configured via the device-tree | 41 | Supports ST SPEAr1340 machine configured via the device-tree |
38 | 42 | ||
diff --git a/arch/arm/mach-spear/include/mach/spear.h b/arch/arm/mach-spear/include/mach/spear.h index 5cdc53d9b653..f2d6a0176575 100644 --- a/arch/arm/mach-spear/include/mach/spear.h +++ b/arch/arm/mach-spear/include/mach/spear.h | |||
@@ -52,10 +52,10 @@ | |||
52 | #ifdef CONFIG_ARCH_SPEAR13XX | 52 | #ifdef CONFIG_ARCH_SPEAR13XX |
53 | 53 | ||
54 | #define PERIP_GRP2_BASE UL(0xB3000000) | 54 | #define PERIP_GRP2_BASE UL(0xB3000000) |
55 | #define VA_PERIP_GRP2_BASE IOMEM(0xFE000000) | 55 | #define VA_PERIP_GRP2_BASE IOMEM(0xF9000000) |
56 | #define MCIF_SDHCI_BASE UL(0xB3000000) | 56 | #define MCIF_SDHCI_BASE UL(0xB3000000) |
57 | #define SYSRAM0_BASE UL(0xB3800000) | 57 | #define SYSRAM0_BASE UL(0xB3800000) |
58 | #define VA_SYSRAM0_BASE IOMEM(0xFE800000) | 58 | #define VA_SYSRAM0_BASE IOMEM(0xF9800000) |
59 | #define SYS_LOCATION (VA_SYSRAM0_BASE + 0x600) | 59 | #define SYS_LOCATION (VA_SYSRAM0_BASE + 0x600) |
60 | 60 | ||
61 | #define PERIP_GRP1_BASE UL(0xE0000000) | 61 | #define PERIP_GRP1_BASE UL(0xE0000000) |
diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c index c601799b4aea..3f3c0f124bd3 100644 --- a/arch/arm/mach-spear/spear1340.c +++ b/arch/arm/mach-spear/spear1340.c | |||
@@ -13,136 +13,13 @@ | |||
13 | 13 | ||
14 | #define pr_fmt(fmt) "SPEAr1340: " fmt | 14 | #define pr_fmt(fmt) "SPEAr1340: " fmt |
15 | 15 | ||
16 | #include <linux/ahci_platform.h> | ||
17 | #include <linux/amba/serial.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/of_platform.h> | 16 | #include <linux/of_platform.h> |
20 | #include <asm/mach/arch.h> | 17 | #include <asm/mach/arch.h> |
21 | #include "generic.h" | 18 | #include "generic.h" |
22 | #include <mach/spear.h> | ||
23 | |||
24 | /* FIXME: Move SATA PHY code into a standalone driver */ | ||
25 | |||
26 | /* Base addresses */ | ||
27 | #define SPEAR1340_SATA_BASE UL(0xB1000000) | ||
28 | |||
29 | /* Power Management Registers */ | ||
30 | #define SPEAR1340_PCM_CFG (VA_MISC_BASE + 0x100) | ||
31 | #define SPEAR1340_PCM_WKUP_CFG (VA_MISC_BASE + 0x104) | ||
32 | #define SPEAR1340_SWITCH_CTR (VA_MISC_BASE + 0x108) | ||
33 | |||
34 | #define SPEAR1340_PERIP1_SW_RST (VA_MISC_BASE + 0x318) | ||
35 | #define SPEAR1340_PERIP2_SW_RST (VA_MISC_BASE + 0x31C) | ||
36 | #define SPEAR1340_PERIP3_SW_RST (VA_MISC_BASE + 0x320) | ||
37 | |||
38 | /* PCIE - SATA configuration registers */ | ||
39 | #define SPEAR1340_PCIE_SATA_CFG (VA_MISC_BASE + 0x424) | ||
40 | /* PCIE CFG MASks */ | ||
41 | #define SPEAR1340_PCIE_CFG_DEVICE_PRESENT (1 << 11) | ||
42 | #define SPEAR1340_PCIE_CFG_POWERUP_RESET (1 << 10) | ||
43 | #define SPEAR1340_PCIE_CFG_CORE_CLK_EN (1 << 9) | ||
44 | #define SPEAR1340_PCIE_CFG_AUX_CLK_EN (1 << 8) | ||
45 | #define SPEAR1340_SATA_CFG_TX_CLK_EN (1 << 4) | ||
46 | #define SPEAR1340_SATA_CFG_RX_CLK_EN (1 << 3) | ||
47 | #define SPEAR1340_SATA_CFG_POWERUP_RESET (1 << 2) | ||
48 | #define SPEAR1340_SATA_CFG_PM_CLK_EN (1 << 1) | ||
49 | #define SPEAR1340_PCIE_SATA_SEL_PCIE (0) | ||
50 | #define SPEAR1340_PCIE_SATA_SEL_SATA (1) | ||
51 | #define SPEAR1340_SATA_PCIE_CFG_MASK 0xF1F | ||
52 | #define SPEAR1340_PCIE_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_PCIE | \ | ||
53 | SPEAR1340_PCIE_CFG_AUX_CLK_EN | \ | ||
54 | SPEAR1340_PCIE_CFG_CORE_CLK_EN | \ | ||
55 | SPEAR1340_PCIE_CFG_POWERUP_RESET | \ | ||
56 | SPEAR1340_PCIE_CFG_DEVICE_PRESENT) | ||
57 | #define SPEAR1340_SATA_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_SATA | \ | ||
58 | SPEAR1340_SATA_CFG_PM_CLK_EN | \ | ||
59 | SPEAR1340_SATA_CFG_POWERUP_RESET | \ | ||
60 | SPEAR1340_SATA_CFG_RX_CLK_EN | \ | ||
61 | SPEAR1340_SATA_CFG_TX_CLK_EN) | ||
62 | |||
63 | #define SPEAR1340_PCIE_MIPHY_CFG (VA_MISC_BASE + 0x428) | ||
64 | #define SPEAR1340_MIPHY_OSC_BYPASS_EXT (1 << 31) | ||
65 | #define SPEAR1340_MIPHY_CLK_REF_DIV2 (1 << 27) | ||
66 | #define SPEAR1340_MIPHY_CLK_REF_DIV4 (2 << 27) | ||
67 | #define SPEAR1340_MIPHY_CLK_REF_DIV8 (3 << 27) | ||
68 | #define SPEAR1340_MIPHY_PLL_RATIO_TOP(x) (x << 0) | ||
69 | #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA \ | ||
70 | (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ | ||
71 | SPEAR1340_MIPHY_CLK_REF_DIV2 | \ | ||
72 | SPEAR1340_MIPHY_PLL_RATIO_TOP(60)) | ||
73 | #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \ | ||
74 | (SPEAR1340_MIPHY_PLL_RATIO_TOP(120)) | ||
75 | #define SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE \ | ||
76 | (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ | ||
77 | SPEAR1340_MIPHY_PLL_RATIO_TOP(25)) | ||
78 | |||
79 | /* SATA device registration */ | ||
80 | static int sata_miphy_init(struct device *dev, void __iomem *addr) | ||
81 | { | ||
82 | writel(SPEAR1340_SATA_CFG_VAL, SPEAR1340_PCIE_SATA_CFG); | ||
83 | writel(SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK, | ||
84 | SPEAR1340_PCIE_MIPHY_CFG); | ||
85 | /* Switch on sata power domain */ | ||
86 | writel((readl(SPEAR1340_PCM_CFG) | (0x800)), SPEAR1340_PCM_CFG); | ||
87 | msleep(20); | ||
88 | /* Disable PCIE SATA Controller reset */ | ||
89 | writel((readl(SPEAR1340_PERIP1_SW_RST) & (~0x1000)), | ||
90 | SPEAR1340_PERIP1_SW_RST); | ||
91 | msleep(20); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void sata_miphy_exit(struct device *dev) | ||
97 | { | ||
98 | writel(0, SPEAR1340_PCIE_SATA_CFG); | ||
99 | writel(0, SPEAR1340_PCIE_MIPHY_CFG); | ||
100 | |||
101 | /* Enable PCIE SATA Controller reset */ | ||
102 | writel((readl(SPEAR1340_PERIP1_SW_RST) | (0x1000)), | ||
103 | SPEAR1340_PERIP1_SW_RST); | ||
104 | msleep(20); | ||
105 | /* Switch off sata power domain */ | ||
106 | writel((readl(SPEAR1340_PCM_CFG) & (~0x800)), SPEAR1340_PCM_CFG); | ||
107 | msleep(20); | ||
108 | } | ||
109 | |||
110 | static int sata_suspend(struct device *dev) | ||
111 | { | ||
112 | if (dev->power.power_state.event == PM_EVENT_FREEZE) | ||
113 | return 0; | ||
114 | |||
115 | sata_miphy_exit(dev); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int sata_resume(struct device *dev) | ||
121 | { | ||
122 | if (dev->power.power_state.event == PM_EVENT_THAW) | ||
123 | return 0; | ||
124 | |||
125 | return sata_miphy_init(dev, NULL); | ||
126 | } | ||
127 | |||
128 | static struct ahci_platform_data sata_pdata = { | ||
129 | .init = sata_miphy_init, | ||
130 | .exit = sata_miphy_exit, | ||
131 | .suspend = sata_suspend, | ||
132 | .resume = sata_resume, | ||
133 | }; | ||
134 | |||
135 | /* Add SPEAr1340 auxdata to pass platform data */ | ||
136 | static struct of_dev_auxdata spear1340_auxdata_lookup[] __initdata = { | ||
137 | OF_DEV_AUXDATA("snps,spear-ahci", SPEAR1340_SATA_BASE, NULL, | ||
138 | &sata_pdata), | ||
139 | {} | ||
140 | }; | ||
141 | 19 | ||
142 | static void __init spear1340_dt_init(void) | 20 | static void __init spear1340_dt_init(void) |
143 | { | 21 | { |
144 | of_platform_populate(NULL, of_default_bus_match_table, | 22 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
145 | spear1340_auxdata_lookup, NULL); | ||
146 | platform_device_register_simple("spear-cpufreq", -1, NULL, 0); | 23 | platform_device_register_simple("spear-cpufreq", -1, NULL, 0); |
147 | } | 24 | } |
148 | 25 | ||
diff --git a/arch/arm/mach-spear/spear13xx.c b/arch/arm/mach-spear/spear13xx.c index 8b56fe61a492..2e463a93468d 100644 --- a/arch/arm/mach-spear/spear13xx.c +++ b/arch/arm/mach-spear/spear13xx.c | |||
@@ -52,7 +52,7 @@ void __init spear13xx_l2x0_init(void) | |||
52 | /* | 52 | /* |
53 | * Following will create 16MB static virtual/physical mappings | 53 | * Following will create 16MB static virtual/physical mappings |
54 | * PHYSICAL VIRTUAL | 54 | * PHYSICAL VIRTUAL |
55 | * 0xB3000000 0xFE000000 | 55 | * 0xB3000000 0xF9000000 |
56 | * 0xE0000000 0xFD000000 | 56 | * 0xE0000000 0xFD000000 |
57 | * 0xEC000000 0xFC000000 | 57 | * 0xEC000000 0xFC000000 |
58 | * 0xED000000 0xFB000000 | 58 | * 0xED000000 0xFB000000 |
diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c index 1ba09e4c02b1..91146b416cdb 100644 --- a/arch/avr32/boards/atngw100/mrmt.c +++ b/arch/avr32/boards/atngw100/mrmt.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <linux/fb.h> | 18 | #include <linux/fb.h> |
19 | #include <linux/leds.h> | 19 | #include <linux/leds.h> |
20 | #include <linux/pwm.h> | ||
21 | #include <linux/leds_pwm.h> | ||
20 | #include <linux/input.h> | 22 | #include <linux/input.h> |
21 | #include <linux/gpio_keys.h> | 23 | #include <linux/gpio_keys.h> |
22 | #include <linux/atmel_serial.h> | 24 | #include <linux/atmel_serial.h> |
@@ -155,21 +157,28 @@ static struct platform_device rmt_ts_device = { | |||
155 | 157 | ||
156 | #ifdef CONFIG_BOARD_MRMT_BL_PWM | 158 | #ifdef CONFIG_BOARD_MRMT_BL_PWM |
157 | /* PWM LEDs: LCD Backlight, etc */ | 159 | /* PWM LEDs: LCD Backlight, etc */ |
158 | static struct gpio_led rmt_pwm_led[] = { | 160 | static struct pwm_lookup pwm_lookup[] = { |
159 | /* here the "gpio" is actually a PWM channel */ | 161 | PWM_LOOKUP("at91sam9rl-pwm", PWM_CH_BL, "leds_pwm", "ds1", |
160 | { .name = "backlight", .gpio = PWM_CH_BL, }, | 162 | 5000, PWM_POLARITY_INVERSED), |
161 | }; | 163 | }; |
162 | 164 | ||
163 | static struct gpio_led_platform_data rmt_pwm_led_data = { | 165 | static struct led_pwm pwm_leds[] = { |
164 | .num_leds = ARRAY_SIZE(rmt_pwm_led), | 166 | { |
165 | .leds = rmt_pwm_led, | 167 | .name = "backlight", |
168 | .max_brightness = 255, | ||
169 | }, | ||
170 | }; | ||
171 | |||
172 | static struct led_pwm_platform_data pwm_data = { | ||
173 | .num_leds = ARRAY_SIZE(pwm_leds), | ||
174 | .leds = pwm_leds, | ||
166 | }; | 175 | }; |
167 | 176 | ||
168 | static struct platform_device rmt_pwm_led_dev = { | 177 | static struct platform_device leds_pwm = { |
169 | .name = "leds-atmel-pwm", | 178 | .name = "leds_pwm", |
170 | .id = -1, | 179 | .id = -1, |
171 | .dev = { | 180 | .dev = { |
172 | .platform_data = &rmt_pwm_led_data, | 181 | .platform_data = &pwm_data, |
173 | }, | 182 | }, |
174 | }; | 183 | }; |
175 | #endif | 184 | #endif |
@@ -325,7 +334,8 @@ static int __init mrmt1_init(void) | |||
325 | #ifdef CONFIG_BOARD_MRMT_BL_PWM | 334 | #ifdef CONFIG_BOARD_MRMT_BL_PWM |
326 | /* Use PWM for Backlight controls */ | 335 | /* Use PWM for Backlight controls */ |
327 | at32_add_device_pwm(1 << PWM_CH_BL); | 336 | at32_add_device_pwm(1 << PWM_CH_BL); |
328 | platform_device_register(&rmt_pwm_led_dev); | 337 | pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup)); |
338 | platform_device_register(&leds_pwm); | ||
329 | #else | 339 | #else |
330 | /* Backlight always on */ | 340 | /* Backlight always on */ |
331 | udelay( 1 ); | 341 | udelay( 1 ); |
diff --git a/arch/avr32/boards/favr-32/setup.c b/arch/avr32/boards/favr-32/setup.c index 1f121497b517..234cb071c601 100644 --- a/arch/avr32/boards/favr-32/setup.c +++ b/arch/avr32/boards/favr-32/setup.c | |||
@@ -18,7 +18,10 @@ | |||
18 | #include <linux/gpio.h> | 18 | #include <linux/gpio.h> |
19 | #include <linux/leds.h> | 19 | #include <linux/leds.h> |
20 | #include <linux/atmel-mci.h> | 20 | #include <linux/atmel-mci.h> |
21 | #include <linux/atmel-pwm-bl.h> | 21 | #include <linux/pwm.h> |
22 | #include <linux/pwm_backlight.h> | ||
23 | #include <linux/regulator/fixed.h> | ||
24 | #include <linux/regulator/machine.h> | ||
22 | #include <linux/spi/spi.h> | 25 | #include <linux/spi/spi.h> |
23 | #include <linux/spi/ads7846.h> | 26 | #include <linux/spi/ads7846.h> |
24 | 27 | ||
@@ -33,6 +36,8 @@ | |||
33 | #include <mach/board.h> | 36 | #include <mach/board.h> |
34 | #include <mach/portmux.h> | 37 | #include <mach/portmux.h> |
35 | 38 | ||
39 | #define PWM_BL_CH 2 | ||
40 | |||
36 | /* Oscillator frequencies. These are board-specific */ | 41 | /* Oscillator frequencies. These are board-specific */ |
37 | unsigned long at32_board_osc_rates[3] = { | 42 | unsigned long at32_board_osc_rates[3] = { |
38 | [0] = 32768, /* 32.768 kHz on RTC osc */ | 43 | [0] = 32768, /* 32.768 kHz on RTC osc */ |
@@ -227,29 +232,36 @@ void __init favr32_setup_leds(void) | |||
227 | platform_device_register(&favr32_led_dev); | 232 | platform_device_register(&favr32_led_dev); |
228 | } | 233 | } |
229 | 234 | ||
230 | static struct atmel_pwm_bl_platform_data atmel_pwm_bl_pdata = { | 235 | static struct pwm_lookup pwm_lookup[] = { |
231 | .pwm_channel = 2, | 236 | PWM_LOOKUP("at91sam9rl-pwm", PWM_BL_CH, "pwm-backlight.0", NULL, |
232 | .pwm_frequency = 200000, | 237 | 5000, PWM_POLARITY_INVERSED), |
233 | .pwm_compare_max = 345, | ||
234 | .pwm_duty_max = 345, | ||
235 | .pwm_duty_min = 90, | ||
236 | .pwm_active_low = 1, | ||
237 | .gpio_on = GPIO_PIN_PA(28), | ||
238 | .on_active_low = 0, | ||
239 | }; | 238 | }; |
240 | 239 | ||
241 | static struct platform_device atmel_pwm_bl_dev = { | 240 | static struct regulator_consumer_supply fixed_power_consumers[] = { |
242 | .name = "atmel-pwm-bl", | 241 | REGULATOR_SUPPLY("power", "pwm-backlight.0"), |
243 | .id = 0, | 242 | }; |
244 | .dev = { | 243 | |
245 | .platform_data = &atmel_pwm_bl_pdata, | 244 | static struct platform_pwm_backlight_data pwm_bl_data = { |
245 | .enable_gpio = GPIO_PIN_PA(28), | ||
246 | .max_brightness = 255, | ||
247 | .dft_brightness = 255, | ||
248 | .lth_brightness = 50, | ||
249 | }; | ||
250 | |||
251 | static struct platform_device pwm_bl_device = { | ||
252 | .name = "pwm-backlight", | ||
253 | .dev = { | ||
254 | .platform_data = &pwm_bl_data, | ||
246 | }, | 255 | }, |
247 | }; | 256 | }; |
248 | 257 | ||
249 | static void __init favr32_setup_atmel_pwm_bl(void) | 258 | static void __init favr32_setup_atmel_pwm_bl(void) |
250 | { | 259 | { |
251 | platform_device_register(&atmel_pwm_bl_dev); | 260 | pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup)); |
252 | at32_select_gpio(atmel_pwm_bl_pdata.gpio_on, 0); | 261 | regulator_register_always_on(0, "fixed", fixed_power_consumers, |
262 | ARRAY_SIZE(fixed_power_consumers), 3300000); | ||
263 | platform_device_register(&pwm_bl_device); | ||
264 | at32_select_gpio(pwm_bl_data.enable_gpio, 0); | ||
253 | } | 265 | } |
254 | 266 | ||
255 | void __init setup_board(void) | 267 | void __init setup_board(void) |
@@ -339,7 +351,7 @@ static int __init favr32_init(void) | |||
339 | 351 | ||
340 | set_abdac_rate(at32_add_device_abdac(0, &abdac0_data)); | 352 | set_abdac_rate(at32_add_device_abdac(0, &abdac0_data)); |
341 | 353 | ||
342 | at32_add_device_pwm(1 << atmel_pwm_bl_pdata.pwm_channel); | 354 | at32_add_device_pwm(1 << PWM_BL_CH); |
343 | at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); | 355 | at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); |
344 | at32_add_device_mci(0, &mci0_data); | 356 | at32_add_device_mci(0, &mci0_data); |
345 | at32_add_device_usba(0, NULL); | 357 | at32_add_device_usba(0, NULL); |
diff --git a/arch/avr32/boards/merisc/setup.c b/arch/avr32/boards/merisc/setup.c index ed137e335796..83d896cc2aed 100644 --- a/arch/avr32/boards/merisc/setup.c +++ b/arch/avr32/boards/merisc/setup.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
23 | #include <linux/fb.h> | 23 | #include <linux/fb.h> |
24 | #include <linux/atmel-mci.h> | 24 | #include <linux/atmel-mci.h> |
25 | #include <linux/pwm.h> | ||
26 | #include <linux/leds_pwm.h> | ||
25 | 27 | ||
26 | #include <asm/io.h> | 28 | #include <asm/io.h> |
27 | #include <asm/setup.h> | 29 | #include <asm/setup.h> |
@@ -167,24 +169,29 @@ static struct i2c_board_info __initdata i2c_info[] = { | |||
167 | }, | 169 | }, |
168 | }; | 170 | }; |
169 | 171 | ||
170 | #ifdef CONFIG_LEDS_ATMEL_PWM | 172 | #if IS_ENABLED(CONFIG_LEDS_PWM) |
171 | static struct gpio_led stk_pwm_led[] = { | 173 | static struct pwm_lookup pwm_lookup[] = { |
174 | PWM_LOOKUP("at91sam9rl-pwm", 0, "leds_pwm", "backlight", | ||
175 | 5000, PWM_POLARITY_NORMAL), | ||
176 | }; | ||
177 | |||
178 | static struct led_pwm pwm_leds[] = { | ||
172 | { | 179 | { |
173 | .name = "backlight", | 180 | .name = "backlight", |
174 | .gpio = 0, /* PWM channel 0 (LCD backlight) */ | 181 | .max_brightness = 255, |
175 | }, | 182 | }, |
176 | }; | 183 | }; |
177 | 184 | ||
178 | static struct gpio_led_platform_data stk_pwm_led_data = { | 185 | static struct led_pwm_platform_data pwm_data = { |
179 | .num_leds = ARRAY_SIZE(stk_pwm_led), | 186 | .num_leds = ARRAY_SIZE(pwm_leds), |
180 | .leds = stk_pwm_led, | 187 | .leds = pwm_leds, |
181 | }; | 188 | }; |
182 | 189 | ||
183 | static struct platform_device stk_pwm_led_dev = { | 190 | static struct platform_device leds_pwm = { |
184 | .name = "leds-atmel-pwm", | 191 | .name = "leds_pwm", |
185 | .id = -1, | 192 | .id = -1, |
186 | .dev = { | 193 | .dev = { |
187 | .platform_data = &stk_pwm_led_data, | 194 | .platform_data = &pwm_data, |
188 | }, | 195 | }, |
189 | }; | 196 | }; |
190 | #endif | 197 | #endif |
@@ -278,9 +285,10 @@ static int __init merisc_init(void) | |||
278 | 285 | ||
279 | at32_add_device_mci(0, &mci0_data); | 286 | at32_add_device_mci(0, &mci0_data); |
280 | 287 | ||
281 | #ifdef CONFIG_LEDS_ATMEL_PWM | 288 | #if IS_ENABLED(CONFIG_LEDS_PWM) |
289 | pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup)); | ||
282 | at32_add_device_pwm((1 << 0) | (1 << 2)); | 290 | at32_add_device_pwm((1 << 0) | (1 << 2)); |
283 | platform_device_register(&stk_pwm_led_dev); | 291 | platform_device_register(&leds_pwm); |
284 | #else | 292 | #else |
285 | at32_add_device_pwm((1 << 2)); | 293 | at32_add_device_pwm((1 << 2)); |
286 | #endif | 294 | #endif |
diff --git a/arch/avr32/configs/atngw100_mrmt_defconfig b/arch/avr32/configs/atngw100_mrmt_defconfig index 9a57da44eb6f..6838781e966f 100644 --- a/arch/avr32/configs/atngw100_mrmt_defconfig +++ b/arch/avr32/configs/atngw100_mrmt_defconfig | |||
@@ -56,7 +56,6 @@ CONFIG_MTD_CFI_AMDSTD=y | |||
56 | CONFIG_MTD_PHYSMAP=y | 56 | CONFIG_MTD_PHYSMAP=y |
57 | CONFIG_MTD_DATAFLASH=y | 57 | CONFIG_MTD_DATAFLASH=y |
58 | CONFIG_BLK_DEV_LOOP=y | 58 | CONFIG_BLK_DEV_LOOP=y |
59 | CONFIG_ATMEL_PWM=y | ||
60 | CONFIG_NETDEVICES=y | 59 | CONFIG_NETDEVICES=y |
61 | CONFIG_NET_ETHERNET=y | 60 | CONFIG_NET_ETHERNET=y |
62 | CONFIG_MACB=y | 61 | CONFIG_MACB=y |
@@ -104,8 +103,8 @@ CONFIG_MMC=y | |||
104 | CONFIG_MMC_ATMELMCI=y | 103 | CONFIG_MMC_ATMELMCI=y |
105 | CONFIG_NEW_LEDS=y | 104 | CONFIG_NEW_LEDS=y |
106 | CONFIG_LEDS_CLASS=y | 105 | CONFIG_LEDS_CLASS=y |
107 | CONFIG_LEDS_ATMEL_PWM=y | ||
108 | CONFIG_LEDS_GPIO=y | 106 | CONFIG_LEDS_GPIO=y |
107 | CONFIG_LEDS_PWM=y | ||
109 | CONFIG_LEDS_TRIGGERS=y | 108 | CONFIG_LEDS_TRIGGERS=y |
110 | CONFIG_LEDS_TRIGGER_TIMER=y | 109 | CONFIG_LEDS_TRIGGER_TIMER=y |
111 | CONFIG_LEDS_TRIGGER_HEARTBEAT=y | 110 | CONFIG_LEDS_TRIGGER_HEARTBEAT=y |
@@ -114,6 +113,8 @@ CONFIG_RTC_DRV_S35390A=m | |||
114 | CONFIG_RTC_DRV_AT32AP700X=m | 113 | CONFIG_RTC_DRV_AT32AP700X=m |
115 | CONFIG_DMADEVICES=y | 114 | CONFIG_DMADEVICES=y |
116 | CONFIG_UIO=y | 115 | CONFIG_UIO=y |
116 | CONFIG_PWM=y | ||
117 | CONFIG_PWM_ATMEL=y | ||
117 | CONFIG_EXT2_FS=y | 118 | CONFIG_EXT2_FS=y |
118 | CONFIG_EXT2_FS_XATTR=y | 119 | CONFIG_EXT2_FS_XATTR=y |
119 | CONFIG_EXT3_FS=y | 120 | CONFIG_EXT3_FS=y |
diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig index 2813dd2b9138..b056820eef33 100644 --- a/arch/avr32/configs/atstk1002_defconfig +++ b/arch/avr32/configs/atstk1002_defconfig | |||
@@ -64,7 +64,6 @@ CONFIG_BLK_DEV_LOOP=m | |||
64 | CONFIG_BLK_DEV_NBD=m | 64 | CONFIG_BLK_DEV_NBD=m |
65 | CONFIG_BLK_DEV_RAM=m | 65 | CONFIG_BLK_DEV_RAM=m |
66 | CONFIG_MISC_DEVICES=y | 66 | CONFIG_MISC_DEVICES=y |
67 | CONFIG_ATMEL_PWM=m | ||
68 | CONFIG_ATMEL_TCLIB=y | 67 | CONFIG_ATMEL_TCLIB=y |
69 | CONFIG_ATMEL_SSC=m | 68 | CONFIG_ATMEL_SSC=m |
70 | # CONFIG_SCSI_PROC_FS is not set | 69 | # CONFIG_SCSI_PROC_FS is not set |
@@ -133,14 +132,16 @@ CONFIG_MMC_TEST=m | |||
133 | CONFIG_MMC_ATMELMCI=y | 132 | CONFIG_MMC_ATMELMCI=y |
134 | CONFIG_NEW_LEDS=y | 133 | CONFIG_NEW_LEDS=y |
135 | CONFIG_LEDS_CLASS=y | 134 | CONFIG_LEDS_CLASS=y |
136 | CONFIG_LEDS_ATMEL_PWM=m | ||
137 | CONFIG_LEDS_GPIO=m | 135 | CONFIG_LEDS_GPIO=m |
136 | CONFIG_LEDS_PWM=m | ||
138 | CONFIG_LEDS_TRIGGERS=y | 137 | CONFIG_LEDS_TRIGGERS=y |
139 | CONFIG_LEDS_TRIGGER_TIMER=m | 138 | CONFIG_LEDS_TRIGGER_TIMER=m |
140 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m | 139 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m |
141 | CONFIG_RTC_CLASS=y | 140 | CONFIG_RTC_CLASS=y |
142 | CONFIG_RTC_DRV_AT32AP700X=y | 141 | CONFIG_RTC_DRV_AT32AP700X=y |
143 | CONFIG_DMADEVICES=y | 142 | CONFIG_DMADEVICES=y |
143 | CONFIG_PWM=y | ||
144 | CONFIG_PWM_ATMEL=m | ||
144 | CONFIG_EXT2_FS=y | 145 | CONFIG_EXT2_FS=y |
145 | CONFIG_EXT3_FS=y | 146 | CONFIG_EXT3_FS=y |
146 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | 147 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set |
diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig index f8ff3a3baad4..0cd23a303da1 100644 --- a/arch/avr32/configs/atstk1003_defconfig +++ b/arch/avr32/configs/atstk1003_defconfig | |||
@@ -53,7 +53,6 @@ CONFIG_BLK_DEV_LOOP=m | |||
53 | CONFIG_BLK_DEV_NBD=m | 53 | CONFIG_BLK_DEV_NBD=m |
54 | CONFIG_BLK_DEV_RAM=m | 54 | CONFIG_BLK_DEV_RAM=m |
55 | CONFIG_MISC_DEVICES=y | 55 | CONFIG_MISC_DEVICES=y |
56 | CONFIG_ATMEL_PWM=m | ||
57 | CONFIG_ATMEL_TCLIB=y | 56 | CONFIG_ATMEL_TCLIB=y |
58 | CONFIG_ATMEL_SSC=m | 57 | CONFIG_ATMEL_SSC=m |
59 | # CONFIG_SCSI_PROC_FS is not set | 58 | # CONFIG_SCSI_PROC_FS is not set |
@@ -112,14 +111,16 @@ CONFIG_MMC_TEST=m | |||
112 | CONFIG_MMC_ATMELMCI=y | 111 | CONFIG_MMC_ATMELMCI=y |
113 | CONFIG_NEW_LEDS=y | 112 | CONFIG_NEW_LEDS=y |
114 | CONFIG_LEDS_CLASS=y | 113 | CONFIG_LEDS_CLASS=y |
115 | CONFIG_LEDS_ATMEL_PWM=m | ||
116 | CONFIG_LEDS_GPIO=m | 114 | CONFIG_LEDS_GPIO=m |
115 | CONFIG_LEDS_PWM=m | ||
117 | CONFIG_LEDS_TRIGGERS=y | 116 | CONFIG_LEDS_TRIGGERS=y |
118 | CONFIG_LEDS_TRIGGER_TIMER=m | 117 | CONFIG_LEDS_TRIGGER_TIMER=m |
119 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m | 118 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m |
120 | CONFIG_RTC_CLASS=y | 119 | CONFIG_RTC_CLASS=y |
121 | CONFIG_RTC_DRV_AT32AP700X=y | 120 | CONFIG_RTC_DRV_AT32AP700X=y |
122 | CONFIG_DMADEVICES=y | 121 | CONFIG_DMADEVICES=y |
122 | CONFIG_PWM=y | ||
123 | CONFIG_PWM_ATMEL=m | ||
123 | CONFIG_EXT2_FS=y | 124 | CONFIG_EXT2_FS=y |
124 | CONFIG_EXT3_FS=y | 125 | CONFIG_EXT3_FS=y |
125 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | 126 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set |
diff --git a/arch/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig index 992228e54e38..ac1041f5f85a 100644 --- a/arch/avr32/configs/atstk1004_defconfig +++ b/arch/avr32/configs/atstk1004_defconfig | |||
@@ -53,7 +53,6 @@ CONFIG_BLK_DEV_LOOP=m | |||
53 | CONFIG_BLK_DEV_NBD=m | 53 | CONFIG_BLK_DEV_NBD=m |
54 | CONFIG_BLK_DEV_RAM=m | 54 | CONFIG_BLK_DEV_RAM=m |
55 | CONFIG_MISC_DEVICES=y | 55 | CONFIG_MISC_DEVICES=y |
56 | CONFIG_ATMEL_PWM=m | ||
57 | CONFIG_ATMEL_TCLIB=y | 56 | CONFIG_ATMEL_TCLIB=y |
58 | CONFIG_ATMEL_SSC=m | 57 | CONFIG_ATMEL_SSC=m |
59 | # CONFIG_SCSI_PROC_FS is not set | 58 | # CONFIG_SCSI_PROC_FS is not set |
@@ -111,14 +110,16 @@ CONFIG_MMC_TEST=m | |||
111 | CONFIG_MMC_ATMELMCI=y | 110 | CONFIG_MMC_ATMELMCI=y |
112 | CONFIG_NEW_LEDS=y | 111 | CONFIG_NEW_LEDS=y |
113 | CONFIG_LEDS_CLASS=y | 112 | CONFIG_LEDS_CLASS=y |
114 | CONFIG_LEDS_ATMEL_PWM=m | ||
115 | CONFIG_LEDS_GPIO=m | 113 | CONFIG_LEDS_GPIO=m |
114 | CONFIG_LEDS_PWM=m | ||
116 | CONFIG_LEDS_TRIGGERS=y | 115 | CONFIG_LEDS_TRIGGERS=y |
117 | CONFIG_LEDS_TRIGGER_TIMER=m | 116 | CONFIG_LEDS_TRIGGER_TIMER=m |
118 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m | 117 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m |
119 | CONFIG_RTC_CLASS=y | 118 | CONFIG_RTC_CLASS=y |
120 | CONFIG_RTC_DRV_AT32AP700X=y | 119 | CONFIG_RTC_DRV_AT32AP700X=y |
121 | CONFIG_DMADEVICES=y | 120 | CONFIG_DMADEVICES=y |
121 | CONFIG_PWM=y | ||
122 | CONFIG_PWM_ATMEL=m | ||
122 | CONFIG_EXT2_FS=y | 123 | CONFIG_EXT2_FS=y |
123 | CONFIG_EXT3_FS=y | 124 | CONFIG_EXT3_FS=y |
124 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | 125 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set |
diff --git a/arch/avr32/configs/atstk1006_defconfig b/arch/avr32/configs/atstk1006_defconfig index b8e698b0d1fa..ea4f670cb995 100644 --- a/arch/avr32/configs/atstk1006_defconfig +++ b/arch/avr32/configs/atstk1006_defconfig | |||
@@ -67,7 +67,6 @@ CONFIG_BLK_DEV_LOOP=m | |||
67 | CONFIG_BLK_DEV_NBD=m | 67 | CONFIG_BLK_DEV_NBD=m |
68 | CONFIG_BLK_DEV_RAM=m | 68 | CONFIG_BLK_DEV_RAM=m |
69 | CONFIG_MISC_DEVICES=y | 69 | CONFIG_MISC_DEVICES=y |
70 | CONFIG_ATMEL_PWM=m | ||
71 | CONFIG_ATMEL_TCLIB=y | 70 | CONFIG_ATMEL_TCLIB=y |
72 | CONFIG_ATMEL_SSC=m | 71 | CONFIG_ATMEL_SSC=m |
73 | # CONFIG_SCSI_PROC_FS is not set | 72 | # CONFIG_SCSI_PROC_FS is not set |
@@ -136,14 +135,16 @@ CONFIG_MMC_TEST=m | |||
136 | CONFIG_MMC_ATMELMCI=y | 135 | CONFIG_MMC_ATMELMCI=y |
137 | CONFIG_NEW_LEDS=y | 136 | CONFIG_NEW_LEDS=y |
138 | CONFIG_LEDS_CLASS=y | 137 | CONFIG_LEDS_CLASS=y |
139 | CONFIG_LEDS_ATMEL_PWM=m | ||
140 | CONFIG_LEDS_GPIO=m | 138 | CONFIG_LEDS_GPIO=m |
139 | CONFIG_LEDS_PWM=m | ||
141 | CONFIG_LEDS_TRIGGERS=y | 140 | CONFIG_LEDS_TRIGGERS=y |
142 | CONFIG_LEDS_TRIGGER_TIMER=m | 141 | CONFIG_LEDS_TRIGGER_TIMER=m |
143 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m | 142 | CONFIG_LEDS_TRIGGER_HEARTBEAT=m |
144 | CONFIG_RTC_CLASS=y | 143 | CONFIG_RTC_CLASS=y |
145 | CONFIG_RTC_DRV_AT32AP700X=y | 144 | CONFIG_RTC_DRV_AT32AP700X=y |
146 | CONFIG_DMADEVICES=y | 145 | CONFIG_DMADEVICES=y |
146 | CONFIG_PWM=y | ||
147 | CONFIG_PWM_ATMEL=m | ||
147 | CONFIG_EXT2_FS=y | 148 | CONFIG_EXT2_FS=y |
148 | CONFIG_EXT3_FS=y | 149 | CONFIG_EXT3_FS=y |
149 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | 150 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set |
diff --git a/arch/avr32/configs/favr-32_defconfig b/arch/avr32/configs/favr-32_defconfig index 07bed3f7eb5e..b3eb67dc05ac 100644 --- a/arch/avr32/configs/favr-32_defconfig +++ b/arch/avr32/configs/favr-32_defconfig | |||
@@ -67,7 +67,6 @@ CONFIG_MTD_PHYSMAP=y | |||
67 | CONFIG_BLK_DEV_LOOP=m | 67 | CONFIG_BLK_DEV_LOOP=m |
68 | CONFIG_BLK_DEV_NBD=m | 68 | CONFIG_BLK_DEV_NBD=m |
69 | CONFIG_BLK_DEV_RAM=m | 69 | CONFIG_BLK_DEV_RAM=m |
70 | CONFIG_ATMEL_PWM=m | ||
71 | CONFIG_ATMEL_TCLIB=y | 70 | CONFIG_ATMEL_TCLIB=y |
72 | CONFIG_ATMEL_SSC=m | 71 | CONFIG_ATMEL_SSC=m |
73 | CONFIG_NETDEVICES=y | 72 | CONFIG_NETDEVICES=y |
@@ -108,7 +107,7 @@ CONFIG_FB=y | |||
108 | CONFIG_FB_ATMEL=y | 107 | CONFIG_FB_ATMEL=y |
109 | CONFIG_BACKLIGHT_LCD_SUPPORT=y | 108 | CONFIG_BACKLIGHT_LCD_SUPPORT=y |
110 | # CONFIG_LCD_CLASS_DEVICE is not set | 109 | # CONFIG_LCD_CLASS_DEVICE is not set |
111 | CONFIG_BACKLIGHT_ATMEL_PWM=m | 110 | CONFIG_BACKLIGHT_PWM=m |
112 | CONFIG_SOUND=m | 111 | CONFIG_SOUND=m |
113 | CONFIG_SOUND_PRIME=m | 112 | CONFIG_SOUND_PRIME=m |
114 | # CONFIG_HID_SUPPORT is not set | 113 | # CONFIG_HID_SUPPORT is not set |
@@ -123,7 +122,6 @@ CONFIG_MMC=y | |||
123 | CONFIG_MMC_ATMELMCI=y | 122 | CONFIG_MMC_ATMELMCI=y |
124 | CONFIG_NEW_LEDS=y | 123 | CONFIG_NEW_LEDS=y |
125 | CONFIG_LEDS_CLASS=y | 124 | CONFIG_LEDS_CLASS=y |
126 | CONFIG_LEDS_ATMEL_PWM=m | ||
127 | CONFIG_LEDS_GPIO=y | 125 | CONFIG_LEDS_GPIO=y |
128 | CONFIG_LEDS_TRIGGERS=y | 126 | CONFIG_LEDS_TRIGGERS=y |
129 | CONFIG_LEDS_TRIGGER_TIMER=y | 127 | CONFIG_LEDS_TRIGGER_TIMER=y |
@@ -132,6 +130,8 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y | |||
132 | CONFIG_RTC_CLASS=y | 130 | CONFIG_RTC_CLASS=y |
133 | CONFIG_RTC_DRV_AT32AP700X=y | 131 | CONFIG_RTC_DRV_AT32AP700X=y |
134 | CONFIG_DMADEVICES=y | 132 | CONFIG_DMADEVICES=y |
133 | CONFIG_PWM=y | ||
134 | CONFIG_PWM_ATMEL=y | ||
135 | CONFIG_EXT2_FS=y | 135 | CONFIG_EXT2_FS=y |
136 | CONFIG_EXT3_FS=y | 136 | CONFIG_EXT3_FS=y |
137 | # CONFIG_EXT3_FS_XATTR is not set | 137 | # CONFIG_EXT3_FS_XATTR is not set |
diff --git a/arch/avr32/configs/merisc_defconfig b/arch/avr32/configs/merisc_defconfig index 91df6b2986be..b9ef4cc85d08 100644 --- a/arch/avr32/configs/merisc_defconfig +++ b/arch/avr32/configs/merisc_defconfig | |||
@@ -55,7 +55,6 @@ CONFIG_MTD_ABSENT=y | |||
55 | CONFIG_MTD_PHYSMAP=y | 55 | CONFIG_MTD_PHYSMAP=y |
56 | CONFIG_MTD_BLOCK2MTD=y | 56 | CONFIG_MTD_BLOCK2MTD=y |
57 | CONFIG_BLK_DEV_LOOP=y | 57 | CONFIG_BLK_DEV_LOOP=y |
58 | CONFIG_ATMEL_PWM=y | ||
59 | CONFIG_ATMEL_SSC=y | 58 | CONFIG_ATMEL_SSC=y |
60 | CONFIG_SCSI=y | 59 | CONFIG_SCSI=y |
61 | CONFIG_BLK_DEV_SD=y | 60 | CONFIG_BLK_DEV_SD=y |
@@ -103,12 +102,14 @@ CONFIG_MMC=y | |||
103 | CONFIG_MMC_ATMELMCI=y | 102 | CONFIG_MMC_ATMELMCI=y |
104 | CONFIG_NEW_LEDS=y | 103 | CONFIG_NEW_LEDS=y |
105 | CONFIG_LEDS_CLASS=y | 104 | CONFIG_LEDS_CLASS=y |
106 | CONFIG_LEDS_ATMEL_PWM=y | 105 | CONFIG_LEDS_PWM=y |
107 | CONFIG_RTC_CLASS=y | 106 | CONFIG_RTC_CLASS=y |
108 | # CONFIG_RTC_HCTOSYS is not set | 107 | # CONFIG_RTC_HCTOSYS is not set |
109 | CONFIG_RTC_DRV_PCF8563=y | 108 | CONFIG_RTC_DRV_PCF8563=y |
110 | CONFIG_DMADEVICES=y | 109 | CONFIG_DMADEVICES=y |
111 | CONFIG_UIO=y | 110 | CONFIG_UIO=y |
111 | CONFIG_PWM=y | ||
112 | CONFIG_PWM_ATMEL=m | ||
112 | CONFIG_EXT2_FS=y | 113 | CONFIG_EXT2_FS=y |
113 | # CONFIG_DNOTIFY is not set | 114 | # CONFIG_DNOTIFY is not set |
114 | CONFIG_FUSE_FS=y | 115 | CONFIG_FUSE_FS=y |
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index a1f4d1e91b52..db85b5ec3351 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c | |||
@@ -1553,7 +1553,7 @@ static struct resource atmel_pwm0_resource[] __initdata = { | |||
1553 | IRQ(24), | 1553 | IRQ(24), |
1554 | }; | 1554 | }; |
1555 | static struct clk atmel_pwm0_mck = { | 1555 | static struct clk atmel_pwm0_mck = { |
1556 | .name = "pwm_clk", | 1556 | .name = "at91sam9rl-pwm", |
1557 | .parent = &pbb_clk, | 1557 | .parent = &pbb_clk, |
1558 | .mode = pbb_clk_mode, | 1558 | .mode = pbb_clk_mode, |
1559 | .get_rate = pbb_clk_get_rate, | 1559 | .get_rate = pbb_clk_get_rate, |
@@ -1568,7 +1568,7 @@ struct platform_device *__init at32_add_device_pwm(u32 mask) | |||
1568 | if (!mask) | 1568 | if (!mask) |
1569 | return NULL; | 1569 | return NULL; |
1570 | 1570 | ||
1571 | pdev = platform_device_alloc("atmel_pwm", 0); | 1571 | pdev = platform_device_alloc("at91sam9rl-pwm", 0); |
1572 | if (!pdev) | 1572 | if (!pdev) |
1573 | return NULL; | 1573 | return NULL; |
1574 | 1574 | ||
@@ -1576,9 +1576,6 @@ struct platform_device *__init at32_add_device_pwm(u32 mask) | |||
1576 | ARRAY_SIZE(atmel_pwm0_resource))) | 1576 | ARRAY_SIZE(atmel_pwm0_resource))) |
1577 | goto out_free_pdev; | 1577 | goto out_free_pdev; |
1578 | 1578 | ||
1579 | if (platform_device_add_data(pdev, &mask, sizeof(mask))) | ||
1580 | goto out_free_pdev; | ||
1581 | |||
1582 | pin_mask = 0; | 1579 | pin_mask = 0; |
1583 | if (mask & (1 << 0)) | 1580 | if (mask & (1 << 0)) |
1584 | pin_mask |= (1 << 28); | 1581 | pin_mask |= (1 << 28); |
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 1f37d9870e7a..603eb1be4f6a 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig | |||
@@ -50,6 +50,14 @@ config ARM_CCI | |||
50 | Driver supporting the CCI cache coherent interconnect for ARM | 50 | Driver supporting the CCI cache coherent interconnect for ARM |
51 | platforms. | 51 | platforms. |
52 | 52 | ||
53 | config ARM_CCN | ||
54 | bool "ARM CCN driver support" | ||
55 | depends on ARM || ARM64 | ||
56 | depends on PERF_EVENTS | ||
57 | help | ||
58 | PMU (perf) driver supporting the ARM CCN (Cache Coherent Network) | ||
59 | interconnect. | ||
60 | |||
53 | config VEXPRESS_CONFIG | 61 | config VEXPRESS_CONFIG |
54 | bool "Versatile Express configuration bus" | 62 | bool "Versatile Express configuration bus" |
55 | default y if ARCH_VEXPRESS | 63 | default y if ARCH_VEXPRESS |
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 6a4ea7e4af1a..2973c18cbcc2 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile | |||
@@ -9,7 +9,9 @@ obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o | |||
9 | 9 | ||
10 | # Interconnect bus driver for OMAP SoCs. | 10 | # Interconnect bus driver for OMAP SoCs. |
11 | obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o | 11 | obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o |
12 | # CCI cache coherent interconnect for ARM platforms | 12 | |
13 | # Interconnect bus drivers for ARM platforms | ||
13 | obj-$(CONFIG_ARM_CCI) += arm-cci.o | 14 | obj-$(CONFIG_ARM_CCI) += arm-cci.o |
15 | obj-$(CONFIG_ARM_CCN) += arm-ccn.o | ||
14 | 16 | ||
15 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o | 17 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o |
diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c new file mode 100644 index 000000000000..3266f8ff9311 --- /dev/null +++ b/drivers/bus/arm-ccn.c | |||
@@ -0,0 +1,1391 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * Copyright (C) 2014 ARM Limited | ||
12 | */ | ||
13 | |||
14 | #include <linux/ctype.h> | ||
15 | #include <linux/hrtimer.h> | ||
16 | #include <linux/idr.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/perf_event.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #define CCN_NUM_XP_PORTS 2 | ||
25 | #define CCN_NUM_VCS 4 | ||
26 | #define CCN_NUM_REGIONS 256 | ||
27 | #define CCN_REGION_SIZE 0x10000 | ||
28 | |||
29 | #define CCN_ALL_OLY_ID 0xff00 | ||
30 | #define CCN_ALL_OLY_ID__OLY_ID__SHIFT 0 | ||
31 | #define CCN_ALL_OLY_ID__OLY_ID__MASK 0x1f | ||
32 | #define CCN_ALL_OLY_ID__NODE_ID__SHIFT 8 | ||
33 | #define CCN_ALL_OLY_ID__NODE_ID__MASK 0x3f | ||
34 | |||
35 | #define CCN_MN_ERRINT_STATUS 0x0008 | ||
36 | #define CCN_MN_ERRINT_STATUS__INTREQ__DESSERT 0x11 | ||
37 | #define CCN_MN_ERRINT_STATUS__ALL_ERRORS__ENABLE 0x02 | ||
38 | #define CCN_MN_ERRINT_STATUS__ALL_ERRORS__DISABLED 0x20 | ||
39 | #define CCN_MN_ERRINT_STATUS__ALL_ERRORS__DISABLE 0x22 | ||
40 | #define CCN_MN_ERRINT_STATUS__CORRECTED_ERRORS_ENABLE 0x04 | ||
41 | #define CCN_MN_ERRINT_STATUS__CORRECTED_ERRORS_DISABLED 0x40 | ||
42 | #define CCN_MN_ERRINT_STATUS__CORRECTED_ERRORS_DISABLE 0x44 | ||
43 | #define CCN_MN_ERRINT_STATUS__PMU_EVENTS__ENABLE 0x08 | ||
44 | #define CCN_MN_ERRINT_STATUS__PMU_EVENTS__DISABLED 0x80 | ||
45 | #define CCN_MN_ERRINT_STATUS__PMU_EVENTS__DISABLE 0x88 | ||
46 | #define CCN_MN_OLY_COMP_LIST_63_0 0x01e0 | ||
47 | #define CCN_MN_ERR_SIG_VAL_63_0 0x0300 | ||
48 | #define CCN_MN_ERR_SIG_VAL_63_0__DT (1 << 1) | ||
49 | |||
50 | #define CCN_DT_ACTIVE_DSM 0x0000 | ||
51 | #define CCN_DT_ACTIVE_DSM__DSM_ID__SHIFT(n) ((n) * 8) | ||
52 | #define CCN_DT_ACTIVE_DSM__DSM_ID__MASK 0xff | ||
53 | #define CCN_DT_CTL 0x0028 | ||
54 | #define CCN_DT_CTL__DT_EN (1 << 0) | ||
55 | #define CCN_DT_PMEVCNT(n) (0x0100 + (n) * 0x8) | ||
56 | #define CCN_DT_PMCCNTR 0x0140 | ||
57 | #define CCN_DT_PMCCNTRSR 0x0190 | ||
58 | #define CCN_DT_PMOVSR 0x0198 | ||
59 | #define CCN_DT_PMOVSR_CLR 0x01a0 | ||
60 | #define CCN_DT_PMCR 0x01a8 | ||
61 | #define CCN_DT_PMCR__OVFL_INTR_EN (1 << 6) | ||
62 | #define CCN_DT_PMCR__PMU_EN (1 << 0) | ||
63 | #define CCN_DT_PMSR 0x01b0 | ||
64 | #define CCN_DT_PMSR_REQ 0x01b8 | ||
65 | #define CCN_DT_PMSR_CLR 0x01c0 | ||
66 | |||
67 | #define CCN_HNF_PMU_EVENT_SEL 0x0600 | ||
68 | #define CCN_HNF_PMU_EVENT_SEL__ID__SHIFT(n) ((n) * 4) | ||
69 | #define CCN_HNF_PMU_EVENT_SEL__ID__MASK 0xf | ||
70 | |||
71 | #define CCN_XP_DT_CONFIG 0x0300 | ||
72 | #define CCN_XP_DT_CONFIG__DT_CFG__SHIFT(n) ((n) * 4) | ||
73 | #define CCN_XP_DT_CONFIG__DT_CFG__MASK 0xf | ||
74 | #define CCN_XP_DT_CONFIG__DT_CFG__PASS_THROUGH 0x0 | ||
75 | #define CCN_XP_DT_CONFIG__DT_CFG__WATCHPOINT_0_OR_1 0x1 | ||
76 | #define CCN_XP_DT_CONFIG__DT_CFG__WATCHPOINT(n) (0x2 + (n)) | ||
77 | #define CCN_XP_DT_CONFIG__DT_CFG__XP_PMU_EVENT(n) (0x4 + (n)) | ||
78 | #define CCN_XP_DT_CONFIG__DT_CFG__DEVICE_PMU_EVENT(d, n) (0x8 + (d) * 4 + (n)) | ||
79 | #define CCN_XP_DT_INTERFACE_SEL 0x0308 | ||
80 | #define CCN_XP_DT_INTERFACE_SEL__DT_IO_SEL__SHIFT(n) (0 + (n) * 8) | ||
81 | #define CCN_XP_DT_INTERFACE_SEL__DT_IO_SEL__MASK 0x1 | ||
82 | #define CCN_XP_DT_INTERFACE_SEL__DT_DEV_SEL__SHIFT(n) (1 + (n) * 8) | ||
83 | #define CCN_XP_DT_INTERFACE_SEL__DT_DEV_SEL__MASK 0x1 | ||
84 | #define CCN_XP_DT_INTERFACE_SEL__DT_VC_SEL__SHIFT(n) (2 + (n) * 8) | ||
85 | #define CCN_XP_DT_INTERFACE_SEL__DT_VC_SEL__MASK 0x3 | ||
86 | #define CCN_XP_DT_CMP_VAL_L(n) (0x0310 + (n) * 0x40) | ||
87 | #define CCN_XP_DT_CMP_VAL_H(n) (0x0318 + (n) * 0x40) | ||
88 | #define CCN_XP_DT_CMP_MASK_L(n) (0x0320 + (n) * 0x40) | ||
89 | #define CCN_XP_DT_CMP_MASK_H(n) (0x0328 + (n) * 0x40) | ||
90 | #define CCN_XP_DT_CONTROL 0x0370 | ||
91 | #define CCN_XP_DT_CONTROL__DT_ENABLE (1 << 0) | ||
92 | #define CCN_XP_DT_CONTROL__WP_ARM_SEL__SHIFT(n) (12 + (n) * 4) | ||
93 | #define CCN_XP_DT_CONTROL__WP_ARM_SEL__MASK 0xf | ||
94 | #define CCN_XP_DT_CONTROL__WP_ARM_SEL__ALWAYS 0xf | ||
95 | #define CCN_XP_PMU_EVENT_SEL 0x0600 | ||
96 | #define CCN_XP_PMU_EVENT_SEL__ID__SHIFT(n) ((n) * 7) | ||
97 | #define CCN_XP_PMU_EVENT_SEL__ID__MASK 0x3f | ||
98 | |||
99 | #define CCN_SBAS_PMU_EVENT_SEL 0x0600 | ||
100 | #define CCN_SBAS_PMU_EVENT_SEL__ID__SHIFT(n) ((n) * 4) | ||
101 | #define CCN_SBAS_PMU_EVENT_SEL__ID__MASK 0xf | ||
102 | |||
103 | #define CCN_RNI_PMU_EVENT_SEL 0x0600 | ||
104 | #define CCN_RNI_PMU_EVENT_SEL__ID__SHIFT(n) ((n) * 4) | ||
105 | #define CCN_RNI_PMU_EVENT_SEL__ID__MASK 0xf | ||
106 | |||
107 | #define CCN_TYPE_MN 0x01 | ||
108 | #define CCN_TYPE_DT 0x02 | ||
109 | #define CCN_TYPE_HNF 0x04 | ||
110 | #define CCN_TYPE_HNI 0x05 | ||
111 | #define CCN_TYPE_XP 0x08 | ||
112 | #define CCN_TYPE_SBSX 0x0c | ||
113 | #define CCN_TYPE_SBAS 0x10 | ||
114 | #define CCN_TYPE_RNI_1P 0x14 | ||
115 | #define CCN_TYPE_RNI_2P 0x15 | ||
116 | #define CCN_TYPE_RNI_3P 0x16 | ||
117 | #define CCN_TYPE_RND_1P 0x18 /* RN-D = RN-I + DVM */ | ||
118 | #define CCN_TYPE_RND_2P 0x19 | ||
119 | #define CCN_TYPE_RND_3P 0x1a | ||
120 | #define CCN_TYPE_CYCLES 0xff /* Pseudotype */ | ||
121 | |||
122 | #define CCN_EVENT_WATCHPOINT 0xfe /* Pseudoevent */ | ||
123 | |||
124 | #define CCN_NUM_PMU_EVENTS 4 | ||
125 | #define CCN_NUM_XP_WATCHPOINTS 2 /* See DT.dbg_id.num_watchpoints */ | ||
126 | #define CCN_NUM_PMU_EVENT_COUNTERS 8 /* See DT.dbg_id.num_pmucntr */ | ||
127 | #define CCN_IDX_PMU_CYCLE_COUNTER CCN_NUM_PMU_EVENT_COUNTERS | ||
128 | |||
129 | #define CCN_NUM_PREDEFINED_MASKS 4 | ||
130 | #define CCN_IDX_MASK_ANY (CCN_NUM_PMU_EVENT_COUNTERS + 0) | ||
131 | #define CCN_IDX_MASK_EXACT (CCN_NUM_PMU_EVENT_COUNTERS + 1) | ||
132 | #define CCN_IDX_MASK_ORDER (CCN_NUM_PMU_EVENT_COUNTERS + 2) | ||
133 | #define CCN_IDX_MASK_OPCODE (CCN_NUM_PMU_EVENT_COUNTERS + 3) | ||
134 | |||
135 | struct arm_ccn_component { | ||
136 | void __iomem *base; | ||
137 | u32 type; | ||
138 | |||
139 | DECLARE_BITMAP(pmu_events_mask, CCN_NUM_PMU_EVENTS); | ||
140 | union { | ||
141 | struct { | ||
142 | DECLARE_BITMAP(dt_cmp_mask, CCN_NUM_XP_WATCHPOINTS); | ||
143 | } xp; | ||
144 | }; | ||
145 | }; | ||
146 | |||
147 | #define pmu_to_arm_ccn(_pmu) container_of(container_of(_pmu, \ | ||
148 | struct arm_ccn_dt, pmu), struct arm_ccn, dt) | ||
149 | |||
150 | struct arm_ccn_dt { | ||
151 | int id; | ||
152 | void __iomem *base; | ||
153 | |||
154 | spinlock_t config_lock; | ||
155 | |||
156 | DECLARE_BITMAP(pmu_counters_mask, CCN_NUM_PMU_EVENT_COUNTERS + 1); | ||
157 | struct { | ||
158 | struct arm_ccn_component *source; | ||
159 | struct perf_event *event; | ||
160 | } pmu_counters[CCN_NUM_PMU_EVENT_COUNTERS + 1]; | ||
161 | |||
162 | struct { | ||
163 | u64 l, h; | ||
164 | } cmp_mask[CCN_NUM_PMU_EVENT_COUNTERS + CCN_NUM_PREDEFINED_MASKS]; | ||
165 | |||
166 | struct hrtimer hrtimer; | ||
167 | |||
168 | struct pmu pmu; | ||
169 | }; | ||
170 | |||
171 | struct arm_ccn { | ||
172 | struct device *dev; | ||
173 | void __iomem *base; | ||
174 | unsigned irq_used:1; | ||
175 | unsigned sbas_present:1; | ||
176 | unsigned sbsx_present:1; | ||
177 | |||
178 | int num_nodes; | ||
179 | struct arm_ccn_component *node; | ||
180 | |||
181 | int num_xps; | ||
182 | struct arm_ccn_component *xp; | ||
183 | |||
184 | struct arm_ccn_dt dt; | ||
185 | }; | ||
186 | |||
187 | |||
188 | static int arm_ccn_node_to_xp(int node) | ||
189 | { | ||
190 | return node / CCN_NUM_XP_PORTS; | ||
191 | } | ||
192 | |||
193 | static int arm_ccn_node_to_xp_port(int node) | ||
194 | { | ||
195 | return node % CCN_NUM_XP_PORTS; | ||
196 | } | ||
197 | |||
198 | |||
199 | /* | ||
200 | * Bit shifts and masks in these defines must be kept in sync with | ||
201 | * arm_ccn_pmu_config_set() and CCN_FORMAT_ATTRs below! | ||
202 | */ | ||
203 | #define CCN_CONFIG_NODE(_config) (((_config) >> 0) & 0xff) | ||
204 | #define CCN_CONFIG_XP(_config) (((_config) >> 0) & 0xff) | ||
205 | #define CCN_CONFIG_TYPE(_config) (((_config) >> 8) & 0xff) | ||
206 | #define CCN_CONFIG_EVENT(_config) (((_config) >> 16) & 0xff) | ||
207 | #define CCN_CONFIG_PORT(_config) (((_config) >> 24) & 0x3) | ||
208 | #define CCN_CONFIG_VC(_config) (((_config) >> 26) & 0x7) | ||
209 | #define CCN_CONFIG_DIR(_config) (((_config) >> 29) & 0x1) | ||
210 | #define CCN_CONFIG_MASK(_config) (((_config) >> 30) & 0xf) | ||
211 | |||
212 | static void arm_ccn_pmu_config_set(u64 *config, u32 node_xp, u32 type, u32 port) | ||
213 | { | ||
214 | *config &= ~((0xff << 0) | (0xff << 8) | (0xff << 24)); | ||
215 | *config |= (node_xp << 0) | (type << 8) | (port << 24); | ||
216 | } | ||
217 | |||
218 | static ssize_t arm_ccn_pmu_format_show(struct device *dev, | ||
219 | struct device_attribute *attr, char *buf) | ||
220 | { | ||
221 | struct dev_ext_attribute *ea = container_of(attr, | ||
222 | struct dev_ext_attribute, attr); | ||
223 | |||
224 | return snprintf(buf, PAGE_SIZE, "%s\n", (char *)ea->var); | ||
225 | } | ||
226 | |||
227 | #define CCN_FORMAT_ATTR(_name, _config) \ | ||
228 | struct dev_ext_attribute arm_ccn_pmu_format_attr_##_name = \ | ||
229 | { __ATTR(_name, S_IRUGO, arm_ccn_pmu_format_show, \ | ||
230 | NULL), _config } | ||
231 | |||
232 | static CCN_FORMAT_ATTR(node, "config:0-7"); | ||
233 | static CCN_FORMAT_ATTR(xp, "config:0-7"); | ||
234 | static CCN_FORMAT_ATTR(type, "config:8-15"); | ||
235 | static CCN_FORMAT_ATTR(event, "config:16-23"); | ||
236 | static CCN_FORMAT_ATTR(port, "config:24-25"); | ||
237 | static CCN_FORMAT_ATTR(vc, "config:26-28"); | ||
238 | static CCN_FORMAT_ATTR(dir, "config:29-29"); | ||
239 | static CCN_FORMAT_ATTR(mask, "config:30-33"); | ||
240 | static CCN_FORMAT_ATTR(cmp_l, "config1:0-62"); | ||
241 | static CCN_FORMAT_ATTR(cmp_h, "config2:0-59"); | ||
242 | |||
243 | static struct attribute *arm_ccn_pmu_format_attrs[] = { | ||
244 | &arm_ccn_pmu_format_attr_node.attr.attr, | ||
245 | &arm_ccn_pmu_format_attr_xp.attr.attr, | ||
246 | &arm_ccn_pmu_format_attr_type.attr.attr, | ||
247 | &arm_ccn_pmu_format_attr_event.attr.attr, | ||
248 | &arm_ccn_pmu_format_attr_port.attr.attr, | ||
249 | &arm_ccn_pmu_format_attr_vc.attr.attr, | ||
250 | &arm_ccn_pmu_format_attr_dir.attr.attr, | ||
251 | &arm_ccn_pmu_format_attr_mask.attr.attr, | ||
252 | &arm_ccn_pmu_format_attr_cmp_l.attr.attr, | ||
253 | &arm_ccn_pmu_format_attr_cmp_h.attr.attr, | ||
254 | NULL | ||
255 | }; | ||
256 | |||
257 | static struct attribute_group arm_ccn_pmu_format_attr_group = { | ||
258 | .name = "format", | ||
259 | .attrs = arm_ccn_pmu_format_attrs, | ||
260 | }; | ||
261 | |||
262 | |||
263 | struct arm_ccn_pmu_event { | ||
264 | struct device_attribute attr; | ||
265 | u32 type; | ||
266 | u32 event; | ||
267 | int num_ports; | ||
268 | int num_vcs; | ||
269 | const char *def; | ||
270 | int mask; | ||
271 | }; | ||
272 | |||
273 | #define CCN_EVENT_ATTR(_name) \ | ||
274 | __ATTR(_name, S_IRUGO, arm_ccn_pmu_event_show, NULL) | ||
275 | |||
276 | /* | ||
277 | * Events defined in TRM for MN, HN-I and SBSX are actually watchpoints set on | ||
278 | * their ports in XP they are connected to. For the sake of usability they are | ||
279 | * explicitly defined here (and translated into a relevant watchpoint in | ||
280 | * arm_ccn_pmu_event_init()) so the user can easily request them without deep | ||
281 | * knowledge of the flit format. | ||
282 | */ | ||
283 | |||
284 | #define CCN_EVENT_MN(_name, _def, _mask) { .attr = CCN_EVENT_ATTR(mn_##_name), \ | ||
285 | .type = CCN_TYPE_MN, .event = CCN_EVENT_WATCHPOINT, \ | ||
286 | .num_ports = CCN_NUM_XP_PORTS, .num_vcs = CCN_NUM_VCS, \ | ||
287 | .def = _def, .mask = _mask, } | ||
288 | |||
289 | #define CCN_EVENT_HNI(_name, _def, _mask) { \ | ||
290 | .attr = CCN_EVENT_ATTR(hni_##_name), .type = CCN_TYPE_HNI, \ | ||
291 | .event = CCN_EVENT_WATCHPOINT, .num_ports = CCN_NUM_XP_PORTS, \ | ||
292 | .num_vcs = CCN_NUM_VCS, .def = _def, .mask = _mask, } | ||
293 | |||
294 | #define CCN_EVENT_SBSX(_name, _def, _mask) { \ | ||
295 | .attr = CCN_EVENT_ATTR(sbsx_##_name), .type = CCN_TYPE_SBSX, \ | ||
296 | .event = CCN_EVENT_WATCHPOINT, .num_ports = CCN_NUM_XP_PORTS, \ | ||
297 | .num_vcs = CCN_NUM_VCS, .def = _def, .mask = _mask, } | ||
298 | |||
299 | #define CCN_EVENT_HNF(_name, _event) { .attr = CCN_EVENT_ATTR(hnf_##_name), \ | ||
300 | .type = CCN_TYPE_HNF, .event = _event, } | ||
301 | |||
302 | #define CCN_EVENT_XP(_name, _event) { .attr = CCN_EVENT_ATTR(xp_##_name), \ | ||
303 | .type = CCN_TYPE_XP, .event = _event, \ | ||
304 | .num_ports = CCN_NUM_XP_PORTS, .num_vcs = CCN_NUM_VCS, } | ||
305 | |||
306 | /* | ||
307 | * RN-I & RN-D (RN-D = RN-I + DVM) nodes have different type ID depending | ||
308 | * on configuration. One of them is picked to represent the whole group, | ||
309 | * as they all share the same event types. | ||
310 | */ | ||
311 | #define CCN_EVENT_RNI(_name, _event) { .attr = CCN_EVENT_ATTR(rni_##_name), \ | ||
312 | .type = CCN_TYPE_RNI_3P, .event = _event, } | ||
313 | |||
314 | #define CCN_EVENT_SBAS(_name, _event) { .attr = CCN_EVENT_ATTR(sbas_##_name), \ | ||
315 | .type = CCN_TYPE_SBAS, .event = _event, } | ||
316 | |||
317 | #define CCN_EVENT_CYCLES(_name) { .attr = CCN_EVENT_ATTR(_name), \ | ||
318 | .type = CCN_TYPE_CYCLES } | ||
319 | |||
320 | |||
321 | static ssize_t arm_ccn_pmu_event_show(struct device *dev, | ||
322 | struct device_attribute *attr, char *buf) | ||
323 | { | ||
324 | struct arm_ccn_pmu_event *event = container_of(attr, | ||
325 | struct arm_ccn_pmu_event, attr); | ||
326 | ssize_t res; | ||
327 | |||
328 | res = snprintf(buf, PAGE_SIZE, "type=0x%x", event->type); | ||
329 | if (event->event) | ||
330 | res += snprintf(buf + res, PAGE_SIZE - res, ",event=0x%x", | ||
331 | event->event); | ||
332 | if (event->def) | ||
333 | res += snprintf(buf + res, PAGE_SIZE - res, ",%s", | ||
334 | event->def); | ||
335 | if (event->mask) | ||
336 | res += snprintf(buf + res, PAGE_SIZE - res, ",mask=0x%x", | ||
337 | event->mask); | ||
338 | res += snprintf(buf + res, PAGE_SIZE - res, "\n"); | ||
339 | |||
340 | return res; | ||
341 | } | ||
342 | |||
343 | static umode_t arm_ccn_pmu_events_is_visible(struct kobject *kobj, | ||
344 | struct attribute *attr, int index) | ||
345 | { | ||
346 | struct device *dev = kobj_to_dev(kobj); | ||
347 | struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev)); | ||
348 | struct device_attribute *dev_attr = container_of(attr, | ||
349 | struct device_attribute, attr); | ||
350 | struct arm_ccn_pmu_event *event = container_of(dev_attr, | ||
351 | struct arm_ccn_pmu_event, attr); | ||
352 | |||
353 | if (event->type == CCN_TYPE_SBAS && !ccn->sbas_present) | ||
354 | return 0; | ||
355 | if (event->type == CCN_TYPE_SBSX && !ccn->sbsx_present) | ||
356 | return 0; | ||
357 | |||
358 | return attr->mode; | ||
359 | } | ||
360 | |||
361 | static struct arm_ccn_pmu_event arm_ccn_pmu_events[] = { | ||
362 | CCN_EVENT_MN(eobarrier, "dir=0,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE), | ||
363 | CCN_EVENT_MN(ecbarrier, "dir=0,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE), | ||
364 | CCN_EVENT_MN(dvmop, "dir=0,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE), | ||
365 | CCN_EVENT_HNI(txdatflits, "dir=1,vc=3", CCN_IDX_MASK_ANY), | ||
366 | CCN_EVENT_HNI(rxdatflits, "dir=0,vc=3", CCN_IDX_MASK_ANY), | ||
367 | CCN_EVENT_HNI(txreqflits, "dir=1,vc=0", CCN_IDX_MASK_ANY), | ||
368 | CCN_EVENT_HNI(rxreqflits, "dir=0,vc=0", CCN_IDX_MASK_ANY), | ||
369 | CCN_EVENT_HNI(rxreqflits_order, "dir=0,vc=0,cmp_h=0x8000", | ||
370 | CCN_IDX_MASK_ORDER), | ||
371 | CCN_EVENT_SBSX(txdatflits, "dir=1,vc=3", CCN_IDX_MASK_ANY), | ||
372 | CCN_EVENT_SBSX(rxdatflits, "dir=0,vc=3", CCN_IDX_MASK_ANY), | ||
373 | CCN_EVENT_SBSX(txreqflits, "dir=1,vc=0", CCN_IDX_MASK_ANY), | ||
374 | CCN_EVENT_SBSX(rxreqflits, "dir=0,vc=0", CCN_IDX_MASK_ANY), | ||
375 | CCN_EVENT_SBSX(rxreqflits_order, "dir=0,vc=0,cmp_h=0x8000", | ||
376 | CCN_IDX_MASK_ORDER), | ||
377 | CCN_EVENT_HNF(cache_miss, 0x1), | ||
378 | CCN_EVENT_HNF(l3_sf_cache_access, 0x02), | ||
379 | CCN_EVENT_HNF(cache_fill, 0x3), | ||
380 | CCN_EVENT_HNF(pocq_retry, 0x4), | ||
381 | CCN_EVENT_HNF(pocq_reqs_recvd, 0x5), | ||
382 | CCN_EVENT_HNF(sf_hit, 0x6), | ||
383 | CCN_EVENT_HNF(sf_evictions, 0x7), | ||
384 | CCN_EVENT_HNF(snoops_sent, 0x8), | ||
385 | CCN_EVENT_HNF(snoops_broadcast, 0x9), | ||
386 | CCN_EVENT_HNF(l3_eviction, 0xa), | ||
387 | CCN_EVENT_HNF(l3_fill_invalid_way, 0xb), | ||
388 | CCN_EVENT_HNF(mc_retries, 0xc), | ||
389 | CCN_EVENT_HNF(mc_reqs, 0xd), | ||
390 | CCN_EVENT_HNF(qos_hh_retry, 0xe), | ||
391 | CCN_EVENT_RNI(rdata_beats_p0, 0x1), | ||
392 | CCN_EVENT_RNI(rdata_beats_p1, 0x2), | ||
393 | CCN_EVENT_RNI(rdata_beats_p2, 0x3), | ||
394 | CCN_EVENT_RNI(rxdat_flits, 0x4), | ||
395 | CCN_EVENT_RNI(txdat_flits, 0x5), | ||
396 | CCN_EVENT_RNI(txreq_flits, 0x6), | ||
397 | CCN_EVENT_RNI(txreq_flits_retried, 0x7), | ||
398 | CCN_EVENT_RNI(rrt_full, 0x8), | ||
399 | CCN_EVENT_RNI(wrt_full, 0x9), | ||
400 | CCN_EVENT_RNI(txreq_flits_replayed, 0xa), | ||
401 | CCN_EVENT_XP(upload_starvation, 0x1), | ||
402 | CCN_EVENT_XP(download_starvation, 0x2), | ||
403 | CCN_EVENT_XP(respin, 0x3), | ||
404 | CCN_EVENT_XP(valid_flit, 0x4), | ||
405 | CCN_EVENT_XP(watchpoint, CCN_EVENT_WATCHPOINT), | ||
406 | CCN_EVENT_SBAS(rdata_beats_p0, 0x1), | ||
407 | CCN_EVENT_SBAS(rxdat_flits, 0x4), | ||
408 | CCN_EVENT_SBAS(txdat_flits, 0x5), | ||
409 | CCN_EVENT_SBAS(txreq_flits, 0x6), | ||
410 | CCN_EVENT_SBAS(txreq_flits_retried, 0x7), | ||
411 | CCN_EVENT_SBAS(rrt_full, 0x8), | ||
412 | CCN_EVENT_SBAS(wrt_full, 0x9), | ||
413 | CCN_EVENT_SBAS(txreq_flits_replayed, 0xa), | ||
414 | CCN_EVENT_CYCLES(cycles), | ||
415 | }; | ||
416 | |||
417 | /* Populated in arm_ccn_init() */ | ||
418 | static struct attribute | ||
419 | *arm_ccn_pmu_events_attrs[ARRAY_SIZE(arm_ccn_pmu_events) + 1]; | ||
420 | |||
421 | static struct attribute_group arm_ccn_pmu_events_attr_group = { | ||
422 | .name = "events", | ||
423 | .is_visible = arm_ccn_pmu_events_is_visible, | ||
424 | .attrs = arm_ccn_pmu_events_attrs, | ||
425 | }; | ||
426 | |||
427 | |||
428 | static u64 *arm_ccn_pmu_get_cmp_mask(struct arm_ccn *ccn, const char *name) | ||
429 | { | ||
430 | unsigned long i; | ||
431 | |||
432 | if (WARN_ON(!name || !name[0] || !isxdigit(name[0]) || !name[1])) | ||
433 | return NULL; | ||
434 | i = isdigit(name[0]) ? name[0] - '0' : 0xa + tolower(name[0]) - 'a'; | ||
435 | |||
436 | switch (name[1]) { | ||
437 | case 'l': | ||
438 | return &ccn->dt.cmp_mask[i].l; | ||
439 | case 'h': | ||
440 | return &ccn->dt.cmp_mask[i].h; | ||
441 | default: | ||
442 | return NULL; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | static ssize_t arm_ccn_pmu_cmp_mask_show(struct device *dev, | ||
447 | struct device_attribute *attr, char *buf) | ||
448 | { | ||
449 | struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev)); | ||
450 | u64 *mask = arm_ccn_pmu_get_cmp_mask(ccn, attr->attr.name); | ||
451 | |||
452 | return mask ? snprintf(buf, PAGE_SIZE, "0x%016llx\n", *mask) : -EINVAL; | ||
453 | } | ||
454 | |||
455 | static ssize_t arm_ccn_pmu_cmp_mask_store(struct device *dev, | ||
456 | struct device_attribute *attr, const char *buf, size_t count) | ||
457 | { | ||
458 | struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev)); | ||
459 | u64 *mask = arm_ccn_pmu_get_cmp_mask(ccn, attr->attr.name); | ||
460 | int err = -EINVAL; | ||
461 | |||
462 | if (mask) | ||
463 | err = kstrtoull(buf, 0, mask); | ||
464 | |||
465 | return err ? err : count; | ||
466 | } | ||
467 | |||
468 | #define CCN_CMP_MASK_ATTR(_name) \ | ||
469 | struct device_attribute arm_ccn_pmu_cmp_mask_attr_##_name = \ | ||
470 | __ATTR(_name, S_IRUGO | S_IWUSR, \ | ||
471 | arm_ccn_pmu_cmp_mask_show, arm_ccn_pmu_cmp_mask_store) | ||
472 | |||
473 | #define CCN_CMP_MASK_ATTR_RO(_name) \ | ||
474 | struct device_attribute arm_ccn_pmu_cmp_mask_attr_##_name = \ | ||
475 | __ATTR(_name, S_IRUGO, arm_ccn_pmu_cmp_mask_show, NULL) | ||
476 | |||
477 | static CCN_CMP_MASK_ATTR(0l); | ||
478 | static CCN_CMP_MASK_ATTR(0h); | ||
479 | static CCN_CMP_MASK_ATTR(1l); | ||
480 | static CCN_CMP_MASK_ATTR(1h); | ||
481 | static CCN_CMP_MASK_ATTR(2l); | ||
482 | static CCN_CMP_MASK_ATTR(2h); | ||
483 | static CCN_CMP_MASK_ATTR(3l); | ||
484 | static CCN_CMP_MASK_ATTR(3h); | ||
485 | static CCN_CMP_MASK_ATTR(4l); | ||
486 | static CCN_CMP_MASK_ATTR(4h); | ||
487 | static CCN_CMP_MASK_ATTR(5l); | ||
488 | static CCN_CMP_MASK_ATTR(5h); | ||
489 | static CCN_CMP_MASK_ATTR(6l); | ||
490 | static CCN_CMP_MASK_ATTR(6h); | ||
491 | static CCN_CMP_MASK_ATTR(7l); | ||
492 | static CCN_CMP_MASK_ATTR(7h); | ||
493 | static CCN_CMP_MASK_ATTR_RO(8l); | ||
494 | static CCN_CMP_MASK_ATTR_RO(8h); | ||
495 | static CCN_CMP_MASK_ATTR_RO(9l); | ||
496 | static CCN_CMP_MASK_ATTR_RO(9h); | ||
497 | static CCN_CMP_MASK_ATTR_RO(al); | ||
498 | static CCN_CMP_MASK_ATTR_RO(ah); | ||
499 | static CCN_CMP_MASK_ATTR_RO(bl); | ||
500 | static CCN_CMP_MASK_ATTR_RO(bh); | ||
501 | |||
502 | static struct attribute *arm_ccn_pmu_cmp_mask_attrs[] = { | ||
503 | &arm_ccn_pmu_cmp_mask_attr_0l.attr, &arm_ccn_pmu_cmp_mask_attr_0h.attr, | ||
504 | &arm_ccn_pmu_cmp_mask_attr_1l.attr, &arm_ccn_pmu_cmp_mask_attr_1h.attr, | ||
505 | &arm_ccn_pmu_cmp_mask_attr_2l.attr, &arm_ccn_pmu_cmp_mask_attr_2h.attr, | ||
506 | &arm_ccn_pmu_cmp_mask_attr_3l.attr, &arm_ccn_pmu_cmp_mask_attr_3h.attr, | ||
507 | &arm_ccn_pmu_cmp_mask_attr_4l.attr, &arm_ccn_pmu_cmp_mask_attr_4h.attr, | ||
508 | &arm_ccn_pmu_cmp_mask_attr_5l.attr, &arm_ccn_pmu_cmp_mask_attr_5h.attr, | ||
509 | &arm_ccn_pmu_cmp_mask_attr_6l.attr, &arm_ccn_pmu_cmp_mask_attr_6h.attr, | ||
510 | &arm_ccn_pmu_cmp_mask_attr_7l.attr, &arm_ccn_pmu_cmp_mask_attr_7h.attr, | ||
511 | &arm_ccn_pmu_cmp_mask_attr_8l.attr, &arm_ccn_pmu_cmp_mask_attr_8h.attr, | ||
512 | &arm_ccn_pmu_cmp_mask_attr_9l.attr, &arm_ccn_pmu_cmp_mask_attr_9h.attr, | ||
513 | &arm_ccn_pmu_cmp_mask_attr_al.attr, &arm_ccn_pmu_cmp_mask_attr_ah.attr, | ||
514 | &arm_ccn_pmu_cmp_mask_attr_bl.attr, &arm_ccn_pmu_cmp_mask_attr_bh.attr, | ||
515 | NULL | ||
516 | }; | ||
517 | |||
518 | static struct attribute_group arm_ccn_pmu_cmp_mask_attr_group = { | ||
519 | .name = "cmp_mask", | ||
520 | .attrs = arm_ccn_pmu_cmp_mask_attrs, | ||
521 | }; | ||
522 | |||
523 | |||
524 | /* | ||
525 | * Default poll period is 10ms, which is way over the top anyway, | ||
526 | * as in the worst case scenario (an event every cycle), with 1GHz | ||
527 | * clocked bus, the smallest, 32 bit counter will overflow in | ||
528 | * more than 4s. | ||
529 | */ | ||
530 | static unsigned int arm_ccn_pmu_poll_period_us = 10000; | ||
531 | module_param_named(pmu_poll_period_us, arm_ccn_pmu_poll_period_us, uint, | ||
532 | S_IRUGO | S_IWUSR); | ||
533 | |||
534 | static ktime_t arm_ccn_pmu_timer_period(void) | ||
535 | { | ||
536 | return ns_to_ktime((u64)arm_ccn_pmu_poll_period_us * 1000); | ||
537 | } | ||
538 | |||
539 | |||
540 | static const struct attribute_group *arm_ccn_pmu_attr_groups[] = { | ||
541 | &arm_ccn_pmu_events_attr_group, | ||
542 | &arm_ccn_pmu_format_attr_group, | ||
543 | &arm_ccn_pmu_cmp_mask_attr_group, | ||
544 | NULL | ||
545 | }; | ||
546 | |||
547 | |||
548 | static int arm_ccn_pmu_alloc_bit(unsigned long *bitmap, unsigned long size) | ||
549 | { | ||
550 | int bit; | ||
551 | |||
552 | do { | ||
553 | bit = find_first_zero_bit(bitmap, size); | ||
554 | if (bit >= size) | ||
555 | return -EAGAIN; | ||
556 | } while (test_and_set_bit(bit, bitmap)); | ||
557 | |||
558 | return bit; | ||
559 | } | ||
560 | |||
561 | /* All RN-I and RN-D nodes have identical PMUs */ | ||
562 | static int arm_ccn_pmu_type_eq(u32 a, u32 b) | ||
563 | { | ||
564 | if (a == b) | ||
565 | return 1; | ||
566 | |||
567 | switch (a) { | ||
568 | case CCN_TYPE_RNI_1P: | ||
569 | case CCN_TYPE_RNI_2P: | ||
570 | case CCN_TYPE_RNI_3P: | ||
571 | case CCN_TYPE_RND_1P: | ||
572 | case CCN_TYPE_RND_2P: | ||
573 | case CCN_TYPE_RND_3P: | ||
574 | switch (b) { | ||
575 | case CCN_TYPE_RNI_1P: | ||
576 | case CCN_TYPE_RNI_2P: | ||
577 | case CCN_TYPE_RNI_3P: | ||
578 | case CCN_TYPE_RND_1P: | ||
579 | case CCN_TYPE_RND_2P: | ||
580 | case CCN_TYPE_RND_3P: | ||
581 | return 1; | ||
582 | } | ||
583 | break; | ||
584 | } | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int arm_ccn_pmu_event_init(struct perf_event *event) | ||
590 | { | ||
591 | struct arm_ccn *ccn; | ||
592 | struct hw_perf_event *hw = &event->hw; | ||
593 | u32 node_xp, type, event_id; | ||
594 | int valid, bit; | ||
595 | struct arm_ccn_component *source; | ||
596 | int i; | ||
597 | |||
598 | if (event->attr.type != event->pmu->type) | ||
599 | return -ENOENT; | ||
600 | |||
601 | ccn = pmu_to_arm_ccn(event->pmu); | ||
602 | |||
603 | if (hw->sample_period) { | ||
604 | dev_warn(ccn->dev, "Sampling not supported!\n"); | ||
605 | return -EOPNOTSUPP; | ||
606 | } | ||
607 | |||
608 | if (has_branch_stack(event) || event->attr.exclude_user || | ||
609 | event->attr.exclude_kernel || event->attr.exclude_hv || | ||
610 | event->attr.exclude_idle) { | ||
611 | dev_warn(ccn->dev, "Can't exclude execution levels!\n"); | ||
612 | return -EOPNOTSUPP; | ||
613 | } | ||
614 | |||
615 | if (event->cpu < 0) { | ||
616 | dev_warn(ccn->dev, "Can't provide per-task data!\n"); | ||
617 | return -EOPNOTSUPP; | ||
618 | } | ||
619 | |||
620 | node_xp = CCN_CONFIG_NODE(event->attr.config); | ||
621 | type = CCN_CONFIG_TYPE(event->attr.config); | ||
622 | event_id = CCN_CONFIG_EVENT(event->attr.config); | ||
623 | |||
624 | /* Validate node/xp vs topology */ | ||
625 | switch (type) { | ||
626 | case CCN_TYPE_XP: | ||
627 | if (node_xp >= ccn->num_xps) { | ||
628 | dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp); | ||
629 | return -EINVAL; | ||
630 | } | ||
631 | break; | ||
632 | case CCN_TYPE_CYCLES: | ||
633 | break; | ||
634 | default: | ||
635 | if (node_xp >= ccn->num_nodes) { | ||
636 | dev_warn(ccn->dev, "Invalid node ID %d!\n", node_xp); | ||
637 | return -EINVAL; | ||
638 | } | ||
639 | if (!arm_ccn_pmu_type_eq(type, ccn->node[node_xp].type)) { | ||
640 | dev_warn(ccn->dev, "Invalid type 0x%x for node %d!\n", | ||
641 | type, node_xp); | ||
642 | return -EINVAL; | ||
643 | } | ||
644 | break; | ||
645 | } | ||
646 | |||
647 | /* Validate event ID vs available for the type */ | ||
648 | for (i = 0, valid = 0; i < ARRAY_SIZE(arm_ccn_pmu_events) && !valid; | ||
649 | i++) { | ||
650 | struct arm_ccn_pmu_event *e = &arm_ccn_pmu_events[i]; | ||
651 | u32 port = CCN_CONFIG_PORT(event->attr.config); | ||
652 | u32 vc = CCN_CONFIG_VC(event->attr.config); | ||
653 | |||
654 | if (!arm_ccn_pmu_type_eq(type, e->type)) | ||
655 | continue; | ||
656 | if (event_id != e->event) | ||
657 | continue; | ||
658 | if (e->num_ports && port >= e->num_ports) { | ||
659 | dev_warn(ccn->dev, "Invalid port %d for node/XP %d!\n", | ||
660 | port, node_xp); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | if (e->num_vcs && vc >= e->num_vcs) { | ||
664 | dev_warn(ccn->dev, "Invalid vc %d for node/XP %d!\n", | ||
665 | port, node_xp); | ||
666 | return -EINVAL; | ||
667 | } | ||
668 | valid = 1; | ||
669 | } | ||
670 | if (!valid) { | ||
671 | dev_warn(ccn->dev, "Invalid event 0x%x for node/XP %d!\n", | ||
672 | event_id, node_xp); | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | |||
676 | /* Watchpoint-based event for a node is actually set on XP */ | ||
677 | if (event_id == CCN_EVENT_WATCHPOINT && type != CCN_TYPE_XP) { | ||
678 | u32 port; | ||
679 | |||
680 | type = CCN_TYPE_XP; | ||
681 | port = arm_ccn_node_to_xp_port(node_xp); | ||
682 | node_xp = arm_ccn_node_to_xp(node_xp); | ||
683 | |||
684 | arm_ccn_pmu_config_set(&event->attr.config, | ||
685 | node_xp, type, port); | ||
686 | } | ||
687 | |||
688 | /* Allocate the cycle counter */ | ||
689 | if (type == CCN_TYPE_CYCLES) { | ||
690 | if (test_and_set_bit(CCN_IDX_PMU_CYCLE_COUNTER, | ||
691 | ccn->dt.pmu_counters_mask)) | ||
692 | return -EAGAIN; | ||
693 | |||
694 | hw->idx = CCN_IDX_PMU_CYCLE_COUNTER; | ||
695 | ccn->dt.pmu_counters[CCN_IDX_PMU_CYCLE_COUNTER].event = event; | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | /* Allocate an event counter */ | ||
701 | hw->idx = arm_ccn_pmu_alloc_bit(ccn->dt.pmu_counters_mask, | ||
702 | CCN_NUM_PMU_EVENT_COUNTERS); | ||
703 | if (hw->idx < 0) { | ||
704 | dev_warn(ccn->dev, "No more counters available!\n"); | ||
705 | return -EAGAIN; | ||
706 | } | ||
707 | |||
708 | if (type == CCN_TYPE_XP) | ||
709 | source = &ccn->xp[node_xp]; | ||
710 | else | ||
711 | source = &ccn->node[node_xp]; | ||
712 | ccn->dt.pmu_counters[hw->idx].source = source; | ||
713 | |||
714 | /* Allocate an event source or a watchpoint */ | ||
715 | if (type == CCN_TYPE_XP && event_id == CCN_EVENT_WATCHPOINT) | ||
716 | bit = arm_ccn_pmu_alloc_bit(source->xp.dt_cmp_mask, | ||
717 | CCN_NUM_XP_WATCHPOINTS); | ||
718 | else | ||
719 | bit = arm_ccn_pmu_alloc_bit(source->pmu_events_mask, | ||
720 | CCN_NUM_PMU_EVENTS); | ||
721 | if (bit < 0) { | ||
722 | dev_warn(ccn->dev, "No more event sources/watchpoints on node/XP %d!\n", | ||
723 | node_xp); | ||
724 | clear_bit(hw->idx, ccn->dt.pmu_counters_mask); | ||
725 | return -EAGAIN; | ||
726 | } | ||
727 | hw->config_base = bit; | ||
728 | |||
729 | ccn->dt.pmu_counters[hw->idx].event = event; | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | static void arm_ccn_pmu_event_free(struct perf_event *event) | ||
735 | { | ||
736 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
737 | struct hw_perf_event *hw = &event->hw; | ||
738 | |||
739 | if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER) { | ||
740 | clear_bit(CCN_IDX_PMU_CYCLE_COUNTER, ccn->dt.pmu_counters_mask); | ||
741 | } else { | ||
742 | struct arm_ccn_component *source = | ||
743 | ccn->dt.pmu_counters[hw->idx].source; | ||
744 | |||
745 | if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP && | ||
746 | CCN_CONFIG_EVENT(event->attr.config) == | ||
747 | CCN_EVENT_WATCHPOINT) | ||
748 | clear_bit(hw->config_base, source->xp.dt_cmp_mask); | ||
749 | else | ||
750 | clear_bit(hw->config_base, source->pmu_events_mask); | ||
751 | clear_bit(hw->idx, ccn->dt.pmu_counters_mask); | ||
752 | } | ||
753 | |||
754 | ccn->dt.pmu_counters[hw->idx].source = NULL; | ||
755 | ccn->dt.pmu_counters[hw->idx].event = NULL; | ||
756 | } | ||
757 | |||
758 | static u64 arm_ccn_pmu_read_counter(struct arm_ccn *ccn, int idx) | ||
759 | { | ||
760 | u64 res; | ||
761 | |||
762 | if (idx == CCN_IDX_PMU_CYCLE_COUNTER) { | ||
763 | #ifdef readq | ||
764 | res = readq(ccn->dt.base + CCN_DT_PMCCNTR); | ||
765 | #else | ||
766 | /* 40 bit counter, can do snapshot and read in two parts */ | ||
767 | writel(0x1, ccn->dt.base + CCN_DT_PMSR_REQ); | ||
768 | while (!(readl(ccn->dt.base + CCN_DT_PMSR) & 0x1)) | ||
769 | ; | ||
770 | writel(0x1, ccn->dt.base + CCN_DT_PMSR_CLR); | ||
771 | res = readl(ccn->dt.base + CCN_DT_PMCCNTRSR + 4) & 0xff; | ||
772 | res <<= 32; | ||
773 | res |= readl(ccn->dt.base + CCN_DT_PMCCNTRSR); | ||
774 | #endif | ||
775 | } else { | ||
776 | res = readl(ccn->dt.base + CCN_DT_PMEVCNT(idx)); | ||
777 | } | ||
778 | |||
779 | return res; | ||
780 | } | ||
781 | |||
782 | static void arm_ccn_pmu_event_update(struct perf_event *event) | ||
783 | { | ||
784 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
785 | struct hw_perf_event *hw = &event->hw; | ||
786 | u64 prev_count, new_count, mask; | ||
787 | |||
788 | do { | ||
789 | prev_count = local64_read(&hw->prev_count); | ||
790 | new_count = arm_ccn_pmu_read_counter(ccn, hw->idx); | ||
791 | } while (local64_xchg(&hw->prev_count, new_count) != prev_count); | ||
792 | |||
793 | mask = (1LLU << (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER ? 40 : 32)) - 1; | ||
794 | |||
795 | local64_add((new_count - prev_count) & mask, &event->count); | ||
796 | } | ||
797 | |||
798 | static void arm_ccn_pmu_xp_dt_config(struct perf_event *event, int enable) | ||
799 | { | ||
800 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
801 | struct hw_perf_event *hw = &event->hw; | ||
802 | struct arm_ccn_component *xp; | ||
803 | u32 val, dt_cfg; | ||
804 | |||
805 | if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP) | ||
806 | xp = &ccn->xp[CCN_CONFIG_XP(event->attr.config)]; | ||
807 | else | ||
808 | xp = &ccn->xp[arm_ccn_node_to_xp( | ||
809 | CCN_CONFIG_NODE(event->attr.config))]; | ||
810 | |||
811 | if (enable) | ||
812 | dt_cfg = hw->event_base; | ||
813 | else | ||
814 | dt_cfg = CCN_XP_DT_CONFIG__DT_CFG__PASS_THROUGH; | ||
815 | |||
816 | spin_lock(&ccn->dt.config_lock); | ||
817 | |||
818 | val = readl(xp->base + CCN_XP_DT_CONFIG); | ||
819 | val &= ~(CCN_XP_DT_CONFIG__DT_CFG__MASK << | ||
820 | CCN_XP_DT_CONFIG__DT_CFG__SHIFT(hw->idx)); | ||
821 | val |= dt_cfg << CCN_XP_DT_CONFIG__DT_CFG__SHIFT(hw->idx); | ||
822 | writel(val, xp->base + CCN_XP_DT_CONFIG); | ||
823 | |||
824 | spin_unlock(&ccn->dt.config_lock); | ||
825 | } | ||
826 | |||
827 | static void arm_ccn_pmu_event_start(struct perf_event *event, int flags) | ||
828 | { | ||
829 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
830 | struct hw_perf_event *hw = &event->hw; | ||
831 | |||
832 | local64_set(&event->hw.prev_count, | ||
833 | arm_ccn_pmu_read_counter(ccn, hw->idx)); | ||
834 | hw->state = 0; | ||
835 | |||
836 | if (!ccn->irq_used) | ||
837 | hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(), | ||
838 | HRTIMER_MODE_REL); | ||
839 | |||
840 | /* Set the DT bus input, engaging the counter */ | ||
841 | arm_ccn_pmu_xp_dt_config(event, 1); | ||
842 | } | ||
843 | |||
844 | static void arm_ccn_pmu_event_stop(struct perf_event *event, int flags) | ||
845 | { | ||
846 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
847 | struct hw_perf_event *hw = &event->hw; | ||
848 | u64 timeout; | ||
849 | |||
850 | /* Disable counting, setting the DT bus to pass-through mode */ | ||
851 | arm_ccn_pmu_xp_dt_config(event, 0); | ||
852 | |||
853 | if (!ccn->irq_used) | ||
854 | hrtimer_cancel(&ccn->dt.hrtimer); | ||
855 | |||
856 | /* Let the DT bus drain */ | ||
857 | timeout = arm_ccn_pmu_read_counter(ccn, CCN_IDX_PMU_CYCLE_COUNTER) + | ||
858 | ccn->num_xps; | ||
859 | while (arm_ccn_pmu_read_counter(ccn, CCN_IDX_PMU_CYCLE_COUNTER) < | ||
860 | timeout) | ||
861 | cpu_relax(); | ||
862 | |||
863 | if (flags & PERF_EF_UPDATE) | ||
864 | arm_ccn_pmu_event_update(event); | ||
865 | |||
866 | hw->state |= PERF_HES_STOPPED; | ||
867 | } | ||
868 | |||
869 | static void arm_ccn_pmu_xp_watchpoint_config(struct perf_event *event) | ||
870 | { | ||
871 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
872 | struct hw_perf_event *hw = &event->hw; | ||
873 | struct arm_ccn_component *source = | ||
874 | ccn->dt.pmu_counters[hw->idx].source; | ||
875 | unsigned long wp = hw->config_base; | ||
876 | u32 val; | ||
877 | u64 cmp_l = event->attr.config1; | ||
878 | u64 cmp_h = event->attr.config2; | ||
879 | u64 mask_l = ccn->dt.cmp_mask[CCN_CONFIG_MASK(event->attr.config)].l; | ||
880 | u64 mask_h = ccn->dt.cmp_mask[CCN_CONFIG_MASK(event->attr.config)].h; | ||
881 | |||
882 | hw->event_base = CCN_XP_DT_CONFIG__DT_CFG__WATCHPOINT(wp); | ||
883 | |||
884 | /* Direction (RX/TX), device (port) & virtual channel */ | ||
885 | val = readl(source->base + CCN_XP_DT_INTERFACE_SEL); | ||
886 | val &= ~(CCN_XP_DT_INTERFACE_SEL__DT_IO_SEL__MASK << | ||
887 | CCN_XP_DT_INTERFACE_SEL__DT_IO_SEL__SHIFT(wp)); | ||
888 | val |= CCN_CONFIG_DIR(event->attr.config) << | ||
889 | CCN_XP_DT_INTERFACE_SEL__DT_IO_SEL__SHIFT(wp); | ||
890 | val &= ~(CCN_XP_DT_INTERFACE_SEL__DT_DEV_SEL__MASK << | ||
891 | CCN_XP_DT_INTERFACE_SEL__DT_DEV_SEL__SHIFT(wp)); | ||
892 | val |= CCN_CONFIG_PORT(event->attr.config) << | ||
893 | CCN_XP_DT_INTERFACE_SEL__DT_DEV_SEL__SHIFT(wp); | ||
894 | val &= ~(CCN_XP_DT_INTERFACE_SEL__DT_VC_SEL__MASK << | ||
895 | CCN_XP_DT_INTERFACE_SEL__DT_VC_SEL__SHIFT(wp)); | ||
896 | val |= CCN_CONFIG_VC(event->attr.config) << | ||
897 | CCN_XP_DT_INTERFACE_SEL__DT_VC_SEL__SHIFT(wp); | ||
898 | writel(val, source->base + CCN_XP_DT_INTERFACE_SEL); | ||
899 | |||
900 | /* Comparison values */ | ||
901 | writel(cmp_l & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_L(wp)); | ||
902 | writel((cmp_l >> 32) & 0xefffffff, | ||
903 | source->base + CCN_XP_DT_CMP_VAL_L(wp) + 4); | ||
904 | writel(cmp_h & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_H(wp)); | ||
905 | writel((cmp_h >> 32) & 0x0fffffff, | ||
906 | source->base + CCN_XP_DT_CMP_VAL_H(wp) + 4); | ||
907 | |||
908 | /* Mask */ | ||
909 | writel(mask_l & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_L(wp)); | ||
910 | writel((mask_l >> 32) & 0xefffffff, | ||
911 | source->base + CCN_XP_DT_CMP_MASK_L(wp) + 4); | ||
912 | writel(mask_h & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_H(wp)); | ||
913 | writel((mask_h >> 32) & 0x0fffffff, | ||
914 | source->base + CCN_XP_DT_CMP_MASK_H(wp) + 4); | ||
915 | } | ||
916 | |||
917 | static void arm_ccn_pmu_xp_event_config(struct perf_event *event) | ||
918 | { | ||
919 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
920 | struct hw_perf_event *hw = &event->hw; | ||
921 | struct arm_ccn_component *source = | ||
922 | ccn->dt.pmu_counters[hw->idx].source; | ||
923 | u32 val, id; | ||
924 | |||
925 | hw->event_base = CCN_XP_DT_CONFIG__DT_CFG__XP_PMU_EVENT(hw->config_base); | ||
926 | |||
927 | id = (CCN_CONFIG_VC(event->attr.config) << 4) | | ||
928 | (CCN_CONFIG_PORT(event->attr.config) << 3) | | ||
929 | (CCN_CONFIG_EVENT(event->attr.config) << 0); | ||
930 | |||
931 | val = readl(source->base + CCN_XP_PMU_EVENT_SEL); | ||
932 | val &= ~(CCN_XP_PMU_EVENT_SEL__ID__MASK << | ||
933 | CCN_XP_PMU_EVENT_SEL__ID__SHIFT(hw->config_base)); | ||
934 | val |= id << CCN_XP_PMU_EVENT_SEL__ID__SHIFT(hw->config_base); | ||
935 | writel(val, source->base + CCN_XP_PMU_EVENT_SEL); | ||
936 | } | ||
937 | |||
938 | static void arm_ccn_pmu_node_event_config(struct perf_event *event) | ||
939 | { | ||
940 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
941 | struct hw_perf_event *hw = &event->hw; | ||
942 | struct arm_ccn_component *source = | ||
943 | ccn->dt.pmu_counters[hw->idx].source; | ||
944 | u32 type = CCN_CONFIG_TYPE(event->attr.config); | ||
945 | u32 val, port; | ||
946 | |||
947 | port = arm_ccn_node_to_xp_port(CCN_CONFIG_NODE(event->attr.config)); | ||
948 | hw->event_base = CCN_XP_DT_CONFIG__DT_CFG__DEVICE_PMU_EVENT(port, | ||
949 | hw->config_base); | ||
950 | |||
951 | /* These *_event_sel regs should be identical, but let's make sure... */ | ||
952 | BUILD_BUG_ON(CCN_HNF_PMU_EVENT_SEL != CCN_SBAS_PMU_EVENT_SEL); | ||
953 | BUILD_BUG_ON(CCN_SBAS_PMU_EVENT_SEL != CCN_RNI_PMU_EVENT_SEL); | ||
954 | BUILD_BUG_ON(CCN_HNF_PMU_EVENT_SEL__ID__SHIFT(1) != | ||
955 | CCN_SBAS_PMU_EVENT_SEL__ID__SHIFT(1)); | ||
956 | BUILD_BUG_ON(CCN_SBAS_PMU_EVENT_SEL__ID__SHIFT(1) != | ||
957 | CCN_RNI_PMU_EVENT_SEL__ID__SHIFT(1)); | ||
958 | BUILD_BUG_ON(CCN_HNF_PMU_EVENT_SEL__ID__MASK != | ||
959 | CCN_SBAS_PMU_EVENT_SEL__ID__MASK); | ||
960 | BUILD_BUG_ON(CCN_SBAS_PMU_EVENT_SEL__ID__MASK != | ||
961 | CCN_RNI_PMU_EVENT_SEL__ID__MASK); | ||
962 | if (WARN_ON(type != CCN_TYPE_HNF && type != CCN_TYPE_SBAS && | ||
963 | !arm_ccn_pmu_type_eq(type, CCN_TYPE_RNI_3P))) | ||
964 | return; | ||
965 | |||
966 | /* Set the event id for the pre-allocated counter */ | ||
967 | val = readl(source->base + CCN_HNF_PMU_EVENT_SEL); | ||
968 | val &= ~(CCN_HNF_PMU_EVENT_SEL__ID__MASK << | ||
969 | CCN_HNF_PMU_EVENT_SEL__ID__SHIFT(hw->config_base)); | ||
970 | val |= CCN_CONFIG_EVENT(event->attr.config) << | ||
971 | CCN_HNF_PMU_EVENT_SEL__ID__SHIFT(hw->config_base); | ||
972 | writel(val, source->base + CCN_HNF_PMU_EVENT_SEL); | ||
973 | } | ||
974 | |||
975 | static void arm_ccn_pmu_event_config(struct perf_event *event) | ||
976 | { | ||
977 | struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu); | ||
978 | struct hw_perf_event *hw = &event->hw; | ||
979 | u32 xp, offset, val; | ||
980 | |||
981 | /* Cycle counter requires no setup */ | ||
982 | if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER) | ||
983 | return; | ||
984 | |||
985 | if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP) | ||
986 | xp = CCN_CONFIG_XP(event->attr.config); | ||
987 | else | ||
988 | xp = arm_ccn_node_to_xp(CCN_CONFIG_NODE(event->attr.config)); | ||
989 | |||
990 | spin_lock(&ccn->dt.config_lock); | ||
991 | |||
992 | /* Set the DT bus "distance" register */ | ||
993 | offset = (hw->idx / 4) * 4; | ||
994 | val = readl(ccn->dt.base + CCN_DT_ACTIVE_DSM + offset); | ||
995 | val &= ~(CCN_DT_ACTIVE_DSM__DSM_ID__MASK << | ||
996 | CCN_DT_ACTIVE_DSM__DSM_ID__SHIFT(hw->idx % 4)); | ||
997 | val |= xp << CCN_DT_ACTIVE_DSM__DSM_ID__SHIFT(hw->idx % 4); | ||
998 | writel(val, ccn->dt.base + CCN_DT_ACTIVE_DSM + offset); | ||
999 | |||
1000 | if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP) { | ||
1001 | if (CCN_CONFIG_EVENT(event->attr.config) == | ||
1002 | CCN_EVENT_WATCHPOINT) | ||
1003 | arm_ccn_pmu_xp_watchpoint_config(event); | ||
1004 | else | ||
1005 | arm_ccn_pmu_xp_event_config(event); | ||
1006 | } else { | ||
1007 | arm_ccn_pmu_node_event_config(event); | ||
1008 | } | ||
1009 | |||
1010 | spin_unlock(&ccn->dt.config_lock); | ||
1011 | } | ||
1012 | |||
1013 | static int arm_ccn_pmu_event_add(struct perf_event *event, int flags) | ||
1014 | { | ||
1015 | struct hw_perf_event *hw = &event->hw; | ||
1016 | |||
1017 | arm_ccn_pmu_event_config(event); | ||
1018 | |||
1019 | hw->state = PERF_HES_STOPPED; | ||
1020 | |||
1021 | if (flags & PERF_EF_START) | ||
1022 | arm_ccn_pmu_event_start(event, PERF_EF_UPDATE); | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static void arm_ccn_pmu_event_del(struct perf_event *event, int flags) | ||
1028 | { | ||
1029 | arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE); | ||
1030 | |||
1031 | arm_ccn_pmu_event_free(event); | ||
1032 | } | ||
1033 | |||
1034 | static void arm_ccn_pmu_event_read(struct perf_event *event) | ||
1035 | { | ||
1036 | arm_ccn_pmu_event_update(event); | ||
1037 | } | ||
1038 | |||
1039 | static irqreturn_t arm_ccn_pmu_overflow_handler(struct arm_ccn_dt *dt) | ||
1040 | { | ||
1041 | u32 pmovsr = readl(dt->base + CCN_DT_PMOVSR); | ||
1042 | int idx; | ||
1043 | |||
1044 | if (!pmovsr) | ||
1045 | return IRQ_NONE; | ||
1046 | |||
1047 | writel(pmovsr, dt->base + CCN_DT_PMOVSR_CLR); | ||
1048 | |||
1049 | BUILD_BUG_ON(CCN_IDX_PMU_CYCLE_COUNTER != CCN_NUM_PMU_EVENT_COUNTERS); | ||
1050 | |||
1051 | for (idx = 0; idx < CCN_NUM_PMU_EVENT_COUNTERS + 1; idx++) { | ||
1052 | struct perf_event *event = dt->pmu_counters[idx].event; | ||
1053 | int overflowed = pmovsr & BIT(idx); | ||
1054 | |||
1055 | WARN_ON_ONCE(overflowed && !event); | ||
1056 | |||
1057 | if (!event || !overflowed) | ||
1058 | continue; | ||
1059 | |||
1060 | arm_ccn_pmu_event_update(event); | ||
1061 | } | ||
1062 | |||
1063 | return IRQ_HANDLED; | ||
1064 | } | ||
1065 | |||
1066 | static enum hrtimer_restart arm_ccn_pmu_timer_handler(struct hrtimer *hrtimer) | ||
1067 | { | ||
1068 | struct arm_ccn_dt *dt = container_of(hrtimer, struct arm_ccn_dt, | ||
1069 | hrtimer); | ||
1070 | unsigned long flags; | ||
1071 | |||
1072 | local_irq_save(flags); | ||
1073 | arm_ccn_pmu_overflow_handler(dt); | ||
1074 | local_irq_restore(flags); | ||
1075 | |||
1076 | hrtimer_forward_now(hrtimer, arm_ccn_pmu_timer_period()); | ||
1077 | return HRTIMER_RESTART; | ||
1078 | } | ||
1079 | |||
1080 | |||
1081 | static DEFINE_IDA(arm_ccn_pmu_ida); | ||
1082 | |||
1083 | static int arm_ccn_pmu_init(struct arm_ccn *ccn) | ||
1084 | { | ||
1085 | int i; | ||
1086 | char *name; | ||
1087 | |||
1088 | /* Initialize DT subsystem */ | ||
1089 | ccn->dt.base = ccn->base + CCN_REGION_SIZE; | ||
1090 | spin_lock_init(&ccn->dt.config_lock); | ||
1091 | writel(CCN_DT_CTL__DT_EN, ccn->dt.base + CCN_DT_CTL); | ||
1092 | writel(CCN_DT_PMCR__OVFL_INTR_EN | CCN_DT_PMCR__PMU_EN, | ||
1093 | ccn->dt.base + CCN_DT_PMCR); | ||
1094 | writel(0x1, ccn->dt.base + CCN_DT_PMSR_CLR); | ||
1095 | for (i = 0; i < ccn->num_xps; i++) { | ||
1096 | writel(0, ccn->xp[i].base + CCN_XP_DT_CONFIG); | ||
1097 | writel((CCN_XP_DT_CONTROL__WP_ARM_SEL__ALWAYS << | ||
1098 | CCN_XP_DT_CONTROL__WP_ARM_SEL__SHIFT(0)) | | ||
1099 | (CCN_XP_DT_CONTROL__WP_ARM_SEL__ALWAYS << | ||
1100 | CCN_XP_DT_CONTROL__WP_ARM_SEL__SHIFT(1)) | | ||
1101 | CCN_XP_DT_CONTROL__DT_ENABLE, | ||
1102 | ccn->xp[i].base + CCN_XP_DT_CONTROL); | ||
1103 | } | ||
1104 | ccn->dt.cmp_mask[CCN_IDX_MASK_ANY].l = ~0; | ||
1105 | ccn->dt.cmp_mask[CCN_IDX_MASK_ANY].h = ~0; | ||
1106 | ccn->dt.cmp_mask[CCN_IDX_MASK_EXACT].l = 0; | ||
1107 | ccn->dt.cmp_mask[CCN_IDX_MASK_EXACT].h = 0; | ||
1108 | ccn->dt.cmp_mask[CCN_IDX_MASK_ORDER].l = ~0; | ||
1109 | ccn->dt.cmp_mask[CCN_IDX_MASK_ORDER].h = ~(0x1 << 15); | ||
1110 | ccn->dt.cmp_mask[CCN_IDX_MASK_OPCODE].l = ~0; | ||
1111 | ccn->dt.cmp_mask[CCN_IDX_MASK_OPCODE].h = ~(0x1f << 9); | ||
1112 | |||
1113 | /* Get a convenient /sys/event_source/devices/ name */ | ||
1114 | ccn->dt.id = ida_simple_get(&arm_ccn_pmu_ida, 0, 0, GFP_KERNEL); | ||
1115 | if (ccn->dt.id == 0) { | ||
1116 | name = "ccn"; | ||
1117 | } else { | ||
1118 | int len = snprintf(NULL, 0, "ccn_%d", ccn->dt.id); | ||
1119 | |||
1120 | name = devm_kzalloc(ccn->dev, len + 1, GFP_KERNEL); | ||
1121 | snprintf(name, len + 1, "ccn_%d", ccn->dt.id); | ||
1122 | } | ||
1123 | |||
1124 | /* Perf driver registration */ | ||
1125 | ccn->dt.pmu = (struct pmu) { | ||
1126 | .attr_groups = arm_ccn_pmu_attr_groups, | ||
1127 | .task_ctx_nr = perf_invalid_context, | ||
1128 | .event_init = arm_ccn_pmu_event_init, | ||
1129 | .add = arm_ccn_pmu_event_add, | ||
1130 | .del = arm_ccn_pmu_event_del, | ||
1131 | .start = arm_ccn_pmu_event_start, | ||
1132 | .stop = arm_ccn_pmu_event_stop, | ||
1133 | .read = arm_ccn_pmu_event_read, | ||
1134 | }; | ||
1135 | |||
1136 | /* No overflow interrupt? Have to use a timer instead. */ | ||
1137 | if (!ccn->irq_used) { | ||
1138 | dev_info(ccn->dev, "No access to interrupts, using timer.\n"); | ||
1139 | hrtimer_init(&ccn->dt.hrtimer, CLOCK_MONOTONIC, | ||
1140 | HRTIMER_MODE_REL); | ||
1141 | ccn->dt.hrtimer.function = arm_ccn_pmu_timer_handler; | ||
1142 | } | ||
1143 | |||
1144 | return perf_pmu_register(&ccn->dt.pmu, name, -1); | ||
1145 | } | ||
1146 | |||
1147 | static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn) | ||
1148 | { | ||
1149 | int i; | ||
1150 | |||
1151 | for (i = 0; i < ccn->num_xps; i++) | ||
1152 | writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL); | ||
1153 | writel(0, ccn->dt.base + CCN_DT_PMCR); | ||
1154 | perf_pmu_unregister(&ccn->dt.pmu); | ||
1155 | ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id); | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | static int arm_ccn_for_each_valid_region(struct arm_ccn *ccn, | ||
1160 | int (*callback)(struct arm_ccn *ccn, int region, | ||
1161 | void __iomem *base, u32 type, u32 id)) | ||
1162 | { | ||
1163 | int region; | ||
1164 | |||
1165 | for (region = 0; region < CCN_NUM_REGIONS; region++) { | ||
1166 | u32 val, type, id; | ||
1167 | void __iomem *base; | ||
1168 | int err; | ||
1169 | |||
1170 | val = readl(ccn->base + CCN_MN_OLY_COMP_LIST_63_0 + | ||
1171 | 4 * (region / 32)); | ||
1172 | if (!(val & (1 << (region % 32)))) | ||
1173 | continue; | ||
1174 | |||
1175 | base = ccn->base + region * CCN_REGION_SIZE; | ||
1176 | val = readl(base + CCN_ALL_OLY_ID); | ||
1177 | type = (val >> CCN_ALL_OLY_ID__OLY_ID__SHIFT) & | ||
1178 | CCN_ALL_OLY_ID__OLY_ID__MASK; | ||
1179 | id = (val >> CCN_ALL_OLY_ID__NODE_ID__SHIFT) & | ||
1180 | CCN_ALL_OLY_ID__NODE_ID__MASK; | ||
1181 | |||
1182 | err = callback(ccn, region, base, type, id); | ||
1183 | if (err) | ||
1184 | return err; | ||
1185 | } | ||
1186 | |||
1187 | return 0; | ||
1188 | } | ||
1189 | |||
1190 | static int arm_ccn_get_nodes_num(struct arm_ccn *ccn, int region, | ||
1191 | void __iomem *base, u32 type, u32 id) | ||
1192 | { | ||
1193 | |||
1194 | if (type == CCN_TYPE_XP && id >= ccn->num_xps) | ||
1195 | ccn->num_xps = id + 1; | ||
1196 | else if (id >= ccn->num_nodes) | ||
1197 | ccn->num_nodes = id + 1; | ||
1198 | |||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static int arm_ccn_init_nodes(struct arm_ccn *ccn, int region, | ||
1203 | void __iomem *base, u32 type, u32 id) | ||
1204 | { | ||
1205 | struct arm_ccn_component *component; | ||
1206 | |||
1207 | dev_dbg(ccn->dev, "Region %d: id=%u, type=0x%02x\n", region, id, type); | ||
1208 | |||
1209 | switch (type) { | ||
1210 | case CCN_TYPE_MN: | ||
1211 | case CCN_TYPE_DT: | ||
1212 | return 0; | ||
1213 | case CCN_TYPE_XP: | ||
1214 | component = &ccn->xp[id]; | ||
1215 | break; | ||
1216 | case CCN_TYPE_SBSX: | ||
1217 | ccn->sbsx_present = 1; | ||
1218 | component = &ccn->node[id]; | ||
1219 | break; | ||
1220 | case CCN_TYPE_SBAS: | ||
1221 | ccn->sbas_present = 1; | ||
1222 | /* Fall-through */ | ||
1223 | default: | ||
1224 | component = &ccn->node[id]; | ||
1225 | break; | ||
1226 | } | ||
1227 | |||
1228 | component->base = base; | ||
1229 | component->type = type; | ||
1230 | |||
1231 | return 0; | ||
1232 | } | ||
1233 | |||
1234 | |||
1235 | static irqreturn_t arm_ccn_error_handler(struct arm_ccn *ccn, | ||
1236 | const u32 *err_sig_val) | ||
1237 | { | ||
1238 | /* This should be really handled by firmware... */ | ||
1239 | dev_err(ccn->dev, "Error reported in %08x%08x%08x%08x%08x%08x.\n", | ||
1240 | err_sig_val[5], err_sig_val[4], err_sig_val[3], | ||
1241 | err_sig_val[2], err_sig_val[1], err_sig_val[0]); | ||
1242 | dev_err(ccn->dev, "Disabling interrupt generation for all errors.\n"); | ||
1243 | writel(CCN_MN_ERRINT_STATUS__ALL_ERRORS__DISABLE, | ||
1244 | ccn->base + CCN_MN_ERRINT_STATUS); | ||
1245 | |||
1246 | return IRQ_HANDLED; | ||
1247 | } | ||
1248 | |||
1249 | |||
1250 | static irqreturn_t arm_ccn_irq_handler(int irq, void *dev_id) | ||
1251 | { | ||
1252 | irqreturn_t res = IRQ_NONE; | ||
1253 | struct arm_ccn *ccn = dev_id; | ||
1254 | u32 err_sig_val[6]; | ||
1255 | u32 err_or; | ||
1256 | int i; | ||
1257 | |||
1258 | /* PMU overflow is a special case */ | ||
1259 | err_or = err_sig_val[0] = readl(ccn->base + CCN_MN_ERR_SIG_VAL_63_0); | ||
1260 | if (err_or & CCN_MN_ERR_SIG_VAL_63_0__DT) { | ||
1261 | err_or &= ~CCN_MN_ERR_SIG_VAL_63_0__DT; | ||
1262 | res = arm_ccn_pmu_overflow_handler(&ccn->dt); | ||
1263 | } | ||
1264 | |||
1265 | /* Have to read all err_sig_vals to clear them */ | ||
1266 | for (i = 1; i < ARRAY_SIZE(err_sig_val); i++) { | ||
1267 | err_sig_val[i] = readl(ccn->base + | ||
1268 | CCN_MN_ERR_SIG_VAL_63_0 + i * 4); | ||
1269 | err_or |= err_sig_val[i]; | ||
1270 | } | ||
1271 | if (err_or) | ||
1272 | res |= arm_ccn_error_handler(ccn, err_sig_val); | ||
1273 | |||
1274 | if (res != IRQ_NONE) | ||
1275 | writel(CCN_MN_ERRINT_STATUS__INTREQ__DESSERT, | ||
1276 | ccn->base + CCN_MN_ERRINT_STATUS); | ||
1277 | |||
1278 | return res; | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | static int arm_ccn_probe(struct platform_device *pdev) | ||
1283 | { | ||
1284 | struct arm_ccn *ccn; | ||
1285 | struct resource *res; | ||
1286 | int err; | ||
1287 | |||
1288 | ccn = devm_kzalloc(&pdev->dev, sizeof(*ccn), GFP_KERNEL); | ||
1289 | if (!ccn) | ||
1290 | return -ENOMEM; | ||
1291 | ccn->dev = &pdev->dev; | ||
1292 | platform_set_drvdata(pdev, ccn); | ||
1293 | |||
1294 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1295 | if (!res) | ||
1296 | return -EINVAL; | ||
1297 | |||
1298 | if (!devm_request_mem_region(ccn->dev, res->start, | ||
1299 | resource_size(res), pdev->name)) | ||
1300 | return -EBUSY; | ||
1301 | |||
1302 | ccn->base = devm_ioremap(ccn->dev, res->start, | ||
1303 | resource_size(res)); | ||
1304 | if (!ccn->base) | ||
1305 | return -EFAULT; | ||
1306 | |||
1307 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1308 | if (!res) | ||
1309 | return -EINVAL; | ||
1310 | |||
1311 | /* Check if we can use the interrupt */ | ||
1312 | writel(CCN_MN_ERRINT_STATUS__PMU_EVENTS__DISABLE, | ||
1313 | ccn->base + CCN_MN_ERRINT_STATUS); | ||
1314 | if (readl(ccn->base + CCN_MN_ERRINT_STATUS) & | ||
1315 | CCN_MN_ERRINT_STATUS__PMU_EVENTS__DISABLED) { | ||
1316 | /* Can set 'disable' bits, so can acknowledge interrupts */ | ||
1317 | writel(CCN_MN_ERRINT_STATUS__PMU_EVENTS__ENABLE, | ||
1318 | ccn->base + CCN_MN_ERRINT_STATUS); | ||
1319 | err = devm_request_irq(ccn->dev, res->start, | ||
1320 | arm_ccn_irq_handler, 0, dev_name(ccn->dev), | ||
1321 | ccn); | ||
1322 | if (err) | ||
1323 | return err; | ||
1324 | |||
1325 | ccn->irq_used = 1; | ||
1326 | } | ||
1327 | |||
1328 | |||
1329 | /* Build topology */ | ||
1330 | |||
1331 | err = arm_ccn_for_each_valid_region(ccn, arm_ccn_get_nodes_num); | ||
1332 | if (err) | ||
1333 | return err; | ||
1334 | |||
1335 | ccn->node = devm_kzalloc(ccn->dev, sizeof(*ccn->node) * ccn->num_nodes, | ||
1336 | GFP_KERNEL); | ||
1337 | ccn->xp = devm_kzalloc(ccn->dev, sizeof(*ccn->node) * ccn->num_xps, | ||
1338 | GFP_KERNEL); | ||
1339 | if (!ccn->node || !ccn->xp) | ||
1340 | return -ENOMEM; | ||
1341 | |||
1342 | err = arm_ccn_for_each_valid_region(ccn, arm_ccn_init_nodes); | ||
1343 | if (err) | ||
1344 | return err; | ||
1345 | |||
1346 | return arm_ccn_pmu_init(ccn); | ||
1347 | } | ||
1348 | |||
1349 | static int arm_ccn_remove(struct platform_device *pdev) | ||
1350 | { | ||
1351 | struct arm_ccn *ccn = platform_get_drvdata(pdev); | ||
1352 | |||
1353 | arm_ccn_pmu_cleanup(ccn); | ||
1354 | |||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | static const struct of_device_id arm_ccn_match[] = { | ||
1359 | { .compatible = "arm,ccn-504", }, | ||
1360 | {}, | ||
1361 | }; | ||
1362 | |||
1363 | static struct platform_driver arm_ccn_driver = { | ||
1364 | .driver = { | ||
1365 | .name = "arm-ccn", | ||
1366 | .of_match_table = arm_ccn_match, | ||
1367 | }, | ||
1368 | .probe = arm_ccn_probe, | ||
1369 | .remove = arm_ccn_remove, | ||
1370 | }; | ||
1371 | |||
1372 | static int __init arm_ccn_init(void) | ||
1373 | { | ||
1374 | int i; | ||
1375 | |||
1376 | for (i = 0; i < ARRAY_SIZE(arm_ccn_pmu_events); i++) | ||
1377 | arm_ccn_pmu_events_attrs[i] = &arm_ccn_pmu_events[i].attr.attr; | ||
1378 | |||
1379 | return platform_driver_register(&arm_ccn_driver); | ||
1380 | } | ||
1381 | |||
1382 | static void __exit arm_ccn_exit(void) | ||
1383 | { | ||
1384 | platform_driver_unregister(&arm_ccn_driver); | ||
1385 | } | ||
1386 | |||
1387 | module_init(arm_ccn_init); | ||
1388 | module_exit(arm_ccn_exit); | ||
1389 | |||
1390 | MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); | ||
1391 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 30e82860567a..8c96e2ddf43b 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -32,14 +32,6 @@ config LEDS_88PM860X | |||
32 | This option enables support for on-chip LED drivers found on Marvell | 32 | This option enables support for on-chip LED drivers found on Marvell |
33 | Semiconductor 88PM8606 PMIC. | 33 | Semiconductor 88PM8606 PMIC. |
34 | 34 | ||
35 | config LEDS_ATMEL_PWM | ||
36 | tristate "LED Support using Atmel PWM outputs" | ||
37 | depends on LEDS_CLASS | ||
38 | depends on ATMEL_PWM | ||
39 | help | ||
40 | This option enables support for LEDs driven using outputs | ||
41 | of the dedicated PWM controller found on newer Atmel SOCs. | ||
42 | |||
43 | config LEDS_LM3530 | 35 | config LEDS_LM3530 |
44 | tristate "LCD Backlight driver for LM3530" | 36 | tristate "LCD Backlight driver for LM3530" |
45 | depends on LEDS_CLASS | 37 | depends on LEDS_CLASS |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index b2a62959ff8f..d8cc5f2777de 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -6,7 +6,6 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o | |||
6 | 6 | ||
7 | # LED Platform Drivers | 7 | # LED Platform Drivers |
8 | obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o | 8 | obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o |
9 | obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o | ||
10 | obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o | 9 | obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o |
11 | obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o | 10 | obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o |
12 | obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o | 11 | obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o |
diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c deleted file mode 100644 index 56cec8d6a2ac..000000000000 --- a/drivers/leds/leds-atmel-pwm.c +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/platform_device.h> | ||
3 | #include <linux/leds.h> | ||
4 | #include <linux/io.h> | ||
5 | #include <linux/atmel_pwm.h> | ||
6 | #include <linux/slab.h> | ||
7 | #include <linux/module.h> | ||
8 | |||
9 | |||
10 | struct pwmled { | ||
11 | struct led_classdev cdev; | ||
12 | struct pwm_channel pwmc; | ||
13 | struct gpio_led *desc; | ||
14 | u32 mult; | ||
15 | u8 active_low; | ||
16 | }; | ||
17 | |||
18 | |||
19 | /* | ||
20 | * For simplicity, we use "brightness" as if it were a linear function | ||
21 | * of PWM duty cycle. However, a logarithmic function of duty cycle is | ||
22 | * probably a better match for perceived brightness: two is half as bright | ||
23 | * as four, four is half as bright as eight, etc | ||
24 | */ | ||
25 | static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b) | ||
26 | { | ||
27 | struct pwmled *led; | ||
28 | |||
29 | /* update the duty cycle for the *next* period */ | ||
30 | led = container_of(cdev, struct pwmled, cdev); | ||
31 | pwm_channel_writel(&led->pwmc, PWM_CUPD, led->mult * (unsigned) b); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * NOTE: we reuse the platform_data structure of GPIO leds, | ||
36 | * but repurpose its "gpio" number as a PWM channel number. | ||
37 | */ | ||
38 | static int pwmled_probe(struct platform_device *pdev) | ||
39 | { | ||
40 | const struct gpio_led_platform_data *pdata; | ||
41 | struct pwmled *leds; | ||
42 | int i; | ||
43 | int status; | ||
44 | |||
45 | pdata = dev_get_platdata(&pdev->dev); | ||
46 | if (!pdata || pdata->num_leds < 1) | ||
47 | return -ENODEV; | ||
48 | |||
49 | leds = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*leds), | ||
50 | GFP_KERNEL); | ||
51 | if (!leds) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | for (i = 0; i < pdata->num_leds; i++) { | ||
55 | struct pwmled *led = leds + i; | ||
56 | const struct gpio_led *dat = pdata->leds + i; | ||
57 | u32 tmp; | ||
58 | |||
59 | led->cdev.name = dat->name; | ||
60 | led->cdev.brightness = LED_OFF; | ||
61 | led->cdev.brightness_set = pwmled_brightness; | ||
62 | led->cdev.default_trigger = dat->default_trigger; | ||
63 | |||
64 | led->active_low = dat->active_low; | ||
65 | |||
66 | status = pwm_channel_alloc(dat->gpio, &led->pwmc); | ||
67 | if (status < 0) | ||
68 | goto err; | ||
69 | |||
70 | /* | ||
71 | * Prescale clock by 2^x, so PWM counts in low MHz. | ||
72 | * Start each cycle with the LED active, so increasing | ||
73 | * the duty cycle gives us more time on (== brighter). | ||
74 | */ | ||
75 | tmp = 5; | ||
76 | if (!led->active_low) | ||
77 | tmp |= PWM_CPR_CPOL; | ||
78 | pwm_channel_writel(&led->pwmc, PWM_CMR, tmp); | ||
79 | |||
80 | /* | ||
81 | * Pick a period so PWM cycles at 100+ Hz; and a multiplier | ||
82 | * for scaling duty cycle: brightness * mult. | ||
83 | */ | ||
84 | tmp = (led->pwmc.mck / (1 << 5)) / 100; | ||
85 | tmp /= 255; | ||
86 | led->mult = tmp; | ||
87 | pwm_channel_writel(&led->pwmc, PWM_CDTY, | ||
88 | led->cdev.brightness * 255); | ||
89 | pwm_channel_writel(&led->pwmc, PWM_CPRD, | ||
90 | LED_FULL * tmp); | ||
91 | |||
92 | pwm_channel_enable(&led->pwmc); | ||
93 | |||
94 | /* Hand it over to the LED framework */ | ||
95 | status = led_classdev_register(&pdev->dev, &led->cdev); | ||
96 | if (status < 0) { | ||
97 | pwm_channel_free(&led->pwmc); | ||
98 | goto err; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | platform_set_drvdata(pdev, leds); | ||
103 | return 0; | ||
104 | |||
105 | err: | ||
106 | if (i > 0) { | ||
107 | for (i = i - 1; i >= 0; i--) { | ||
108 | led_classdev_unregister(&leds[i].cdev); | ||
109 | pwm_channel_free(&leds[i].pwmc); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | return status; | ||
114 | } | ||
115 | |||
116 | static int pwmled_remove(struct platform_device *pdev) | ||
117 | { | ||
118 | const struct gpio_led_platform_data *pdata; | ||
119 | struct pwmled *leds; | ||
120 | unsigned i; | ||
121 | |||
122 | pdata = dev_get_platdata(&pdev->dev); | ||
123 | leds = platform_get_drvdata(pdev); | ||
124 | |||
125 | for (i = 0; i < pdata->num_leds; i++) { | ||
126 | struct pwmled *led = leds + i; | ||
127 | |||
128 | led_classdev_unregister(&led->cdev); | ||
129 | pwm_channel_free(&led->pwmc); | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static struct platform_driver pwmled_driver = { | ||
136 | .driver = { | ||
137 | .name = "leds-atmel-pwm", | ||
138 | .owner = THIS_MODULE, | ||
139 | }, | ||
140 | /* REVISIT add suspend() and resume() methods */ | ||
141 | .probe = pwmled_probe, | ||
142 | .remove = pwmled_remove, | ||
143 | }; | ||
144 | |||
145 | module_platform_driver(pwmled_driver); | ||
146 | |||
147 | MODULE_DESCRIPTION("Driver for LEDs with PWM-controlled brightness"); | ||
148 | MODULE_LICENSE("GPL"); | ||
149 | MODULE_ALIAS("platform:leds-atmel-pwm"); | ||
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index c8b5c13bcd05..9fd9c6717e0c 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig | |||
@@ -16,26 +16,9 @@ config PL320_MBOX | |||
16 | Management Engine, primarily for cpufreq. Say Y here if you want | 16 | Management Engine, primarily for cpufreq. Say Y here if you want |
17 | to use the PL320 IPCM support. | 17 | to use the PL320 IPCM support. |
18 | 18 | ||
19 | config OMAP_MBOX | ||
20 | tristate | ||
21 | help | ||
22 | This option is selected by any OMAP architecture specific mailbox | ||
23 | driver such as CONFIG_OMAP1_MBOX or CONFIG_OMAP2PLUS_MBOX. This | ||
24 | enables the common OMAP mailbox framework code. | ||
25 | |||
26 | config OMAP1_MBOX | ||
27 | tristate "OMAP1 Mailbox framework support" | ||
28 | depends on ARCH_OMAP1 | ||
29 | select OMAP_MBOX | ||
30 | help | ||
31 | Mailbox implementation for OMAP chips with hardware for | ||
32 | interprocessor communication involving DSP in OMAP1. Say Y here | ||
33 | if you want to use OMAP1 Mailbox framework support. | ||
34 | |||
35 | config OMAP2PLUS_MBOX | 19 | config OMAP2PLUS_MBOX |
36 | tristate "OMAP2+ Mailbox framework support" | 20 | tristate "OMAP2+ Mailbox framework support" |
37 | depends on ARCH_OMAP2PLUS | 21 | depends on ARCH_OMAP2PLUS |
38 | select OMAP_MBOX | ||
39 | help | 22 | help |
40 | Mailbox implementation for OMAP family chips with hardware for | 23 | Mailbox implementation for OMAP family chips with hardware for |
41 | interprocessor communication involving DSP, IVA1.0 and IVA2 in | 24 | interprocessor communication involving DSP, IVA1.0 and IVA2 in |
@@ -44,7 +27,7 @@ config OMAP2PLUS_MBOX | |||
44 | 27 | ||
45 | config OMAP_MBOX_KFIFO_SIZE | 28 | config OMAP_MBOX_KFIFO_SIZE |
46 | int "Mailbox kfifo default buffer size (bytes)" | 29 | int "Mailbox kfifo default buffer size (bytes)" |
47 | depends on OMAP2PLUS_MBOX || OMAP1_MBOX | 30 | depends on OMAP2PLUS_MBOX |
48 | default 256 | 31 | default 256 |
49 | help | 32 | help |
50 | Specify the default size of mailbox's kfifo buffers (bytes). | 33 | Specify the default size of mailbox's kfifo buffers (bytes). |
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index e0facb34084a..6d184dbcaca8 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile | |||
@@ -1,7 +1,3 @@ | |||
1 | obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o | 1 | obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o |
2 | 2 | ||
3 | obj-$(CONFIG_OMAP_MBOX) += omap-mailbox.o | 3 | obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o |
4 | obj-$(CONFIG_OMAP1_MBOX) += mailbox_omap1.o | ||
5 | mailbox_omap1-objs := mailbox-omap1.o | ||
6 | obj-$(CONFIG_OMAP2PLUS_MBOX) += mailbox_omap2.o | ||
7 | mailbox_omap2-objs := mailbox-omap2.o | ||
diff --git a/drivers/mailbox/mailbox-omap1.c b/drivers/mailbox/mailbox-omap1.c deleted file mode 100644 index 9001b7633f10..000000000000 --- a/drivers/mailbox/mailbox-omap1.c +++ /dev/null | |||
@@ -1,203 +0,0 @@ | |||
1 | /* | ||
2 | * Mailbox reservation modules for OMAP1 | ||
3 | * | ||
4 | * Copyright (C) 2006-2009 Nokia Corporation | ||
5 | * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> | ||
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/module.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/io.h> | ||
16 | |||
17 | #include "omap-mbox.h" | ||
18 | |||
19 | #define MAILBOX_ARM2DSP1 0x00 | ||
20 | #define MAILBOX_ARM2DSP1b 0x04 | ||
21 | #define MAILBOX_DSP2ARM1 0x08 | ||
22 | #define MAILBOX_DSP2ARM1b 0x0c | ||
23 | #define MAILBOX_DSP2ARM2 0x10 | ||
24 | #define MAILBOX_DSP2ARM2b 0x14 | ||
25 | #define MAILBOX_ARM2DSP1_Flag 0x18 | ||
26 | #define MAILBOX_DSP2ARM1_Flag 0x1c | ||
27 | #define MAILBOX_DSP2ARM2_Flag 0x20 | ||
28 | |||
29 | static void __iomem *mbox_base; | ||
30 | |||
31 | struct omap_mbox1_fifo { | ||
32 | unsigned long cmd; | ||
33 | unsigned long data; | ||
34 | unsigned long flag; | ||
35 | }; | ||
36 | |||
37 | struct omap_mbox1_priv { | ||
38 | struct omap_mbox1_fifo tx_fifo; | ||
39 | struct omap_mbox1_fifo rx_fifo; | ||
40 | }; | ||
41 | |||
42 | static inline int mbox_read_reg(size_t ofs) | ||
43 | { | ||
44 | return __raw_readw(mbox_base + ofs); | ||
45 | } | ||
46 | |||
47 | static inline void mbox_write_reg(u32 val, size_t ofs) | ||
48 | { | ||
49 | __raw_writew(val, mbox_base + ofs); | ||
50 | } | ||
51 | |||
52 | /* msg */ | ||
53 | static mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox) | ||
54 | { | ||
55 | struct omap_mbox1_fifo *fifo = | ||
56 | &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; | ||
57 | mbox_msg_t msg; | ||
58 | |||
59 | msg = mbox_read_reg(fifo->data); | ||
60 | msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16; | ||
61 | |||
62 | return msg; | ||
63 | } | ||
64 | |||
65 | static void | ||
66 | omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) | ||
67 | { | ||
68 | struct omap_mbox1_fifo *fifo = | ||
69 | &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo; | ||
70 | |||
71 | mbox_write_reg(msg & 0xffff, fifo->data); | ||
72 | mbox_write_reg(msg >> 16, fifo->cmd); | ||
73 | } | ||
74 | |||
75 | static int omap1_mbox_fifo_empty(struct omap_mbox *mbox) | ||
76 | { | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int omap1_mbox_fifo_full(struct omap_mbox *mbox) | ||
81 | { | ||
82 | struct omap_mbox1_fifo *fifo = | ||
83 | &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo; | ||
84 | |||
85 | return mbox_read_reg(fifo->flag); | ||
86 | } | ||
87 | |||
88 | /* irq */ | ||
89 | static void | ||
90 | omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
91 | { | ||
92 | if (irq == IRQ_RX) | ||
93 | enable_irq(mbox->irq); | ||
94 | } | ||
95 | |||
96 | static void | ||
97 | omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
98 | { | ||
99 | if (irq == IRQ_RX) | ||
100 | disable_irq(mbox->irq); | ||
101 | } | ||
102 | |||
103 | static int | ||
104 | omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
105 | { | ||
106 | if (irq == IRQ_TX) | ||
107 | return 0; | ||
108 | return 1; | ||
109 | } | ||
110 | |||
111 | static struct omap_mbox_ops omap1_mbox_ops = { | ||
112 | .type = OMAP_MBOX_TYPE1, | ||
113 | .fifo_read = omap1_mbox_fifo_read, | ||
114 | .fifo_write = omap1_mbox_fifo_write, | ||
115 | .fifo_empty = omap1_mbox_fifo_empty, | ||
116 | .fifo_full = omap1_mbox_fifo_full, | ||
117 | .enable_irq = omap1_mbox_enable_irq, | ||
118 | .disable_irq = omap1_mbox_disable_irq, | ||
119 | .is_irq = omap1_mbox_is_irq, | ||
120 | }; | ||
121 | |||
122 | /* FIXME: the following struct should be created automatically by the user id */ | ||
123 | |||
124 | /* DSP */ | ||
125 | static struct omap_mbox1_priv omap1_mbox_dsp_priv = { | ||
126 | .tx_fifo = { | ||
127 | .cmd = MAILBOX_ARM2DSP1b, | ||
128 | .data = MAILBOX_ARM2DSP1, | ||
129 | .flag = MAILBOX_ARM2DSP1_Flag, | ||
130 | }, | ||
131 | .rx_fifo = { | ||
132 | .cmd = MAILBOX_DSP2ARM1b, | ||
133 | .data = MAILBOX_DSP2ARM1, | ||
134 | .flag = MAILBOX_DSP2ARM1_Flag, | ||
135 | }, | ||
136 | }; | ||
137 | |||
138 | static struct omap_mbox mbox_dsp_info = { | ||
139 | .name = "dsp", | ||
140 | .ops = &omap1_mbox_ops, | ||
141 | .priv = &omap1_mbox_dsp_priv, | ||
142 | }; | ||
143 | |||
144 | static struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL }; | ||
145 | |||
146 | static int omap1_mbox_probe(struct platform_device *pdev) | ||
147 | { | ||
148 | struct resource *mem; | ||
149 | int ret; | ||
150 | struct omap_mbox **list; | ||
151 | |||
152 | list = omap1_mboxes; | ||
153 | list[0]->irq = platform_get_irq_byname(pdev, "dsp"); | ||
154 | |||
155 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
156 | if (!mem) | ||
157 | return -ENOENT; | ||
158 | |||
159 | mbox_base = ioremap(mem->start, resource_size(mem)); | ||
160 | if (!mbox_base) | ||
161 | return -ENOMEM; | ||
162 | |||
163 | ret = omap_mbox_register(&pdev->dev, list); | ||
164 | if (ret) { | ||
165 | iounmap(mbox_base); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int omap1_mbox_remove(struct platform_device *pdev) | ||
173 | { | ||
174 | omap_mbox_unregister(); | ||
175 | iounmap(mbox_base); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static struct platform_driver omap1_mbox_driver = { | ||
180 | .probe = omap1_mbox_probe, | ||
181 | .remove = omap1_mbox_remove, | ||
182 | .driver = { | ||
183 | .name = "omap-mailbox", | ||
184 | }, | ||
185 | }; | ||
186 | |||
187 | static int __init omap1_mbox_init(void) | ||
188 | { | ||
189 | return platform_driver_register(&omap1_mbox_driver); | ||
190 | } | ||
191 | |||
192 | static void __exit omap1_mbox_exit(void) | ||
193 | { | ||
194 | platform_driver_unregister(&omap1_mbox_driver); | ||
195 | } | ||
196 | |||
197 | module_init(omap1_mbox_init); | ||
198 | module_exit(omap1_mbox_exit); | ||
199 | |||
200 | MODULE_LICENSE("GPL v2"); | ||
201 | MODULE_DESCRIPTION("omap mailbox: omap1 architecture specific functions"); | ||
202 | MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>"); | ||
203 | MODULE_ALIAS("platform:omap1-mailbox"); | ||
diff --git a/drivers/mailbox/mailbox-omap2.c b/drivers/mailbox/mailbox-omap2.c deleted file mode 100644 index 42d2b893ea67..000000000000 --- a/drivers/mailbox/mailbox-omap2.c +++ /dev/null | |||
@@ -1,357 +0,0 @@ | |||
1 | /* | ||
2 | * Mailbox reservation modules for OMAP2/3 | ||
3 | * | ||
4 | * Copyright (C) 2006-2009 Nokia Corporation | ||
5 | * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> | ||
6 | * and Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | #include <linux/platform_data/mailbox-omap.h> | ||
21 | |||
22 | #include "omap-mbox.h" | ||
23 | |||
24 | #define MAILBOX_REVISION 0x000 | ||
25 | #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) | ||
26 | #define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) | ||
27 | #define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m)) | ||
28 | #define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u)) | ||
29 | #define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u)) | ||
30 | |||
31 | #define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u)) | ||
32 | #define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u)) | ||
33 | #define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u)) | ||
34 | |||
35 | #define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m))) | ||
36 | #define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1)) | ||
37 | |||
38 | #define MBOX_REG_SIZE 0x120 | ||
39 | |||
40 | #define OMAP4_MBOX_REG_SIZE 0x130 | ||
41 | |||
42 | #define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) | ||
43 | #define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32)) | ||
44 | |||
45 | static void __iomem *mbox_base; | ||
46 | |||
47 | struct omap_mbox2_fifo { | ||
48 | unsigned long msg; | ||
49 | unsigned long fifo_stat; | ||
50 | unsigned long msg_stat; | ||
51 | }; | ||
52 | |||
53 | struct omap_mbox2_priv { | ||
54 | struct omap_mbox2_fifo tx_fifo; | ||
55 | struct omap_mbox2_fifo rx_fifo; | ||
56 | unsigned long irqenable; | ||
57 | unsigned long irqstatus; | ||
58 | u32 newmsg_bit; | ||
59 | u32 notfull_bit; | ||
60 | u32 ctx[OMAP4_MBOX_NR_REGS]; | ||
61 | unsigned long irqdisable; | ||
62 | u32 intr_type; | ||
63 | }; | ||
64 | |||
65 | static inline unsigned int mbox_read_reg(size_t ofs) | ||
66 | { | ||
67 | return __raw_readl(mbox_base + ofs); | ||
68 | } | ||
69 | |||
70 | static inline void mbox_write_reg(u32 val, size_t ofs) | ||
71 | { | ||
72 | __raw_writel(val, mbox_base + ofs); | ||
73 | } | ||
74 | |||
75 | /* Mailbox H/W preparations */ | ||
76 | static int omap2_mbox_startup(struct omap_mbox *mbox) | ||
77 | { | ||
78 | u32 l; | ||
79 | |||
80 | pm_runtime_enable(mbox->dev->parent); | ||
81 | pm_runtime_get_sync(mbox->dev->parent); | ||
82 | |||
83 | l = mbox_read_reg(MAILBOX_REVISION); | ||
84 | pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static void omap2_mbox_shutdown(struct omap_mbox *mbox) | ||
90 | { | ||
91 | pm_runtime_put_sync(mbox->dev->parent); | ||
92 | pm_runtime_disable(mbox->dev->parent); | ||
93 | } | ||
94 | |||
95 | /* Mailbox FIFO handle functions */ | ||
96 | static mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox) | ||
97 | { | ||
98 | struct omap_mbox2_fifo *fifo = | ||
99 | &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; | ||
100 | return (mbox_msg_t) mbox_read_reg(fifo->msg); | ||
101 | } | ||
102 | |||
103 | static void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) | ||
104 | { | ||
105 | struct omap_mbox2_fifo *fifo = | ||
106 | &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; | ||
107 | mbox_write_reg(msg, fifo->msg); | ||
108 | } | ||
109 | |||
110 | static int omap2_mbox_fifo_empty(struct omap_mbox *mbox) | ||
111 | { | ||
112 | struct omap_mbox2_fifo *fifo = | ||
113 | &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo; | ||
114 | return (mbox_read_reg(fifo->msg_stat) == 0); | ||
115 | } | ||
116 | |||
117 | static int omap2_mbox_fifo_full(struct omap_mbox *mbox) | ||
118 | { | ||
119 | struct omap_mbox2_fifo *fifo = | ||
120 | &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo; | ||
121 | return mbox_read_reg(fifo->fifo_stat); | ||
122 | } | ||
123 | |||
124 | /* Mailbox IRQ handle functions */ | ||
125 | static void omap2_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
126 | { | ||
127 | struct omap_mbox2_priv *p = mbox->priv; | ||
128 | u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; | ||
129 | |||
130 | l = mbox_read_reg(p->irqenable); | ||
131 | l |= bit; | ||
132 | mbox_write_reg(l, p->irqenable); | ||
133 | } | ||
134 | |||
135 | static void omap2_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
136 | { | ||
137 | struct omap_mbox2_priv *p = mbox->priv; | ||
138 | u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; | ||
139 | |||
140 | /* | ||
141 | * Read and update the interrupt configuration register for pre-OMAP4. | ||
142 | * OMAP4 and later SoCs have a dedicated interrupt disabling register. | ||
143 | */ | ||
144 | if (!p->intr_type) | ||
145 | bit = mbox_read_reg(p->irqdisable) & ~bit; | ||
146 | |||
147 | mbox_write_reg(bit, p->irqdisable); | ||
148 | } | ||
149 | |||
150 | static void omap2_mbox_ack_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
151 | { | ||
152 | struct omap_mbox2_priv *p = mbox->priv; | ||
153 | u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; | ||
154 | |||
155 | mbox_write_reg(bit, p->irqstatus); | ||
156 | |||
157 | /* Flush posted write for irq status to avoid spurious interrupts */ | ||
158 | mbox_read_reg(p->irqstatus); | ||
159 | } | ||
160 | |||
161 | static int omap2_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
162 | { | ||
163 | struct omap_mbox2_priv *p = mbox->priv; | ||
164 | u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; | ||
165 | u32 enable = mbox_read_reg(p->irqenable); | ||
166 | u32 status = mbox_read_reg(p->irqstatus); | ||
167 | |||
168 | return (int)(enable & status & bit); | ||
169 | } | ||
170 | |||
171 | static void omap2_mbox_save_ctx(struct omap_mbox *mbox) | ||
172 | { | ||
173 | int i; | ||
174 | struct omap_mbox2_priv *p = mbox->priv; | ||
175 | int nr_regs; | ||
176 | |||
177 | if (p->intr_type) | ||
178 | nr_regs = OMAP4_MBOX_NR_REGS; | ||
179 | else | ||
180 | nr_regs = MBOX_NR_REGS; | ||
181 | for (i = 0; i < nr_regs; i++) { | ||
182 | p->ctx[i] = mbox_read_reg(i * sizeof(u32)); | ||
183 | |||
184 | dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, | ||
185 | i, p->ctx[i]); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) | ||
190 | { | ||
191 | int i; | ||
192 | struct omap_mbox2_priv *p = mbox->priv; | ||
193 | int nr_regs; | ||
194 | |||
195 | if (p->intr_type) | ||
196 | nr_regs = OMAP4_MBOX_NR_REGS; | ||
197 | else | ||
198 | nr_regs = MBOX_NR_REGS; | ||
199 | for (i = 0; i < nr_regs; i++) { | ||
200 | mbox_write_reg(p->ctx[i], i * sizeof(u32)); | ||
201 | |||
202 | dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, | ||
203 | i, p->ctx[i]); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | static struct omap_mbox_ops omap2_mbox_ops = { | ||
208 | .type = OMAP_MBOX_TYPE2, | ||
209 | .startup = omap2_mbox_startup, | ||
210 | .shutdown = omap2_mbox_shutdown, | ||
211 | .fifo_read = omap2_mbox_fifo_read, | ||
212 | .fifo_write = omap2_mbox_fifo_write, | ||
213 | .fifo_empty = omap2_mbox_fifo_empty, | ||
214 | .fifo_full = omap2_mbox_fifo_full, | ||
215 | .enable_irq = omap2_mbox_enable_irq, | ||
216 | .disable_irq = omap2_mbox_disable_irq, | ||
217 | .ack_irq = omap2_mbox_ack_irq, | ||
218 | .is_irq = omap2_mbox_is_irq, | ||
219 | .save_ctx = omap2_mbox_save_ctx, | ||
220 | .restore_ctx = omap2_mbox_restore_ctx, | ||
221 | }; | ||
222 | |||
223 | static int omap2_mbox_probe(struct platform_device *pdev) | ||
224 | { | ||
225 | struct resource *mem; | ||
226 | int ret; | ||
227 | struct omap_mbox **list, *mbox, *mboxblk; | ||
228 | struct omap_mbox2_priv *priv, *privblk; | ||
229 | struct omap_mbox_pdata *pdata = pdev->dev.platform_data; | ||
230 | struct omap_mbox_dev_info *info; | ||
231 | int i; | ||
232 | |||
233 | if (!pdata || !pdata->info_cnt || !pdata->info) { | ||
234 | pr_err("%s: platform not supported\n", __func__); | ||
235 | return -ENODEV; | ||
236 | } | ||
237 | |||
238 | /* allocate one extra for marking end of list */ | ||
239 | list = kzalloc((pdata->info_cnt + 1) * sizeof(*list), GFP_KERNEL); | ||
240 | if (!list) | ||
241 | return -ENOMEM; | ||
242 | |||
243 | mboxblk = mbox = kzalloc(pdata->info_cnt * sizeof(*mbox), GFP_KERNEL); | ||
244 | if (!mboxblk) { | ||
245 | ret = -ENOMEM; | ||
246 | goto free_list; | ||
247 | } | ||
248 | |||
249 | privblk = priv = kzalloc(pdata->info_cnt * sizeof(*priv), GFP_KERNEL); | ||
250 | if (!privblk) { | ||
251 | ret = -ENOMEM; | ||
252 | goto free_mboxblk; | ||
253 | } | ||
254 | |||
255 | info = pdata->info; | ||
256 | for (i = 0; i < pdata->info_cnt; i++, info++, priv++) { | ||
257 | priv->tx_fifo.msg = MAILBOX_MESSAGE(info->tx_id); | ||
258 | priv->tx_fifo.fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id); | ||
259 | priv->rx_fifo.msg = MAILBOX_MESSAGE(info->rx_id); | ||
260 | priv->rx_fifo.msg_stat = MAILBOX_MSGSTATUS(info->rx_id); | ||
261 | priv->notfull_bit = MAILBOX_IRQ_NOTFULL(info->tx_id); | ||
262 | priv->newmsg_bit = MAILBOX_IRQ_NEWMSG(info->rx_id); | ||
263 | if (pdata->intr_type) { | ||
264 | priv->irqenable = OMAP4_MAILBOX_IRQENABLE(info->usr_id); | ||
265 | priv->irqstatus = OMAP4_MAILBOX_IRQSTATUS(info->usr_id); | ||
266 | priv->irqdisable = | ||
267 | OMAP4_MAILBOX_IRQENABLE_CLR(info->usr_id); | ||
268 | } else { | ||
269 | priv->irqenable = MAILBOX_IRQENABLE(info->usr_id); | ||
270 | priv->irqstatus = MAILBOX_IRQSTATUS(info->usr_id); | ||
271 | priv->irqdisable = MAILBOX_IRQENABLE(info->usr_id); | ||
272 | } | ||
273 | priv->intr_type = pdata->intr_type; | ||
274 | |||
275 | mbox->priv = priv; | ||
276 | mbox->name = info->name; | ||
277 | mbox->ops = &omap2_mbox_ops; | ||
278 | mbox->irq = platform_get_irq(pdev, info->irq_id); | ||
279 | if (mbox->irq < 0) { | ||
280 | ret = mbox->irq; | ||
281 | goto free_privblk; | ||
282 | } | ||
283 | list[i] = mbox++; | ||
284 | } | ||
285 | |||
286 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
287 | if (!mem) { | ||
288 | ret = -ENOENT; | ||
289 | goto free_privblk; | ||
290 | } | ||
291 | |||
292 | mbox_base = ioremap(mem->start, resource_size(mem)); | ||
293 | if (!mbox_base) { | ||
294 | ret = -ENOMEM; | ||
295 | goto free_privblk; | ||
296 | } | ||
297 | |||
298 | ret = omap_mbox_register(&pdev->dev, list); | ||
299 | if (ret) | ||
300 | goto unmap_mbox; | ||
301 | platform_set_drvdata(pdev, list); | ||
302 | |||
303 | return 0; | ||
304 | |||
305 | unmap_mbox: | ||
306 | iounmap(mbox_base); | ||
307 | free_privblk: | ||
308 | kfree(privblk); | ||
309 | free_mboxblk: | ||
310 | kfree(mboxblk); | ||
311 | free_list: | ||
312 | kfree(list); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | static int omap2_mbox_remove(struct platform_device *pdev) | ||
317 | { | ||
318 | struct omap_mbox2_priv *privblk; | ||
319 | struct omap_mbox **list = platform_get_drvdata(pdev); | ||
320 | struct omap_mbox *mboxblk = list[0]; | ||
321 | |||
322 | privblk = mboxblk->priv; | ||
323 | omap_mbox_unregister(); | ||
324 | iounmap(mbox_base); | ||
325 | kfree(privblk); | ||
326 | kfree(mboxblk); | ||
327 | kfree(list); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static struct platform_driver omap2_mbox_driver = { | ||
333 | .probe = omap2_mbox_probe, | ||
334 | .remove = omap2_mbox_remove, | ||
335 | .driver = { | ||
336 | .name = "omap-mailbox", | ||
337 | }, | ||
338 | }; | ||
339 | |||
340 | static int __init omap2_mbox_init(void) | ||
341 | { | ||
342 | return platform_driver_register(&omap2_mbox_driver); | ||
343 | } | ||
344 | |||
345 | static void __exit omap2_mbox_exit(void) | ||
346 | { | ||
347 | platform_driver_unregister(&omap2_mbox_driver); | ||
348 | } | ||
349 | |||
350 | module_init(omap2_mbox_init); | ||
351 | module_exit(omap2_mbox_exit); | ||
352 | |||
353 | MODULE_LICENSE("GPL v2"); | ||
354 | MODULE_DESCRIPTION("omap mailbox: omap2/3/4 architecture specific functions"); | ||
355 | MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>"); | ||
356 | MODULE_AUTHOR("Paul Mundt"); | ||
357 | MODULE_ALIAS("platform:omap2-mailbox"); | ||
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index d79a646b9042..a27e00e63a8a 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c | |||
@@ -2,8 +2,10 @@ | |||
2 | * OMAP mailbox driver | 2 | * OMAP mailbox driver |
3 | * | 3 | * |
4 | * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. | 4 | * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved. |
5 | * Copyright (C) 2013-2014 Texas Instruments Inc. | ||
5 | * | 6 | * |
6 | * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> | 7 | * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com> |
8 | * Suman Anna <s-anna@ti.com> | ||
7 | * | 9 | * |
8 | * This program is free software; you can redistribute it and/or | 10 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License | 11 | * modify it under the terms of the GNU General Public License |
@@ -24,70 +26,164 @@ | |||
24 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
25 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
26 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
27 | #include <linux/delay.h> | ||
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
29 | #include <linux/kfifo.h> | 30 | #include <linux/kfifo.h> |
30 | #include <linux/err.h> | 31 | #include <linux/err.h> |
31 | #include <linux/notifier.h> | 32 | #include <linux/notifier.h> |
32 | #include <linux/module.h> | 33 | #include <linux/module.h> |
33 | 34 | #include <linux/platform_device.h> | |
34 | #include "omap-mbox.h" | 35 | #include <linux/pm_runtime.h> |
35 | 36 | #include <linux/platform_data/mailbox-omap.h> | |
36 | static struct omap_mbox **mboxes; | 37 | #include <linux/omap-mailbox.h> |
37 | 38 | ||
38 | static int mbox_configured; | 39 | #define MAILBOX_REVISION 0x000 |
39 | static DEFINE_MUTEX(mbox_configured_lock); | 40 | #define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) |
41 | #define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) | ||
42 | #define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m)) | ||
43 | |||
44 | #define OMAP2_MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u)) | ||
45 | #define OMAP2_MAILBOX_IRQENABLE(u) (0x104 + 8 * (u)) | ||
46 | |||
47 | #define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u)) | ||
48 | #define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u)) | ||
49 | #define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u)) | ||
50 | |||
51 | #define MAILBOX_IRQSTATUS(type, u) (type ? OMAP4_MAILBOX_IRQSTATUS(u) : \ | ||
52 | OMAP2_MAILBOX_IRQSTATUS(u)) | ||
53 | #define MAILBOX_IRQENABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE(u) : \ | ||
54 | OMAP2_MAILBOX_IRQENABLE(u)) | ||
55 | #define MAILBOX_IRQDISABLE(type, u) (type ? OMAP4_MAILBOX_IRQENABLE_CLR(u) \ | ||
56 | : OMAP2_MAILBOX_IRQENABLE(u)) | ||
57 | |||
58 | #define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m))) | ||
59 | #define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1)) | ||
60 | |||
61 | #define MBOX_REG_SIZE 0x120 | ||
62 | |||
63 | #define OMAP4_MBOX_REG_SIZE 0x130 | ||
64 | |||
65 | #define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) | ||
66 | #define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32)) | ||
67 | |||
68 | struct omap_mbox_fifo { | ||
69 | unsigned long msg; | ||
70 | unsigned long fifo_stat; | ||
71 | unsigned long msg_stat; | ||
72 | unsigned long irqenable; | ||
73 | unsigned long irqstatus; | ||
74 | unsigned long irqdisable; | ||
75 | u32 intr_bit; | ||
76 | }; | ||
77 | |||
78 | struct omap_mbox_queue { | ||
79 | spinlock_t lock; | ||
80 | struct kfifo fifo; | ||
81 | struct work_struct work; | ||
82 | struct tasklet_struct tasklet; | ||
83 | struct omap_mbox *mbox; | ||
84 | bool full; | ||
85 | }; | ||
86 | |||
87 | struct omap_mbox_device { | ||
88 | struct device *dev; | ||
89 | struct mutex cfg_lock; | ||
90 | void __iomem *mbox_base; | ||
91 | u32 num_users; | ||
92 | u32 num_fifos; | ||
93 | struct omap_mbox **mboxes; | ||
94 | struct list_head elem; | ||
95 | }; | ||
96 | |||
97 | struct omap_mbox { | ||
98 | const char *name; | ||
99 | int irq; | ||
100 | struct omap_mbox_queue *txq, *rxq; | ||
101 | struct device *dev; | ||
102 | struct omap_mbox_device *parent; | ||
103 | struct omap_mbox_fifo tx_fifo; | ||
104 | struct omap_mbox_fifo rx_fifo; | ||
105 | u32 ctx[OMAP4_MBOX_NR_REGS]; | ||
106 | u32 intr_type; | ||
107 | int use_count; | ||
108 | struct blocking_notifier_head notifier; | ||
109 | }; | ||
110 | |||
111 | /* global variables for the mailbox devices */ | ||
112 | static DEFINE_MUTEX(omap_mbox_devices_lock); | ||
113 | static LIST_HEAD(omap_mbox_devices); | ||
40 | 114 | ||
41 | static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; | 115 | static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; |
42 | module_param(mbox_kfifo_size, uint, S_IRUGO); | 116 | module_param(mbox_kfifo_size, uint, S_IRUGO); |
43 | MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); | 117 | MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); |
44 | 118 | ||
119 | static inline | ||
120 | unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs) | ||
121 | { | ||
122 | return __raw_readl(mdev->mbox_base + ofs); | ||
123 | } | ||
124 | |||
125 | static inline | ||
126 | void mbox_write_reg(struct omap_mbox_device *mdev, u32 val, size_t ofs) | ||
127 | { | ||
128 | __raw_writel(val, mdev->mbox_base + ofs); | ||
129 | } | ||
130 | |||
45 | /* Mailbox FIFO handle functions */ | 131 | /* Mailbox FIFO handle functions */ |
46 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) | 132 | static mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) |
47 | { | 133 | { |
48 | return mbox->ops->fifo_read(mbox); | 134 | struct omap_mbox_fifo *fifo = &mbox->rx_fifo; |
135 | return (mbox_msg_t) mbox_read_reg(mbox->parent, fifo->msg); | ||
49 | } | 136 | } |
50 | static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) | 137 | |
138 | static void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) | ||
51 | { | 139 | { |
52 | mbox->ops->fifo_write(mbox, msg); | 140 | struct omap_mbox_fifo *fifo = &mbox->tx_fifo; |
141 | mbox_write_reg(mbox->parent, msg, fifo->msg); | ||
53 | } | 142 | } |
54 | static inline int mbox_fifo_empty(struct omap_mbox *mbox) | 143 | |
144 | static int mbox_fifo_empty(struct omap_mbox *mbox) | ||
55 | { | 145 | { |
56 | return mbox->ops->fifo_empty(mbox); | 146 | struct omap_mbox_fifo *fifo = &mbox->rx_fifo; |
147 | return (mbox_read_reg(mbox->parent, fifo->msg_stat) == 0); | ||
57 | } | 148 | } |
58 | static inline int mbox_fifo_full(struct omap_mbox *mbox) | 149 | |
150 | static int mbox_fifo_full(struct omap_mbox *mbox) | ||
59 | { | 151 | { |
60 | return mbox->ops->fifo_full(mbox); | 152 | struct omap_mbox_fifo *fifo = &mbox->tx_fifo; |
153 | return mbox_read_reg(mbox->parent, fifo->fifo_stat); | ||
61 | } | 154 | } |
62 | 155 | ||
63 | /* Mailbox IRQ handle functions */ | 156 | /* Mailbox IRQ handle functions */ |
64 | static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | 157 | static void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) |
65 | { | 158 | { |
66 | if (mbox->ops->ack_irq) | 159 | struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? |
67 | mbox->ops->ack_irq(mbox, irq); | 160 | &mbox->tx_fifo : &mbox->rx_fifo; |
161 | u32 bit = fifo->intr_bit; | ||
162 | u32 irqstatus = fifo->irqstatus; | ||
163 | |||
164 | mbox_write_reg(mbox->parent, bit, irqstatus); | ||
165 | |||
166 | /* Flush posted write for irq status to avoid spurious interrupts */ | ||
167 | mbox_read_reg(mbox->parent, irqstatus); | ||
68 | } | 168 | } |
69 | static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | 169 | |
170 | static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
70 | { | 171 | { |
71 | return mbox->ops->is_irq(mbox, irq); | 172 | struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? |
173 | &mbox->tx_fifo : &mbox->rx_fifo; | ||
174 | u32 bit = fifo->intr_bit; | ||
175 | u32 irqenable = fifo->irqenable; | ||
176 | u32 irqstatus = fifo->irqstatus; | ||
177 | |||
178 | u32 enable = mbox_read_reg(mbox->parent, irqenable); | ||
179 | u32 status = mbox_read_reg(mbox->parent, irqstatus); | ||
180 | |||
181 | return (int)(enable & status & bit); | ||
72 | } | 182 | } |
73 | 183 | ||
74 | /* | 184 | /* |
75 | * message sender | 185 | * message sender |
76 | */ | 186 | */ |
77 | static int __mbox_poll_for_space(struct omap_mbox *mbox) | ||
78 | { | ||
79 | int ret = 0, i = 1000; | ||
80 | |||
81 | while (mbox_fifo_full(mbox)) { | ||
82 | if (mbox->ops->type == OMAP_MBOX_TYPE2) | ||
83 | return -1; | ||
84 | if (--i == 0) | ||
85 | return -1; | ||
86 | udelay(1); | ||
87 | } | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | 187 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) |
92 | { | 188 | { |
93 | struct omap_mbox_queue *mq = mbox->txq; | 189 | struct omap_mbox_queue *mq = mbox->txq; |
@@ -100,7 +196,7 @@ int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | |||
100 | goto out; | 196 | goto out; |
101 | } | 197 | } |
102 | 198 | ||
103 | if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) { | 199 | if (kfifo_is_empty(&mq->fifo) && !mbox_fifo_full(mbox)) { |
104 | mbox_fifo_write(mbox, msg); | 200 | mbox_fifo_write(mbox, msg); |
105 | goto out; | 201 | goto out; |
106 | } | 202 | } |
@@ -118,35 +214,69 @@ EXPORT_SYMBOL(omap_mbox_msg_send); | |||
118 | 214 | ||
119 | void omap_mbox_save_ctx(struct omap_mbox *mbox) | 215 | void omap_mbox_save_ctx(struct omap_mbox *mbox) |
120 | { | 216 | { |
121 | if (!mbox->ops->save_ctx) { | 217 | int i; |
122 | dev_err(mbox->dev, "%s:\tno save\n", __func__); | 218 | int nr_regs; |
123 | return; | 219 | |
124 | } | 220 | if (mbox->intr_type) |
221 | nr_regs = OMAP4_MBOX_NR_REGS; | ||
222 | else | ||
223 | nr_regs = MBOX_NR_REGS; | ||
224 | for (i = 0; i < nr_regs; i++) { | ||
225 | mbox->ctx[i] = mbox_read_reg(mbox->parent, i * sizeof(u32)); | ||
125 | 226 | ||
126 | mbox->ops->save_ctx(mbox); | 227 | dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, |
228 | i, mbox->ctx[i]); | ||
229 | } | ||
127 | } | 230 | } |
128 | EXPORT_SYMBOL(omap_mbox_save_ctx); | 231 | EXPORT_SYMBOL(omap_mbox_save_ctx); |
129 | 232 | ||
130 | void omap_mbox_restore_ctx(struct omap_mbox *mbox) | 233 | void omap_mbox_restore_ctx(struct omap_mbox *mbox) |
131 | { | 234 | { |
132 | if (!mbox->ops->restore_ctx) { | 235 | int i; |
133 | dev_err(mbox->dev, "%s:\tno restore\n", __func__); | 236 | int nr_regs; |
134 | return; | ||
135 | } | ||
136 | 237 | ||
137 | mbox->ops->restore_ctx(mbox); | 238 | if (mbox->intr_type) |
239 | nr_regs = OMAP4_MBOX_NR_REGS; | ||
240 | else | ||
241 | nr_regs = MBOX_NR_REGS; | ||
242 | for (i = 0; i < nr_regs; i++) { | ||
243 | mbox_write_reg(mbox->parent, mbox->ctx[i], i * sizeof(u32)); | ||
244 | |||
245 | dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, | ||
246 | i, mbox->ctx[i]); | ||
247 | } | ||
138 | } | 248 | } |
139 | EXPORT_SYMBOL(omap_mbox_restore_ctx); | 249 | EXPORT_SYMBOL(omap_mbox_restore_ctx); |
140 | 250 | ||
141 | void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | 251 | void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) |
142 | { | 252 | { |
143 | mbox->ops->enable_irq(mbox, irq); | 253 | u32 l; |
254 | struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? | ||
255 | &mbox->tx_fifo : &mbox->rx_fifo; | ||
256 | u32 bit = fifo->intr_bit; | ||
257 | u32 irqenable = fifo->irqenable; | ||
258 | |||
259 | l = mbox_read_reg(mbox->parent, irqenable); | ||
260 | l |= bit; | ||
261 | mbox_write_reg(mbox->parent, l, irqenable); | ||
144 | } | 262 | } |
145 | EXPORT_SYMBOL(omap_mbox_enable_irq); | 263 | EXPORT_SYMBOL(omap_mbox_enable_irq); |
146 | 264 | ||
147 | void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | 265 | void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) |
148 | { | 266 | { |
149 | mbox->ops->disable_irq(mbox, irq); | 267 | struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ? |
268 | &mbox->tx_fifo : &mbox->rx_fifo; | ||
269 | u32 bit = fifo->intr_bit; | ||
270 | u32 irqdisable = fifo->irqdisable; | ||
271 | |||
272 | /* | ||
273 | * Read and update the interrupt configuration register for pre-OMAP4. | ||
274 | * OMAP4 and later SoCs have a dedicated interrupt disabling register. | ||
275 | */ | ||
276 | if (!mbox->intr_type) | ||
277 | bit = mbox_read_reg(mbox->parent, irqdisable) & ~bit; | ||
278 | |||
279 | mbox_write_reg(mbox->parent, bit, irqdisable); | ||
150 | } | 280 | } |
151 | EXPORT_SYMBOL(omap_mbox_disable_irq); | 281 | EXPORT_SYMBOL(omap_mbox_disable_irq); |
152 | 282 | ||
@@ -158,7 +288,7 @@ static void mbox_tx_tasklet(unsigned long tx_data) | |||
158 | int ret; | 288 | int ret; |
159 | 289 | ||
160 | while (kfifo_len(&mq->fifo)) { | 290 | while (kfifo_len(&mq->fifo)) { |
161 | if (__mbox_poll_for_space(mbox)) { | 291 | if (mbox_fifo_full(mbox)) { |
162 | omap_mbox_enable_irq(mbox, IRQ_TX); | 292 | omap_mbox_enable_irq(mbox, IRQ_TX); |
163 | break; | 293 | break; |
164 | } | 294 | } |
@@ -223,9 +353,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) | |||
223 | 353 | ||
224 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); | 354 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); |
225 | WARN_ON(len != sizeof(msg)); | 355 | WARN_ON(len != sizeof(msg)); |
226 | |||
227 | if (mbox->ops->type == OMAP_MBOX_TYPE1) | ||
228 | break; | ||
229 | } | 356 | } |
230 | 357 | ||
231 | /* no more messages in the fifo. clear IRQ source. */ | 358 | /* no more messages in the fifo. clear IRQ source. */ |
@@ -283,16 +410,12 @@ static int omap_mbox_startup(struct omap_mbox *mbox) | |||
283 | { | 410 | { |
284 | int ret = 0; | 411 | int ret = 0; |
285 | struct omap_mbox_queue *mq; | 412 | struct omap_mbox_queue *mq; |
413 | struct omap_mbox_device *mdev = mbox->parent; | ||
286 | 414 | ||
287 | mutex_lock(&mbox_configured_lock); | 415 | mutex_lock(&mdev->cfg_lock); |
288 | if (!mbox_configured++) { | 416 | ret = pm_runtime_get_sync(mdev->dev); |
289 | if (likely(mbox->ops->startup)) { | 417 | if (unlikely(ret < 0)) |
290 | ret = mbox->ops->startup(mbox); | 418 | goto fail_startup; |
291 | if (unlikely(ret)) | ||
292 | goto fail_startup; | ||
293 | } else | ||
294 | goto fail_startup; | ||
295 | } | ||
296 | 419 | ||
297 | if (!mbox->use_count++) { | 420 | if (!mbox->use_count++) { |
298 | mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); | 421 | mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); |
@@ -319,7 +442,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox) | |||
319 | 442 | ||
320 | omap_mbox_enable_irq(mbox, IRQ_RX); | 443 | omap_mbox_enable_irq(mbox, IRQ_RX); |
321 | } | 444 | } |
322 | mutex_unlock(&mbox_configured_lock); | 445 | mutex_unlock(&mdev->cfg_lock); |
323 | return 0; | 446 | return 0; |
324 | 447 | ||
325 | fail_request_irq: | 448 | fail_request_irq: |
@@ -327,18 +450,18 @@ fail_request_irq: | |||
327 | fail_alloc_rxq: | 450 | fail_alloc_rxq: |
328 | mbox_queue_free(mbox->txq); | 451 | mbox_queue_free(mbox->txq); |
329 | fail_alloc_txq: | 452 | fail_alloc_txq: |
330 | if (mbox->ops->shutdown) | 453 | pm_runtime_put_sync(mdev->dev); |
331 | mbox->ops->shutdown(mbox); | ||
332 | mbox->use_count--; | 454 | mbox->use_count--; |
333 | fail_startup: | 455 | fail_startup: |
334 | mbox_configured--; | 456 | mutex_unlock(&mdev->cfg_lock); |
335 | mutex_unlock(&mbox_configured_lock); | ||
336 | return ret; | 457 | return ret; |
337 | } | 458 | } |
338 | 459 | ||
339 | static void omap_mbox_fini(struct omap_mbox *mbox) | 460 | static void omap_mbox_fini(struct omap_mbox *mbox) |
340 | { | 461 | { |
341 | mutex_lock(&mbox_configured_lock); | 462 | struct omap_mbox_device *mdev = mbox->parent; |
463 | |||
464 | mutex_lock(&mdev->cfg_lock); | ||
342 | 465 | ||
343 | if (!--mbox->use_count) { | 466 | if (!--mbox->use_count) { |
344 | omap_mbox_disable_irq(mbox, IRQ_RX); | 467 | omap_mbox_disable_irq(mbox, IRQ_RX); |
@@ -349,28 +472,43 @@ static void omap_mbox_fini(struct omap_mbox *mbox) | |||
349 | mbox_queue_free(mbox->rxq); | 472 | mbox_queue_free(mbox->rxq); |
350 | } | 473 | } |
351 | 474 | ||
352 | if (likely(mbox->ops->shutdown)) { | 475 | pm_runtime_put_sync(mdev->dev); |
353 | if (!--mbox_configured) | ||
354 | mbox->ops->shutdown(mbox); | ||
355 | } | ||
356 | 476 | ||
357 | mutex_unlock(&mbox_configured_lock); | 477 | mutex_unlock(&mdev->cfg_lock); |
358 | } | 478 | } |
359 | 479 | ||
360 | struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) | 480 | static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev, |
481 | const char *mbox_name) | ||
361 | { | 482 | { |
362 | struct omap_mbox *_mbox, *mbox = NULL; | 483 | struct omap_mbox *_mbox, *mbox = NULL; |
363 | int i, ret; | 484 | struct omap_mbox **mboxes = mdev->mboxes; |
485 | int i; | ||
364 | 486 | ||
365 | if (!mboxes) | 487 | if (!mboxes) |
366 | return ERR_PTR(-EINVAL); | 488 | return NULL; |
367 | 489 | ||
368 | for (i = 0; (_mbox = mboxes[i]); i++) { | 490 | for (i = 0; (_mbox = mboxes[i]); i++) { |
369 | if (!strcmp(_mbox->name, name)) { | 491 | if (!strcmp(_mbox->name, mbox_name)) { |
370 | mbox = _mbox; | 492 | mbox = _mbox; |
371 | break; | 493 | break; |
372 | } | 494 | } |
373 | } | 495 | } |
496 | return mbox; | ||
497 | } | ||
498 | |||
499 | struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) | ||
500 | { | ||
501 | struct omap_mbox *mbox = NULL; | ||
502 | struct omap_mbox_device *mdev; | ||
503 | int ret; | ||
504 | |||
505 | mutex_lock(&omap_mbox_devices_lock); | ||
506 | list_for_each_entry(mdev, &omap_mbox_devices, elem) { | ||
507 | mbox = omap_mbox_device_find(mdev, name); | ||
508 | if (mbox) | ||
509 | break; | ||
510 | } | ||
511 | mutex_unlock(&omap_mbox_devices_lock); | ||
374 | 512 | ||
375 | if (!mbox) | 513 | if (!mbox) |
376 | return ERR_PTR(-ENOENT); | 514 | return ERR_PTR(-ENOENT); |
@@ -397,19 +535,20 @@ EXPORT_SYMBOL(omap_mbox_put); | |||
397 | 535 | ||
398 | static struct class omap_mbox_class = { .name = "mbox", }; | 536 | static struct class omap_mbox_class = { .name = "mbox", }; |
399 | 537 | ||
400 | int omap_mbox_register(struct device *parent, struct omap_mbox **list) | 538 | static int omap_mbox_register(struct omap_mbox_device *mdev) |
401 | { | 539 | { |
402 | int ret; | 540 | int ret; |
403 | int i; | 541 | int i; |
542 | struct omap_mbox **mboxes; | ||
404 | 543 | ||
405 | mboxes = list; | 544 | if (!mdev || !mdev->mboxes) |
406 | if (!mboxes) | ||
407 | return -EINVAL; | 545 | return -EINVAL; |
408 | 546 | ||
547 | mboxes = mdev->mboxes; | ||
409 | for (i = 0; mboxes[i]; i++) { | 548 | for (i = 0; mboxes[i]; i++) { |
410 | struct omap_mbox *mbox = mboxes[i]; | 549 | struct omap_mbox *mbox = mboxes[i]; |
411 | mbox->dev = device_create(&omap_mbox_class, | 550 | mbox->dev = device_create(&omap_mbox_class, |
412 | parent, 0, mbox, "%s", mbox->name); | 551 | mdev->dev, 0, mbox, "%s", mbox->name); |
413 | if (IS_ERR(mbox->dev)) { | 552 | if (IS_ERR(mbox->dev)) { |
414 | ret = PTR_ERR(mbox->dev); | 553 | ret = PTR_ERR(mbox->dev); |
415 | goto err_out; | 554 | goto err_out; |
@@ -417,6 +556,11 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list) | |||
417 | 556 | ||
418 | BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); | 557 | BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); |
419 | } | 558 | } |
559 | |||
560 | mutex_lock(&omap_mbox_devices_lock); | ||
561 | list_add(&mdev->elem, &omap_mbox_devices); | ||
562 | mutex_unlock(&omap_mbox_devices_lock); | ||
563 | |||
420 | return 0; | 564 | return 0; |
421 | 565 | ||
422 | err_out: | 566 | err_out: |
@@ -424,21 +568,148 @@ err_out: | |||
424 | device_unregister(mboxes[i]->dev); | 568 | device_unregister(mboxes[i]->dev); |
425 | return ret; | 569 | return ret; |
426 | } | 570 | } |
427 | EXPORT_SYMBOL(omap_mbox_register); | ||
428 | 571 | ||
429 | int omap_mbox_unregister(void) | 572 | static int omap_mbox_unregister(struct omap_mbox_device *mdev) |
430 | { | 573 | { |
431 | int i; | 574 | int i; |
575 | struct omap_mbox **mboxes; | ||
432 | 576 | ||
433 | if (!mboxes) | 577 | if (!mdev || !mdev->mboxes) |
434 | return -EINVAL; | 578 | return -EINVAL; |
435 | 579 | ||
580 | mutex_lock(&omap_mbox_devices_lock); | ||
581 | list_del(&mdev->elem); | ||
582 | mutex_unlock(&omap_mbox_devices_lock); | ||
583 | |||
584 | mboxes = mdev->mboxes; | ||
436 | for (i = 0; mboxes[i]; i++) | 585 | for (i = 0; mboxes[i]; i++) |
437 | device_unregister(mboxes[i]->dev); | 586 | device_unregister(mboxes[i]->dev); |
438 | mboxes = NULL; | ||
439 | return 0; | 587 | return 0; |
440 | } | 588 | } |
441 | EXPORT_SYMBOL(omap_mbox_unregister); | 589 | |
590 | static int omap_mbox_probe(struct platform_device *pdev) | ||
591 | { | ||
592 | struct resource *mem; | ||
593 | int ret; | ||
594 | struct omap_mbox **list, *mbox, *mboxblk; | ||
595 | struct omap_mbox_pdata *pdata = pdev->dev.platform_data; | ||
596 | struct omap_mbox_dev_info *info; | ||
597 | struct omap_mbox_device *mdev; | ||
598 | struct omap_mbox_fifo *fifo; | ||
599 | u32 intr_type; | ||
600 | u32 l; | ||
601 | int i; | ||
602 | |||
603 | if (!pdata || !pdata->info_cnt || !pdata->info) { | ||
604 | pr_err("%s: platform not supported\n", __func__); | ||
605 | return -ENODEV; | ||
606 | } | ||
607 | |||
608 | mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL); | ||
609 | if (!mdev) | ||
610 | return -ENOMEM; | ||
611 | |||
612 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
613 | mdev->mbox_base = devm_ioremap_resource(&pdev->dev, mem); | ||
614 | if (IS_ERR(mdev->mbox_base)) | ||
615 | return PTR_ERR(mdev->mbox_base); | ||
616 | |||
617 | /* allocate one extra for marking end of list */ | ||
618 | list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list), | ||
619 | GFP_KERNEL); | ||
620 | if (!list) | ||
621 | return -ENOMEM; | ||
622 | |||
623 | mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox), | ||
624 | GFP_KERNEL); | ||
625 | if (!mboxblk) | ||
626 | return -ENOMEM; | ||
627 | |||
628 | info = pdata->info; | ||
629 | intr_type = pdata->intr_type; | ||
630 | mbox = mboxblk; | ||
631 | for (i = 0; i < pdata->info_cnt; i++, info++) { | ||
632 | fifo = &mbox->tx_fifo; | ||
633 | fifo->msg = MAILBOX_MESSAGE(info->tx_id); | ||
634 | fifo->fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id); | ||
635 | fifo->intr_bit = MAILBOX_IRQ_NOTFULL(info->tx_id); | ||
636 | fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id); | ||
637 | fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id); | ||
638 | fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id); | ||
639 | |||
640 | fifo = &mbox->rx_fifo; | ||
641 | fifo->msg = MAILBOX_MESSAGE(info->rx_id); | ||
642 | fifo->msg_stat = MAILBOX_MSGSTATUS(info->rx_id); | ||
643 | fifo->intr_bit = MAILBOX_IRQ_NEWMSG(info->rx_id); | ||
644 | fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id); | ||
645 | fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id); | ||
646 | fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id); | ||
647 | |||
648 | mbox->intr_type = intr_type; | ||
649 | |||
650 | mbox->parent = mdev; | ||
651 | mbox->name = info->name; | ||
652 | mbox->irq = platform_get_irq(pdev, info->irq_id); | ||
653 | if (mbox->irq < 0) | ||
654 | return mbox->irq; | ||
655 | list[i] = mbox++; | ||
656 | } | ||
657 | |||
658 | mutex_init(&mdev->cfg_lock); | ||
659 | mdev->dev = &pdev->dev; | ||
660 | mdev->num_users = pdata->num_users; | ||
661 | mdev->num_fifos = pdata->num_fifos; | ||
662 | mdev->mboxes = list; | ||
663 | ret = omap_mbox_register(mdev); | ||
664 | if (ret) | ||
665 | return ret; | ||
666 | |||
667 | platform_set_drvdata(pdev, mdev); | ||
668 | pm_runtime_enable(mdev->dev); | ||
669 | |||
670 | ret = pm_runtime_get_sync(mdev->dev); | ||
671 | if (ret < 0) { | ||
672 | pm_runtime_put_noidle(mdev->dev); | ||
673 | goto unregister; | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * just print the raw revision register, the format is not | ||
678 | * uniform across all SoCs | ||
679 | */ | ||
680 | l = mbox_read_reg(mdev, MAILBOX_REVISION); | ||
681 | dev_info(mdev->dev, "omap mailbox rev 0x%x\n", l); | ||
682 | |||
683 | ret = pm_runtime_put_sync(mdev->dev); | ||
684 | if (ret < 0) | ||
685 | goto unregister; | ||
686 | |||
687 | return 0; | ||
688 | |||
689 | unregister: | ||
690 | pm_runtime_disable(mdev->dev); | ||
691 | omap_mbox_unregister(mdev); | ||
692 | return ret; | ||
693 | } | ||
694 | |||
695 | static int omap_mbox_remove(struct platform_device *pdev) | ||
696 | { | ||
697 | struct omap_mbox_device *mdev = platform_get_drvdata(pdev); | ||
698 | |||
699 | pm_runtime_disable(mdev->dev); | ||
700 | omap_mbox_unregister(mdev); | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | static struct platform_driver omap_mbox_driver = { | ||
706 | .probe = omap_mbox_probe, | ||
707 | .remove = omap_mbox_remove, | ||
708 | .driver = { | ||
709 | .name = "omap-mailbox", | ||
710 | .owner = THIS_MODULE, | ||
711 | }, | ||
712 | }; | ||
442 | 713 | ||
443 | static int __init omap_mbox_init(void) | 714 | static int __init omap_mbox_init(void) |
444 | { | 715 | { |
@@ -453,12 +724,13 @@ static int __init omap_mbox_init(void) | |||
453 | mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, | 724 | mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, |
454 | sizeof(mbox_msg_t)); | 725 | sizeof(mbox_msg_t)); |
455 | 726 | ||
456 | return 0; | 727 | return platform_driver_register(&omap_mbox_driver); |
457 | } | 728 | } |
458 | subsys_initcall(omap_mbox_init); | 729 | subsys_initcall(omap_mbox_init); |
459 | 730 | ||
460 | static void __exit omap_mbox_exit(void) | 731 | static void __exit omap_mbox_exit(void) |
461 | { | 732 | { |
733 | platform_driver_unregister(&omap_mbox_driver); | ||
462 | class_unregister(&omap_mbox_class); | 734 | class_unregister(&omap_mbox_class); |
463 | } | 735 | } |
464 | module_exit(omap_mbox_exit); | 736 | module_exit(omap_mbox_exit); |
diff --git a/drivers/mailbox/omap-mbox.h b/drivers/mailbox/omap-mbox.h deleted file mode 100644 index 86d7518cd13b..000000000000 --- a/drivers/mailbox/omap-mbox.h +++ /dev/null | |||
@@ -1,67 +0,0 @@ | |||
1 | /* | ||
2 | * omap-mbox.h: OMAP mailbox internal definitions | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef OMAP_MBOX_H | ||
10 | #define OMAP_MBOX_H | ||
11 | |||
12 | #include <linux/device.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/kfifo.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/workqueue.h> | ||
17 | #include <linux/omap-mailbox.h> | ||
18 | |||
19 | typedef int __bitwise omap_mbox_type_t; | ||
20 | #define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1) | ||
21 | #define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2) | ||
22 | |||
23 | struct omap_mbox_ops { | ||
24 | omap_mbox_type_t type; | ||
25 | int (*startup)(struct omap_mbox *mbox); | ||
26 | void (*shutdown)(struct omap_mbox *mbox); | ||
27 | /* fifo */ | ||
28 | mbox_msg_t (*fifo_read)(struct omap_mbox *mbox); | ||
29 | void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg); | ||
30 | int (*fifo_empty)(struct omap_mbox *mbox); | ||
31 | int (*fifo_full)(struct omap_mbox *mbox); | ||
32 | /* irq */ | ||
33 | void (*enable_irq)(struct omap_mbox *mbox, | ||
34 | omap_mbox_irq_t irq); | ||
35 | void (*disable_irq)(struct omap_mbox *mbox, | ||
36 | omap_mbox_irq_t irq); | ||
37 | void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); | ||
38 | int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); | ||
39 | /* ctx */ | ||
40 | void (*save_ctx)(struct omap_mbox *mbox); | ||
41 | void (*restore_ctx)(struct omap_mbox *mbox); | ||
42 | }; | ||
43 | |||
44 | struct omap_mbox_queue { | ||
45 | spinlock_t lock; | ||
46 | struct kfifo fifo; | ||
47 | struct work_struct work; | ||
48 | struct tasklet_struct tasklet; | ||
49 | struct omap_mbox *mbox; | ||
50 | bool full; | ||
51 | }; | ||
52 | |||
53 | struct omap_mbox { | ||
54 | const char *name; | ||
55 | int irq; | ||
56 | struct omap_mbox_queue *txq, *rxq; | ||
57 | struct omap_mbox_ops *ops; | ||
58 | struct device *dev; | ||
59 | void *priv; | ||
60 | int use_count; | ||
61 | struct blocking_notifier_head notifier; | ||
62 | }; | ||
63 | |||
64 | int omap_mbox_register(struct device *parent, struct omap_mbox **); | ||
65 | int omap_mbox_unregister(void); | ||
66 | |||
67 | #endif /* OMAP_MBOX_H */ | ||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ee9402324a23..b841180c7c74 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -51,16 +51,6 @@ config AD525X_DPOT_SPI | |||
51 | To compile this driver as a module, choose M here: the | 51 | To compile this driver as a module, choose M here: the |
52 | module will be called ad525x_dpot-spi. | 52 | module will be called ad525x_dpot-spi. |
53 | 53 | ||
54 | config ATMEL_PWM | ||
55 | tristate "Atmel AT32/AT91 PWM support" | ||
56 | depends on HAVE_CLK | ||
57 | depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 | ||
58 | help | ||
59 | This option enables device driver support for the PWM channels | ||
60 | on certain Atmel processors. Pulse Width Modulation is used for | ||
61 | purposes including software controlled power-efficient backlights | ||
62 | on LCD displays, motor control, and waveform generation. | ||
63 | |||
64 | config ATMEL_TCLIB | 54 | config ATMEL_TCLIB |
65 | bool "Atmel AT32/AT91 Timer/Counter Library" | 55 | bool "Atmel AT32/AT91 Timer/Counter Library" |
66 | depends on (AVR32 || ARCH_AT91) | 56 | depends on (AVR32 || ARCH_AT91) |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d59ce1261b38..5497d026e651 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -7,7 +7,6 @@ obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o | |||
7 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o | 7 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o |
8 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o | 8 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o |
9 | obj-$(CONFIG_INTEL_MID_PTI) += pti.o | 9 | obj-$(CONFIG_INTEL_MID_PTI) += pti.o |
10 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o | ||
11 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o | 10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o |
12 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o | 11 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o |
13 | obj-$(CONFIG_BMP085) += bmp085.o | 12 | obj-$(CONFIG_BMP085) += bmp085.o |
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c deleted file mode 100644 index a6dc56e1bc58..000000000000 --- a/drivers/misc/atmel_pwm.c +++ /dev/null | |||
@@ -1,402 +0,0 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/clk.h> | ||
3 | #include <linux/err.h> | ||
4 | #include <linux/slab.h> | ||
5 | #include <linux/io.h> | ||
6 | #include <linux/interrupt.h> | ||
7 | #include <linux/platform_device.h> | ||
8 | #include <linux/atmel_pwm.h> | ||
9 | |||
10 | |||
11 | /* | ||
12 | * This is a simple driver for the PWM controller found in various newer | ||
13 | * Atmel SOCs, including the AVR32 series and the AT91sam9263. | ||
14 | * | ||
15 | * Chips with current Linux ports have only 4 PWM channels, out of max 32. | ||
16 | * AT32UC3A and AT32UC3B chips have 7 channels (but currently no Linux). | ||
17 | * Docs are inconsistent about the width of the channel counter registers; | ||
18 | * it's at least 16 bits, but several places say 20 bits. | ||
19 | */ | ||
20 | #define PWM_NCHAN 4 /* max 32 */ | ||
21 | |||
22 | struct pwm { | ||
23 | spinlock_t lock; | ||
24 | struct platform_device *pdev; | ||
25 | u32 mask; | ||
26 | int irq; | ||
27 | void __iomem *base; | ||
28 | struct clk *clk; | ||
29 | struct pwm_channel *channel[PWM_NCHAN]; | ||
30 | void (*handler[PWM_NCHAN])(struct pwm_channel *); | ||
31 | }; | ||
32 | |||
33 | |||
34 | /* global PWM controller registers */ | ||
35 | #define PWM_MR 0x00 | ||
36 | #define PWM_ENA 0x04 | ||
37 | #define PWM_DIS 0x08 | ||
38 | #define PWM_SR 0x0c | ||
39 | #define PWM_IER 0x10 | ||
40 | #define PWM_IDR 0x14 | ||
41 | #define PWM_IMR 0x18 | ||
42 | #define PWM_ISR 0x1c | ||
43 | |||
44 | static inline void pwm_writel(const struct pwm *p, unsigned offset, u32 val) | ||
45 | { | ||
46 | __raw_writel(val, p->base + offset); | ||
47 | } | ||
48 | |||
49 | static inline u32 pwm_readl(const struct pwm *p, unsigned offset) | ||
50 | { | ||
51 | return __raw_readl(p->base + offset); | ||
52 | } | ||
53 | |||
54 | static inline void __iomem *pwmc_regs(const struct pwm *p, int index) | ||
55 | { | ||
56 | return p->base + 0x200 + index * 0x20; | ||
57 | } | ||
58 | |||
59 | static struct pwm *pwm; | ||
60 | |||
61 | static void pwm_dumpregs(struct pwm_channel *ch, char *tag) | ||
62 | { | ||
63 | struct device *dev = &pwm->pdev->dev; | ||
64 | |||
65 | dev_dbg(dev, "%s: mr %08x, sr %08x, imr %08x\n", | ||
66 | tag, | ||
67 | pwm_readl(pwm, PWM_MR), | ||
68 | pwm_readl(pwm, PWM_SR), | ||
69 | pwm_readl(pwm, PWM_IMR)); | ||
70 | dev_dbg(dev, | ||
71 | "pwm ch%d - mr %08x, dty %u, prd %u, cnt %u\n", | ||
72 | ch->index, | ||
73 | pwm_channel_readl(ch, PWM_CMR), | ||
74 | pwm_channel_readl(ch, PWM_CDTY), | ||
75 | pwm_channel_readl(ch, PWM_CPRD), | ||
76 | pwm_channel_readl(ch, PWM_CCNT)); | ||
77 | } | ||
78 | |||
79 | |||
80 | /** | ||
81 | * pwm_channel_alloc - allocate an unused PWM channel | ||
82 | * @index: identifies the channel | ||
83 | * @ch: structure to be initialized | ||
84 | * | ||
85 | * Drivers allocate PWM channels according to the board's wiring, and | ||
86 | * matching board-specific setup code. Returns zero or negative errno. | ||
87 | */ | ||
88 | int pwm_channel_alloc(int index, struct pwm_channel *ch) | ||
89 | { | ||
90 | unsigned long flags; | ||
91 | int status = 0; | ||
92 | |||
93 | if (!pwm) | ||
94 | return -EPROBE_DEFER; | ||
95 | |||
96 | if (!(pwm->mask & 1 << index)) | ||
97 | return -ENODEV; | ||
98 | |||
99 | if (index < 0 || index >= PWM_NCHAN || !ch) | ||
100 | return -EINVAL; | ||
101 | memset(ch, 0, sizeof *ch); | ||
102 | |||
103 | spin_lock_irqsave(&pwm->lock, flags); | ||
104 | if (pwm->channel[index]) | ||
105 | status = -EBUSY; | ||
106 | else { | ||
107 | clk_enable(pwm->clk); | ||
108 | |||
109 | ch->regs = pwmc_regs(pwm, index); | ||
110 | ch->index = index; | ||
111 | |||
112 | /* REVISIT: ap7000 seems to go 2x as fast as we expect!! */ | ||
113 | ch->mck = clk_get_rate(pwm->clk); | ||
114 | |||
115 | pwm->channel[index] = ch; | ||
116 | pwm->handler[index] = NULL; | ||
117 | |||
118 | /* channel and irq are always disabled when we return */ | ||
119 | pwm_writel(pwm, PWM_DIS, 1 << index); | ||
120 | pwm_writel(pwm, PWM_IDR, 1 << index); | ||
121 | } | ||
122 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
123 | return status; | ||
124 | } | ||
125 | EXPORT_SYMBOL(pwm_channel_alloc); | ||
126 | |||
127 | static int pwmcheck(struct pwm_channel *ch) | ||
128 | { | ||
129 | int index; | ||
130 | |||
131 | if (!pwm) | ||
132 | return -ENODEV; | ||
133 | if (!ch) | ||
134 | return -EINVAL; | ||
135 | index = ch->index; | ||
136 | if (index < 0 || index >= PWM_NCHAN || pwm->channel[index] != ch) | ||
137 | return -EINVAL; | ||
138 | |||
139 | return index; | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * pwm_channel_free - release a previously allocated channel | ||
144 | * @ch: the channel being released | ||
145 | * | ||
146 | * The channel is completely shut down (counter and IRQ disabled), | ||
147 | * and made available for re-use. Returns zero, or negative errno. | ||
148 | */ | ||
149 | int pwm_channel_free(struct pwm_channel *ch) | ||
150 | { | ||
151 | unsigned long flags; | ||
152 | int t; | ||
153 | |||
154 | spin_lock_irqsave(&pwm->lock, flags); | ||
155 | t = pwmcheck(ch); | ||
156 | if (t >= 0) { | ||
157 | pwm->channel[t] = NULL; | ||
158 | pwm->handler[t] = NULL; | ||
159 | |||
160 | /* channel and irq are always disabled when we return */ | ||
161 | pwm_writel(pwm, PWM_DIS, 1 << t); | ||
162 | pwm_writel(pwm, PWM_IDR, 1 << t); | ||
163 | |||
164 | clk_disable(pwm->clk); | ||
165 | t = 0; | ||
166 | } | ||
167 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
168 | return t; | ||
169 | } | ||
170 | EXPORT_SYMBOL(pwm_channel_free); | ||
171 | |||
172 | int __pwm_channel_onoff(struct pwm_channel *ch, int enabled) | ||
173 | { | ||
174 | unsigned long flags; | ||
175 | int t; | ||
176 | |||
177 | /* OMITTED FUNCTIONALITY: starting several channels in synch */ | ||
178 | |||
179 | spin_lock_irqsave(&pwm->lock, flags); | ||
180 | t = pwmcheck(ch); | ||
181 | if (t >= 0) { | ||
182 | pwm_writel(pwm, enabled ? PWM_ENA : PWM_DIS, 1 << t); | ||
183 | t = 0; | ||
184 | pwm_dumpregs(ch, enabled ? "enable" : "disable"); | ||
185 | } | ||
186 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
187 | |||
188 | return t; | ||
189 | } | ||
190 | EXPORT_SYMBOL(__pwm_channel_onoff); | ||
191 | |||
192 | /** | ||
193 | * pwm_clk_alloc - allocate and configure CLKA or CLKB | ||
194 | * @prescale: from 0..10, the power of two used to divide MCK | ||
195 | * @div: from 1..255, the linear divisor to use | ||
196 | * | ||
197 | * Returns PWM_CPR_CLKA, PWM_CPR_CLKB, or negative errno. The allocated | ||
198 | * clock will run with a period of (2^prescale * div) / MCK, or twice as | ||
199 | * long if center aligned PWM output is used. The clock must later be | ||
200 | * deconfigured using pwm_clk_free(). | ||
201 | */ | ||
202 | int pwm_clk_alloc(unsigned prescale, unsigned div) | ||
203 | { | ||
204 | unsigned long flags; | ||
205 | u32 mr; | ||
206 | u32 val = (prescale << 8) | div; | ||
207 | int ret = -EBUSY; | ||
208 | |||
209 | if (prescale >= 10 || div == 0 || div > 255) | ||
210 | return -EINVAL; | ||
211 | |||
212 | spin_lock_irqsave(&pwm->lock, flags); | ||
213 | mr = pwm_readl(pwm, PWM_MR); | ||
214 | if ((mr & 0xffff) == 0) { | ||
215 | mr |= val; | ||
216 | ret = PWM_CPR_CLKA; | ||
217 | } else if ((mr & (0xffff << 16)) == 0) { | ||
218 | mr |= val << 16; | ||
219 | ret = PWM_CPR_CLKB; | ||
220 | } | ||
221 | if (ret > 0) | ||
222 | pwm_writel(pwm, PWM_MR, mr); | ||
223 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
224 | return ret; | ||
225 | } | ||
226 | EXPORT_SYMBOL(pwm_clk_alloc); | ||
227 | |||
228 | /** | ||
229 | * pwm_clk_free - deconfigure and release CLKA or CLKB | ||
230 | * | ||
231 | * Reverses the effect of pwm_clk_alloc(). | ||
232 | */ | ||
233 | void pwm_clk_free(unsigned clk) | ||
234 | { | ||
235 | unsigned long flags; | ||
236 | u32 mr; | ||
237 | |||
238 | spin_lock_irqsave(&pwm->lock, flags); | ||
239 | mr = pwm_readl(pwm, PWM_MR); | ||
240 | if (clk == PWM_CPR_CLKA) | ||
241 | pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 0)); | ||
242 | if (clk == PWM_CPR_CLKB) | ||
243 | pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 16)); | ||
244 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
245 | } | ||
246 | EXPORT_SYMBOL(pwm_clk_free); | ||
247 | |||
248 | /** | ||
249 | * pwm_channel_handler - manage channel's IRQ handler | ||
250 | * @ch: the channel | ||
251 | * @handler: the handler to use, possibly NULL | ||
252 | * | ||
253 | * If the handler is non-null, the handler will be called after every | ||
254 | * period of this PWM channel. If the handler is null, this channel | ||
255 | * won't generate an IRQ. | ||
256 | */ | ||
257 | int pwm_channel_handler(struct pwm_channel *ch, | ||
258 | void (*handler)(struct pwm_channel *ch)) | ||
259 | { | ||
260 | unsigned long flags; | ||
261 | int t; | ||
262 | |||
263 | spin_lock_irqsave(&pwm->lock, flags); | ||
264 | t = pwmcheck(ch); | ||
265 | if (t >= 0) { | ||
266 | pwm->handler[t] = handler; | ||
267 | pwm_writel(pwm, handler ? PWM_IER : PWM_IDR, 1 << t); | ||
268 | t = 0; | ||
269 | } | ||
270 | spin_unlock_irqrestore(&pwm->lock, flags); | ||
271 | |||
272 | return t; | ||
273 | } | ||
274 | EXPORT_SYMBOL(pwm_channel_handler); | ||
275 | |||
276 | static irqreturn_t pwm_irq(int id, void *_pwm) | ||
277 | { | ||
278 | struct pwm *p = _pwm; | ||
279 | irqreturn_t handled = IRQ_NONE; | ||
280 | u32 irqstat; | ||
281 | int index; | ||
282 | |||
283 | spin_lock(&p->lock); | ||
284 | |||
285 | /* ack irqs, then handle them */ | ||
286 | irqstat = pwm_readl(pwm, PWM_ISR); | ||
287 | |||
288 | while (irqstat) { | ||
289 | struct pwm_channel *ch; | ||
290 | void (*handler)(struct pwm_channel *ch); | ||
291 | |||
292 | index = ffs(irqstat) - 1; | ||
293 | irqstat &= ~(1 << index); | ||
294 | ch = pwm->channel[index]; | ||
295 | handler = pwm->handler[index]; | ||
296 | if (handler && ch) { | ||
297 | spin_unlock(&p->lock); | ||
298 | handler(ch); | ||
299 | spin_lock(&p->lock); | ||
300 | handled = IRQ_HANDLED; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | spin_unlock(&p->lock); | ||
305 | return handled; | ||
306 | } | ||
307 | |||
308 | static int __init pwm_probe(struct platform_device *pdev) | ||
309 | { | ||
310 | struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
311 | int irq = platform_get_irq(pdev, 0); | ||
312 | u32 *mp = pdev->dev.platform_data; | ||
313 | struct pwm *p; | ||
314 | int status = -EIO; | ||
315 | |||
316 | if (pwm) | ||
317 | return -EBUSY; | ||
318 | if (!r || irq < 0 || !mp || !*mp) | ||
319 | return -ENODEV; | ||
320 | if (*mp & ~((1<<PWM_NCHAN)-1)) { | ||
321 | dev_warn(&pdev->dev, "mask 0x%x ... more than %d channels\n", | ||
322 | *mp, PWM_NCHAN); | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | |||
326 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
327 | if (!p) | ||
328 | return -ENOMEM; | ||
329 | |||
330 | spin_lock_init(&p->lock); | ||
331 | p->pdev = pdev; | ||
332 | p->mask = *mp; | ||
333 | p->irq = irq; | ||
334 | p->base = ioremap(r->start, resource_size(r)); | ||
335 | if (!p->base) | ||
336 | goto fail; | ||
337 | p->clk = clk_get(&pdev->dev, "pwm_clk"); | ||
338 | if (IS_ERR(p->clk)) { | ||
339 | status = PTR_ERR(p->clk); | ||
340 | p->clk = NULL; | ||
341 | goto fail; | ||
342 | } | ||
343 | |||
344 | status = request_irq(irq, pwm_irq, 0, pdev->name, p); | ||
345 | if (status < 0) | ||
346 | goto fail; | ||
347 | |||
348 | pwm = p; | ||
349 | platform_set_drvdata(pdev, p); | ||
350 | |||
351 | return 0; | ||
352 | |||
353 | fail: | ||
354 | if (p->clk) | ||
355 | clk_put(p->clk); | ||
356 | if (p->base) | ||
357 | iounmap(p->base); | ||
358 | |||
359 | kfree(p); | ||
360 | return status; | ||
361 | } | ||
362 | |||
363 | static int __exit pwm_remove(struct platform_device *pdev) | ||
364 | { | ||
365 | struct pwm *p = platform_get_drvdata(pdev); | ||
366 | |||
367 | if (p != pwm) | ||
368 | return -EINVAL; | ||
369 | |||
370 | clk_enable(pwm->clk); | ||
371 | pwm_writel(pwm, PWM_DIS, (1 << PWM_NCHAN) - 1); | ||
372 | pwm_writel(pwm, PWM_IDR, (1 << PWM_NCHAN) - 1); | ||
373 | clk_disable(pwm->clk); | ||
374 | |||
375 | pwm = NULL; | ||
376 | |||
377 | free_irq(p->irq, p); | ||
378 | clk_put(p->clk); | ||
379 | iounmap(p->base); | ||
380 | kfree(p); | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static struct platform_driver atmel_pwm_driver = { | ||
386 | .driver = { | ||
387 | .name = "atmel_pwm", | ||
388 | .owner = THIS_MODULE, | ||
389 | }, | ||
390 | .remove = __exit_p(pwm_remove), | ||
391 | |||
392 | /* NOTE: PWM can keep running in AVR32 "idle" and "frozen" states; | ||
393 | * and all AT91sam9263 states, albeit at reduced clock rate if | ||
394 | * MCK becomes the slow clock (i.e. what Linux labels STR). | ||
395 | */ | ||
396 | }; | ||
397 | |||
398 | module_platform_driver_probe(atmel_pwm_driver, pwm_probe); | ||
399 | |||
400 | MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module"); | ||
401 | MODULE_LICENSE("GPL"); | ||
402 | MODULE_ALIAS("platform:atmel_pwm"); | ||
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 21df477be0c8..2d8a4d05d78f 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig | |||
@@ -46,4 +46,12 @@ config PCI_HOST_GENERIC | |||
46 | Say Y here if you want to support a simple generic PCI host | 46 | Say Y here if you want to support a simple generic PCI host |
47 | controller, such as the one emulated by kvmtool. | 47 | controller, such as the one emulated by kvmtool. |
48 | 48 | ||
49 | config PCIE_SPEAR13XX | ||
50 | tristate "STMicroelectronics SPEAr PCIe controller" | ||
51 | depends on ARCH_SPEAR13XX | ||
52 | select PCIEPORTBUS | ||
53 | select PCIE_DW | ||
54 | help | ||
55 | Say Y here if you want PCIe support on SPEAr13XX SoCs. | ||
56 | |||
49 | endmenu | 57 | endmenu |
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 611ba4b48c94..0daec7941aba 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile | |||
@@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o | |||
6 | obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o | 6 | obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o |
7 | obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o | 7 | obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o |
8 | obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o | 8 | obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o |
9 | obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o | ||
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 60a7299e9632..abd65784618d 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -234,7 +234,6 @@ struct tegra_pcie_soc_data { | |||
234 | bool has_pex_clkreq_en; | 234 | bool has_pex_clkreq_en; |
235 | bool has_pex_bias_ctrl; | 235 | bool has_pex_bias_ctrl; |
236 | bool has_intr_prsnt_sense; | 236 | bool has_intr_prsnt_sense; |
237 | bool has_avdd_supply; | ||
238 | bool has_cml_clk; | 237 | bool has_cml_clk; |
239 | }; | 238 | }; |
240 | 239 | ||
@@ -273,9 +272,8 @@ struct tegra_pcie { | |||
273 | unsigned int num_ports; | 272 | unsigned int num_ports; |
274 | u32 xbar_config; | 273 | u32 xbar_config; |
275 | 274 | ||
276 | struct regulator *pex_clk_supply; | 275 | struct regulator_bulk_data *supplies; |
277 | struct regulator *vdd_supply; | 276 | unsigned int num_supplies; |
278 | struct regulator *avdd_supply; | ||
279 | 277 | ||
280 | const struct tegra_pcie_soc_data *soc_data; | 278 | const struct tegra_pcie_soc_data *soc_data; |
281 | }; | 279 | }; |
@@ -895,7 +893,6 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) | |||
895 | 893 | ||
896 | static void tegra_pcie_power_off(struct tegra_pcie *pcie) | 894 | static void tegra_pcie_power_off(struct tegra_pcie *pcie) |
897 | { | 895 | { |
898 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | ||
899 | int err; | 896 | int err; |
900 | 897 | ||
901 | /* TODO: disable and unprepare clocks? */ | 898 | /* TODO: disable and unprepare clocks? */ |
@@ -906,23 +903,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) | |||
906 | 903 | ||
907 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); | 904 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); |
908 | 905 | ||
909 | if (soc->has_avdd_supply) { | 906 | err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); |
910 | err = regulator_disable(pcie->avdd_supply); | ||
911 | if (err < 0) | ||
912 | dev_warn(pcie->dev, | ||
913 | "failed to disable AVDD regulator: %d\n", | ||
914 | err); | ||
915 | } | ||
916 | |||
917 | err = regulator_disable(pcie->pex_clk_supply); | ||
918 | if (err < 0) | 907 | if (err < 0) |
919 | dev_warn(pcie->dev, "failed to disable pex-clk regulator: %d\n", | 908 | dev_warn(pcie->dev, "failed to disable regulators: %d\n", err); |
920 | err); | ||
921 | |||
922 | err = regulator_disable(pcie->vdd_supply); | ||
923 | if (err < 0) | ||
924 | dev_warn(pcie->dev, "failed to disable VDD regulator: %d\n", | ||
925 | err); | ||
926 | } | 909 | } |
927 | 910 | ||
928 | static int tegra_pcie_power_on(struct tegra_pcie *pcie) | 911 | static int tegra_pcie_power_on(struct tegra_pcie *pcie) |
@@ -937,28 +920,9 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) | |||
937 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); | 920 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); |
938 | 921 | ||
939 | /* enable regulators */ | 922 | /* enable regulators */ |
940 | err = regulator_enable(pcie->vdd_supply); | 923 | err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); |
941 | if (err < 0) { | 924 | if (err < 0) |
942 | dev_err(pcie->dev, "failed to enable VDD regulator: %d\n", err); | 925 | dev_err(pcie->dev, "failed to enable regulators: %d\n", err); |
943 | return err; | ||
944 | } | ||
945 | |||
946 | err = regulator_enable(pcie->pex_clk_supply); | ||
947 | if (err < 0) { | ||
948 | dev_err(pcie->dev, "failed to enable pex-clk regulator: %d\n", | ||
949 | err); | ||
950 | return err; | ||
951 | } | ||
952 | |||
953 | if (soc->has_avdd_supply) { | ||
954 | err = regulator_enable(pcie->avdd_supply); | ||
955 | if (err < 0) { | ||
956 | dev_err(pcie->dev, | ||
957 | "failed to enable AVDD regulator: %d\n", | ||
958 | err); | ||
959 | return err; | ||
960 | } | ||
961 | } | ||
962 | 926 | ||
963 | err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, | 927 | err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, |
964 | pcie->pex_clk, | 928 | pcie->pex_clk, |
@@ -1395,14 +1359,157 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, | |||
1395 | return -EINVAL; | 1359 | return -EINVAL; |
1396 | } | 1360 | } |
1397 | 1361 | ||
1362 | /* | ||
1363 | * Check whether a given set of supplies is available in a device tree node. | ||
1364 | * This is used to check whether the new or the legacy device tree bindings | ||
1365 | * should be used. | ||
1366 | */ | ||
1367 | static bool of_regulator_bulk_available(struct device_node *np, | ||
1368 | struct regulator_bulk_data *supplies, | ||
1369 | unsigned int num_supplies) | ||
1370 | { | ||
1371 | char property[32]; | ||
1372 | unsigned int i; | ||
1373 | |||
1374 | for (i = 0; i < num_supplies; i++) { | ||
1375 | snprintf(property, 32, "%s-supply", supplies[i].supply); | ||
1376 | |||
1377 | if (of_find_property(np, property, NULL) == NULL) | ||
1378 | return false; | ||
1379 | } | ||
1380 | |||
1381 | return true; | ||
1382 | } | ||
1383 | |||
1384 | /* | ||
1385 | * Old versions of the device tree binding for this device used a set of power | ||
1386 | * supplies that didn't match the hardware inputs. This happened to work for a | ||
1387 | * number of cases but is not future proof. However to preserve backwards- | ||
1388 | * compatibility with old device trees, this function will try to use the old | ||
1389 | * set of supplies. | ||
1390 | */ | ||
1391 | static int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie) | ||
1392 | { | ||
1393 | struct device_node *np = pcie->dev->of_node; | ||
1394 | |||
1395 | if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) | ||
1396 | pcie->num_supplies = 3; | ||
1397 | else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) | ||
1398 | pcie->num_supplies = 2; | ||
1399 | |||
1400 | if (pcie->num_supplies == 0) { | ||
1401 | dev_err(pcie->dev, "device %s not supported in legacy mode\n", | ||
1402 | np->full_name); | ||
1403 | return -ENODEV; | ||
1404 | } | ||
1405 | |||
1406 | pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, | ||
1407 | sizeof(*pcie->supplies), | ||
1408 | GFP_KERNEL); | ||
1409 | if (!pcie->supplies) | ||
1410 | return -ENOMEM; | ||
1411 | |||
1412 | pcie->supplies[0].supply = "pex-clk"; | ||
1413 | pcie->supplies[1].supply = "vdd"; | ||
1414 | |||
1415 | if (pcie->num_supplies > 2) | ||
1416 | pcie->supplies[2].supply = "avdd"; | ||
1417 | |||
1418 | return devm_regulator_bulk_get(pcie->dev, pcie->num_supplies, | ||
1419 | pcie->supplies); | ||
1420 | } | ||
1421 | |||
1422 | /* | ||
1423 | * Obtains the list of regulators required for a particular generation of the | ||
1424 | * IP block. | ||
1425 | * | ||
1426 | * This would've been nice to do simply by providing static tables for use | ||
1427 | * with the regulator_bulk_*() API, but unfortunately Tegra30 is a bit quirky | ||
1428 | * in that it has two pairs or AVDD_PEX and VDD_PEX supplies (PEXA and PEXB) | ||
1429 | * and either seems to be optional depending on which ports are being used. | ||
1430 | */ | ||
1431 | static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) | ||
1432 | { | ||
1433 | struct device_node *np = pcie->dev->of_node; | ||
1434 | unsigned int i = 0; | ||
1435 | |||
1436 | if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { | ||
1437 | bool need_pexa = false, need_pexb = false; | ||
1438 | |||
1439 | /* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */ | ||
1440 | if (lane_mask & 0x0f) | ||
1441 | need_pexa = true; | ||
1442 | |||
1443 | /* VDD_PEXB and AVDD_PEXB supply lanes 4 to 5 */ | ||
1444 | if (lane_mask & 0x30) | ||
1445 | need_pexb = true; | ||
1446 | |||
1447 | pcie->num_supplies = 4 + (need_pexa ? 2 : 0) + | ||
1448 | (need_pexb ? 2 : 0); | ||
1449 | |||
1450 | pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, | ||
1451 | sizeof(*pcie->supplies), | ||
1452 | GFP_KERNEL); | ||
1453 | if (!pcie->supplies) | ||
1454 | return -ENOMEM; | ||
1455 | |||
1456 | pcie->supplies[i++].supply = "avdd-pex-pll"; | ||
1457 | pcie->supplies[i++].supply = "hvdd-pex"; | ||
1458 | pcie->supplies[i++].supply = "vddio-pex-ctl"; | ||
1459 | pcie->supplies[i++].supply = "avdd-plle"; | ||
1460 | |||
1461 | if (need_pexa) { | ||
1462 | pcie->supplies[i++].supply = "avdd-pexa"; | ||
1463 | pcie->supplies[i++].supply = "vdd-pexa"; | ||
1464 | } | ||
1465 | |||
1466 | if (need_pexb) { | ||
1467 | pcie->supplies[i++].supply = "avdd-pexb"; | ||
1468 | pcie->supplies[i++].supply = "vdd-pexb"; | ||
1469 | } | ||
1470 | } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { | ||
1471 | pcie->num_supplies = 5; | ||
1472 | |||
1473 | pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, | ||
1474 | sizeof(*pcie->supplies), | ||
1475 | GFP_KERNEL); | ||
1476 | if (!pcie->supplies) | ||
1477 | return -ENOMEM; | ||
1478 | |||
1479 | pcie->supplies[0].supply = "avdd-pex"; | ||
1480 | pcie->supplies[1].supply = "vdd-pex"; | ||
1481 | pcie->supplies[2].supply = "avdd-pex-pll"; | ||
1482 | pcie->supplies[3].supply = "avdd-plle"; | ||
1483 | pcie->supplies[4].supply = "vddio-pex-clk"; | ||
1484 | } | ||
1485 | |||
1486 | if (of_regulator_bulk_available(pcie->dev->of_node, pcie->supplies, | ||
1487 | pcie->num_supplies)) | ||
1488 | return devm_regulator_bulk_get(pcie->dev, pcie->num_supplies, | ||
1489 | pcie->supplies); | ||
1490 | |||
1491 | /* | ||
1492 | * If not all regulators are available for this new scheme, assume | ||
1493 | * that the device tree complies with an older version of the device | ||
1494 | * tree binding. | ||
1495 | */ | ||
1496 | dev_info(pcie->dev, "using legacy DT binding for power supplies\n"); | ||
1497 | |||
1498 | devm_kfree(pcie->dev, pcie->supplies); | ||
1499 | pcie->num_supplies = 0; | ||
1500 | |||
1501 | return tegra_pcie_get_legacy_regulators(pcie); | ||
1502 | } | ||
1503 | |||
1398 | static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | 1504 | static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) |
1399 | { | 1505 | { |
1400 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | 1506 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; |
1401 | struct device_node *np = pcie->dev->of_node, *port; | 1507 | struct device_node *np = pcie->dev->of_node, *port; |
1402 | struct of_pci_range_parser parser; | 1508 | struct of_pci_range_parser parser; |
1403 | struct of_pci_range range; | 1509 | struct of_pci_range range; |
1510 | u32 lanes = 0, mask = 0; | ||
1511 | unsigned int lane = 0; | ||
1404 | struct resource res; | 1512 | struct resource res; |
1405 | u32 lanes = 0; | ||
1406 | int err; | 1513 | int err; |
1407 | 1514 | ||
1408 | if (of_pci_range_parser_init(&parser, np)) { | 1515 | if (of_pci_range_parser_init(&parser, np)) { |
@@ -1410,20 +1517,6 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | |||
1410 | return -EINVAL; | 1517 | return -EINVAL; |
1411 | } | 1518 | } |
1412 | 1519 | ||
1413 | pcie->vdd_supply = devm_regulator_get(pcie->dev, "vdd"); | ||
1414 | if (IS_ERR(pcie->vdd_supply)) | ||
1415 | return PTR_ERR(pcie->vdd_supply); | ||
1416 | |||
1417 | pcie->pex_clk_supply = devm_regulator_get(pcie->dev, "pex-clk"); | ||
1418 | if (IS_ERR(pcie->pex_clk_supply)) | ||
1419 | return PTR_ERR(pcie->pex_clk_supply); | ||
1420 | |||
1421 | if (soc->has_avdd_supply) { | ||
1422 | pcie->avdd_supply = devm_regulator_get(pcie->dev, "avdd"); | ||
1423 | if (IS_ERR(pcie->avdd_supply)) | ||
1424 | return PTR_ERR(pcie->avdd_supply); | ||
1425 | } | ||
1426 | |||
1427 | for_each_of_pci_range(&parser, &range) { | 1520 | for_each_of_pci_range(&parser, &range) { |
1428 | of_pci_range_to_resource(&range, np, &res); | 1521 | of_pci_range_to_resource(&range, np, &res); |
1429 | 1522 | ||
@@ -1491,8 +1584,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | |||
1491 | 1584 | ||
1492 | lanes |= value << (index << 3); | 1585 | lanes |= value << (index << 3); |
1493 | 1586 | ||
1494 | if (!of_device_is_available(port)) | 1587 | if (!of_device_is_available(port)) { |
1588 | lane += value; | ||
1495 | continue; | 1589 | continue; |
1590 | } | ||
1591 | |||
1592 | mask |= ((1 << value) - 1) << lane; | ||
1593 | lane += value; | ||
1496 | 1594 | ||
1497 | rp = devm_kzalloc(pcie->dev, sizeof(*rp), GFP_KERNEL); | 1595 | rp = devm_kzalloc(pcie->dev, sizeof(*rp), GFP_KERNEL); |
1498 | if (!rp) | 1596 | if (!rp) |
@@ -1523,6 +1621,10 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | |||
1523 | return err; | 1621 | return err; |
1524 | } | 1622 | } |
1525 | 1623 | ||
1624 | err = tegra_pcie_get_regulators(pcie, mask); | ||
1625 | if (err < 0) | ||
1626 | return err; | ||
1627 | |||
1526 | return 0; | 1628 | return 0; |
1527 | } | 1629 | } |
1528 | 1630 | ||
@@ -1616,7 +1718,6 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = { | |||
1616 | .has_pex_clkreq_en = false, | 1718 | .has_pex_clkreq_en = false, |
1617 | .has_pex_bias_ctrl = false, | 1719 | .has_pex_bias_ctrl = false, |
1618 | .has_intr_prsnt_sense = false, | 1720 | .has_intr_prsnt_sense = false, |
1619 | .has_avdd_supply = false, | ||
1620 | .has_cml_clk = false, | 1721 | .has_cml_clk = false, |
1621 | }; | 1722 | }; |
1622 | 1723 | ||
@@ -1628,7 +1729,6 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = { | |||
1628 | .has_pex_clkreq_en = true, | 1729 | .has_pex_clkreq_en = true, |
1629 | .has_pex_bias_ctrl = true, | 1730 | .has_pex_bias_ctrl = true, |
1630 | .has_intr_prsnt_sense = true, | 1731 | .has_intr_prsnt_sense = true, |
1631 | .has_avdd_supply = true, | ||
1632 | .has_cml_clk = true, | 1732 | .has_cml_clk = true, |
1633 | }; | 1733 | }; |
1634 | 1734 | ||
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c new file mode 100644 index 000000000000..6dea9e43a75c --- /dev/null +++ b/drivers/pci/host/pcie-spear13xx.c | |||
@@ -0,0 +1,393 @@ | |||
1 | /* | ||
2 | * PCIe host controller driver for ST Microelectronics SPEAr13xx SoCs | ||
3 | * | ||
4 | * SPEAr13xx PCIe Glue Layer Source Code | ||
5 | * | ||
6 | * Copyright (C) 2010-2014 ST Microelectronics | ||
7 | * Pratyush Anand <pratyush.anand@st.com> | ||
8 | * Mohit Kumar <mohit.kumar@st.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public | ||
11 | * License version 2. This program is licensed "as is" without any | ||
12 | * warranty of any kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/phy/phy.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/resource.h> | ||
25 | |||
26 | #include "pcie-designware.h" | ||
27 | |||
28 | struct spear13xx_pcie { | ||
29 | void __iomem *app_base; | ||
30 | struct phy *phy; | ||
31 | struct clk *clk; | ||
32 | struct pcie_port pp; | ||
33 | bool is_gen1; | ||
34 | }; | ||
35 | |||
36 | struct pcie_app_reg { | ||
37 | u32 app_ctrl_0; /* cr0 */ | ||
38 | u32 app_ctrl_1; /* cr1 */ | ||
39 | u32 app_status_0; /* cr2 */ | ||
40 | u32 app_status_1; /* cr3 */ | ||
41 | u32 msg_status; /* cr4 */ | ||
42 | u32 msg_payload; /* cr5 */ | ||
43 | u32 int_sts; /* cr6 */ | ||
44 | u32 int_clr; /* cr7 */ | ||
45 | u32 int_mask; /* cr8 */ | ||
46 | u32 mst_bmisc; /* cr9 */ | ||
47 | u32 phy_ctrl; /* cr10 */ | ||
48 | u32 phy_status; /* cr11 */ | ||
49 | u32 cxpl_debug_info_0; /* cr12 */ | ||
50 | u32 cxpl_debug_info_1; /* cr13 */ | ||
51 | u32 ven_msg_ctrl_0; /* cr14 */ | ||
52 | u32 ven_msg_ctrl_1; /* cr15 */ | ||
53 | u32 ven_msg_data_0; /* cr16 */ | ||
54 | u32 ven_msg_data_1; /* cr17 */ | ||
55 | u32 ven_msi_0; /* cr18 */ | ||
56 | u32 ven_msi_1; /* cr19 */ | ||
57 | u32 mst_rmisc; /* cr20 */ | ||
58 | }; | ||
59 | |||
60 | /* CR0 ID */ | ||
61 | #define RX_LANE_FLIP_EN_ID 0 | ||
62 | #define TX_LANE_FLIP_EN_ID 1 | ||
63 | #define SYS_AUX_PWR_DET_ID 2 | ||
64 | #define APP_LTSSM_ENABLE_ID 3 | ||
65 | #define SYS_ATTEN_BUTTON_PRESSED_ID 4 | ||
66 | #define SYS_MRL_SENSOR_STATE_ID 5 | ||
67 | #define SYS_PWR_FAULT_DET_ID 6 | ||
68 | #define SYS_MRL_SENSOR_CHGED_ID 7 | ||
69 | #define SYS_PRE_DET_CHGED_ID 8 | ||
70 | #define SYS_CMD_CPLED_INT_ID 9 | ||
71 | #define APP_INIT_RST_0_ID 11 | ||
72 | #define APP_REQ_ENTR_L1_ID 12 | ||
73 | #define APP_READY_ENTR_L23_ID 13 | ||
74 | #define APP_REQ_EXIT_L1_ID 14 | ||
75 | #define DEVICE_TYPE_EP (0 << 25) | ||
76 | #define DEVICE_TYPE_LEP (1 << 25) | ||
77 | #define DEVICE_TYPE_RC (4 << 25) | ||
78 | #define SYS_INT_ID 29 | ||
79 | #define MISCTRL_EN_ID 30 | ||
80 | #define REG_TRANSLATION_ENABLE 31 | ||
81 | |||
82 | /* CR1 ID */ | ||
83 | #define APPS_PM_XMT_TURNOFF_ID 2 | ||
84 | #define APPS_PM_XMT_PME_ID 5 | ||
85 | |||
86 | /* CR3 ID */ | ||
87 | #define XMLH_LTSSM_STATE_DETECT_QUIET 0x00 | ||
88 | #define XMLH_LTSSM_STATE_DETECT_ACT 0x01 | ||
89 | #define XMLH_LTSSM_STATE_POLL_ACTIVE 0x02 | ||
90 | #define XMLH_LTSSM_STATE_POLL_COMPLIANCE 0x03 | ||
91 | #define XMLH_LTSSM_STATE_POLL_CONFIG 0x04 | ||
92 | #define XMLH_LTSSM_STATE_PRE_DETECT_QUIET 0x05 | ||
93 | #define XMLH_LTSSM_STATE_DETECT_WAIT 0x06 | ||
94 | #define XMLH_LTSSM_STATE_CFG_LINKWD_START 0x07 | ||
95 | #define XMLH_LTSSM_STATE_CFG_LINKWD_ACEPT 0x08 | ||
96 | #define XMLH_LTSSM_STATE_CFG_LANENUM_WAIT 0x09 | ||
97 | #define XMLH_LTSSM_STATE_CFG_LANENUM_ACEPT 0x0A | ||
98 | #define XMLH_LTSSM_STATE_CFG_COMPLETE 0x0B | ||
99 | #define XMLH_LTSSM_STATE_CFG_IDLE 0x0C | ||
100 | #define XMLH_LTSSM_STATE_RCVRY_LOCK 0x0D | ||
101 | #define XMLH_LTSSM_STATE_RCVRY_SPEED 0x0E | ||
102 | #define XMLH_LTSSM_STATE_RCVRY_RCVRCFG 0x0F | ||
103 | #define XMLH_LTSSM_STATE_RCVRY_IDLE 0x10 | ||
104 | #define XMLH_LTSSM_STATE_L0 0x11 | ||
105 | #define XMLH_LTSSM_STATE_L0S 0x12 | ||
106 | #define XMLH_LTSSM_STATE_L123_SEND_EIDLE 0x13 | ||
107 | #define XMLH_LTSSM_STATE_L1_IDLE 0x14 | ||
108 | #define XMLH_LTSSM_STATE_L2_IDLE 0x15 | ||
109 | #define XMLH_LTSSM_STATE_L2_WAKE 0x16 | ||
110 | #define XMLH_LTSSM_STATE_DISABLED_ENTRY 0x17 | ||
111 | #define XMLH_LTSSM_STATE_DISABLED_IDLE 0x18 | ||
112 | #define XMLH_LTSSM_STATE_DISABLED 0x19 | ||
113 | #define XMLH_LTSSM_STATE_LPBK_ENTRY 0x1A | ||
114 | #define XMLH_LTSSM_STATE_LPBK_ACTIVE 0x1B | ||
115 | #define XMLH_LTSSM_STATE_LPBK_EXIT 0x1C | ||
116 | #define XMLH_LTSSM_STATE_LPBK_EXIT_TIMEOUT 0x1D | ||
117 | #define XMLH_LTSSM_STATE_HOT_RESET_ENTRY 0x1E | ||
118 | #define XMLH_LTSSM_STATE_HOT_RESET 0x1F | ||
119 | #define XMLH_LTSSM_STATE_MASK 0x3F | ||
120 | #define XMLH_LINK_UP (1 << 6) | ||
121 | |||
122 | /* CR4 ID */ | ||
123 | #define CFG_MSI_EN_ID 18 | ||
124 | |||
125 | /* CR6 */ | ||
126 | #define INTA_CTRL_INT (1 << 7) | ||
127 | #define INTB_CTRL_INT (1 << 8) | ||
128 | #define INTC_CTRL_INT (1 << 9) | ||
129 | #define INTD_CTRL_INT (1 << 10) | ||
130 | #define MSI_CTRL_INT (1 << 26) | ||
131 | |||
132 | /* CR19 ID */ | ||
133 | #define VEN_MSI_REQ_ID 11 | ||
134 | #define VEN_MSI_FUN_NUM_ID 8 | ||
135 | #define VEN_MSI_TC_ID 5 | ||
136 | #define VEN_MSI_VECTOR_ID 0 | ||
137 | #define VEN_MSI_REQ_EN ((u32)0x1 << VEN_MSI_REQ_ID) | ||
138 | #define VEN_MSI_FUN_NUM_MASK ((u32)0x7 << VEN_MSI_FUN_NUM_ID) | ||
139 | #define VEN_MSI_TC_MASK ((u32)0x7 << VEN_MSI_TC_ID) | ||
140 | #define VEN_MSI_VECTOR_MASK ((u32)0x1F << VEN_MSI_VECTOR_ID) | ||
141 | |||
142 | #define EXP_CAP_ID_OFFSET 0x70 | ||
143 | |||
144 | #define to_spear13xx_pcie(x) container_of(x, struct spear13xx_pcie, pp) | ||
145 | |||
146 | static int spear13xx_pcie_establish_link(struct pcie_port *pp) | ||
147 | { | ||
148 | u32 val; | ||
149 | int count = 0; | ||
150 | struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); | ||
151 | struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; | ||
152 | u32 exp_cap_off = EXP_CAP_ID_OFFSET; | ||
153 | |||
154 | if (dw_pcie_link_up(pp)) { | ||
155 | dev_err(pp->dev, "link already up\n"); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | dw_pcie_setup_rc(pp); | ||
160 | |||
161 | /* | ||
162 | * this controller support only 128 bytes read size, however its | ||
163 | * default value in capability register is 512 bytes. So force | ||
164 | * it to 128 here. | ||
165 | */ | ||
166 | dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, &val); | ||
167 | val &= ~PCI_EXP_DEVCTL_READRQ; | ||
168 | dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + PCI_EXP_DEVCTL, 4, val); | ||
169 | |||
170 | dw_pcie_cfg_write(pp->dbi_base, PCI_VENDOR_ID, 2, 0x104A); | ||
171 | dw_pcie_cfg_write(pp->dbi_base, PCI_DEVICE_ID, 2, 0xCD80); | ||
172 | |||
173 | /* | ||
174 | * if is_gen1 is set then handle it, so that some buggy card | ||
175 | * also works | ||
176 | */ | ||
177 | if (spear13xx_pcie->is_gen1) { | ||
178 | dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCAP, 4, | ||
179 | &val); | ||
180 | if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { | ||
181 | val &= ~((u32)PCI_EXP_LNKCAP_SLS); | ||
182 | val |= PCI_EXP_LNKCAP_SLS_2_5GB; | ||
183 | dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + | ||
184 | PCI_EXP_LNKCAP, 4, val); | ||
185 | } | ||
186 | |||
187 | dw_pcie_cfg_read(pp->dbi_base, exp_cap_off + PCI_EXP_LNKCTL2, 4, | ||
188 | &val); | ||
189 | if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { | ||
190 | val &= ~((u32)PCI_EXP_LNKCAP_SLS); | ||
191 | val |= PCI_EXP_LNKCAP_SLS_2_5GB; | ||
192 | dw_pcie_cfg_write(pp->dbi_base, exp_cap_off + | ||
193 | PCI_EXP_LNKCTL2, 4, val); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* enable ltssm */ | ||
198 | writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID) | ||
199 | | (1 << APP_LTSSM_ENABLE_ID) | ||
200 | | ((u32)1 << REG_TRANSLATION_ENABLE), | ||
201 | &app_reg->app_ctrl_0); | ||
202 | |||
203 | /* check if the link is up or not */ | ||
204 | while (!dw_pcie_link_up(pp)) { | ||
205 | mdelay(100); | ||
206 | count++; | ||
207 | if (count == 10) { | ||
208 | dev_err(pp->dev, "link Fail\n"); | ||
209 | return -EINVAL; | ||
210 | } | ||
211 | } | ||
212 | dev_info(pp->dev, "link up\n"); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) | ||
218 | { | ||
219 | struct pcie_port *pp = arg; | ||
220 | struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); | ||
221 | struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; | ||
222 | unsigned int status; | ||
223 | |||
224 | status = readl(&app_reg->int_sts); | ||
225 | |||
226 | if (status & MSI_CTRL_INT) { | ||
227 | if (!IS_ENABLED(CONFIG_PCI_MSI)) | ||
228 | BUG(); | ||
229 | dw_handle_msi_irq(pp); | ||
230 | } | ||
231 | |||
232 | writel(status, &app_reg->int_clr); | ||
233 | |||
234 | return IRQ_HANDLED; | ||
235 | } | ||
236 | |||
237 | static void spear13xx_pcie_enable_interrupts(struct pcie_port *pp) | ||
238 | { | ||
239 | struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); | ||
240 | struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; | ||
241 | |||
242 | /* Enable MSI interrupt */ | ||
243 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
244 | dw_pcie_msi_init(pp); | ||
245 | writel(readl(&app_reg->int_mask) | | ||
246 | MSI_CTRL_INT, &app_reg->int_mask); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static int spear13xx_pcie_link_up(struct pcie_port *pp) | ||
251 | { | ||
252 | struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); | ||
253 | struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; | ||
254 | |||
255 | if (readl(&app_reg->app_status_1) & XMLH_LINK_UP) | ||
256 | return 1; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static void spear13xx_pcie_host_init(struct pcie_port *pp) | ||
262 | { | ||
263 | spear13xx_pcie_establish_link(pp); | ||
264 | spear13xx_pcie_enable_interrupts(pp); | ||
265 | } | ||
266 | |||
267 | static struct pcie_host_ops spear13xx_pcie_host_ops = { | ||
268 | .link_up = spear13xx_pcie_link_up, | ||
269 | .host_init = spear13xx_pcie_host_init, | ||
270 | }; | ||
271 | |||
272 | static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) | ||
273 | { | ||
274 | struct device *dev = &pdev->dev; | ||
275 | int ret; | ||
276 | |||
277 | pp->irq = platform_get_irq(pdev, 0); | ||
278 | if (!pp->irq) { | ||
279 | dev_err(dev, "failed to get irq\n"); | ||
280 | return -ENODEV; | ||
281 | } | ||
282 | ret = devm_request_irq(dev, pp->irq, spear13xx_pcie_irq_handler, | ||
283 | IRQF_SHARED, "spear1340-pcie", pp); | ||
284 | if (ret) { | ||
285 | dev_err(dev, "failed to request irq %d\n", pp->irq); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | pp->root_bus_nr = -1; | ||
290 | pp->ops = &spear13xx_pcie_host_ops; | ||
291 | |||
292 | ret = dw_pcie_host_init(pp); | ||
293 | if (ret) { | ||
294 | dev_err(dev, "failed to initialize host\n"); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int __init spear13xx_pcie_probe(struct platform_device *pdev) | ||
302 | { | ||
303 | struct spear13xx_pcie *spear13xx_pcie; | ||
304 | struct pcie_port *pp; | ||
305 | struct device *dev = &pdev->dev; | ||
306 | struct device_node *np = pdev->dev.of_node; | ||
307 | struct resource *dbi_base; | ||
308 | int ret; | ||
309 | |||
310 | spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL); | ||
311 | if (!spear13xx_pcie) { | ||
312 | dev_err(dev, "no memory for SPEAr13xx pcie\n"); | ||
313 | return -ENOMEM; | ||
314 | } | ||
315 | |||
316 | spear13xx_pcie->phy = devm_phy_get(dev, "pcie-phy"); | ||
317 | if (IS_ERR(spear13xx_pcie->phy)) { | ||
318 | ret = PTR_ERR(spear13xx_pcie->phy); | ||
319 | if (ret == -EPROBE_DEFER) | ||
320 | dev_info(dev, "probe deferred\n"); | ||
321 | else | ||
322 | dev_err(dev, "couldn't get pcie-phy\n"); | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | phy_init(spear13xx_pcie->phy); | ||
327 | |||
328 | spear13xx_pcie->clk = devm_clk_get(dev, NULL); | ||
329 | if (IS_ERR(spear13xx_pcie->clk)) { | ||
330 | dev_err(dev, "couldn't get clk for pcie\n"); | ||
331 | return PTR_ERR(spear13xx_pcie->clk); | ||
332 | } | ||
333 | ret = clk_prepare_enable(spear13xx_pcie->clk); | ||
334 | if (ret) { | ||
335 | dev_err(dev, "couldn't enable clk for pcie\n"); | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | pp = &spear13xx_pcie->pp; | ||
340 | |||
341 | pp->dev = dev; | ||
342 | |||
343 | dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
344 | pp->dbi_base = devm_ioremap_resource(dev, dbi_base); | ||
345 | if (IS_ERR(pp->dbi_base)) { | ||
346 | dev_err(dev, "couldn't remap dbi base %p\n", dbi_base); | ||
347 | ret = PTR_ERR(pp->dbi_base); | ||
348 | goto fail_clk; | ||
349 | } | ||
350 | spear13xx_pcie->app_base = pp->dbi_base + 0x2000; | ||
351 | |||
352 | if (of_property_read_bool(np, "st,pcie-is-gen1")) | ||
353 | spear13xx_pcie->is_gen1 = true; | ||
354 | |||
355 | ret = add_pcie_port(pp, pdev); | ||
356 | if (ret < 0) | ||
357 | goto fail_clk; | ||
358 | |||
359 | platform_set_drvdata(pdev, spear13xx_pcie); | ||
360 | return 0; | ||
361 | |||
362 | fail_clk: | ||
363 | clk_disable_unprepare(spear13xx_pcie->clk); | ||
364 | |||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static const struct of_device_id spear13xx_pcie_of_match[] = { | ||
369 | { .compatible = "st,spear1340-pcie", }, | ||
370 | {}, | ||
371 | }; | ||
372 | MODULE_DEVICE_TABLE(of, spear13xx_pcie_of_match); | ||
373 | |||
374 | static struct platform_driver spear13xx_pcie_driver __initdata = { | ||
375 | .probe = spear13xx_pcie_probe, | ||
376 | .driver = { | ||
377 | .name = "spear-pcie", | ||
378 | .owner = THIS_MODULE, | ||
379 | .of_match_table = of_match_ptr(spear13xx_pcie_of_match), | ||
380 | }, | ||
381 | }; | ||
382 | |||
383 | /* SPEAr13xx PCIe driver does not allow module unload */ | ||
384 | |||
385 | static int __init pcie_init(void) | ||
386 | { | ||
387 | return platform_driver_register(&spear13xx_pcie_driver); | ||
388 | } | ||
389 | module_init(pcie_init); | ||
390 | |||
391 | MODULE_DESCRIPTION("ST Microelectronics SPEAr13xx PCIe host controller driver"); | ||
392 | MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>"); | ||
393 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index d1f5fc924c93..0dd742719154 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
@@ -197,13 +197,6 @@ config PHY_EXYNOS5_USBDRD | |||
197 | This driver provides PHY interface for USB 3.0 DRD controller | 197 | This driver provides PHY interface for USB 3.0 DRD controller |
198 | present on Exynos5 SoC series. | 198 | present on Exynos5 SoC series. |
199 | 199 | ||
200 | config PHY_XGENE | ||
201 | tristate "APM X-Gene 15Gbps PHY support" | ||
202 | depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) | ||
203 | select GENERIC_PHY | ||
204 | help | ||
205 | This option enables support for APM X-Gene SoC multi-purpose PHY. | ||
206 | |||
207 | config PHY_QCOM_APQ8064_SATA | 200 | config PHY_QCOM_APQ8064_SATA |
208 | tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" | 201 | tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" |
209 | depends on ARCH_QCOM | 202 | depends on ARCH_QCOM |
@@ -218,4 +211,23 @@ config PHY_QCOM_IPQ806X_SATA | |||
218 | depends on OF | 211 | depends on OF |
219 | select GENERIC_PHY | 212 | select GENERIC_PHY |
220 | 213 | ||
214 | config PHY_ST_SPEAR1310_MIPHY | ||
215 | tristate "ST SPEAR1310-MIPHY driver" | ||
216 | select GENERIC_PHY | ||
217 | help | ||
218 | Support for ST SPEAr1310 MIPHY which can be used for PCIe and SATA. | ||
219 | |||
220 | config PHY_ST_SPEAR1340_MIPHY | ||
221 | tristate "ST SPEAR1340-MIPHY driver" | ||
222 | select GENERIC_PHY | ||
223 | help | ||
224 | Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA. | ||
225 | |||
226 | config PHY_XGENE | ||
227 | tristate "APM X-Gene 15Gbps PHY support" | ||
228 | depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) | ||
229 | select GENERIC_PHY | ||
230 | help | ||
231 | This option enables support for APM X-Gene SoC multi-purpose PHY. | ||
232 | |||
221 | endmenu | 233 | endmenu |
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ec24e915349b..95c69ed5ed45 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile | |||
@@ -23,6 +23,8 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o | |||
23 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o | 23 | phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o |
24 | phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o | 24 | phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o |
25 | obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o | 25 | obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o |
26 | obj-$(CONFIG_PHY_XGENE) += phy-xgene.o | ||
27 | obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o | 26 | obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o |
28 | obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o | 27 | obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o |
28 | obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o | ||
29 | obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o | ||
30 | obj-$(CONFIG_PHY_XGENE) += phy-xgene.o | ||
diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c new file mode 100644 index 000000000000..6dcbfcddb372 --- /dev/null +++ b/drivers/phy/phy-spear1310-miphy.c | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * ST SPEAr1310-miphy driver | ||
3 | * | ||
4 | * Copyright (C) 2014 ST Microelectronics | ||
5 | * Pratyush Anand <pratyush.anand@st.com> | ||
6 | * Mohit Kumar <mohit.kumar@st.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 | |||
14 | #include <linux/bitops.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/mfd/syscon.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/phy/phy.h> | ||
22 | #include <linux/regmap.h> | ||
23 | |||
24 | /* SPEAr1310 Registers */ | ||
25 | #define SPEAR1310_PCIE_SATA_CFG 0x3A4 | ||
26 | #define SPEAR1310_PCIE_SATA2_SEL_PCIE (0 << 31) | ||
27 | #define SPEAR1310_PCIE_SATA1_SEL_PCIE (0 << 30) | ||
28 | #define SPEAR1310_PCIE_SATA0_SEL_PCIE (0 << 29) | ||
29 | #define SPEAR1310_PCIE_SATA2_SEL_SATA BIT(31) | ||
30 | #define SPEAR1310_PCIE_SATA1_SEL_SATA BIT(30) | ||
31 | #define SPEAR1310_PCIE_SATA0_SEL_SATA BIT(29) | ||
32 | #define SPEAR1310_SATA2_CFG_TX_CLK_EN BIT(27) | ||
33 | #define SPEAR1310_SATA2_CFG_RX_CLK_EN BIT(26) | ||
34 | #define SPEAR1310_SATA2_CFG_POWERUP_RESET BIT(25) | ||
35 | #define SPEAR1310_SATA2_CFG_PM_CLK_EN BIT(24) | ||
36 | #define SPEAR1310_SATA1_CFG_TX_CLK_EN BIT(23) | ||
37 | #define SPEAR1310_SATA1_CFG_RX_CLK_EN BIT(22) | ||
38 | #define SPEAR1310_SATA1_CFG_POWERUP_RESET BIT(21) | ||
39 | #define SPEAR1310_SATA1_CFG_PM_CLK_EN BIT(20) | ||
40 | #define SPEAR1310_SATA0_CFG_TX_CLK_EN BIT(19) | ||
41 | #define SPEAR1310_SATA0_CFG_RX_CLK_EN BIT(18) | ||
42 | #define SPEAR1310_SATA0_CFG_POWERUP_RESET BIT(17) | ||
43 | #define SPEAR1310_SATA0_CFG_PM_CLK_EN BIT(16) | ||
44 | #define SPEAR1310_PCIE2_CFG_DEVICE_PRESENT BIT(11) | ||
45 | #define SPEAR1310_PCIE2_CFG_POWERUP_RESET BIT(10) | ||
46 | #define SPEAR1310_PCIE2_CFG_CORE_CLK_EN BIT(9) | ||
47 | #define SPEAR1310_PCIE2_CFG_AUX_CLK_EN BIT(8) | ||
48 | #define SPEAR1310_PCIE1_CFG_DEVICE_PRESENT BIT(7) | ||
49 | #define SPEAR1310_PCIE1_CFG_POWERUP_RESET BIT(6) | ||
50 | #define SPEAR1310_PCIE1_CFG_CORE_CLK_EN BIT(5) | ||
51 | #define SPEAR1310_PCIE1_CFG_AUX_CLK_EN BIT(4) | ||
52 | #define SPEAR1310_PCIE0_CFG_DEVICE_PRESENT BIT(3) | ||
53 | #define SPEAR1310_PCIE0_CFG_POWERUP_RESET BIT(2) | ||
54 | #define SPEAR1310_PCIE0_CFG_CORE_CLK_EN BIT(1) | ||
55 | #define SPEAR1310_PCIE0_CFG_AUX_CLK_EN BIT(0) | ||
56 | |||
57 | #define SPEAR1310_PCIE_CFG_MASK(x) ((0xF << (x * 4)) | BIT((x + 29))) | ||
58 | #define SPEAR1310_SATA_CFG_MASK(x) ((0xF << (x * 4 + 16)) | \ | ||
59 | BIT((x + 29))) | ||
60 | #define SPEAR1310_PCIE_CFG_VAL(x) \ | ||
61 | (SPEAR1310_PCIE_SATA##x##_SEL_PCIE | \ | ||
62 | SPEAR1310_PCIE##x##_CFG_AUX_CLK_EN | \ | ||
63 | SPEAR1310_PCIE##x##_CFG_CORE_CLK_EN | \ | ||
64 | SPEAR1310_PCIE##x##_CFG_POWERUP_RESET | \ | ||
65 | SPEAR1310_PCIE##x##_CFG_DEVICE_PRESENT) | ||
66 | #define SPEAR1310_SATA_CFG_VAL(x) \ | ||
67 | (SPEAR1310_PCIE_SATA##x##_SEL_SATA | \ | ||
68 | SPEAR1310_SATA##x##_CFG_PM_CLK_EN | \ | ||
69 | SPEAR1310_SATA##x##_CFG_POWERUP_RESET | \ | ||
70 | SPEAR1310_SATA##x##_CFG_RX_CLK_EN | \ | ||
71 | SPEAR1310_SATA##x##_CFG_TX_CLK_EN) | ||
72 | |||
73 | #define SPEAR1310_PCIE_MIPHY_CFG_1 0x3A8 | ||
74 | #define SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT BIT(31) | ||
75 | #define SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 BIT(28) | ||
76 | #define SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(x) (x << 16) | ||
77 | #define SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT BIT(15) | ||
78 | #define SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 BIT(12) | ||
79 | #define SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(x) (x << 0) | ||
80 | #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_MASK (0xFFFF) | ||
81 | #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK (0xFFFF << 16) | ||
82 | #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA \ | ||
83 | (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \ | ||
84 | SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 | \ | ||
85 | SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(60) | \ | ||
86 | SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \ | ||
87 | SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 | \ | ||
88 | SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(60)) | ||
89 | #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \ | ||
90 | (SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(120)) | ||
91 | #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE \ | ||
92 | (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \ | ||
93 | SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(25) | \ | ||
94 | SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \ | ||
95 | SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(25)) | ||
96 | |||
97 | #define SPEAR1310_PCIE_MIPHY_CFG_2 0x3AC | ||
98 | |||
99 | enum spear1310_miphy_mode { | ||
100 | SATA, | ||
101 | PCIE, | ||
102 | }; | ||
103 | |||
104 | struct spear1310_miphy_priv { | ||
105 | /* instance id of this phy */ | ||
106 | u32 id; | ||
107 | /* phy mode: 0 for SATA 1 for PCIe */ | ||
108 | enum spear1310_miphy_mode mode; | ||
109 | /* regmap for any soc specific misc registers */ | ||
110 | struct regmap *misc; | ||
111 | /* phy struct pointer */ | ||
112 | struct phy *phy; | ||
113 | }; | ||
114 | |||
115 | static int spear1310_miphy_pcie_init(struct spear1310_miphy_priv *priv) | ||
116 | { | ||
117 | u32 val; | ||
118 | |||
119 | regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1, | ||
120 | SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK, | ||
121 | SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE); | ||
122 | |||
123 | switch (priv->id) { | ||
124 | case 0: | ||
125 | val = SPEAR1310_PCIE_CFG_VAL(0); | ||
126 | break; | ||
127 | case 1: | ||
128 | val = SPEAR1310_PCIE_CFG_VAL(1); | ||
129 | break; | ||
130 | case 2: | ||
131 | val = SPEAR1310_PCIE_CFG_VAL(2); | ||
132 | break; | ||
133 | default: | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG, | ||
138 | SPEAR1310_PCIE_CFG_MASK(priv->id), val); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int spear1310_miphy_pcie_exit(struct spear1310_miphy_priv *priv) | ||
144 | { | ||
145 | regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG, | ||
146 | SPEAR1310_PCIE_CFG_MASK(priv->id), 0); | ||
147 | |||
148 | regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1, | ||
149 | SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK, 0); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int spear1310_miphy_init(struct phy *phy) | ||
155 | { | ||
156 | struct spear1310_miphy_priv *priv = phy_get_drvdata(phy); | ||
157 | int ret = 0; | ||
158 | |||
159 | if (priv->mode == PCIE) | ||
160 | ret = spear1310_miphy_pcie_init(priv); | ||
161 | |||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static int spear1310_miphy_exit(struct phy *phy) | ||
166 | { | ||
167 | struct spear1310_miphy_priv *priv = phy_get_drvdata(phy); | ||
168 | int ret = 0; | ||
169 | |||
170 | if (priv->mode == PCIE) | ||
171 | ret = spear1310_miphy_pcie_exit(priv); | ||
172 | |||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static const struct of_device_id spear1310_miphy_of_match[] = { | ||
177 | { .compatible = "st,spear1310-miphy" }, | ||
178 | { }, | ||
179 | }; | ||
180 | MODULE_DEVICE_TABLE(of, spear1310_miphy_of_match); | ||
181 | |||
182 | static struct phy_ops spear1310_miphy_ops = { | ||
183 | .init = spear1310_miphy_init, | ||
184 | .exit = spear1310_miphy_exit, | ||
185 | .owner = THIS_MODULE, | ||
186 | }; | ||
187 | |||
188 | static struct phy *spear1310_miphy_xlate(struct device *dev, | ||
189 | struct of_phandle_args *args) | ||
190 | { | ||
191 | struct spear1310_miphy_priv *priv = dev_get_drvdata(dev); | ||
192 | |||
193 | if (args->args_count < 1) { | ||
194 | dev_err(dev, "DT did not pass correct no of args\n"); | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | priv->mode = args->args[0]; | ||
199 | |||
200 | if (priv->mode != SATA && priv->mode != PCIE) { | ||
201 | dev_err(dev, "DT did not pass correct phy mode\n"); | ||
202 | return NULL; | ||
203 | } | ||
204 | |||
205 | return priv->phy; | ||
206 | } | ||
207 | |||
208 | static int spear1310_miphy_probe(struct platform_device *pdev) | ||
209 | { | ||
210 | struct device *dev = &pdev->dev; | ||
211 | struct spear1310_miphy_priv *priv; | ||
212 | struct phy_provider *phy_provider; | ||
213 | |||
214 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
215 | if (!priv) { | ||
216 | dev_err(dev, "can't alloc spear1310_miphy private date memory\n"); | ||
217 | return -ENOMEM; | ||
218 | } | ||
219 | |||
220 | priv->misc = | ||
221 | syscon_regmap_lookup_by_phandle(dev->of_node, "misc"); | ||
222 | if (IS_ERR(priv->misc)) { | ||
223 | dev_err(dev, "failed to find misc regmap\n"); | ||
224 | return PTR_ERR(priv->misc); | ||
225 | } | ||
226 | |||
227 | if (of_property_read_u32(dev->of_node, "phy-id", &priv->id)) { | ||
228 | dev_err(dev, "failed to find phy id\n"); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL); | ||
233 | if (IS_ERR(priv->phy)) { | ||
234 | dev_err(dev, "failed to create SATA PCIe PHY\n"); | ||
235 | return PTR_ERR(priv->phy); | ||
236 | } | ||
237 | |||
238 | dev_set_drvdata(dev, priv); | ||
239 | phy_set_drvdata(priv->phy, priv); | ||
240 | |||
241 | phy_provider = | ||
242 | devm_of_phy_provider_register(dev, spear1310_miphy_xlate); | ||
243 | if (IS_ERR(phy_provider)) { | ||
244 | dev_err(dev, "failed to register phy provider\n"); | ||
245 | return PTR_ERR(phy_provider); | ||
246 | } | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static struct platform_driver spear1310_miphy_driver = { | ||
252 | .probe = spear1310_miphy_probe, | ||
253 | .driver = { | ||
254 | .name = "spear1310-miphy", | ||
255 | .owner = THIS_MODULE, | ||
256 | .of_match_table = of_match_ptr(spear1310_miphy_of_match), | ||
257 | }, | ||
258 | }; | ||
259 | |||
260 | static int __init spear1310_miphy_phy_init(void) | ||
261 | { | ||
262 | return platform_driver_register(&spear1310_miphy_driver); | ||
263 | } | ||
264 | module_init(spear1310_miphy_phy_init); | ||
265 | |||
266 | static void __exit spear1310_miphy_phy_exit(void) | ||
267 | { | ||
268 | platform_driver_unregister(&spear1310_miphy_driver); | ||
269 | } | ||
270 | module_exit(spear1310_miphy_phy_exit); | ||
271 | |||
272 | MODULE_DESCRIPTION("ST SPEAR1310-MIPHY driver"); | ||
273 | MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>"); | ||
274 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c new file mode 100644 index 000000000000..7135ba2603b6 --- /dev/null +++ b/drivers/phy/phy-spear1340-miphy.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | * ST spear1340-miphy driver | ||
3 | * | ||
4 | * Copyright (C) 2014 ST Microelectronics | ||
5 | * Pratyush Anand <pratyush.anand@st.com> | ||
6 | * Mohit Kumar <mohit.kumar@st.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 | |||
14 | #include <linux/bitops.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/mfd/syscon.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/phy/phy.h> | ||
22 | #include <linux/regmap.h> | ||
23 | |||
24 | /* SPEAr1340 Registers */ | ||
25 | /* Power Management Registers */ | ||
26 | #define SPEAR1340_PCM_CFG 0x100 | ||
27 | #define SPEAR1340_PCM_CFG_SATA_POWER_EN BIT(11) | ||
28 | #define SPEAR1340_PCM_WKUP_CFG 0x104 | ||
29 | #define SPEAR1340_SWITCH_CTR 0x108 | ||
30 | |||
31 | #define SPEAR1340_PERIP1_SW_RST 0x318 | ||
32 | #define SPEAR1340_PERIP1_SW_RSATA BIT(12) | ||
33 | #define SPEAR1340_PERIP2_SW_RST 0x31C | ||
34 | #define SPEAR1340_PERIP3_SW_RST 0x320 | ||
35 | |||
36 | /* PCIE - SATA configuration registers */ | ||
37 | #define SPEAR1340_PCIE_SATA_CFG 0x424 | ||
38 | /* PCIE CFG MASks */ | ||
39 | #define SPEAR1340_PCIE_CFG_DEVICE_PRESENT BIT(11) | ||
40 | #define SPEAR1340_PCIE_CFG_POWERUP_RESET BIT(10) | ||
41 | #define SPEAR1340_PCIE_CFG_CORE_CLK_EN BIT(9) | ||
42 | #define SPEAR1340_PCIE_CFG_AUX_CLK_EN BIT(8) | ||
43 | #define SPEAR1340_SATA_CFG_TX_CLK_EN BIT(4) | ||
44 | #define SPEAR1340_SATA_CFG_RX_CLK_EN BIT(3) | ||
45 | #define SPEAR1340_SATA_CFG_POWERUP_RESET BIT(2) | ||
46 | #define SPEAR1340_SATA_CFG_PM_CLK_EN BIT(1) | ||
47 | #define SPEAR1340_PCIE_SATA_SEL_PCIE (0) | ||
48 | #define SPEAR1340_PCIE_SATA_SEL_SATA (1) | ||
49 | #define SPEAR1340_PCIE_SATA_CFG_MASK 0xF1F | ||
50 | #define SPEAR1340_PCIE_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_PCIE | \ | ||
51 | SPEAR1340_PCIE_CFG_AUX_CLK_EN | \ | ||
52 | SPEAR1340_PCIE_CFG_CORE_CLK_EN | \ | ||
53 | SPEAR1340_PCIE_CFG_POWERUP_RESET | \ | ||
54 | SPEAR1340_PCIE_CFG_DEVICE_PRESENT) | ||
55 | #define SPEAR1340_SATA_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_SATA | \ | ||
56 | SPEAR1340_SATA_CFG_PM_CLK_EN | \ | ||
57 | SPEAR1340_SATA_CFG_POWERUP_RESET | \ | ||
58 | SPEAR1340_SATA_CFG_RX_CLK_EN | \ | ||
59 | SPEAR1340_SATA_CFG_TX_CLK_EN) | ||
60 | |||
61 | #define SPEAR1340_PCIE_MIPHY_CFG 0x428 | ||
62 | #define SPEAR1340_MIPHY_OSC_BYPASS_EXT BIT(31) | ||
63 | #define SPEAR1340_MIPHY_CLK_REF_DIV2 BIT(27) | ||
64 | #define SPEAR1340_MIPHY_CLK_REF_DIV4 (2 << 27) | ||
65 | #define SPEAR1340_MIPHY_CLK_REF_DIV8 (3 << 27) | ||
66 | #define SPEAR1340_MIPHY_PLL_RATIO_TOP(x) (x << 0) | ||
67 | #define SPEAR1340_PCIE_MIPHY_CFG_MASK 0xF80000FF | ||
68 | #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA \ | ||
69 | (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ | ||
70 | SPEAR1340_MIPHY_CLK_REF_DIV2 | \ | ||
71 | SPEAR1340_MIPHY_PLL_RATIO_TOP(60)) | ||
72 | #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \ | ||
73 | (SPEAR1340_MIPHY_PLL_RATIO_TOP(120)) | ||
74 | #define SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE \ | ||
75 | (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ | ||
76 | SPEAR1340_MIPHY_PLL_RATIO_TOP(25)) | ||
77 | |||
78 | enum spear1340_miphy_mode { | ||
79 | SATA, | ||
80 | PCIE, | ||
81 | }; | ||
82 | |||
83 | struct spear1340_miphy_priv { | ||
84 | /* phy mode: 0 for SATA 1 for PCIe */ | ||
85 | enum spear1340_miphy_mode mode; | ||
86 | /* regmap for any soc specific misc registers */ | ||
87 | struct regmap *misc; | ||
88 | /* phy struct pointer */ | ||
89 | struct phy *phy; | ||
90 | }; | ||
91 | |||
92 | static int spear1340_miphy_sata_init(struct spear1340_miphy_priv *priv) | ||
93 | { | ||
94 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, | ||
95 | SPEAR1340_PCIE_SATA_CFG_MASK, | ||
96 | SPEAR1340_SATA_CFG_VAL); | ||
97 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, | ||
98 | SPEAR1340_PCIE_MIPHY_CFG_MASK, | ||
99 | SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK); | ||
100 | /* Switch on sata power domain */ | ||
101 | regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG, | ||
102 | SPEAR1340_PCM_CFG_SATA_POWER_EN, | ||
103 | SPEAR1340_PCM_CFG_SATA_POWER_EN); | ||
104 | /* Wait for SATA power domain on */ | ||
105 | msleep(20); | ||
106 | |||
107 | /* Disable PCIE SATA Controller reset */ | ||
108 | regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST, | ||
109 | SPEAR1340_PERIP1_SW_RSATA, 0); | ||
110 | /* Wait for SATA reset de-assert completion */ | ||
111 | msleep(20); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int spear1340_miphy_sata_exit(struct spear1340_miphy_priv *priv) | ||
117 | { | ||
118 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, | ||
119 | SPEAR1340_PCIE_SATA_CFG_MASK, 0); | ||
120 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, | ||
121 | SPEAR1340_PCIE_MIPHY_CFG_MASK, 0); | ||
122 | |||
123 | /* Enable PCIE SATA Controller reset */ | ||
124 | regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST, | ||
125 | SPEAR1340_PERIP1_SW_RSATA, | ||
126 | SPEAR1340_PERIP1_SW_RSATA); | ||
127 | /* Wait for SATA power domain off */ | ||
128 | msleep(20); | ||
129 | /* Switch off sata power domain */ | ||
130 | regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG, | ||
131 | SPEAR1340_PCM_CFG_SATA_POWER_EN, 0); | ||
132 | /* Wait for SATA reset assert completion */ | ||
133 | msleep(20); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int spear1340_miphy_pcie_init(struct spear1340_miphy_priv *priv) | ||
139 | { | ||
140 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, | ||
141 | SPEAR1340_PCIE_MIPHY_CFG_MASK, | ||
142 | SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE); | ||
143 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, | ||
144 | SPEAR1340_PCIE_SATA_CFG_MASK, | ||
145 | SPEAR1340_PCIE_CFG_VAL); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int spear1340_miphy_pcie_exit(struct spear1340_miphy_priv *priv) | ||
151 | { | ||
152 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG, | ||
153 | SPEAR1340_PCIE_MIPHY_CFG_MASK, 0); | ||
154 | regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG, | ||
155 | SPEAR1340_PCIE_SATA_CFG_MASK, 0); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int spear1340_miphy_init(struct phy *phy) | ||
161 | { | ||
162 | struct spear1340_miphy_priv *priv = phy_get_drvdata(phy); | ||
163 | int ret = 0; | ||
164 | |||
165 | if (priv->mode == SATA) | ||
166 | ret = spear1340_miphy_sata_init(priv); | ||
167 | else if (priv->mode == PCIE) | ||
168 | ret = spear1340_miphy_pcie_init(priv); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static int spear1340_miphy_exit(struct phy *phy) | ||
174 | { | ||
175 | struct spear1340_miphy_priv *priv = phy_get_drvdata(phy); | ||
176 | int ret = 0; | ||
177 | |||
178 | if (priv->mode == SATA) | ||
179 | ret = spear1340_miphy_sata_exit(priv); | ||
180 | else if (priv->mode == PCIE) | ||
181 | ret = spear1340_miphy_pcie_exit(priv); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | static const struct of_device_id spear1340_miphy_of_match[] = { | ||
187 | { .compatible = "st,spear1340-miphy" }, | ||
188 | { }, | ||
189 | }; | ||
190 | MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match); | ||
191 | |||
192 | static struct phy_ops spear1340_miphy_ops = { | ||
193 | .init = spear1340_miphy_init, | ||
194 | .exit = spear1340_miphy_exit, | ||
195 | .owner = THIS_MODULE, | ||
196 | }; | ||
197 | |||
198 | #ifdef CONFIG_PM_SLEEP | ||
199 | static int spear1340_miphy_suspend(struct device *dev) | ||
200 | { | ||
201 | struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); | ||
202 | int ret = 0; | ||
203 | |||
204 | if (priv->mode == SATA) | ||
205 | ret = spear1340_miphy_sata_exit(priv); | ||
206 | |||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | static int spear1340_miphy_resume(struct device *dev) | ||
211 | { | ||
212 | struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); | ||
213 | int ret = 0; | ||
214 | |||
215 | if (priv->mode == SATA) | ||
216 | ret = spear1340_miphy_sata_init(priv); | ||
217 | |||
218 | return ret; | ||
219 | } | ||
220 | #endif | ||
221 | |||
222 | static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend, | ||
223 | spear1340_miphy_resume); | ||
224 | |||
225 | static struct phy *spear1340_miphy_xlate(struct device *dev, | ||
226 | struct of_phandle_args *args) | ||
227 | { | ||
228 | struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); | ||
229 | |||
230 | if (args->args_count < 1) { | ||
231 | dev_err(dev, "DT did not pass correct no of args\n"); | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | priv->mode = args->args[0]; | ||
236 | |||
237 | if (priv->mode != SATA && priv->mode != PCIE) { | ||
238 | dev_err(dev, "DT did not pass correct phy mode\n"); | ||
239 | return NULL; | ||
240 | } | ||
241 | |||
242 | return priv->phy; | ||
243 | } | ||
244 | |||
245 | static int spear1340_miphy_probe(struct platform_device *pdev) | ||
246 | { | ||
247 | struct device *dev = &pdev->dev; | ||
248 | struct spear1340_miphy_priv *priv; | ||
249 | struct phy_provider *phy_provider; | ||
250 | |||
251 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
252 | if (!priv) { | ||
253 | dev_err(dev, "can't alloc spear1340_miphy private date memory\n"); | ||
254 | return -ENOMEM; | ||
255 | } | ||
256 | |||
257 | priv->misc = | ||
258 | syscon_regmap_lookup_by_phandle(dev->of_node, "misc"); | ||
259 | if (IS_ERR(priv->misc)) { | ||
260 | dev_err(dev, "failed to find misc regmap\n"); | ||
261 | return PTR_ERR(priv->misc); | ||
262 | } | ||
263 | |||
264 | priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL); | ||
265 | if (IS_ERR(priv->phy)) { | ||
266 | dev_err(dev, "failed to create SATA PCIe PHY\n"); | ||
267 | return PTR_ERR(priv->phy); | ||
268 | } | ||
269 | |||
270 | dev_set_drvdata(dev, priv); | ||
271 | phy_set_drvdata(priv->phy, priv); | ||
272 | |||
273 | phy_provider = | ||
274 | devm_of_phy_provider_register(dev, spear1340_miphy_xlate); | ||
275 | if (IS_ERR(phy_provider)) { | ||
276 | dev_err(dev, "failed to register phy provider\n"); | ||
277 | return PTR_ERR(phy_provider); | ||
278 | } | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static struct platform_driver spear1340_miphy_driver = { | ||
284 | .probe = spear1340_miphy_probe, | ||
285 | .driver = { | ||
286 | .name = "spear1340-miphy", | ||
287 | .owner = THIS_MODULE, | ||
288 | .pm = &spear1340_miphy_pm_ops, | ||
289 | .of_match_table = of_match_ptr(spear1340_miphy_of_match), | ||
290 | }, | ||
291 | }; | ||
292 | |||
293 | static int __init spear1340_miphy_phy_init(void) | ||
294 | { | ||
295 | return platform_driver_register(&spear1340_miphy_driver); | ||
296 | } | ||
297 | module_init(spear1340_miphy_phy_init); | ||
298 | |||
299 | static void __exit spear1340_miphy_phy_exit(void) | ||
300 | { | ||
301 | platform_driver_unregister(&spear1340_miphy_driver); | ||
302 | } | ||
303 | module_exit(spear1340_miphy_phy_exit); | ||
304 | |||
305 | MODULE_DESCRIPTION("ST SPEAR1340-MIPHY driver"); | ||
306 | MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>"); | ||
307 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c index 4a7daf577b49..a06620474845 100644 --- a/drivers/pinctrl/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/pinctrl-tegra-xusb.c | |||
@@ -910,7 +910,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
910 | goto reset; | 910 | goto reset; |
911 | } | 911 | } |
912 | 912 | ||
913 | phy = devm_phy_create(&pdev->dev, &pcie_phy_ops, NULL); | 913 | phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops, NULL); |
914 | if (IS_ERR(phy)) { | 914 | if (IS_ERR(phy)) { |
915 | err = PTR_ERR(phy); | 915 | err = PTR_ERR(phy); |
916 | goto unregister; | 916 | goto unregister; |
@@ -919,7 +919,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
919 | padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy; | 919 | padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy; |
920 | phy_set_drvdata(phy, padctl); | 920 | phy_set_drvdata(phy, padctl); |
921 | 921 | ||
922 | phy = devm_phy_create(&pdev->dev, &sata_phy_ops, NULL); | 922 | phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops, NULL); |
923 | if (IS_ERR(phy)) { | 923 | if (IS_ERR(phy)) { |
924 | err = PTR_ERR(phy); | 924 | err = PTR_ERR(phy); |
925 | goto unregister; | 925 | goto unregister; |
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 4ad7b89a4cb4..331dfca415c7 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig | |||
@@ -43,7 +43,7 @@ config PWM_AB8500 | |||
43 | 43 | ||
44 | config PWM_ATMEL | 44 | config PWM_ATMEL |
45 | tristate "Atmel PWM support" | 45 | tristate "Atmel PWM support" |
46 | depends on ARCH_AT91 | 46 | depends on ARCH_AT91 || AVR32 |
47 | help | 47 | help |
48 | Generic PWM framework driver for Atmel SoC. | 48 | Generic PWM framework driver for Atmel SoC. |
49 | 49 | ||
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index cc153f55d9f9..8d03924749b8 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig | |||
@@ -178,17 +178,6 @@ config BACKLIGHT_ATMEL_LCDC | |||
178 | If in doubt, it's safe to enable this option; it doesn't kick | 178 | If in doubt, it's safe to enable this option; it doesn't kick |
179 | in unless the board's description says it's wired that way. | 179 | in unless the board's description says it's wired that way. |
180 | 180 | ||
181 | config BACKLIGHT_ATMEL_PWM | ||
182 | tristate "Atmel PWM backlight control" | ||
183 | depends on ATMEL_PWM | ||
184 | help | ||
185 | Say Y here if you want to use the PWM peripheral in Atmel AT91 and | ||
186 | AVR32 devices. This driver will need additional platform data to know | ||
187 | which PWM instance to use and how to configure it. | ||
188 | |||
189 | To compile this driver as a module, choose M here: the module will be | ||
190 | called atmel-pwm-bl. | ||
191 | |||
192 | config BACKLIGHT_EP93XX | 181 | config BACKLIGHT_EP93XX |
193 | tristate "Cirrus EP93xx Backlight Driver" | 182 | tristate "Cirrus EP93xx Backlight Driver" |
194 | depends on FB_EP93XX | 183 | depends on FB_EP93XX |
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index a9ea34a39cad..fcd50b732165 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile | |||
@@ -25,7 +25,6 @@ obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o | |||
25 | obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o | 25 | obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o |
26 | obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o | 26 | obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o |
27 | obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o | 27 | obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o |
28 | obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o | ||
29 | obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o | 28 | obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o |
30 | obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o | 29 | obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o |
31 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | 30 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o |
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c deleted file mode 100644 index 261b1a4ec3d8..000000000000 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ /dev/null | |||
@@ -1,223 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Atmel Corporation | ||
3 | * | ||
4 | * Backlight driver using Atmel PWM peripheral. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/fb.h> | ||
15 | #include <linux/gpio.h> | ||
16 | #include <linux/backlight.h> | ||
17 | #include <linux/atmel_pwm.h> | ||
18 | #include <linux/atmel-pwm-bl.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | struct atmel_pwm_bl { | ||
22 | const struct atmel_pwm_bl_platform_data *pdata; | ||
23 | struct backlight_device *bldev; | ||
24 | struct platform_device *pdev; | ||
25 | struct pwm_channel pwmc; | ||
26 | int gpio_on; | ||
27 | }; | ||
28 | |||
29 | static void atmel_pwm_bl_set_gpio_on(struct atmel_pwm_bl *pwmbl, int on) | ||
30 | { | ||
31 | if (!gpio_is_valid(pwmbl->gpio_on)) | ||
32 | return; | ||
33 | |||
34 | gpio_set_value(pwmbl->gpio_on, on ^ pwmbl->pdata->on_active_low); | ||
35 | } | ||
36 | |||
37 | static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) | ||
38 | { | ||
39 | struct atmel_pwm_bl *pwmbl = bl_get_data(bd); | ||
40 | int intensity = bd->props.brightness; | ||
41 | int pwm_duty; | ||
42 | |||
43 | if (bd->props.power != FB_BLANK_UNBLANK) | ||
44 | intensity = 0; | ||
45 | if (bd->props.fb_blank != FB_BLANK_UNBLANK) | ||
46 | intensity = 0; | ||
47 | |||
48 | if (pwmbl->pdata->pwm_active_low) | ||
49 | pwm_duty = pwmbl->pdata->pwm_duty_min + intensity; | ||
50 | else | ||
51 | pwm_duty = pwmbl->pdata->pwm_duty_max - intensity; | ||
52 | |||
53 | if (pwm_duty > pwmbl->pdata->pwm_duty_max) | ||
54 | pwm_duty = pwmbl->pdata->pwm_duty_max; | ||
55 | if (pwm_duty < pwmbl->pdata->pwm_duty_min) | ||
56 | pwm_duty = pwmbl->pdata->pwm_duty_min; | ||
57 | |||
58 | if (!intensity) { | ||
59 | atmel_pwm_bl_set_gpio_on(pwmbl, 0); | ||
60 | pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty); | ||
61 | pwm_channel_disable(&pwmbl->pwmc); | ||
62 | } else { | ||
63 | pwm_channel_enable(&pwmbl->pwmc); | ||
64 | pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty); | ||
65 | atmel_pwm_bl_set_gpio_on(pwmbl, 1); | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int atmel_pwm_bl_get_intensity(struct backlight_device *bd) | ||
72 | { | ||
73 | struct atmel_pwm_bl *pwmbl = bl_get_data(bd); | ||
74 | u32 cdty; | ||
75 | u32 intensity; | ||
76 | |||
77 | cdty = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY); | ||
78 | if (pwmbl->pdata->pwm_active_low) | ||
79 | intensity = cdty - pwmbl->pdata->pwm_duty_min; | ||
80 | else | ||
81 | intensity = pwmbl->pdata->pwm_duty_max - cdty; | ||
82 | |||
83 | return intensity & 0xffff; | ||
84 | } | ||
85 | |||
86 | static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl) | ||
87 | { | ||
88 | unsigned long pwm_rate = pwmbl->pwmc.mck; | ||
89 | unsigned long prescale = DIV_ROUND_UP(pwm_rate, | ||
90 | (pwmbl->pdata->pwm_frequency * | ||
91 | pwmbl->pdata->pwm_compare_max)) - 1; | ||
92 | |||
93 | /* | ||
94 | * Prescale must be power of two and maximum 0xf in size because of | ||
95 | * hardware limit. PWM speed will be: | ||
96 | * PWM module clock speed / (2 ^ prescale). | ||
97 | */ | ||
98 | prescale = fls(prescale); | ||
99 | if (prescale > 0xf) | ||
100 | prescale = 0xf; | ||
101 | |||
102 | pwm_channel_writel(&pwmbl->pwmc, PWM_CMR, prescale); | ||
103 | pwm_channel_writel(&pwmbl->pwmc, PWM_CDTY, | ||
104 | pwmbl->pdata->pwm_duty_min + | ||
105 | pwmbl->bldev->props.brightness); | ||
106 | pwm_channel_writel(&pwmbl->pwmc, PWM_CPRD, | ||
107 | pwmbl->pdata->pwm_compare_max); | ||
108 | |||
109 | dev_info(&pwmbl->pdev->dev, "Atmel PWM backlight driver (%lu Hz)\n", | ||
110 | pwmbl->pwmc.mck / pwmbl->pdata->pwm_compare_max / | ||
111 | (1 << prescale)); | ||
112 | |||
113 | return pwm_channel_enable(&pwmbl->pwmc); | ||
114 | } | ||
115 | |||
116 | static const struct backlight_ops atmel_pwm_bl_ops = { | ||
117 | .get_brightness = atmel_pwm_bl_get_intensity, | ||
118 | .update_status = atmel_pwm_bl_set_intensity, | ||
119 | }; | ||
120 | |||
121 | static int atmel_pwm_bl_probe(struct platform_device *pdev) | ||
122 | { | ||
123 | struct backlight_properties props; | ||
124 | const struct atmel_pwm_bl_platform_data *pdata; | ||
125 | struct backlight_device *bldev; | ||
126 | struct atmel_pwm_bl *pwmbl; | ||
127 | unsigned long flags; | ||
128 | int retval; | ||
129 | |||
130 | pdata = dev_get_platdata(&pdev->dev); | ||
131 | if (!pdata) | ||
132 | return -ENODEV; | ||
133 | |||
134 | if (pdata->pwm_compare_max < pdata->pwm_duty_max || | ||
135 | pdata->pwm_duty_min > pdata->pwm_duty_max || | ||
136 | pdata->pwm_frequency == 0) | ||
137 | return -EINVAL; | ||
138 | |||
139 | pwmbl = devm_kzalloc(&pdev->dev, sizeof(struct atmel_pwm_bl), | ||
140 | GFP_KERNEL); | ||
141 | if (!pwmbl) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | pwmbl->pdev = pdev; | ||
145 | pwmbl->pdata = pdata; | ||
146 | pwmbl->gpio_on = pdata->gpio_on; | ||
147 | |||
148 | retval = pwm_channel_alloc(pdata->pwm_channel, &pwmbl->pwmc); | ||
149 | if (retval) | ||
150 | return retval; | ||
151 | |||
152 | if (gpio_is_valid(pwmbl->gpio_on)) { | ||
153 | /* Turn display off by default. */ | ||
154 | if (pdata->on_active_low) | ||
155 | flags = GPIOF_OUT_INIT_HIGH; | ||
156 | else | ||
157 | flags = GPIOF_OUT_INIT_LOW; | ||
158 | |||
159 | retval = devm_gpio_request_one(&pdev->dev, pwmbl->gpio_on, | ||
160 | flags, "gpio_atmel_pwm_bl"); | ||
161 | if (retval) | ||
162 | goto err_free_pwm; | ||
163 | } | ||
164 | |||
165 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
166 | props.type = BACKLIGHT_RAW; | ||
167 | props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min; | ||
168 | bldev = devm_backlight_device_register(&pdev->dev, "atmel-pwm-bl", | ||
169 | &pdev->dev, pwmbl, &atmel_pwm_bl_ops, | ||
170 | &props); | ||
171 | if (IS_ERR(bldev)) { | ||
172 | retval = PTR_ERR(bldev); | ||
173 | goto err_free_pwm; | ||
174 | } | ||
175 | |||
176 | pwmbl->bldev = bldev; | ||
177 | |||
178 | platform_set_drvdata(pdev, pwmbl); | ||
179 | |||
180 | /* Power up the backlight by default at middle intesity. */ | ||
181 | bldev->props.power = FB_BLANK_UNBLANK; | ||
182 | bldev->props.brightness = bldev->props.max_brightness / 2; | ||
183 | |||
184 | retval = atmel_pwm_bl_init_pwm(pwmbl); | ||
185 | if (retval) | ||
186 | goto err_free_pwm; | ||
187 | |||
188 | atmel_pwm_bl_set_intensity(bldev); | ||
189 | |||
190 | return 0; | ||
191 | |||
192 | err_free_pwm: | ||
193 | pwm_channel_free(&pwmbl->pwmc); | ||
194 | |||
195 | return retval; | ||
196 | } | ||
197 | |||
198 | static int atmel_pwm_bl_remove(struct platform_device *pdev) | ||
199 | { | ||
200 | struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev); | ||
201 | |||
202 | atmel_pwm_bl_set_gpio_on(pwmbl, 0); | ||
203 | pwm_channel_disable(&pwmbl->pwmc); | ||
204 | pwm_channel_free(&pwmbl->pwmc); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static struct platform_driver atmel_pwm_bl_driver = { | ||
210 | .driver = { | ||
211 | .name = "atmel-pwm-bl", | ||
212 | }, | ||
213 | /* REVISIT add suspend() and resume() */ | ||
214 | .probe = atmel_pwm_bl_probe, | ||
215 | .remove = atmel_pwm_bl_remove, | ||
216 | }; | ||
217 | |||
218 | module_platform_driver(atmel_pwm_bl_driver); | ||
219 | |||
220 | MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>"); | ||
221 | MODULE_DESCRIPTION("Atmel PWM backlight driver"); | ||
222 | MODULE_LICENSE("GPL"); | ||
223 | MODULE_ALIAS("platform:atmel-pwm-bl"); | ||
diff --git a/include/linux/atmel-pwm-bl.h b/include/linux/atmel-pwm-bl.h deleted file mode 100644 index 0153a47806c2..000000000000 --- a/include/linux/atmel-pwm-bl.h +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 Atmel Corporation | ||
3 | * | ||
4 | * Driver for the AT32AP700X PS/2 controller (PSIF). | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published | ||
8 | * by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __INCLUDE_ATMEL_PWM_BL_H | ||
12 | #define __INCLUDE_ATMEL_PWM_BL_H | ||
13 | |||
14 | /** | ||
15 | * struct atmel_pwm_bl_platform_data | ||
16 | * @pwm_channel: which PWM channel in the PWM module to use. | ||
17 | * @pwm_frequency: PWM frequency to generate, the driver will try to be as | ||
18 | * close as the prescaler allows. | ||
19 | * @pwm_compare_max: value to use in the PWM channel compare register. | ||
20 | * @pwm_duty_max: maximum duty cycle value, must be less than or equal to | ||
21 | * pwm_compare_max. | ||
22 | * @pwm_duty_min: minimum duty cycle value, must be less than pwm_duty_max. | ||
23 | * @pwm_active_low: set to one if the low part of the PWM signal increases the | ||
24 | * brightness of the backlight. | ||
25 | * @gpio_on: GPIO line to control the backlight on/off, set to -1 if not used. | ||
26 | * @on_active_low: set to one if the on/off signal is on when GPIO is low. | ||
27 | * | ||
28 | * This struct must be added to the platform device in the board code. It is | ||
29 | * used by the atmel-pwm-bl driver to setup the GPIO to control on/off and the | ||
30 | * PWM device. | ||
31 | */ | ||
32 | struct atmel_pwm_bl_platform_data { | ||
33 | unsigned int pwm_channel; | ||
34 | unsigned int pwm_frequency; | ||
35 | unsigned int pwm_compare_max; | ||
36 | unsigned int pwm_duty_max; | ||
37 | unsigned int pwm_duty_min; | ||
38 | unsigned int pwm_active_low; | ||
39 | int gpio_on; | ||
40 | unsigned int on_active_low; | ||
41 | }; | ||
42 | |||
43 | #endif /* __INCLUDE_ATMEL_PWM_BL_H */ | ||
diff --git a/include/linux/atmel_pwm.h b/include/linux/atmel_pwm.h deleted file mode 100644 index ea04abb3db8e..000000000000 --- a/include/linux/atmel_pwm.h +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | #ifndef __LINUX_ATMEL_PWM_H | ||
2 | #define __LINUX_ATMEL_PWM_H | ||
3 | |||
4 | /** | ||
5 | * struct pwm_channel - driver handle to a PWM channel | ||
6 | * @regs: base of this channel's registers | ||
7 | * @index: number of this channel (0..31) | ||
8 | * @mck: base clock rate, which can be prescaled and maybe subdivided | ||
9 | * | ||
10 | * Drivers initialize a pwm_channel structure using pwm_channel_alloc(). | ||
11 | * Then they configure its clock rate (derived from MCK), alignment, | ||
12 | * polarity, and duty cycle by writing directly to the channel registers, | ||
13 | * before enabling the channel by calling pwm_channel_enable(). | ||
14 | * | ||
15 | * After emitting a PWM signal for the desired length of time, drivers | ||
16 | * may then pwm_channel_disable() or pwm_channel_free(). Both of these | ||
17 | * disable the channel, but when it's freed the IRQ is deconfigured and | ||
18 | * the channel must later be re-allocated and reconfigured. | ||
19 | * | ||
20 | * Note that if the period or duty cycle need to be changed while the | ||
21 | * PWM channel is operating, drivers must use the PWM_CUPD double buffer | ||
22 | * mechanism, either polling until they change or getting implicitly | ||
23 | * notified through a once-per-period interrupt handler. | ||
24 | */ | ||
25 | struct pwm_channel { | ||
26 | void __iomem *regs; | ||
27 | unsigned index; | ||
28 | unsigned long mck; | ||
29 | }; | ||
30 | |||
31 | extern int pwm_channel_alloc(int index, struct pwm_channel *ch); | ||
32 | extern int pwm_channel_free(struct pwm_channel *ch); | ||
33 | |||
34 | extern int pwm_clk_alloc(unsigned prescale, unsigned div); | ||
35 | extern void pwm_clk_free(unsigned clk); | ||
36 | |||
37 | extern int __pwm_channel_onoff(struct pwm_channel *ch, int enabled); | ||
38 | |||
39 | #define pwm_channel_enable(ch) __pwm_channel_onoff((ch), 1) | ||
40 | #define pwm_channel_disable(ch) __pwm_channel_onoff((ch), 0) | ||
41 | |||
42 | /* periodic interrupts, mostly for CUPD changes to period or cycle */ | ||
43 | extern int pwm_channel_handler(struct pwm_channel *ch, | ||
44 | void (*handler)(struct pwm_channel *ch)); | ||
45 | |||
46 | /* per-channel registers (banked at pwm_channel->regs) */ | ||
47 | #define PWM_CMR 0x00 /* mode register */ | ||
48 | #define PWM_CPR_CPD (1 << 10) /* set: CUPD modifies period */ | ||
49 | #define PWM_CPR_CPOL (1 << 9) /* set: idle high */ | ||
50 | #define PWM_CPR_CALG (1 << 8) /* set: center align */ | ||
51 | #define PWM_CPR_CPRE (0xf << 0) /* mask: rate is mck/(2^pre) */ | ||
52 | #define PWM_CPR_CLKA (0xb << 0) /* rate CLKA */ | ||
53 | #define PWM_CPR_CLKB (0xc << 0) /* rate CLKB */ | ||
54 | #define PWM_CDTY 0x04 /* duty cycle (max of CPRD) */ | ||
55 | #define PWM_CPRD 0x08 /* period (count up from zero) */ | ||
56 | #define PWM_CCNT 0x0c /* counter (20 bits?) */ | ||
57 | #define PWM_CUPD 0x10 /* update CPRD (or CDTY) next period */ | ||
58 | |||
59 | static inline void | ||
60 | pwm_channel_writel(struct pwm_channel *pwmc, unsigned offset, u32 val) | ||
61 | { | ||
62 | __raw_writel(val, pwmc->regs + offset); | ||
63 | } | ||
64 | |||
65 | static inline u32 pwm_channel_readl(struct pwm_channel *pwmc, unsigned offset) | ||
66 | { | ||
67 | return __raw_readl(pwmc->regs + offset); | ||
68 | } | ||
69 | |||
70 | #endif /* __LINUX_ATMEL_PWM_H */ | ||