blob: c426ff95cac025dc0c14f1ba150a91029b5e2cb4 [file] [log] [blame]
Ashwin Chaugule39242ba2012-10-29 16:30:05 -04001/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/platform_device.h>
Ashwin Chaugule39242ba2012-10-29 16:30:05 -040014#include <linux/irq.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <asm/pmu.h>
16#include <mach/irqs.h>
Ashwin Chaugule39242ba2012-10-29 16:30:05 -040017#include <mach/socinfo.h>
18
Ashwin Chauguled82ed3a2012-11-05 10:35:30 -050019#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
20 || defined(CONFIG_ARCH_MSM8625)
Ashwin Chaugule39242ba2012-10-29 16:30:05 -040021static DEFINE_PER_CPU(u32, pmu_irq_cookie);
22
23static void enable_irq_callback(void *info)
24{
25 int irq = *(unsigned int *)info;
26 enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
27}
28
29static void disable_irq_callback(void *info)
30{
31 int irq = *(unsigned int *)info;
32 disable_percpu_irq(irq);
33}
34
35static int
36multicore_request_irq(int irq, irq_handler_t *handle_irq)
37{
38 int err = 0;
39 int cpu;
40
41 err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
42 &pmu_irq_cookie);
43
44 if (!err) {
45 for_each_cpu(cpu, cpu_online_mask) {
46 smp_call_function_single(cpu,
47 enable_irq_callback, &irq, 1);
48 }
49 }
50
51 return err;
52}
53
54static void
55multicore_free_irq(int irq)
56{
57 int cpu;
58
59 if (irq >= 0) {
60 for_each_cpu(cpu, cpu_online_mask) {
61 smp_call_function_single(cpu,
62 disable_irq_callback, &irq, 1);
63 }
64 free_percpu_irq(irq, &pmu_irq_cookie);
65 }
66}
67
68static struct arm_pmu_platdata multicore_data = {
69 .request_pmu_irq = multicore_request_irq,
70 .free_pmu_irq = multicore_free_irq,
71};
72#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073
Chintan Pandya9a429932012-02-13 19:14:16 +053074static struct resource cpu_pmu_resource[] = {
75 {
76 .start = INT_ARMQC_PERFMON,
77 .end = INT_ARMQC_PERFMON,
78 .flags = IORESOURCE_IRQ,
79 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070080};
81
82#ifdef CONFIG_CPU_HAS_L2_PMU
Chintan Pandya9a429932012-02-13 19:14:16 +053083static struct resource l2_pmu_resource[] = {
84 {
85 .start = SC_SICL2PERFMONIRPTREQ,
86 .end = SC_SICL2PERFMONIRPTREQ,
87 .flags = IORESOURCE_IRQ,
88 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089};
90
91static struct platform_device l2_pmu_device = {
92 .name = "l2-arm-pmu",
Ashwin Chaugule4a81cb82012-06-07 13:40:54 -040093 .id = ARM_PMU_DEVICE_L2CC,
Chintan Pandya9a429932012-02-13 19:14:16 +053094 .resource = l2_pmu_resource,
95 .num_resources = ARRAY_SIZE(l2_pmu_resource),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096};
97
98#endif
99
100static struct platform_device cpu_pmu_device = {
101 .name = "cpu-arm-pmu",
102 .id = ARM_PMU_DEVICE_CPU,
Chintan Pandya9a429932012-02-13 19:14:16 +0530103 .resource = cpu_pmu_resource,
104 .num_resources = ARRAY_SIZE(cpu_pmu_resource),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105};
106
Ashwin Chauguled82ed3a2012-11-05 10:35:30 -0500107/*
108 * The 8625 is a special case. Due to the requirement of a single
109 * kernel image for the 7x27a and 8625 (which share IRQ headers),
110 * this target breaks the uniformity of IRQ names.
111 * See the file - arch/arm/mach-msm/include/mach/irqs-8625.h
112 */
113#ifdef CONFIG_ARCH_MSM8625
114static struct resource msm8625_cpu_pmu_resource[] = {
115 {
116 .start = MSM8625_INT_ARMQC_PERFMON,
117 .end = MSM8625_INT_ARMQC_PERFMON,
118 .flags = IORESOURCE_IRQ,
119 },
120};
121
122static struct platform_device msm8625_cpu_pmu_device = {
123 .name = "cpu-arm-pmu",
124 .id = ARM_PMU_DEVICE_CPU,
125 .resource = msm8625_cpu_pmu_resource,
126 .num_resources = ARRAY_SIZE(msm8625_cpu_pmu_resource),
127};
128#endif
Ashwin Chaugule39242ba2012-10-29 16:30:05 -0400129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130static struct platform_device *pmu_devices[] = {
131 &cpu_pmu_device,
132#ifdef CONFIG_CPU_HAS_L2_PMU
133 &l2_pmu_device,
134#endif
135};
136
137static int __init msm_pmu_init(void)
138{
Ashwin Chaugule39242ba2012-10-29 16:30:05 -0400139 /*
140 * For the targets we know are multicore's set the request/free IRQ
141 * handlers to call the percpu API.
142 * Defaults to unicore API {request,free}_irq().
143 * See arch/arm/kernel/perf_event.c
144 */
145#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP)
146 cpu_pmu_device.dev.platform_data = &multicore_data;
147#endif
148
Ashwin Chauguled82ed3a2012-11-05 10:35:30 -0500149 /*
150 * The 7x27a and 8625 require a single kernel image.
151 * So we need to check if we're on an 8625 at runtime
152 * and point to the appropriate 'struct resource'.
153 */
154#ifdef CONFIG_ARCH_MSM8625
155 if (cpu_is_msm8625()) {
156 pmu_devices[0] = &msm8625_cpu_pmu_device;
157 msm8625_cpu_pmu_device.dev.platform_data = &multicore_data;
158 }
159#endif
160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 return platform_add_devices(pmu_devices, ARRAY_SIZE(pmu_devices));
162}
163
164arch_initcall(msm_pmu_init);