From patchwork Tue Dec 13 06:25:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Zhao X-Patchwork-Id: 130998 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B7F9C1007D3 for ; Tue, 13 Dec 2011 17:29:39 +1100 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1RaLoq-00029b-3I; Tue, 13 Dec 2011 06:26:28 +0000 Received: from db3ehsobe002.messaging.microsoft.com ([213.199.154.140] helo=DB3EHSOBE002.bigfish.com) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1RaLoP-000275-CN for linux-arm-kernel@lists.infradead.org; Tue, 13 Dec 2011 06:26:03 +0000 Received: from mail83-db3-R.bigfish.com (10.3.81.246) by DB3EHSOBE002.bigfish.com (10.3.84.22) with Microsoft SMTP Server id 14.1.225.23; Tue, 13 Dec 2011 06:25:55 +0000 Received: from mail83-db3 (localhost [127.0.0.1]) by mail83-db3-R.bigfish.com (Postfix) with ESMTP id B302F2002BA; Tue, 13 Dec 2011 06:25:55 +0000 (UTC) X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzz8275dhz2dh87h2a8h668h839h) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-FB-DOMAIN-IP-MATCH: fail Received: from mail83-db3 (localhost.localdomain [127.0.0.1]) by mail83-db3 (MessageSwitch) id 1323757555534026_25305; Tue, 13 Dec 2011 06:25:55 +0000 (UTC) Received: from DB3EHSMHS012.bigfish.com (unknown [10.3.81.241]) by mail83-db3.bigfish.com (Postfix) with ESMTP id 7388E3C0042; Tue, 13 Dec 2011 06:25:55 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by DB3EHSMHS012.bigfish.com (10.3.87.112) with Microsoft SMTP Server (TLS) id 14.1.225.23; Tue, 13 Dec 2011 06:25:55 +0000 Received: from az33smr01.freescale.net (10.64.34.199) by 039-SN1MMR1-002.039d.mgd.msft.net (10.84.1.15) with Microsoft SMTP Server id 14.1.355.3; Tue, 13 Dec 2011 00:25:56 -0600 Received: from b20223-02.ap.freescale.net (b20223-02.ap.freescale.net [10.192.242.124]) by az33smr01.freescale.net (8.13.1/8.13.0) with ESMTP id pBD6PjOL010279; Tue, 13 Dec 2011 00:25:54 -0600 (CST) From: Richard Zhao To: Subject: [PATCH V2 3/7] arm/imx: cpufreq: add multi-core support Date: Tue, 13 Dec 2011 14:25:26 +0800 Message-ID: <1323757530-19402-4-git-send-email-richard.zhao@linaro.org> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1323757530-19402-1-git-send-email-richard.zhao@linaro.org> References: <1323757530-19402-1-git-send-email-richard.zhao@linaro.org> MIME-Version: 1.0 X-OriginatorOrg: sigmatel.com X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [213.199.154.140 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: fabio.estevam@freescale.com, robert.lee@linaro.org, eric.miao@linaro.org, kernel@pengutronix.de, shawn.guo@linaro.org, richard.zhao@linaro.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Signed-off-by: Richard Zhao --- arch/arm/plat-mxc/cpufreq.c | 99 ++++++++++++++++++++++++++++-------------- 1 files changed, 66 insertions(+), 33 deletions(-) diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c index adbff70..85d037f 100644 --- a/arch/arm/plat-mxc/cpufreq.c +++ b/arch/arm/plat-mxc/cpufreq.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ static int cpu_freq_khz_min; static int cpu_freq_khz_max; static struct clk *cpu_clk; +static DEFINE_MUTEX(cpu_lock); static struct cpufreq_frequency_table *imx_freq_table; static int cpu_op_nr; @@ -59,17 +61,11 @@ static int set_cpu_freq(int freq) static int mxc_verify_speed(struct cpufreq_policy *policy) { - if (policy->cpu != 0) - return -EINVAL; - return cpufreq_frequency_table_verify(policy, imx_freq_table); } static unsigned int mxc_get_speed(unsigned int cpu) { - if (cpu) - return 0; - return clk_get_rate(cpu_clk) / 1000; } @@ -77,23 +73,49 @@ static int mxc_set_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { struct cpufreq_freqs freqs; - int freq_Hz; + int freq_Hz, cpu; int ret = 0; unsigned int index; + mutex_lock(&cpu_lock); + cpufreq_frequency_table_target(policy, imx_freq_table, target_freq, relation, &index); freq_Hz = imx_freq_table[index].frequency * 1000; freqs.old = clk_get_rate(cpu_clk) / 1000; - freqs.new = freq_Hz / 1000; - freqs.cpu = 0; + freqs.new = clk_round_rate(cpu_clk, freq_Hz); + freqs.new = (freqs.new ? freqs.new : freq_Hz) / 1000; freqs.flags = 0; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + if (freqs.old == freqs.new) { + mutex_unlock(&cpu_lock); + return 0; + } + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } ret = set_cpu_freq(freq_Hz); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +#ifdef CONFIG_SMP + /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. + * So update it for all CPUs. + */ + for_each_possible_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(cpu_data, cpu).loops_per_jiffy, + freqs.old, freqs.new); +#endif + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + mutex_unlock(&cpu_lock); return ret; } @@ -105,7 +127,7 @@ static int __init mxc_cpufreq_init(struct cpufreq_policy *policy) printk(KERN_INFO "i.MXC CPU frequency driver\n"); - if (policy->cpu != 0) + if (policy->cpu >= num_possible_cpus()) return -EINVAL; if (!get_cpu_op) @@ -117,37 +139,45 @@ static int __init mxc_cpufreq_init(struct cpufreq_policy *policy) return PTR_ERR(cpu_clk); } - cpu_op_tbl = get_cpu_op(&cpu_op_nr); + mutex_lock(&cpu_lock); + if (!imx_freq_table) { + cpu_op_tbl = get_cpu_op(&cpu_op_nr); - cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000; - cpu_freq_khz_max = cpu_op_tbl[0].cpu_rate / 1000; + cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000; + cpu_freq_khz_max = cpu_op_tbl[0].cpu_rate / 1000; - imx_freq_table = kmalloc( - sizeof(struct cpufreq_frequency_table) * (cpu_op_nr + 1), - GFP_KERNEL); - if (!imx_freq_table) { - ret = -ENOMEM; - goto err1; - } + imx_freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) + * (cpu_op_nr + 1), GFP_KERNEL); + if (!imx_freq_table) { + ret = -ENOMEM; + mutex_unlock(&cpu_lock); + goto err1; + } - for (i = 0; i < cpu_op_nr; i++) { - imx_freq_table[i].index = i; - imx_freq_table[i].frequency = cpu_op_tbl[i].cpu_rate / 1000; + for (i = 0; i < cpu_op_nr; i++) { + imx_freq_table[i].index = i; + imx_freq_table[i].frequency = + cpu_op_tbl[i].cpu_rate / 1000; - if ((cpu_op_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min) - cpu_freq_khz_min = cpu_op_tbl[i].cpu_rate / 1000; + if ((cpu_op_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min) + cpu_freq_khz_min = + cpu_op_tbl[i].cpu_rate / 1000; - if ((cpu_op_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max) - cpu_freq_khz_max = cpu_op_tbl[i].cpu_rate / 1000; - } + if ((cpu_op_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max) + cpu_freq_khz_max = + cpu_op_tbl[i].cpu_rate / 1000; + } - imx_freq_table[i].index = i; - imx_freq_table[i].frequency = CPUFREQ_TABLE_END; + imx_freq_table[i].index = i; + imx_freq_table[i].frequency = CPUFREQ_TABLE_END; + } + mutex_unlock(&cpu_lock); policy->cur = clk_get_rate(cpu_clk) / 1000; policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min; policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max; - + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; + cpumask_setall(policy->cpus); /* Manual states, that PLL stabilizes in two CLK32 periods */ policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ; @@ -174,7 +204,10 @@ static int mxc_cpufreq_exit(struct cpufreq_policy *policy) set_cpu_freq(cpu_freq_khz_max * 1000); clk_put(cpu_clk); + mutex_lock(&cpu_lock); kfree(imx_freq_table); + imx_freq_table = NULL; + mutex_unlock(&cpu_lock); return 0; }