diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-22 12:18:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-22 12:18:17 -0400 |
commit | 7d2b6ef19cf0f98cef17aa5185de3631a618710a (patch) | |
tree | d4e87f3c47837fef59ef15273f89f68b73d963af /drivers/bus | |
parent | 5c73cc4b6c83e88863a5de869cc5df3b913aef4a (diff) | |
parent | 7415d97ee2b809119270fc3a365968ff8d4f544b (diff) |
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Olof Johansson:
"Driver updates for v4.1. Some of these are for drivers/soc, where we
find more and more SoC-specific drivers these days. Some are for
other driver subsystems where we have received acks from the
appropriate maintainers.
The larger parts of this branch are:
- MediaTek support for their PMIC wrapper interface, a high-level
interface for talking to the system PMIC over a dedicated I2C
interface.
- Qualcomm SCM driver has been moved to drivers/firmware. It's used
for CPU up/down and needs to be in a shared location for arm/arm64
common code.
- cleanup of ARM-CCI PMU code.
- another set of cleanusp to the OMAP GPMC code"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (43 commits)
soc/mediatek: Remove unused variables
clocksource: atmel-st: select MFD_SYSCON
soc: mediatek: Add PMIC wrapper for MT8135 and MT8173 SoCs
arm-cci: Fix CCI PMU event validation
arm-cci: Split the code for PMU vs driver support
arm-cci: Get rid of secure transactions for PMU driver
arm-cci: Abstract the CCI400 PMU specific definitions
arm-cci: Rearrange code for splitting PMU vs driver code
drivers: cci: reject groups spanning multiple HW PMUs
ARM: at91: remove useless include
clocksource: atmel-st: remove mach/hardware dependency
clocksource: atmel-st: use syscon/regmap
ARM: at91: time: move the system timer driver to drivers/clocksource
ARM: at91: properly initialize timer
ARM: at91: at91rm9200: remove deprecated arm_pm_restart
watchdog: at91rm9200: implement restart handler
watchdog: at91rm9200: use the system timer syscon
mfd: syscon: Add atmel system timer registers definition
ARM: at91/dt: declare atmel,at91rm9200-st as a syscon
soc: qcom: gsbi: Add support for ADM CRCI muxing
...
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/Kconfig | 73 | ||||
-rw-r--r-- | drivers/bus/Makefile | 17 | ||||
-rw-r--r-- | drivers/bus/arm-cci.c | 517 | ||||
-rw-r--r-- | drivers/bus/simple-pm-bus.c | 58 |
4 files changed, 410 insertions, 255 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index cbddbaddb347..a1d4af6df3f5 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig | |||
@@ -4,6 +4,41 @@ | |||
4 | 4 | ||
5 | menu "Bus devices" | 5 | menu "Bus devices" |
6 | 6 | ||
7 | config ARM_CCI | ||
8 | bool | ||
9 | |||
10 | config ARM_CCI400_COMMON | ||
11 | bool | ||
12 | select ARM_CCI | ||
13 | |||
14 | config ARM_CCI400_PMU | ||
15 | bool "ARM CCI400 PMU support" | ||
16 | default y | ||
17 | depends on ARM || ARM64 | ||
18 | depends on HW_PERF_EVENTS | ||
19 | select ARM_CCI400_COMMON | ||
20 | help | ||
21 | Support for PMU events monitoring on the ARM CCI cache coherent | ||
22 | interconnect. | ||
23 | |||
24 | If unsure, say Y | ||
25 | |||
26 | config ARM_CCI400_PORT_CTRL | ||
27 | bool | ||
28 | depends on ARM && OF && CPU_V7 | ||
29 | select ARM_CCI400_COMMON | ||
30 | help | ||
31 | Low level power management driver for CCI400 cache coherent | ||
32 | interconnect for ARM platforms. | ||
33 | |||
34 | config ARM_CCN | ||
35 | bool "ARM CCN driver support" | ||
36 | depends on ARM || ARM64 | ||
37 | depends on PERF_EVENTS | ||
38 | help | ||
39 | PMU (perf) driver supporting the ARM CCN (Cache Coherent Network) | ||
40 | interconnect. | ||
41 | |||
7 | config BRCMSTB_GISB_ARB | 42 | config BRCMSTB_GISB_ARB |
8 | bool "Broadcom STB GISB bus arbiter" | 43 | bool "Broadcom STB GISB bus arbiter" |
9 | depends on ARM || MIPS | 44 | depends on ARM || MIPS |
@@ -40,15 +75,6 @@ config MVEBU_MBUS | |||
40 | Driver needed for the MBus configuration on Marvell EBU SoCs | 75 | Driver needed for the MBus configuration on Marvell EBU SoCs |
41 | (Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP). | 76 | (Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP). |
42 | 77 | ||
43 | config OMAP_OCP2SCP | ||
44 | tristate "OMAP OCP2SCP DRIVER" | ||
45 | depends on ARCH_OMAP2PLUS | ||
46 | help | ||
47 | Driver to enable ocp2scp module which transforms ocp interface | ||
48 | protocol to scp protocol. In OMAP4, USB PHY is connected via | ||
49 | OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via | ||
50 | OCP2SCP. | ||
51 | |||
52 | config OMAP_INTERCONNECT | 78 | config OMAP_INTERCONNECT |
53 | tristate "OMAP INTERCONNECT DRIVER" | 79 | tristate "OMAP INTERCONNECT DRIVER" |
54 | depends on ARCH_OMAP2PLUS | 80 | depends on ARCH_OMAP2PLUS |
@@ -56,20 +82,27 @@ config OMAP_INTERCONNECT | |||
56 | help | 82 | help |
57 | Driver to enable OMAP interconnect error handling driver. | 83 | Driver to enable OMAP interconnect error handling driver. |
58 | 84 | ||
59 | config ARM_CCI | 85 | config OMAP_OCP2SCP |
60 | bool "ARM CCI driver support" | 86 | tristate "OMAP OCP2SCP DRIVER" |
61 | depends on ARM && OF && CPU_V7 | 87 | depends on ARCH_OMAP2PLUS |
62 | help | 88 | help |
63 | Driver supporting the CCI cache coherent interconnect for ARM | 89 | Driver to enable ocp2scp module which transforms ocp interface |
64 | platforms. | 90 | protocol to scp protocol. In OMAP4, USB PHY is connected via |
91 | OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via | ||
92 | OCP2SCP. | ||
65 | 93 | ||
66 | config ARM_CCN | 94 | config SIMPLE_PM_BUS |
67 | bool "ARM CCN driver support" | 95 | bool "Simple Power-Managed Bus Driver" |
68 | depends on ARM || ARM64 | 96 | depends on OF && PM |
69 | depends on PERF_EVENTS | 97 | depends on ARCH_SHMOBILE || COMPILE_TEST |
70 | help | 98 | help |
71 | PMU (perf) driver supporting the ARM CCN (Cache Coherent Network) | 99 | Driver for transparent busses that don't need a real driver, but |
72 | interconnect. | 100 | where the bus controller is part of a PM domain, or under the control |
101 | of a functional clock, and thus relies on runtime PM for managing | ||
102 | this PM domain and/or clock. | ||
103 | An example of such a bus controller is the Renesas Bus State | ||
104 | Controller (BSC, sometimes called "LBSC within Bus Bridge", or | ||
105 | "External Bus Interface") as found on several Renesas ARM SoCs. | ||
73 | 106 | ||
74 | config VEXPRESS_CONFIG | 107 | config VEXPRESS_CONFIG |
75 | bool "Versatile Express configuration bus" | 108 | bool "Versatile Express configuration bus" |
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 807dd17ef2f8..790e7b933fb2 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile | |||
@@ -2,17 +2,18 @@ | |||
2 | # Makefile for the bus drivers. | 2 | # Makefile for the bus drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | # Interconnect bus drivers for ARM platforms | ||
6 | obj-$(CONFIG_ARM_CCI) += arm-cci.o | ||
7 | obj-$(CONFIG_ARM_CCN) += arm-ccn.o | ||
8 | |||
5 | obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o | 9 | obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o |
6 | obj-$(CONFIG_IMX_WEIM) += imx-weim.o | 10 | obj-$(CONFIG_IMX_WEIM) += imx-weim.o |
7 | obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o | 11 | obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o |
8 | obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o | 12 | obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o |
9 | obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o | ||
10 | 13 | ||
11 | # Interconnect bus driver for OMAP SoCs. | 14 | # Interconnect bus driver for OMAP SoCs. |
12 | obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o | 15 | obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o |
13 | 16 | ||
14 | # Interconnect bus drivers for ARM platforms | 17 | obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o |
15 | obj-$(CONFIG_ARM_CCI) += arm-cci.o | 18 | obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o |
16 | obj-$(CONFIG_ARM_CCN) += arm-ccn.o | ||
17 | |||
18 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o | 19 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o |
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 84fd66057dad..b854125e4831 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c | |||
@@ -29,41 +29,36 @@ | |||
29 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
30 | #include <asm/smp_plat.h> | 30 | #include <asm/smp_plat.h> |
31 | 31 | ||
32 | #define DRIVER_NAME "CCI-400" | 32 | static void __iomem *cci_ctrl_base; |
33 | #define DRIVER_NAME_PMU DRIVER_NAME " PMU" | 33 | static unsigned long cci_ctrl_phys; |
34 | |||
35 | #define CCI_PORT_CTRL 0x0 | ||
36 | #define CCI_CTRL_STATUS 0xc | ||
37 | |||
38 | #define CCI_ENABLE_SNOOP_REQ 0x1 | ||
39 | #define CCI_ENABLE_DVM_REQ 0x2 | ||
40 | #define CCI_ENABLE_REQ (CCI_ENABLE_SNOOP_REQ | CCI_ENABLE_DVM_REQ) | ||
41 | 34 | ||
35 | #ifdef CONFIG_ARM_CCI400_PORT_CTRL | ||
42 | struct cci_nb_ports { | 36 | struct cci_nb_ports { |
43 | unsigned int nb_ace; | 37 | unsigned int nb_ace; |
44 | unsigned int nb_ace_lite; | 38 | unsigned int nb_ace_lite; |
45 | }; | 39 | }; |
46 | 40 | ||
47 | enum cci_ace_port_type { | 41 | static const struct cci_nb_ports cci400_ports = { |
48 | ACE_INVALID_PORT = 0x0, | 42 | .nb_ace = 2, |
49 | ACE_PORT, | 43 | .nb_ace_lite = 3 |
50 | ACE_LITE_PORT, | ||
51 | }; | 44 | }; |
52 | 45 | ||
53 | struct cci_ace_port { | 46 | #define CCI400_PORTS_DATA (&cci400_ports) |
54 | void __iomem *base; | 47 | #else |
55 | unsigned long phys; | 48 | #define CCI400_PORTS_DATA (NULL) |
56 | enum cci_ace_port_type type; | 49 | #endif |
57 | struct device_node *dn; | ||
58 | }; | ||
59 | 50 | ||
60 | static struct cci_ace_port *ports; | 51 | static const struct of_device_id arm_cci_matches[] = { |
61 | static unsigned int nb_cci_ports; | 52 | #ifdef CONFIG_ARM_CCI400_COMMON |
53 | {.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA }, | ||
54 | #endif | ||
55 | {}, | ||
56 | }; | ||
62 | 57 | ||
63 | static void __iomem *cci_ctrl_base; | 58 | #ifdef CONFIG_ARM_CCI400_PMU |
64 | static unsigned long cci_ctrl_phys; | ||
65 | 59 | ||
66 | #ifdef CONFIG_HW_PERF_EVENTS | 60 | #define DRIVER_NAME "CCI-400" |
61 | #define DRIVER_NAME_PMU DRIVER_NAME " PMU" | ||
67 | 62 | ||
68 | #define CCI_PMCR 0x0100 | 63 | #define CCI_PMCR 0x0100 |
69 | #define CCI_PID2 0x0fe8 | 64 | #define CCI_PID2 0x0fe8 |
@@ -75,20 +70,6 @@ static unsigned long cci_ctrl_phys; | |||
75 | #define CCI_PID2_REV_MASK 0xf0 | 70 | #define CCI_PID2_REV_MASK 0xf0 |
76 | #define CCI_PID2_REV_SHIFT 4 | 71 | #define CCI_PID2_REV_SHIFT 4 |
77 | 72 | ||
78 | /* Port ids */ | ||
79 | #define CCI_PORT_S0 0 | ||
80 | #define CCI_PORT_S1 1 | ||
81 | #define CCI_PORT_S2 2 | ||
82 | #define CCI_PORT_S3 3 | ||
83 | #define CCI_PORT_S4 4 | ||
84 | #define CCI_PORT_M0 5 | ||
85 | #define CCI_PORT_M1 6 | ||
86 | #define CCI_PORT_M2 7 | ||
87 | |||
88 | #define CCI_REV_R0 0 | ||
89 | #define CCI_REV_R1 1 | ||
90 | #define CCI_REV_R1_PX 5 | ||
91 | |||
92 | #define CCI_PMU_EVT_SEL 0x000 | 73 | #define CCI_PMU_EVT_SEL 0x000 |
93 | #define CCI_PMU_CNTR 0x004 | 74 | #define CCI_PMU_CNTR 0x004 |
94 | #define CCI_PMU_CNTR_CTRL 0x008 | 75 | #define CCI_PMU_CNTR_CTRL 0x008 |
@@ -100,76 +81,22 @@ static unsigned long cci_ctrl_phys; | |||
100 | 81 | ||
101 | #define CCI_PMU_CNTR_MASK ((1ULL << 32) -1) | 82 | #define CCI_PMU_CNTR_MASK ((1ULL << 32) -1) |
102 | 83 | ||
103 | /* | 84 | #define CCI_PMU_EVENT_MASK 0xffUL |
104 | * Instead of an event id to monitor CCI cycles, a dedicated counter is | ||
105 | * provided. Use 0xff to represent CCI cycles and hope that no future revisions | ||
106 | * make use of this event in hardware. | ||
107 | */ | ||
108 | enum cci400_perf_events { | ||
109 | CCI_PMU_CYCLES = 0xff | ||
110 | }; | ||
111 | |||
112 | #define CCI_PMU_EVENT_MASK 0xff | ||
113 | #define CCI_PMU_EVENT_SOURCE(event) ((event >> 5) & 0x7) | 85 | #define CCI_PMU_EVENT_SOURCE(event) ((event >> 5) & 0x7) |
114 | #define CCI_PMU_EVENT_CODE(event) (event & 0x1f) | 86 | #define CCI_PMU_EVENT_CODE(event) (event & 0x1f) |
115 | 87 | ||
116 | #define CCI_PMU_MAX_HW_EVENTS 5 /* CCI PMU has 4 counters + 1 cycle counter */ | 88 | #define CCI_PMU_MAX_HW_EVENTS 5 /* CCI PMU has 4 counters + 1 cycle counter */ |
117 | 89 | ||
118 | #define CCI_PMU_CYCLE_CNTR_IDX 0 | 90 | /* Types of interfaces that can generate events */ |
119 | #define CCI_PMU_CNTR0_IDX 1 | 91 | enum { |
120 | #define CCI_PMU_CNTR_LAST(cci_pmu) (CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1) | 92 | CCI_IF_SLAVE, |
121 | 93 | CCI_IF_MASTER, | |
122 | /* | 94 | CCI_IF_MAX, |
123 | * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8 | ||
124 | * ports and bits 4:0 are event codes. There are different event codes | ||
125 | * associated with each port type. | ||
126 | * | ||
127 | * Additionally, the range of events associated with the port types changed | ||
128 | * between Rev0 and Rev1. | ||
129 | * | ||
130 | * The constants below define the range of valid codes for each port type for | ||
131 | * the different revisions and are used to validate the event to be monitored. | ||
132 | */ | ||
133 | |||
134 | #define CCI_REV_R0_SLAVE_PORT_MIN_EV 0x00 | ||
135 | #define CCI_REV_R0_SLAVE_PORT_MAX_EV 0x13 | ||
136 | #define CCI_REV_R0_MASTER_PORT_MIN_EV 0x14 | ||
137 | #define CCI_REV_R0_MASTER_PORT_MAX_EV 0x1a | ||
138 | |||
139 | #define CCI_REV_R1_SLAVE_PORT_MIN_EV 0x00 | ||
140 | #define CCI_REV_R1_SLAVE_PORT_MAX_EV 0x14 | ||
141 | #define CCI_REV_R1_MASTER_PORT_MIN_EV 0x00 | ||
142 | #define CCI_REV_R1_MASTER_PORT_MAX_EV 0x11 | ||
143 | |||
144 | struct pmu_port_event_ranges { | ||
145 | u8 slave_min; | ||
146 | u8 slave_max; | ||
147 | u8 master_min; | ||
148 | u8 master_max; | ||
149 | }; | ||
150 | |||
151 | static struct pmu_port_event_ranges port_event_range[] = { | ||
152 | [CCI_REV_R0] = { | ||
153 | .slave_min = CCI_REV_R0_SLAVE_PORT_MIN_EV, | ||
154 | .slave_max = CCI_REV_R0_SLAVE_PORT_MAX_EV, | ||
155 | .master_min = CCI_REV_R0_MASTER_PORT_MIN_EV, | ||
156 | .master_max = CCI_REV_R0_MASTER_PORT_MAX_EV, | ||
157 | }, | ||
158 | [CCI_REV_R1] = { | ||
159 | .slave_min = CCI_REV_R1_SLAVE_PORT_MIN_EV, | ||
160 | .slave_max = CCI_REV_R1_SLAVE_PORT_MAX_EV, | ||
161 | .master_min = CCI_REV_R1_MASTER_PORT_MIN_EV, | ||
162 | .master_max = CCI_REV_R1_MASTER_PORT_MAX_EV, | ||
163 | }, | ||
164 | }; | 95 | }; |
165 | 96 | ||
166 | /* | 97 | struct event_range { |
167 | * Export different PMU names for the different revisions so userspace knows | 98 | u32 min; |
168 | * because the event ids are different | 99 | u32 max; |
169 | */ | ||
170 | static char *const pmu_names[] = { | ||
171 | [CCI_REV_R0] = "CCI_400", | ||
172 | [CCI_REV_R1] = "CCI_400_r1", | ||
173 | }; | 100 | }; |
174 | 101 | ||
175 | struct cci_pmu_hw_events { | 102 | struct cci_pmu_hw_events { |
@@ -178,13 +105,20 @@ struct cci_pmu_hw_events { | |||
178 | raw_spinlock_t pmu_lock; | 105 | raw_spinlock_t pmu_lock; |
179 | }; | 106 | }; |
180 | 107 | ||
108 | struct cci_pmu_model { | ||
109 | char *name; | ||
110 | struct event_range event_ranges[CCI_IF_MAX]; | ||
111 | }; | ||
112 | |||
113 | static struct cci_pmu_model cci_pmu_models[]; | ||
114 | |||
181 | struct cci_pmu { | 115 | struct cci_pmu { |
182 | void __iomem *base; | 116 | void __iomem *base; |
183 | struct pmu pmu; | 117 | struct pmu pmu; |
184 | int nr_irqs; | 118 | int nr_irqs; |
185 | int irqs[CCI_PMU_MAX_HW_EVENTS]; | 119 | int irqs[CCI_PMU_MAX_HW_EVENTS]; |
186 | unsigned long active_irqs; | 120 | unsigned long active_irqs; |
187 | struct pmu_port_event_ranges *port_ranges; | 121 | const struct cci_pmu_model *model; |
188 | struct cci_pmu_hw_events hw_events; | 122 | struct cci_pmu_hw_events hw_events; |
189 | struct platform_device *plat_device; | 123 | struct platform_device *plat_device; |
190 | int num_events; | 124 | int num_events; |
@@ -196,52 +130,63 @@ static struct cci_pmu *pmu; | |||
196 | 130 | ||
197 | #define to_cci_pmu(c) (container_of(c, struct cci_pmu, pmu)) | 131 | #define to_cci_pmu(c) (container_of(c, struct cci_pmu, pmu)) |
198 | 132 | ||
199 | static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs) | 133 | /* Port ids */ |
200 | { | 134 | #define CCI_PORT_S0 0 |
201 | int i; | 135 | #define CCI_PORT_S1 1 |
202 | 136 | #define CCI_PORT_S2 2 | |
203 | for (i = 0; i < nr_irqs; i++) | 137 | #define CCI_PORT_S3 3 |
204 | if (irq == irqs[i]) | 138 | #define CCI_PORT_S4 4 |
205 | return true; | 139 | #define CCI_PORT_M0 5 |
206 | 140 | #define CCI_PORT_M1 6 | |
207 | return false; | 141 | #define CCI_PORT_M2 7 |
208 | } | ||
209 | 142 | ||
210 | static int probe_cci_revision(void) | 143 | #define CCI_REV_R0 0 |
211 | { | 144 | #define CCI_REV_R1 1 |
212 | int rev; | 145 | #define CCI_REV_R1_PX 5 |
213 | rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK; | ||
214 | rev >>= CCI_PID2_REV_SHIFT; | ||
215 | 146 | ||
216 | if (rev < CCI_REV_R1_PX) | 147 | /* |
217 | return CCI_REV_R0; | 148 | * Instead of an event id to monitor CCI cycles, a dedicated counter is |
218 | else | 149 | * provided. Use 0xff to represent CCI cycles and hope that no future revisions |
219 | return CCI_REV_R1; | 150 | * make use of this event in hardware. |
220 | } | 151 | */ |
152 | enum cci400_perf_events { | ||
153 | CCI_PMU_CYCLES = 0xff | ||
154 | }; | ||
221 | 155 | ||
222 | static struct pmu_port_event_ranges *port_range_by_rev(void) | 156 | #define CCI_PMU_CYCLE_CNTR_IDX 0 |
223 | { | 157 | #define CCI_PMU_CNTR0_IDX 1 |
224 | int rev = probe_cci_revision(); | 158 | #define CCI_PMU_CNTR_LAST(cci_pmu) (CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1) |
225 | 159 | ||
226 | return &port_event_range[rev]; | 160 | /* |
227 | } | 161 | * CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8 |
162 | * ports and bits 4:0 are event codes. There are different event codes | ||
163 | * associated with each port type. | ||
164 | * | ||
165 | * Additionally, the range of events associated with the port types changed | ||
166 | * between Rev0 and Rev1. | ||
167 | * | ||
168 | * The constants below define the range of valid codes for each port type for | ||
169 | * the different revisions and are used to validate the event to be monitored. | ||
170 | */ | ||
228 | 171 | ||
229 | static int pmu_is_valid_slave_event(u8 ev_code) | 172 | #define CCI_REV_R0_SLAVE_PORT_MIN_EV 0x00 |
230 | { | 173 | #define CCI_REV_R0_SLAVE_PORT_MAX_EV 0x13 |
231 | return pmu->port_ranges->slave_min <= ev_code && | 174 | #define CCI_REV_R0_MASTER_PORT_MIN_EV 0x14 |
232 | ev_code <= pmu->port_ranges->slave_max; | 175 | #define CCI_REV_R0_MASTER_PORT_MAX_EV 0x1a |
233 | } | ||
234 | 176 | ||
235 | static int pmu_is_valid_master_event(u8 ev_code) | 177 | #define CCI_REV_R1_SLAVE_PORT_MIN_EV 0x00 |
236 | { | 178 | #define CCI_REV_R1_SLAVE_PORT_MAX_EV 0x14 |
237 | return pmu->port_ranges->master_min <= ev_code && | 179 | #define CCI_REV_R1_MASTER_PORT_MIN_EV 0x00 |
238 | ev_code <= pmu->port_ranges->master_max; | 180 | #define CCI_REV_R1_MASTER_PORT_MAX_EV 0x11 |
239 | } | ||
240 | 181 | ||
241 | static int pmu_validate_hw_event(u8 hw_event) | 182 | static int pmu_validate_hw_event(unsigned long hw_event) |
242 | { | 183 | { |
243 | u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event); | 184 | u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event); |
244 | u8 ev_code = CCI_PMU_EVENT_CODE(hw_event); | 185 | u8 ev_code = CCI_PMU_EVENT_CODE(hw_event); |
186 | int if_type; | ||
187 | |||
188 | if (hw_event & ~CCI_PMU_EVENT_MASK) | ||
189 | return -ENOENT; | ||
245 | 190 | ||
246 | switch (ev_source) { | 191 | switch (ev_source) { |
247 | case CCI_PORT_S0: | 192 | case CCI_PORT_S0: |
@@ -250,21 +195,44 @@ static int pmu_validate_hw_event(u8 hw_event) | |||
250 | case CCI_PORT_S3: | 195 | case CCI_PORT_S3: |
251 | case CCI_PORT_S4: | 196 | case CCI_PORT_S4: |
252 | /* Slave Interface */ | 197 | /* Slave Interface */ |
253 | if (pmu_is_valid_slave_event(ev_code)) | 198 | if_type = CCI_IF_SLAVE; |
254 | return hw_event; | ||
255 | break; | 199 | break; |
256 | case CCI_PORT_M0: | 200 | case CCI_PORT_M0: |
257 | case CCI_PORT_M1: | 201 | case CCI_PORT_M1: |
258 | case CCI_PORT_M2: | 202 | case CCI_PORT_M2: |
259 | /* Master Interface */ | 203 | /* Master Interface */ |
260 | if (pmu_is_valid_master_event(ev_code)) | 204 | if_type = CCI_IF_MASTER; |
261 | return hw_event; | ||
262 | break; | 205 | break; |
206 | default: | ||
207 | return -ENOENT; | ||
263 | } | 208 | } |
264 | 209 | ||
210 | if (ev_code >= pmu->model->event_ranges[if_type].min && | ||
211 | ev_code <= pmu->model->event_ranges[if_type].max) | ||
212 | return hw_event; | ||
213 | |||
265 | return -ENOENT; | 214 | return -ENOENT; |
266 | } | 215 | } |
267 | 216 | ||
217 | static int probe_cci_revision(void) | ||
218 | { | ||
219 | int rev; | ||
220 | rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK; | ||
221 | rev >>= CCI_PID2_REV_SHIFT; | ||
222 | |||
223 | if (rev < CCI_REV_R1_PX) | ||
224 | return CCI_REV_R0; | ||
225 | else | ||
226 | return CCI_REV_R1; | ||
227 | } | ||
228 | |||
229 | static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev) | ||
230 | { | ||
231 | if (platform_has_secure_cci_access()) | ||
232 | return &cci_pmu_models[probe_cci_revision()]; | ||
233 | return NULL; | ||
234 | } | ||
235 | |||
268 | static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx) | 236 | static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx) |
269 | { | 237 | { |
270 | return CCI_PMU_CYCLE_CNTR_IDX <= idx && | 238 | return CCI_PMU_CYCLE_CNTR_IDX <= idx && |
@@ -293,7 +261,6 @@ static void pmu_enable_counter(int idx) | |||
293 | 261 | ||
294 | static void pmu_set_event(int idx, unsigned long event) | 262 | static void pmu_set_event(int idx, unsigned long event) |
295 | { | 263 | { |
296 | event &= CCI_PMU_EVENT_MASK; | ||
297 | pmu_write_register(event, idx, CCI_PMU_EVT_SEL); | 264 | pmu_write_register(event, idx, CCI_PMU_EVT_SEL); |
298 | } | 265 | } |
299 | 266 | ||
@@ -310,7 +277,7 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev | |||
310 | { | 277 | { |
311 | struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu); | 278 | struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu); |
312 | struct hw_perf_event *hw_event = &event->hw; | 279 | struct hw_perf_event *hw_event = &event->hw; |
313 | unsigned long cci_event = hw_event->config_base & CCI_PMU_EVENT_MASK; | 280 | unsigned long cci_event = hw_event->config_base; |
314 | int idx; | 281 | int idx; |
315 | 282 | ||
316 | if (cci_event == CCI_PMU_CYCLES) { | 283 | if (cci_event == CCI_PMU_CYCLES) { |
@@ -331,7 +298,7 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev | |||
331 | static int pmu_map_event(struct perf_event *event) | 298 | static int pmu_map_event(struct perf_event *event) |
332 | { | 299 | { |
333 | int mapping; | 300 | int mapping; |
334 | u8 config = event->attr.config & CCI_PMU_EVENT_MASK; | 301 | unsigned long config = event->attr.config; |
335 | 302 | ||
336 | if (event->attr.type < PERF_TYPE_MAX) | 303 | if (event->attr.type < PERF_TYPE_MAX) |
337 | return -ENOENT; | 304 | return -ENOENT; |
@@ -660,12 +627,21 @@ static void cci_pmu_del(struct perf_event *event, int flags) | |||
660 | } | 627 | } |
661 | 628 | ||
662 | static int | 629 | static int |
663 | validate_event(struct cci_pmu_hw_events *hw_events, | 630 | validate_event(struct pmu *cci_pmu, |
664 | struct perf_event *event) | 631 | struct cci_pmu_hw_events *hw_events, |
632 | struct perf_event *event) | ||
665 | { | 633 | { |
666 | if (is_software_event(event)) | 634 | if (is_software_event(event)) |
667 | return 1; | 635 | return 1; |
668 | 636 | ||
637 | /* | ||
638 | * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The | ||
639 | * core perf code won't check that the pmu->ctx == leader->ctx | ||
640 | * until after pmu->event_init(event). | ||
641 | */ | ||
642 | if (event->pmu != cci_pmu) | ||
643 | return 0; | ||
644 | |||
669 | if (event->state < PERF_EVENT_STATE_OFF) | 645 | if (event->state < PERF_EVENT_STATE_OFF) |
670 | return 1; | 646 | return 1; |
671 | 647 | ||
@@ -687,15 +663,15 @@ validate_group(struct perf_event *event) | |||
687 | .used_mask = CPU_BITS_NONE, | 663 | .used_mask = CPU_BITS_NONE, |
688 | }; | 664 | }; |
689 | 665 | ||
690 | if (!validate_event(&fake_pmu, leader)) | 666 | if (!validate_event(event->pmu, &fake_pmu, leader)) |
691 | return -EINVAL; | 667 | return -EINVAL; |
692 | 668 | ||
693 | list_for_each_entry(sibling, &leader->sibling_list, group_entry) { | 669 | list_for_each_entry(sibling, &leader->sibling_list, group_entry) { |
694 | if (!validate_event(&fake_pmu, sibling)) | 670 | if (!validate_event(event->pmu, &fake_pmu, sibling)) |
695 | return -EINVAL; | 671 | return -EINVAL; |
696 | } | 672 | } |
697 | 673 | ||
698 | if (!validate_event(&fake_pmu, event)) | 674 | if (!validate_event(event->pmu, &fake_pmu, event)) |
699 | return -EINVAL; | 675 | return -EINVAL; |
700 | 676 | ||
701 | return 0; | 677 | return 0; |
@@ -831,9 +807,9 @@ static const struct attribute_group *pmu_attr_groups[] = { | |||
831 | 807 | ||
832 | static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev) | 808 | static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev) |
833 | { | 809 | { |
834 | char *name = pmu_names[probe_cci_revision()]; | 810 | char *name = cci_pmu->model->name; |
835 | cci_pmu->pmu = (struct pmu) { | 811 | cci_pmu->pmu = (struct pmu) { |
836 | .name = pmu_names[probe_cci_revision()], | 812 | .name = cci_pmu->model->name, |
837 | .task_ctx_nr = perf_invalid_context, | 813 | .task_ctx_nr = perf_invalid_context, |
838 | .pmu_enable = cci_pmu_enable, | 814 | .pmu_enable = cci_pmu_enable, |
839 | .pmu_disable = cci_pmu_disable, | 815 | .pmu_disable = cci_pmu_disable, |
@@ -886,22 +862,93 @@ static struct notifier_block cci_pmu_cpu_nb = { | |||
886 | .priority = CPU_PRI_PERF + 1, | 862 | .priority = CPU_PRI_PERF + 1, |
887 | }; | 863 | }; |
888 | 864 | ||
865 | static struct cci_pmu_model cci_pmu_models[] = { | ||
866 | [CCI_REV_R0] = { | ||
867 | .name = "CCI_400", | ||
868 | .event_ranges = { | ||
869 | [CCI_IF_SLAVE] = { | ||
870 | CCI_REV_R0_SLAVE_PORT_MIN_EV, | ||
871 | CCI_REV_R0_SLAVE_PORT_MAX_EV, | ||
872 | }, | ||
873 | [CCI_IF_MASTER] = { | ||
874 | CCI_REV_R0_MASTER_PORT_MIN_EV, | ||
875 | CCI_REV_R0_MASTER_PORT_MAX_EV, | ||
876 | }, | ||
877 | }, | ||
878 | }, | ||
879 | [CCI_REV_R1] = { | ||
880 | .name = "CCI_400_r1", | ||
881 | .event_ranges = { | ||
882 | [CCI_IF_SLAVE] = { | ||
883 | CCI_REV_R1_SLAVE_PORT_MIN_EV, | ||
884 | CCI_REV_R1_SLAVE_PORT_MAX_EV, | ||
885 | }, | ||
886 | [CCI_IF_MASTER] = { | ||
887 | CCI_REV_R1_MASTER_PORT_MIN_EV, | ||
888 | CCI_REV_R1_MASTER_PORT_MAX_EV, | ||
889 | }, | ||
890 | }, | ||
891 | }, | ||
892 | }; | ||
893 | |||
889 | static const struct of_device_id arm_cci_pmu_matches[] = { | 894 | static const struct of_device_id arm_cci_pmu_matches[] = { |
890 | { | 895 | { |
891 | .compatible = "arm,cci-400-pmu", | 896 | .compatible = "arm,cci-400-pmu", |
897 | .data = NULL, | ||
898 | }, | ||
899 | { | ||
900 | .compatible = "arm,cci-400-pmu,r0", | ||
901 | .data = &cci_pmu_models[CCI_REV_R0], | ||
902 | }, | ||
903 | { | ||
904 | .compatible = "arm,cci-400-pmu,r1", | ||
905 | .data = &cci_pmu_models[CCI_REV_R1], | ||
892 | }, | 906 | }, |
893 | {}, | 907 | {}, |
894 | }; | 908 | }; |
895 | 909 | ||
910 | static inline const struct cci_pmu_model *get_cci_model(struct platform_device *pdev) | ||
911 | { | ||
912 | const struct of_device_id *match = of_match_node(arm_cci_pmu_matches, | ||
913 | pdev->dev.of_node); | ||
914 | if (!match) | ||
915 | return NULL; | ||
916 | if (match->data) | ||
917 | return match->data; | ||
918 | |||
919 | dev_warn(&pdev->dev, "DEPRECATED compatible property," | ||
920 | "requires secure access to CCI registers"); | ||
921 | return probe_cci_model(pdev); | ||
922 | } | ||
923 | |||
924 | static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs) | ||
925 | { | ||
926 | int i; | ||
927 | |||
928 | for (i = 0; i < nr_irqs; i++) | ||
929 | if (irq == irqs[i]) | ||
930 | return true; | ||
931 | |||
932 | return false; | ||
933 | } | ||
934 | |||
896 | static int cci_pmu_probe(struct platform_device *pdev) | 935 | static int cci_pmu_probe(struct platform_device *pdev) |
897 | { | 936 | { |
898 | struct resource *res; | 937 | struct resource *res; |
899 | int i, ret, irq; | 938 | int i, ret, irq; |
939 | const struct cci_pmu_model *model; | ||
940 | |||
941 | model = get_cci_model(pdev); | ||
942 | if (!model) { | ||
943 | dev_warn(&pdev->dev, "CCI PMU version not supported\n"); | ||
944 | return -ENODEV; | ||
945 | } | ||
900 | 946 | ||
901 | pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); | 947 | pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); |
902 | if (!pmu) | 948 | if (!pmu) |
903 | return -ENOMEM; | 949 | return -ENOMEM; |
904 | 950 | ||
951 | pmu->model = model; | ||
905 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 952 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
906 | pmu->base = devm_ioremap_resource(&pdev->dev, res); | 953 | pmu->base = devm_ioremap_resource(&pdev->dev, res); |
907 | if (IS_ERR(pmu->base)) | 954 | if (IS_ERR(pmu->base)) |
@@ -933,12 +980,6 @@ static int cci_pmu_probe(struct platform_device *pdev) | |||
933 | return -EINVAL; | 980 | return -EINVAL; |
934 | } | 981 | } |
935 | 982 | ||
936 | pmu->port_ranges = port_range_by_rev(); | ||
937 | if (!pmu->port_ranges) { | ||
938 | dev_warn(&pdev->dev, "CCI PMU version not supported\n"); | ||
939 | return -EINVAL; | ||
940 | } | ||
941 | |||
942 | raw_spin_lock_init(&pmu->hw_events.pmu_lock); | 983 | raw_spin_lock_init(&pmu->hw_events.pmu_lock); |
943 | mutex_init(&pmu->reserve_mutex); | 984 | mutex_init(&pmu->reserve_mutex); |
944 | atomic_set(&pmu->active_events, 0); | 985 | atomic_set(&pmu->active_events, 0); |
@@ -952,6 +993,7 @@ static int cci_pmu_probe(struct platform_device *pdev) | |||
952 | if (ret) | 993 | if (ret) |
953 | return ret; | 994 | return ret; |
954 | 995 | ||
996 | pr_info("ARM %s PMU driver probed", pmu->model->name); | ||
955 | return 0; | 997 | return 0; |
956 | } | 998 | } |
957 | 999 | ||
@@ -963,7 +1005,66 @@ static int cci_platform_probe(struct platform_device *pdev) | |||
963 | return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); | 1005 | return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); |
964 | } | 1006 | } |
965 | 1007 | ||
966 | #endif /* CONFIG_HW_PERF_EVENTS */ | 1008 | static struct platform_driver cci_pmu_driver = { |
1009 | .driver = { | ||
1010 | .name = DRIVER_NAME_PMU, | ||
1011 | .of_match_table = arm_cci_pmu_matches, | ||
1012 | }, | ||
1013 | .probe = cci_pmu_probe, | ||
1014 | }; | ||
1015 | |||
1016 | static struct platform_driver cci_platform_driver = { | ||
1017 | .driver = { | ||
1018 | .name = DRIVER_NAME, | ||
1019 | .of_match_table = arm_cci_matches, | ||
1020 | }, | ||
1021 | .probe = cci_platform_probe, | ||
1022 | }; | ||
1023 | |||
1024 | static int __init cci_platform_init(void) | ||
1025 | { | ||
1026 | int ret; | ||
1027 | |||
1028 | ret = platform_driver_register(&cci_pmu_driver); | ||
1029 | if (ret) | ||
1030 | return ret; | ||
1031 | |||
1032 | return platform_driver_register(&cci_platform_driver); | ||
1033 | } | ||
1034 | |||
1035 | #else /* !CONFIG_ARM_CCI400_PMU */ | ||
1036 | |||
1037 | static int __init cci_platform_init(void) | ||
1038 | { | ||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | #endif /* CONFIG_ARM_CCI400_PMU */ | ||
1043 | |||
1044 | #ifdef CONFIG_ARM_CCI400_PORT_CTRL | ||
1045 | |||
1046 | #define CCI_PORT_CTRL 0x0 | ||
1047 | #define CCI_CTRL_STATUS 0xc | ||
1048 | |||
1049 | #define CCI_ENABLE_SNOOP_REQ 0x1 | ||
1050 | #define CCI_ENABLE_DVM_REQ 0x2 | ||
1051 | #define CCI_ENABLE_REQ (CCI_ENABLE_SNOOP_REQ | CCI_ENABLE_DVM_REQ) | ||
1052 | |||
1053 | enum cci_ace_port_type { | ||
1054 | ACE_INVALID_PORT = 0x0, | ||
1055 | ACE_PORT, | ||
1056 | ACE_LITE_PORT, | ||
1057 | }; | ||
1058 | |||
1059 | struct cci_ace_port { | ||
1060 | void __iomem *base; | ||
1061 | unsigned long phys; | ||
1062 | enum cci_ace_port_type type; | ||
1063 | struct device_node *dn; | ||
1064 | }; | ||
1065 | |||
1066 | static struct cci_ace_port *ports; | ||
1067 | static unsigned int nb_cci_ports; | ||
967 | 1068 | ||
968 | struct cpu_port { | 1069 | struct cpu_port { |
969 | u64 mpidr; | 1070 | u64 mpidr; |
@@ -1284,36 +1385,20 @@ int notrace __cci_control_port_by_index(u32 port, bool enable) | |||
1284 | } | 1385 | } |
1285 | EXPORT_SYMBOL_GPL(__cci_control_port_by_index); | 1386 | EXPORT_SYMBOL_GPL(__cci_control_port_by_index); |
1286 | 1387 | ||
1287 | static const struct cci_nb_ports cci400_ports = { | ||
1288 | .nb_ace = 2, | ||
1289 | .nb_ace_lite = 3 | ||
1290 | }; | ||
1291 | |||
1292 | static const struct of_device_id arm_cci_matches[] = { | ||
1293 | {.compatible = "arm,cci-400", .data = &cci400_ports }, | ||
1294 | {}, | ||
1295 | }; | ||
1296 | |||
1297 | static const struct of_device_id arm_cci_ctrl_if_matches[] = { | 1388 | static const struct of_device_id arm_cci_ctrl_if_matches[] = { |
1298 | {.compatible = "arm,cci-400-ctrl-if", }, | 1389 | {.compatible = "arm,cci-400-ctrl-if", }, |
1299 | {}, | 1390 | {}, |
1300 | }; | 1391 | }; |
1301 | 1392 | ||
1302 | static int cci_probe(void) | 1393 | static int cci_probe_ports(struct device_node *np) |
1303 | { | 1394 | { |
1304 | struct cci_nb_ports const *cci_config; | 1395 | struct cci_nb_ports const *cci_config; |
1305 | int ret, i, nb_ace = 0, nb_ace_lite = 0; | 1396 | int ret, i, nb_ace = 0, nb_ace_lite = 0; |
1306 | struct device_node *np, *cp; | 1397 | struct device_node *cp; |
1307 | struct resource res; | 1398 | struct resource res; |
1308 | const char *match_str; | 1399 | const char *match_str; |
1309 | bool is_ace; | 1400 | bool is_ace; |
1310 | 1401 | ||
1311 | np = of_find_matching_node(NULL, arm_cci_matches); | ||
1312 | if (!np) | ||
1313 | return -ENODEV; | ||
1314 | |||
1315 | if (!of_device_is_available(np)) | ||
1316 | return -ENODEV; | ||
1317 | 1402 | ||
1318 | cci_config = of_match_node(arm_cci_matches, np)->data; | 1403 | cci_config = of_match_node(arm_cci_matches, np)->data; |
1319 | if (!cci_config) | 1404 | if (!cci_config) |
@@ -1325,17 +1410,6 @@ static int cci_probe(void) | |||
1325 | if (!ports) | 1410 | if (!ports) |
1326 | return -ENOMEM; | 1411 | return -ENOMEM; |
1327 | 1412 | ||
1328 | ret = of_address_to_resource(np, 0, &res); | ||
1329 | if (!ret) { | ||
1330 | cci_ctrl_base = ioremap(res.start, resource_size(&res)); | ||
1331 | cci_ctrl_phys = res.start; | ||
1332 | } | ||
1333 | if (ret || !cci_ctrl_base) { | ||
1334 | WARN(1, "unable to ioremap CCI ctrl\n"); | ||
1335 | ret = -ENXIO; | ||
1336 | goto memalloc_err; | ||
1337 | } | ||
1338 | |||
1339 | for_each_child_of_node(np, cp) { | 1413 | for_each_child_of_node(np, cp) { |
1340 | if (!of_match_node(arm_cci_ctrl_if_matches, cp)) | 1414 | if (!of_match_node(arm_cci_ctrl_if_matches, cp)) |
1341 | continue; | 1415 | continue; |
@@ -1395,12 +1469,37 @@ static int cci_probe(void) | |||
1395 | sync_cache_w(&cpu_port); | 1469 | sync_cache_w(&cpu_port); |
1396 | __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports); | 1470 | __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports); |
1397 | pr_info("ARM CCI driver probed\n"); | 1471 | pr_info("ARM CCI driver probed\n"); |
1472 | |||
1398 | return 0; | 1473 | return 0; |
1474 | } | ||
1475 | #else /* !CONFIG_ARM_CCI400_PORT_CTRL */ | ||
1476 | static inline int cci_probe_ports(struct device_node *np) | ||
1477 | { | ||
1478 | return 0; | ||
1479 | } | ||
1480 | #endif /* CONFIG_ARM_CCI400_PORT_CTRL */ | ||
1399 | 1481 | ||
1400 | memalloc_err: | 1482 | static int cci_probe(void) |
1483 | { | ||
1484 | int ret; | ||
1485 | struct device_node *np; | ||
1486 | struct resource res; | ||
1487 | |||
1488 | np = of_find_matching_node(NULL, arm_cci_matches); | ||
1489 | if(!np || !of_device_is_available(np)) | ||
1490 | return -ENODEV; | ||
1401 | 1491 | ||
1402 | kfree(ports); | 1492 | ret = of_address_to_resource(np, 0, &res); |
1403 | return ret; | 1493 | if (!ret) { |
1494 | cci_ctrl_base = ioremap(res.start, resource_size(&res)); | ||
1495 | cci_ctrl_phys = res.start; | ||
1496 | } | ||
1497 | if (ret || !cci_ctrl_base) { | ||
1498 | WARN(1, "unable to ioremap CCI ctrl\n"); | ||
1499 | return -ENXIO; | ||
1500 | } | ||
1501 | |||
1502 | return cci_probe_ports(np); | ||
1404 | } | 1503 | } |
1405 | 1504 | ||
1406 | static int cci_init_status = -EAGAIN; | 1505 | static int cci_init_status = -EAGAIN; |
@@ -1418,42 +1517,6 @@ static int cci_init(void) | |||
1418 | return cci_init_status; | 1517 | return cci_init_status; |
1419 | } | 1518 | } |
1420 | 1519 | ||
1421 | #ifdef CONFIG_HW_PERF_EVENTS | ||
1422 | static struct platform_driver cci_pmu_driver = { | ||
1423 | .driver = { | ||
1424 | .name = DRIVER_NAME_PMU, | ||
1425 | .of_match_table = arm_cci_pmu_matches, | ||
1426 | }, | ||
1427 | .probe = cci_pmu_probe, | ||
1428 | }; | ||
1429 | |||
1430 | static struct platform_driver cci_platform_driver = { | ||
1431 | .driver = { | ||
1432 | .name = DRIVER_NAME, | ||
1433 | .of_match_table = arm_cci_matches, | ||
1434 | }, | ||
1435 | .probe = cci_platform_probe, | ||
1436 | }; | ||
1437 | |||
1438 | static int __init cci_platform_init(void) | ||
1439 | { | ||
1440 | int ret; | ||
1441 | |||
1442 | ret = platform_driver_register(&cci_pmu_driver); | ||
1443 | if (ret) | ||
1444 | return ret; | ||
1445 | |||
1446 | return platform_driver_register(&cci_platform_driver); | ||
1447 | } | ||
1448 | |||
1449 | #else | ||
1450 | |||
1451 | static int __init cci_platform_init(void) | ||
1452 | { | ||
1453 | return 0; | ||
1454 | } | ||
1455 | |||
1456 | #endif | ||
1457 | /* | 1520 | /* |
1458 | * To sort out early init calls ordering a helper function is provided to | 1521 | * To sort out early init calls ordering a helper function is provided to |
1459 | * check if the CCI driver has beed initialized. Function check if the driver | 1522 | * check if the CCI driver has beed initialized. Function check if the driver |
diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c new file mode 100644 index 000000000000..c5eb46cbf388 --- /dev/null +++ b/drivers/bus/simple-pm-bus.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Simple Power-Managed Bus Driver | ||
3 | * | ||
4 | * Copyright (C) 2014-2015 Glider bvba | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/of_platform.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/pm_runtime.h> | ||
15 | |||
16 | |||
17 | static int simple_pm_bus_probe(struct platform_device *pdev) | ||
18 | { | ||
19 | struct device_node *np = pdev->dev.of_node; | ||
20 | |||
21 | dev_dbg(&pdev->dev, "%s\n", __func__); | ||
22 | |||
23 | pm_runtime_enable(&pdev->dev); | ||
24 | |||
25 | if (np) | ||
26 | of_platform_populate(np, NULL, NULL, &pdev->dev); | ||
27 | |||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | static int simple_pm_bus_remove(struct platform_device *pdev) | ||
32 | { | ||
33 | dev_dbg(&pdev->dev, "%s\n", __func__); | ||
34 | |||
35 | pm_runtime_disable(&pdev->dev); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static const struct of_device_id simple_pm_bus_of_match[] = { | ||
40 | { .compatible = "simple-pm-bus", }, | ||
41 | { /* sentinel */ } | ||
42 | }; | ||
43 | MODULE_DEVICE_TABLE(of, simple_pm_bus_of_match); | ||
44 | |||
45 | static struct platform_driver simple_pm_bus_driver = { | ||
46 | .probe = simple_pm_bus_probe, | ||
47 | .remove = simple_pm_bus_remove, | ||
48 | .driver = { | ||
49 | .name = "simple-pm-bus", | ||
50 | .of_match_table = simple_pm_bus_of_match, | ||
51 | }, | ||
52 | }; | ||
53 | |||
54 | module_platform_driver(simple_pm_bus_driver); | ||
55 | |||
56 | MODULE_DESCRIPTION("Simple Power-Managed Bus Driver"); | ||
57 | MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>"); | ||
58 | MODULE_LICENSE("GPL v2"); | ||