blob: 0cc22726c2f2df6d99336442000b53176eae5089 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
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
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/types.h>
18#include <linux/bug.h>
19#include <linux/mutex.h>
20#include <linux/proc_fs.h>
21#include <linux/spinlock.h>
22#include <linux/cpu.h>
23#include <mach/rpm.h>
24#include <mach/msm_iomap.h>
25#include <asm/mach-types.h>
26#include <linux/io.h>
Praveen Chidambaram841d46c2011-08-04 09:07:53 -060027#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include "mpm.h"
29#include "rpm_resources.h"
30#include "spm.h"
Maheshkumar Sivasubramaniana012e092011-08-18 10:13:03 -060031#include "idle.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032
33/******************************************************************************
34 * Debug Definitions
35 *****************************************************************************/
36
37enum {
38 MSM_RPMRS_DEBUG_OUTPUT = BIT(0),
39 MSM_RPMRS_DEBUG_BUFFER = BIT(1),
40};
41
42static int msm_rpmrs_debug_mask;
43module_param_named(
44 debug_mask, msm_rpmrs_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
45);
46
47static struct msm_rpmrs_level *msm_rpmrs_levels;
48static int msm_rpmrs_level_count;
49
50static bool msm_rpmrs_pxo_beyond_limits(struct msm_rpmrs_limits *limits);
51static void msm_rpmrs_aggregate_pxo(struct msm_rpmrs_limits *limits);
52static void msm_rpmrs_restore_pxo(void);
53static bool msm_rpmrs_l2_cache_beyond_limits(struct msm_rpmrs_limits *limits);
54static void msm_rpmrs_aggregate_l2_cache(struct msm_rpmrs_limits *limits);
55static void msm_rpmrs_restore_l2_cache(void);
56static bool msm_rpmrs_vdd_mem_beyond_limits(struct msm_rpmrs_limits *limits);
57static void msm_rpmrs_aggregate_vdd_mem(struct msm_rpmrs_limits *limits);
58static void msm_rpmrs_restore_vdd_mem(void);
59static bool msm_rpmrs_vdd_dig_beyond_limits(struct msm_rpmrs_limits *limits);
60static void msm_rpmrs_aggregate_vdd_dig(struct msm_rpmrs_limits *limits);
61static void msm_rpmrs_restore_vdd_dig(void);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062
Praveen Chidambaram66775c62011-08-04 16:59:24 -060063static ssize_t msm_rpmrs_resource_attr_show(
64 struct kobject *kobj, struct kobj_attribute *attr, char *buf);
65static ssize_t msm_rpmrs_resource_attr_store(struct kobject *kobj,
66 struct kobj_attribute *attr, const char *buf, size_t count);
67
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068static void *msm_rpmrs_l2_counter_addr;
69static int msm_rpmrs_l2_reset_count;
70#define L2_PC_COUNTER_ADDR 0x660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72#define MSM_RPMRS_MAX_RS_REGISTER_COUNT 2
73
Praveen Chidambaram66775c62011-08-04 16:59:24 -060074#define RPMRS_ATTR(_name) \
75 __ATTR(_name, S_IRUGO|S_IWUSR, \
76 msm_rpmrs_resource_attr_show, msm_rpmrs_resource_attr_store)
77
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070078struct msm_rpmrs_resource {
79 struct msm_rpm_iv_pair rs[MSM_RPMRS_MAX_RS_REGISTER_COUNT];
80 uint32_t size;
81 char *name;
82
83 uint32_t enable_low_power;
84
85 bool (*beyond_limits)(struct msm_rpmrs_limits *limits);
86 void (*aggregate)(struct msm_rpmrs_limits *limits);
87 void (*restore)(void);
Praveen Chidambaram66775c62011-08-04 16:59:24 -060088
89 struct kobj_attribute ko_attr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090};
91
92static struct msm_rpmrs_resource msm_rpmrs_pxo = {
93 .rs[0].id = MSM_RPMRS_ID_PXO_CLK,
94 .size = 1,
95 .name = "pxo",
96 .beyond_limits = msm_rpmrs_pxo_beyond_limits,
97 .aggregate = msm_rpmrs_aggregate_pxo,
98 .restore = msm_rpmrs_restore_pxo,
Praveen Chidambaram66775c62011-08-04 16:59:24 -060099 .ko_attr = RPMRS_ATTR(pxo),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100};
101
102static struct msm_rpmrs_resource msm_rpmrs_l2_cache = {
103 .rs[0].id = MSM_RPMRS_ID_APPS_L2_CACHE_CTL,
104 .size = 1,
105 .name = "L2_cache",
106 .beyond_limits = msm_rpmrs_l2_cache_beyond_limits,
107 .aggregate = msm_rpmrs_aggregate_l2_cache,
108 .restore = msm_rpmrs_restore_l2_cache,
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600109 .ko_attr = RPMRS_ATTR(L2_cache),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110};
111
112static struct msm_rpmrs_resource msm_rpmrs_vdd_mem = {
113 .rs[0].id = MSM_RPMRS_ID_VDD_MEM_0,
114 .rs[1].id = MSM_RPMRS_ID_VDD_MEM_1,
115 .size = 2,
116 .name = "vdd_mem",
117 .beyond_limits = msm_rpmrs_vdd_mem_beyond_limits,
118 .aggregate = msm_rpmrs_aggregate_vdd_mem,
119 .restore = msm_rpmrs_restore_vdd_mem,
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600120 .ko_attr = RPMRS_ATTR(vdd_mem),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121};
122
123static struct msm_rpmrs_resource msm_rpmrs_vdd_dig = {
124 .rs[0].id = MSM_RPMRS_ID_VDD_DIG_0,
125 .rs[1].id = MSM_RPMRS_ID_VDD_DIG_1,
126 .size = 2,
127 .name = "vdd_dig",
128 .beyond_limits = msm_rpmrs_vdd_dig_beyond_limits,
129 .aggregate = msm_rpmrs_aggregate_vdd_dig,
130 .restore = msm_rpmrs_restore_vdd_dig,
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600131 .ko_attr = RPMRS_ATTR(vdd_dig),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132};
133
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600134static struct msm_rpmrs_resource msm_rpmrs_rpm_ctl = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 .rs[0].id = MSM_RPMRS_ID_RPM_CTL,
136 .size = 1,
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600137 .name = "rpm_ctl",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 .beyond_limits = NULL,
Eugene Seah78aa5e72011-07-18 18:28:37 -0600139 .aggregate = NULL,
140 .restore = NULL,
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600141 .ko_attr = RPMRS_ATTR(rpm_ctl),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142};
143
144static struct msm_rpmrs_resource *msm_rpmrs_resources[] = {
145 &msm_rpmrs_pxo,
146 &msm_rpmrs_l2_cache,
147 &msm_rpmrs_vdd_mem,
148 &msm_rpmrs_vdd_dig,
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600149 &msm_rpmrs_rpm_ctl,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150};
151
152static uint32_t msm_rpmrs_buffer[MSM_RPM_ID_LAST + 1];
153static DECLARE_BITMAP(msm_rpmrs_buffered, MSM_RPM_ID_LAST + 1);
154static DECLARE_BITMAP(msm_rpmrs_listed, MSM_RPM_ID_LAST + 1);
155static DEFINE_SPINLOCK(msm_rpmrs_lock);
156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157#define MSM_RPMRS_VDD(v) ((v) & (MSM_RPMRS_VDD_MASK))
158
159/******************************************************************************
160 * Attribute Definitions
161 *****************************************************************************/
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600162static struct attribute *msm_rpmrs_attributes[] = {
163 &msm_rpmrs_pxo.ko_attr.attr,
164 &msm_rpmrs_l2_cache.ko_attr.attr,
165 &msm_rpmrs_vdd_mem.ko_attr.attr,
166 &msm_rpmrs_vdd_dig.ko_attr.attr,
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600167 NULL,
168};
169static struct attribute *msm_rpmrs_mode_attributes[] = {
170 &msm_rpmrs_rpm_ctl.ko_attr.attr,
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600171 NULL,
172};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600174static struct attribute_group msm_rpmrs_attribute_group = {
175 .attrs = msm_rpmrs_attributes,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176};
177
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600178static struct attribute_group msm_rpmrs_mode_attribute_group = {
179 .attrs = msm_rpmrs_mode_attributes,
180};
181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182#define GET_RS_FROM_ATTR(attr) \
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600183 (container_of(attr, struct msm_rpmrs_resource, ko_attr))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185
186/******************************************************************************
187 * Resource Specific Functions
188 *****************************************************************************/
189
190static void msm_rpmrs_aggregate_sclk(uint32_t sclk_count)
191{
192 msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_TO] = 0;
193 set_bit(MSM_RPM_ID_TRIGGER_TIMED_TO, msm_rpmrs_buffered);
194 msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT] = sclk_count;
195 set_bit(MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT, msm_rpmrs_buffered);
196}
197
198static void msm_rpmrs_restore_sclk(void)
199{
200 clear_bit(MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT, msm_rpmrs_buffered);
201 msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_SCLK_COUNT] = 0;
202 clear_bit(MSM_RPM_ID_TRIGGER_TIMED_TO, msm_rpmrs_buffered);
203 msm_rpmrs_buffer[MSM_RPM_ID_TRIGGER_TIMED_TO] = 0;
204}
205
206static bool msm_rpmrs_pxo_beyond_limits(struct msm_rpmrs_limits *limits)
207{
208 struct msm_rpmrs_resource *rs = &msm_rpmrs_pxo;
209 uint32_t pxo;
210
211 if (rs->enable_low_power && test_bit(rs->rs[0].id, msm_rpmrs_buffered))
212 pxo = msm_rpmrs_buffer[rs->rs[0].id];
213 else
214 pxo = MSM_RPMRS_PXO_ON;
215
216 return pxo > limits->pxo;
217}
218
219static void msm_rpmrs_aggregate_pxo(struct msm_rpmrs_limits *limits)
220{
221 struct msm_rpmrs_resource *rs = &msm_rpmrs_pxo;
222 uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
223
224 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
225 rs->rs[0].value = *buf;
226 if (limits->pxo > *buf)
227 *buf = limits->pxo;
228 if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
229 pr_info("%s: %d (0x%x)\n", __func__, *buf, *buf);
230 }
231}
232
233static void msm_rpmrs_restore_pxo(void)
234{
235 struct msm_rpmrs_resource *rs = &msm_rpmrs_pxo;
236
237 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
238 msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
239}
240
241static bool msm_rpmrs_l2_cache_beyond_limits(struct msm_rpmrs_limits *limits)
242{
243 struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
244 uint32_t l2_cache;
245
246 if (rs->enable_low_power && test_bit(rs->rs[0].id, msm_rpmrs_buffered))
247 l2_cache = msm_rpmrs_buffer[rs->rs[0].id];
248 else
249 l2_cache = MSM_RPMRS_L2_CACHE_ACTIVE;
250
251 return l2_cache > limits->l2_cache;
252}
253
254static void msm_rpmrs_aggregate_l2_cache(struct msm_rpmrs_limits *limits)
255{
256 struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
257 uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
258
259 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
260 rs->rs[0].value = *buf;
261 if (limits->l2_cache > *buf)
262 *buf = limits->l2_cache;
263
264 if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
265 pr_info("%s: %d (0x%x)\n", __func__, *buf, *buf);
266 }
267}
268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269static bool msm_spm_l2_cache_beyond_limits(struct msm_rpmrs_limits *limits)
270{
271 struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
272 uint32_t l2_cache = rs->rs[0].value;
273
274 if (!rs->enable_low_power)
275 l2_cache = MSM_RPMRS_L2_CACHE_ACTIVE;
276
277 return l2_cache > limits->l2_cache;
278}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279
280static void msm_rpmrs_restore_l2_cache(void)
281{
282 struct msm_rpmrs_resource *rs = &msm_rpmrs_l2_cache;
283
284 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
285 msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
286}
287
288static bool msm_rpmrs_vdd_mem_beyond_limits(struct msm_rpmrs_limits *limits)
289{
290 struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_mem;
291 uint32_t vdd_mem;
292
293 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
294 uint32_t buffered_value = msm_rpmrs_buffer[rs->rs[0].id];
295
296 if (rs->enable_low_power == 0)
297 vdd_mem = MSM_RPMRS_VDD_MEM_ACTIVE;
298 else if (rs->enable_low_power == 1)
299 vdd_mem = MSM_RPMRS_VDD_MEM_RET_HIGH;
300 else
301 vdd_mem = MSM_RPMRS_VDD_MEM_RET_LOW;
302
303 if (MSM_RPMRS_VDD(buffered_value) > MSM_RPMRS_VDD(vdd_mem))
304 vdd_mem = buffered_value;
305 } else {
306 vdd_mem = MSM_RPMRS_VDD_MEM_ACTIVE;
307 }
308
309 return MSM_RPMRS_VDD(vdd_mem) >=
310 MSM_RPMRS_VDD(limits->vdd_mem_upper_bound);
311}
312
313static void msm_rpmrs_aggregate_vdd_mem(struct msm_rpmrs_limits *limits)
314{
315 struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_mem;
316 uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
317
318 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
319 rs->rs[0].value = *buf;
320 if (MSM_RPMRS_VDD(limits->vdd_mem) > MSM_RPMRS_VDD(*buf)) {
321 *buf &= ~MSM_RPMRS_VDD_MASK;
322 *buf |= MSM_RPMRS_VDD(limits->vdd_mem);
323 }
324
325 if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
326 pr_info("%s: vdd %d (0x%x)\n", __func__,
327 MSM_RPMRS_VDD(*buf), MSM_RPMRS_VDD(*buf));
328 }
329}
330
331static void msm_rpmrs_restore_vdd_mem(void)
332{
333 struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_mem;
334
335 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
336 msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
337}
338
339static bool msm_rpmrs_vdd_dig_beyond_limits(struct msm_rpmrs_limits *limits)
340{
341 struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_dig;
342 uint32_t vdd_dig;
343
344 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
345 uint32_t buffered_value = msm_rpmrs_buffer[rs->rs[0].id];
346
347 if (rs->enable_low_power == 0)
348 vdd_dig = MSM_RPMRS_VDD_DIG_ACTIVE;
349 else if (rs->enable_low_power == 1)
350 vdd_dig = MSM_RPMRS_VDD_DIG_RET_HIGH;
351 else
352 vdd_dig = MSM_RPMRS_VDD_DIG_RET_LOW;
353
354 if (MSM_RPMRS_VDD(buffered_value) > MSM_RPMRS_VDD(vdd_dig))
355 vdd_dig = buffered_value;
356 } else {
357 vdd_dig = MSM_RPMRS_VDD_DIG_ACTIVE;
358 }
359
360 return MSM_RPMRS_VDD(vdd_dig) >=
361 MSM_RPMRS_VDD(limits->vdd_dig_upper_bound);
362}
363
364static void msm_rpmrs_aggregate_vdd_dig(struct msm_rpmrs_limits *limits)
365{
366 struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_dig;
367 uint32_t *buf = &msm_rpmrs_buffer[rs->rs[0].id];
368
369 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered)) {
370 rs->rs[0].value = *buf;
371 if (MSM_RPMRS_VDD(limits->vdd_dig) > MSM_RPMRS_VDD(*buf)) {
372 *buf &= ~MSM_RPMRS_VDD_MASK;
373 *buf |= MSM_RPMRS_VDD(limits->vdd_dig);
374 }
375
376
377 if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
378 pr_info("%s: vdd %d (0x%x)\n", __func__,
379 MSM_RPMRS_VDD(*buf), MSM_RPMRS_VDD(*buf));
380 }
381}
382
383static void msm_rpmrs_restore_vdd_dig(void)
384{
385 struct msm_rpmrs_resource *rs = &msm_rpmrs_vdd_dig;
386
387 if (test_bit(rs->rs[0].id, msm_rpmrs_buffered))
388 msm_rpmrs_buffer[rs->rs[0].id] = rs->rs[0].value;
389}
390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391/******************************************************************************
392 * Buffering Functions
393 *****************************************************************************/
394
395static bool msm_rpmrs_irqs_detectable(struct msm_rpmrs_limits *limits,
396 bool irqs_detect, bool gpio_detect)
397{
398
399 if (limits->vdd_dig <= MSM_RPMRS_VDD_DIG_RET_HIGH)
400 return irqs_detect;
401
402 if (limits->pxo == MSM_RPMRS_PXO_OFF)
403 return gpio_detect;
404
405 return true;
406}
407
408static bool msm_rpmrs_use_mpm(struct msm_rpmrs_limits *limits)
409{
410 return (limits->pxo == MSM_RPMRS_PXO_OFF) ||
411 (limits->vdd_dig <= MSM_RPMRS_VDD_DIG_RET_HIGH);
412}
413
414static void msm_rpmrs_update_levels(void)
415{
416 int i, k;
417
418 for (i = 0; i < msm_rpmrs_level_count; i++) {
419 struct msm_rpmrs_level *level = &msm_rpmrs_levels[i];
420
421 if (level->sleep_mode != MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
422 continue;
423
424 level->available = true;
425
426 for (k = 0; k < ARRAY_SIZE(msm_rpmrs_resources); k++) {
427 struct msm_rpmrs_resource *rs = msm_rpmrs_resources[k];
428
429 if (rs->beyond_limits &&
430 rs->beyond_limits(&level->rs_limits)) {
431 level->available = false;
432 break;
433 }
434 }
435 }
436}
437
438/*
439 * Return value:
440 * 0: no entries in <req> is on our resource list
441 * 1: one or more entries in <req> is on our resource list
442 * -EINVAL: invalid id in <req> array
443 */
444static int msm_rpmrs_buffer_request(struct msm_rpm_iv_pair *req, int count)
445{
446 bool listed;
447 int i;
448
449 for (i = 0; i < count; i++)
450 if (req[i].id > MSM_RPM_ID_LAST)
451 return -EINVAL;
452
453 for (i = 0, listed = false; i < count; i++) {
454 msm_rpmrs_buffer[req[i].id] = req[i].value;
455 set_bit(req[i].id, msm_rpmrs_buffered);
456
457 if (MSM_RPMRS_DEBUG_BUFFER & msm_rpmrs_debug_mask)
458 pr_info("%s: reg %d: 0x%x\n",
459 __func__, req[i].id, req[i].value);
460
461 if (listed)
462 continue;
463
464 if (test_bit(req[i].id, msm_rpmrs_listed))
465 listed = true;
466 }
467
468 return listed ? 1 : 0;
469}
470
471/*
472 * Return value:
473 * 0: no entries in <req> is on our resource list
474 * 1: one or more entries in <req> is on our resource list
475 * -EINVAL: invalid id in <req> array
476 */
477static int msm_rpmrs_clear_buffer(struct msm_rpm_iv_pair *req, int count)
478{
479 bool listed;
480 int i;
481
482 for (i = 0; i < count; i++)
483 if (req[i].id > MSM_RPM_ID_LAST)
484 return -EINVAL;
485
486 for (i = 0, listed = false; i < count; i++) {
487 msm_rpmrs_buffer[req[i].id] = 0;
488 clear_bit(req[i].id, msm_rpmrs_buffered);
489
490 if (MSM_RPMRS_DEBUG_BUFFER & msm_rpmrs_debug_mask)
491 pr_info("%s: reg %d\n", __func__, req[i].id);
492
493 if (listed)
494 continue;
495
496 if (test_bit(req[i].id, msm_rpmrs_listed))
497 listed = true;
498 }
499
500 return listed ? 1 : 0;
501}
502
503#ifdef CONFIG_MSM_L2_SPM
504static int msm_rpmrs_flush_L2(struct msm_rpmrs_limits *limits, int notify_rpm)
505{
506 int rc = 0;
507 int lpm;
508
509 switch (limits->l2_cache) {
510 case MSM_RPMRS_L2_CACHE_HSFS_OPEN:
511 lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
512 /* Increment the counter for TZ to init L2 on warmboot */
513 /* Barrier in msm_spm_l2_set_low_power_mode */
514 BUG_ON(!msm_rpmrs_l2_counter_addr);
515 writel_relaxed(++msm_rpmrs_l2_reset_count,
516 msm_rpmrs_l2_counter_addr);
Maheshkumar Sivasubramaniana012e092011-08-18 10:13:03 -0600517 msm_pm_set_l2_flush_flag(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518 break;
519 case MSM_RPMRS_L2_CACHE_GDHS:
520 lpm = MSM_SPM_L2_MODE_GDHS;
521 break;
522 case MSM_RPMRS_L2_CACHE_RETENTION:
523 lpm = MSM_SPM_L2_MODE_RETENTION;
524 break;
525 default:
526 case MSM_RPMRS_L2_CACHE_ACTIVE:
527 lpm = MSM_SPM_L2_MODE_DISABLED;
528 break;
529 }
530
531 rc = msm_spm_l2_set_low_power_mode(lpm, notify_rpm);
532 if (MSM_RPMRS_DEBUG_BUFFER & msm_rpmrs_debug_mask)
533 pr_info("%s: Requesting low power mode %d returned %d\n",
534 __func__, lpm, rc);
535
536 return rc;
537}
Maheshkumar Sivasubramaniandd93ecf2011-09-15 19:39:14 -0600538static void msm_rpmrs_L2_restore(struct msm_rpmrs_limits *limits,
539 bool notify_rpm, bool collapsed)
540{
541 msm_spm_l2_set_low_power_mode(MSM_SPM_MODE_DISABLED, notify_rpm);
Maheshkumar Sivasubramaniana012e092011-08-18 10:13:03 -0600542 msm_pm_set_l2_flush_flag(0);
Maheshkumar Sivasubramaniandd93ecf2011-09-15 19:39:14 -0600543 if (!collapsed && (limits->l2_cache == MSM_RPMRS_L2_CACHE_HSFS_OPEN))
544 writel_relaxed(--msm_rpmrs_l2_reset_count,
545 msm_rpmrs_l2_counter_addr);
546}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547#else
548static int msm_rpmrs_flush_L2(struct msm_rpmrs_limits *limits, int notify_rpm)
549{
550 return 0;
551}
Maheshkumar Sivasubramaniandd93ecf2011-09-15 19:39:14 -0600552static void msm_rpmrs_L2_restore(struct msm_rpmrs_limits *limits,
553 bool notify_rpm, bool collapsed)
554{
555}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556#endif
557
558static int msm_rpmrs_flush_buffer(
559 uint32_t sclk_count, struct msm_rpmrs_limits *limits, int from_idle)
560{
561 struct msm_rpm_iv_pair *req;
562 int count;
563 int rc;
564 int i;
565
566 msm_rpmrs_aggregate_sclk(sclk_count);
567 for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
568 if (msm_rpmrs_resources[i]->aggregate)
569 msm_rpmrs_resources[i]->aggregate(limits);
570 }
571
572 count = bitmap_weight(msm_rpmrs_buffered, MSM_RPM_ID_LAST + 1);
573
574 req = kmalloc(sizeof(*req) * count, GFP_ATOMIC);
575 if (!req) {
576 rc = -ENOMEM;
577 goto flush_buffer_restore;
578 }
579
580 count = 0;
581 i = find_first_bit(msm_rpmrs_buffered, MSM_RPM_ID_LAST + 1);
582
583 while (i < MSM_RPM_ID_LAST + 1) {
584 if (MSM_RPMRS_DEBUG_OUTPUT & msm_rpmrs_debug_mask)
585 pr_info("%s: reg %d: 0x%x\n",
586 __func__, i, msm_rpmrs_buffer[i]);
587
588 req[count].id = i;
589 req[count].value = msm_rpmrs_buffer[i];
590 count++;
591
592 i = find_next_bit(msm_rpmrs_buffered, MSM_RPM_ID_LAST+1, i+1);
593 }
594
595 rc = msm_rpm_set_noirq(MSM_RPM_CTX_SET_SLEEP, req, count);
596 kfree(req);
597
598 if (rc)
599 goto flush_buffer_restore;
600
601 bitmap_and(msm_rpmrs_buffered,
602 msm_rpmrs_buffered, msm_rpmrs_listed, MSM_RPM_ID_LAST + 1);
603
604flush_buffer_restore:
605 for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
606 if (msm_rpmrs_resources[i]->restore)
607 msm_rpmrs_resources[i]->restore();
608 }
609 msm_rpmrs_restore_sclk();
610
611 if (rc)
612 pr_err("%s: failed: %d\n", __func__, rc);
613 return rc;
614}
615
616static int msm_rpmrs_set_common(
617 int ctx, struct msm_rpm_iv_pair *req, int count, bool noirq)
618{
619 if (ctx == MSM_RPM_CTX_SET_SLEEP) {
620 unsigned long flags;
621 int rc;
622
623 spin_lock_irqsave(&msm_rpmrs_lock, flags);
624 rc = msm_rpmrs_buffer_request(req, count);
625 if (rc > 0) {
626 msm_rpmrs_update_levels();
627 rc = 0;
628 }
629 spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
630
631 return rc;
632 }
633
634 if (noirq)
635 return msm_rpm_set_noirq(ctx, req, count);
636 else
637 return msm_rpm_set(ctx, req, count);
638}
639
640static int msm_rpmrs_clear_common(
641 int ctx, struct msm_rpm_iv_pair *req, int count, bool noirq)
642{
643 if (ctx == MSM_RPM_CTX_SET_SLEEP) {
644 unsigned long flags;
645 int rc;
646
647 spin_lock_irqsave(&msm_rpmrs_lock, flags);
648 rc = msm_rpmrs_clear_buffer(req, count);
649 if (rc > 0) {
650 msm_rpmrs_update_levels();
651 rc = 0;
652 }
653 spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
654
655 if (rc < 0)
656 return rc;
657 }
658
659 if (noirq)
660 return msm_rpm_clear_noirq(ctx, req, count);
661 else
662 return msm_rpm_clear(ctx, req, count);
663}
664
665/******************************************************************************
666 * Attribute Functions
667 *****************************************************************************/
668
669static ssize_t msm_rpmrs_resource_attr_show(
670 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
671{
672 struct kernel_param kp;
673 unsigned long flags;
674 unsigned int temp;
675 int rc;
676
677 spin_lock_irqsave(&msm_rpmrs_lock, flags);
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600678 /* special case active-set signal for MSM_RPMRS_ID_RPM_CTL */
679 if (GET_RS_FROM_ATTR(attr)->rs[0].id == MSM_RPMRS_ID_RPM_CTL)
680 temp = GET_RS_FROM_ATTR(attr)->rs[0].value;
681 else
682 temp = GET_RS_FROM_ATTR(attr)->enable_low_power;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683 spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
684
685 kp.arg = &temp;
686 rc = param_get_uint(buf, &kp);
687
688 if (rc > 0) {
Praveen Chidambaram2b0fdd02011-10-28 16:40:58 -0600689 strlcat(buf, "\n", PAGE_SIZE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 rc++;
691 }
692
693 return rc;
694}
695
696static ssize_t msm_rpmrs_resource_attr_store(struct kobject *kobj,
697 struct kobj_attribute *attr, const char *buf, size_t count)
698{
699 struct kernel_param kp;
700 unsigned long flags;
701 unsigned int temp;
702 int rc;
703
704 kp.arg = &temp;
705 rc = param_set_uint(buf, &kp);
706 if (rc)
707 return rc;
708
709 spin_lock_irqsave(&msm_rpmrs_lock, flags);
710 GET_RS_FROM_ATTR(attr)->enable_low_power = temp;
Eugene Seah78aa5e72011-07-18 18:28:37 -0600711
712 /* special case active-set signal for MSM_RPMRS_ID_RPM_CTL */
713 if (GET_RS_FROM_ATTR(attr)->rs[0].id == MSM_RPMRS_ID_RPM_CTL) {
714 struct msm_rpm_iv_pair req;
715 req.id = MSM_RPMRS_ID_RPM_CTL;
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600716 req.value = GET_RS_FROM_ATTR(attr)->enable_low_power;
717 GET_RS_FROM_ATTR(attr)->rs[0].value = req.value;
Eugene Seah78aa5e72011-07-18 18:28:37 -0600718
719 rc = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &req, 1);
720 if (rc) {
721 pr_err("%s: failed to request RPM_CTL to %d: %d\n",
722 __func__, req.value, rc);
723 }
724 }
725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 msm_rpmrs_update_levels();
727 spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
728
729 return count;
730}
731
732static int __init msm_rpmrs_resource_sysfs_add(void)
733{
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600734 struct kobject *module_kobj = NULL;
735 struct kobject *low_power_kobj = NULL;
736 struct kobject *mode_kobj = NULL;
737 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738
739 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
740 if (!module_kobj) {
741 pr_err("%s: cannot find kobject for module %s\n",
742 __func__, KBUILD_MODNAME);
743 rc = -ENOENT;
744 goto resource_sysfs_add_exit;
745 }
746
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600747 low_power_kobj = kobject_create_and_add(
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748 "enable_low_power", module_kobj);
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600749 if (!low_power_kobj) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 pr_err("%s: cannot create kobject\n", __func__);
751 rc = -ENOMEM;
752 goto resource_sysfs_add_exit;
753 }
754
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600755 mode_kobj = kobject_create_and_add(
756 "mode", module_kobj);
757 if (!mode_kobj) {
758 pr_err("%s: cannot create kobject\n", __func__);
759 rc = -ENOMEM;
760 goto resource_sysfs_add_exit;
761 }
762
763 rc = sysfs_create_group(low_power_kobj, &msm_rpmrs_attribute_group);
Praveen Chidambaram66775c62011-08-04 16:59:24 -0600764 if (rc) {
765 pr_err("%s: cannot create kobject attribute group\n", __func__);
766 goto resource_sysfs_add_exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767 }
768
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600769 rc = sysfs_create_group(mode_kobj, &msm_rpmrs_mode_attribute_group);
770 if (rc) {
771 pr_err("%s: cannot create kobject attribute group\n", __func__);
772 goto resource_sysfs_add_exit;
773 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774
Maheshkumar Sivasubramaniana012e092011-08-18 10:13:03 -0600775 rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776resource_sysfs_add_exit:
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600777 if (rc) {
778 if (low_power_kobj)
779 sysfs_remove_group(low_power_kobj,
780 &msm_rpmrs_attribute_group);
781 kobject_del(low_power_kobj);
782 kobject_del(mode_kobj);
783 }
784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700785 return rc;
786}
787
788/******************************************************************************
789 * Public Functions
790 *****************************************************************************/
791
792int msm_rpmrs_set(int ctx, struct msm_rpm_iv_pair *req, int count)
793{
794 return msm_rpmrs_set_common(ctx, req, count, false);
795}
796
797int msm_rpmrs_set_noirq(int ctx, struct msm_rpm_iv_pair *req, int count)
798{
799 WARN(!irqs_disabled(), "msm_rpmrs_set_noirq can only be called "
800 "safely when local irqs are disabled. Consider using "
801 "msm_rpmrs_set or msm_rpmrs_set_nosleep instead.");
802 return msm_rpmrs_set_common(ctx, req, count, true);
803}
804
Praveen Chidambaram9dfa8712011-09-14 16:25:01 -0600805/* Allow individual bits of an rpm resource be set, currently used only for
806 * active context resource viz. RPM_CTL. The API is generic enough to possibly
807 * extend it to other resources as well in the future.
808 */
809int msm_rpmrs_set_bits_noirq(int ctx, struct msm_rpm_iv_pair *req, int count,
810 int *mask)
811{
812 unsigned long flags;
813 int i, j;
814 int rc = -1;
815 struct msm_rpmrs_resource *rs;
816
817 if (ctx != MSM_RPM_CTX_SET_0)
818 return -ENOSYS;
819
820 spin_lock_irqsave(&msm_rpmrs_lock, flags);
821 for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
822 rs = msm_rpmrs_resources[i];
823 if (rs->rs[0].id == req[0].id && rs->size == count) {
824 for (j = 0; j < rs->size; j++) {
825 rs->rs[j].value &= ~mask[j];
826 rs->rs[j].value |= req[j].value & mask[j];
827 }
828 break;
829 }
830 }
831
832 if (i != ARRAY_SIZE(msm_rpmrs_resources)) {
833 rc = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &rs->rs[0], rs->size);
834 if (rc) {
835 for (j = 0; j < rs->size; j++) {
836 pr_err("%s: failed to request %d to %d: %d\n",
837 __func__,
838 rs->rs[j].id, rs->rs[j].value, rc);
839 }
840 }
841 }
842 spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
843
844 return rc;
845
846}
847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848int msm_rpmrs_clear(int ctx, struct msm_rpm_iv_pair *req, int count)
849{
850 return msm_rpmrs_clear_common(ctx, req, count, false);
851}
852
853int msm_rpmrs_clear_noirq(int ctx, struct msm_rpm_iv_pair *req, int count)
854{
855 WARN(!irqs_disabled(), "msm_rpmrs_clear_noirq can only be called "
856 "safely when local irqs are disabled. Consider using "
857 "msm_rpmrs_clear or msm_rpmrs_clear_nosleep instead.");
858 return msm_rpmrs_clear_common(ctx, req, count, true);
859}
860
861void msm_rpmrs_show_resources(void)
862{
863 struct msm_rpmrs_resource *rs;
864 unsigned long flags;
865 int i;
866
867 spin_lock_irqsave(&msm_rpmrs_lock, flags);
868 for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
869 rs = msm_rpmrs_resources[i];
870 if (rs->rs[0].id < MSM_RPM_ID_LAST + 1)
871 pr_info("%s: resource %s: buffered %d, value 0x%x\n",
872 __func__, rs->name,
873 test_bit(rs->rs[0].id, msm_rpmrs_buffered),
874 msm_rpmrs_buffer[rs->rs[0].id]);
875 else
876 pr_info("%s: resource %s: value %d\n",
877 __func__, rs->name, rs->rs[0].value);
878 }
879 spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
880}
881
882struct msm_rpmrs_limits *msm_rpmrs_lowest_limits(
883 bool from_idle, enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
884 uint32_t sleep_us)
885{
886 unsigned int cpu = smp_processor_id();
887 struct msm_rpmrs_level *best_level = NULL;
888 bool irqs_detectable = false;
889 bool gpio_detectable = false;
890 int i;
891
892 if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
893 irqs_detectable = msm_mpm_irqs_detectable(from_idle);
894 gpio_detectable = msm_mpm_gpio_irqs_detectable(from_idle);
895 }
896
897 for (i = 0; i < msm_rpmrs_level_count; i++) {
898 struct msm_rpmrs_level *level = &msm_rpmrs_levels[i];
899 uint32_t power;
900
901 if (!level->available)
902 continue;
903
904 if (sleep_mode != level->sleep_mode)
905 continue;
906
907 if (latency_us < level->latency_us)
908 continue;
909
910 if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
911 irqs_detectable, gpio_detectable))
912 continue;
913
914 if (sleep_us <= 1) {
915 power = level->energy_overhead;
916 } else if (sleep_us <= level->time_overhead_us) {
917 power = level->energy_overhead / sleep_us;
918 } else if ((sleep_us >> 10) > level->time_overhead_us) {
919 power = level->steady_state_power;
920 } else {
Maheshkumar Sivasubramaniand2239ad2011-10-04 09:07:51 -0600921 power = level->steady_state_power;
922 power -= (level->time_overhead_us *
923 level->steady_state_power)/sleep_us;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924 power += level->energy_overhead / sleep_us;
925 }
926
927 if (!best_level ||
928 best_level->rs_limits.power[cpu] >= power) {
929 level->rs_limits.latency_us[cpu] = level->latency_us;
930 level->rs_limits.power[cpu] = power;
931 best_level = level;
932 }
933 }
934
935 return best_level ? &best_level->rs_limits : NULL;
936}
937
938int msm_rpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
939 bool from_idle, bool notify_rpm)
940{
941 int rc = 0;
942
943 rc = msm_rpmrs_flush_L2(limits, notify_rpm);
944 if (rc)
945 return rc;
946
947 if (notify_rpm) {
948 rc = msm_rpmrs_flush_buffer(sclk_count, limits, from_idle);
949 if (rc)
950 return rc;
951
952 if (msm_rpmrs_use_mpm(limits))
953 msm_mpm_enter_sleep(from_idle);
954 }
955
956 return rc;
957}
958
Maheshkumar Sivasubramaniandd93ecf2011-09-15 19:39:14 -0600959void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits, bool from_idle,
960 bool notify_rpm, bool collapsed)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961{
962
963 /* Disable L2 for now, we dont want L2 to do retention by default */
Maheshkumar Sivasubramaniandd93ecf2011-09-15 19:39:14 -0600964 msm_rpmrs_L2_restore(limits, notify_rpm, collapsed);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965
966 if (msm_rpmrs_use_mpm(limits))
967 msm_mpm_exit_sleep(from_idle);
968}
969
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970static int rpmrs_cpu_callback(struct notifier_block *nfb,
971 unsigned long action, void *hcpu)
972{
973 switch (action) {
974 case CPU_ONLINE_FROZEN:
975 case CPU_ONLINE:
976 if (num_online_cpus() > 1)
977 msm_rpmrs_l2_cache.rs[0].value =
978 MSM_RPMRS_L2_CACHE_ACTIVE;
979 break;
980 case CPU_DEAD_FROZEN:
981 case CPU_DEAD:
982 if (num_online_cpus() == 1)
983 msm_rpmrs_l2_cache.rs[0].value =
984 MSM_RPMRS_L2_CACHE_HSFS_OPEN;
985 break;
986 }
987
988 msm_rpmrs_update_levels();
989 return NOTIFY_OK;
990}
991
992static struct notifier_block __refdata rpmrs_cpu_notifier = {
993 .notifier_call = rpmrs_cpu_callback,
994};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995
996int __init msm_rpmrs_levels_init(struct msm_rpmrs_level *levels, int size)
997{
998 msm_rpmrs_levels = kzalloc(sizeof(struct msm_rpmrs_level) * size,
999 GFP_KERNEL);
1000 if (!msm_rpmrs_levels)
1001 return -ENOMEM;
1002 msm_rpmrs_level_count = size;
1003 memcpy(msm_rpmrs_levels, levels, size * sizeof(struct msm_rpmrs_level));
1004
1005 return 0;
1006}
1007
1008static int __init msm_rpmrs_init(void)
1009{
1010 struct msm_rpm_iv_pair req;
1011 int rc;
1012
Stepan Moskovchenko0302fbc2011-08-05 18:06:13 -07001013 if (cpu_is_apq8064())
1014 return -ENODEV;
1015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 BUG_ON(!msm_rpmrs_levels);
1017
Praveen Chidambaram841d46c2011-08-04 09:07:53 -06001018 if (cpu_is_msm8x60()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019 req.id = MSM_RPMRS_ID_APPS_L2_CACHE_CTL;
1020 req.value = 1;
1021
1022 rc = msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
1023 if (rc) {
1024 pr_err("%s: failed to request L2 cache: %d\n",
1025 __func__, rc);
1026 goto init_exit;
1027 }
1028
1029 req.id = MSM_RPMRS_ID_APPS_L2_CACHE_CTL;
1030 req.value = 0;
1031
1032 rc = msm_rpmrs_set(MSM_RPM_CTX_SET_SLEEP, &req, 1);
1033 if (rc) {
1034 pr_err("%s: failed to initialize L2 cache for sleep: "
1035 "%d\n", __func__, rc);
1036 goto init_exit;
1037 }
1038 }
1039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 rc = msm_rpmrs_resource_sysfs_add();
1041
1042init_exit:
1043 return rc;
1044}
1045device_initcall(msm_rpmrs_init);
1046
1047static int __init msm_rpmrs_early_init(void)
1048{
1049 int i, k;
1050
1051 /* Initialize listed bitmap for valid resource IDs */
1052 for (i = 0; i < ARRAY_SIZE(msm_rpmrs_resources); i++) {
1053 for (k = 0; k < msm_rpmrs_resources[i]->size; k++)
1054 set_bit(msm_rpmrs_resources[i]->rs[k].id,
1055 msm_rpmrs_listed);
1056 }
1057
1058 return 0;
1059}
1060early_initcall(msm_rpmrs_early_init);
1061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062static int __init msm_rpmrs_l2_counter_init(void)
1063{
Stepan Moskovchenko7aab57c2011-10-25 14:41:14 -07001064 if (cpu_is_msm8960() || cpu_is_msm8930()) {
Maheshkumar Sivasubramanian07c363f2011-10-18 09:52:33 -06001065 msm_rpmrs_l2_counter_addr = MSM_IMEM_BASE + L2_PC_COUNTER_ADDR;
1066 writel_relaxed(msm_rpmrs_l2_reset_count,
1067 msm_rpmrs_l2_counter_addr);
1068 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069
Maheshkumar Sivasubramaniana012e092011-08-18 10:13:03 -06001070 msm_pm_set_l2_flush_flag(0);
1071
Maheshkumar Sivasubramanian07c363f2011-10-18 09:52:33 -06001072 msm_rpmrs_l2_cache.beyond_limits =
1073 msm_spm_l2_cache_beyond_limits;
1074 msm_rpmrs_l2_cache.aggregate = NULL;
1075 msm_rpmrs_l2_cache.restore = NULL;
1076 register_hotcpu_notifier(&rpmrs_cpu_notifier);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077
Maheshkumar Sivasubramanian07c363f2011-10-18 09:52:33 -06001078 } else if (cpu_is_msm9615()) {
1079 msm_rpmrs_l2_cache.beyond_limits = NULL;
1080 msm_rpmrs_l2_cache.aggregate = NULL;
1081 msm_rpmrs_l2_cache.restore = NULL;
1082 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001083 return 0;
1084}
1085early_initcall(msm_rpmrs_l2_counter_init);