blob: eb48d352bd79d2c742def6416e7e4ae53bc54034 [file] [log] [blame]
Trevor Bourgetfd2f7052012-04-20 17:25:53 -07001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
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 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13#include <linux/kernel.h>
14#include <linux/workqueue.h>
15#include <linux/percpu.h>
16#include <linux/cpu.h>
17#include <linux/smp.h>
18#include <linux/sysfs.h>
19#include <linux/sysdev.h>
20
21#include <mach/scm.h>
22
23#define CPU_CONFIG_CMD 5
24#define CPU_CONFIG_QUERY_CMD 6
25
26static int query_cpu_config(void)
27{
28 struct cpu_config_query_req_resp {
29 u32 id;
30 u32 arg0;
31 u32 arg1;
32 u32 arg2;
33 } request;
34 struct cpu_config_query_resp {
35 u32 ret0;
36 u32 ret1;
37 u32 ret2;
38 u32 ret3;
39 } response = {0};
40 int ret;
41
42 request.id = 1;
43 ret = scm_call(SCM_SVC_BOOT, CPU_CONFIG_QUERY_CMD, &request,
44 sizeof(request), &response, sizeof(response));
45 return ret ? : response.ret0;
46}
47
48static void set_cpu_config(int enable)
49{
50 struct cpu_config_req {
51 u32 id;
52 u32 arg0;
53 u32 arg1;
54 u32 arg2;
55 } request;
56
57 request.id = 1;
58 request.arg0 = enable;
59 scm_call(SCM_SVC_BOOT, CPU_CONFIG_CMD, &request, sizeof(request),
60 NULL, 0);
61}
62
63void enable_cpu_config(struct work_struct *work)
64{
65 set_cpu_config(1);
66}
67
68void disable_cpu_config(struct work_struct *work)
69{
70 set_cpu_config(0);
71}
72
73int cpu_config_on_each_cpu(bool enable)
74{
75 work_func_t func = enable ? enable_cpu_config : disable_cpu_config;
76 return schedule_on_each_cpu(func);
77}
78
79static ssize_t show_cpuctl(struct sysdev_class *class,
80 struct sysdev_class_attribute *attr, char *buf)
81{
82 return snprintf(buf, PAGE_SIZE, "%d\n", query_cpu_config());
83}
84
85static ssize_t store_cpuctl(struct sysdev_class *class,
86 struct sysdev_class_attribute *attr, const char *buf,
87 size_t count)
88{
89 unsigned val;
90 int ret;
91
92 ret = kstrtouint(buf, 10, &val);
93 if (ret < 0)
94 return ret;
95 ret = cpu_config_on_each_cpu(val);
96 if (ret < 0)
97 return ret;
98
99 return count;
100}
101
102static SYSDEV_CLASS_ATTR(cpuctl, 0600, show_cpuctl, store_cpuctl);
103
104static int __init init_scm_cpu(void)
105{
106 return sysfs_create_file(&cpu_subsys.dev_root->kobj,
107 &attr_cpuctl.attr);
108}
109module_init(init_scm_cpu);