Samsung S2R PM updates for v3.15
From Tomasz Figa: This series reworks suspend/resume handling of Samsung clock drivers to cover more SoC specific aspects that are beyond simple register save and restore. The goal is to have all the suspend/resume code that touches the clock controller in single place, which is the clock driver. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJTE9NAAAoJEA0Cl+kVi2xqLHEQAKtWQKYXNIkGtTpjs5Nf+3Jv 9CZpvAHAQ7Lto1Euewo3KSF0JBo9o3TnOUbu6AUuo9UQV9G0TrRTpme4nlWpf0IF UdCSb7px3tsd1pcOS2FyI9I+DBZ9qbk/ytJV6K/KWjvkp+sFfKtDO3ockVQLy/oF zR7vB4kF9SSICPk7I4lHvs1JV8z/do8V7PTMOywDPUAYpw5pwSLovFXLOjKDvOCC w/Q1X0fqrVCPBbKpnAfez2dJHfL/iQXCa5vD5T0HeVgMOUgKA7MgLeAbZa+vsFVd NKOya+eAn8vGZxxC9eX2F5XcT+fvs+7aLaHmW5Rw8mg4Dh8F0+8OyFYOpZxFr58P N+jQPlGnOhgPw/pGmtzgktyvNlB/7iRMXHnUksQbmtz47nxQAZTe/USTSWj0nUUy X21+8qI+RJI5UURvB4AH7pY7tmNdY4LjJsB1MgwlY3EIf9AN9Str1IkFxV3kylGK V67uQv7VKRBz2IKMsgTjNhriSGIoIV+0pnOj1l/zz+Rs1S0sVQwuDqPTSzPezBOS vWqTQOa6uGQvMzW8lAAyhdpxt+nWxUXsB9ZilqfDLSrmQHngaF5dnUJp98zwt2yX xRE/R329i76uls3W+HBHZU4TfAi724NJbct0/Ieoa4oz6ZFcweL8oObm8s264mId 3EpHFU0ju7owDiP+FBXV =82IK -----END PGP SIGNATURE----- Merge tag 'samsung-pm-1' of http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/drivers Merge "Samsung S2R PM updates for v3.15" from Kukjin Kim: From Tomasz Figa: This series reworks suspend/resume handling of Samsung clock drivers to cover more SoC specific aspects that are beyond simple register save and restore. The goal is to have all the suspend/resume code that touches the clock controller in single place, which is the clock driver. * tag 'samsung-pm-1' of http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung: ARM: EXYNOS: Drop legacy Exynos4 clock suspend/resume code clk: samsung: exynos4: Add remaining suspend/resume handling clk: samsung: Drop old suspend/resume code clk: samsung: s3c64xx: Move suspend/resume handling to SoC driver clk: samsung: exynos5420: Move suspend/resume handling to SoC driver clk: samsung: exynos5250: Move suspend/resume handling to SoC driver clk: samsung: exynos4: Move suspend/resume handling to SoC driver clk: samsung: Provide common helpers for register save/restore clk: exynos4: Remove remnants of non-DT support Acked-by: Mike Turquette <mturquette@linaro.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Коммит
f1d7d8c86b
|
@ -35,56 +35,6 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "regs-pmu.h"
|
#include "regs-pmu.h"
|
||||||
|
|
||||||
#define EXYNOS4_EPLL_LOCK (S5P_VA_CMU + 0x0C010)
|
|
||||||
#define EXYNOS4_VPLL_LOCK (S5P_VA_CMU + 0x0C020)
|
|
||||||
|
|
||||||
#define EXYNOS4_EPLL_CON0 (S5P_VA_CMU + 0x0C110)
|
|
||||||
#define EXYNOS4_EPLL_CON1 (S5P_VA_CMU + 0x0C114)
|
|
||||||
#define EXYNOS4_VPLL_CON0 (S5P_VA_CMU + 0x0C120)
|
|
||||||
#define EXYNOS4_VPLL_CON1 (S5P_VA_CMU + 0x0C124)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_TOP (S5P_VA_CMU + 0x0C310)
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_CAM (S5P_VA_CMU + 0x0C320)
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_TV (S5P_VA_CMU + 0x0C324)
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_LCD0 (S5P_VA_CMU + 0x0C334)
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_MAUDIO (S5P_VA_CMU + 0x0C33C)
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_FSYS (S5P_VA_CMU + 0x0C340)
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_PERIL0 (S5P_VA_CMU + 0x0C350)
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_PERIL1 (S5P_VA_CMU + 0x0C354)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKSRC_MASK_DMC (S5P_VA_CMU + 0x10300)
|
|
||||||
|
|
||||||
#define EXYNOS4_EPLLCON0_LOCKED_SHIFT (29)
|
|
||||||
#define EXYNOS4_VPLLCON0_LOCKED_SHIFT (29)
|
|
||||||
|
|
||||||
#define EXYNOS4210_CLKSRC_MASK_LCD1 (S5P_VA_CMU + 0x0C338)
|
|
||||||
|
|
||||||
static const struct sleep_save exynos4_set_clksrc[] = {
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_TOP , .val = 0x00000001, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_CAM , .val = 0x11111111, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_TV , .val = 0x00000111, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_LCD0 , .val = 0x00001111, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_MAUDIO , .val = 0x00000001, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_FSYS , .val = 0x01011111, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_PERIL0 , .val = 0x01111111, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_PERIL1 , .val = 0x01110111, },
|
|
||||||
{ .reg = EXYNOS4_CLKSRC_MASK_DMC , .val = 0x00010000, },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct sleep_save exynos4210_set_clksrc[] = {
|
|
||||||
{ .reg = EXYNOS4210_CLKSRC_MASK_LCD1 , .val = 0x00001111, },
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct sleep_save exynos4_epll_save[] = {
|
|
||||||
SAVE_ITEM(EXYNOS4_EPLL_CON0),
|
|
||||||
SAVE_ITEM(EXYNOS4_EPLL_CON1),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct sleep_save exynos4_vpll_save[] = {
|
|
||||||
SAVE_ITEM(EXYNOS4_VPLL_CON0),
|
|
||||||
SAVE_ITEM(EXYNOS4_VPLL_CON1),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct sleep_save exynos5_sys_save[] = {
|
static struct sleep_save exynos5_sys_save[] = {
|
||||||
SAVE_ITEM(EXYNOS5_SYS_I2C_CFG),
|
SAVE_ITEM(EXYNOS5_SYS_I2C_CFG),
|
||||||
};
|
};
|
||||||
|
@ -124,10 +74,7 @@ static void exynos_pm_prepare(void)
|
||||||
|
|
||||||
s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
|
s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
|
||||||
|
|
||||||
if (!soc_is_exynos5250()) {
|
if (soc_is_exynos5250()) {
|
||||||
s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
|
|
||||||
s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
|
|
||||||
} else {
|
|
||||||
s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save));
|
s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save));
|
||||||
/* Disable USE_RETENTION of JPEG_MEM_OPTION */
|
/* Disable USE_RETENTION of JPEG_MEM_OPTION */
|
||||||
tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION);
|
tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION);
|
||||||
|
@ -143,15 +90,6 @@ static void exynos_pm_prepare(void)
|
||||||
/* ensure at least INFORM0 has the resume address */
|
/* ensure at least INFORM0 has the resume address */
|
||||||
|
|
||||||
__raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
|
__raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
|
||||||
|
|
||||||
/* Before enter central sequence mode, clock src register have to set */
|
|
||||||
|
|
||||||
if (!soc_is_exynos5250())
|
|
||||||
s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc));
|
|
||||||
|
|
||||||
if (soc_is_exynos4210())
|
|
||||||
s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_pm_add(struct device *dev, struct subsys_interface *sif)
|
static int exynos_pm_add(struct device *dev, struct subsys_interface *sif)
|
||||||
|
@ -162,73 +100,6 @@ static int exynos_pm_add(struct device *dev, struct subsys_interface *sif)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long pll_base_rate;
|
|
||||||
|
|
||||||
static void exynos4_restore_pll(void)
|
|
||||||
{
|
|
||||||
unsigned long pll_con, locktime, lockcnt;
|
|
||||||
unsigned long pll_in_rate;
|
|
||||||
unsigned int p_div, epll_wait = 0, vpll_wait = 0;
|
|
||||||
|
|
||||||
if (pll_base_rate == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pll_in_rate = pll_base_rate;
|
|
||||||
|
|
||||||
/* EPLL */
|
|
||||||
pll_con = exynos4_epll_save[0].val;
|
|
||||||
|
|
||||||
if (pll_con & (1 << 31)) {
|
|
||||||
pll_con &= (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT);
|
|
||||||
p_div = (pll_con >> PLL46XX_PDIV_SHIFT);
|
|
||||||
|
|
||||||
pll_in_rate /= 1000000;
|
|
||||||
|
|
||||||
locktime = (3000 / pll_in_rate) * p_div;
|
|
||||||
lockcnt = locktime * 10000 / (10000 / pll_in_rate);
|
|
||||||
|
|
||||||
__raw_writel(lockcnt, EXYNOS4_EPLL_LOCK);
|
|
||||||
|
|
||||||
s3c_pm_do_restore_core(exynos4_epll_save,
|
|
||||||
ARRAY_SIZE(exynos4_epll_save));
|
|
||||||
epll_wait = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pll_in_rate = pll_base_rate;
|
|
||||||
|
|
||||||
/* VPLL */
|
|
||||||
pll_con = exynos4_vpll_save[0].val;
|
|
||||||
|
|
||||||
if (pll_con & (1 << 31)) {
|
|
||||||
pll_in_rate /= 1000000;
|
|
||||||
/* 750us */
|
|
||||||
locktime = 750;
|
|
||||||
lockcnt = locktime * 10000 / (10000 / pll_in_rate);
|
|
||||||
|
|
||||||
__raw_writel(lockcnt, EXYNOS4_VPLL_LOCK);
|
|
||||||
|
|
||||||
s3c_pm_do_restore_core(exynos4_vpll_save,
|
|
||||||
ARRAY_SIZE(exynos4_vpll_save));
|
|
||||||
vpll_wait = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait PLL locking */
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (epll_wait) {
|
|
||||||
pll_con = __raw_readl(EXYNOS4_EPLL_CON0);
|
|
||||||
if (pll_con & (1 << EXYNOS4_EPLLCON0_LOCKED_SHIFT))
|
|
||||||
epll_wait = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vpll_wait) {
|
|
||||||
pll_con = __raw_readl(EXYNOS4_VPLL_CON0);
|
|
||||||
if (pll_con & (1 << EXYNOS4_VPLLCON0_LOCKED_SHIFT))
|
|
||||||
vpll_wait = 0;
|
|
||||||
}
|
|
||||||
} while (epll_wait || vpll_wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct subsys_interface exynos_pm_interface = {
|
static struct subsys_interface exynos_pm_interface = {
|
||||||
.name = "exynos_pm",
|
.name = "exynos_pm",
|
||||||
.subsys = &exynos_subsys,
|
.subsys = &exynos_subsys,
|
||||||
|
@ -237,7 +108,6 @@ static struct subsys_interface exynos_pm_interface = {
|
||||||
|
|
||||||
static __init int exynos_pm_drvinit(void)
|
static __init int exynos_pm_drvinit(void)
|
||||||
{
|
{
|
||||||
struct clk *pll_base;
|
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
|
|
||||||
if (soc_is_exynos5440())
|
if (soc_is_exynos5440())
|
||||||
|
@ -251,15 +121,6 @@ static __init int exynos_pm_drvinit(void)
|
||||||
tmp |= ((0xFF << 8) | (0x1F << 1));
|
tmp |= ((0xFF << 8) | (0x1F << 1));
|
||||||
__raw_writel(tmp, S5P_WAKEUP_MASK);
|
__raw_writel(tmp, S5P_WAKEUP_MASK);
|
||||||
|
|
||||||
if (!soc_is_exynos5250()) {
|
|
||||||
pll_base = clk_get(NULL, "xtal");
|
|
||||||
|
|
||||||
if (!IS_ERR(pll_base)) {
|
|
||||||
pll_base_rate = clk_get_rate(pll_base);
|
|
||||||
clk_put(pll_base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return subsys_interface_register(&exynos_pm_interface);
|
return subsys_interface_register(&exynos_pm_interface);
|
||||||
}
|
}
|
||||||
arch_initcall(exynos_pm_drvinit);
|
arch_initcall(exynos_pm_drvinit);
|
||||||
|
@ -343,13 +204,8 @@ static void exynos_pm_resume(void)
|
||||||
|
|
||||||
s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
|
s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
|
||||||
|
|
||||||
if (!soc_is_exynos5250()) {
|
if (IS_ENABLED(CONFIG_SMP) && !soc_is_exynos5250())
|
||||||
exynos4_restore_pll();
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
scu_enable(S5P_VA_SCU);
|
scu_enable(S5P_VA_SCU);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
early_wakeup:
|
early_wakeup:
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
|
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
|
|
||||||
|
@ -130,6 +131,17 @@ enum exynos4_plls {
|
||||||
nr_plls /* number of PLLs */
|
nr_plls /* number of PLLs */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void __iomem *reg_base;
|
||||||
|
static enum exynos4_soc exynos4_soc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support for CMU save/restore across system suspends
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static struct samsung_clk_reg_dump *exynos4_save_common;
|
||||||
|
static struct samsung_clk_reg_dump *exynos4_save_soc;
|
||||||
|
static struct samsung_clk_reg_dump *exynos4_save_pll;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* list of controller registers to be saved and restored during a
|
* list of controller registers to be saved and restored during a
|
||||||
* suspend/resume cycle.
|
* suspend/resume cycle.
|
||||||
|
@ -154,6 +166,17 @@ static unsigned long exynos4x12_clk_save[] __initdata = {
|
||||||
E4X12_MPLL_CON0,
|
E4X12_MPLL_CON0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static unsigned long exynos4_clk_pll_regs[] __initdata = {
|
||||||
|
EPLL_LOCK,
|
||||||
|
VPLL_LOCK,
|
||||||
|
EPLL_CON0,
|
||||||
|
EPLL_CON1,
|
||||||
|
EPLL_CON2,
|
||||||
|
VPLL_CON0,
|
||||||
|
VPLL_CON1,
|
||||||
|
VPLL_CON2,
|
||||||
|
};
|
||||||
|
|
||||||
static unsigned long exynos4_clk_regs[] __initdata = {
|
static unsigned long exynos4_clk_regs[] __initdata = {
|
||||||
SRC_LEFTBUS,
|
SRC_LEFTBUS,
|
||||||
DIV_LEFTBUS,
|
DIV_LEFTBUS,
|
||||||
|
@ -161,12 +184,6 @@ static unsigned long exynos4_clk_regs[] __initdata = {
|
||||||
SRC_RIGHTBUS,
|
SRC_RIGHTBUS,
|
||||||
DIV_RIGHTBUS,
|
DIV_RIGHTBUS,
|
||||||
GATE_IP_RIGHTBUS,
|
GATE_IP_RIGHTBUS,
|
||||||
EPLL_CON0,
|
|
||||||
EPLL_CON1,
|
|
||||||
EPLL_CON2,
|
|
||||||
VPLL_CON0,
|
|
||||||
VPLL_CON1,
|
|
||||||
VPLL_CON2,
|
|
||||||
SRC_TOP0,
|
SRC_TOP0,
|
||||||
SRC_TOP1,
|
SRC_TOP1,
|
||||||
SRC_CAM,
|
SRC_CAM,
|
||||||
|
@ -227,6 +244,124 @@ static unsigned long exynos4_clk_regs[] __initdata = {
|
||||||
GATE_IP_CPU,
|
GATE_IP_CPU,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump src_mask_suspend[] = {
|
||||||
|
{ .offset = SRC_MASK_TOP, .value = 0x00000001, },
|
||||||
|
{ .offset = SRC_MASK_CAM, .value = 0x11111111, },
|
||||||
|
{ .offset = SRC_MASK_TV, .value = 0x00000111, },
|
||||||
|
{ .offset = SRC_MASK_LCD0, .value = 0x00001111, },
|
||||||
|
{ .offset = SRC_MASK_MAUDIO, .value = 0x00000001, },
|
||||||
|
{ .offset = SRC_MASK_FSYS, .value = 0x01011111, },
|
||||||
|
{ .offset = SRC_MASK_PERIL0, .value = 0x01111111, },
|
||||||
|
{ .offset = SRC_MASK_PERIL1, .value = 0x01110111, },
|
||||||
|
{ .offset = SRC_MASK_DMC, .value = 0x00010000, },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct samsung_clk_reg_dump src_mask_suspend_e4210[] = {
|
||||||
|
{ .offset = E4210_SRC_MASK_LCD1, .value = 0x00001111, },
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PLL_ENABLED (1 << 31)
|
||||||
|
#define PLL_LOCKED (1 << 29)
|
||||||
|
|
||||||
|
static void exynos4_clk_wait_for_pll(u32 reg)
|
||||||
|
{
|
||||||
|
u32 pll_con;
|
||||||
|
|
||||||
|
pll_con = readl(reg_base + reg);
|
||||||
|
if (!(pll_con & PLL_ENABLED))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (!(pll_con & PLL_LOCKED)) {
|
||||||
|
cpu_relax();
|
||||||
|
pll_con = readl(reg_base + reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exynos4_clk_suspend(void)
|
||||||
|
{
|
||||||
|
samsung_clk_save(reg_base, exynos4_save_common,
|
||||||
|
ARRAY_SIZE(exynos4_clk_regs));
|
||||||
|
samsung_clk_save(reg_base, exynos4_save_pll,
|
||||||
|
ARRAY_SIZE(exynos4_clk_pll_regs));
|
||||||
|
|
||||||
|
if (exynos4_soc == EXYNOS4210) {
|
||||||
|
samsung_clk_save(reg_base, exynos4_save_soc,
|
||||||
|
ARRAY_SIZE(exynos4210_clk_save));
|
||||||
|
samsung_clk_restore(reg_base, src_mask_suspend_e4210,
|
||||||
|
ARRAY_SIZE(src_mask_suspend_e4210));
|
||||||
|
} else {
|
||||||
|
samsung_clk_save(reg_base, exynos4_save_soc,
|
||||||
|
ARRAY_SIZE(exynos4x12_clk_save));
|
||||||
|
}
|
||||||
|
|
||||||
|
samsung_clk_restore(reg_base, src_mask_suspend,
|
||||||
|
ARRAY_SIZE(src_mask_suspend));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exynos4_clk_resume(void)
|
||||||
|
{
|
||||||
|
samsung_clk_restore(reg_base, exynos4_save_pll,
|
||||||
|
ARRAY_SIZE(exynos4_clk_pll_regs));
|
||||||
|
|
||||||
|
exynos4_clk_wait_for_pll(EPLL_CON0);
|
||||||
|
exynos4_clk_wait_for_pll(VPLL_CON0);
|
||||||
|
|
||||||
|
samsung_clk_restore(reg_base, exynos4_save_common,
|
||||||
|
ARRAY_SIZE(exynos4_clk_regs));
|
||||||
|
|
||||||
|
if (exynos4_soc == EXYNOS4210)
|
||||||
|
samsung_clk_restore(reg_base, exynos4_save_soc,
|
||||||
|
ARRAY_SIZE(exynos4210_clk_save));
|
||||||
|
else
|
||||||
|
samsung_clk_restore(reg_base, exynos4_save_soc,
|
||||||
|
ARRAY_SIZE(exynos4x12_clk_save));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct syscore_ops exynos4_clk_syscore_ops = {
|
||||||
|
.suspend = exynos4_clk_suspend,
|
||||||
|
.resume = exynos4_clk_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void exynos4_clk_sleep_init(void)
|
||||||
|
{
|
||||||
|
exynos4_save_common = samsung_clk_alloc_reg_dump(exynos4_clk_regs,
|
||||||
|
ARRAY_SIZE(exynos4_clk_regs));
|
||||||
|
if (!exynos4_save_common)
|
||||||
|
goto err_warn;
|
||||||
|
|
||||||
|
if (exynos4_soc == EXYNOS4210)
|
||||||
|
exynos4_save_soc = samsung_clk_alloc_reg_dump(
|
||||||
|
exynos4210_clk_save,
|
||||||
|
ARRAY_SIZE(exynos4210_clk_save));
|
||||||
|
else
|
||||||
|
exynos4_save_soc = samsung_clk_alloc_reg_dump(
|
||||||
|
exynos4x12_clk_save,
|
||||||
|
ARRAY_SIZE(exynos4x12_clk_save));
|
||||||
|
if (!exynos4_save_soc)
|
||||||
|
goto err_common;
|
||||||
|
|
||||||
|
exynos4_save_pll = samsung_clk_alloc_reg_dump(exynos4_clk_pll_regs,
|
||||||
|
ARRAY_SIZE(exynos4_clk_pll_regs));
|
||||||
|
if (!exynos4_save_pll)
|
||||||
|
goto err_soc;
|
||||||
|
|
||||||
|
register_syscore_ops(&exynos4_clk_syscore_ops);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_soc:
|
||||||
|
kfree(exynos4_save_soc);
|
||||||
|
err_common:
|
||||||
|
kfree(exynos4_save_common);
|
||||||
|
err_warn:
|
||||||
|
pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void exynos4_clk_sleep_init(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
|
PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
|
||||||
PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
|
PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
|
||||||
|
@ -908,12 +1043,13 @@ static unsigned long exynos4_get_xom(void)
|
||||||
return xom;
|
return xom;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init exynos4_clk_register_finpll(unsigned long xom)
|
static void __init exynos4_clk_register_finpll(void)
|
||||||
{
|
{
|
||||||
struct samsung_fixed_rate_clock fclk;
|
struct samsung_fixed_rate_clock fclk;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
unsigned long finpll_f = 24000000;
|
unsigned long finpll_f = 24000000;
|
||||||
char *parent_name;
|
char *parent_name;
|
||||||
|
unsigned int xom = exynos4_get_xom();
|
||||||
|
|
||||||
parent_name = xom & 1 ? "xusbxti" : "xxti";
|
parent_name = xom & 1 ? "xusbxti" : "xxti";
|
||||||
clk = clk_get(NULL, parent_name);
|
clk = clk_get(NULL, parent_name);
|
||||||
|
@ -1038,27 +1174,21 @@ static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = {
|
||||||
|
|
||||||
/* register exynos4 clocks */
|
/* register exynos4 clocks */
|
||||||
static void __init exynos4_clk_init(struct device_node *np,
|
static void __init exynos4_clk_init(struct device_node *np,
|
||||||
enum exynos4_soc exynos4_soc,
|
enum exynos4_soc soc)
|
||||||
void __iomem *reg_base, unsigned long xom)
|
|
||||||
{
|
{
|
||||||
|
exynos4_soc = soc;
|
||||||
|
|
||||||
reg_base = of_iomap(np, 0);
|
reg_base = of_iomap(np, 0);
|
||||||
if (!reg_base)
|
if (!reg_base)
|
||||||
panic("%s: failed to map registers\n", __func__);
|
panic("%s: failed to map registers\n", __func__);
|
||||||
|
|
||||||
if (exynos4_soc == EXYNOS4210)
|
samsung_clk_init(np, reg_base, CLK_NR_CLKS);
|
||||||
samsung_clk_init(np, reg_base, CLK_NR_CLKS,
|
|
||||||
exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
|
|
||||||
exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save));
|
|
||||||
else
|
|
||||||
samsung_clk_init(np, reg_base, CLK_NR_CLKS,
|
|
||||||
exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
|
|
||||||
exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save));
|
|
||||||
|
|
||||||
samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks,
|
samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks,
|
||||||
ARRAY_SIZE(exynos4_fixed_rate_ext_clks),
|
ARRAY_SIZE(exynos4_fixed_rate_ext_clks),
|
||||||
ext_clk_match);
|
ext_clk_match);
|
||||||
|
|
||||||
exynos4_clk_register_finpll(xom);
|
exynos4_clk_register_finpll();
|
||||||
|
|
||||||
if (exynos4_soc == EXYNOS4210) {
|
if (exynos4_soc == EXYNOS4210) {
|
||||||
samsung_clk_register_mux(exynos4210_mux_early,
|
samsung_clk_register_mux(exynos4210_mux_early,
|
||||||
|
@ -1125,6 +1255,8 @@ static void __init exynos4_clk_init(struct device_node *np,
|
||||||
samsung_clk_register_alias(exynos4_aliases,
|
samsung_clk_register_alias(exynos4_aliases,
|
||||||
ARRAY_SIZE(exynos4_aliases));
|
ARRAY_SIZE(exynos4_aliases));
|
||||||
|
|
||||||
|
exynos4_clk_sleep_init();
|
||||||
|
|
||||||
pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
|
pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
|
||||||
"\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
|
"\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
|
||||||
exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
|
exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
|
||||||
|
@ -1136,12 +1268,12 @@ static void __init exynos4_clk_init(struct device_node *np,
|
||||||
|
|
||||||
static void __init exynos4210_clk_init(struct device_node *np)
|
static void __init exynos4210_clk_init(struct device_node *np)
|
||||||
{
|
{
|
||||||
exynos4_clk_init(np, EXYNOS4210, NULL, exynos4_get_xom());
|
exynos4_clk_init(np, EXYNOS4210);
|
||||||
}
|
}
|
||||||
CLK_OF_DECLARE(exynos4210_clk, "samsung,exynos4210-clock", exynos4210_clk_init);
|
CLK_OF_DECLARE(exynos4210_clk, "samsung,exynos4210-clock", exynos4210_clk_init);
|
||||||
|
|
||||||
static void __init exynos4412_clk_init(struct device_node *np)
|
static void __init exynos4412_clk_init(struct device_node *np)
|
||||||
{
|
{
|
||||||
exynos4_clk_init(np, EXYNOS4X12, NULL, exynos4_get_xom());
|
exynos4_clk_init(np, EXYNOS4X12);
|
||||||
}
|
}
|
||||||
CLK_OF_DECLARE(exynos4412_clk, "samsung,exynos4412-clock", exynos4412_clk_init);
|
CLK_OF_DECLARE(exynos4412_clk, "samsung,exynos4412-clock", exynos4412_clk_init);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
|
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
|
|
||||||
|
@ -85,6 +86,11 @@ enum exynos5250_plls {
|
||||||
nr_plls /* number of PLLs */
|
nr_plls /* number of PLLs */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void __iomem *reg_base;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static struct samsung_clk_reg_dump *exynos5250_save;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* list of controller registers to be saved and restored during a
|
* list of controller registers to be saved and restored during a
|
||||||
* suspend/resume cycle.
|
* suspend/resume cycle.
|
||||||
|
@ -137,6 +143,41 @@ static unsigned long exynos5250_clk_regs[] __initdata = {
|
||||||
GATE_IP_ACP,
|
GATE_IP_ACP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int exynos5250_clk_suspend(void)
|
||||||
|
{
|
||||||
|
samsung_clk_save(reg_base, exynos5250_save,
|
||||||
|
ARRAY_SIZE(exynos5250_clk_regs));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exynos5250_clk_resume(void)
|
||||||
|
{
|
||||||
|
samsung_clk_restore(reg_base, exynos5250_save,
|
||||||
|
ARRAY_SIZE(exynos5250_clk_regs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct syscore_ops exynos5250_clk_syscore_ops = {
|
||||||
|
.suspend = exynos5250_clk_suspend,
|
||||||
|
.resume = exynos5250_clk_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void exynos5250_clk_sleep_init(void)
|
||||||
|
{
|
||||||
|
exynos5250_save = samsung_clk_alloc_reg_dump(exynos5250_clk_regs,
|
||||||
|
ARRAY_SIZE(exynos5250_clk_regs));
|
||||||
|
if (!exynos5250_save) {
|
||||||
|
pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
|
||||||
|
__func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
register_syscore_ops(&exynos5250_clk_syscore_ops);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void exynos5250_clk_sleep_init(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* list of all parent clock list */
|
/* list of all parent clock list */
|
||||||
PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
|
PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
|
||||||
PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", };
|
PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", };
|
||||||
|
@ -645,8 +686,6 @@ static struct of_device_id ext_clk_match[] __initdata = {
|
||||||
/* register exynox5250 clocks */
|
/* register exynox5250 clocks */
|
||||||
static void __init exynos5250_clk_init(struct device_node *np)
|
static void __init exynos5250_clk_init(struct device_node *np)
|
||||||
{
|
{
|
||||||
void __iomem *reg_base;
|
|
||||||
|
|
||||||
if (np) {
|
if (np) {
|
||||||
reg_base = of_iomap(np, 0);
|
reg_base = of_iomap(np, 0);
|
||||||
if (!reg_base)
|
if (!reg_base)
|
||||||
|
@ -655,9 +694,7 @@ static void __init exynos5250_clk_init(struct device_node *np)
|
||||||
panic("%s: unable to determine soc\n", __func__);
|
panic("%s: unable to determine soc\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
samsung_clk_init(np, reg_base, CLK_NR_CLKS,
|
samsung_clk_init(np, reg_base, CLK_NR_CLKS);
|
||||||
exynos5250_clk_regs, ARRAY_SIZE(exynos5250_clk_regs),
|
|
||||||
NULL, 0);
|
|
||||||
samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks,
|
samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks,
|
||||||
ARRAY_SIZE(exynos5250_fixed_rate_ext_clks),
|
ARRAY_SIZE(exynos5250_fixed_rate_ext_clks),
|
||||||
ext_clk_match);
|
ext_clk_match);
|
||||||
|
@ -685,6 +722,8 @@ static void __init exynos5250_clk_init(struct device_node *np)
|
||||||
samsung_clk_register_gate(exynos5250_gate_clks,
|
samsung_clk_register_gate(exynos5250_gate_clks,
|
||||||
ARRAY_SIZE(exynos5250_gate_clks));
|
ARRAY_SIZE(exynos5250_gate_clks));
|
||||||
|
|
||||||
|
exynos5250_clk_sleep_init();
|
||||||
|
|
||||||
pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
|
pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
|
||||||
_get_rate("div_arm2"));
|
_get_rate("div_arm2"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
|
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
|
|
||||||
|
@ -108,6 +109,11 @@ enum exynos5420_plls {
|
||||||
nr_plls /* number of PLLs */
|
nr_plls /* number of PLLs */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void __iomem *reg_base;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static struct samsung_clk_reg_dump *exynos5420_save;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* list of controller registers to be saved and restored during a
|
* list of controller registers to be saved and restored during a
|
||||||
* suspend/resume cycle.
|
* suspend/resume cycle.
|
||||||
|
@ -174,6 +180,41 @@ static unsigned long exynos5420_clk_regs[] __initdata = {
|
||||||
DIV_KFC0,
|
DIV_KFC0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int exynos5420_clk_suspend(void)
|
||||||
|
{
|
||||||
|
samsung_clk_save(reg_base, exynos5420_save,
|
||||||
|
ARRAY_SIZE(exynos5420_clk_regs));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exynos5420_clk_resume(void)
|
||||||
|
{
|
||||||
|
samsung_clk_restore(reg_base, exynos5420_save,
|
||||||
|
ARRAY_SIZE(exynos5420_clk_regs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct syscore_ops exynos5420_clk_syscore_ops = {
|
||||||
|
.suspend = exynos5420_clk_suspend,
|
||||||
|
.resume = exynos5420_clk_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void exynos5420_clk_sleep_init(void)
|
||||||
|
{
|
||||||
|
exynos5420_save = samsung_clk_alloc_reg_dump(exynos5420_clk_regs,
|
||||||
|
ARRAY_SIZE(exynos5420_clk_regs));
|
||||||
|
if (!exynos5420_save) {
|
||||||
|
pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
|
||||||
|
__func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
register_syscore_ops(&exynos5420_clk_syscore_ops);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void exynos5420_clk_sleep_init(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* list of all parent clocks */
|
/* list of all parent clocks */
|
||||||
PNAME(mspll_cpu_p) = { "sclk_cpll", "sclk_dpll",
|
PNAME(mspll_cpu_p) = { "sclk_cpll", "sclk_dpll",
|
||||||
"sclk_mpll", "sclk_spll" };
|
"sclk_mpll", "sclk_spll" };
|
||||||
|
@ -737,8 +778,6 @@ static struct of_device_id ext_clk_match[] __initdata = {
|
||||||
/* register exynos5420 clocks */
|
/* register exynos5420 clocks */
|
||||||
static void __init exynos5420_clk_init(struct device_node *np)
|
static void __init exynos5420_clk_init(struct device_node *np)
|
||||||
{
|
{
|
||||||
void __iomem *reg_base;
|
|
||||||
|
|
||||||
if (np) {
|
if (np) {
|
||||||
reg_base = of_iomap(np, 0);
|
reg_base = of_iomap(np, 0);
|
||||||
if (!reg_base)
|
if (!reg_base)
|
||||||
|
@ -747,9 +786,7 @@ static void __init exynos5420_clk_init(struct device_node *np)
|
||||||
panic("%s: unable to determine soc\n", __func__);
|
panic("%s: unable to determine soc\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
samsung_clk_init(np, reg_base, CLK_NR_CLKS,
|
samsung_clk_init(np, reg_base, CLK_NR_CLKS);
|
||||||
exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs),
|
|
||||||
NULL, 0);
|
|
||||||
samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks,
|
samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks,
|
||||||
ARRAY_SIZE(exynos5420_fixed_rate_ext_clks),
|
ARRAY_SIZE(exynos5420_fixed_rate_ext_clks),
|
||||||
ext_clk_match);
|
ext_clk_match);
|
||||||
|
@ -765,5 +802,7 @@ static void __init exynos5420_clk_init(struct device_node *np)
|
||||||
ARRAY_SIZE(exynos5420_div_clks));
|
ARRAY_SIZE(exynos5420_div_clks));
|
||||||
samsung_clk_register_gate(exynos5420_gate_clks,
|
samsung_clk_register_gate(exynos5420_gate_clks,
|
||||||
ARRAY_SIZE(exynos5420_gate_clks));
|
ARRAY_SIZE(exynos5420_gate_clks));
|
||||||
|
|
||||||
|
exynos5420_clk_sleep_init();
|
||||||
}
|
}
|
||||||
CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init);
|
CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init);
|
||||||
|
|
|
@ -101,7 +101,7 @@ static void __init exynos5440_clk_init(struct device_node *np)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
samsung_clk_init(np, reg_base, CLK_NR_CLKS, NULL, 0, NULL, 0);
|
samsung_clk_init(np, reg_base, CLK_NR_CLKS);
|
||||||
samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks,
|
samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks,
|
||||||
ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match);
|
ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/clk-provider.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
|
|
||||||
#include <dt-bindings/clock/samsung,s3c64xx-clock.h>
|
#include <dt-bindings/clock/samsung,s3c64xx-clock.h>
|
||||||
|
|
||||||
|
@ -61,6 +62,13 @@ enum s3c64xx_plls {
|
||||||
apll, mpll, epll,
|
apll, mpll, epll,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void __iomem *reg_base;
|
||||||
|
static bool is_s3c6400;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static struct samsung_clk_reg_dump *s3c64xx_save_common;
|
||||||
|
static struct samsung_clk_reg_dump *s3c64xx_save_soc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of controller registers to be saved and restored during
|
* List of controller registers to be saved and restored during
|
||||||
* a suspend/resume cycle.
|
* a suspend/resume cycle.
|
||||||
|
@ -87,6 +95,60 @@ static unsigned long s3c6410_clk_regs[] __initdata = {
|
||||||
MEM0_GATE,
|
MEM0_GATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int s3c64xx_clk_suspend(void)
|
||||||
|
{
|
||||||
|
samsung_clk_save(reg_base, s3c64xx_save_common,
|
||||||
|
ARRAY_SIZE(s3c64xx_clk_regs));
|
||||||
|
|
||||||
|
if (!is_s3c6400)
|
||||||
|
samsung_clk_save(reg_base, s3c64xx_save_soc,
|
||||||
|
ARRAY_SIZE(s3c6410_clk_regs));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void s3c64xx_clk_resume(void)
|
||||||
|
{
|
||||||
|
samsung_clk_restore(reg_base, s3c64xx_save_common,
|
||||||
|
ARRAY_SIZE(s3c64xx_clk_regs));
|
||||||
|
|
||||||
|
if (!is_s3c6400)
|
||||||
|
samsung_clk_restore(reg_base, s3c64xx_save_soc,
|
||||||
|
ARRAY_SIZE(s3c6410_clk_regs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct syscore_ops s3c64xx_clk_syscore_ops = {
|
||||||
|
.suspend = s3c64xx_clk_suspend,
|
||||||
|
.resume = s3c64xx_clk_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void s3c64xx_clk_sleep_init(void)
|
||||||
|
{
|
||||||
|
s3c64xx_save_common = samsung_clk_alloc_reg_dump(s3c64xx_clk_regs,
|
||||||
|
ARRAY_SIZE(s3c64xx_clk_regs));
|
||||||
|
if (!s3c64xx_save_common)
|
||||||
|
goto err_warn;
|
||||||
|
|
||||||
|
if (!is_s3c6400) {
|
||||||
|
s3c64xx_save_soc = samsung_clk_alloc_reg_dump(s3c6410_clk_regs,
|
||||||
|
ARRAY_SIZE(s3c6410_clk_regs));
|
||||||
|
if (!s3c64xx_save_soc)
|
||||||
|
goto err_soc;
|
||||||
|
}
|
||||||
|
|
||||||
|
register_syscore_ops(&s3c64xx_clk_syscore_ops);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_soc:
|
||||||
|
kfree(s3c64xx_save_common);
|
||||||
|
err_warn:
|
||||||
|
pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void s3c64xx_clk_sleep_init(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* List of parent clocks common for all S3C64xx SoCs. */
|
/* List of parent clocks common for all S3C64xx SoCs. */
|
||||||
PNAME(spi_mmc_p) = { "mout_epll", "dout_mpll", "fin_pll", "clk27m" };
|
PNAME(spi_mmc_p) = { "mout_epll", "dout_mpll", "fin_pll", "clk27m" };
|
||||||
PNAME(uart_p) = { "mout_epll", "dout_mpll" };
|
PNAME(uart_p) = { "mout_epll", "dout_mpll" };
|
||||||
|
@ -391,11 +453,11 @@ static void __init s3c64xx_clk_register_fixed_ext(unsigned long fin_pll_f,
|
||||||
|
|
||||||
/* Register s3c64xx clocks. */
|
/* Register s3c64xx clocks. */
|
||||||
void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
|
void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
|
||||||
unsigned long xusbxti_f, bool is_s3c6400,
|
unsigned long xusbxti_f, bool s3c6400,
|
||||||
void __iomem *reg_base)
|
void __iomem *base)
|
||||||
{
|
{
|
||||||
unsigned long *soc_regs = NULL;
|
reg_base = base;
|
||||||
unsigned long nr_soc_regs = 0;
|
is_s3c6400 = s3c6400;
|
||||||
|
|
||||||
if (np) {
|
if (np) {
|
||||||
reg_base = of_iomap(np, 0);
|
reg_base = of_iomap(np, 0);
|
||||||
|
@ -403,13 +465,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
|
||||||
panic("%s: failed to map registers\n", __func__);
|
panic("%s: failed to map registers\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_s3c6400) {
|
samsung_clk_init(np, reg_base, NR_CLKS);
|
||||||
soc_regs = s3c6410_clk_regs;
|
|
||||||
nr_soc_regs = ARRAY_SIZE(s3c6410_clk_regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
samsung_clk_init(np, reg_base, NR_CLKS, s3c64xx_clk_regs,
|
|
||||||
ARRAY_SIZE(s3c64xx_clk_regs), soc_regs, nr_soc_regs);
|
|
||||||
|
|
||||||
/* Register external clocks. */
|
/* Register external clocks. */
|
||||||
if (!np)
|
if (!np)
|
||||||
|
@ -452,6 +508,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
|
||||||
|
|
||||||
samsung_clk_register_alias(s3c64xx_clock_aliases,
|
samsung_clk_register_alias(s3c64xx_clock_aliases,
|
||||||
ARRAY_SIZE(s3c64xx_clock_aliases));
|
ARRAY_SIZE(s3c64xx_clock_aliases));
|
||||||
|
s3c64xx_clk_sleep_init();
|
||||||
|
|
||||||
pr_info("%s clocks: apll = %lu, mpll = %lu\n"
|
pr_info("%s clocks: apll = %lu, mpll = %lu\n"
|
||||||
"\tepll = %lu, arm_clk = %lu\n",
|
"\tepll = %lu, arm_clk = %lu\n",
|
||||||
|
|
|
@ -21,64 +21,45 @@ static void __iomem *reg_base;
|
||||||
static struct clk_onecell_data clk_data;
|
static struct clk_onecell_data clk_data;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
void samsung_clk_save(void __iomem *base,
|
||||||
static struct samsung_clk_reg_dump *reg_dump;
|
struct samsung_clk_reg_dump *rd,
|
||||||
static unsigned long nr_reg_dump;
|
unsigned int num_regs)
|
||||||
|
|
||||||
static int samsung_clk_suspend(void)
|
|
||||||
{
|
{
|
||||||
struct samsung_clk_reg_dump *rd = reg_dump;
|
for (; num_regs > 0; --num_regs, ++rd)
|
||||||
unsigned long i;
|
rd->value = readl(base + rd->offset);
|
||||||
|
|
||||||
for (i = 0; i < nr_reg_dump; i++, rd++)
|
|
||||||
rd->value = __raw_readl(reg_base + rd->offset);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void samsung_clk_resume(void)
|
void samsung_clk_restore(void __iomem *base,
|
||||||
|
const struct samsung_clk_reg_dump *rd,
|
||||||
|
unsigned int num_regs)
|
||||||
{
|
{
|
||||||
struct samsung_clk_reg_dump *rd = reg_dump;
|
for (; num_regs > 0; --num_regs, ++rd)
|
||||||
unsigned long i;
|
writel(rd->value, base + rd->offset);
|
||||||
|
|
||||||
for (i = 0; i < nr_reg_dump; i++, rd++)
|
|
||||||
__raw_writel(rd->value, reg_base + rd->offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct syscore_ops samsung_clk_syscore_ops = {
|
struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
|
||||||
.suspend = samsung_clk_suspend,
|
const unsigned long *rdump,
|
||||||
.resume = samsung_clk_resume,
|
unsigned long nr_rdump)
|
||||||
};
|
{
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
struct samsung_clk_reg_dump *rd;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL);
|
||||||
|
if (!rd)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_rdump; ++i)
|
||||||
|
rd[i].offset = rdump[i];
|
||||||
|
|
||||||
|
return rd;
|
||||||
|
}
|
||||||
|
|
||||||
/* setup the essentials required to support clock lookup using ccf */
|
/* setup the essentials required to support clock lookup using ccf */
|
||||||
void __init samsung_clk_init(struct device_node *np, void __iomem *base,
|
void __init samsung_clk_init(struct device_node *np, void __iomem *base,
|
||||||
unsigned long nr_clks, unsigned long *rdump,
|
unsigned long nr_clks)
|
||||||
unsigned long nr_rdump, unsigned long *soc_rdump,
|
|
||||||
unsigned long nr_soc_rdump)
|
|
||||||
{
|
{
|
||||||
reg_base = base;
|
reg_base = base;
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
if (rdump && nr_rdump) {
|
|
||||||
unsigned int idx;
|
|
||||||
reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
|
|
||||||
* (nr_rdump + nr_soc_rdump), GFP_KERNEL);
|
|
||||||
if (!reg_dump) {
|
|
||||||
pr_err("%s: memory alloc for register dump failed\n",
|
|
||||||
__func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (idx = 0; idx < nr_rdump; idx++)
|
|
||||||
reg_dump[idx].offset = rdump[idx];
|
|
||||||
for (idx = 0; idx < nr_soc_rdump; idx++)
|
|
||||||
reg_dump[nr_rdump + idx].offset = soc_rdump[idx];
|
|
||||||
nr_reg_dump = nr_rdump + nr_soc_rdump;
|
|
||||||
register_syscore_ops(&samsung_clk_syscore_ops);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
|
clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
|
||||||
if (!clk_table)
|
if (!clk_table)
|
||||||
panic("could not allocate clock lookup table\n");
|
panic("could not allocate clock lookup table\n");
|
||||||
|
|
|
@ -313,9 +313,7 @@ struct samsung_pll_clock {
|
||||||
_lock, _con, _rtable, _alias)
|
_lock, _con, _rtable, _alias)
|
||||||
|
|
||||||
extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
|
extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
|
||||||
unsigned long nr_clks, unsigned long *rdump,
|
unsigned long nr_clks);
|
||||||
unsigned long nr_rdump, unsigned long *soc_rdump,
|
|
||||||
unsigned long nr_soc_rdump);
|
|
||||||
extern void __init samsung_clk_of_register_fixed_ext(
|
extern void __init samsung_clk_of_register_fixed_ext(
|
||||||
struct samsung_fixed_rate_clock *fixed_rate_clk,
|
struct samsung_fixed_rate_clock *fixed_rate_clk,
|
||||||
unsigned int nr_fixed_rate_clk,
|
unsigned int nr_fixed_rate_clk,
|
||||||
|
@ -340,4 +338,14 @@ extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
|
||||||
|
|
||||||
extern unsigned long _get_rate(const char *clk_name);
|
extern unsigned long _get_rate(const char *clk_name);
|
||||||
|
|
||||||
|
extern void samsung_clk_save(void __iomem *base,
|
||||||
|
struct samsung_clk_reg_dump *rd,
|
||||||
|
unsigned int num_regs);
|
||||||
|
extern void samsung_clk_restore(void __iomem *base,
|
||||||
|
const struct samsung_clk_reg_dump *rd,
|
||||||
|
unsigned int num_regs);
|
||||||
|
extern struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
|
||||||
|
const unsigned long *rdump,
|
||||||
|
unsigned long nr_rdump);
|
||||||
|
|
||||||
#endif /* __SAMSUNG_CLK_H */
|
#endif /* __SAMSUNG_CLK_H */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче