From patchwork Wed Apr 3 06:27:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akshay Saraswat X-Patchwork-Id: 233293 X-Patchwork-Delegate: promsoft@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 9BBA72C00B1 for ; Wed, 3 Apr 2013 17:14:13 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EEBE6A73DC; Wed, 3 Apr 2013 08:14:11 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id XbqfcSpgi5uN; Wed, 3 Apr 2013 08:14:06 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id AB8384A797; Wed, 3 Apr 2013 08:11:55 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 50A8E4A6E3 for ; Wed, 3 Apr 2013 08:11:17 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0BXsm3xn966Q for ; Wed, 3 Apr 2013 08:11:03 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) by theia.denx.de (Postfix) with ESMTP id 524D44A39C for ; Wed, 3 Apr 2013 08:07:50 +0200 (CEST) Received: from epcpsbgr4.samsung.com (u144.gpu120.samsung.co.kr [203.254.230.144]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MKO0036Z1107LQ0@mailout3.samsung.com> for u-boot@lists.denx.de; Wed, 03 Apr 2013 15:07:48 +0900 (KST) Received: from epcpsbgm2.samsung.com ( [172.20.52.124]) by epcpsbgr4.samsung.com (EPCPMTA) with SMTP id F4.FA.02019.337CB515; Wed, 03 Apr 2013 15:07:47 +0900 (KST) X-AuditID: cbfee690-b7f656d0000007e3-25-515bc733fe11 Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 22.42.13494.337CB515; Wed, 03 Apr 2013 15:07:47 +0900 (KST) Received: from chrome-ubuntu.sisodomain.com ([107.108.73.106]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MKO0019K10O9I00@mmp2.samsung.com>; Wed, 03 Apr 2013 15:07:47 +0900 (KST) From: Akshay Saraswat To: u-boot@lists.denx.de Date: Wed, 03 Apr 2013 02:27:18 -0400 Message-id: <1364970440-25942-3-git-send-email-akshay.s@samsung.com> X-Mailer: git-send-email 1.8.0 In-reply-to: <1364970440-25942-1-git-send-email-akshay.s@samsung.com> References: <1364970440-25942-1-git-send-email-akshay.s@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrILMWRmVeSWpSXmKPExsWyRsSkRtf4eHSgwY+rKhZTH5xjtPi2ZRuj xfLXG9kt3u7tZHdg8ZjdcJHFY+esu+weCzaVepy9s4MxgCWKyyYlNSezLLVI3y6BK+P/jhfs BWujK078WcHcwHjeo4uRk0NCwESi890OdghbTOLCvfVsXYxcHEICSxkllnZuB3I4wIrWT9UF qRESmM4o0X6eEaKml0liesdCVpAEm4COxPYl38EGiQhISPzqv8oIYjMLOEns/bMarEZYwE/i 0412MJtFQFVi2/H1TCA2r4CLxKS7x9ggjpCT+LDnEdgcTgFXieNzvrBBLHaRaNu5ixVksYTA fzaJH2svMEEMEpD4NvkQC8ShshKbDjBDzJGUOLjiBssERuEFjAyrGEVTC5ILipPSi0z0ihNz i0vz0vWS83M3MQKD9/S/ZxN2MN47YH2IMRlo3ERmKdHkfGDw55XEGxqbGVmYmpgaG5lbmpEm rCTOq95iHSgkkJ5YkpqdmlqQWhRfVJqTWnyIkYmDU6qB0ZB1y3OHC+v67ZafrfgiYfLd7x4D z5TQaXYnu2a1tOyoZM+ebbeX20H+3smc1NmyaRqLQu9f+XvZ5bKz1P87Qktmp15m6KoKz3Lf 3207J7DN8dAc+wxmG+XPC/KF+sXfrrZ/3f/u7D3P4+/aWZfnJRhvEFq63OGhKa/fbK2sN3zc bY6CulGHlFiKMxINtZiLihMBYPRNVXQCAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrHIsWRmVeSWpSXmKPExsVy+t9jQV3j49GBBuduS1lMfXCO0eLblm2M Fstfb2S3eLu3k92BxWN2w0UWj52z7rJ7LNhU6nH2zg7GAJaoBkabjNTElNQihdS85PyUzLx0 WyXv4HjneFMzA0NdQ0sLcyWFvMTcVFslF58AXbfMHKCdSgpliTmlQKGAxOJiJX07TBNCQ9x0 LWAaI3R9Q4LgeowM0EDCGsaM/ztesBesja448WcFcwPjeY8uRg4OCQETifVTdbsYOYFMMYkL 99azgdhCAtMZJdrPM3YxcgHZvUwS0zsWsoIk2AR0JLYv+c4OYosISEj86r/KCGIzCzhJ7P2z GqxGWMBP4tONdjCbRUBVYtvx9UwgNq+Ai8Sku8fYIJbJSXzY8whsDqeAq8TxOV+gFrtItO3c xTqBkXcBI8MqRtHUguSC4qT0XCO94sTc4tK8dL3k/NxNjODYeCa9g3FVg8UhRgEORiUe3hNf ogKFWBPLiitzDzFKcDArifCeDosOFOJNSaysSi3Kjy8qzUktPsSYDHTVRGYp0eR8YNzmlcQb GpuYmxqbWppYmJhZkiasJM57sNU6UEggPbEkNTs1tSC1CGYLEwenVANjzto7nMb/EtnuSHyP 2PR7IWNnXpEO41b3vokVN54flv6dxXnhoXKP8s8Nheunn3t4MLTv67Nw/onW1e/Ujm22fuPc K/6CY9kkvW8VXRLG09OjpQq9tV+E2/RE/lK+//Hraeei0mWHr+frZUhv+XHHLsX/Wnv6w4ip BVvnyfIceHTNdXJ6xJkoJZbijERDLeai4kQA+9lEGtECAAA= DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Cc: u-boot-review@google.com Subject: [U-Boot] [PATCH 2/4] Exynos5: cpufreq: Implement frequency scaling for exynos5 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Exynos5 currently runs at full speed i.e. 1.7 GHz everytime. Scaling down the clock speed in certain situations, may help in reducing the ARM temperature and power consumption. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass --- arch/arm/include/asm/arch-exynos/cpufreq.h | 54 ++++++ drivers/power/Makefile | 1 + drivers/power/exynos-cpufreq.c | 282 +++++++++++++++++++++++++++++ 3 files changed, 337 insertions(+) create mode 100644 arch/arm/include/asm/arch-exynos/cpufreq.h create mode 100644 drivers/power/exynos-cpufreq.c diff --git a/arch/arm/include/asm/arch-exynos/cpufreq.h b/arch/arm/include/asm/arch-exynos/cpufreq.h new file mode 100644 index 0000000..173e804 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/cpufreq.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - CPU frequency scaling support + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* Define various levels of ARM frequency */ +enum cpufreq_level { + CPU_FREQ_L200, /* 200 MHz */ + CPU_FREQ_L300, /* 300 MHz */ + CPU_FREQ_L400, /* 400 MHz */ + CPU_FREQ_L500, /* 500 MHz */ + CPU_FREQ_L600, /* 600 MHz */ + CPU_FREQ_L700, /* 700 MHz */ + CPU_FREQ_L800, /* 800 MHz */ + CPU_FREQ_L900, /* 900 MHz */ + CPU_FREQ_L1000, /* 1000 MHz */ + CPU_FREQ_L1100, /* 1100 MHz */ + CPU_FREQ_L1200, /* 1200 MHz */ + CPU_FREQ_L1300, /* 1300 MHz */ + CPU_FREQ_L1400, /* 1400 MHz */ + CPU_FREQ_L1500, /* 1500 MHz */ + CPU_FREQ_L1600, /* 1600 MHz */ + CPU_FREQ_L1700, /* 1700 MHz */ + CPU_FREQ_LCOUNT, +}; + +/* + * Initialize ARM frequency scaling + * + * @param blob FDT blob + * @return int value, 0 for success + */ +int exynos_cpufreq_init(void); + +/* + * Switch ARM frequency to new level + * + * @param new_freq_level enum cpufreq_level, states new frequency + * @return int value, 0 for success + */ +int exynos_set_frequency(enum cpufreq_level new_freq_level); diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 1dac16a..4589d9b 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_TPS6586X_POWER) += tps6586x.o COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o COBJS-$(CONFIG_TWL6030_POWER) += twl6030.o COBJS-$(CONFIG_TWL6035_POWER) += twl6035.o +COBJS-$(CONFIG_EXYNOS_CPUFREQ) += exynos-cpufreq.o COBJS-$(CONFIG_POWER) += power_core.o COBJS-$(CONFIG_DIALOG_POWER) += power_dialog.o diff --git a/drivers/power/exynos-cpufreq.c b/drivers/power/exynos-cpufreq.c new file mode 100644 index 0000000..f473167 --- /dev/null +++ b/drivers/power/exynos-cpufreq.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - CPU frequency scaling support + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +/* APLL CON0 */ +#define CON0_LOCK_BIT_MASK (0x1 << 29) +#define MDIV_MASK(x) (x << 16) +#define PDIV_MASK(x) (x << 8) +#define SDIV_MASK(x) (x << 0) +#define APLL_PMS_MASK ~(MDIV_MASK(0x3ff) \ + | PDIV_MASK(0x3f) | SDIV_MASK(0x7)) + +/* MUX_STAT CPU select */ +#define MUX_CPU_NONE (0x7 << 16) +#define MUX_CPU_MOUT_APLL (0x1 << 16) + +/* CLK_DIV_CPU0_VAL */ +#define DIV_CPU0_RSVD ~((0x7 << 28) \ + | (0x7 << 24) \ + | (0x7 << 20) \ + | (0x7 << 16) \ + | (0x7 << 12) \ + | (0x7 << 8) \ + | (0x7 << 4) \ + | (0x7)) + +/* CLK_DIV_CPU1 */ +#define DIV_CPU1_RSVD ~((0x7 << 4) | (0x7)) + +struct cpufreq_clkdiv { + uint8_t cpu0; + uint8_t cpu1; +}; + +struct cpufreq_data { + uint8_t arm; + uint8_t cpud; + uint8_t acp; + uint8_t periph; + uint8_t atb; + uint8_t pclk_dbg; + uint8_t apll; + uint8_t arm2; + uint8_t copy; + uint8_t hpm; + uint32_t apll_mdiv; + uint32_t apll_pdiv; + uint32_t apll_sdiv; + uint32_t volt; +}; + +static enum cpufreq_level old_freq_level; +static struct cpufreq_clkdiv exynos5250_clkdiv; + +/* + * Clock divider, PMS and ASV group voltage values corresponding + * to frequencies. + */ +static struct cpufreq_data exynos5250_data_table[CPU_FREQ_LCOUNT] = { + /* + * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2, COPY, HPM, + * APLL_MDIV, APLL_PDIV, APLL_SDIV, VOLTAGE } + */ + { 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 100, 3, 2, 925000 }, /* 200 MHz */ + { 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 200, 4, 2, 937500 }, /* 300 MHz */ + { 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 100, 3, 1, 950000 }, /* 400 MHz */ + { 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 125, 3, 1, 975000 }, /* 500 MHz */ + { 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 200, 4, 1, 1000000 }, /* 600 MHz */ + { 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 175, 3, 1, 1012500 }, /* 700 MHz */ + { 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 100, 3, 0, 1025000 }, /* 800 MHz */ + { 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 150, 4, 0, 1050000 }, /* 900 MHz */ + { 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 125, 3, 0, 1075000 }, /* 1000 MHz */ + { 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 275, 6, 0, 1100000 }, /* 1100 MHz */ + { 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 200, 4, 0, 1125000 }, /* 1200 MHz */ + { 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 325, 6, 0, 1150000 }, /* 1300 MHz */ + { 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 175, 3, 0, 1200000 }, /* 1400 MHz */ + { 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 250, 4, 0, 1225000 }, /* 1500 MHz */ + { 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 200, 3, 0, 1250000 }, /* 1600 MHz */ + { 0, 3, 7, 7, 7, 2, 5, 0, 0, 2, 425, 6, 0, 1300000 }, /* 1700 MHz */ +}; + +/* + * Set clock divider values to alter exynos5 frequency + * + * @param new_freq_level enum cpufreq_level, states new frequency + * @param clk struct exynos5_clock *, + * provides clock reg addresses + */ +static void exynos5_set_clkdiv(enum cpufreq_level new_freq_level, + struct exynos5_clock *clk) +{ + unsigned int val; + + /* Change Divider - CPU0 */ + val = exynos5250_clkdiv.cpu0; + + val |= (exynos5250_data_table[new_freq_level].arm << 0) | + (exynos5250_data_table[new_freq_level].cpud << 4) | + (exynos5250_data_table[new_freq_level].acp << 8) | + (exynos5250_data_table[new_freq_level].periph << 12) | + (exynos5250_data_table[new_freq_level].atb << 16) | + (exynos5250_data_table[new_freq_level].pclk_dbg << 20) | + (exynos5250_data_table[new_freq_level].apll << 24) | + (exynos5250_data_table[new_freq_level].arm2 << 28); + + writel(val, &clk->div_cpu0); + + /* Wait for CPU0 divider to be stable */ + while (readl(&clk->div_stat_cpu0) & 0x11111111) + ; + + /* Change Divider - CPU1 */ + val = exynos5250_clkdiv.cpu1; + + val |= (exynos5250_data_table[new_freq_level].copy << 0) | + (exynos5250_data_table[new_freq_level].hpm << 4); + + writel(val, &clk->div_cpu1); + + /* Wait for CPU1 divider to be stable */ + while (readl(&clk->div_stat_cpu1) & 0x11) + ; +} + +/* + * Set APLL values to alter exynos5 frequency + * + * @param new_freq_level enum cpufreq_level, states new frequency + * @param clk struct exynos5_clock *, + * provides clock reg addresses + */ +static void exynos5_set_apll(enum cpufreq_level new_freq_level, + struct exynos5_clock *clk) +{ + unsigned int val, pdiv; + + /* Set APLL Lock time */ + pdiv = exynos5250_data_table[new_freq_level].apll_pdiv; + writel((pdiv * 250), &clk->apll_lock); + + /* Change PLL PMS values */ + val = readl(&clk->apll_con0); + val &= APLL_PMS_MASK; + val |= MDIV_MASK(exynos5250_data_table[new_freq_level].apll_mdiv) | + PDIV_MASK(exynos5250_data_table[new_freq_level].apll_pdiv) | + SDIV_MASK(exynos5250_data_table[new_freq_level].apll_sdiv); + writel(val, &clk->apll_con0); + + /* Wait for APLL lock time to complete */ + while (!(readl(&clk->apll_con0) & CON0_LOCK_BIT_MASK)) + ; +} + +/* + * Switch ARM power corresponding to new frequency level + * + * @param new_volt_index enum cpufreq_level, provides new voltage + * corresponing to new frequency level + * @return int value, 0 for success + */ +static int exynos5_set_voltage(enum cpufreq_level new_volt_index) +{ + u32 new_volt; + + new_volt = exynos5250_data_table[new_volt_index].volt; + + return pmic_set_voltage(new_volt); +} + +/* + * Switch exybos5 frequency to new level + * + * @param new_freq_level enum cpufreq_level, provides new frequency + * @return int value, 0 for success + */ +static int exynos5_set_frequency(enum cpufreq_level new_freq_level) +{ + int error = 0; + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + if (old_freq_level < new_freq_level) { + /* Alter voltage corresponding to new frequency */ + error = exynos5_set_voltage(new_freq_level); + + /* Change the system clock divider values */ + exynos5_set_clkdiv(new_freq_level, clk); + + /* Change the apll m,p,s value */ + exynos5_set_apll(new_freq_level, clk); + } else if (old_freq_level > new_freq_level) { + /* Change the apll m,p,s value */ + exynos5_set_apll(new_freq_level, clk); + + /* Change the system clock divider values */ + exynos5_set_clkdiv(new_freq_level, clk); + + /* Alter voltage corresponding to new frequency */ + error = exynos5_set_voltage(new_freq_level); + } + + old_freq_level = new_freq_level; + debug("ARM Frequency changed\n"); + + return error; +} + +/* + * Switch ARM frequency to new level + * + * @param new_freq_level enum cpufreq_level, states new frequency + * @return int value, 0 for success + */ +int exynos_set_frequency(enum cpufreq_level new_freq_level) +{ + if (cpu_is_exynos5()) { + return exynos5_set_frequency(new_freq_level); + } else { + debug("CPUFREQ: Frequency scaling not allowed for this CPU\n"); + return -1; + } +} + +/* + * Initialize frequency scaling for exynos5 + */ +static void exynos5_cpufreq_init(void) +{ + unsigned int val; + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + /* Save default divider ratios for CPU0 */ + val = readl(&clk->div_cpu0); + val &= DIV_CPU0_RSVD; + exynos5250_clkdiv.cpu0 = val; + + /* Save default divider ratios for CPU1 */ + val = readl(&clk->div_cpu1); + val &= DIV_CPU1_RSVD; + exynos5250_clkdiv.cpu1 = val; + + /* Calculate default ARM frequence level */ + old_freq_level = (get_pll_clk(APLL) / 100000000) - 2; + debug("Current ARM frequency is %u\n", val); +} + +/* + * Initialize ARM frequency scaling + * + * @return int value, 0 for success + */ +int exynos_cpufreq_init(void) +{ + if (cpu_is_exynos5()) { + exynos5_cpufreq_init(); + return 0; + } else { + debug("CPUFREQ: Could not init for this CPU\n"); + return -1; + } +}