Skip to content

Commit

Permalink
Merge branch 'imx/soc' into imx/dt
Browse files Browse the repository at this point in the history
  • Loading branch information
Shawn Guo committed Jan 13, 2015
2 parents cbd54fe + c205389 commit 5d15798
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 20 deletions.
12 changes: 12 additions & 0 deletions Documentation/devicetree/bindings/arm/fsl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ i.MX6q generic board
Required root node properties:
- compatible = "fsl,imx6q";

Freescale Vybrid Platform Device Tree Bindings
----------------------------------------------

For the Vybrid SoC familiy all variants with DDR controller are supported,
which is the VF5xx and VF6xx series. Out of historical reasons, in most
places the kernel uses vf610 to refer to the whole familiy.

Required root node compatible property (one of them):
- compatible = "fsl,vf500";
- compatible = "fsl,vf510";
- compatible = "fsl,vf600";
- compatible = "fsl,vf610";

Freescale LS1021A Platform Device Tree Bindings
------------------------------------------------
Expand Down
3 changes: 1 addition & 2 deletions arch/arm/mach-imx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ ifeq ($(CONFIG_CPU_IDLE),y)
obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o
# i.MX6SX reuses i.MX6Q cpuidle driver
obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6q.o
obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o
endif

ifdef CONFIG_SND_IMX_SOC
Expand Down
23 changes: 19 additions & 4 deletions arch/arm/mach-imx/clk-gate2.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,30 @@ static int clk_gate2_is_enabled(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);

if (gate->share_count)
return !!__clk_get_enable_count(hw->clk);
else
return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
}

static void clk_gate2_disable_unused(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
unsigned long flags = 0;
u32 reg;

spin_lock_irqsave(gate->lock, flags);

if (!gate->share_count || *gate->share_count == 0) {
reg = readl(gate->reg);
reg &= ~(3 << gate->bit_idx);
writel(reg, gate->reg);
}

spin_unlock_irqrestore(gate->lock, flags);
}

static struct clk_ops clk_gate2_ops = {
.enable = clk_gate2_enable,
.disable = clk_gate2_disable,
.disable_unused = clk_gate2_disable_unused,
.is_enabled = clk_gate2_is_enabled,
};

Expand Down
10 changes: 7 additions & 3 deletions arch/arm/mach-imx/clk-pllv3.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* @base: base address of PLL registers
* @powerup_set: set POWER bit to power up the PLL
* @div_mask: mask of divider bits
* @div_shift: shift of divider bits
*
* IMX PLL clock version 3, found on i.MX6 series. Divider for pllv3
* is actually a multiplier, and always sits at bit 0.
Expand All @@ -40,6 +41,7 @@ struct clk_pllv3 {
void __iomem *base;
bool powerup_set;
u32 div_mask;
u32 div_shift;
};

#define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw)
Expand Down Expand Up @@ -97,7 +99,7 @@ static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pllv3 *pll = to_clk_pllv3(hw);
u32 div = readl_relaxed(pll->base) & pll->div_mask;
u32 div = (readl_relaxed(pll->base) >> pll->div_shift) & pll->div_mask;

return (div == 1) ? parent_rate * 22 : parent_rate * 20;
}
Expand Down Expand Up @@ -125,8 +127,8 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate,
return -EINVAL;

val = readl_relaxed(pll->base);
val &= ~pll->div_mask;
val |= div;
val &= ~(pll->div_mask << pll->div_shift);
val |= (div << pll->div_shift);
writel_relaxed(val, pll->base);

return clk_pllv3_wait_lock(pll);
Expand Down Expand Up @@ -295,6 +297,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
case IMX_PLLV3_SYS:
ops = &clk_pllv3_sys_ops;
break;
case IMX_PLLV3_USB_VF610:
pll->div_shift = 1;
case IMX_PLLV3_USB:
ops = &clk_pllv3_ops;
pll->powerup_set = true;
Expand Down
8 changes: 6 additions & 2 deletions arch/arm/mach-imx/clk-vf610.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,11 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)

clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1);
clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1);
clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", PLL3_CTRL, 0x1);
clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB_VF610, "pll3", "pll3_bypass_src", PLL3_CTRL, 0x2);
clk[VF610_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", PLL4_CTRL, 0x7f);
clk[VF610_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll5", "pll5_bypass_src", PLL5_CTRL, 0x3);
clk[VF610_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_AV, "pll6", "pll6_bypass_src", PLL6_CTRL, 0x7f);
clk[VF610_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", PLL7_CTRL, 0x1);
clk[VF610_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB_VF610, "pll7", "pll7_bypass_src", PLL7_CTRL, 0x2);

clk[VF610_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", PLL1_CTRL, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
clk[VF610_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", PLL2_CTRL, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
Expand Down Expand Up @@ -267,6 +267,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_UART1] = imx_clk_gate2("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8));
clk[VF610_CLK_UART2] = imx_clk_gate2("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9));
clk[VF610_CLK_UART3] = imx_clk_gate2("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10));
clk[VF610_CLK_UART4] = imx_clk_gate2("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9));
clk[VF610_CLK_UART5] = imx_clk_gate2("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10));

clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6));
clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7));
Expand Down Expand Up @@ -380,6 +382,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_DMAMUX2] = imx_clk_gate2("dmamux2", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(1));
clk[VF610_CLK_DMAMUX3] = imx_clk_gate2("dmamux3", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(2));

clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(7));

imx_check_clocks(clk, ARRAY_SIZE(clk));

clk_set_parent(clk[VF610_CLK_QSPI0_SEL], clk[VF610_CLK_PLL1_PFD4]);
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-imx/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum imx_pllv3_type {
IMX_PLLV3_GENERIC,
IMX_PLLV3_SYS,
IMX_PLLV3_USB,
IMX_PLLV3_USB_VF610,
IMX_PLLV3_AV,
IMX_PLLV3_ENET,
};
Expand Down
4 changes: 4 additions & 0 deletions arch/arm/mach-imx/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ void imx_set_soc_revision(unsigned int rev);
unsigned int imx_get_soc_revision(void);
void imx_init_revision_from_anatop(void);
struct device *imx_soc_device_init(void);
void imx6_enable_rbc(bool enable);
void imx_gpc_set_arm_power_in_lpm(bool power_off);
void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw);
void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw);

enum mxc_cpu_pwr_mode {
WAIT_CLOCKED, /* wfi only */
Expand Down
105 changes: 105 additions & 0 deletions arch/arm/mach-imx/cpuidle-imx6sx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* 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.
*/

#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/module.h>
#include <asm/cpuidle.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>

#include "common.h"
#include "cpuidle.h"

static int imx6sx_idle_finish(unsigned long val)
{
cpu_do_idle();

return 0;
}

static int imx6sx_enter_wait(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
imx6q_set_lpm(WAIT_UNCLOCKED);

switch (index) {
case 1:
cpu_do_idle();
break;
case 2:
imx6_enable_rbc(true);
imx_gpc_set_arm_power_in_lpm(true);
imx_set_cpu_jump(0, v7_cpu_resume);
/* Need to notify there is a cpu pm operation. */
cpu_pm_enter();
cpu_cluster_pm_enter();

cpu_suspend(0, imx6sx_idle_finish);

cpu_cluster_pm_exit();
cpu_pm_exit();
imx_gpc_set_arm_power_in_lpm(false);
imx6_enable_rbc(false);
break;
default:
break;
}

imx6q_set_lpm(WAIT_CLOCKED);

return index;
}

static struct cpuidle_driver imx6sx_cpuidle_driver = {
.name = "imx6sx_cpuidle",
.owner = THIS_MODULE,
.states = {
/* WFI */
ARM_CPUIDLE_WFI_STATE,
/* WAIT */
{
.exit_latency = 50,
.target_residency = 75,
.flags = CPUIDLE_FLAG_TIMER_STOP,
.enter = imx6sx_enter_wait,
.name = "WAIT",
.desc = "Clock off",
},
/* WAIT + ARM power off */
{
/*
* ARM gating 31us * 5 + RBC clear 65us
* and some margin for SW execution, here set it
* to 300us.
*/
.exit_latency = 300,
.target_residency = 500,
.enter = imx6sx_enter_wait,
.name = "LOW-POWER-IDLE",
.desc = "ARM power off",
},
},
.state_count = 3,
.safe_state_index = 0,
};

int __init imx6sx_cpuidle_init(void)
{
imx6_enable_rbc(false);
/*
* set ARM power up/down timing to the fastest,
* sw2iso and sw can be set to one 32K cycle = 31us
* except for power up sw2iso which need to be
* larger than LDO ramp up time.
*/
imx_gpc_set_arm_power_up_timing(2, 1);
imx_gpc_set_arm_power_down_timing(1, 1);

return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
}
5 changes: 5 additions & 0 deletions arch/arm/mach-imx/cpuidle.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
extern int imx5_cpuidle_init(void);
extern int imx6q_cpuidle_init(void);
extern int imx6sl_cpuidle_init(void);
extern int imx6sx_cpuidle_init(void);
#else
static inline int imx5_cpuidle_init(void)
{
Expand All @@ -27,4 +28,8 @@ static inline int imx6sl_cpuidle_init(void)
{
return 0;
}
static inline int imx6sx_cpuidle_init(void)
{
return 0;
}
#endif
25 changes: 23 additions & 2 deletions arch/arm/mach-imx/gpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,42 @@

#define GPC_IMR1 0x008
#define GPC_PGC_CPU_PDN 0x2a0
#define GPC_PGC_CPU_PUPSCR 0x2a4
#define GPC_PGC_CPU_PDNSCR 0x2a8
#define GPC_PGC_SW2ISO_SHIFT 0x8
#define GPC_PGC_SW_SHIFT 0x0

#define IMR_NUM 4

static void __iomem *gpc_base;
static u32 gpc_wake_irqs[IMR_NUM];
static u32 gpc_saved_imrs[IMR_NUM];

void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw)
{
writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) |
(sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PUPSCR);
}

void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw)
{
writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) |
(sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PDNSCR);
}

void imx_gpc_set_arm_power_in_lpm(bool power_off)
{
writel_relaxed(power_off, gpc_base + GPC_PGC_CPU_PDN);
}

void imx_gpc_pre_suspend(bool arm_power_off)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
int i;

/* Tell GPC to power off ARM core when suspend */
if (arm_power_off)
writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
imx_gpc_set_arm_power_in_lpm(arm_power_off);

for (i = 0; i < IMR_NUM; i++) {
gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
Expand All @@ -48,7 +69,7 @@ void imx_gpc_post_resume(void)
int i;

/* Keep ARM core powered on for other low-power modes */
writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN);
imx_gpc_set_arm_power_in_lpm(false);

for (i = 0; i < IMR_NUM; i++)
writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/mach-imx/mach-imx6sx.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static void __init imx6sx_init_irq(void)

static void __init imx6sx_init_late(void)
{
imx6q_cpuidle_init();
imx6sx_cpuidle_init();

if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
Expand Down
5 changes: 4 additions & 1 deletion arch/arm/mach-imx/mach-vf610.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
#include <asm/hardware/cache-l2x0.h>

static const char * const vf610_dt_compat[] __initconst = {
"fsl,vf500",
"fsl,vf510",
"fsl,vf600",
"fsl,vf610",
NULL,
};

DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF610 (Device Tree)")
DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF5xx/VF6xx (Device Tree)")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
.dt_compat = vf610_dt_compat,
Expand Down
7 changes: 3 additions & 4 deletions arch/arm/mach-imx/pm-imx6.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ void imx6q_set_int_mem_clk_lpm(bool enable)
writel_relaxed(val, ccm_base + CGPR);
}

static void imx6q_enable_rbc(bool enable)
void imx6_enable_rbc(bool enable)
{
u32 val;

Expand Down Expand Up @@ -359,17 +359,16 @@ static int imx6q_pm_enter(suspend_state_t state)
* RBC setting, so we do NOT need to do that here.
*/
if (!imx6_suspend_in_ocram_fn)
imx6q_enable_rbc(true);
imx6_enable_rbc(true);
imx_gpc_pre_suspend(true);
imx_anatop_pre_suspend();
imx_set_cpu_jump(0, v7_cpu_resume);
/* Zzz ... */
cpu_suspend(0, imx6q_suspend_finish);
if (cpu_is_imx6q() || cpu_is_imx6dl())
imx_smp_prepare();
imx_anatop_post_resume();
imx_gpc_post_resume();
imx6q_enable_rbc(false);
imx6_enable_rbc(false);
imx6q_enable_wb(false);
imx6q_set_int_mem_clk_lpm(true);
imx6q_set_lpm(WAIT_CLOCKED);
Expand Down
3 changes: 2 additions & 1 deletion include/dt-bindings/clock/vf610-clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@
#define VF610_PLL5_BYPASS 179
#define VF610_PLL6_BYPASS 180
#define VF610_PLL7_BYPASS 181
#define VF610_CLK_END 182
#define VF610_CLK_SNVS 182
#define VF610_CLK_END 183

#endif /* __DT_BINDINGS_CLOCK_VF610_H */

0 comments on commit 5d15798

Please sign in to comment.