Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform support updates from Kevin Hilman: "Our SoC branch usually contains expanded support for new SoCs and other core platform code. Some highlights from this round: - sunxi: SMP support for A23 SoC - socpga: big-endian support - pxa: conversion to common clock framework - bcm: SMP support for BCM63138 - imx: support new I.MX7D SoC - zte: basic support for ZX296702 SoC" * tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (134 commits) ARM: zx: Add basic defconfig support for ZX296702 ARM: dts: zx: add an initial zx296702 dts and doc clk: zx: add clock support to zx296702 dt-bindings: Add #defines for ZTE ZX296702 clocks ARM: socfpga: fix build error due to secondary_startup MAINTAINERS: ARM64: EXYNOS: Extend entry for ARM64 DTS ARM: ep93xx: simone: support for SPI-based MMC/SD cards MAINTAINERS: update Shawn's email to use kernel.org one ARM: socfpga: support suspend to ram ARM: socfpga: add CPU_METHOD_OF_DECLARE for Arria 10 ARM: socfpga: use CPU_METHOD_OF_DECLARE for socfpga_cyclone5 ARM: EXYNOS: register power domain driver from core_initcall ARM: EXYNOS: use PS_HOLD based poweroff for all supported SoCs ARM: SAMSUNG: Constify platform_device_id ARM: EXYNOS: Constify irq_domain_ops ARM: EXYNOS: add coupled cpuidle support for Exynos3250 ARM: EXYNOS: add exynos_get_boot_addr() helper ARM: EXYNOS: add exynos_set_boot_addr() helper ARM: EXYNOS: make exynos_core_restart() less verbose ARM: EXYNOS: fix exynos_boot_secondary() return value on timeout ...
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
menuconfig ARCH_MXC
|
||||
bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7
|
||||
bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 || ARM_SINGLE_ARMV7M
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select ARM_CPU_SUSPEND if PM
|
||||
select CLKSRC_MMIO
|
||||
select CLKSRC_IMX_GPT
|
||||
select GENERIC_IRQ_CHIP
|
||||
select PINCTRL
|
||||
select PM_OPP if PM
|
||||
@@ -462,10 +462,10 @@ config MACH_VPR200
|
||||
|
||||
endif
|
||||
|
||||
if ARCH_MULTI_V5
|
||||
|
||||
comment "Device tree only"
|
||||
|
||||
if ARCH_MULTI_V5
|
||||
|
||||
config SOC_IMX25
|
||||
bool "i.MX25 support"
|
||||
select ARCH_MXC_IOMUX_V3
|
||||
@@ -478,7 +478,7 @@ endif
|
||||
|
||||
if ARCH_MULTI_V7
|
||||
|
||||
comment "Device tree only"
|
||||
comment "Cortex-A platforms"
|
||||
|
||||
config SOC_IMX5
|
||||
bool
|
||||
@@ -548,10 +548,33 @@ config SOC_IMX6SX
|
||||
help
|
||||
This enables support for Freescale i.MX6 SoloX processor.
|
||||
|
||||
config SOC_IMX7D
|
||||
bool "i.MX7 Dual support"
|
||||
select PINCTRL_IMX7D
|
||||
select ARM_GIC
|
||||
select HAVE_IMX_ANATOP
|
||||
select HAVE_IMX_MMDC
|
||||
help
|
||||
This enables support for Freescale i.MX7 Dual processor.
|
||||
|
||||
config SOC_LS1021A
|
||||
bool "Freescale LS1021A support"
|
||||
select ARM_GIC
|
||||
select HAVE_ARM_ARCH_TIMER
|
||||
select PCI_DOMAINS if PCI
|
||||
select ZONE_DMA if ARM_LPAE
|
||||
help
|
||||
This enables support for Freescale LS1021A processor.
|
||||
|
||||
endif
|
||||
|
||||
comment "Cortex-A/Cortex-M asymmetric multiprocessing platforms"
|
||||
|
||||
if ARCH_MULTI_V7 || ARM_SINGLE_ARMV7M
|
||||
|
||||
config SOC_VF610
|
||||
bool "Vybrid Family VF610 support"
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select ARM_GIC
|
||||
select ARM_GIC if ARCH_MULTI_V7
|
||||
select PINCTRL_VF610
|
||||
select PL310_ERRATA_769419 if CACHE_L2X0
|
||||
select SMP_ON_UP if SMP
|
||||
@@ -565,7 +588,7 @@ choice
|
||||
default VF_USE_ARM_GLOBAL_TIMER
|
||||
|
||||
config VF_USE_ARM_GLOBAL_TIMER
|
||||
bool "Use ARM Global Timer"
|
||||
bool "Use ARM Global Timer" if ARCH_MULTI_V7
|
||||
select ARM_GLOBAL_TIMER
|
||||
select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
|
||||
help
|
||||
@@ -579,16 +602,6 @@ choice
|
||||
|
||||
endchoice
|
||||
|
||||
config SOC_LS1021A
|
||||
bool "Freescale LS1021A support"
|
||||
select ARM_GIC
|
||||
select HAVE_ARM_ARCH_TIMER
|
||||
select PCI_DOMAINS if PCI
|
||||
select ZONE_DMA if ARM_LPAE
|
||||
|
||||
help
|
||||
This enables support for Freescale LS1021A processor.
|
||||
|
||||
endif
|
||||
|
||||
source "arch/arm/mach-imx/devices/Kconfig"
|
||||
|
@@ -1,23 +1,18 @@
|
||||
obj-y := time.o cpu.o system.o irq-common.o
|
||||
obj-y := cpu.o system.o irq-common.o
|
||||
|
||||
obj-$(CONFIG_SOC_IMX1) += clk-imx1.o mm-imx1.o
|
||||
obj-$(CONFIG_SOC_IMX21) += clk-imx21.o mm-imx21.o
|
||||
obj-$(CONFIG_SOC_IMX1) += mm-imx1.o
|
||||
obj-$(CONFIG_SOC_IMX21) += mm-imx21.o
|
||||
|
||||
obj-$(CONFIG_SOC_IMX25) += clk-imx25.o cpu-imx25.o mach-imx25.o
|
||||
obj-$(CONFIG_SOC_IMX25) += cpu-imx25.o mach-imx25.o
|
||||
|
||||
obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o
|
||||
obj-$(CONFIG_SOC_IMX27) += clk-imx27.o mm-imx27.o ehci-imx27.o
|
||||
obj-$(CONFIG_SOC_IMX27) += mm-imx27.o ehci-imx27.o
|
||||
|
||||
obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o
|
||||
obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o
|
||||
obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o
|
||||
obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o ehci-imx35.o pm-imx3.o
|
||||
|
||||
imx5-pm-$(CONFIG_PM) += pm-imx5.o
|
||||
obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y)
|
||||
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \
|
||||
clk-pfd.o clk-busy.o clk.o \
|
||||
clk-fixup-div.o clk-fixup-mux.o \
|
||||
clk-gate-exclusive.o
|
||||
obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o $(imx5-pm-y)
|
||||
|
||||
obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
|
||||
obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
|
||||
@@ -85,13 +80,15 @@ AFLAGS_headsmp.o :=-Wa,-march=armv7-a
|
||||
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
endif
|
||||
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o
|
||||
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o
|
||||
obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.o
|
||||
obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o
|
||||
obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o
|
||||
obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o
|
||||
obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o
|
||||
|
||||
ifeq ($(CONFIG_SUSPEND),y)
|
||||
AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a
|
||||
obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o
|
||||
obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o
|
||||
endif
|
||||
obj-$(CONFIG_SOC_IMX6) += pm-imx6.o
|
||||
|
||||
@@ -99,7 +96,7 @@ obj-$(CONFIG_SOC_IMX50) += mach-imx50.o
|
||||
obj-$(CONFIG_SOC_IMX51) += mach-imx51.o
|
||||
obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
|
||||
|
||||
obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o
|
||||
obj-$(CONFIG_SOC_VF610) += mach-vf610.o
|
||||
|
||||
obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o
|
||||
|
||||
|
0
arch/arm/mach-imx/Makefile.boot
Normal file
0
arch/arm/mach-imx/Makefile.boot
Normal file
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
@@ -28,6 +28,7 @@
|
||||
#define ANADIG_USB2_CHRG_DETECT 0x210
|
||||
#define ANADIG_DIGPROG 0x260
|
||||
#define ANADIG_DIGPROG_IMX6SL 0x280
|
||||
#define ANADIG_DIGPROG_IMX7D 0x800
|
||||
|
||||
#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000
|
||||
#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8
|
||||
@@ -121,6 +122,8 @@ void __init imx_init_revision_from_anatop(void)
|
||||
WARN_ON(!anatop_base);
|
||||
if (of_device_is_compatible(np, "fsl,imx6sl-anatop"))
|
||||
offset = ANADIG_DIGPROG_IMX6SL;
|
||||
if (of_device_is_compatible(np, "fsl,imx7d-anatop"))
|
||||
offset = ANADIG_DIGPROG_IMX7D;
|
||||
digprog = readl_relaxed(anatop_base + offset);
|
||||
iounmap(anatop_base);
|
||||
|
||||
|
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright 2012 Linaro Ltd.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/err.h>
|
||||
#include "clk.h"
|
||||
|
||||
static int clk_busy_wait(void __iomem *reg, u8 shift)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(10);
|
||||
|
||||
while (readl_relaxed(reg) & (1 << shift))
|
||||
if (time_after(jiffies, timeout))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct clk_busy_divider {
|
||||
struct clk_divider div;
|
||||
const struct clk_ops *div_ops;
|
||||
void __iomem *reg;
|
||||
u8 shift;
|
||||
};
|
||||
|
||||
static inline struct clk_busy_divider *to_clk_busy_divider(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_divider *div = container_of(hw, struct clk_divider, hw);
|
||||
|
||||
return container_of(div, struct clk_busy_divider, div);
|
||||
}
|
||||
|
||||
static unsigned long clk_busy_divider_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_busy_divider *busy = to_clk_busy_divider(hw);
|
||||
|
||||
return busy->div_ops->recalc_rate(&busy->div.hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_busy_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_busy_divider *busy = to_clk_busy_divider(hw);
|
||||
|
||||
return busy->div_ops->round_rate(&busy->div.hw, rate, prate);
|
||||
}
|
||||
|
||||
static int clk_busy_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_busy_divider *busy = to_clk_busy_divider(hw);
|
||||
int ret;
|
||||
|
||||
ret = busy->div_ops->set_rate(&busy->div.hw, rate, parent_rate);
|
||||
if (!ret)
|
||||
ret = clk_busy_wait(busy->reg, busy->shift);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_busy_divider_ops = {
|
||||
.recalc_rate = clk_busy_divider_recalc_rate,
|
||||
.round_rate = clk_busy_divider_round_rate,
|
||||
.set_rate = clk_busy_divider_set_rate,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
void __iomem *busy_reg, u8 busy_shift)
|
||||
{
|
||||
struct clk_busy_divider *busy;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
busy = kzalloc(sizeof(*busy), GFP_KERNEL);
|
||||
if (!busy)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
busy->reg = busy_reg;
|
||||
busy->shift = busy_shift;
|
||||
|
||||
busy->div.reg = reg;
|
||||
busy->div.shift = shift;
|
||||
busy->div.width = width;
|
||||
busy->div.lock = &imx_ccm_lock;
|
||||
busy->div_ops = &clk_divider_ops;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_busy_divider_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
busy->div.hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &busy->div.hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(busy);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk_busy_mux {
|
||||
struct clk_mux mux;
|
||||
const struct clk_ops *mux_ops;
|
||||
void __iomem *reg;
|
||||
u8 shift;
|
||||
};
|
||||
|
||||
static inline struct clk_busy_mux *to_clk_busy_mux(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_mux *mux = container_of(hw, struct clk_mux, hw);
|
||||
|
||||
return container_of(mux, struct clk_busy_mux, mux);
|
||||
}
|
||||
|
||||
static u8 clk_busy_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_busy_mux *busy = to_clk_busy_mux(hw);
|
||||
|
||||
return busy->mux_ops->get_parent(&busy->mux.hw);
|
||||
}
|
||||
|
||||
static int clk_busy_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_busy_mux *busy = to_clk_busy_mux(hw);
|
||||
int ret;
|
||||
|
||||
ret = busy->mux_ops->set_parent(&busy->mux.hw, index);
|
||||
if (!ret)
|
||||
ret = clk_busy_wait(busy->reg, busy->shift);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_busy_mux_ops = {
|
||||
.get_parent = clk_busy_mux_get_parent,
|
||||
.set_parent = clk_busy_mux_set_parent,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
|
||||
u8 width, void __iomem *busy_reg, u8 busy_shift,
|
||||
const char **parent_names, int num_parents)
|
||||
{
|
||||
struct clk_busy_mux *busy;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
busy = kzalloc(sizeof(*busy), GFP_KERNEL);
|
||||
if (!busy)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
busy->reg = busy_reg;
|
||||
busy->shift = busy_shift;
|
||||
|
||||
busy->mux.reg = reg;
|
||||
busy->mux.shift = shift;
|
||||
busy->mux.mask = BIT(width) - 1;
|
||||
busy->mux.lock = &imx_ccm_lock;
|
||||
busy->mux_ops = &clk_mux_ops;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_busy_mux_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
busy->mux.hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &busy->mux.hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(busy);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct clk_cpu {
|
||||
struct clk_hw hw;
|
||||
struct clk *div;
|
||||
struct clk *mux;
|
||||
struct clk *pll;
|
||||
struct clk *step;
|
||||
};
|
||||
|
||||
static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct clk_cpu, hw);
|
||||
}
|
||||
|
||||
static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_cpu *cpu = to_clk_cpu(hw);
|
||||
|
||||
return clk_get_rate(cpu->div);
|
||||
}
|
||||
|
||||
static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_cpu *cpu = to_clk_cpu(hw);
|
||||
|
||||
return clk_round_rate(cpu->pll, rate);
|
||||
}
|
||||
|
||||
static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_cpu *cpu = to_clk_cpu(hw);
|
||||
int ret;
|
||||
|
||||
/* switch to PLL bypass clock */
|
||||
ret = clk_set_parent(cpu->mux, cpu->step);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* reprogram PLL */
|
||||
ret = clk_set_rate(cpu->pll, rate);
|
||||
if (ret) {
|
||||
clk_set_parent(cpu->mux, cpu->pll);
|
||||
return ret;
|
||||
}
|
||||
/* switch back to PLL clock */
|
||||
clk_set_parent(cpu->mux, cpu->pll);
|
||||
|
||||
/* Ensure the divider is what we expect */
|
||||
clk_set_rate(cpu->div, rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_cpu_ops = {
|
||||
.recalc_rate = clk_cpu_recalc_rate,
|
||||
.round_rate = clk_cpu_round_rate,
|
||||
.set_rate = clk_cpu_set_rate,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
|
||||
struct clk *div, struct clk *mux, struct clk *pll,
|
||||
struct clk *step)
|
||||
{
|
||||
struct clk_cpu *cpu;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
|
||||
if (!cpu)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cpu->div = div;
|
||||
cpu->mux = mux;
|
||||
cpu->pll = pll;
|
||||
cpu->step = step;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_cpu_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
cpu->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &cpu->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(cpu);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include "clk.h"
|
||||
|
||||
#define to_clk_div(_hw) container_of(_hw, struct clk_divider, hw)
|
||||
#define div_mask(d) ((1 << (d->width)) - 1)
|
||||
|
||||
/**
|
||||
* struct clk_fixup_div - imx integer fixup divider clock
|
||||
* @divider: the parent class
|
||||
* @ops: pointer to clk_ops of parent class
|
||||
* @fixup: a hook to fixup the write value
|
||||
*
|
||||
* The imx fixup divider clock is a subclass of basic clk_divider
|
||||
* with an addtional fixup hook.
|
||||
*/
|
||||
struct clk_fixup_div {
|
||||
struct clk_divider divider;
|
||||
const struct clk_ops *ops;
|
||||
void (*fixup)(u32 *val);
|
||||
};
|
||||
|
||||
static inline struct clk_fixup_div *to_clk_fixup_div(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_div(hw);
|
||||
|
||||
return container_of(divider, struct clk_fixup_div, divider);
|
||||
}
|
||||
|
||||
static unsigned long clk_fixup_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
|
||||
|
||||
return fixup_div->ops->recalc_rate(&fixup_div->divider.hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_fixup_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
|
||||
|
||||
return fixup_div->ops->round_rate(&fixup_div->divider.hw, rate, prate);
|
||||
}
|
||||
|
||||
static int clk_fixup_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw);
|
||||
struct clk_divider *div = to_clk_div(hw);
|
||||
unsigned int divider, value;
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
divider = parent_rate / rate;
|
||||
|
||||
/* Zero based divider */
|
||||
value = divider - 1;
|
||||
|
||||
if (value > div_mask(div))
|
||||
value = div_mask(div);
|
||||
|
||||
spin_lock_irqsave(div->lock, flags);
|
||||
|
||||
val = readl(div->reg);
|
||||
val &= ~(div_mask(div) << div->shift);
|
||||
val |= value << div->shift;
|
||||
fixup_div->fixup(&val);
|
||||
writel(val, div->reg);
|
||||
|
||||
spin_unlock_irqrestore(div->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_fixup_div_ops = {
|
||||
.recalc_rate = clk_fixup_div_recalc_rate,
|
||||
.round_rate = clk_fixup_div_round_rate,
|
||||
.set_rate = clk_fixup_div_set_rate,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
void (*fixup)(u32 *val))
|
||||
{
|
||||
struct clk_fixup_div *fixup_div;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!fixup)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
fixup_div = kzalloc(sizeof(*fixup_div), GFP_KERNEL);
|
||||
if (!fixup_div)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_fixup_div_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = parent ? &parent : NULL;
|
||||
init.num_parents = parent ? 1 : 0;
|
||||
|
||||
fixup_div->divider.reg = reg;
|
||||
fixup_div->divider.shift = shift;
|
||||
fixup_div->divider.width = width;
|
||||
fixup_div->divider.lock = &imx_ccm_lock;
|
||||
fixup_div->divider.hw.init = &init;
|
||||
fixup_div->ops = &clk_divider_ops;
|
||||
fixup_div->fixup = fixup;
|
||||
|
||||
clk = clk_register(NULL, &fixup_div->divider.hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(fixup_div);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include "clk.h"
|
||||
|
||||
#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
|
||||
|
||||
/**
|
||||
* struct clk_fixup_mux - imx integer fixup multiplexer clock
|
||||
* @mux: the parent class
|
||||
* @ops: pointer to clk_ops of parent class
|
||||
* @fixup: a hook to fixup the write value
|
||||
*
|
||||
* The imx fixup multiplexer clock is a subclass of basic clk_mux
|
||||
* with an addtional fixup hook.
|
||||
*/
|
||||
struct clk_fixup_mux {
|
||||
struct clk_mux mux;
|
||||
const struct clk_ops *ops;
|
||||
void (*fixup)(u32 *val);
|
||||
};
|
||||
|
||||
static inline struct clk_fixup_mux *to_clk_fixup_mux(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_mux *mux = to_clk_mux(hw);
|
||||
|
||||
return container_of(mux, struct clk_fixup_mux, mux);
|
||||
}
|
||||
|
||||
static u8 clk_fixup_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
|
||||
|
||||
return fixup_mux->ops->get_parent(&fixup_mux->mux.hw);
|
||||
}
|
||||
|
||||
static int clk_fixup_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw);
|
||||
struct clk_mux *mux = to_clk_mux(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(mux->lock, flags);
|
||||
|
||||
val = readl(mux->reg);
|
||||
val &= ~(mux->mask << mux->shift);
|
||||
val |= index << mux->shift;
|
||||
fixup_mux->fixup(&val);
|
||||
writel(val, mux->reg);
|
||||
|
||||
spin_unlock_irqrestore(mux->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_fixup_mux_ops = {
|
||||
.get_parent = clk_fixup_mux_get_parent,
|
||||
.set_parent = clk_fixup_mux_set_parent,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents,
|
||||
int num_parents, void (*fixup)(u32 *val))
|
||||
{
|
||||
struct clk_fixup_mux *fixup_mux;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!fixup)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
fixup_mux = kzalloc(sizeof(*fixup_mux), GFP_KERNEL);
|
||||
if (!fixup_mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_fixup_mux_ops;
|
||||
init.parent_names = parents;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = 0;
|
||||
|
||||
fixup_mux->mux.reg = reg;
|
||||
fixup_mux->mux.shift = shift;
|
||||
fixup_mux->mux.mask = BIT(width) - 1;
|
||||
fixup_mux->mux.lock = &imx_ccm_lock;
|
||||
fixup_mux->mux.hw.init = &init;
|
||||
fixup_mux->ops = &clk_mux_ops;
|
||||
fixup_mux->fixup = fixup;
|
||||
|
||||
clk = clk_register(NULL, &fixup_mux->mux.hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(fixup_mux);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 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/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include "clk.h"
|
||||
|
||||
/**
|
||||
* struct clk_gate_exclusive - i.MX specific gate clock which is mutually
|
||||
* exclusive with other gate clocks
|
||||
*
|
||||
* @gate: the parent class
|
||||
* @exclusive_mask: mask of gate bits which are mutually exclusive to this
|
||||
* gate clock
|
||||
*
|
||||
* The imx exclusive gate clock is a subclass of basic clk_gate
|
||||
* with an addtional mask to indicate which other gate bits in the same
|
||||
* register is mutually exclusive to this gate clock.
|
||||
*/
|
||||
struct clk_gate_exclusive {
|
||||
struct clk_gate gate;
|
||||
u32 exclusive_mask;
|
||||
};
|
||||
|
||||
static int clk_gate_exclusive_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate *gate = container_of(hw, struct clk_gate, hw);
|
||||
struct clk_gate_exclusive *exgate = container_of(gate,
|
||||
struct clk_gate_exclusive, gate);
|
||||
u32 val = readl(gate->reg);
|
||||
|
||||
if (val & exgate->exclusive_mask)
|
||||
return -EBUSY;
|
||||
|
||||
return clk_gate_ops.enable(hw);
|
||||
}
|
||||
|
||||
static void clk_gate_exclusive_disable(struct clk_hw *hw)
|
||||
{
|
||||
clk_gate_ops.disable(hw);
|
||||
}
|
||||
|
||||
static int clk_gate_exclusive_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
return clk_gate_ops.is_enabled(hw);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_gate_exclusive_ops = {
|
||||
.enable = clk_gate_exclusive_enable,
|
||||
.disable = clk_gate_exclusive_disable,
|
||||
.is_enabled = clk_gate_exclusive_is_enabled,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u32 exclusive_mask)
|
||||
{
|
||||
struct clk_gate_exclusive *exgate;
|
||||
struct clk_gate *gate;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (exclusive_mask == 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
exgate = kzalloc(sizeof(*exgate), GFP_KERNEL);
|
||||
if (!exgate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
gate = &exgate->gate;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_gate_exclusive_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = parent ? &parent : NULL;
|
||||
init.num_parents = parent ? 1 : 0;
|
||||
|
||||
gate->reg = reg;
|
||||
gate->bit_idx = shift;
|
||||
gate->lock = &imx_ccm_lock;
|
||||
gate->hw.init = &init;
|
||||
exgate->exclusive_mask = exclusive_mask;
|
||||
|
||||
clk = clk_register(NULL, &gate->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(exgate);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
|
||||
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Gated clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
#include "clk.h"
|
||||
|
||||
/**
|
||||
* DOC: basic gatable clock which can gate and ungate it's ouput
|
||||
*
|
||||
* Traits of this clock:
|
||||
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
||||
* enable - clk_enable and clk_disable are functional & control gating
|
||||
* rate - inherits rate from parent. No clk_set_rate support
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*/
|
||||
|
||||
struct clk_gate2 {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 bit_idx;
|
||||
u8 flags;
|
||||
spinlock_t *lock;
|
||||
unsigned int *share_count;
|
||||
};
|
||||
|
||||
#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
|
||||
|
||||
static int clk_gate2_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
u32 reg;
|
||||
unsigned long flags = 0;
|
||||
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
if (gate->share_count && (*gate->share_count)++ > 0)
|
||||
goto out;
|
||||
|
||||
reg = readl(gate->reg);
|
||||
reg |= 3 << gate->bit_idx;
|
||||
writel(reg, gate->reg);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_gate2_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
u32 reg;
|
||||
unsigned long flags = 0;
|
||||
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
|
||||
if (gate->share_count) {
|
||||
if (WARN_ON(*gate->share_count == 0))
|
||||
goto out;
|
||||
else if (--(*gate->share_count) > 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg = readl(gate->reg);
|
||||
reg &= ~(3 << gate->bit_idx);
|
||||
writel(reg, gate->reg);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
}
|
||||
|
||||
static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx)
|
||||
{
|
||||
u32 val = readl(reg);
|
||||
|
||||
if (((val >> bit_idx) & 1) == 1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_gate2_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gate2 *gate = to_clk_gate2(hw);
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
struct clk *clk_register_gate2(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx,
|
||||
u8 clk_gate2_flags, spinlock_t *lock,
|
||||
unsigned int *share_count)
|
||||
{
|
||||
struct clk_gate2 *gate;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* struct clk_gate2 assignments */
|
||||
gate->reg = reg;
|
||||
gate->bit_idx = bit_idx;
|
||||
gate->flags = clk_gate2_flags;
|
||||
gate->lock = lock;
|
||||
gate->share_count = share_count;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_gate2_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
gate->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &gate->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(gate);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <dt-bindings/clock/imx1-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
static const char *prem_sel_clks[] = { "clk32_premult", "clk16m", };
|
||||
static const char *clko_sel_clks[] = { "per1", "hclk", "clk48m", "clk16m",
|
||||
"prem", "fclk", };
|
||||
|
||||
static struct clk *clk[IMX1_CLK_MAX];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static void __iomem *ccm __initdata;
|
||||
#define CCM_CSCR (ccm + 0x0000)
|
||||
#define CCM_MPCTL0 (ccm + 0x0004)
|
||||
#define CCM_SPCTL0 (ccm + 0x000c)
|
||||
#define CCM_PCDR (ccm + 0x0020)
|
||||
#define SCM_GCCR (ccm + 0x0810)
|
||||
|
||||
static void __init _mx1_clocks_init(unsigned long fref)
|
||||
{
|
||||
clk[IMX1_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
clk[IMX1_CLK_CLK32] = imx_obtain_fixed_clock("clk32", fref);
|
||||
clk[IMX1_CLK_CLK16M_EXT] = imx_clk_fixed("clk16m_ext", 16000000);
|
||||
clk[IMX1_CLK_CLK16M] = imx_clk_gate("clk16m", "clk16m_ext", CCM_CSCR, 17);
|
||||
clk[IMX1_CLK_CLK32_PREMULT] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1);
|
||||
clk[IMX1_CLK_PREM] = imx_clk_mux("prem", CCM_CSCR, 16, 1, prem_sel_clks, ARRAY_SIZE(prem_sel_clks));
|
||||
clk[IMX1_CLK_MPLL] = imx_clk_pllv1("mpll", "clk32_premult", CCM_MPCTL0);
|
||||
clk[IMX1_CLK_MPLL_GATE] = imx_clk_gate("mpll_gate", "mpll", CCM_CSCR, 0);
|
||||
clk[IMX1_CLK_SPLL] = imx_clk_pllv1("spll", "prem", CCM_SPCTL0);
|
||||
clk[IMX1_CLK_SPLL_GATE] = imx_clk_gate("spll_gate", "spll", CCM_CSCR, 1);
|
||||
clk[IMX1_CLK_MCU] = imx_clk_divider("mcu", "clk32_premult", CCM_CSCR, 15, 1);
|
||||
clk[IMX1_CLK_FCLK] = imx_clk_divider("fclk", "mpll_gate", CCM_CSCR, 15, 1);
|
||||
clk[IMX1_CLK_HCLK] = imx_clk_divider("hclk", "spll_gate", CCM_CSCR, 10, 4);
|
||||
clk[IMX1_CLK_CLK48M] = imx_clk_divider("clk48m", "spll_gate", CCM_CSCR, 26, 3);
|
||||
clk[IMX1_CLK_PER1] = imx_clk_divider("per1", "spll_gate", CCM_PCDR, 0, 4);
|
||||
clk[IMX1_CLK_PER2] = imx_clk_divider("per2", "spll_gate", CCM_PCDR, 4, 4);
|
||||
clk[IMX1_CLK_PER3] = imx_clk_divider("per3", "spll_gate", CCM_PCDR, 16, 7);
|
||||
clk[IMX1_CLK_CLKO] = imx_clk_mux("clko", CCM_CSCR, 29, 3, clko_sel_clks, ARRAY_SIZE(clko_sel_clks));
|
||||
clk[IMX1_CLK_UART3_GATE] = imx_clk_gate("uart3_gate", "hclk", SCM_GCCR, 6);
|
||||
clk[IMX1_CLK_SSI2_GATE] = imx_clk_gate("ssi2_gate", "hclk", SCM_GCCR, 5);
|
||||
clk[IMX1_CLK_BROM_GATE] = imx_clk_gate("brom_gate", "hclk", SCM_GCCR, 4);
|
||||
clk[IMX1_CLK_DMA_GATE] = imx_clk_gate("dma_gate", "hclk", SCM_GCCR, 3);
|
||||
clk[IMX1_CLK_CSI_GATE] = imx_clk_gate("csi_gate", "hclk", SCM_GCCR, 2);
|
||||
clk[IMX1_CLK_MMA_GATE] = imx_clk_gate("mma_gate", "hclk", SCM_GCCR, 1);
|
||||
clk[IMX1_CLK_USBD_GATE] = imx_clk_gate("usbd_gate", "clk48m", SCM_GCCR, 0);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
}
|
||||
|
||||
int __init mx1_clocks_init(unsigned long fref)
|
||||
{
|
||||
ccm = MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR);
|
||||
|
||||
_mx1_clocks_init(fref);
|
||||
|
||||
clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_DMA_GATE], "ahb", "imx1-dma");
|
||||
clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx1-dma");
|
||||
clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx1-uart.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx1-uart.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx1-uart.1");
|
||||
clk_register_clkdev(clk[IMX1_CLK_HCLK], "ipg", "imx1-uart.1");
|
||||
clk_register_clkdev(clk[IMX1_CLK_PER1], "per", "imx1-uart.2");
|
||||
clk_register_clkdev(clk[IMX1_CLK_UART3_GATE], "ipg", "imx1-uart.2");
|
||||
clk_register_clkdev(clk[IMX1_CLK_HCLK], NULL, "imx1-i2c.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_PER2], "per", "imx1-cspi.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-cspi.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_PER2], "per", "imx1-cspi.1");
|
||||
clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-cspi.1");
|
||||
clk_register_clkdev(clk[IMX1_CLK_PER2], "per", "imx1-fb.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-fb.0");
|
||||
clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ahb", "imx1-fb.0");
|
||||
|
||||
mxc_timer_init(MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), MX1_TIM1_INT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init mx1_clocks_init_dt(struct device_node *np)
|
||||
{
|
||||
ccm = of_iomap(np, 0);
|
||||
BUG_ON(!ccm);
|
||||
|
||||
_mx1_clocks_init(32768);
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(imx1_ccm, "fsl,imx1-ccm", mx1_clocks_init_dt);
|
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
|
||||
* Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <dt-bindings/clock/imx21-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
static void __iomem *ccm __initdata;
|
||||
|
||||
/* Register offsets */
|
||||
#define CCM_CSCR (ccm + 0x00)
|
||||
#define CCM_MPCTL0 (ccm + 0x04)
|
||||
#define CCM_SPCTL0 (ccm + 0x0c)
|
||||
#define CCM_PCDR0 (ccm + 0x18)
|
||||
#define CCM_PCDR1 (ccm + 0x1c)
|
||||
#define CCM_PCCR0 (ccm + 0x20)
|
||||
#define CCM_PCCR1 (ccm + 0x24)
|
||||
|
||||
static const char *mpll_osc_sel_clks[] = { "ckih_gate", "ckih_div1p5", };
|
||||
static const char *mpll_sel_clks[] = { "fpm_gate", "mpll_osc_sel", };
|
||||
static const char *spll_sel_clks[] = { "fpm_gate", "mpll_osc_sel", };
|
||||
static const char *ssi_sel_clks[] = { "spll_gate", "mpll_gate", };
|
||||
|
||||
static struct clk *clk[IMX21_CLK_MAX];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static void __init _mx21_clocks_init(unsigned long lref, unsigned long href)
|
||||
{
|
||||
BUG_ON(!ccm);
|
||||
|
||||
clk[IMX21_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
clk[IMX21_CLK_CKIL] = imx_obtain_fixed_clock("ckil", lref);
|
||||
clk[IMX21_CLK_CKIH] = imx_obtain_fixed_clock("ckih", href);
|
||||
clk[IMX21_CLK_FPM] = imx_clk_fixed_factor("fpm", "ckil", 512, 1);
|
||||
clk[IMX21_CLK_CKIH_DIV1P5] = imx_clk_fixed_factor("ckih_div1p5", "ckih_gate", 2, 3);
|
||||
|
||||
clk[IMX21_CLK_MPLL_GATE] = imx_clk_gate("mpll_gate", "mpll", CCM_CSCR, 0);
|
||||
clk[IMX21_CLK_SPLL_GATE] = imx_clk_gate("spll_gate", "spll", CCM_CSCR, 1);
|
||||
clk[IMX21_CLK_FPM_GATE] = imx_clk_gate("fpm_gate", "fpm", CCM_CSCR, 2);
|
||||
clk[IMX21_CLK_CKIH_GATE] = imx_clk_gate_dis("ckih_gate", "ckih", CCM_CSCR, 3);
|
||||
clk[IMX21_CLK_MPLL_OSC_SEL] = imx_clk_mux("mpll_osc_sel", CCM_CSCR, 4, 1, mpll_osc_sel_clks, ARRAY_SIZE(mpll_osc_sel_clks));
|
||||
clk[IMX21_CLK_IPG] = imx_clk_divider("ipg", "hclk", CCM_CSCR, 9, 1);
|
||||
clk[IMX21_CLK_HCLK] = imx_clk_divider("hclk", "fclk", CCM_CSCR, 10, 4);
|
||||
clk[IMX21_CLK_MPLL_SEL] = imx_clk_mux("mpll_sel", CCM_CSCR, 16, 1, mpll_sel_clks, ARRAY_SIZE(mpll_sel_clks));
|
||||
clk[IMX21_CLK_SPLL_SEL] = imx_clk_mux("spll_sel", CCM_CSCR, 17, 1, spll_sel_clks, ARRAY_SIZE(spll_sel_clks));
|
||||
clk[IMX21_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", CCM_CSCR, 19, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks));
|
||||
clk[IMX21_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", CCM_CSCR, 20, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks));
|
||||
clk[IMX21_CLK_USB_DIV] = imx_clk_divider("usb_div", "spll_gate", CCM_CSCR, 26, 3);
|
||||
clk[IMX21_CLK_FCLK] = imx_clk_divider("fclk", "mpll_gate", CCM_CSCR, 29, 3);
|
||||
|
||||
clk[IMX21_CLK_MPLL] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0);
|
||||
|
||||
clk[IMX21_CLK_SPLL] = imx_clk_pllv1("spll", "spll_sel", CCM_SPCTL0);
|
||||
|
||||
clk[IMX21_CLK_NFC_DIV] = imx_clk_divider("nfc_div", "fclk", CCM_PCDR0, 12, 4);
|
||||
clk[IMX21_CLK_SSI1_DIV] = imx_clk_divider("ssi1_div", "ssi1_sel", CCM_PCDR0, 16, 6);
|
||||
clk[IMX21_CLK_SSI2_DIV] = imx_clk_divider("ssi2_div", "ssi2_sel", CCM_PCDR0, 26, 6);
|
||||
|
||||
clk[IMX21_CLK_PER1] = imx_clk_divider("per1", "mpll_gate", CCM_PCDR1, 0, 6);
|
||||
clk[IMX21_CLK_PER2] = imx_clk_divider("per2", "mpll_gate", CCM_PCDR1, 8, 6);
|
||||
clk[IMX21_CLK_PER3] = imx_clk_divider("per3", "mpll_gate", CCM_PCDR1, 16, 6);
|
||||
clk[IMX21_CLK_PER4] = imx_clk_divider("per4", "mpll_gate", CCM_PCDR1, 24, 6);
|
||||
|
||||
clk[IMX21_CLK_UART1_IPG_GATE] = imx_clk_gate("uart1_ipg_gate", "ipg", CCM_PCCR0, 0);
|
||||
clk[IMX21_CLK_UART2_IPG_GATE] = imx_clk_gate("uart2_ipg_gate", "ipg", CCM_PCCR0, 1);
|
||||
clk[IMX21_CLK_UART3_IPG_GATE] = imx_clk_gate("uart3_ipg_gate", "ipg", CCM_PCCR0, 2);
|
||||
clk[IMX21_CLK_UART4_IPG_GATE] = imx_clk_gate("uart4_ipg_gate", "ipg", CCM_PCCR0, 3);
|
||||
clk[IMX21_CLK_CSPI1_IPG_GATE] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 4);
|
||||
clk[IMX21_CLK_CSPI2_IPG_GATE] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 5);
|
||||
clk[IMX21_CLK_SSI1_GATE] = imx_clk_gate("ssi1_gate", "ipg", CCM_PCCR0, 6);
|
||||
clk[IMX21_CLK_SSI2_GATE] = imx_clk_gate("ssi2_gate", "ipg", CCM_PCCR0, 7);
|
||||
clk[IMX21_CLK_SDHC1_IPG_GATE] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 9);
|
||||
clk[IMX21_CLK_SDHC2_IPG_GATE] = imx_clk_gate("sdhc2_ipg_gate", "ipg", CCM_PCCR0, 10);
|
||||
clk[IMX21_CLK_GPIO_GATE] = imx_clk_gate("gpio_gate", "ipg", CCM_PCCR0, 11);
|
||||
clk[IMX21_CLK_I2C_GATE] = imx_clk_gate("i2c_gate", "ipg", CCM_PCCR0, 12);
|
||||
clk[IMX21_CLK_DMA_GATE] = imx_clk_gate("dma_gate", "ipg", CCM_PCCR0, 13);
|
||||
clk[IMX21_CLK_USB_GATE] = imx_clk_gate("usb_gate", "usb_div", CCM_PCCR0, 14);
|
||||
clk[IMX21_CLK_EMMA_GATE] = imx_clk_gate("emma_gate", "ipg", CCM_PCCR0, 15);
|
||||
clk[IMX21_CLK_SSI2_BAUD_GATE] = imx_clk_gate("ssi2_baud_gate", "ipg", CCM_PCCR0, 16);
|
||||
clk[IMX21_CLK_SSI1_BAUD_GATE] = imx_clk_gate("ssi1_baud_gate", "ipg", CCM_PCCR0, 17);
|
||||
clk[IMX21_CLK_LCDC_IPG_GATE] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 18);
|
||||
clk[IMX21_CLK_NFC_GATE] = imx_clk_gate("nfc_gate", "nfc_div", CCM_PCCR0, 19);
|
||||
clk[IMX21_CLK_SLCDC_HCLK_GATE] = imx_clk_gate("slcdc_hclk_gate", "hclk", CCM_PCCR0, 21);
|
||||
clk[IMX21_CLK_PER4_GATE] = imx_clk_gate("per4_gate", "per4", CCM_PCCR0, 22);
|
||||
clk[IMX21_CLK_BMI_GATE] = imx_clk_gate("bmi_gate", "hclk", CCM_PCCR0, 23);
|
||||
clk[IMX21_CLK_USB_HCLK_GATE] = imx_clk_gate("usb_hclk_gate", "hclk", CCM_PCCR0, 24);
|
||||
clk[IMX21_CLK_SLCDC_GATE] = imx_clk_gate("slcdc_gate", "hclk", CCM_PCCR0, 25);
|
||||
clk[IMX21_CLK_LCDC_HCLK_GATE] = imx_clk_gate("lcdc_hclk_gate", "hclk", CCM_PCCR0, 26);
|
||||
clk[IMX21_CLK_EMMA_HCLK_GATE] = imx_clk_gate("emma_hclk_gate", "hclk", CCM_PCCR0, 27);
|
||||
clk[IMX21_CLK_BROM_GATE] = imx_clk_gate("brom_gate", "hclk", CCM_PCCR0, 28);
|
||||
clk[IMX21_CLK_DMA_HCLK_GATE] = imx_clk_gate("dma_hclk_gate", "hclk", CCM_PCCR0, 30);
|
||||
clk[IMX21_CLK_CSI_HCLK_GATE] = imx_clk_gate("csi_hclk_gate", "hclk", CCM_PCCR0, 31);
|
||||
|
||||
clk[IMX21_CLK_CSPI3_IPG_GATE] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR1, 23);
|
||||
clk[IMX21_CLK_WDOG_GATE] = imx_clk_gate("wdog_gate", "ipg", CCM_PCCR1, 24);
|
||||
clk[IMX21_CLK_GPT1_IPG_GATE] = imx_clk_gate("gpt1_ipg_gate", "ipg", CCM_PCCR1, 25);
|
||||
clk[IMX21_CLK_GPT2_IPG_GATE] = imx_clk_gate("gpt2_ipg_gate", "ipg", CCM_PCCR1, 26);
|
||||
clk[IMX21_CLK_GPT3_IPG_GATE] = imx_clk_gate("gpt3_ipg_gate", "ipg", CCM_PCCR1, 27);
|
||||
clk[IMX21_CLK_PWM_IPG_GATE] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR1, 28);
|
||||
clk[IMX21_CLK_RTC_GATE] = imx_clk_gate("rtc_gate", "ipg", CCM_PCCR1, 29);
|
||||
clk[IMX21_CLK_KPP_GATE] = imx_clk_gate("kpp_gate", "ipg", CCM_PCCR1, 30);
|
||||
clk[IMX21_CLK_OWIRE_GATE] = imx_clk_gate("owire_gate", "ipg", CCM_PCCR1, 31);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
}
|
||||
|
||||
int __init mx21_clocks_init(unsigned long lref, unsigned long href)
|
||||
{
|
||||
ccm = ioremap(MX21_CCM_BASE_ADDR, SZ_2K);
|
||||
|
||||
_mx21_clocks_init(lref, href);
|
||||
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER1], "per", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_UART1_IPG_GATE], "ipg", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER1], "per", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[IMX21_CLK_UART2_IPG_GATE], "ipg", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER1], "per", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[IMX21_CLK_UART3_IPG_GATE], "ipg", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER1], "per", "imx21-uart.3");
|
||||
clk_register_clkdev(clk[IMX21_CLK_UART4_IPG_GATE], "ipg", "imx21-uart.3");
|
||||
clk_register_clkdev(clk[IMX21_CLK_GPT1_IPG_GATE], "ipg", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER1], "per", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER2], "per", "imx21-cspi.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_CSPI1_IPG_GATE], "ipg", "imx21-cspi.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER2], "per", "imx21-cspi.1");
|
||||
clk_register_clkdev(clk[IMX21_CLK_CSPI2_IPG_GATE], "ipg", "imx21-cspi.1");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER2], "per", "imx21-cspi.2");
|
||||
clk_register_clkdev(clk[IMX21_CLK_CSPI3_IPG_GATE], "ipg", "imx21-cspi.2");
|
||||
clk_register_clkdev(clk[IMX21_CLK_PER3], "per", "imx21-fb.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_LCDC_IPG_GATE], "ipg", "imx21-fb.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_LCDC_HCLK_GATE], "ahb", "imx21-fb.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_USB_GATE], "per", "imx21-hcd.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_USB_HCLK_GATE], "ahb", "imx21-hcd.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_NFC_GATE], NULL, "imx21-nand.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_DMA_HCLK_GATE], "ahb", "imx21-dma");
|
||||
clk_register_clkdev(clk[IMX21_CLK_DMA_GATE], "ipg", "imx21-dma");
|
||||
clk_register_clkdev(clk[IMX21_CLK_WDOG_GATE], NULL, "imx2-wdt.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_I2C_GATE], NULL, "imx21-i2c.0");
|
||||
clk_register_clkdev(clk[IMX21_CLK_OWIRE_GATE], NULL, "mxc_w1.0");
|
||||
|
||||
mxc_timer_init(MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), MX21_INT_GPT1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init mx21_clocks_init_dt(struct device_node *np)
|
||||
{
|
||||
ccm = of_iomap(np, 0);
|
||||
|
||||
_mx21_clocks_init(32768, 26000000);
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(imx27_ccm, "fsl,imx21-ccm", mx21_clocks_init_dt);
|
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 by Sascha Hauer, Pengutronix
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#define CCM_MPCTL 0x00
|
||||
#define CCM_UPCTL 0x04
|
||||
#define CCM_CCTL 0x08
|
||||
#define CCM_CGCR0 0x0C
|
||||
#define CCM_CGCR1 0x10
|
||||
#define CCM_CGCR2 0x14
|
||||
#define CCM_PCDR0 0x18
|
||||
#define CCM_PCDR1 0x1C
|
||||
#define CCM_PCDR2 0x20
|
||||
#define CCM_PCDR3 0x24
|
||||
#define CCM_RCSR 0x28
|
||||
#define CCM_CRDR 0x2C
|
||||
#define CCM_DCVR0 0x30
|
||||
#define CCM_DCVR1 0x34
|
||||
#define CCM_DCVR2 0x38
|
||||
#define CCM_DCVR3 0x3c
|
||||
#define CCM_LTR0 0x40
|
||||
#define CCM_LTR1 0x44
|
||||
#define CCM_LTR2 0x48
|
||||
#define CCM_LTR3 0x4c
|
||||
#define CCM_MCR 0x64
|
||||
|
||||
#define ccm(x) (ccm_base + (x))
|
||||
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static const char *cpu_sel_clks[] = { "mpll", "mpll_cpu_3_4", };
|
||||
static const char *per_sel_clks[] = { "ahb", "upll", };
|
||||
static const char *cko_sel_clks[] = { "dummy", "osc", "cpu", "ahb",
|
||||
"ipg", "dummy", "dummy", "dummy",
|
||||
"dummy", "dummy", "per0", "per2",
|
||||
"per13", "per14", "usbotg_ahb", "dummy",};
|
||||
|
||||
enum mx25_clks {
|
||||
dummy, osc, mpll, upll, mpll_cpu_3_4, cpu_sel, cpu, ahb, usb_div, ipg,
|
||||
per0_sel, per1_sel, per2_sel, per3_sel, per4_sel, per5_sel, per6_sel,
|
||||
per7_sel, per8_sel, per9_sel, per10_sel, per11_sel, per12_sel,
|
||||
per13_sel, per14_sel, per15_sel, per0, per1, per2, per3, per4, per5,
|
||||
per6, per7, per8, per9, per10, per11, per12, per13, per14, per15,
|
||||
csi_ipg_per, epit_ipg_per, esai_ipg_per, esdhc1_ipg_per, esdhc2_ipg_per,
|
||||
gpt_ipg_per, i2c_ipg_per, lcdc_ipg_per, nfc_ipg_per, owire_ipg_per,
|
||||
pwm_ipg_per, sim1_ipg_per, sim2_ipg_per, ssi1_ipg_per, ssi2_ipg_per,
|
||||
uart_ipg_per, ata_ahb, reserved1, csi_ahb, emi_ahb, esai_ahb, esdhc1_ahb,
|
||||
esdhc2_ahb, fec_ahb, lcdc_ahb, rtic_ahb, sdma_ahb, slcdc_ahb, usbotg_ahb,
|
||||
reserved2, reserved3, reserved4, reserved5, can1_ipg, can2_ipg, csi_ipg,
|
||||
cspi1_ipg, cspi2_ipg, cspi3_ipg, dryice_ipg, ect_ipg, epit1_ipg, epit2_ipg,
|
||||
reserved6, esdhc1_ipg, esdhc2_ipg, fec_ipg, reserved7, reserved8, reserved9,
|
||||
gpt1_ipg, gpt2_ipg, gpt3_ipg, gpt4_ipg, reserved10, reserved11, reserved12,
|
||||
iim_ipg, reserved13, reserved14, kpp_ipg, lcdc_ipg, reserved15, pwm1_ipg,
|
||||
pwm2_ipg, pwm3_ipg, pwm4_ipg, rngb_ipg, reserved16, scc_ipg, sdma_ipg,
|
||||
sim1_ipg, sim2_ipg, slcdc_ipg, spba_ipg, ssi1_ipg, ssi2_ipg, tsc_ipg,
|
||||
uart1_ipg, uart2_ipg, uart3_ipg, uart4_ipg, uart5_ipg, reserved17,
|
||||
wdt_ipg, cko_div, cko_sel, cko, clk_max
|
||||
};
|
||||
|
||||
static struct clk *clk[clk_max];
|
||||
|
||||
static int __init __mx25_clocks_init(unsigned long osc_rate,
|
||||
void __iomem *ccm_base)
|
||||
{
|
||||
BUG_ON(!ccm_base);
|
||||
|
||||
clk[dummy] = imx_clk_fixed("dummy", 0);
|
||||
clk[osc] = imx_clk_fixed("osc", osc_rate);
|
||||
clk[mpll] = imx_clk_pllv1("mpll", "osc", ccm(CCM_MPCTL));
|
||||
clk[upll] = imx_clk_pllv1("upll", "osc", ccm(CCM_UPCTL));
|
||||
clk[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4);
|
||||
clk[cpu_sel] = imx_clk_mux("cpu_sel", ccm(CCM_CCTL), 14, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks));
|
||||
clk[cpu] = imx_clk_divider("cpu", "cpu_sel", ccm(CCM_CCTL), 30, 2);
|
||||
clk[ahb] = imx_clk_divider("ahb", "cpu", ccm(CCM_CCTL), 28, 2);
|
||||
clk[usb_div] = imx_clk_divider("usb_div", "upll", ccm(CCM_CCTL), 16, 6);
|
||||
clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2);
|
||||
clk[per0_sel] = imx_clk_mux("per0_sel", ccm(CCM_MCR), 0, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per1_sel] = imx_clk_mux("per1_sel", ccm(CCM_MCR), 1, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per2_sel] = imx_clk_mux("per2_sel", ccm(CCM_MCR), 2, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per3_sel] = imx_clk_mux("per3_sel", ccm(CCM_MCR), 3, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per4_sel] = imx_clk_mux("per4_sel", ccm(CCM_MCR), 4, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per5_sel] = imx_clk_mux("per5_sel", ccm(CCM_MCR), 5, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per6_sel] = imx_clk_mux("per6_sel", ccm(CCM_MCR), 6, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per7_sel] = imx_clk_mux("per7_sel", ccm(CCM_MCR), 7, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per8_sel] = imx_clk_mux("per8_sel", ccm(CCM_MCR), 8, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per9_sel] = imx_clk_mux("per9_sel", ccm(CCM_MCR), 9, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per10_sel] = imx_clk_mux("per10_sel", ccm(CCM_MCR), 10, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per11_sel] = imx_clk_mux("per11_sel", ccm(CCM_MCR), 11, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per12_sel] = imx_clk_mux("per12_sel", ccm(CCM_MCR), 12, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per13_sel] = imx_clk_mux("per13_sel", ccm(CCM_MCR), 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per14_sel] = imx_clk_mux("per14_sel", ccm(CCM_MCR), 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[per15_sel] = imx_clk_mux("per15_sel", ccm(CCM_MCR), 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
|
||||
clk[cko_div] = imx_clk_divider("cko_div", "cko_sel", ccm(CCM_MCR), 24, 6);
|
||||
clk[cko_sel] = imx_clk_mux("cko_sel", ccm(CCM_MCR), 20, 4, cko_sel_clks, ARRAY_SIZE(cko_sel_clks));
|
||||
clk[cko] = imx_clk_gate("cko", "cko_div", ccm(CCM_MCR), 30);
|
||||
clk[per0] = imx_clk_divider("per0", "per0_sel", ccm(CCM_PCDR0), 0, 6);
|
||||
clk[per1] = imx_clk_divider("per1", "per1_sel", ccm(CCM_PCDR0), 8, 6);
|
||||
clk[per2] = imx_clk_divider("per2", "per2_sel", ccm(CCM_PCDR0), 16, 6);
|
||||
clk[per3] = imx_clk_divider("per3", "per3_sel", ccm(CCM_PCDR0), 24, 6);
|
||||
clk[per4] = imx_clk_divider("per4", "per4_sel", ccm(CCM_PCDR1), 0, 6);
|
||||
clk[per5] = imx_clk_divider("per5", "per5_sel", ccm(CCM_PCDR1), 8, 6);
|
||||
clk[per6] = imx_clk_divider("per6", "per6_sel", ccm(CCM_PCDR1), 16, 6);
|
||||
clk[per7] = imx_clk_divider("per7", "per7_sel", ccm(CCM_PCDR1), 24, 6);
|
||||
clk[per8] = imx_clk_divider("per8", "per8_sel", ccm(CCM_PCDR2), 0, 6);
|
||||
clk[per9] = imx_clk_divider("per9", "per9_sel", ccm(CCM_PCDR2), 8, 6);
|
||||
clk[per10] = imx_clk_divider("per10", "per10_sel", ccm(CCM_PCDR2), 16, 6);
|
||||
clk[per11] = imx_clk_divider("per11", "per11_sel", ccm(CCM_PCDR2), 24, 6);
|
||||
clk[per12] = imx_clk_divider("per12", "per12_sel", ccm(CCM_PCDR3), 0, 6);
|
||||
clk[per13] = imx_clk_divider("per13", "per13_sel", ccm(CCM_PCDR3), 8, 6);
|
||||
clk[per14] = imx_clk_divider("per14", "per14_sel", ccm(CCM_PCDR3), 16, 6);
|
||||
clk[per15] = imx_clk_divider("per15", "per15_sel", ccm(CCM_PCDR3), 24, 6);
|
||||
clk[csi_ipg_per] = imx_clk_gate("csi_ipg_per", "per0", ccm(CCM_CGCR0), 0);
|
||||
clk[epit_ipg_per] = imx_clk_gate("epit_ipg_per", "per1", ccm(CCM_CGCR0), 1);
|
||||
clk[esai_ipg_per] = imx_clk_gate("esai_ipg_per", "per2", ccm(CCM_CGCR0), 2);
|
||||
clk[esdhc1_ipg_per] = imx_clk_gate("esdhc1_ipg_per", "per3", ccm(CCM_CGCR0), 3);
|
||||
clk[esdhc2_ipg_per] = imx_clk_gate("esdhc2_ipg_per", "per4", ccm(CCM_CGCR0), 4);
|
||||
clk[gpt_ipg_per] = imx_clk_gate("gpt_ipg_per", "per5", ccm(CCM_CGCR0), 5);
|
||||
clk[i2c_ipg_per] = imx_clk_gate("i2c_ipg_per", "per6", ccm(CCM_CGCR0), 6);
|
||||
clk[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per7", ccm(CCM_CGCR0), 7);
|
||||
clk[nfc_ipg_per] = imx_clk_gate("nfc_ipg_per", "per8", ccm(CCM_CGCR0), 8);
|
||||
clk[owire_ipg_per] = imx_clk_gate("owire_ipg_per", "per9", ccm(CCM_CGCR0), 9);
|
||||
clk[pwm_ipg_per] = imx_clk_gate("pwm_ipg_per", "per10", ccm(CCM_CGCR0), 10);
|
||||
clk[sim1_ipg_per] = imx_clk_gate("sim1_ipg_per", "per11", ccm(CCM_CGCR0), 11);
|
||||
clk[sim2_ipg_per] = imx_clk_gate("sim2_ipg_per", "per12", ccm(CCM_CGCR0), 12);
|
||||
clk[ssi1_ipg_per] = imx_clk_gate("ssi1_ipg_per", "per13", ccm(CCM_CGCR0), 13);
|
||||
clk[ssi2_ipg_per] = imx_clk_gate("ssi2_ipg_per", "per14", ccm(CCM_CGCR0), 14);
|
||||
clk[uart_ipg_per] = imx_clk_gate("uart_ipg_per", "per15", ccm(CCM_CGCR0), 15);
|
||||
clk[ata_ahb] = imx_clk_gate("ata_ahb", "ahb", ccm(CCM_CGCR0), 16);
|
||||
/* CCM_CGCR0(17): reserved */
|
||||
clk[csi_ahb] = imx_clk_gate("csi_ahb", "ahb", ccm(CCM_CGCR0), 18);
|
||||
clk[emi_ahb] = imx_clk_gate("emi_ahb", "ahb", ccm(CCM_CGCR0), 19);
|
||||
clk[esai_ahb] = imx_clk_gate("esai_ahb", "ahb", ccm(CCM_CGCR0), 20);
|
||||
clk[esdhc1_ahb] = imx_clk_gate("esdhc1_ahb", "ahb", ccm(CCM_CGCR0), 21);
|
||||
clk[esdhc2_ahb] = imx_clk_gate("esdhc2_ahb", "ahb", ccm(CCM_CGCR0), 22);
|
||||
clk[fec_ahb] = imx_clk_gate("fec_ahb", "ahb", ccm(CCM_CGCR0), 23);
|
||||
clk[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", ccm(CCM_CGCR0), 24);
|
||||
clk[rtic_ahb] = imx_clk_gate("rtic_ahb", "ahb", ccm(CCM_CGCR0), 25);
|
||||
clk[sdma_ahb] = imx_clk_gate("sdma_ahb", "ahb", ccm(CCM_CGCR0), 26);
|
||||
clk[slcdc_ahb] = imx_clk_gate("slcdc_ahb", "ahb", ccm(CCM_CGCR0), 27);
|
||||
clk[usbotg_ahb] = imx_clk_gate("usbotg_ahb", "ahb", ccm(CCM_CGCR0), 28);
|
||||
/* CCM_CGCR0(29-31): reserved */
|
||||
/* CCM_CGCR1(0): reserved in datasheet, used as audmux in FSL kernel */
|
||||
clk[can1_ipg] = imx_clk_gate("can1_ipg", "ipg", ccm(CCM_CGCR1), 2);
|
||||
clk[can2_ipg] = imx_clk_gate("can2_ipg", "ipg", ccm(CCM_CGCR1), 3);
|
||||
clk[csi_ipg] = imx_clk_gate("csi_ipg", "ipg", ccm(CCM_CGCR1), 4);
|
||||
clk[cspi1_ipg] = imx_clk_gate("cspi1_ipg", "ipg", ccm(CCM_CGCR1), 5);
|
||||
clk[cspi2_ipg] = imx_clk_gate("cspi2_ipg", "ipg", ccm(CCM_CGCR1), 6);
|
||||
clk[cspi3_ipg] = imx_clk_gate("cspi3_ipg", "ipg", ccm(CCM_CGCR1), 7);
|
||||
clk[dryice_ipg] = imx_clk_gate("dryice_ipg", "ipg", ccm(CCM_CGCR1), 8);
|
||||
clk[ect_ipg] = imx_clk_gate("ect_ipg", "ipg", ccm(CCM_CGCR1), 9);
|
||||
clk[epit1_ipg] = imx_clk_gate("epit1_ipg", "ipg", ccm(CCM_CGCR1), 10);
|
||||
clk[epit2_ipg] = imx_clk_gate("epit2_ipg", "ipg", ccm(CCM_CGCR1), 11);
|
||||
/* CCM_CGCR1(12): reserved in datasheet, used as esai in FSL kernel */
|
||||
clk[esdhc1_ipg] = imx_clk_gate("esdhc1_ipg", "ipg", ccm(CCM_CGCR1), 13);
|
||||
clk[esdhc2_ipg] = imx_clk_gate("esdhc2_ipg", "ipg", ccm(CCM_CGCR1), 14);
|
||||
clk[fec_ipg] = imx_clk_gate("fec_ipg", "ipg", ccm(CCM_CGCR1), 15);
|
||||
/* CCM_CGCR1(16): reserved in datasheet, used as gpio1 in FSL kernel */
|
||||
/* CCM_CGCR1(17): reserved in datasheet, used as gpio2 in FSL kernel */
|
||||
/* CCM_CGCR1(18): reserved in datasheet, used as gpio3 in FSL kernel */
|
||||
clk[gpt1_ipg] = imx_clk_gate("gpt1_ipg", "ipg", ccm(CCM_CGCR1), 19);
|
||||
clk[gpt2_ipg] = imx_clk_gate("gpt2_ipg", "ipg", ccm(CCM_CGCR1), 20);
|
||||
clk[gpt3_ipg] = imx_clk_gate("gpt3_ipg", "ipg", ccm(CCM_CGCR1), 21);
|
||||
clk[gpt4_ipg] = imx_clk_gate("gpt4_ipg", "ipg", ccm(CCM_CGCR1), 22);
|
||||
/* CCM_CGCR1(23): reserved in datasheet, used as i2c1 in FSL kernel */
|
||||
/* CCM_CGCR1(24): reserved in datasheet, used as i2c2 in FSL kernel */
|
||||
/* CCM_CGCR1(25): reserved in datasheet, used as i2c3 in FSL kernel */
|
||||
clk[iim_ipg] = imx_clk_gate("iim_ipg", "ipg", ccm(CCM_CGCR1), 26);
|
||||
/* CCM_CGCR1(27): reserved in datasheet, used as iomuxc in FSL kernel */
|
||||
/* CCM_CGCR1(28): reserved in datasheet, used as kpp in FSL kernel */
|
||||
clk[kpp_ipg] = imx_clk_gate("kpp_ipg", "ipg", ccm(CCM_CGCR1), 28);
|
||||
clk[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", ccm(CCM_CGCR1), 29);
|
||||
/* CCM_CGCR1(30): reserved in datasheet, used as owire in FSL kernel */
|
||||
clk[pwm1_ipg] = imx_clk_gate("pwm1_ipg", "ipg", ccm(CCM_CGCR1), 31);
|
||||
clk[pwm2_ipg] = imx_clk_gate("pwm2_ipg", "ipg", ccm(CCM_CGCR2), 0);
|
||||
clk[pwm3_ipg] = imx_clk_gate("pwm3_ipg", "ipg", ccm(CCM_CGCR2), 1);
|
||||
clk[pwm4_ipg] = imx_clk_gate("pwm4_ipg", "ipg", ccm(CCM_CGCR2), 2);
|
||||
clk[rngb_ipg] = imx_clk_gate("rngb_ipg", "ipg", ccm(CCM_CGCR2), 3);
|
||||
/* CCM_CGCR2(4): reserved in datasheet, used as rtic in FSL kernel */
|
||||
clk[scc_ipg] = imx_clk_gate("scc_ipg", "ipg", ccm(CCM_CGCR2), 5);
|
||||
clk[sdma_ipg] = imx_clk_gate("sdma_ipg", "ipg", ccm(CCM_CGCR2), 6);
|
||||
clk[sim1_ipg] = imx_clk_gate("sim1_ipg", "ipg", ccm(CCM_CGCR2), 7);
|
||||
clk[sim2_ipg] = imx_clk_gate("sim2_ipg", "ipg", ccm(CCM_CGCR2), 8);
|
||||
clk[slcdc_ipg] = imx_clk_gate("slcdc_ipg", "ipg", ccm(CCM_CGCR2), 9);
|
||||
clk[spba_ipg] = imx_clk_gate("spba_ipg", "ipg", ccm(CCM_CGCR2), 10);
|
||||
clk[ssi1_ipg] = imx_clk_gate("ssi1_ipg", "ipg", ccm(CCM_CGCR2), 11);
|
||||
clk[ssi2_ipg] = imx_clk_gate("ssi2_ipg", "ipg", ccm(CCM_CGCR2), 12);
|
||||
clk[tsc_ipg] = imx_clk_gate("tsc_ipg", "ipg", ccm(CCM_CGCR2), 13);
|
||||
clk[uart1_ipg] = imx_clk_gate("uart1_ipg", "ipg", ccm(CCM_CGCR2), 14);
|
||||
clk[uart2_ipg] = imx_clk_gate("uart2_ipg", "ipg", ccm(CCM_CGCR2), 15);
|
||||
clk[uart3_ipg] = imx_clk_gate("uart3_ipg", "ipg", ccm(CCM_CGCR2), 16);
|
||||
clk[uart4_ipg] = imx_clk_gate("uart4_ipg", "ipg", ccm(CCM_CGCR2), 17);
|
||||
clk[uart5_ipg] = imx_clk_gate("uart5_ipg", "ipg", ccm(CCM_CGCR2), 18);
|
||||
/* CCM_CGCR2(19): reserved in datasheet, but used as wdt in FSL kernel */
|
||||
clk[wdt_ipg] = imx_clk_gate("wdt_ipg", "ipg", ccm(CCM_CGCR2), 19);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
clk_prepare_enable(clk[emi_ahb]);
|
||||
|
||||
/* Clock source for gpt must be derived from AHB */
|
||||
clk_set_parent(clk[per5_sel], clk[ahb]);
|
||||
|
||||
/*
|
||||
* Let's initially set up CLKO parent as ipg, since this configuration
|
||||
* is used on some imx25 board designs to clock the audio codec.
|
||||
*/
|
||||
clk_set_parent(clk[cko_sel], clk[ipg]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init mx25_clocks_init_dt(struct device_node *np)
|
||||
{
|
||||
struct device_node *refnp;
|
||||
unsigned long osc_rate = 24000000;
|
||||
void __iomem *ccm;
|
||||
|
||||
/* retrieve the freqency of fixed clocks from device tree */
|
||||
for_each_compatible_node(refnp, NULL, "fixed-clock") {
|
||||
u32 rate;
|
||||
if (of_property_read_u32(refnp, "clock-frequency", &rate))
|
||||
continue;
|
||||
|
||||
if (of_device_is_compatible(refnp, "fsl,imx-osc"))
|
||||
osc_rate = rate;
|
||||
}
|
||||
|
||||
ccm = of_iomap(np, 0);
|
||||
__mx25_clocks_init(osc_rate, ccm);
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(imx25_ccm, "fsl,imx25-ccm", mx25_clocks_init_dt);
|
@@ -1,258 +0,0 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <dt-bindings/clock/imx27-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
static void __iomem *ccm __initdata;
|
||||
|
||||
/* Register offsets */
|
||||
#define CCM_CSCR (ccm + 0x00)
|
||||
#define CCM_MPCTL0 (ccm + 0x04)
|
||||
#define CCM_MPCTL1 (ccm + 0x08)
|
||||
#define CCM_SPCTL0 (ccm + 0x0c)
|
||||
#define CCM_SPCTL1 (ccm + 0x10)
|
||||
#define CCM_PCDR0 (ccm + 0x18)
|
||||
#define CCM_PCDR1 (ccm + 0x1c)
|
||||
#define CCM_PCCR0 (ccm + 0x20)
|
||||
#define CCM_PCCR1 (ccm + 0x24)
|
||||
#define CCM_CCSR (ccm + 0x28)
|
||||
|
||||
static const char *vpu_sel_clks[] = { "spll", "mpll_main2", };
|
||||
static const char *cpu_sel_clks[] = { "mpll_main2", "mpll", };
|
||||
static const char *mpll_sel_clks[] = { "fpm", "mpll_osc_sel", };
|
||||
static const char *mpll_osc_sel_clks[] = { "ckih_gate", "ckih_div1p5", };
|
||||
static const char *clko_sel_clks[] = {
|
||||
"ckil", "fpm", "ckih_gate", "ckih_gate",
|
||||
"ckih_gate", "mpll", "spll", "cpu_div",
|
||||
"ahb", "ipg", "per1_div", "per2_div",
|
||||
"per3_div", "per4_div", "ssi1_div", "ssi2_div",
|
||||
"nfc_div", "mshc_div", "vpu_div", "60m",
|
||||
"32k", "usb_div", "dptc",
|
||||
};
|
||||
|
||||
static const char *ssi_sel_clks[] = { "spll_gate", "mpll", };
|
||||
|
||||
static struct clk *clk[IMX27_CLK_MAX];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static void __init _mx27_clocks_init(unsigned long fref)
|
||||
{
|
||||
BUG_ON(!ccm);
|
||||
|
||||
clk[IMX27_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
clk[IMX27_CLK_CKIH] = imx_clk_fixed("ckih", fref);
|
||||
clk[IMX27_CLK_CKIL] = imx_clk_fixed("ckil", 32768);
|
||||
clk[IMX27_CLK_FPM] = imx_clk_fixed_factor("fpm", "ckil", 1024, 1);
|
||||
clk[IMX27_CLK_CKIH_DIV1P5] = imx_clk_fixed_factor("ckih_div1p5", "ckih_gate", 2, 3);
|
||||
clk[IMX27_CLK_CKIH_GATE] = imx_clk_gate_dis("ckih_gate", "ckih", CCM_CSCR, 3);
|
||||
clk[IMX27_CLK_MPLL_OSC_SEL] = imx_clk_mux("mpll_osc_sel", CCM_CSCR, 4, 1, mpll_osc_sel_clks, ARRAY_SIZE(mpll_osc_sel_clks));
|
||||
clk[IMX27_CLK_MPLL_SEL] = imx_clk_mux("mpll_sel", CCM_CSCR, 16, 1, mpll_sel_clks, ARRAY_SIZE(mpll_sel_clks));
|
||||
clk[IMX27_CLK_MPLL] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0);
|
||||
clk[IMX27_CLK_SPLL] = imx_clk_pllv1("spll", "ckih_gate", CCM_SPCTL0);
|
||||
clk[IMX27_CLK_SPLL_GATE] = imx_clk_gate("spll_gate", "spll", CCM_CSCR, 1);
|
||||
clk[IMX27_CLK_MPLL_MAIN2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3);
|
||||
|
||||
if (mx27_revision() >= IMX_CHIP_REVISION_2_0) {
|
||||
clk[IMX27_CLK_AHB] = imx_clk_divider("ahb", "mpll_main2", CCM_CSCR, 8, 2);
|
||||
clk[IMX27_CLK_IPG] = imx_clk_fixed_factor("ipg", "ahb", 1, 2);
|
||||
} else {
|
||||
clk[IMX27_CLK_AHB] = imx_clk_divider("ahb", "mpll_main2", CCM_CSCR, 9, 4);
|
||||
clk[IMX27_CLK_IPG] = imx_clk_divider("ipg", "ahb", CCM_CSCR, 8, 1);
|
||||
}
|
||||
|
||||
clk[IMX27_CLK_MSHC_DIV] = imx_clk_divider("mshc_div", "ahb", CCM_PCDR0, 0, 6);
|
||||
clk[IMX27_CLK_NFC_DIV] = imx_clk_divider("nfc_div", "ahb", CCM_PCDR0, 6, 4);
|
||||
clk[IMX27_CLK_PER1_DIV] = imx_clk_divider("per1_div", "mpll_main2", CCM_PCDR1, 0, 6);
|
||||
clk[IMX27_CLK_PER2_DIV] = imx_clk_divider("per2_div", "mpll_main2", CCM_PCDR1, 8, 6);
|
||||
clk[IMX27_CLK_PER3_DIV] = imx_clk_divider("per3_div", "mpll_main2", CCM_PCDR1, 16, 6);
|
||||
clk[IMX27_CLK_PER4_DIV] = imx_clk_divider("per4_div", "mpll_main2", CCM_PCDR1, 24, 6);
|
||||
clk[IMX27_CLK_VPU_SEL] = imx_clk_mux("vpu_sel", CCM_CSCR, 21, 1, vpu_sel_clks, ARRAY_SIZE(vpu_sel_clks));
|
||||
clk[IMX27_CLK_VPU_DIV] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 6);
|
||||
clk[IMX27_CLK_USB_DIV] = imx_clk_divider("usb_div", "spll_gate", CCM_CSCR, 28, 3);
|
||||
clk[IMX27_CLK_CPU_SEL] = imx_clk_mux("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks));
|
||||
clk[IMX27_CLK_CLKO_SEL] = imx_clk_mux("clko_sel", CCM_CCSR, 0, 5, clko_sel_clks, ARRAY_SIZE(clko_sel_clks));
|
||||
|
||||
if (mx27_revision() >= IMX_CHIP_REVISION_2_0)
|
||||
clk[IMX27_CLK_CPU_DIV] = imx_clk_divider("cpu_div", "cpu_sel", CCM_CSCR, 12, 2);
|
||||
else
|
||||
clk[IMX27_CLK_CPU_DIV] = imx_clk_divider("cpu_div", "cpu_sel", CCM_CSCR, 13, 3);
|
||||
|
||||
clk[IMX27_CLK_CLKO_DIV] = imx_clk_divider("clko_div", "clko_sel", CCM_PCDR0, 22, 3);
|
||||
clk[IMX27_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", CCM_CSCR, 22, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks));
|
||||
clk[IMX27_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", CCM_CSCR, 23, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks));
|
||||
clk[IMX27_CLK_SSI1_DIV] = imx_clk_divider("ssi1_div", "ssi1_sel", CCM_PCDR0, 16, 6);
|
||||
clk[IMX27_CLK_SSI2_DIV] = imx_clk_divider("ssi2_div", "ssi2_sel", CCM_PCDR0, 26, 6);
|
||||
clk[IMX27_CLK_CLKO_EN] = imx_clk_gate("clko_en", "clko_div", CCM_PCCR0, 0);
|
||||
clk[IMX27_CLK_SSI2_IPG_GATE] = imx_clk_gate("ssi2_ipg_gate", "ipg", CCM_PCCR0, 0);
|
||||
clk[IMX27_CLK_SSI1_IPG_GATE] = imx_clk_gate("ssi1_ipg_gate", "ipg", CCM_PCCR0, 1);
|
||||
clk[IMX27_CLK_SLCDC_IPG_GATE] = imx_clk_gate("slcdc_ipg_gate", "ipg", CCM_PCCR0, 2);
|
||||
clk[IMX27_CLK_SDHC3_IPG_GATE] = imx_clk_gate("sdhc3_ipg_gate", "ipg", CCM_PCCR0, 3);
|
||||
clk[IMX27_CLK_SDHC2_IPG_GATE] = imx_clk_gate("sdhc2_ipg_gate", "ipg", CCM_PCCR0, 4);
|
||||
clk[IMX27_CLK_SDHC1_IPG_GATE] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 5);
|
||||
clk[IMX27_CLK_SCC_IPG_GATE] = imx_clk_gate("scc_ipg_gate", "ipg", CCM_PCCR0, 6);
|
||||
clk[IMX27_CLK_SAHARA_IPG_GATE] = imx_clk_gate("sahara_ipg_gate", "ipg", CCM_PCCR0, 7);
|
||||
clk[IMX27_CLK_RTIC_IPG_GATE] = imx_clk_gate("rtic_ipg_gate", "ipg", CCM_PCCR0, 8);
|
||||
clk[IMX27_CLK_RTC_IPG_GATE] = imx_clk_gate("rtc_ipg_gate", "ipg", CCM_PCCR0, 9);
|
||||
clk[IMX27_CLK_PWM_IPG_GATE] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR0, 11);
|
||||
clk[IMX27_CLK_OWIRE_IPG_GATE] = imx_clk_gate("owire_ipg_gate", "ipg", CCM_PCCR0, 12);
|
||||
clk[IMX27_CLK_MSHC_IPG_GATE] = imx_clk_gate("mshc_ipg_gate", "ipg", CCM_PCCR0, 13);
|
||||
clk[IMX27_CLK_LCDC_IPG_GATE] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 14);
|
||||
clk[IMX27_CLK_KPP_IPG_GATE] = imx_clk_gate("kpp_ipg_gate", "ipg", CCM_PCCR0, 15);
|
||||
clk[IMX27_CLK_IIM_IPG_GATE] = imx_clk_gate("iim_ipg_gate", "ipg", CCM_PCCR0, 16);
|
||||
clk[IMX27_CLK_I2C2_IPG_GATE] = imx_clk_gate("i2c2_ipg_gate", "ipg", CCM_PCCR0, 17);
|
||||
clk[IMX27_CLK_I2C1_IPG_GATE] = imx_clk_gate("i2c1_ipg_gate", "ipg", CCM_PCCR0, 18);
|
||||
clk[IMX27_CLK_GPT6_IPG_GATE] = imx_clk_gate("gpt6_ipg_gate", "ipg", CCM_PCCR0, 19);
|
||||
clk[IMX27_CLK_GPT5_IPG_GATE] = imx_clk_gate("gpt5_ipg_gate", "ipg", CCM_PCCR0, 20);
|
||||
clk[IMX27_CLK_GPT4_IPG_GATE] = imx_clk_gate("gpt4_ipg_gate", "ipg", CCM_PCCR0, 21);
|
||||
clk[IMX27_CLK_GPT3_IPG_GATE] = imx_clk_gate("gpt3_ipg_gate", "ipg", CCM_PCCR0, 22);
|
||||
clk[IMX27_CLK_GPT2_IPG_GATE] = imx_clk_gate("gpt2_ipg_gate", "ipg", CCM_PCCR0, 23);
|
||||
clk[IMX27_CLK_GPT1_IPG_GATE] = imx_clk_gate("gpt1_ipg_gate", "ipg", CCM_PCCR0, 24);
|
||||
clk[IMX27_CLK_GPIO_IPG_GATE] = imx_clk_gate("gpio_ipg_gate", "ipg", CCM_PCCR0, 25);
|
||||
clk[IMX27_CLK_FEC_IPG_GATE] = imx_clk_gate("fec_ipg_gate", "ipg", CCM_PCCR0, 26);
|
||||
clk[IMX27_CLK_EMMA_IPG_GATE] = imx_clk_gate("emma_ipg_gate", "ipg", CCM_PCCR0, 27);
|
||||
clk[IMX27_CLK_DMA_IPG_GATE] = imx_clk_gate("dma_ipg_gate", "ipg", CCM_PCCR0, 28);
|
||||
clk[IMX27_CLK_CSPI3_IPG_GATE] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR0, 29);
|
||||
clk[IMX27_CLK_CSPI2_IPG_GATE] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 30);
|
||||
clk[IMX27_CLK_CSPI1_IPG_GATE] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 31);
|
||||
clk[IMX27_CLK_MSHC_BAUD_GATE] = imx_clk_gate("mshc_baud_gate", "mshc_div", CCM_PCCR1, 2);
|
||||
clk[IMX27_CLK_NFC_BAUD_GATE] = imx_clk_gate("nfc_baud_gate", "nfc_div", CCM_PCCR1, 3);
|
||||
clk[IMX27_CLK_SSI2_BAUD_GATE] = imx_clk_gate("ssi2_baud_gate", "ssi2_div", CCM_PCCR1, 4);
|
||||
clk[IMX27_CLK_SSI1_BAUD_GATE] = imx_clk_gate("ssi1_baud_gate", "ssi1_div", CCM_PCCR1, 5);
|
||||
clk[IMX27_CLK_VPU_BAUD_GATE] = imx_clk_gate("vpu_baud_gate", "vpu_div", CCM_PCCR1, 6);
|
||||
clk[IMX27_CLK_PER4_GATE] = imx_clk_gate("per4_gate", "per4_div", CCM_PCCR1, 7);
|
||||
clk[IMX27_CLK_PER3_GATE] = imx_clk_gate("per3_gate", "per3_div", CCM_PCCR1, 8);
|
||||
clk[IMX27_CLK_PER2_GATE] = imx_clk_gate("per2_gate", "per2_div", CCM_PCCR1, 9);
|
||||
clk[IMX27_CLK_PER1_GATE] = imx_clk_gate("per1_gate", "per1_div", CCM_PCCR1, 10);
|
||||
clk[IMX27_CLK_USB_AHB_GATE] = imx_clk_gate("usb_ahb_gate", "ahb", CCM_PCCR1, 11);
|
||||
clk[IMX27_CLK_SLCDC_AHB_GATE] = imx_clk_gate("slcdc_ahb_gate", "ahb", CCM_PCCR1, 12);
|
||||
clk[IMX27_CLK_SAHARA_AHB_GATE] = imx_clk_gate("sahara_ahb_gate", "ahb", CCM_PCCR1, 13);
|
||||
clk[IMX27_CLK_RTIC_AHB_GATE] = imx_clk_gate("rtic_ahb_gate", "ahb", CCM_PCCR1, 14);
|
||||
clk[IMX27_CLK_LCDC_AHB_GATE] = imx_clk_gate("lcdc_ahb_gate", "ahb", CCM_PCCR1, 15);
|
||||
clk[IMX27_CLK_VPU_AHB_GATE] = imx_clk_gate("vpu_ahb_gate", "ahb", CCM_PCCR1, 16);
|
||||
clk[IMX27_CLK_FEC_AHB_GATE] = imx_clk_gate("fec_ahb_gate", "ahb", CCM_PCCR1, 17);
|
||||
clk[IMX27_CLK_EMMA_AHB_GATE] = imx_clk_gate("emma_ahb_gate", "ahb", CCM_PCCR1, 18);
|
||||
clk[IMX27_CLK_EMI_AHB_GATE] = imx_clk_gate("emi_ahb_gate", "ahb", CCM_PCCR1, 19);
|
||||
clk[IMX27_CLK_DMA_AHB_GATE] = imx_clk_gate("dma_ahb_gate", "ahb", CCM_PCCR1, 20);
|
||||
clk[IMX27_CLK_CSI_AHB_GATE] = imx_clk_gate("csi_ahb_gate", "ahb", CCM_PCCR1, 21);
|
||||
clk[IMX27_CLK_BROM_AHB_GATE] = imx_clk_gate("brom_ahb_gate", "ahb", CCM_PCCR1, 22);
|
||||
clk[IMX27_CLK_ATA_AHB_GATE] = imx_clk_gate("ata_ahb_gate", "ahb", CCM_PCCR1, 23);
|
||||
clk[IMX27_CLK_WDOG_IPG_GATE] = imx_clk_gate("wdog_ipg_gate", "ipg", CCM_PCCR1, 24);
|
||||
clk[IMX27_CLK_USB_IPG_GATE] = imx_clk_gate("usb_ipg_gate", "ipg", CCM_PCCR1, 25);
|
||||
clk[IMX27_CLK_UART6_IPG_GATE] = imx_clk_gate("uart6_ipg_gate", "ipg", CCM_PCCR1, 26);
|
||||
clk[IMX27_CLK_UART5_IPG_GATE] = imx_clk_gate("uart5_ipg_gate", "ipg", CCM_PCCR1, 27);
|
||||
clk[IMX27_CLK_UART4_IPG_GATE] = imx_clk_gate("uart4_ipg_gate", "ipg", CCM_PCCR1, 28);
|
||||
clk[IMX27_CLK_UART3_IPG_GATE] = imx_clk_gate("uart3_ipg_gate", "ipg", CCM_PCCR1, 29);
|
||||
clk[IMX27_CLK_UART2_IPG_GATE] = imx_clk_gate("uart2_ipg_gate", "ipg", CCM_PCCR1, 30);
|
||||
clk[IMX27_CLK_UART1_IPG_GATE] = imx_clk_gate("uart1_ipg_gate", "ipg", CCM_PCCR1, 31);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
clk_register_clkdev(clk[IMX27_CLK_CPU_DIV], NULL, "cpu0");
|
||||
|
||||
clk_prepare_enable(clk[IMX27_CLK_EMI_AHB_GATE]);
|
||||
|
||||
imx_print_silicon_rev("i.MX27", mx27_revision());
|
||||
}
|
||||
|
||||
int __init mx27_clocks_init(unsigned long fref)
|
||||
{
|
||||
ccm = ioremap(MX27_CCM_BASE_ADDR, SZ_4K);
|
||||
|
||||
_mx27_clocks_init(fref);
|
||||
|
||||
clk_register_clkdev(clk[IMX27_CLK_UART1_IPG_GATE], "ipg", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_UART2_IPG_GATE], "ipg", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_UART3_IPG_GATE], "ipg", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_UART4_IPG_GATE], "ipg", "imx21-uart.3");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.3");
|
||||
clk_register_clkdev(clk[IMX27_CLK_UART5_IPG_GATE], "ipg", "imx21-uart.4");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.4");
|
||||
clk_register_clkdev(clk[IMX27_CLK_UART6_IPG_GATE], "ipg", "imx21-uart.5");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.5");
|
||||
clk_register_clkdev(clk[IMX27_CLK_GPT1_IPG_GATE], "ipg", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx21-mmc.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_SDHC1_IPG_GATE], "ipg", "imx21-mmc.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx21-mmc.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_SDHC2_IPG_GATE], "ipg", "imx21-mmc.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx21-mmc.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_SDHC2_IPG_GATE], "ipg", "imx21-mmc.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx27-cspi.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_CSPI1_IPG_GATE], "ipg", "imx27-cspi.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx27-cspi.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_CSPI2_IPG_GATE], "ipg", "imx27-cspi.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx27-cspi.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_CSPI3_IPG_GATE], "ipg", "imx27-cspi.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER3_GATE], "per", "imx21-fb.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_LCDC_IPG_GATE], "ipg", "imx21-fb.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_LCDC_AHB_GATE], "ahb", "imx21-fb.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_CSI_AHB_GATE], "ahb", "imx27-camera.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_PER4_GATE], "per", "imx27-camera.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[IMX27_CLK_SSI1_IPG_GATE], NULL, "imx-ssi.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_SSI2_IPG_GATE], NULL, "imx-ssi.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_NFC_BAUD_GATE], NULL, "imx27-nand.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_VPU_BAUD_GATE], "per", "coda-imx27.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_VPU_AHB_GATE], "ahb", "coda-imx27.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_DMA_AHB_GATE], "ahb", "imx27-dma");
|
||||
clk_register_clkdev(clk[IMX27_CLK_DMA_IPG_GATE], "ipg", "imx27-dma");
|
||||
clk_register_clkdev(clk[IMX27_CLK_FEC_IPG_GATE], "ipg", "imx27-fec.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_FEC_AHB_GATE], "ahb", "imx27-fec.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_WDOG_IPG_GATE], NULL, "imx2-wdt.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_I2C1_IPG_GATE], NULL, "imx21-i2c.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_I2C2_IPG_GATE], NULL, "imx21-i2c.1");
|
||||
clk_register_clkdev(clk[IMX27_CLK_OWIRE_IPG_GATE], NULL, "mxc_w1.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_KPP_IPG_GATE], NULL, "imx-keypad");
|
||||
clk_register_clkdev(clk[IMX27_CLK_EMMA_AHB_GATE], "emma-ahb", "imx27-camera.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_EMMA_IPG_GATE], "emma-ipg", "imx27-camera.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_EMMA_AHB_GATE], "ahb", "m2m-emmaprp.0");
|
||||
clk_register_clkdev(clk[IMX27_CLK_EMMA_IPG_GATE], "ipg", "m2m-emmaprp.0");
|
||||
|
||||
mxc_timer_init(MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), MX27_INT_GPT1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init mx27_clocks_init_dt(struct device_node *np)
|
||||
{
|
||||
struct device_node *refnp;
|
||||
u32 fref = 26000000; /* default */
|
||||
|
||||
for_each_compatible_node(refnp, NULL, "fixed-clock") {
|
||||
if (!of_device_is_compatible(refnp, "fsl,imx-osc26m"))
|
||||
continue;
|
||||
|
||||
if (!of_property_read_u32(refnp, "clock-frequency", &fref))
|
||||
break;
|
||||
}
|
||||
|
||||
ccm = of_iomap(np, 0);
|
||||
|
||||
_mx27_clocks_init(fref);
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(imx27_ccm, "fsl,imx27-ccm", mx27_clocks_init_dt);
|
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Sascha Hauer <kernel@pengutronix.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "crmregs-imx3.h"
|
||||
#include "hardware.h"
|
||||
#include "mx31.h"
|
||||
|
||||
static const char *mcu_main_sel[] = { "spll", "mpll", };
|
||||
static const char *per_sel[] = { "per_div", "ipg", };
|
||||
static const char *csi_sel[] = { "upll", "spll", };
|
||||
static const char *fir_sel[] = { "mcu_main", "upll", "spll" };
|
||||
|
||||
enum mx31_clks {
|
||||
dummy, ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg,
|
||||
per_div, per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre,
|
||||
fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate,
|
||||
iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate,
|
||||
uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate,
|
||||
mstick1_gate, mstick2_gate, csi_gate, rtc_gate, wdog_gate, pwm_gate,
|
||||
sim_gate, ect_gate, usb_gate, kpp_gate, ipu_gate, uart3_gate,
|
||||
uart4_gate, uart5_gate, owire_gate, ssi2_gate, cspi1_gate, cspi2_gate,
|
||||
gacc_gate, emi_gate, rtic_gate, firi_gate, clk_max
|
||||
};
|
||||
|
||||
static struct clk *clk[clk_max];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
int __init mx31_clocks_init(unsigned long fref)
|
||||
{
|
||||
void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR);
|
||||
struct device_node *np;
|
||||
|
||||
clk[dummy] = imx_clk_fixed("dummy", 0);
|
||||
clk[ckih] = imx_clk_fixed("ckih", fref);
|
||||
clk[ckil] = imx_clk_fixed("ckil", 32768);
|
||||
clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MXC_CCM_MPCTL);
|
||||
clk[spll] = imx_clk_pllv1("spll", "ckih", base + MXC_CCM_SRPCTL);
|
||||
clk[upll] = imx_clk_pllv1("upll", "ckih", base + MXC_CCM_UPCTL);
|
||||
clk[mcu_main] = imx_clk_mux("mcu_main", base + MXC_CCM_PMCR0, 31, 1, mcu_main_sel, ARRAY_SIZE(mcu_main_sel));
|
||||
clk[hsp] = imx_clk_divider("hsp", "mcu_main", base + MXC_CCM_PDR0, 11, 3);
|
||||
clk[ahb] = imx_clk_divider("ahb", "mcu_main", base + MXC_CCM_PDR0, 3, 3);
|
||||
clk[nfc] = imx_clk_divider("nfc", "ahb", base + MXC_CCM_PDR0, 8, 3);
|
||||
clk[ipg] = imx_clk_divider("ipg", "ahb", base + MXC_CCM_PDR0, 6, 2);
|
||||
clk[per_div] = imx_clk_divider("per_div", "upll", base + MXC_CCM_PDR0, 16, 5);
|
||||
clk[per] = imx_clk_mux("per", base + MXC_CCM_CCMR, 24, 1, per_sel, ARRAY_SIZE(per_sel));
|
||||
clk[csi] = imx_clk_mux("csi_sel", base + MXC_CCM_CCMR, 25, 1, csi_sel, ARRAY_SIZE(csi_sel));
|
||||
clk[fir] = imx_clk_mux("fir_sel", base + MXC_CCM_CCMR, 11, 2, fir_sel, ARRAY_SIZE(fir_sel));
|
||||
clk[csi_div] = imx_clk_divider("csi_div", "csi_sel", base + MXC_CCM_PDR0, 23, 9);
|
||||
clk[usb_div_pre] = imx_clk_divider("usb_div_pre", "upll", base + MXC_CCM_PDR1, 30, 2);
|
||||
clk[usb_div_post] = imx_clk_divider("usb_div_post", "usb_div_pre", base + MXC_CCM_PDR1, 27, 3);
|
||||
clk[fir_div_pre] = imx_clk_divider("fir_div_pre", "fir_sel", base + MXC_CCM_PDR1, 24, 3);
|
||||
clk[fir_div_post] = imx_clk_divider("fir_div_post", "fir_div_pre", base + MXC_CCM_PDR1, 23, 6);
|
||||
clk[sdhc1_gate] = imx_clk_gate2("sdhc1_gate", "per", base + MXC_CCM_CGR0, 0);
|
||||
clk[sdhc2_gate] = imx_clk_gate2("sdhc2_gate", "per", base + MXC_CCM_CGR0, 2);
|
||||
clk[gpt_gate] = imx_clk_gate2("gpt_gate", "per", base + MXC_CCM_CGR0, 4);
|
||||
clk[epit1_gate] = imx_clk_gate2("epit1_gate", "per", base + MXC_CCM_CGR0, 6);
|
||||
clk[epit2_gate] = imx_clk_gate2("epit2_gate", "per", base + MXC_CCM_CGR0, 8);
|
||||
clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MXC_CCM_CGR0, 10);
|
||||
clk[ata_gate] = imx_clk_gate2("ata_gate", "ipg", base + MXC_CCM_CGR0, 12);
|
||||
clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ahb", base + MXC_CCM_CGR0, 14);
|
||||
clk[cspi3_gate] = imx_clk_gate2("cspi3_gate", "ipg", base + MXC_CCM_CGR0, 16);
|
||||
clk[rng_gate] = imx_clk_gate2("rng_gate", "ipg", base + MXC_CCM_CGR0, 18);
|
||||
clk[uart1_gate] = imx_clk_gate2("uart1_gate", "per", base + MXC_CCM_CGR0, 20);
|
||||
clk[uart2_gate] = imx_clk_gate2("uart2_gate", "per", base + MXC_CCM_CGR0, 22);
|
||||
clk[ssi1_gate] = imx_clk_gate2("ssi1_gate", "spll", base + MXC_CCM_CGR0, 24);
|
||||
clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "per", base + MXC_CCM_CGR0, 26);
|
||||
clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "per", base + MXC_CCM_CGR0, 28);
|
||||
clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per", base + MXC_CCM_CGR0, 30);
|
||||
clk[hantro_gate] = imx_clk_gate2("hantro_gate", "per", base + MXC_CCM_CGR1, 0);
|
||||
clk[mstick1_gate] = imx_clk_gate2("mstick1_gate", "per", base + MXC_CCM_CGR1, 2);
|
||||
clk[mstick2_gate] = imx_clk_gate2("mstick2_gate", "per", base + MXC_CCM_CGR1, 4);
|
||||
clk[csi_gate] = imx_clk_gate2("csi_gate", "csi_div", base + MXC_CCM_CGR1, 6);
|
||||
clk[rtc_gate] = imx_clk_gate2("rtc_gate", "ipg", base + MXC_CCM_CGR1, 8);
|
||||
clk[wdog_gate] = imx_clk_gate2("wdog_gate", "ipg", base + MXC_CCM_CGR1, 10);
|
||||
clk[pwm_gate] = imx_clk_gate2("pwm_gate", "per", base + MXC_CCM_CGR1, 12);
|
||||
clk[sim_gate] = imx_clk_gate2("sim_gate", "per", base + MXC_CCM_CGR1, 14);
|
||||
clk[ect_gate] = imx_clk_gate2("ect_gate", "per", base + MXC_CCM_CGR1, 16);
|
||||
clk[usb_gate] = imx_clk_gate2("usb_gate", "ahb", base + MXC_CCM_CGR1, 18);
|
||||
clk[kpp_gate] = imx_clk_gate2("kpp_gate", "ipg", base + MXC_CCM_CGR1, 20);
|
||||
clk[ipu_gate] = imx_clk_gate2("ipu_gate", "hsp", base + MXC_CCM_CGR1, 22);
|
||||
clk[uart3_gate] = imx_clk_gate2("uart3_gate", "per", base + MXC_CCM_CGR1, 24);
|
||||
clk[uart4_gate] = imx_clk_gate2("uart4_gate", "per", base + MXC_CCM_CGR1, 26);
|
||||
clk[uart5_gate] = imx_clk_gate2("uart5_gate", "per", base + MXC_CCM_CGR1, 28);
|
||||
clk[owire_gate] = imx_clk_gate2("owire_gate", "per", base + MXC_CCM_CGR1, 30);
|
||||
clk[ssi2_gate] = imx_clk_gate2("ssi2_gate", "spll", base + MXC_CCM_CGR2, 0);
|
||||
clk[cspi1_gate] = imx_clk_gate2("cspi1_gate", "ipg", base + MXC_CCM_CGR2, 2);
|
||||
clk[cspi2_gate] = imx_clk_gate2("cspi2_gate", "ipg", base + MXC_CCM_CGR2, 4);
|
||||
clk[gacc_gate] = imx_clk_gate2("gacc_gate", "per", base + MXC_CCM_CGR2, 6);
|
||||
clk[emi_gate] = imx_clk_gate2("emi_gate", "ahb", base + MXC_CCM_CGR2, 8);
|
||||
clk[rtic_gate] = imx_clk_gate2("rtic_gate", "ahb", base + MXC_CCM_CGR2, 10);
|
||||
clk[firi_gate] = imx_clk_gate2("firi_gate", "upll", base+MXC_CCM_CGR2, 12);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx31-ccm");
|
||||
|
||||
if (np) {
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
}
|
||||
|
||||
clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[cspi1_gate], NULL, "imx31-cspi.0");
|
||||
clk_register_clkdev(clk[cspi2_gate], NULL, "imx31-cspi.1");
|
||||
clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2");
|
||||
clk_register_clkdev(clk[pwm_gate], "pwm", NULL);
|
||||
clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
|
||||
clk_register_clkdev(clk[rtc_gate], NULL, "imx21-rtc");
|
||||
clk_register_clkdev(clk[epit1_gate], "epit", NULL);
|
||||
clk_register_clkdev(clk[epit2_gate], "epit", NULL);
|
||||
clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0");
|
||||
clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core");
|
||||
clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
|
||||
clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad");
|
||||
clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[usb_div_post], "per", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[usb_gate], "ahb", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
|
||||
/* i.mx31 has the i.mx21 type uart */
|
||||
clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[uart4_gate], "per", "imx21-uart.3");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.3");
|
||||
clk_register_clkdev(clk[uart5_gate], "per", "imx21-uart.4");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.4");
|
||||
clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0");
|
||||
clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1");
|
||||
clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2");
|
||||
clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0");
|
||||
clk_register_clkdev(clk[sdhc1_gate], NULL, "imx31-mmc.0");
|
||||
clk_register_clkdev(clk[sdhc2_gate], NULL, "imx31-mmc.1");
|
||||
clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0");
|
||||
clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1");
|
||||
clk_register_clkdev(clk[firi_gate], "firi", NULL);
|
||||
clk_register_clkdev(clk[ata_gate], NULL, "pata_imx");
|
||||
clk_register_clkdev(clk[rtic_gate], "rtic", NULL);
|
||||
clk_register_clkdev(clk[rng_gate], NULL, "mxc_rnga");
|
||||
clk_register_clkdev(clk[sdma_gate], NULL, "imx31-sdma");
|
||||
clk_register_clkdev(clk[iim_gate], "iim", NULL);
|
||||
|
||||
clk_set_parent(clk[csi], clk[upll]);
|
||||
clk_prepare_enable(clk[emi_gate]);
|
||||
clk_prepare_enable(clk[iim_gate]);
|
||||
mx31_revision();
|
||||
clk_disable_unprepare(clk[iim_gate]);
|
||||
|
||||
mxc_timer_init(MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), MX31_INT_GPT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init mx31_clocks_init_dt(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 fref = 26000000; /* default */
|
||||
|
||||
for_each_compatible_node(np, NULL, "fixed-clock") {
|
||||
if (!of_device_is_compatible(np, "fsl,imx-osc26m"))
|
||||
continue;
|
||||
|
||||
if (!of_property_read_u32(np, "clock-frequency", &fref))
|
||||
break;
|
||||
}
|
||||
|
||||
return mx31_clocks_init(fref);
|
||||
}
|
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
|
||||
*
|
||||
* 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/mm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "crmregs-imx3.h"
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
struct arm_ahb_div {
|
||||
unsigned char arm, ahb, sel;
|
||||
};
|
||||
|
||||
static struct arm_ahb_div clk_consumer[] = {
|
||||
{ .arm = 1, .ahb = 4, .sel = 0},
|
||||
{ .arm = 1, .ahb = 3, .sel = 1},
|
||||
{ .arm = 2, .ahb = 2, .sel = 0},
|
||||
{ .arm = 0, .ahb = 0, .sel = 0},
|
||||
{ .arm = 0, .ahb = 0, .sel = 0},
|
||||
{ .arm = 0, .ahb = 0, .sel = 0},
|
||||
{ .arm = 4, .ahb = 1, .sel = 0},
|
||||
{ .arm = 1, .ahb = 5, .sel = 0},
|
||||
{ .arm = 1, .ahb = 8, .sel = 0},
|
||||
{ .arm = 1, .ahb = 6, .sel = 1},
|
||||
{ .arm = 2, .ahb = 4, .sel = 0},
|
||||
{ .arm = 0, .ahb = 0, .sel = 0},
|
||||
{ .arm = 0, .ahb = 0, .sel = 0},
|
||||
{ .arm = 0, .ahb = 0, .sel = 0},
|
||||
{ .arm = 4, .ahb = 2, .sel = 0},
|
||||
{ .arm = 0, .ahb = 0, .sel = 0},
|
||||
};
|
||||
|
||||
static char hsp_div_532[] = { 4, 8, 3, 0 };
|
||||
static char hsp_div_400[] = { 3, 6, 3, 0 };
|
||||
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static const char *std_sel[] = {"ppll", "arm"};
|
||||
static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"};
|
||||
|
||||
enum mx35_clks {
|
||||
ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
|
||||
arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel,
|
||||
esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre,
|
||||
spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre,
|
||||
ssi2_div_post, usb_sel, usb_div, nfc_div, asrc_gate, pata_gate,
|
||||
audmux_gate, can1_gate, can2_gate, cspi1_gate, cspi2_gate, ect_gate,
|
||||
edio_gate, emi_gate, epit1_gate, epit2_gate, esai_gate, esdhc1_gate,
|
||||
esdhc2_gate, esdhc3_gate, fec_gate, gpio1_gate, gpio2_gate, gpio3_gate,
|
||||
gpt_gate, i2c1_gate, i2c2_gate, i2c3_gate, iomuxc_gate, ipu_gate,
|
||||
kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate,
|
||||
rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate,
|
||||
ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate,
|
||||
wdog_gate, max_gate, admux_gate, csi_gate, csi_div, csi_sel, iim_gate,
|
||||
gpu2d_gate, clk_max
|
||||
};
|
||||
|
||||
static struct clk *clk[clk_max];
|
||||
|
||||
int __init mx35_clocks_init(void)
|
||||
{
|
||||
void __iomem *base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR);
|
||||
u32 pdr0, consumer_sel, hsp_sel;
|
||||
struct arm_ahb_div *aad;
|
||||
unsigned char *hsp_div;
|
||||
|
||||
pdr0 = __raw_readl(base + MXC_CCM_PDR0);
|
||||
consumer_sel = (pdr0 >> 16) & 0xf;
|
||||
aad = &clk_consumer[consumer_sel];
|
||||
if (!aad->arm) {
|
||||
pr_err("i.MX35 clk: illegal consumer mux selection 0x%x\n", consumer_sel);
|
||||
/*
|
||||
* We are basically stuck. Continue with a default entry and hope we
|
||||
* get far enough to actually show the above message
|
||||
*/
|
||||
aad = &clk_consumer[0];
|
||||
}
|
||||
|
||||
clk[ckih] = imx_clk_fixed("ckih", 24000000);
|
||||
clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MX35_CCM_MPCTL);
|
||||
clk[ppll] = imx_clk_pllv1("ppll", "ckih", base + MX35_CCM_PPCTL);
|
||||
|
||||
clk[mpll] = imx_clk_fixed_factor("mpll_075", "mpll", 3, 4);
|
||||
|
||||
if (aad->sel)
|
||||
clk[arm] = imx_clk_fixed_factor("arm", "mpll_075", 1, aad->arm);
|
||||
else
|
||||
clk[arm] = imx_clk_fixed_factor("arm", "mpll", 1, aad->arm);
|
||||
|
||||
if (clk_get_rate(clk[arm]) > 400000000)
|
||||
hsp_div = hsp_div_532;
|
||||
else
|
||||
hsp_div = hsp_div_400;
|
||||
|
||||
hsp_sel = (pdr0 >> 20) & 0x3;
|
||||
if (!hsp_div[hsp_sel]) {
|
||||
pr_err("i.MX35 clk: illegal hsp clk selection 0x%x\n", hsp_sel);
|
||||
hsp_sel = 0;
|
||||
}
|
||||
|
||||
clk[hsp] = imx_clk_fixed_factor("hsp", "arm", 1, hsp_div[hsp_sel]);
|
||||
|
||||
clk[ahb] = imx_clk_fixed_factor("ahb", "arm", 1, aad->ahb);
|
||||
clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2);
|
||||
|
||||
clk[arm_per_div] = imx_clk_divider("arm_per_div", "arm", base + MX35_CCM_PDR4, 16, 6);
|
||||
clk[ahb_per_div] = imx_clk_divider("ahb_per_div", "ahb", base + MXC_CCM_PDR0, 12, 3);
|
||||
clk[ipg_per] = imx_clk_mux("ipg_per", base + MXC_CCM_PDR0, 26, 1, ipg_per_sel, ARRAY_SIZE(ipg_per_sel));
|
||||
|
||||
clk[uart_sel] = imx_clk_mux("uart_sel", base + MX35_CCM_PDR3, 14, 1, std_sel, ARRAY_SIZE(std_sel));
|
||||
clk[uart_div] = imx_clk_divider("uart_div", "uart_sel", base + MX35_CCM_PDR4, 10, 6);
|
||||
|
||||
clk[esdhc_sel] = imx_clk_mux("esdhc_sel", base + MX35_CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel));
|
||||
clk[esdhc1_div] = imx_clk_divider("esdhc1_div", "esdhc_sel", base + MX35_CCM_PDR3, 0, 6);
|
||||
clk[esdhc2_div] = imx_clk_divider("esdhc2_div", "esdhc_sel", base + MX35_CCM_PDR3, 8, 6);
|
||||
clk[esdhc3_div] = imx_clk_divider("esdhc3_div", "esdhc_sel", base + MX35_CCM_PDR3, 16, 6);
|
||||
|
||||
clk[spdif_sel] = imx_clk_mux("spdif_sel", base + MX35_CCM_PDR3, 22, 1, std_sel, ARRAY_SIZE(std_sel));
|
||||
clk[spdif_div_pre] = imx_clk_divider("spdif_div_pre", "spdif_sel", base + MX35_CCM_PDR3, 29, 3); /* divide by 1 not allowed */
|
||||
clk[spdif_div_post] = imx_clk_divider("spdif_div_post", "spdif_div_pre", base + MX35_CCM_PDR3, 23, 6);
|
||||
|
||||
clk[ssi_sel] = imx_clk_mux("ssi_sel", base + MX35_CCM_PDR2, 6, 1, std_sel, ARRAY_SIZE(std_sel));
|
||||
clk[ssi1_div_pre] = imx_clk_divider("ssi1_div_pre", "ssi_sel", base + MX35_CCM_PDR2, 24, 3);
|
||||
clk[ssi1_div_post] = imx_clk_divider("ssi1_div_post", "ssi1_div_pre", base + MX35_CCM_PDR2, 0, 6);
|
||||
clk[ssi2_div_pre] = imx_clk_divider("ssi2_div_pre", "ssi_sel", base + MX35_CCM_PDR2, 27, 3);
|
||||
clk[ssi2_div_post] = imx_clk_divider("ssi2_div_post", "ssi2_div_pre", base + MX35_CCM_PDR2, 8, 6);
|
||||
|
||||
clk[usb_sel] = imx_clk_mux("usb_sel", base + MX35_CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel));
|
||||
clk[usb_div] = imx_clk_divider("usb_div", "usb_sel", base + MX35_CCM_PDR4, 22, 6);
|
||||
|
||||
clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + MX35_CCM_PDR4, 28, 4);
|
||||
|
||||
clk[csi_sel] = imx_clk_mux("csi_sel", base + MX35_CCM_PDR2, 7, 1, std_sel, ARRAY_SIZE(std_sel));
|
||||
clk[csi_div] = imx_clk_divider("csi_div", "csi_sel", base + MX35_CCM_PDR2, 16, 6);
|
||||
|
||||
clk[asrc_gate] = imx_clk_gate2("asrc_gate", "ipg", base + MX35_CCM_CGR0, 0);
|
||||
clk[pata_gate] = imx_clk_gate2("pata_gate", "ipg", base + MX35_CCM_CGR0, 2);
|
||||
clk[audmux_gate] = imx_clk_gate2("audmux_gate", "ipg", base + MX35_CCM_CGR0, 4);
|
||||
clk[can1_gate] = imx_clk_gate2("can1_gate", "ipg", base + MX35_CCM_CGR0, 6);
|
||||
clk[can2_gate] = imx_clk_gate2("can2_gate", "ipg", base + MX35_CCM_CGR0, 8);
|
||||
clk[cspi1_gate] = imx_clk_gate2("cspi1_gate", "ipg", base + MX35_CCM_CGR0, 10);
|
||||
clk[cspi2_gate] = imx_clk_gate2("cspi2_gate", "ipg", base + MX35_CCM_CGR0, 12);
|
||||
clk[ect_gate] = imx_clk_gate2("ect_gate", "ipg", base + MX35_CCM_CGR0, 14);
|
||||
clk[edio_gate] = imx_clk_gate2("edio_gate", "ipg", base + MX35_CCM_CGR0, 16);
|
||||
clk[emi_gate] = imx_clk_gate2("emi_gate", "ipg", base + MX35_CCM_CGR0, 18);
|
||||
clk[epit1_gate] = imx_clk_gate2("epit1_gate", "ipg", base + MX35_CCM_CGR0, 20);
|
||||
clk[epit2_gate] = imx_clk_gate2("epit2_gate", "ipg", base + MX35_CCM_CGR0, 22);
|
||||
clk[esai_gate] = imx_clk_gate2("esai_gate", "ipg", base + MX35_CCM_CGR0, 24);
|
||||
clk[esdhc1_gate] = imx_clk_gate2("esdhc1_gate", "esdhc1_div", base + MX35_CCM_CGR0, 26);
|
||||
clk[esdhc2_gate] = imx_clk_gate2("esdhc2_gate", "esdhc2_div", base + MX35_CCM_CGR0, 28);
|
||||
clk[esdhc3_gate] = imx_clk_gate2("esdhc3_gate", "esdhc3_div", base + MX35_CCM_CGR0, 30);
|
||||
|
||||
clk[fec_gate] = imx_clk_gate2("fec_gate", "ipg", base + MX35_CCM_CGR1, 0);
|
||||
clk[gpio1_gate] = imx_clk_gate2("gpio1_gate", "ipg", base + MX35_CCM_CGR1, 2);
|
||||
clk[gpio2_gate] = imx_clk_gate2("gpio2_gate", "ipg", base + MX35_CCM_CGR1, 4);
|
||||
clk[gpio3_gate] = imx_clk_gate2("gpio3_gate", "ipg", base + MX35_CCM_CGR1, 6);
|
||||
clk[gpt_gate] = imx_clk_gate2("gpt_gate", "ipg", base + MX35_CCM_CGR1, 8);
|
||||
clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "ipg_per", base + MX35_CCM_CGR1, 10);
|
||||
clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "ipg_per", base + MX35_CCM_CGR1, 12);
|
||||
clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "ipg_per", base + MX35_CCM_CGR1, 14);
|
||||
clk[iomuxc_gate] = imx_clk_gate2("iomuxc_gate", "ipg", base + MX35_CCM_CGR1, 16);
|
||||
clk[ipu_gate] = imx_clk_gate2("ipu_gate", "hsp", base + MX35_CCM_CGR1, 18);
|
||||
clk[kpp_gate] = imx_clk_gate2("kpp_gate", "ipg", base + MX35_CCM_CGR1, 20);
|
||||
clk[mlb_gate] = imx_clk_gate2("mlb_gate", "ahb", base + MX35_CCM_CGR1, 22);
|
||||
clk[mshc_gate] = imx_clk_gate2("mshc_gate", "dummy", base + MX35_CCM_CGR1, 24);
|
||||
clk[owire_gate] = imx_clk_gate2("owire_gate", "ipg_per", base + MX35_CCM_CGR1, 26);
|
||||
clk[pwm_gate] = imx_clk_gate2("pwm_gate", "ipg_per", base + MX35_CCM_CGR1, 28);
|
||||
clk[rngc_gate] = imx_clk_gate2("rngc_gate", "ipg", base + MX35_CCM_CGR1, 30);
|
||||
|
||||
clk[rtc_gate] = imx_clk_gate2("rtc_gate", "ipg", base + MX35_CCM_CGR2, 0);
|
||||
clk[rtic_gate] = imx_clk_gate2("rtic_gate", "ahb", base + MX35_CCM_CGR2, 2);
|
||||
clk[scc_gate] = imx_clk_gate2("scc_gate", "ipg", base + MX35_CCM_CGR2, 4);
|
||||
clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ahb", base + MX35_CCM_CGR2, 6);
|
||||
clk[spba_gate] = imx_clk_gate2("spba_gate", "ipg", base + MX35_CCM_CGR2, 8);
|
||||
clk[spdif_gate] = imx_clk_gate2("spdif_gate", "spdif_div_post", base + MX35_CCM_CGR2, 10);
|
||||
clk[ssi1_gate] = imx_clk_gate2("ssi1_gate", "ssi1_div_post", base + MX35_CCM_CGR2, 12);
|
||||
clk[ssi2_gate] = imx_clk_gate2("ssi2_gate", "ssi2_div_post", base + MX35_CCM_CGR2, 14);
|
||||
clk[uart1_gate] = imx_clk_gate2("uart1_gate", "uart_div", base + MX35_CCM_CGR2, 16);
|
||||
clk[uart2_gate] = imx_clk_gate2("uart2_gate", "uart_div", base + MX35_CCM_CGR2, 18);
|
||||
clk[uart3_gate] = imx_clk_gate2("uart3_gate", "uart_div", base + MX35_CCM_CGR2, 20);
|
||||
clk[usbotg_gate] = imx_clk_gate2("usbotg_gate", "ahb", base + MX35_CCM_CGR2, 22);
|
||||
clk[wdog_gate] = imx_clk_gate2("wdog_gate", "ipg", base + MX35_CCM_CGR2, 24);
|
||||
clk[max_gate] = imx_clk_gate2("max_gate", "dummy", base + MX35_CCM_CGR2, 26);
|
||||
clk[admux_gate] = imx_clk_gate2("admux_gate", "ipg", base + MX35_CCM_CGR2, 30);
|
||||
|
||||
clk[csi_gate] = imx_clk_gate2("csi_gate", "csi_div", base + MX35_CCM_CGR3, 0);
|
||||
clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MX35_CCM_CGR3, 2);
|
||||
clk[gpu2d_gate] = imx_clk_gate2("gpu2d_gate", "ahb", base + MX35_CCM_CGR3, 4);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
clk_register_clkdev(clk[pata_gate], NULL, "pata_imx");
|
||||
clk_register_clkdev(clk[can1_gate], NULL, "flexcan.0");
|
||||
clk_register_clkdev(clk[can2_gate], NULL, "flexcan.1");
|
||||
clk_register_clkdev(clk[cspi1_gate], "per", "imx35-cspi.0");
|
||||
clk_register_clkdev(clk[cspi1_gate], "ipg", "imx35-cspi.0");
|
||||
clk_register_clkdev(clk[cspi2_gate], "per", "imx35-cspi.1");
|
||||
clk_register_clkdev(clk[cspi2_gate], "ipg", "imx35-cspi.1");
|
||||
clk_register_clkdev(clk[epit1_gate], NULL, "imx-epit.0");
|
||||
clk_register_clkdev(clk[epit2_gate], NULL, "imx-epit.1");
|
||||
clk_register_clkdev(clk[esdhc1_gate], "per", "sdhci-esdhc-imx35.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.0");
|
||||
clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.0");
|
||||
clk_register_clkdev(clk[esdhc2_gate], "per", "sdhci-esdhc-imx35.1");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.1");
|
||||
clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.1");
|
||||
clk_register_clkdev(clk[esdhc3_gate], "per", "sdhci-esdhc-imx35.2");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.2");
|
||||
clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.2");
|
||||
/* i.mx35 has the i.mx27 type fec */
|
||||
clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0");
|
||||
clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0");
|
||||
clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0");
|
||||
clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1");
|
||||
clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2");
|
||||
clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core");
|
||||
clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
|
||||
clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad");
|
||||
clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1");
|
||||
clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma");
|
||||
clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0");
|
||||
clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1");
|
||||
/* i.mx35 has the i.mx21 type uart */
|
||||
clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0");
|
||||
clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1");
|
||||
clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2");
|
||||
clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.0");
|
||||
clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.1");
|
||||
clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.2");
|
||||
clk_register_clkdev(clk[usb_div], "per", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[usbotg_gate], "ahb", "imx-udc-mx27");
|
||||
clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
|
||||
clk_register_clkdev(clk[nfc_div], NULL, "imx25-nand.0");
|
||||
clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
|
||||
clk_register_clkdev(clk[admux_gate], "audmux", NULL);
|
||||
|
||||
clk_prepare_enable(clk[spba_gate]);
|
||||
clk_prepare_enable(clk[gpio1_gate]);
|
||||
clk_prepare_enable(clk[gpio2_gate]);
|
||||
clk_prepare_enable(clk[gpio3_gate]);
|
||||
clk_prepare_enable(clk[iim_gate]);
|
||||
clk_prepare_enable(clk[emi_gate]);
|
||||
clk_prepare_enable(clk[max_gate]);
|
||||
clk_prepare_enable(clk[iomuxc_gate]);
|
||||
|
||||
/*
|
||||
* SCC is needed to boot via mmc after a watchdog reset. The clock code
|
||||
* before conversion to common clk also enabled UART1 (which isn't
|
||||
* handled here and not needed for mmc) and IIM (which is enabled
|
||||
* unconditionally above).
|
||||
*/
|
||||
clk_prepare_enable(clk[scc_gate]);
|
||||
|
||||
imx_print_silicon_rev("i.MX35", mx35_revision());
|
||||
|
||||
#ifdef CONFIG_MXC_USE_EPIT
|
||||
epit_timer_init(MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1);
|
||||
#else
|
||||
mxc_timer_init(MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init mx35_clocks_init_dt(struct device_node *ccm_node)
|
||||
{
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
mx35_clocks_init();
|
||||
}
|
||||
CLK_OF_DECLARE(imx35, "fsl,imx35-ccm", mx35_clocks_init_dt);
|
@@ -1,573 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
|
||||
*
|
||||
* 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/mm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <dt-bindings/clock/imx5-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#define MX51_DPLL1_BASE 0x83f80000
|
||||
#define MX51_DPLL2_BASE 0x83f84000
|
||||
#define MX51_DPLL3_BASE 0x83f88000
|
||||
|
||||
#define MX53_DPLL1_BASE 0x63f80000
|
||||
#define MX53_DPLL2_BASE 0x63f84000
|
||||
#define MX53_DPLL3_BASE 0x63f88000
|
||||
#define MX53_DPLL4_BASE 0x63f8c000
|
||||
|
||||
#define MXC_CCM_CCR (ccm_base + 0x00)
|
||||
#define MXC_CCM_CCDR (ccm_base + 0x04)
|
||||
#define MXC_CCM_CSR (ccm_base + 0x08)
|
||||
#define MXC_CCM_CCSR (ccm_base + 0x0c)
|
||||
#define MXC_CCM_CACRR (ccm_base + 0x10)
|
||||
#define MXC_CCM_CBCDR (ccm_base + 0x14)
|
||||
#define MXC_CCM_CBCMR (ccm_base + 0x18)
|
||||
#define MXC_CCM_CSCMR1 (ccm_base + 0x1c)
|
||||
#define MXC_CCM_CSCMR2 (ccm_base + 0x20)
|
||||
#define MXC_CCM_CSCDR1 (ccm_base + 0x24)
|
||||
#define MXC_CCM_CS1CDR (ccm_base + 0x28)
|
||||
#define MXC_CCM_CS2CDR (ccm_base + 0x2c)
|
||||
#define MXC_CCM_CDCDR (ccm_base + 0x30)
|
||||
#define MXC_CCM_CHSCDR (ccm_base + 0x34)
|
||||
#define MXC_CCM_CSCDR2 (ccm_base + 0x38)
|
||||
#define MXC_CCM_CSCDR3 (ccm_base + 0x3c)
|
||||
#define MXC_CCM_CSCDR4 (ccm_base + 0x40)
|
||||
#define MXC_CCM_CWDR (ccm_base + 0x44)
|
||||
#define MXC_CCM_CDHIPR (ccm_base + 0x48)
|
||||
#define MXC_CCM_CDCR (ccm_base + 0x4c)
|
||||
#define MXC_CCM_CTOR (ccm_base + 0x50)
|
||||
#define MXC_CCM_CLPCR (ccm_base + 0x54)
|
||||
#define MXC_CCM_CISR (ccm_base + 0x58)
|
||||
#define MXC_CCM_CIMR (ccm_base + 0x5c)
|
||||
#define MXC_CCM_CCOSR (ccm_base + 0x60)
|
||||
#define MXC_CCM_CGPR (ccm_base + 0x64)
|
||||
#define MXC_CCM_CCGR0 (ccm_base + 0x68)
|
||||
#define MXC_CCM_CCGR1 (ccm_base + 0x6c)
|
||||
#define MXC_CCM_CCGR2 (ccm_base + 0x70)
|
||||
#define MXC_CCM_CCGR3 (ccm_base + 0x74)
|
||||
#define MXC_CCM_CCGR4 (ccm_base + 0x78)
|
||||
#define MXC_CCM_CCGR5 (ccm_base + 0x7c)
|
||||
#define MXC_CCM_CCGR6 (ccm_base + 0x80)
|
||||
#define MXC_CCM_CCGR7 (ccm_base + 0x84)
|
||||
|
||||
/* Low-power Audio Playback Mode clock */
|
||||
static const char *lp_apm_sel[] = { "osc", };
|
||||
|
||||
/* This is used multiple times */
|
||||
static const char *standard_pll_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "lp_apm", };
|
||||
static const char *periph_apm_sel[] = { "pll1_sw", "pll3_sw", "lp_apm", };
|
||||
static const char *main_bus_sel[] = { "pll2_sw", "periph_apm", };
|
||||
static const char *per_lp_apm_sel[] = { "main_bus", "lp_apm", };
|
||||
static const char *per_root_sel[] = { "per_podf", "ipg", };
|
||||
static const char *esdhc_c_sel[] = { "esdhc_a_podf", "esdhc_b_podf", };
|
||||
static const char *esdhc_d_sel[] = { "esdhc_a_podf", "esdhc_b_podf", };
|
||||
static const char *ssi_apm_sels[] = { "ckih1", "lp_amp", "ckih2", };
|
||||
static const char *ssi_clk_sels[] = { "pll1_sw", "pll2_sw", "pll3_sw", "ssi_apm", };
|
||||
static const char *ssi3_clk_sels[] = { "ssi1_root_gate", "ssi2_root_gate", };
|
||||
static const char *ssi_ext1_com_sels[] = { "ssi_ext1_podf", "ssi1_root_gate", };
|
||||
static const char *ssi_ext2_com_sels[] = { "ssi_ext2_podf", "ssi2_root_gate", };
|
||||
static const char *emi_slow_sel[] = { "main_bus", "ahb", };
|
||||
static const char *usb_phy_sel_str[] = { "osc", "usb_phy_podf", };
|
||||
static const char *mx51_ipu_di0_sel[] = { "di_pred", "osc", "ckih1", "tve_di", };
|
||||
static const char *mx53_ipu_di0_sel[] = { "di_pred", "osc", "ckih1", "di_pll4_podf", "dummy", "ldb_di0_gate", };
|
||||
static const char *mx53_ldb_di0_sel[] = { "pll3_sw", "pll4_sw", };
|
||||
static const char *mx51_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "ipp_di1", };
|
||||
static const char *mx53_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "ipp_di1", "ldb_di1_gate", };
|
||||
static const char *mx53_ldb_di1_sel[] = { "pll3_sw", "pll4_sw", };
|
||||
static const char *mx51_tve_ext_sel[] = { "osc", "ckih1", };
|
||||
static const char *mx53_tve_ext_sel[] = { "pll4_sw", "ckih1", };
|
||||
static const char *mx51_tve_sel[] = { "tve_pred", "tve_ext_sel", };
|
||||
static const char *ipu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };
|
||||
static const char *gpu3d_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb" };
|
||||
static const char *gpu2d_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb" };
|
||||
static const char *vpu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };
|
||||
static const char *mx53_can_sel[] = { "ipg", "ckih1", "ckih2", "lp_apm", };
|
||||
static const char *mx53_cko1_sel[] = {
|
||||
"cpu_podf", "pll1_sw", "pll2_sw", "pll3_sw",
|
||||
"emi_slow_podf", "pll4_sw", "nfc_podf", "dummy",
|
||||
"di_pred", "dummy", "dummy", "ahb",
|
||||
"ipg", "per_root", "ckil", "dummy",};
|
||||
static const char *mx53_cko2_sel[] = {
|
||||
"dummy"/* dptc_core */, "dummy"/* dptc_perich */,
|
||||
"dummy", "esdhc_a_podf",
|
||||
"usboh3_podf", "dummy"/* wrck_clk_root */,
|
||||
"ecspi_podf", "dummy"/* pll1_ref_clk */,
|
||||
"esdhc_b_podf", "dummy"/* ddr_clk_root */,
|
||||
"dummy"/* arm_axi_clk_root */, "dummy"/* usb_phy_out */,
|
||||
"vpu_sel", "ipu_sel",
|
||||
"osc", "ckih1",
|
||||
"dummy", "esdhc_c_sel",
|
||||
"ssi1_root_podf", "ssi2_root_podf",
|
||||
"dummy", "dummy",
|
||||
"dummy"/* lpsr_clk_root */, "dummy"/* pgc_clk_root */,
|
||||
"dummy"/* tve_out */, "usb_phy_sel",
|
||||
"tve_sel", "lp_apm",
|
||||
"uart_root", "dummy"/* spdif0_clk_root */,
|
||||
"dummy", "dummy", };
|
||||
static const char *mx51_spdif_xtal_sel[] = { "osc", "ckih", "ckih2", };
|
||||
static const char *mx53_spdif_xtal_sel[] = { "osc", "ckih", "ckih2", "pll4_sw", };
|
||||
static const char *spdif_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "spdif_xtal_sel", };
|
||||
static const char *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", };
|
||||
static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_root_gate", };
|
||||
static const char *step_sels[] = { "lp_apm", };
|
||||
static const char *cpu_podf_sels[] = { "pll1_sw", "step_sel" };
|
||||
|
||||
static struct clk *clk[IMX5_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static void __init mx5_clocks_common_init(void __iomem *ccm_base)
|
||||
{
|
||||
imx5_pm_set_ccm_base(ccm_base);
|
||||
|
||||
clk[IMX5_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
clk[IMX5_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
|
||||
clk[IMX5_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
|
||||
clk[IMX5_CLK_CKIH1] = imx_obtain_fixed_clock("ckih1", 0);
|
||||
clk[IMX5_CLK_CKIH2] = imx_obtain_fixed_clock("ckih2", 0);
|
||||
|
||||
clk[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2,
|
||||
periph_apm_sel, ARRAY_SIZE(periph_apm_sel));
|
||||
clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1,
|
||||
main_bus_sel, ARRAY_SIZE(main_bus_sel));
|
||||
clk[IMX5_CLK_PER_LP_APM] = imx_clk_mux("per_lp_apm", MXC_CCM_CBCMR, 1, 1,
|
||||
per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel));
|
||||
clk[IMX5_CLK_PER_PRED1] = imx_clk_divider("per_pred1", "per_lp_apm", MXC_CCM_CBCDR, 6, 2);
|
||||
clk[IMX5_CLK_PER_PRED2] = imx_clk_divider("per_pred2", "per_pred1", MXC_CCM_CBCDR, 3, 3);
|
||||
clk[IMX5_CLK_PER_PODF] = imx_clk_divider("per_podf", "per_pred2", MXC_CCM_CBCDR, 0, 3);
|
||||
clk[IMX5_CLK_PER_ROOT] = imx_clk_mux("per_root", MXC_CCM_CBCMR, 0, 1,
|
||||
per_root_sel, ARRAY_SIZE(per_root_sel));
|
||||
clk[IMX5_CLK_AHB] = imx_clk_divider("ahb", "main_bus", MXC_CCM_CBCDR, 10, 3);
|
||||
clk[IMX5_CLK_AHB_MAX] = imx_clk_gate2("ahb_max", "ahb", MXC_CCM_CCGR0, 28);
|
||||
clk[IMX5_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", MXC_CCM_CCGR0, 24);
|
||||
clk[IMX5_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", MXC_CCM_CCGR0, 26);
|
||||
clk[IMX5_CLK_TMAX1] = imx_clk_gate2("tmax1", "ahb", MXC_CCM_CCGR1, 0);
|
||||
clk[IMX5_CLK_TMAX2] = imx_clk_gate2("tmax2", "ahb", MXC_CCM_CCGR1, 2);
|
||||
clk[IMX5_CLK_TMAX3] = imx_clk_gate2("tmax3", "ahb", MXC_CCM_CCGR1, 4);
|
||||
clk[IMX5_CLK_SPBA] = imx_clk_gate2("spba", "ipg", MXC_CCM_CCGR5, 0);
|
||||
clk[IMX5_CLK_IPG] = imx_clk_divider("ipg", "ahb", MXC_CCM_CBCDR, 8, 2);
|
||||
clk[IMX5_CLK_AXI_A] = imx_clk_divider("axi_a", "main_bus", MXC_CCM_CBCDR, 16, 3);
|
||||
clk[IMX5_CLK_AXI_B] = imx_clk_divider("axi_b", "main_bus", MXC_CCM_CBCDR, 19, 3);
|
||||
clk[IMX5_CLK_UART_SEL] = imx_clk_mux("uart_sel", MXC_CCM_CSCMR1, 24, 2,
|
||||
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
|
||||
clk[IMX5_CLK_UART_PRED] = imx_clk_divider("uart_pred", "uart_sel", MXC_CCM_CSCDR1, 3, 3);
|
||||
clk[IMX5_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_pred", MXC_CCM_CSCDR1, 0, 3);
|
||||
|
||||
clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2,
|
||||
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
|
||||
clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2,
|
||||
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
|
||||
clk[IMX5_CLK_ESDHC_A_PRED] = imx_clk_divider("esdhc_a_pred", "esdhc_a_sel", MXC_CCM_CSCDR1, 16, 3);
|
||||
clk[IMX5_CLK_ESDHC_A_PODF] = imx_clk_divider("esdhc_a_podf", "esdhc_a_pred", MXC_CCM_CSCDR1, 11, 3);
|
||||
clk[IMX5_CLK_ESDHC_B_PRED] = imx_clk_divider("esdhc_b_pred", "esdhc_b_sel", MXC_CCM_CSCDR1, 22, 3);
|
||||
clk[IMX5_CLK_ESDHC_B_PODF] = imx_clk_divider("esdhc_b_podf", "esdhc_b_pred", MXC_CCM_CSCDR1, 19, 3);
|
||||
clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel));
|
||||
clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel));
|
||||
|
||||
clk[IMX5_CLK_EMI_SEL] = imx_clk_mux("emi_sel", MXC_CCM_CBCDR, 26, 1,
|
||||
emi_slow_sel, ARRAY_SIZE(emi_slow_sel));
|
||||
clk[IMX5_CLK_EMI_SLOW_PODF] = imx_clk_divider("emi_slow_podf", "emi_sel", MXC_CCM_CBCDR, 22, 3);
|
||||
clk[IMX5_CLK_NFC_PODF] = imx_clk_divider("nfc_podf", "emi_slow_podf", MXC_CCM_CBCDR, 13, 3);
|
||||
clk[IMX5_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", MXC_CCM_CSCMR1, 4, 2,
|
||||
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
|
||||
clk[IMX5_CLK_ECSPI_PRED] = imx_clk_divider("ecspi_pred", "ecspi_sel", MXC_CCM_CSCDR2, 25, 3);
|
||||
clk[IMX5_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_pred", MXC_CCM_CSCDR2, 19, 6);
|
||||
clk[IMX5_CLK_USBOH3_SEL] = imx_clk_mux("usboh3_sel", MXC_CCM_CSCMR1, 22, 2,
|
||||
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
|
||||
clk[IMX5_CLK_USBOH3_PRED] = imx_clk_divider("usboh3_pred", "usboh3_sel", MXC_CCM_CSCDR1, 8, 3);
|
||||
clk[IMX5_CLK_USBOH3_PODF] = imx_clk_divider("usboh3_podf", "usboh3_pred", MXC_CCM_CSCDR1, 6, 2);
|
||||
clk[IMX5_CLK_USB_PHY_PRED] = imx_clk_divider("usb_phy_pred", "pll3_sw", MXC_CCM_CDCDR, 3, 3);
|
||||
clk[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3);
|
||||
clk[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1,
|
||||
usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));
|
||||
clk[IMX5_CLK_STEP_SEL] = imx_clk_mux("step_sel", MXC_CCM_CCSR, 7, 2, step_sels, ARRAY_SIZE(step_sels));
|
||||
clk[IMX5_CLK_CPU_PODF_SEL] = imx_clk_mux("cpu_podf_sel", MXC_CCM_CCSR, 2, 1, cpu_podf_sels, ARRAY_SIZE(cpu_podf_sels));
|
||||
clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "cpu_podf_sel", MXC_CCM_CACRR, 0, 3);
|
||||
clk[IMX5_CLK_DI_PRED] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3);
|
||||
clk[IMX5_CLK_IIM_GATE] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30);
|
||||
clk[IMX5_CLK_UART1_IPG_GATE] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6);
|
||||
clk[IMX5_CLK_UART1_PER_GATE] = imx_clk_gate2("uart1_per_gate", "uart_root", MXC_CCM_CCGR1, 8);
|
||||
clk[IMX5_CLK_UART2_IPG_GATE] = imx_clk_gate2("uart2_ipg_gate", "ipg", MXC_CCM_CCGR1, 10);
|
||||
clk[IMX5_CLK_UART2_PER_GATE] = imx_clk_gate2("uart2_per_gate", "uart_root", MXC_CCM_CCGR1, 12);
|
||||
clk[IMX5_CLK_UART3_IPG_GATE] = imx_clk_gate2("uart3_ipg_gate", "ipg", MXC_CCM_CCGR1, 14);
|
||||
clk[IMX5_CLK_UART3_PER_GATE] = imx_clk_gate2("uart3_per_gate", "uart_root", MXC_CCM_CCGR1, 16);
|
||||
clk[IMX5_CLK_I2C1_GATE] = imx_clk_gate2("i2c1_gate", "per_root", MXC_CCM_CCGR1, 18);
|
||||
clk[IMX5_CLK_I2C2_GATE] = imx_clk_gate2("i2c2_gate", "per_root", MXC_CCM_CCGR1, 20);
|
||||
clk[IMX5_CLK_PWM1_IPG_GATE] = imx_clk_gate2("pwm1_ipg_gate", "ipg", MXC_CCM_CCGR2, 10);
|
||||
clk[IMX5_CLK_PWM1_HF_GATE] = imx_clk_gate2("pwm1_hf_gate", "per_root", MXC_CCM_CCGR2, 12);
|
||||
clk[IMX5_CLK_PWM2_IPG_GATE] = imx_clk_gate2("pwm2_ipg_gate", "ipg", MXC_CCM_CCGR2, 14);
|
||||
clk[IMX5_CLK_PWM2_HF_GATE] = imx_clk_gate2("pwm2_hf_gate", "per_root", MXC_CCM_CCGR2, 16);
|
||||
clk[IMX5_CLK_GPT_IPG_GATE] = imx_clk_gate2("gpt_ipg_gate", "ipg", MXC_CCM_CCGR2, 18);
|
||||
clk[IMX5_CLK_GPT_HF_GATE] = imx_clk_gate2("gpt_hf_gate", "per_root", MXC_CCM_CCGR2, 20);
|
||||
clk[IMX5_CLK_FEC_GATE] = imx_clk_gate2("fec_gate", "ipg", MXC_CCM_CCGR2, 24);
|
||||
clk[IMX5_CLK_USBOH3_GATE] = imx_clk_gate2("usboh3_gate", "ipg", MXC_CCM_CCGR2, 26);
|
||||
clk[IMX5_CLK_USBOH3_PER_GATE] = imx_clk_gate2("usboh3_per_gate", "usboh3_podf", MXC_CCM_CCGR2, 28);
|
||||
clk[IMX5_CLK_ESDHC1_IPG_GATE] = imx_clk_gate2("esdhc1_ipg_gate", "ipg", MXC_CCM_CCGR3, 0);
|
||||
clk[IMX5_CLK_ESDHC2_IPG_GATE] = imx_clk_gate2("esdhc2_ipg_gate", "ipg", MXC_CCM_CCGR3, 4);
|
||||
clk[IMX5_CLK_ESDHC3_IPG_GATE] = imx_clk_gate2("esdhc3_ipg_gate", "ipg", MXC_CCM_CCGR3, 8);
|
||||
clk[IMX5_CLK_ESDHC4_IPG_GATE] = imx_clk_gate2("esdhc4_ipg_gate", "ipg", MXC_CCM_CCGR3, 12);
|
||||
clk[IMX5_CLK_SSI1_IPG_GATE] = imx_clk_gate2("ssi1_ipg_gate", "ipg", MXC_CCM_CCGR3, 16);
|
||||
clk[IMX5_CLK_SSI2_IPG_GATE] = imx_clk_gate2("ssi2_ipg_gate", "ipg", MXC_CCM_CCGR3, 20);
|
||||
clk[IMX5_CLK_SSI3_IPG_GATE] = imx_clk_gate2("ssi3_ipg_gate", "ipg", MXC_CCM_CCGR3, 24);
|
||||
clk[IMX5_CLK_ECSPI1_IPG_GATE] = imx_clk_gate2("ecspi1_ipg_gate", "ipg", MXC_CCM_CCGR4, 18);
|
||||
clk[IMX5_CLK_ECSPI1_PER_GATE] = imx_clk_gate2("ecspi1_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 20);
|
||||
clk[IMX5_CLK_ECSPI2_IPG_GATE] = imx_clk_gate2("ecspi2_ipg_gate", "ipg", MXC_CCM_CCGR4, 22);
|
||||
clk[IMX5_CLK_ECSPI2_PER_GATE] = imx_clk_gate2("ecspi2_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 24);
|
||||
clk[IMX5_CLK_CSPI_IPG_GATE] = imx_clk_gate2("cspi_ipg_gate", "ipg", MXC_CCM_CCGR4, 26);
|
||||
clk[IMX5_CLK_SDMA_GATE] = imx_clk_gate2("sdma_gate", "ipg", MXC_CCM_CCGR4, 30);
|
||||
clk[IMX5_CLK_EMI_FAST_GATE] = imx_clk_gate2("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14);
|
||||
clk[IMX5_CLK_EMI_SLOW_GATE] = imx_clk_gate2("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16);
|
||||
clk[IMX5_CLK_IPU_SEL] = imx_clk_mux("ipu_sel", MXC_CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel));
|
||||
clk[IMX5_CLK_IPU_GATE] = imx_clk_gate2("ipu_gate", "ipu_sel", MXC_CCM_CCGR5, 10);
|
||||
clk[IMX5_CLK_NFC_GATE] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20);
|
||||
clk[IMX5_CLK_IPU_DI0_GATE] = imx_clk_gate2("ipu_di0_gate", "ipu_di0_sel", MXC_CCM_CCGR6, 10);
|
||||
clk[IMX5_CLK_IPU_DI1_GATE] = imx_clk_gate2("ipu_di1_gate", "ipu_di1_sel", MXC_CCM_CCGR6, 12);
|
||||
clk[IMX5_CLK_GPU3D_SEL] = imx_clk_mux("gpu3d_sel", MXC_CCM_CBCMR, 4, 2, gpu3d_sel, ARRAY_SIZE(gpu3d_sel));
|
||||
clk[IMX5_CLK_GPU2D_SEL] = imx_clk_mux("gpu2d_sel", MXC_CCM_CBCMR, 16, 2, gpu2d_sel, ARRAY_SIZE(gpu2d_sel));
|
||||
clk[IMX5_CLK_GPU3D_GATE] = imx_clk_gate2("gpu3d_gate", "gpu3d_sel", MXC_CCM_CCGR5, 2);
|
||||
clk[IMX5_CLK_GARB_GATE] = imx_clk_gate2("garb_gate", "axi_a", MXC_CCM_CCGR5, 4);
|
||||
clk[IMX5_CLK_GPU2D_GATE] = imx_clk_gate2("gpu2d_gate", "gpu2d_sel", MXC_CCM_CCGR6, 14);
|
||||
clk[IMX5_CLK_VPU_SEL] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel));
|
||||
clk[IMX5_CLK_VPU_GATE] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6);
|
||||
clk[IMX5_CLK_VPU_REFERENCE_GATE] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8);
|
||||
clk[IMX5_CLK_UART4_IPG_GATE] = imx_clk_gate2("uart4_ipg_gate", "ipg", MXC_CCM_CCGR7, 8);
|
||||
clk[IMX5_CLK_UART4_PER_GATE] = imx_clk_gate2("uart4_per_gate", "uart_root", MXC_CCM_CCGR7, 10);
|
||||
clk[IMX5_CLK_UART5_IPG_GATE] = imx_clk_gate2("uart5_ipg_gate", "ipg", MXC_CCM_CCGR7, 12);
|
||||
clk[IMX5_CLK_UART5_PER_GATE] = imx_clk_gate2("uart5_per_gate", "uart_root", MXC_CCM_CCGR7, 14);
|
||||
clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24);
|
||||
|
||||
clk[IMX5_CLK_SSI_APM] = imx_clk_mux("ssi_apm", MXC_CCM_CSCMR1, 8, 2, ssi_apm_sels, ARRAY_SIZE(ssi_apm_sels));
|
||||
clk[IMX5_CLK_SSI1_ROOT_SEL] = imx_clk_mux("ssi1_root_sel", MXC_CCM_CSCMR1, 14, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels));
|
||||
clk[IMX5_CLK_SSI2_ROOT_SEL] = imx_clk_mux("ssi2_root_sel", MXC_CCM_CSCMR1, 12, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels));
|
||||
clk[IMX5_CLK_SSI3_ROOT_SEL] = imx_clk_mux("ssi3_root_sel", MXC_CCM_CSCMR1, 11, 1, ssi3_clk_sels, ARRAY_SIZE(ssi3_clk_sels));
|
||||
clk[IMX5_CLK_SSI_EXT1_SEL] = imx_clk_mux("ssi_ext1_sel", MXC_CCM_CSCMR1, 28, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels));
|
||||
clk[IMX5_CLK_SSI_EXT2_SEL] = imx_clk_mux("ssi_ext2_sel", MXC_CCM_CSCMR1, 30, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels));
|
||||
clk[IMX5_CLK_SSI_EXT1_COM_SEL] = imx_clk_mux("ssi_ext1_com_sel", MXC_CCM_CSCMR1, 0, 1, ssi_ext1_com_sels, ARRAY_SIZE(ssi_ext1_com_sels));
|
||||
clk[IMX5_CLK_SSI_EXT2_COM_SEL] = imx_clk_mux("ssi_ext2_com_sel", MXC_CCM_CSCMR1, 1, 1, ssi_ext2_com_sels, ARRAY_SIZE(ssi_ext2_com_sels));
|
||||
clk[IMX5_CLK_SSI1_ROOT_PRED] = imx_clk_divider("ssi1_root_pred", "ssi1_root_sel", MXC_CCM_CS1CDR, 6, 3);
|
||||
clk[IMX5_CLK_SSI1_ROOT_PODF] = imx_clk_divider("ssi1_root_podf", "ssi1_root_pred", MXC_CCM_CS1CDR, 0, 6);
|
||||
clk[IMX5_CLK_SSI2_ROOT_PRED] = imx_clk_divider("ssi2_root_pred", "ssi2_root_sel", MXC_CCM_CS2CDR, 6, 3);
|
||||
clk[IMX5_CLK_SSI2_ROOT_PODF] = imx_clk_divider("ssi2_root_podf", "ssi2_root_pred", MXC_CCM_CS2CDR, 0, 6);
|
||||
clk[IMX5_CLK_SSI_EXT1_PRED] = imx_clk_divider("ssi_ext1_pred", "ssi_ext1_sel", MXC_CCM_CS1CDR, 22, 3);
|
||||
clk[IMX5_CLK_SSI_EXT1_PODF] = imx_clk_divider("ssi_ext1_podf", "ssi_ext1_pred", MXC_CCM_CS1CDR, 16, 6);
|
||||
clk[IMX5_CLK_SSI_EXT2_PRED] = imx_clk_divider("ssi_ext2_pred", "ssi_ext2_sel", MXC_CCM_CS2CDR, 22, 3);
|
||||
clk[IMX5_CLK_SSI_EXT2_PODF] = imx_clk_divider("ssi_ext2_podf", "ssi_ext2_pred", MXC_CCM_CS2CDR, 16, 6);
|
||||
clk[IMX5_CLK_SSI1_ROOT_GATE] = imx_clk_gate2("ssi1_root_gate", "ssi1_root_podf", MXC_CCM_CCGR3, 18);
|
||||
clk[IMX5_CLK_SSI2_ROOT_GATE] = imx_clk_gate2("ssi2_root_gate", "ssi2_root_podf", MXC_CCM_CCGR3, 22);
|
||||
clk[IMX5_CLK_SSI3_ROOT_GATE] = imx_clk_gate2("ssi3_root_gate", "ssi3_root_sel", MXC_CCM_CCGR3, 26);
|
||||
clk[IMX5_CLK_SSI_EXT1_GATE] = imx_clk_gate2("ssi_ext1_gate", "ssi_ext1_com_sel", MXC_CCM_CCGR3, 28);
|
||||
clk[IMX5_CLK_SSI_EXT2_GATE] = imx_clk_gate2("ssi_ext2_gate", "ssi_ext2_com_sel", MXC_CCM_CCGR3, 30);
|
||||
clk[IMX5_CLK_EPIT1_IPG_GATE] = imx_clk_gate2("epit1_ipg_gate", "ipg", MXC_CCM_CCGR2, 2);
|
||||
clk[IMX5_CLK_EPIT1_HF_GATE] = imx_clk_gate2("epit1_hf_gate", "per_root", MXC_CCM_CCGR2, 4);
|
||||
clk[IMX5_CLK_EPIT2_IPG_GATE] = imx_clk_gate2("epit2_ipg_gate", "ipg", MXC_CCM_CCGR2, 6);
|
||||
clk[IMX5_CLK_EPIT2_HF_GATE] = imx_clk_gate2("epit2_hf_gate", "per_root", MXC_CCM_CCGR2, 8);
|
||||
clk[IMX5_CLK_OWIRE_GATE] = imx_clk_gate2("owire_gate", "per_root", MXC_CCM_CCGR2, 22);
|
||||
clk[IMX5_CLK_SRTC_GATE] = imx_clk_gate2("srtc_gate", "per_root", MXC_CCM_CCGR4, 28);
|
||||
clk[IMX5_CLK_PATA_GATE] = imx_clk_gate2("pata_gate", "ipg", MXC_CCM_CCGR4, 0);
|
||||
clk[IMX5_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", MXC_CCM_CSCMR2, 0, 2, spdif_sel, ARRAY_SIZE(spdif_sel));
|
||||
clk[IMX5_CLK_SPDIF0_PRED] = imx_clk_divider("spdif0_pred", "spdif0_sel", MXC_CCM_CDCDR, 25, 3);
|
||||
clk[IMX5_CLK_SPDIF0_PODF] = imx_clk_divider("spdif0_podf", "spdif0_pred", MXC_CCM_CDCDR, 19, 6);
|
||||
clk[IMX5_CLK_SPDIF0_COM_SEL] = imx_clk_mux_flags("spdif0_com_sel", MXC_CCM_CSCMR2, 4, 1,
|
||||
spdif0_com_sel, ARRAY_SIZE(spdif0_com_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_SPDIF0_GATE] = imx_clk_gate2("spdif0_gate", "spdif0_com_sel", MXC_CCM_CCGR5, 26);
|
||||
clk[IMX5_CLK_SPDIF_IPG_GATE] = imx_clk_gate2("spdif_ipg_gate", "ipg", MXC_CCM_CCGR5, 30);
|
||||
clk[IMX5_CLK_SAHARA_IPG_GATE] = imx_clk_gate2("sahara_ipg_gate", "ipg", MXC_CCM_CCGR4, 14);
|
||||
clk[IMX5_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "usb_phy1_gate", 1, 1);
|
||||
|
||||
clk_register_clkdev(clk[IMX5_CLK_CPU_PODF], NULL, "cpu0");
|
||||
clk_register_clkdev(clk[IMX5_CLK_GPC_DVFS], "gpc_dvfs", NULL);
|
||||
|
||||
/* Set SDHC parents to be PLL2 */
|
||||
clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]);
|
||||
clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]);
|
||||
|
||||
/* move usb phy clk to 24MHz */
|
||||
clk_set_parent(clk[IMX5_CLK_USB_PHY_SEL], clk[IMX5_CLK_OSC]);
|
||||
|
||||
clk_prepare_enable(clk[IMX5_CLK_GPC_DVFS]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_AHB_MAX]); /* esdhc3 */
|
||||
clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ1]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ2]); /* fec */
|
||||
clk_prepare_enable(clk[IMX5_CLK_SPBA]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_EMI_FAST_GATE]); /* fec */
|
||||
clk_prepare_enable(clk[IMX5_CLK_EMI_SLOW_GATE]); /* eim */
|
||||
clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC1_GATE]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC2_GATE]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_MIPI_ESC_GATE]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_MIPI_HSP_GATE]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_TMAX1]);
|
||||
clk_prepare_enable(clk[IMX5_CLK_TMAX2]); /* esdhc2, fec */
|
||||
clk_prepare_enable(clk[IMX5_CLK_TMAX3]); /* esdhc1, esdhc4 */
|
||||
}
|
||||
|
||||
static void __init mx50_clocks_init(struct device_node *np)
|
||||
{
|
||||
void __iomem *ccm_base;
|
||||
void __iomem *pll_base;
|
||||
unsigned long r;
|
||||
|
||||
pll_base = ioremap(MX53_DPLL1_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", pll_base);
|
||||
|
||||
pll_base = ioremap(MX53_DPLL2_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", pll_base);
|
||||
|
||||
pll_base = ioremap(MX53_DPLL3_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", pll_base);
|
||||
|
||||
ccm_base = of_iomap(np, 0);
|
||||
WARN_ON(!ccm_base);
|
||||
|
||||
mx5_clocks_common_init(ccm_base);
|
||||
|
||||
clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 10, 1,
|
||||
lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
|
||||
clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2);
|
||||
clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6);
|
||||
clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10);
|
||||
clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
|
||||
clk[IMX5_CLK_USB_PHY1_GATE] = imx_clk_gate2("usb_phy1_gate", "usb_phy_sel", MXC_CCM_CCGR4, 10);
|
||||
clk[IMX5_CLK_USB_PHY2_GATE] = imx_clk_gate2("usb_phy2_gate", "usb_phy_sel", MXC_CCM_CCGR4, 12);
|
||||
clk[IMX5_CLK_I2C3_GATE] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22);
|
||||
|
||||
clk[IMX5_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", MXC_CCM_CCOSR, 0, 4,
|
||||
mx53_cko1_sel, ARRAY_SIZE(mx53_cko1_sel));
|
||||
clk[IMX5_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", MXC_CCM_CCOSR, 4, 3);
|
||||
clk[IMX5_CLK_CKO1] = imx_clk_gate2("cko1", "cko1_podf", MXC_CCM_CCOSR, 7);
|
||||
|
||||
clk[IMX5_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", MXC_CCM_CCOSR, 16, 5,
|
||||
mx53_cko2_sel, ARRAY_SIZE(mx53_cko2_sel));
|
||||
clk[IMX5_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", MXC_CCM_CCOSR, 21, 3);
|
||||
clk[IMX5_CLK_CKO2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
/* set SDHC root clock to 200MHZ*/
|
||||
clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 200000000);
|
||||
clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 200000000);
|
||||
|
||||
clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]);
|
||||
imx_print_silicon_rev("i.MX50", IMX_CHIP_REVISION_1_1);
|
||||
clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]);
|
||||
|
||||
r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
|
||||
clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
|
||||
}
|
||||
CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init);
|
||||
|
||||
static void __init mx51_clocks_init(struct device_node *np)
|
||||
{
|
||||
void __iomem *ccm_base;
|
||||
void __iomem *pll_base;
|
||||
u32 val;
|
||||
|
||||
pll_base = ioremap(MX51_DPLL1_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", pll_base);
|
||||
|
||||
pll_base = ioremap(MX51_DPLL2_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", pll_base);
|
||||
|
||||
pll_base = ioremap(MX51_DPLL3_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", pll_base);
|
||||
|
||||
ccm_base = of_iomap(np, 0);
|
||||
WARN_ON(!ccm_base);
|
||||
|
||||
mx5_clocks_common_init(ccm_base);
|
||||
|
||||
clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1,
|
||||
lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
|
||||
clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
|
||||
mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel));
|
||||
clk[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
|
||||
mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel));
|
||||
clk[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1,
|
||||
mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_TVE_SEL] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1,
|
||||
mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel));
|
||||
clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_sel", MXC_CCM_CCGR2, 30);
|
||||
clk[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "pll3_sw", MXC_CCM_CDCDR, 28, 3);
|
||||
clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2);
|
||||
clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 6);
|
||||
clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 10);
|
||||
clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
|
||||
clk[IMX5_CLK_USB_PHY_GATE] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0);
|
||||
clk[IMX5_CLK_HSI2C_GATE] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22);
|
||||
clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6);
|
||||
clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8);
|
||||
clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10);
|
||||
clk[IMX5_CLK_MIPI_HSP_GATE] = imx_clk_gate2("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12);
|
||||
clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2,
|
||||
mx51_spdif_xtal_sel, ARRAY_SIZE(mx51_spdif_xtal_sel));
|
||||
clk[IMX5_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", MXC_CCM_CSCMR2, 2, 2,
|
||||
spdif_sel, ARRAY_SIZE(spdif_sel));
|
||||
clk[IMX5_CLK_SPDIF1_PRED] = imx_clk_divider("spdif1_pred", "spdif1_sel", MXC_CCM_CDCDR, 16, 3);
|
||||
clk[IMX5_CLK_SPDIF1_PODF] = imx_clk_divider("spdif1_podf", "spdif1_pred", MXC_CCM_CDCDR, 9, 6);
|
||||
clk[IMX5_CLK_SPDIF1_COM_SEL] = imx_clk_mux("spdif1_com_sel", MXC_CCM_CSCMR2, 5, 1,
|
||||
mx51_spdif1_com_sel, ARRAY_SIZE(mx51_spdif1_com_sel));
|
||||
clk[IMX5_CLK_SPDIF1_GATE] = imx_clk_gate2("spdif1_gate", "spdif1_com_sel", MXC_CCM_CCGR5, 28);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
/* set the usboh3 parent to pll2_sw */
|
||||
clk_set_parent(clk[IMX5_CLK_USBOH3_SEL], clk[IMX5_CLK_PLL2_SW]);
|
||||
|
||||
/* set SDHC root clock to 166.25MHZ*/
|
||||
clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 166250000);
|
||||
clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 166250000);
|
||||
|
||||
clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]);
|
||||
imx_print_silicon_rev("i.MX51", mx51_revision());
|
||||
clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]);
|
||||
|
||||
/*
|
||||
* Reference Manual says: Functionality of CCDR[18] and CLPCR[23] is no
|
||||
* longer supported. Set to one for better power saving.
|
||||
*
|
||||
* The effect of not setting these bits is that MIPI clocks can't be
|
||||
* enabled without the IPU clock being enabled aswell.
|
||||
*/
|
||||
val = readl(MXC_CCM_CCDR);
|
||||
val |= 1 << 18;
|
||||
writel(val, MXC_CCM_CCDR);
|
||||
|
||||
val = readl(MXC_CCM_CLPCR);
|
||||
val |= 1 << 23;
|
||||
writel(val, MXC_CCM_CLPCR);
|
||||
}
|
||||
CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init);
|
||||
|
||||
static void __init mx53_clocks_init(struct device_node *np)
|
||||
{
|
||||
void __iomem *ccm_base;
|
||||
void __iomem *pll_base;
|
||||
unsigned long r;
|
||||
|
||||
pll_base = ioremap(MX53_DPLL1_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", pll_base);
|
||||
|
||||
pll_base = ioremap(MX53_DPLL2_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", pll_base);
|
||||
|
||||
pll_base = ioremap(MX53_DPLL3_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", pll_base);
|
||||
|
||||
pll_base = ioremap(MX53_DPLL4_BASE, SZ_16K);
|
||||
WARN_ON(!pll_base);
|
||||
clk[IMX5_CLK_PLL4_SW] = imx_clk_pllv2("pll4_sw", "osc", pll_base);
|
||||
|
||||
ccm_base = of_iomap(np, 0);
|
||||
WARN_ON(!ccm_base);
|
||||
|
||||
mx5_clocks_common_init(ccm_base);
|
||||
|
||||
clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 10, 1,
|
||||
lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
|
||||
clk[IMX5_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
|
||||
clk[IMX5_CLK_LDB_DI1_DIV] = imx_clk_divider_flags("ldb_di1_div", "ldb_di1_div_3_5", MXC_CCM_CSCMR2, 11, 1, 0);
|
||||
clk[IMX5_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", MXC_CCM_CSCMR2, 9, 1,
|
||||
mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_DI_PLL4_PODF] = imx_clk_divider("di_pll4_podf", "pll4_sw", MXC_CCM_CDCDR, 16, 3);
|
||||
clk[IMX5_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
|
||||
clk[IMX5_CLK_LDB_DI0_DIV] = imx_clk_divider_flags("ldb_di0_div", "ldb_di0_div_3_5", MXC_CCM_CSCMR2, 10, 1, 0);
|
||||
clk[IMX5_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", MXC_CCM_CSCMR2, 8, 1,
|
||||
mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_LDB_DI0_GATE] = imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28);
|
||||
clk[IMX5_CLK_LDB_DI1_GATE] = imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30);
|
||||
clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
|
||||
mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel));
|
||||
clk[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
|
||||
mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel));
|
||||
clk[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1,
|
||||
mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30);
|
||||
clk[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "tve_ext_sel", MXC_CCM_CDCDR, 28, 3);
|
||||
clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2);
|
||||
clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6);
|
||||
clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10);
|
||||
clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
|
||||
clk[IMX5_CLK_USB_PHY1_GATE] = imx_clk_gate2("usb_phy1_gate", "usb_phy_sel", MXC_CCM_CCGR4, 10);
|
||||
clk[IMX5_CLK_USB_PHY2_GATE] = imx_clk_gate2("usb_phy2_gate", "usb_phy_sel", MXC_CCM_CCGR4, 12);
|
||||
clk[IMX5_CLK_CAN_SEL] = imx_clk_mux("can_sel", MXC_CCM_CSCMR2, 6, 2,
|
||||
mx53_can_sel, ARRAY_SIZE(mx53_can_sel));
|
||||
clk[IMX5_CLK_CAN1_SERIAL_GATE] = imx_clk_gate2("can1_serial_gate", "can_sel", MXC_CCM_CCGR6, 22);
|
||||
clk[IMX5_CLK_CAN1_IPG_GATE] = imx_clk_gate2("can1_ipg_gate", "ipg", MXC_CCM_CCGR6, 20);
|
||||
clk[IMX5_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", MXC_CCM_CCGR6, 2);
|
||||
clk[IMX5_CLK_CAN2_SERIAL_GATE] = imx_clk_gate2("can2_serial_gate", "can_sel", MXC_CCM_CCGR4, 8);
|
||||
clk[IMX5_CLK_CAN2_IPG_GATE] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 6);
|
||||
clk[IMX5_CLK_I2C3_GATE] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22);
|
||||
clk[IMX5_CLK_SATA_GATE] = imx_clk_gate2("sata_gate", "ipg", MXC_CCM_CCGR4, 2);
|
||||
|
||||
clk[IMX5_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", MXC_CCM_CCOSR, 0, 4,
|
||||
mx53_cko1_sel, ARRAY_SIZE(mx53_cko1_sel));
|
||||
clk[IMX5_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", MXC_CCM_CCOSR, 4, 3);
|
||||
clk[IMX5_CLK_CKO1] = imx_clk_gate2("cko1", "cko1_podf", MXC_CCM_CCOSR, 7);
|
||||
|
||||
clk[IMX5_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", MXC_CCM_CCOSR, 16, 5,
|
||||
mx53_cko2_sel, ARRAY_SIZE(mx53_cko2_sel));
|
||||
clk[IMX5_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", MXC_CCM_CCOSR, 21, 3);
|
||||
clk[IMX5_CLK_CKO2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24);
|
||||
clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2,
|
||||
mx53_spdif_xtal_sel, ARRAY_SIZE(mx53_spdif_xtal_sel));
|
||||
clk[IMX5_CLK_ARM] = imx_clk_cpu("arm", "cpu_podf",
|
||||
clk[IMX5_CLK_CPU_PODF],
|
||||
clk[IMX5_CLK_CPU_PODF_SEL],
|
||||
clk[IMX5_CLK_PLL1_SW],
|
||||
clk[IMX5_CLK_STEP_SEL]);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
/* set SDHC root clock to 200MHZ*/
|
||||
clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 200000000);
|
||||
clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 200000000);
|
||||
|
||||
/* move can bus clk to 24MHz */
|
||||
clk_set_parent(clk[IMX5_CLK_CAN_SEL], clk[IMX5_CLK_LP_APM]);
|
||||
|
||||
/* make sure step clock is running from 24MHz */
|
||||
clk_set_parent(clk[IMX5_CLK_STEP_SEL], clk[IMX5_CLK_LP_APM]);
|
||||
|
||||
clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]);
|
||||
imx_print_silicon_rev("i.MX53", mx53_revision());
|
||||
clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]);
|
||||
|
||||
r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
|
||||
clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
|
||||
}
|
||||
CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init);
|
@@ -1,534 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2013 Freescale Semiconductor, Inc.
|
||||
* Copyright 2011 Linaro Ltd.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <dt-bindings/clock/imx6qdl-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
|
||||
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
|
||||
static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
|
||||
static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", };
|
||||
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", };
|
||||
static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
|
||||
static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
|
||||
static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", };
|
||||
static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", };
|
||||
static const char *gpu_axi_sels[] = { "axi", "ahb", };
|
||||
static const char *gpu2d_core_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", };
|
||||
static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd2_396m", };
|
||||
static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll3_pfd0_720m", };
|
||||
static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
|
||||
static const char *ldb_di_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", };
|
||||
static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", };
|
||||
static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
|
||||
static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
|
||||
static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
|
||||
static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
|
||||
static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", };
|
||||
static const char *pcie_axi_sels[] = { "axi", "ahb", };
|
||||
static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", };
|
||||
static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", };
|
||||
static const char *eim_sels[] = { "pll2_pfd2_396m", "pll3_usb_otg", "axi", "pll2_pfd0_352m", };
|
||||
static const char *eim_slow_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *vdo_axi_sels[] = { "axi", "ahb", };
|
||||
static const char *vpu_axi_sels[] = { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",
|
||||
"dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0",
|
||||
"ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio_div", };
|
||||
static const char *cko2_sels[] = {
|
||||
"mmdc_ch0_axi", "mmdc_ch1_axi", "usdhc4", "usdhc1",
|
||||
"gpu2d_axi", "dummy", "ecspi_root", "gpu3d_axi",
|
||||
"usdhc3", "dummy", "arm", "ipu1",
|
||||
"ipu2", "vdo_axi", "osc", "gpu2d_core",
|
||||
"gpu3d_core", "usdhc2", "ssi1", "ssi2",
|
||||
"ssi3", "gpu3d_shader", "vpu_axi", "can_root",
|
||||
"ldb_di0", "ldb_di1", "esai_extal", "eim_slow",
|
||||
"uart_serial", "spdif", "asrc", "hsi_tx",
|
||||
};
|
||||
static const char *cko_sels[] = { "cko1", "cko2", };
|
||||
static const char *lvds_sels[] = {
|
||||
"dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
|
||||
"pll4_audio", "pll5_video", "pll8_mlb", "enet_ref",
|
||||
"pcie_ref_125m", "sata_ref_100m",
|
||||
};
|
||||
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
|
||||
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
|
||||
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
|
||||
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
|
||||
static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
|
||||
static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
|
||||
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
|
||||
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
|
||||
|
||||
static struct clk *clk[IMX6QDL_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static unsigned int const clks_init_on[] __initconst = {
|
||||
IMX6QDL_CLK_MMDC_CH0_AXI,
|
||||
IMX6QDL_CLK_ROM,
|
||||
IMX6QDL_CLK_ARM,
|
||||
};
|
||||
|
||||
static struct clk_div_table clk_enet_ref_table[] = {
|
||||
{ .val = 0, .div = 20, },
|
||||
{ .val = 1, .div = 10, },
|
||||
{ .val = 2, .div = 5, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 0, .div = 4, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct clk_div_table video_div_table[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static unsigned int share_count_esai;
|
||||
static unsigned int share_count_asrc;
|
||||
static unsigned int share_count_ssi1;
|
||||
static unsigned int share_count_ssi2;
|
||||
static unsigned int share_count_ssi3;
|
||||
static unsigned int share_count_mipi_core_cfg;
|
||||
|
||||
static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *base;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
|
||||
clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
|
||||
clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
|
||||
/* Clock source from external clock via CLK1/2 PADs */
|
||||
clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
|
||||
clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
|
||||
if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
|
||||
post_div_table[1].div = 1;
|
||||
post_div_table[2].div = 1;
|
||||
video_div_table[1].div = 1;
|
||||
video_div_table[3].div = 1;
|
||||
}
|
||||
|
||||
clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
|
||||
/* type name parent_name base div_mask */
|
||||
clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
|
||||
clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
|
||||
clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
|
||||
clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
|
||||
clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
|
||||
clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
|
||||
clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
|
||||
|
||||
clk[IMX6QDL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
|
||||
/* Do not bypass PLLs initially */
|
||||
clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]);
|
||||
clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]);
|
||||
clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]);
|
||||
clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]);
|
||||
clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]);
|
||||
clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]);
|
||||
clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]);
|
||||
|
||||
clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
|
||||
clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
|
||||
clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
|
||||
clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
|
||||
clk[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
|
||||
clk[IMX6QDL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
|
||||
clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
|
||||
|
||||
/*
|
||||
* Bit 20 is the reserved and read-only bit, we do this only for:
|
||||
* - Do nothing for usbphy clk_enable/disable
|
||||
* - Keep refcount when do usbphy clk_enable/disable, in that case,
|
||||
* the clk framework may need to enable/disable usbphy's parent
|
||||
*/
|
||||
clk[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
|
||||
clk[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
|
||||
|
||||
/*
|
||||
* usbphy*_gate needs to be on after system boots up, and software
|
||||
* never needs to control it anymore.
|
||||
*/
|
||||
clk[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
|
||||
clk[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
|
||||
|
||||
clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
|
||||
clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
|
||||
|
||||
clk[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
|
||||
clk[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
|
||||
|
||||
clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
|
||||
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
|
||||
&imx_ccm_lock);
|
||||
|
||||
clk[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
|
||||
clk[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
|
||||
|
||||
/*
|
||||
* lvds1_gate and lvds2_gate are pseudo-gates. Both can be
|
||||
* independently configured as clock inputs or outputs. We treat
|
||||
* the "output_enable" bit as a gate, even though it's really just
|
||||
* enabling clock output.
|
||||
*/
|
||||
clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
|
||||
clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
|
||||
|
||||
clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
|
||||
clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
|
||||
|
||||
/* name parent_name reg idx */
|
||||
clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
|
||||
clk[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
|
||||
clk[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
|
||||
clk[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
|
||||
clk[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
|
||||
clk[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
|
||||
clk[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
|
||||
|
||||
/* name parent_name mult div */
|
||||
clk[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
|
||||
clk[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
|
||||
clk[IMX6QDL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
|
||||
clk[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
|
||||
clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
|
||||
clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
|
||||
clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
|
||||
if (cpu_is_imx6dl()) {
|
||||
clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
|
||||
clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
|
||||
}
|
||||
|
||||
clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
|
||||
clk[IMX6QDL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
|
||||
|
||||
np = ccm_node;
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
imx6q_pm_set_ccm_base(base);
|
||||
|
||||
/* name reg shift width parent_names num_parents */
|
||||
clk[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
|
||||
clk[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
|
||||
clk[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
|
||||
clk[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
|
||||
clk[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
|
||||
clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
|
||||
clk[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels));
|
||||
clk[IMX6QDL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clk[IMX6QDL_CLK_ASRC_SEL] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clk[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
if (cpu_is_imx6q()) {
|
||||
clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
|
||||
clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
|
||||
}
|
||||
clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels));
|
||||
clk[IMX6QDL_CLK_GPU3D_CORE_SEL] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels));
|
||||
clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
|
||||
clk[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
|
||||
clk[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
|
||||
clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_mux_flags("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_mux_flags("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_mux_flags("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_mux_flags("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT);
|
||||
clk[IMX6QDL_CLK_HSI_TX_SEL] = imx_clk_mux("hsi_tx_sel", base + 0x30, 28, 1, hsi_tx_sels, ARRAY_SIZE(hsi_tx_sels));
|
||||
clk[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
|
||||
clk[IMX6QDL_CLK_SSI1_SEL] = imx_clk_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_SSI2_SEL] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_SSI3_SEL] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels));
|
||||
clk[IMX6QDL_CLK_EIM_SEL] = imx_clk_fixup_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_fixup_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels), imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels));
|
||||
clk[IMX6QDL_CLK_VPU_AXI_SEL] = imx_clk_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels));
|
||||
clk[IMX6QDL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
|
||||
clk[IMX6QDL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
|
||||
clk[IMX6QDL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
|
||||
|
||||
/* name reg shift width busy: reg, shift parent_names num_parents */
|
||||
clk[IMX6QDL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
|
||||
clk[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
|
||||
|
||||
/* name parent_name reg shift width */
|
||||
clk[IMX6QDL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
|
||||
clk[IMX6QDL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
|
||||
clk[IMX6QDL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
|
||||
clk[IMX6QDL_CLK_IPG_PER] = imx_clk_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
|
||||
clk[IMX6QDL_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
|
||||
clk[IMX6QDL_CLK_ASRC_PRED] = imx_clk_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3);
|
||||
clk[IMX6QDL_CLK_ASRC_PODF] = imx_clk_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3);
|
||||
clk[IMX6QDL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
|
||||
clk[IMX6QDL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
|
||||
clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
|
||||
clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
|
||||
clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3);
|
||||
clk[IMX6QDL_CLK_GPU3D_CORE_PODF] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3);
|
||||
clk[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3);
|
||||
clk[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3);
|
||||
clk[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3);
|
||||
clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
|
||||
clk[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);
|
||||
clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
|
||||
clk[IMX6QDL_CLK_LDB_DI1_PODF] = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);
|
||||
clk[IMX6QDL_CLK_IPU1_DI0_PRE] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3);
|
||||
clk[IMX6QDL_CLK_IPU1_DI1_PRE] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3);
|
||||
clk[IMX6QDL_CLK_IPU2_DI0_PRE] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3);
|
||||
clk[IMX6QDL_CLK_IPU2_DI1_PRE] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", base + 0x38, 12, 3);
|
||||
clk[IMX6QDL_CLK_HSI_TX_PODF] = imx_clk_divider("hsi_tx_podf", "hsi_tx_sel", base + 0x30, 29, 3);
|
||||
clk[IMX6QDL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
|
||||
clk[IMX6QDL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
|
||||
clk[IMX6QDL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
|
||||
clk[IMX6QDL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
|
||||
clk[IMX6QDL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
|
||||
clk[IMX6QDL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
|
||||
clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6);
|
||||
clk[IMX6QDL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
|
||||
clk[IMX6QDL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
|
||||
clk[IMX6QDL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
|
||||
clk[IMX6QDL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
|
||||
clk[IMX6QDL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
|
||||
clk[IMX6QDL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
|
||||
clk[IMX6QDL_CLK_EIM_PODF] = imx_clk_fixup_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3, imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_fixup_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3, imx_cscmr1_fixup);
|
||||
clk[IMX6QDL_CLK_VPU_AXI_PODF] = imx_clk_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3);
|
||||
clk[IMX6QDL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
|
||||
clk[IMX6QDL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
|
||||
|
||||
/* name parent_name reg shift width busy: reg, shift */
|
||||
clk[IMX6QDL_CLK_AXI] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
|
||||
clk[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4);
|
||||
clk[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
|
||||
clk[IMX6QDL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
|
||||
clk[IMX6QDL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
|
||||
|
||||
/* name parent_name reg shift */
|
||||
clk[IMX6QDL_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
|
||||
clk[IMX6QDL_CLK_ASRC] = imx_clk_gate2_shared("asrc", "asrc_podf", base + 0x68, 6, &share_count_asrc);
|
||||
clk[IMX6QDL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
|
||||
clk[IMX6QDL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
|
||||
clk[IMX6QDL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
|
||||
clk[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16);
|
||||
clk[IMX6QDL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
|
||||
clk[IMX6QDL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20);
|
||||
clk[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
|
||||
clk[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
|
||||
clk[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
|
||||
clk[IMX6QDL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
|
||||
if (cpu_is_imx6dl())
|
||||
clk[IMX6DL_CLK_I2C4] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8);
|
||||
else
|
||||
clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8);
|
||||
clk[IMX6QDL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10);
|
||||
clk[IMX6QDL_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
|
||||
clk[IMX6QDL_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
|
||||
clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
|
||||
clk[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20);
|
||||
clk[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22);
|
||||
if (cpu_is_imx6dl())
|
||||
/*
|
||||
* The multiplexer and divider of imx6q clock gpu3d_shader get
|
||||
* redefined/reused as gpu2d_core_sel and gpu2d_core_podf on imx6dl.
|
||||
*/
|
||||
clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu3d_shader", base + 0x6c, 24);
|
||||
else
|
||||
clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
|
||||
clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26);
|
||||
clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0);
|
||||
clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4);
|
||||
clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6);
|
||||
clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8);
|
||||
clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10);
|
||||
clk[IMX6QDL_CLK_IIM] = imx_clk_gate2("iim", "ipg", base + 0x70, 12);
|
||||
clk[IMX6QDL_CLK_ENFC] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14);
|
||||
clk[IMX6QDL_CLK_VDOA] = imx_clk_gate2("vdoa", "vdo_axi", base + 0x70, 26);
|
||||
clk[IMX6QDL_CLK_IPU1] = imx_clk_gate2("ipu1", "ipu1_podf", base + 0x74, 0);
|
||||
clk[IMX6QDL_CLK_IPU1_DI0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", base + 0x74, 2);
|
||||
clk[IMX6QDL_CLK_IPU1_DI1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", base + 0x74, 4);
|
||||
clk[IMX6QDL_CLK_IPU2] = imx_clk_gate2("ipu2", "ipu2_podf", base + 0x74, 6);
|
||||
clk[IMX6QDL_CLK_IPU2_DI0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", base + 0x74, 8);
|
||||
clk[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12);
|
||||
clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14);
|
||||
clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10);
|
||||
clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg);
|
||||
clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
|
||||
clk[IMX6QDL_CLK_MIPI_IPG] = imx_clk_gate2_shared("mipi_ipg", "ipg", base + 0x74, 16, &share_count_mipi_core_cfg);
|
||||
if (cpu_is_imx6dl())
|
||||
/*
|
||||
* The multiplexer and divider of the imx6q clock gpu2d get
|
||||
* redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl.
|
||||
*/
|
||||
clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "gpu2d_core_podf", base + 0x74, 18);
|
||||
else
|
||||
clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18);
|
||||
clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20);
|
||||
clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22);
|
||||
clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28);
|
||||
clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30);
|
||||
clk[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0);
|
||||
clk[IMX6QDL_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12);
|
||||
clk[IMX6QDL_CLK_PWM1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16);
|
||||
clk[IMX6QDL_CLK_PWM2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18);
|
||||
clk[IMX6QDL_CLK_PWM3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20);
|
||||
clk[IMX6QDL_CLK_PWM4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22);
|
||||
clk[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
|
||||
clk[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
|
||||
clk[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28);
|
||||
clk[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
|
||||
clk[IMX6QDL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
|
||||
clk[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4);
|
||||
clk[IMX6QDL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
|
||||
clk[IMX6QDL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
|
||||
clk[IMX6QDL_CLK_SPDIF] = imx_clk_gate2("spdif", "spdif_podf", base + 0x7c, 14);
|
||||
clk[IMX6QDL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
|
||||
clk[IMX6QDL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
|
||||
clk[IMX6QDL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
|
||||
clk[IMX6QDL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
|
||||
clk[IMX6QDL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
|
||||
clk[IMX6QDL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
|
||||
clk[IMX6QDL_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24);
|
||||
clk[IMX6QDL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26);
|
||||
clk[IMX6QDL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
|
||||
clk[IMX6QDL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
|
||||
clk[IMX6QDL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
|
||||
clk[IMX6QDL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
|
||||
clk[IMX6QDL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
|
||||
clk[IMX6QDL_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
|
||||
clk[IMX6QDL_CLK_VDO_AXI] = imx_clk_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12);
|
||||
clk[IMX6QDL_CLK_VPU_AXI] = imx_clk_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14);
|
||||
clk[IMX6QDL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
|
||||
clk[IMX6QDL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
|
||||
|
||||
/*
|
||||
* The gpt_3m clock is not available on i.MX6Q TO1.0. Let's point it
|
||||
* to clock gpt_ipg_per to ease the gpt driver code.
|
||||
*/
|
||||
if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
|
||||
clk[IMX6QDL_CLK_GPT_3M] = clk[IMX6QDL_CLK_GPT_IPG_PER];
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
|
||||
|
||||
if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) ||
|
||||
cpu_is_imx6dl()) {
|
||||
clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
}
|
||||
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_SEL], clk[IMX6QDL_CLK_IPU1_DI0_PRE]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_SEL], clk[IMX6QDL_CLK_IPU1_DI1_PRE]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_SEL], clk[IMX6QDL_CLK_IPU2_DI0_PRE]);
|
||||
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_SEL], clk[IMX6QDL_CLK_IPU2_DI1_PRE]);
|
||||
|
||||
/*
|
||||
* The gpmi needs 100MHz frequency in the EDO/Sync mode,
|
||||
* We can not get the 100MHz from the pll2_pfd0_352m.
|
||||
* So choose pll2_pfd2_396m as enfc_sel's parent.
|
||||
*/
|
||||
clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||
clk_prepare_enable(clk[clks_init_on[i]]);
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
|
||||
clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]);
|
||||
clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's initially set up CLKO with OSC24M, since this configuration
|
||||
* is widely used by imx6q board designs to clock audio codec.
|
||||
*/
|
||||
ret = clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]);
|
||||
if (!ret)
|
||||
ret = clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]);
|
||||
if (ret)
|
||||
pr_warn("failed to set up CLKO: %d\n", ret);
|
||||
|
||||
/* Audio-related clocks configuration */
|
||||
clk_set_parent(clk[IMX6QDL_CLK_SPDIF_SEL], clk[IMX6QDL_CLK_PLL3_PFD3_454M]);
|
||||
|
||||
/* All existing boards with PCIe use LVDS1 */
|
||||
if (IS_ENABLED(CONFIG_PCI_IMX6))
|
||||
clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
|
||||
|
||||
/* Set initial power mode */
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
}
|
||||
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
|
@@ -1,450 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-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/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <dt-bindings/clock/imx6sl-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
|
||||
#define CCSR 0xc
|
||||
#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
|
||||
#define CACRR 0x10
|
||||
#define CDHIPR 0x48
|
||||
#define BM_CDHIPR_ARM_PODF_BUSY (1 << 16)
|
||||
#define ARM_WAIT_DIV_396M 2
|
||||
#define ARM_WAIT_DIV_792M 4
|
||||
#define ARM_WAIT_DIV_996M 6
|
||||
|
||||
#define PLL_ARM 0x0
|
||||
#define BM_PLL_ARM_DIV_SELECT (0x7f << 0)
|
||||
#define BM_PLL_ARM_POWERDOWN (1 << 12)
|
||||
#define BM_PLL_ARM_ENABLE (1 << 13)
|
||||
#define BM_PLL_ARM_LOCK (1 << 31)
|
||||
#define PLL_ARM_DIV_792M 66
|
||||
|
||||
static const char *step_sels[] = { "osc", "pll2_pfd2", };
|
||||
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
|
||||
static const char *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", };
|
||||
static const char *ocram_sels[] = { "periph", "ocram_alt_sels", };
|
||||
static const char *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", };
|
||||
static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", };
|
||||
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", };
|
||||
static const char *periph_sels[] = { "pre_periph_sel", "periph_clk2_podf", };
|
||||
static const char *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", };
|
||||
static const char *csi_sels[] = { "osc", "pll2_pfd2", "pll3_120m", "pll3_pfd1", };
|
||||
static const char *lcdif_axi_sels[] = { "pll2_bus", "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", };
|
||||
static const char *usdhc_sels[] = { "pll2_pfd2", "pll2_pfd0", };
|
||||
static const char *ssi_sels[] = { "pll3_pfd2", "pll3_pfd3", "pll4_audio_div", "dummy", };
|
||||
static const char *perclk_sels[] = { "ipg", "osc", };
|
||||
static const char *pxp_axi_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd3", };
|
||||
static const char *epdc_axi_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd2", };
|
||||
static const char *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", };
|
||||
static const char *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", };
|
||||
static const char *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", };
|
||||
static const char *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", };
|
||||
static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", };
|
||||
static const char *ecspi_sels[] = { "pll3_60m", "osc", };
|
||||
static const char *uart_sels[] = { "pll3_80m", "osc", };
|
||||
static const char *lvds_sels[] = {
|
||||
"pll1_sys", "pll2_bus", "pll2_pfd0", "pll2_pfd1", "pll2_pfd2", "dummy", "pll4_audio", "pll5_video",
|
||||
"dummy", "enet_ref", "dummy", "dummy", "pll3_usb_otg", "pll7_usb_host", "pll3_pfd0", "pll3_pfd1",
|
||||
"pll3_pfd2", "pll3_pfd3", "osc", "dummy", "dummy", "dummy", "dummy", "dummy",
|
||||
"dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
|
||||
};
|
||||
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", };
|
||||
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
|
||||
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
|
||||
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
|
||||
static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
|
||||
static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
|
||||
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
|
||||
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
|
||||
|
||||
static struct clk_div_table clk_enet_ref_table[] = {
|
||||
{ .val = 0, .div = 20, },
|
||||
{ .val = 1, .div = 10, },
|
||||
{ .val = 2, .div = 5, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 0, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table video_div_table[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static unsigned int share_count_ssi1;
|
||||
static unsigned int share_count_ssi2;
|
||||
static unsigned int share_count_ssi3;
|
||||
|
||||
static struct clk *clks[IMX6SL_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
static void __iomem *ccm_base;
|
||||
static void __iomem *anatop_base;
|
||||
|
||||
static const u32 clks_init_on[] __initconst = {
|
||||
IMX6SL_CLK_IPG, IMX6SL_CLK_ARM, IMX6SL_CLK_MMDC_ROOT,
|
||||
};
|
||||
|
||||
/*
|
||||
* ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken
|
||||
* during WAIT mode entry process could cause cache memory
|
||||
* corruption.
|
||||
*
|
||||
* Software workaround:
|
||||
* To prevent this issue from occurring, software should ensure that the
|
||||
* ARM to IPG clock ratio is less than 12:5 (that is < 2.4x), before
|
||||
* entering WAIT mode.
|
||||
*
|
||||
* This function will set the ARM clk to max value within the 12:5 limit.
|
||||
* As IPG clock is fixed at 66MHz(so ARM freq must not exceed 158.4MHz),
|
||||
* ARM freq are one of below setpoints: 396MHz, 792MHz and 996MHz, since
|
||||
* the clk APIs can NOT be called in idle thread(may cause kernel schedule
|
||||
* as there is sleep function in PLL wait function), so here we just slow
|
||||
* down ARM to below freq according to previous freq:
|
||||
*
|
||||
* run mode wait mode
|
||||
* 396MHz -> 132MHz;
|
||||
* 792MHz -> 158.4MHz;
|
||||
* 996MHz -> 142.3MHz;
|
||||
*/
|
||||
static int imx6sl_get_arm_divider_for_wait(void)
|
||||
{
|
||||
if (readl_relaxed(ccm_base + CCSR) & BM_CCSR_PLL1_SW_CLK_SEL) {
|
||||
return ARM_WAIT_DIV_396M;
|
||||
} else {
|
||||
if ((readl_relaxed(anatop_base + PLL_ARM) &
|
||||
BM_PLL_ARM_DIV_SELECT) == PLL_ARM_DIV_792M)
|
||||
return ARM_WAIT_DIV_792M;
|
||||
else
|
||||
return ARM_WAIT_DIV_996M;
|
||||
}
|
||||
}
|
||||
|
||||
static void imx6sl_enable_pll_arm(bool enable)
|
||||
{
|
||||
static u32 saved_pll_arm;
|
||||
u32 val;
|
||||
|
||||
if (enable) {
|
||||
saved_pll_arm = val = readl_relaxed(anatop_base + PLL_ARM);
|
||||
val |= BM_PLL_ARM_ENABLE;
|
||||
val &= ~BM_PLL_ARM_POWERDOWN;
|
||||
writel_relaxed(val, anatop_base + PLL_ARM);
|
||||
while (!(__raw_readl(anatop_base + PLL_ARM) & BM_PLL_ARM_LOCK))
|
||||
;
|
||||
} else {
|
||||
writel_relaxed(saved_pll_arm, anatop_base + PLL_ARM);
|
||||
}
|
||||
}
|
||||
|
||||
void imx6sl_set_wait_clk(bool enter)
|
||||
{
|
||||
static unsigned long saved_arm_div;
|
||||
int arm_div_for_wait = imx6sl_get_arm_divider_for_wait();
|
||||
|
||||
/*
|
||||
* According to hardware design, arm podf change need
|
||||
* PLL1 clock enabled.
|
||||
*/
|
||||
if (arm_div_for_wait == ARM_WAIT_DIV_396M)
|
||||
imx6sl_enable_pll_arm(true);
|
||||
|
||||
if (enter) {
|
||||
saved_arm_div = readl_relaxed(ccm_base + CACRR);
|
||||
writel_relaxed(arm_div_for_wait, ccm_base + CACRR);
|
||||
} else {
|
||||
writel_relaxed(saved_arm_div, ccm_base + CACRR);
|
||||
}
|
||||
while (__raw_readl(ccm_base + CDHIPR) & BM_CDHIPR_ARM_PODF_BUSY)
|
||||
;
|
||||
|
||||
if (arm_div_for_wait == ARM_WAIT_DIV_396M)
|
||||
imx6sl_enable_pll_arm(false);
|
||||
}
|
||||
|
||||
static void __init imx6sl_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *base;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
|
||||
clks[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
|
||||
/* Clock source from external clock via CLK1 PAD */
|
||||
clks[IMX6SL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
anatop_base = base;
|
||||
|
||||
clks[IMX6SL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
|
||||
/* type name parent_name base div_mask */
|
||||
clks[IMX6SL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
|
||||
clks[IMX6SL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
|
||||
clks[IMX6SL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
|
||||
clks[IMX6SL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
|
||||
clks[IMX6SL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
|
||||
clks[IMX6SL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
|
||||
clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
|
||||
|
||||
clks[IMX6SL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
|
||||
/* Do not bypass PLLs initially */
|
||||
clk_set_parent(clks[IMX6SL_PLL1_BYPASS], clks[IMX6SL_CLK_PLL1]);
|
||||
clk_set_parent(clks[IMX6SL_PLL2_BYPASS], clks[IMX6SL_CLK_PLL2]);
|
||||
clk_set_parent(clks[IMX6SL_PLL3_BYPASS], clks[IMX6SL_CLK_PLL3]);
|
||||
clk_set_parent(clks[IMX6SL_PLL4_BYPASS], clks[IMX6SL_CLK_PLL4]);
|
||||
clk_set_parent(clks[IMX6SL_PLL5_BYPASS], clks[IMX6SL_CLK_PLL5]);
|
||||
clk_set_parent(clks[IMX6SL_PLL6_BYPASS], clks[IMX6SL_CLK_PLL6]);
|
||||
clk_set_parent(clks[IMX6SL_PLL7_BYPASS], clks[IMX6SL_CLK_PLL7]);
|
||||
|
||||
clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
|
||||
clks[IMX6SL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
|
||||
clks[IMX6SL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
|
||||
clks[IMX6SL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
|
||||
clks[IMX6SL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
|
||||
clks[IMX6SL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
|
||||
clks[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
|
||||
|
||||
clks[IMX6SL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
|
||||
clks[IMX6SL_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
|
||||
clks[IMX6SL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
|
||||
|
||||
/*
|
||||
* usbphy1 and usbphy2 are implemented as dummy gates using reserve
|
||||
* bit 20. They are used by phy driver to keep the refcount of
|
||||
* parent PLL correct. usbphy1_gate and usbphy2_gate only needs to be
|
||||
* turned on during boot, and software will not need to control it
|
||||
* anymore after that.
|
||||
*/
|
||||
clks[IMX6SL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
|
||||
clks[IMX6SL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
|
||||
clks[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
|
||||
clks[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
|
||||
|
||||
/* dev name parent_name flags reg shift width div: flags, div_table lock */
|
||||
clks[IMX6SL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clks[IMX6SL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
|
||||
clks[IMX6SL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
|
||||
clks[IMX6SL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
|
||||
|
||||
/* name parent_name reg idx */
|
||||
clks[IMX6SL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0", "pll2_bus", base + 0x100, 0);
|
||||
clks[IMX6SL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus", base + 0x100, 1);
|
||||
clks[IMX6SL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus", base + 0x100, 2);
|
||||
clks[IMX6SL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0, 0);
|
||||
clks[IMX6SL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0, 1);
|
||||
clks[IMX6SL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0, 2);
|
||||
clks[IMX6SL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0, 3);
|
||||
|
||||
/* name parent_name mult div */
|
||||
clks[IMX6SL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2", 1, 2);
|
||||
clks[IMX6SL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
|
||||
clks[IMX6SL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
|
||||
clks[IMX6SL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
|
||||
|
||||
np = ccm_node;
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
ccm_base = base;
|
||||
|
||||
/* Reuse imx6q pm code */
|
||||
imx6q_pm_set_ccm_base(base);
|
||||
|
||||
/* name reg shift width parent_names num_parents */
|
||||
clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
|
||||
clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
|
||||
clks[IMX6SL_CLK_OCRAM_ALT_SEL] = imx_clk_mux("ocram_alt_sel", base + 0x14, 7, 1, ocram_alt_sels, ARRAY_SIZE(ocram_alt_sels));
|
||||
clks[IMX6SL_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels));
|
||||
clks[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_mux("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
|
||||
clks[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
|
||||
clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
|
||||
clks[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
|
||||
clks[IMX6SL_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
|
||||
clks[IMX6SL_CLK_LCDIF_AXI_SEL] = imx_clk_mux("lcdif_axi_sel", base + 0x3c, 14, 2, lcdif_axi_sels, ARRAY_SIZE(lcdif_axi_sels));
|
||||
clks[IMX6SL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_USDHC2_SEL] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_USDHC3_SEL] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_USDHC4_SEL] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_SSI1_SEL] = imx_clk_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_SSI2_SEL] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_SSI3_SEL] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_PERCLK_SEL] = imx_clk_fixup_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_PXP_AXI_SEL] = imx_clk_mux("pxp_axi_sel", base + 0x34, 6, 3, pxp_axi_sels, ARRAY_SIZE(pxp_axi_sels));
|
||||
clks[IMX6SL_CLK_EPDC_AXI_SEL] = imx_clk_mux("epdc_axi_sel", base + 0x34, 15, 3, epdc_axi_sels, ARRAY_SIZE(epdc_axi_sels));
|
||||
clks[IMX6SL_CLK_GPU2D_OVG_SEL] = imx_clk_mux("gpu2d_ovg_sel", base + 0x18, 4, 2, gpu2d_ovg_sels, ARRAY_SIZE(gpu2d_ovg_sels));
|
||||
clks[IMX6SL_CLK_GPU2D_SEL] = imx_clk_mux("gpu2d_sel", base + 0x18, 8, 2, gpu2d_sels, ARRAY_SIZE(gpu2d_sels));
|
||||
clks[IMX6SL_CLK_LCDIF_PIX_SEL] = imx_clk_mux("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels));
|
||||
clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels));
|
||||
clks[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clks[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clks[IMX6SL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
|
||||
clks[IMX6SL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
|
||||
|
||||
/* name reg shift width busy: reg, shift parent_names num_parents */
|
||||
clks[IMX6SL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
|
||||
clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
|
||||
|
||||
/* name parent_name reg shift width */
|
||||
clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3);
|
||||
clks[IMX6SL_CLK_PERIPH_CLK2_PODF] = imx_clk_divider("periph_clk2_podf", "periph_clk2_sel", base + 0x14, 27, 3);
|
||||
clks[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_divider("periph2_clk2_podf", "periph2_clk2_sel", base + 0x14, 0, 3);
|
||||
clks[IMX6SL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
|
||||
clks[IMX6SL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
|
||||
clks[IMX6SL_CLK_LCDIF_AXI_PODF] = imx_clk_divider("lcdif_axi_podf", "lcdif_axi_sel", base + 0x3c, 16, 3);
|
||||
clks[IMX6SL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
|
||||
clks[IMX6SL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
|
||||
clks[IMX6SL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
|
||||
clks[IMX6SL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
|
||||
clks[IMX6SL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
|
||||
clks[IMX6SL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
|
||||
clks[IMX6SL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
|
||||
clks[IMX6SL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
|
||||
clks[IMX6SL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
|
||||
clks[IMX6SL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
|
||||
clks[IMX6SL_CLK_PERCLK] = imx_clk_fixup_divider("perclk", "perclk_sel", base + 0x1c, 0, 6, imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_PXP_AXI_PODF] = imx_clk_divider("pxp_axi_podf", "pxp_axi_sel", base + 0x34, 3, 3);
|
||||
clks[IMX6SL_CLK_EPDC_AXI_PODF] = imx_clk_divider("epdc_axi_podf", "epdc_axi_sel", base + 0x34, 12, 3);
|
||||
clks[IMX6SL_CLK_GPU2D_OVG_PODF] = imx_clk_divider("gpu2d_ovg_podf", "gpu2d_ovg_sel", base + 0x18, 26, 3);
|
||||
clks[IMX6SL_CLK_GPU2D_PODF] = imx_clk_divider("gpu2d_podf", "gpu2d_sel", base + 0x18, 29, 3);
|
||||
clks[IMX6SL_CLK_LCDIF_PIX_PRED] = imx_clk_divider("lcdif_pix_pred", "lcdif_pix_sel", base + 0x38, 3, 3);
|
||||
clks[IMX6SL_CLK_EPDC_PIX_PRED] = imx_clk_divider("epdc_pix_pred", "epdc_pix_sel", base + 0x38, 12, 3);
|
||||
clks[IMX6SL_CLK_LCDIF_PIX_PODF] = imx_clk_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup);
|
||||
clks[IMX6SL_CLK_EPDC_PIX_PODF] = imx_clk_divider("epdc_pix_podf", "epdc_pix_pred", base + 0x18, 23, 3);
|
||||
clks[IMX6SL_CLK_SPDIF0_PRED] = imx_clk_divider("spdif0_pred", "spdif0_sel", base + 0x30, 25, 3);
|
||||
clks[IMX6SL_CLK_SPDIF0_PODF] = imx_clk_divider("spdif0_podf", "spdif0_pred", base + 0x30, 22, 3);
|
||||
clks[IMX6SL_CLK_SPDIF1_PRED] = imx_clk_divider("spdif1_pred", "spdif1_sel", base + 0x30, 12, 3);
|
||||
clks[IMX6SL_CLK_SPDIF1_PODF] = imx_clk_divider("spdif1_podf", "spdif1_pred", base + 0x30, 9, 3);
|
||||
clks[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel", base + 0x28, 9, 3);
|
||||
clks[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3);
|
||||
clks[IMX6SL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6);
|
||||
clks[IMX6SL_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_sel", base + 0x24, 0, 6);
|
||||
|
||||
/* name parent_name reg shift width busy: reg, shift */
|
||||
clks[IMX6SL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
|
||||
clks[IMX6SL_CLK_MMDC_ROOT] = imx_clk_busy_divider("mmdc", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
|
||||
clks[IMX6SL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
|
||||
|
||||
/* name parent_name reg shift */
|
||||
clks[IMX6SL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
|
||||
clks[IMX6SL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
|
||||
clks[IMX6SL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
|
||||
clks[IMX6SL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
|
||||
clks[IMX6SL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10);
|
||||
clks[IMX6SL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
|
||||
clks[IMX6SL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
|
||||
clks[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16);
|
||||
clks[IMX6SL_CLK_GPT] = imx_clk_gate2("gpt", "perclk", base + 0x6c, 20);
|
||||
clks[IMX6SL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22);
|
||||
clks[IMX6SL_CLK_GPU2D_OVG] = imx_clk_gate2("gpu2d_ovg", "gpu2d_ovg_podf", base + 0x6c, 26);
|
||||
clks[IMX6SL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
|
||||
clks[IMX6SL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
|
||||
clks[IMX6SL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
|
||||
clks[IMX6SL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
|
||||
clks[IMX6SL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x74, 0);
|
||||
clks[IMX6SL_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "pxp_axi_podf", base + 0x74, 2);
|
||||
clks[IMX6SL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_axi", "epdc_axi_podf", base + 0x74, 4);
|
||||
clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6);
|
||||
clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8);
|
||||
clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10);
|
||||
clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
|
||||
clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
|
||||
clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
|
||||
clks[IMX6SL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
|
||||
clks[IMX6SL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
|
||||
clks[IMX6SL_CLK_SDMA] = imx_clk_gate2("sdma", "ipg", base + 0x7c, 6);
|
||||
clks[IMX6SL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
|
||||
clks[IMX6SL_CLK_SPDIF] = imx_clk_gate2("spdif", "spdif0_podf", base + 0x7c, 14);
|
||||
clks[IMX6SL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
|
||||
clks[IMX6SL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
|
||||
clks[IMX6SL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
|
||||
clks[IMX6SL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
|
||||
clks[IMX6SL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
|
||||
clks[IMX6SL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
|
||||
clks[IMX6SL_CLK_UART] = imx_clk_gate2("uart", "ipg", base + 0x7c, 24);
|
||||
clks[IMX6SL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_root", base + 0x7c, 26);
|
||||
clks[IMX6SL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
|
||||
clks[IMX6SL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
|
||||
clks[IMX6SL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
|
||||
clks[IMX6SL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
|
||||
clks[IMX6SL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
|
||||
|
||||
imx_check_clocks(clks, ARRAY_SIZE(clks));
|
||||
|
||||
clk_data.clks = clks;
|
||||
clk_data.clk_num = ARRAY_SIZE(clks);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
/* Ensure the AHB clk is at 132MHz. */
|
||||
ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000);
|
||||
if (ret)
|
||||
pr_warn("%s: failed to set AHB clock rate %d!\n",
|
||||
__func__, ret);
|
||||
|
||||
/*
|
||||
* Make sure those always on clocks are enabled to maintain the correct
|
||||
* usecount and enabling/disabling of parent PLLs.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||
clk_prepare_enable(clks[clks_init_on[i]]);
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
|
||||
clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]);
|
||||
clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]);
|
||||
}
|
||||
|
||||
/* Audio-related clocks configuration */
|
||||
clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
|
||||
|
||||
/* set PLL5 video as lcdif pix parent clock */
|
||||
clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL],
|
||||
clks[IMX6SL_CLK_PLL5_VIDEO_DIV]);
|
||||
|
||||
clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL],
|
||||
clks[IMX6SL_CLK_PLL2_PFD2]);
|
||||
|
||||
/* Set initial power mode */
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
}
|
||||
CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
|
@@ -1,567 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <dt-bindings/clock/imx6sx-clock.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
|
||||
#define CCDR 0x4
|
||||
#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
|
||||
|
||||
static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
|
||||
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
|
||||
static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
|
||||
static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", };
|
||||
static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", };
|
||||
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
|
||||
static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
|
||||
static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
|
||||
static const char *ocram_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", };
|
||||
static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", };
|
||||
static const char *gpu_axi_sels[] = { "pll2_pfd2_396m", "pll3_pfd0_720m", "pll3_pfd1_540m", "pll2_bus", };
|
||||
static const char *gpu_core_sels[] = { "pll3_pfd1_540m", "pll3_pfd0_720m", "pll2_bus", "pll2_pfd2_396m", };
|
||||
static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
|
||||
static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
|
||||
static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", };
|
||||
static const char *ldb_di1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", };
|
||||
static const char *pcie_axi_sels[] = { "axi", "ahb", };
|
||||
static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll5_video_div", "pll4_audio_div", };
|
||||
static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", };
|
||||
static const char *perclk_sels[] = { "ipg", "osc", };
|
||||
static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *vid_sels[] = { "pll3_pfd1_540m", "pll3_usb_otg", "pll3_pfd3_454m", "pll4_audio_div", "pll5_video_div", };
|
||||
static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", "dummy", };
|
||||
static const char *uart_sels[] = { "pll3_80m", "osc", };
|
||||
static const char *qspi2_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", };
|
||||
static const char *enet_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
|
||||
static const char *enet_sels[] = { "enet_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
|
||||
static const char *m4_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "osc", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd3_454m", };
|
||||
static const char *m4_sels[] = { "m4_pre_sel", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
|
||||
static const char *eim_slow_sels[] = { "ocram", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *ecspi_sels[] = { "pll3_60m", "osc", };
|
||||
static const char *lcdif1_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", };
|
||||
static const char *lcdif1_sels[] = { "lcdif1_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
|
||||
static const char *lcdif2_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd3_594m", "pll3_pfd1_540m", };
|
||||
static const char *lcdif2_sels[] = { "lcdif2_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
|
||||
static const char *display_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll3_usb_otg", "pll3_pfd1_540m", };
|
||||
static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
|
||||
static const char *cko1_sels[] = {
|
||||
"pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",
|
||||
"dummy", "ocram", "dummy", "pxp_axi", "epdc_axi", "lcdif_pix",
|
||||
"epdc_pix", "ahb", "ipg", "perclk", "ckil", "pll4_audio_div",
|
||||
};
|
||||
static const char *cko2_sels[] = {
|
||||
"dummy", "mmdc_p0_fast", "usdhc4", "usdhc1", "dummy", "wrck",
|
||||
"ecspi_root", "dummy", "usdhc3", "pcie", "arm", "csi_core",
|
||||
"lcdif_axi", "dummy", "osc", "dummy", "gpu2d_ovg_core",
|
||||
"usdhc2", "ssi1", "ssi2", "ssi3", "gpu2d_core", "dummy",
|
||||
"dummy", "dummy", "dummy", "esai_extal", "eim_slow", "uart_serial",
|
||||
"spdif", "asrc", "dummy",
|
||||
};
|
||||
static const char *cko_sels[] = { "cko1", "cko2", };
|
||||
static const char *lvds_sels[] = {
|
||||
"arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div",
|
||||
"dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2",
|
||||
};
|
||||
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", };
|
||||
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
|
||||
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
|
||||
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
|
||||
static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
|
||||
static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
|
||||
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
|
||||
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
|
||||
|
||||
static struct clk *clks[IMX6SX_CLK_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static int const clks_init_on[] __initconst = {
|
||||
IMX6SX_CLK_AIPS_TZ1, IMX6SX_CLK_AIPS_TZ2, IMX6SX_CLK_AIPS_TZ3,
|
||||
IMX6SX_CLK_IPMUX1, IMX6SX_CLK_IPMUX2, IMX6SX_CLK_IPMUX3,
|
||||
IMX6SX_CLK_WAKEUP, IMX6SX_CLK_MMDC_P0_FAST, IMX6SX_CLK_MMDC_P0_IPG,
|
||||
IMX6SX_CLK_ROM, IMX6SX_CLK_ARM, IMX6SX_CLK_IPG, IMX6SX_CLK_OCRAM,
|
||||
IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_M4,
|
||||
IMX6SX_CLK_QSPI1, IMX6SX_CLK_QSPI2, IMX6SX_CLK_UART_IPG,
|
||||
IMX6SX_CLK_UART_SERIAL, IMX6SX_CLK_I2C3, IMX6SX_CLK_ECSPI5,
|
||||
IMX6SX_CLK_CAN1_IPG, IMX6SX_CLK_CAN1_SERIAL, IMX6SX_CLK_CAN2_IPG,
|
||||
IMX6SX_CLK_CAN2_SERIAL, IMX6SX_CLK_CANFD, IMX6SX_CLK_EPIT1,
|
||||
IMX6SX_CLK_EPIT2,
|
||||
};
|
||||
|
||||
static struct clk_div_table clk_enet_ref_table[] = {
|
||||
{ .val = 0, .div = 20, },
|
||||
{ .val = 1, .div = 10, },
|
||||
{ .val = 2, .div = 5, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 0, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table video_div_table[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static u32 share_count_asrc;
|
||||
static u32 share_count_audio;
|
||||
static u32 share_count_esai;
|
||||
static u32 share_count_ssi1;
|
||||
static u32 share_count_ssi2;
|
||||
static u32 share_count_ssi3;
|
||||
|
||||
static void __init imx6sx_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *base;
|
||||
int i;
|
||||
|
||||
clks[IMX6SX_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
|
||||
clks[IMX6SX_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
|
||||
clks[IMX6SX_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
|
||||
|
||||
/* ipp_di clock is external input */
|
||||
clks[IMX6SX_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
|
||||
clks[IMX6SX_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
|
||||
|
||||
/* Clock source from external clock via CLK1 PAD */
|
||||
clks[IMX6SX_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
|
||||
/* type name parent_name base div_mask */
|
||||
clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
|
||||
clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
|
||||
clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
|
||||
clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
|
||||
clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
|
||||
clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
|
||||
clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
|
||||
|
||||
clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
|
||||
/* Do not bypass PLLs initially */
|
||||
clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]);
|
||||
clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]);
|
||||
clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]);
|
||||
clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]);
|
||||
clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]);
|
||||
clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]);
|
||||
clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]);
|
||||
|
||||
clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
|
||||
clks[IMX6SX_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
|
||||
clks[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
|
||||
clks[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
|
||||
clks[IMX6SX_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
|
||||
clks[IMX6SX_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
|
||||
clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
|
||||
|
||||
/*
|
||||
* Bit 20 is the reserved and read-only bit, we do this only for:
|
||||
* - Do nothing for usbphy clk_enable/disable
|
||||
* - Keep refcount when do usbphy clk_enable/disable, in that case,
|
||||
* the clk framework may need to enable/disable usbphy's parent
|
||||
*/
|
||||
clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
|
||||
clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
|
||||
|
||||
/*
|
||||
* usbphy*_gate needs to be on after system boots up, and software
|
||||
* never needs to control it anymore.
|
||||
*/
|
||||
clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
|
||||
clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
|
||||
|
||||
/* FIXME 100MHz is used for pcie ref for all imx6 pcie, excepted imx6q */
|
||||
clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
|
||||
clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
|
||||
|
||||
clks[IMX6SX_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
|
||||
clks[IMX6SX_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
|
||||
|
||||
clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
|
||||
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
|
||||
&imx_ccm_lock);
|
||||
clks[IMX6SX_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
|
||||
base + 0xe0, 2, 2, 0, clk_enet_ref_table,
|
||||
&imx_ccm_lock);
|
||||
clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
|
||||
|
||||
clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
|
||||
clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
|
||||
|
||||
/* name parent_name reg idx */
|
||||
clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
|
||||
clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
|
||||
clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
|
||||
clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
|
||||
clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
|
||||
clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
|
||||
clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
|
||||
clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
|
||||
|
||||
/* name parent_name mult div */
|
||||
clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
|
||||
clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
|
||||
clks[IMX6SX_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
|
||||
clks[IMX6SX_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
|
||||
clks[IMX6SX_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
|
||||
clks[IMX6SX_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
|
||||
|
||||
clks[IMX6SX_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
|
||||
CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
|
||||
CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
|
||||
clks[IMX6SX_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
|
||||
CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
|
||||
clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
|
||||
CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
|
||||
|
||||
/* name reg shift width parent_names num_parents */
|
||||
clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
|
||||
|
||||
np = ccm_node;
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
imx6q_pm_set_ccm_base(base);
|
||||
|
||||
/* name reg shift width parent_names num_parents */
|
||||
clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
|
||||
clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
|
||||
clks[IMX6SX_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 2, ocram_sels, ARRAY_SIZE(ocram_sels));
|
||||
clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
|
||||
clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
|
||||
clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
|
||||
clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
|
||||
clks[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
|
||||
clks[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
|
||||
clks[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels));
|
||||
clks[IMX6SX_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
|
||||
clks[IMX6SX_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
clks[IMX6SX_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
clks[IMX6SX_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
clks[IMX6SX_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
|
||||
clks[IMX6SX_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
|
||||
clks[IMX6SX_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
|
||||
clks[IMX6SX_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
|
||||
clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux_flags("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
|
||||
clks[IMX6SX_CLK_VID_SEL] = imx_clk_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels));
|
||||
clks[IMX6SX_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clks[IMX6SX_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
|
||||
clks[IMX6SX_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
|
||||
clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clks[IMX6SX_CLK_AUDIO_SEL] = imx_clk_mux("audio_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
|
||||
clks[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels));
|
||||
clks[IMX6SX_CLK_ENET_SEL] = imx_clk_mux("enet_sel", base + 0x34, 9, 3, enet_sels, ARRAY_SIZE(enet_sels));
|
||||
clks[IMX6SX_CLK_M4_PRE_SEL] = imx_clk_mux("m4_pre_sel", base + 0x34, 6, 3, m4_pre_sels, ARRAY_SIZE(m4_pre_sels));
|
||||
clks[IMX6SX_CLK_M4_SEL] = imx_clk_mux("m4_sel", base + 0x34, 0, 3, m4_sels, ARRAY_SIZE(m4_sels));
|
||||
clks[IMX6SX_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
|
||||
clks[IMX6SX_CLK_LCDIF2_PRE_SEL] = imx_clk_mux("lcdif2_pre_sel", base + 0x38, 6, 3, lcdif2_pre_sels, ARRAY_SIZE(lcdif2_pre_sels));
|
||||
clks[IMX6SX_CLK_LCDIF2_SEL] = imx_clk_mux("lcdif2_sel", base + 0x38, 0, 3, lcdif2_sels, ARRAY_SIZE(lcdif2_sels));
|
||||
clks[IMX6SX_CLK_DISPLAY_SEL] = imx_clk_mux("display_sel", base + 0x3c, 14, 2, display_sels, ARRAY_SIZE(display_sels));
|
||||
clks[IMX6SX_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
|
||||
clks[IMX6SX_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
|
||||
clks[IMX6SX_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
|
||||
clks[IMX6SX_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
|
||||
|
||||
clks[IMX6SX_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_CLK_LCDIF1_PRE_SEL] = imx_clk_mux_flags("lcdif1_pre_sel", base + 0x38, 15, 3, lcdif1_pre_sels, ARRAY_SIZE(lcdif1_pre_sels), CLK_SET_RATE_PARENT);
|
||||
clks[IMX6SX_CLK_LCDIF1_SEL] = imx_clk_mux_flags("lcdif1_sel", base + 0x38, 9, 3, lcdif1_sels, ARRAY_SIZE(lcdif1_sels), CLK_SET_RATE_PARENT);
|
||||
|
||||
/* name parent_name reg shift width */
|
||||
clks[IMX6SX_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
|
||||
clks[IMX6SX_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
|
||||
clks[IMX6SX_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
|
||||
clks[IMX6SX_CLK_GPU_CORE_PODF] = imx_clk_divider("gpu_core_podf", "gpu_core_sel", base + 0x18, 29, 3);
|
||||
clks[IMX6SX_CLK_GPU_AXI_PODF] = imx_clk_divider("gpu_axi_podf", "gpu_axi_sel", base + 0x18, 26, 3);
|
||||
clks[IMX6SX_CLK_LCDIF1_PODF] = imx_clk_divider("lcdif1_podf", "lcdif1_pred", base + 0x18, 23, 3);
|
||||
clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
|
||||
clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
|
||||
clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3);
|
||||
clks[IMX6SX_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
|
||||
clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2);
|
||||
clks[IMX6SX_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
|
||||
clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
|
||||
clks[IMX6SX_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
|
||||
clks[IMX6SX_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
|
||||
clks[IMX6SX_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
|
||||
clks[IMX6SX_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
|
||||
clks[IMX6SX_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
|
||||
clks[IMX6SX_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
|
||||
clks[IMX6SX_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
|
||||
clks[IMX6SX_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
|
||||
clks[IMX6SX_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
|
||||
clks[IMX6SX_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
|
||||
clks[IMX6SX_CLK_QSPI2_PRED] = imx_clk_divider("qspi2_pred", "qspi2_sel", base + 0x2c, 18, 3);
|
||||
clks[IMX6SX_CLK_QSPI2_PODF] = imx_clk_divider("qspi2_podf", "qspi2_pred", base + 0x2c, 21, 6);
|
||||
clks[IMX6SX_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
|
||||
clks[IMX6SX_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
|
||||
clks[IMX6SX_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
|
||||
clks[IMX6SX_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
|
||||
clks[IMX6SX_CLK_AUDIO_PRED] = imx_clk_divider("audio_pred", "audio_sel", base + 0x30, 12, 3);
|
||||
clks[IMX6SX_CLK_AUDIO_PODF] = imx_clk_divider("audio_podf", "audio_pred", base + 0x30, 9, 3);
|
||||
clks[IMX6SX_CLK_ENET_PODF] = imx_clk_divider("enet_podf", "enet_pre_sel", base + 0x34, 12, 3);
|
||||
clks[IMX6SX_CLK_M4_PODF] = imx_clk_divider("m4_podf", "m4_sel", base + 0x34, 3, 3);
|
||||
clks[IMX6SX_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
|
||||
clks[IMX6SX_CLK_LCDIF1_PRED] = imx_clk_divider("lcdif1_pred", "lcdif1_pre_sel", base + 0x38, 12, 3);
|
||||
clks[IMX6SX_CLK_LCDIF2_PRED] = imx_clk_divider("lcdif2_pred", "lcdif2_pre_sel", base + 0x38, 3, 3);
|
||||
clks[IMX6SX_CLK_DISPLAY_PODF] = imx_clk_divider("display_podf", "display_sel", base + 0x3c, 16, 3);
|
||||
clks[IMX6SX_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
|
||||
clks[IMX6SX_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
|
||||
clks[IMX6SX_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
|
||||
|
||||
clks[IMX6SX_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
|
||||
clks[IMX6SX_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
|
||||
clks[IMX6SX_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
|
||||
clks[IMX6SX_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
|
||||
|
||||
/* name reg shift width busy: reg, shift parent_names num_parents */
|
||||
clks[IMX6SX_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
|
||||
clks[IMX6SX_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
|
||||
/* name parent_name reg shift width busy: reg, shift */
|
||||
clks[IMX6SX_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
|
||||
clks[IMX6SX_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
|
||||
clks[IMX6SX_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
|
||||
clks[IMX6SX_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
|
||||
|
||||
/* name parent_name reg shift */
|
||||
/* CCGR0 */
|
||||
clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0);
|
||||
clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2);
|
||||
clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
|
||||
clks[IMX6SX_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
|
||||
clks[IMX6SX_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
|
||||
clks[IMX6SX_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
|
||||
clks[IMX6SX_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
|
||||
clks[IMX6SX_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
|
||||
clks[IMX6SX_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
|
||||
clks[IMX6SX_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16);
|
||||
clks[IMX6SX_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
|
||||
clks[IMX6SX_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20);
|
||||
clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24);
|
||||
clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26);
|
||||
clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
|
||||
|
||||
/* CCGR1 */
|
||||
clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
|
||||
clks[IMX6SX_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
|
||||
clks[IMX6SX_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
|
||||
clks[IMX6SX_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
|
||||
clks[IMX6SX_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_podf", base + 0x6c, 8);
|
||||
clks[IMX6SX_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
|
||||
clks[IMX6SX_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
|
||||
clks[IMX6SX_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai);
|
||||
clks[IMX6SX_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai);
|
||||
clks[IMX6SX_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
|
||||
clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2("wakeup", "ipg", base + 0x6c, 18);
|
||||
clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20);
|
||||
clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22);
|
||||
clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26);
|
||||
clks[IMX6SX_CLK_CANFD] = imx_clk_gate2("canfd", "can_podf", base + 0x6c, 30);
|
||||
|
||||
/* CCGR2 */
|
||||
clks[IMX6SX_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2);
|
||||
clks[IMX6SX_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
|
||||
clks[IMX6SX_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
|
||||
clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
|
||||
clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
|
||||
clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14);
|
||||
clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2("ipmux1", "ahb", base + 0x70, 16);
|
||||
clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2("ipmux2", "ahb", base + 0x70, 18);
|
||||
clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2("ipmux3", "ahb", base + 0x70, 20);
|
||||
clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2("tzasc1", "mmdc_podf", base + 0x70, 22);
|
||||
clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28);
|
||||
clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30);
|
||||
|
||||
/* CCGR3 */
|
||||
clks[IMX6SX_CLK_M4] = imx_clk_gate2("m4", "m4_podf", base + 0x74, 2);
|
||||
clks[IMX6SX_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
|
||||
clks[IMX6SX_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "enet_sel", base + 0x74, 4);
|
||||
clks[IMX6SX_CLK_DISPLAY_AXI] = imx_clk_gate2("display_axi", "display_podf", base + 0x74, 6);
|
||||
clks[IMX6SX_CLK_LCDIF2_PIX] = imx_clk_gate2("lcdif2_pix", "lcdif2_sel", base + 0x74, 8);
|
||||
clks[IMX6SX_CLK_LCDIF1_PIX] = imx_clk_gate2("lcdif1_pix", "lcdif1_sel", base + 0x74, 10);
|
||||
clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12);
|
||||
clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
|
||||
clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18);
|
||||
clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20);
|
||||
clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24);
|
||||
clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
|
||||
|
||||
/* CCGR4 */
|
||||
clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0);
|
||||
clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10);
|
||||
clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12);
|
||||
clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2("per2_main", "ahb", base + 0x78, 14);
|
||||
clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
|
||||
clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
|
||||
clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
|
||||
clks[IMX6SX_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
|
||||
clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
|
||||
clks[IMX6SX_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
|
||||
clks[IMX6SX_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "qspi2_podf", base + 0x78, 28);
|
||||
clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
|
||||
|
||||
/* CCGR5 */
|
||||
clks[IMX6SX_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
|
||||
clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
|
||||
clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
|
||||
clks[IMX6SX_CLK_AUDIO] = imx_clk_gate2_shared("audio", "audio_podf", base + 0x7c, 14, &share_count_audio);
|
||||
clks[IMX6SX_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
|
||||
clks[IMX6SX_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
|
||||
clks[IMX6SX_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
|
||||
clks[IMX6SX_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
|
||||
clks[IMX6SX_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
|
||||
clks[IMX6SX_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
|
||||
clks[IMX6SX_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
|
||||
clks[IMX6SX_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24);
|
||||
clks[IMX6SX_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_podf", base + 0x7c, 26);
|
||||
clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2("sai1_ipg", "ipg", base + 0x7c, 28);
|
||||
clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2("sai2_ipg", "ipg", base + 0x7c, 30);
|
||||
clks[IMX6SX_CLK_SAI1] = imx_clk_gate2("sai1", "ssi1_podf", base + 0x7c, 28);
|
||||
clks[IMX6SX_CLK_SAI2] = imx_clk_gate2("sai2", "ssi2_podf", base + 0x7c, 30);
|
||||
|
||||
/* CCGR6 */
|
||||
clks[IMX6SX_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
|
||||
clks[IMX6SX_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
|
||||
clks[IMX6SX_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
|
||||
clks[IMX6SX_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
|
||||
clks[IMX6SX_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
|
||||
clks[IMX6SX_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
|
||||
clks[IMX6SX_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16);
|
||||
clks[IMX6SX_CLK_VADC] = imx_clk_gate2("vadc", "vid_podf", base + 0x80, 20);
|
||||
clks[IMX6SX_CLK_GIS] = imx_clk_gate2("gis", "display_podf", base + 0x80, 22);
|
||||
clks[IMX6SX_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24);
|
||||
clks[IMX6SX_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26);
|
||||
clks[IMX6SX_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
|
||||
clks[IMX6SX_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30);
|
||||
|
||||
clks[IMX6SX_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
|
||||
clks[IMX6SX_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
|
||||
|
||||
/* mask handshake of mmdc */
|
||||
writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
|
||||
|
||||
imx_check_clocks(clks, ARRAY_SIZE(clks));
|
||||
|
||||
clk_data.clks = clks;
|
||||
clk_data.clk_num = ARRAY_SIZE(clks);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||
clk_prepare_enable(clks[clks_init_on[i]]);
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
|
||||
clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
|
||||
clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);
|
||||
}
|
||||
|
||||
/* Set the default 132MHz for EIM module */
|
||||
clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
|
||||
clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000);
|
||||
|
||||
/* set parent clock for LCDIF1 pixel clock */
|
||||
clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]);
|
||||
clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]);
|
||||
|
||||
/* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */
|
||||
if (clk_set_parent(clks[IMX6SX_CLK_LVDS1_SEL], clks[IMX6SX_CLK_PCIE_REF_125M]))
|
||||
pr_err("Failed to set pcie bus parent clk.\n");
|
||||
if (clk_set_parent(clks[IMX6SX_CLK_PCIE_AXI_SEL], clks[IMX6SX_CLK_AXI]))
|
||||
pr_err("Failed to set pcie parent clk.\n");
|
||||
|
||||
/*
|
||||
* Init enet system AHB clock, set to 200MHz
|
||||
* pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
|
||||
*/
|
||||
clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
|
||||
clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]);
|
||||
clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000);
|
||||
clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000);
|
||||
clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000);
|
||||
|
||||
/* Audio clocks */
|
||||
clk_set_rate(clks[IMX6SX_CLK_PLL4_AUDIO_DIV], 393216000);
|
||||
|
||||
clk_set_parent(clks[IMX6SX_CLK_SPDIF_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
|
||||
clk_set_rate(clks[IMX6SX_CLK_SPDIF_PODF], 98304000);
|
||||
|
||||
clk_set_parent(clks[IMX6SX_CLK_AUDIO_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
|
||||
clk_set_rate(clks[IMX6SX_CLK_AUDIO_PODF], 24000000);
|
||||
|
||||
clk_set_parent(clks[IMX6SX_CLK_SSI1_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
|
||||
clk_set_parent(clks[IMX6SX_CLK_SSI2_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
|
||||
clk_set_parent(clks[IMX6SX_CLK_SSI3_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
|
||||
clk_set_rate(clks[IMX6SX_CLK_SSI1_PODF], 24576000);
|
||||
clk_set_rate(clks[IMX6SX_CLK_SSI2_PODF], 24576000);
|
||||
clk_set_rate(clks[IMX6SX_CLK_SSI3_PODF], 24576000);
|
||||
|
||||
clk_set_parent(clks[IMX6SX_CLK_ESAI_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
|
||||
clk_set_rate(clks[IMX6SX_CLK_ESAI_PODF], 24576000);
|
||||
|
||||
/* Set parent clock for vadc */
|
||||
clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
|
||||
|
||||
/* default parent of can_sel clock is invalid, manually set it here */
|
||||
clk_set_parent(clks[IMX6SX_CLK_CAN_SEL], clks[IMX6SX_CLK_PLL3_60M]);
|
||||
|
||||
/* Update gpu clock from default 528M to 720M */
|
||||
clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
|
||||
clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
|
||||
|
||||
clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
|
||||
clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
|
||||
|
||||
/* Set initial power mode */
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
}
|
||||
CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
|
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright 2012 Linaro Ltd.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include "clk.h"
|
||||
|
||||
/**
|
||||
* struct clk_pfd - IMX PFD clock
|
||||
* @clk_hw: clock source
|
||||
* @reg: PFD register address
|
||||
* @idx: the index of PFD encoded in the register
|
||||
*
|
||||
* PFD clock found on i.MX6 series. Each register for PFD has 4 clk_pfd
|
||||
* data encoded, and member idx is used to specify the one. And each
|
||||
* register has SET, CLR and TOG registers at offset 0x4 0x8 and 0xc.
|
||||
*/
|
||||
struct clk_pfd {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 idx;
|
||||
};
|
||||
|
||||
#define to_clk_pfd(_hw) container_of(_hw, struct clk_pfd, hw)
|
||||
|
||||
#define SET 0x4
|
||||
#define CLR 0x8
|
||||
#define OTG 0xc
|
||||
|
||||
static int clk_pfd_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pfd *pfd = to_clk_pfd(hw);
|
||||
|
||||
writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_pfd_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pfd *pfd = to_clk_pfd(hw);
|
||||
|
||||
writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
|
||||
}
|
||||
|
||||
static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pfd *pfd = to_clk_pfd(hw);
|
||||
u64 tmp = parent_rate;
|
||||
u8 frac = (readl_relaxed(pfd->reg) >> (pfd->idx * 8)) & 0x3f;
|
||||
|
||||
tmp *= 18;
|
||||
do_div(tmp, frac);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static long clk_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
u64 tmp = *prate;
|
||||
u8 frac;
|
||||
|
||||
tmp = tmp * 18 + rate / 2;
|
||||
do_div(tmp, rate);
|
||||
frac = tmp;
|
||||
if (frac < 12)
|
||||
frac = 12;
|
||||
else if (frac > 35)
|
||||
frac = 35;
|
||||
tmp = *prate;
|
||||
tmp *= 18;
|
||||
do_div(tmp, frac);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static int clk_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pfd *pfd = to_clk_pfd(hw);
|
||||
u64 tmp = parent_rate;
|
||||
u8 frac;
|
||||
|
||||
tmp = tmp * 18 + rate / 2;
|
||||
do_div(tmp, rate);
|
||||
frac = tmp;
|
||||
if (frac < 12)
|
||||
frac = 12;
|
||||
else if (frac > 35)
|
||||
frac = 35;
|
||||
|
||||
writel_relaxed(0x3f << (pfd->idx * 8), pfd->reg + CLR);
|
||||
writel_relaxed(frac << (pfd->idx * 8), pfd->reg + SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_pfd_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pfd *pfd = to_clk_pfd(hw);
|
||||
|
||||
if (readl_relaxed(pfd->reg) & (1 << ((pfd->idx + 1) * 8 - 1)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pfd_ops = {
|
||||
.enable = clk_pfd_enable,
|
||||
.disable = clk_pfd_disable,
|
||||
.recalc_rate = clk_pfd_recalc_rate,
|
||||
.round_rate = clk_pfd_round_rate,
|
||||
.set_rate = clk_pfd_set_rate,
|
||||
.is_enabled = clk_pfd_is_enabled,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_pfd(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 idx)
|
||||
{
|
||||
struct clk_pfd *pfd;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
|
||||
if (!pfd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pfd->reg = reg;
|
||||
pfd->idx = idx;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_pfd_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
pfd->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &pfd->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(pfd);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,126 +0,0 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "clk.h"
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
/**
|
||||
* pll v1
|
||||
*
|
||||
* @clk_hw clock source
|
||||
* @parent the parent clock name
|
||||
* @base base address of pll registers
|
||||
*
|
||||
* PLL clock version 1, found on i.MX1/21/25/27/31/35
|
||||
*/
|
||||
|
||||
#define MFN_BITS (10)
|
||||
#define MFN_SIGN (BIT(MFN_BITS - 1))
|
||||
#define MFN_MASK (MFN_SIGN - 1)
|
||||
|
||||
struct clk_pllv1 {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
#define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk))
|
||||
|
||||
static inline bool mfn_is_negative(unsigned int mfn)
|
||||
{
|
||||
return !cpu_is_mx1() && !cpu_is_mx21() && (mfn & MFN_SIGN);
|
||||
}
|
||||
|
||||
static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv1 *pll = to_clk_pllv1(hw);
|
||||
long long ll;
|
||||
int mfn_abs;
|
||||
unsigned int mfi, mfn, mfd, pd;
|
||||
u32 reg;
|
||||
unsigned long rate;
|
||||
|
||||
reg = readl(pll->base);
|
||||
|
||||
/*
|
||||
* Get the resulting clock rate from a PLL register value and the input
|
||||
* frequency. PLLs with this register layout can be found on i.MX1,
|
||||
* i.MX21, i.MX27 and i,MX31
|
||||
*
|
||||
* mfi + mfn / (mfd + 1)
|
||||
* f = 2 * f_ref * --------------------
|
||||
* pd + 1
|
||||
*/
|
||||
|
||||
mfi = (reg >> 10) & 0xf;
|
||||
mfn = reg & 0x3ff;
|
||||
mfd = (reg >> 16) & 0x3ff;
|
||||
pd = (reg >> 26) & 0xf;
|
||||
|
||||
mfi = mfi <= 5 ? 5 : mfi;
|
||||
|
||||
mfn_abs = mfn;
|
||||
|
||||
/*
|
||||
* On all i.MXs except i.MX1 and i.MX21 mfn is a 10bit
|
||||
* 2's complements number.
|
||||
* On i.MX27 the bit 9 is the sign bit.
|
||||
*/
|
||||
if (mfn_is_negative(mfn)) {
|
||||
if (cpu_is_mx27())
|
||||
mfn_abs = mfn & MFN_MASK;
|
||||
else
|
||||
mfn_abs = BIT(MFN_BITS) - mfn;
|
||||
}
|
||||
|
||||
rate = parent_rate * 2;
|
||||
rate /= pd + 1;
|
||||
|
||||
ll = (unsigned long long)rate * mfn_abs;
|
||||
|
||||
do_div(ll, mfd + 1);
|
||||
|
||||
if (mfn_is_negative(mfn))
|
||||
ll = -ll;
|
||||
|
||||
ll = (rate * mfi) + ll;
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_pllv1_ops = {
|
||||
.recalc_rate = clk_pllv1_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_pllv1(const char *name, const char *parent,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct clk_pllv1 *pll;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
pll = kmalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pll->base = base;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_pllv1_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent;
|
||||
init.num_parents = 1;
|
||||
|
||||
pll->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &pll->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(pll);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,266 +0,0 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define to_clk_pllv2(clk) (container_of(clk, struct clk_pllv2, clk))
|
||||
|
||||
/* PLL Register Offsets */
|
||||
#define MXC_PLL_DP_CTL 0x00
|
||||
#define MXC_PLL_DP_CONFIG 0x04
|
||||
#define MXC_PLL_DP_OP 0x08
|
||||
#define MXC_PLL_DP_MFD 0x0C
|
||||
#define MXC_PLL_DP_MFN 0x10
|
||||
#define MXC_PLL_DP_MFNMINUS 0x14
|
||||
#define MXC_PLL_DP_MFNPLUS 0x18
|
||||
#define MXC_PLL_DP_HFS_OP 0x1C
|
||||
#define MXC_PLL_DP_HFS_MFD 0x20
|
||||
#define MXC_PLL_DP_HFS_MFN 0x24
|
||||
#define MXC_PLL_DP_MFN_TOGC 0x28
|
||||
#define MXC_PLL_DP_DESTAT 0x2c
|
||||
|
||||
/* PLL Register Bit definitions */
|
||||
#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000
|
||||
#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000
|
||||
#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12
|
||||
#define MXC_PLL_DP_CTL_ADE 0x800
|
||||
#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400
|
||||
#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8)
|
||||
#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8
|
||||
#define MXC_PLL_DP_CTL_HFSM 0x80
|
||||
#define MXC_PLL_DP_CTL_PRE 0x40
|
||||
#define MXC_PLL_DP_CTL_UPEN 0x20
|
||||
#define MXC_PLL_DP_CTL_RST 0x10
|
||||
#define MXC_PLL_DP_CTL_RCP 0x8
|
||||
#define MXC_PLL_DP_CTL_PLM 0x4
|
||||
#define MXC_PLL_DP_CTL_BRM0 0x2
|
||||
#define MXC_PLL_DP_CTL_LRF 0x1
|
||||
|
||||
#define MXC_PLL_DP_CONFIG_BIST 0x8
|
||||
#define MXC_PLL_DP_CONFIG_SJC_CE 0x4
|
||||
#define MXC_PLL_DP_CONFIG_AREN 0x2
|
||||
#define MXC_PLL_DP_CONFIG_LDREQ 0x1
|
||||
|
||||
#define MXC_PLL_DP_OP_MFI_OFFSET 4
|
||||
#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4)
|
||||
#define MXC_PLL_DP_OP_PDF_OFFSET 0
|
||||
#define MXC_PLL_DP_OP_PDF_MASK 0xF
|
||||
|
||||
#define MXC_PLL_DP_MFD_OFFSET 0
|
||||
#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF
|
||||
|
||||
#define MXC_PLL_DP_MFN_OFFSET 0x0
|
||||
#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF
|
||||
|
||||
#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17)
|
||||
#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16)
|
||||
#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x0
|
||||
#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF
|
||||
|
||||
#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31)
|
||||
#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF
|
||||
|
||||
#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */
|
||||
|
||||
struct clk_pllv2 {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
|
||||
u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn)
|
||||
{
|
||||
long mfi, mfn, mfd, pdf, ref_clk, mfn_abs;
|
||||
unsigned long dbl;
|
||||
s64 temp;
|
||||
|
||||
dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
|
||||
|
||||
pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
|
||||
mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET;
|
||||
mfi = (mfi <= 5) ? 5 : mfi;
|
||||
mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
|
||||
mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK;
|
||||
/* Sign extend to 32-bits */
|
||||
if (mfn >= 0x04000000) {
|
||||
mfn |= 0xFC000000;
|
||||
mfn_abs = -mfn;
|
||||
}
|
||||
|
||||
ref_clk = 2 * parent_rate;
|
||||
if (dbl != 0)
|
||||
ref_clk *= 2;
|
||||
|
||||
ref_clk /= (pdf + 1);
|
||||
temp = (u64) ref_clk * mfn_abs;
|
||||
do_div(temp, mfd + 1);
|
||||
if (mfn < 0)
|
||||
temp = -temp;
|
||||
temp = (ref_clk * mfi) + temp;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
static unsigned long clk_pllv2_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 dp_op, dp_mfd, dp_mfn, dp_ctl;
|
||||
void __iomem *pllbase;
|
||||
struct clk_pllv2 *pll = to_clk_pllv2(hw);
|
||||
|
||||
pllbase = pll->base;
|
||||
|
||||
dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
|
||||
dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);
|
||||
dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);
|
||||
dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);
|
||||
|
||||
return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn);
|
||||
}
|
||||
|
||||
static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,
|
||||
u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn)
|
||||
{
|
||||
u32 reg;
|
||||
long mfi, pdf, mfn, mfd = 999999;
|
||||
s64 temp64;
|
||||
unsigned long quad_parent_rate;
|
||||
|
||||
quad_parent_rate = 4 * parent_rate;
|
||||
pdf = mfi = -1;
|
||||
while (++pdf < 16 && mfi < 5)
|
||||
mfi = rate * (pdf+1) / quad_parent_rate;
|
||||
if (mfi > 15)
|
||||
return -EINVAL;
|
||||
pdf--;
|
||||
|
||||
temp64 = rate * (pdf + 1) - quad_parent_rate * mfi;
|
||||
do_div(temp64, quad_parent_rate / 1000000);
|
||||
mfn = (long)temp64;
|
||||
|
||||
reg = mfi << 4 | pdf;
|
||||
|
||||
*dp_op = reg;
|
||||
*dp_mfd = mfd;
|
||||
*dp_mfn = mfn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_pllv2_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv2 *pll = to_clk_pllv2(hw);
|
||||
void __iomem *pllbase;
|
||||
u32 dp_ctl, dp_op, dp_mfd, dp_mfn;
|
||||
int ret;
|
||||
|
||||
pllbase = pll->base;
|
||||
|
||||
|
||||
ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
|
||||
/* use dpdck0_2 */
|
||||
__raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL);
|
||||
|
||||
__raw_writel(dp_op, pllbase + MXC_PLL_DP_OP);
|
||||
__raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD);
|
||||
__raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
u32 dp_op, dp_mfd, dp_mfn;
|
||||
|
||||
__clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn);
|
||||
return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN,
|
||||
dp_op, dp_mfd, dp_mfn);
|
||||
}
|
||||
|
||||
static int clk_pllv2_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pllv2 *pll = to_clk_pllv2(hw);
|
||||
u32 reg;
|
||||
void __iomem *pllbase;
|
||||
int i = 0;
|
||||
|
||||
pllbase = pll->base;
|
||||
reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;
|
||||
__raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
|
||||
|
||||
/* Wait for lock */
|
||||
do {
|
||||
reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
|
||||
if (reg & MXC_PLL_DP_CTL_LRF)
|
||||
break;
|
||||
|
||||
udelay(1);
|
||||
} while (++i < MAX_DPLL_WAIT_TRIES);
|
||||
|
||||
if (i == MAX_DPLL_WAIT_TRIES) {
|
||||
pr_err("MX5: pll locking failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_pllv2_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pllv2 *pll = to_clk_pllv2(hw);
|
||||
u32 reg;
|
||||
void __iomem *pllbase;
|
||||
|
||||
pllbase = pll->base;
|
||||
reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN;
|
||||
__raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
|
||||
}
|
||||
|
||||
static struct clk_ops clk_pllv2_ops = {
|
||||
.prepare = clk_pllv2_prepare,
|
||||
.unprepare = clk_pllv2_unprepare,
|
||||
.recalc_rate = clk_pllv2_recalc_rate,
|
||||
.round_rate = clk_pllv2_round_rate,
|
||||
.set_rate = clk_pllv2_set_rate,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_pllv2(const char *name, const char *parent,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct clk_pllv2 *pll;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pll->base = base;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_pllv2_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent;
|
||||
init.num_parents = 1;
|
||||
|
||||
pll->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &pll->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(pll);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright 2012 Linaro Ltd.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/err.h>
|
||||
#include "clk.h"
|
||||
|
||||
#define PLL_NUM_OFFSET 0x10
|
||||
#define PLL_DENOM_OFFSET 0x20
|
||||
|
||||
#define BM_PLL_POWER (0x1 << 12)
|
||||
#define BM_PLL_LOCK (0x1 << 31)
|
||||
|
||||
/**
|
||||
* struct clk_pllv3 - IMX PLL clock version 3
|
||||
* @clk_hw: clock source
|
||||
* @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.
|
||||
*/
|
||||
struct clk_pllv3 {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
bool powerup_set;
|
||||
u32 div_mask;
|
||||
u32 div_shift;
|
||||
};
|
||||
|
||||
#define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw)
|
||||
|
||||
static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(10);
|
||||
u32 val = readl_relaxed(pll->base) & BM_PLL_POWER;
|
||||
|
||||
/* No need to wait for lock when pll is not powered up */
|
||||
if ((pll->powerup_set && !val) || (!pll->powerup_set && val))
|
||||
return 0;
|
||||
|
||||
/* Wait for PLL to lock */
|
||||
do {
|
||||
if (readl_relaxed(pll->base) & BM_PLL_LOCK)
|
||||
break;
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
usleep_range(50, 500);
|
||||
} while (1);
|
||||
|
||||
return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int clk_pllv3_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pllv3 *pll = to_clk_pllv3(hw);
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(pll->base);
|
||||
if (pll->powerup_set)
|
||||
val |= BM_PLL_POWER;
|
||||
else
|
||||
val &= ~BM_PLL_POWER;
|
||||
writel_relaxed(val, pll->base);
|
||||
|
||||
return clk_pllv3_wait_lock(pll);
|
||||
}
|
||||
|
||||
static void clk_pllv3_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pllv3 *pll = to_clk_pllv3(hw);
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(pll->base);
|
||||
if (pll->powerup_set)
|
||||
val &= ~BM_PLL_POWER;
|
||||
else
|
||||
val |= BM_PLL_POWER;
|
||||
writel_relaxed(val, pll->base);
|
||||
}
|
||||
|
||||
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_shift) & pll->div_mask;
|
||||
|
||||
return (div == 1) ? parent_rate * 22 : parent_rate * 20;
|
||||
}
|
||||
|
||||
static long clk_pllv3_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
unsigned long parent_rate = *prate;
|
||||
|
||||
return (rate >= parent_rate * 22) ? parent_rate * 22 :
|
||||
parent_rate * 20;
|
||||
}
|
||||
|
||||
static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv3 *pll = to_clk_pllv3(hw);
|
||||
u32 val, div;
|
||||
|
||||
if (rate == parent_rate * 22)
|
||||
div = 1;
|
||||
else if (rate == parent_rate * 20)
|
||||
div = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
val = readl_relaxed(pll->base);
|
||||
val &= ~(pll->div_mask << pll->div_shift);
|
||||
val |= (div << pll->div_shift);
|
||||
writel_relaxed(val, pll->base);
|
||||
|
||||
return clk_pllv3_wait_lock(pll);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pllv3_ops = {
|
||||
.prepare = clk_pllv3_prepare,
|
||||
.unprepare = clk_pllv3_unprepare,
|
||||
.recalc_rate = clk_pllv3_recalc_rate,
|
||||
.round_rate = clk_pllv3_round_rate,
|
||||
.set_rate = clk_pllv3_set_rate,
|
||||
};
|
||||
|
||||
static unsigned long clk_pllv3_sys_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;
|
||||
|
||||
return parent_rate * div / 2;
|
||||
}
|
||||
|
||||
static long clk_pllv3_sys_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
unsigned long parent_rate = *prate;
|
||||
unsigned long min_rate = parent_rate * 54 / 2;
|
||||
unsigned long max_rate = parent_rate * 108 / 2;
|
||||
u32 div;
|
||||
|
||||
if (rate > max_rate)
|
||||
rate = max_rate;
|
||||
else if (rate < min_rate)
|
||||
rate = min_rate;
|
||||
div = rate * 2 / parent_rate;
|
||||
|
||||
return parent_rate * div / 2;
|
||||
}
|
||||
|
||||
static int clk_pllv3_sys_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv3 *pll = to_clk_pllv3(hw);
|
||||
unsigned long min_rate = parent_rate * 54 / 2;
|
||||
unsigned long max_rate = parent_rate * 108 / 2;
|
||||
u32 val, div;
|
||||
|
||||
if (rate < min_rate || rate > max_rate)
|
||||
return -EINVAL;
|
||||
|
||||
div = rate * 2 / parent_rate;
|
||||
val = readl_relaxed(pll->base);
|
||||
val &= ~pll->div_mask;
|
||||
val |= div;
|
||||
writel_relaxed(val, pll->base);
|
||||
|
||||
return clk_pllv3_wait_lock(pll);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pllv3_sys_ops = {
|
||||
.prepare = clk_pllv3_prepare,
|
||||
.unprepare = clk_pllv3_unprepare,
|
||||
.recalc_rate = clk_pllv3_sys_recalc_rate,
|
||||
.round_rate = clk_pllv3_sys_round_rate,
|
||||
.set_rate = clk_pllv3_sys_set_rate,
|
||||
};
|
||||
|
||||
static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv3 *pll = to_clk_pllv3(hw);
|
||||
u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET);
|
||||
u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET);
|
||||
u32 div = readl_relaxed(pll->base) & pll->div_mask;
|
||||
|
||||
return (parent_rate * div) + ((parent_rate / mfd) * mfn);
|
||||
}
|
||||
|
||||
static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
unsigned long parent_rate = *prate;
|
||||
unsigned long min_rate = parent_rate * 27;
|
||||
unsigned long max_rate = parent_rate * 54;
|
||||
u32 div;
|
||||
u32 mfn, mfd = 1000000;
|
||||
s64 temp64;
|
||||
|
||||
if (rate > max_rate)
|
||||
rate = max_rate;
|
||||
else if (rate < min_rate)
|
||||
rate = min_rate;
|
||||
|
||||
div = rate / parent_rate;
|
||||
temp64 = (u64) (rate - div * parent_rate);
|
||||
temp64 *= mfd;
|
||||
do_div(temp64, parent_rate);
|
||||
mfn = temp64;
|
||||
|
||||
return parent_rate * div + parent_rate / mfd * mfn;
|
||||
}
|
||||
|
||||
static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv3 *pll = to_clk_pllv3(hw);
|
||||
unsigned long min_rate = parent_rate * 27;
|
||||
unsigned long max_rate = parent_rate * 54;
|
||||
u32 val, div;
|
||||
u32 mfn, mfd = 1000000;
|
||||
s64 temp64;
|
||||
|
||||
if (rate < min_rate || rate > max_rate)
|
||||
return -EINVAL;
|
||||
|
||||
div = rate / parent_rate;
|
||||
temp64 = (u64) (rate - div * parent_rate);
|
||||
temp64 *= mfd;
|
||||
do_div(temp64, parent_rate);
|
||||
mfn = temp64;
|
||||
|
||||
val = readl_relaxed(pll->base);
|
||||
val &= ~pll->div_mask;
|
||||
val |= div;
|
||||
writel_relaxed(val, pll->base);
|
||||
writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
|
||||
writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
|
||||
|
||||
return clk_pllv3_wait_lock(pll);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pllv3_av_ops = {
|
||||
.prepare = clk_pllv3_prepare,
|
||||
.unprepare = clk_pllv3_unprepare,
|
||||
.recalc_rate = clk_pllv3_av_recalc_rate,
|
||||
.round_rate = clk_pllv3_av_round_rate,
|
||||
.set_rate = clk_pllv3_av_set_rate,
|
||||
};
|
||||
|
||||
static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return 500000000;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pllv3_enet_ops = {
|
||||
.prepare = clk_pllv3_prepare,
|
||||
.unprepare = clk_pllv3_unprepare,
|
||||
.recalc_rate = clk_pllv3_enet_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
|
||||
const char *parent_name, void __iomem *base,
|
||||
u32 div_mask)
|
||||
{
|
||||
struct clk_pllv3 *pll;
|
||||
const struct clk_ops *ops;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
switch (type) {
|
||||
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;
|
||||
break;
|
||||
case IMX_PLLV3_AV:
|
||||
ops = &clk_pllv3_av_ops;
|
||||
break;
|
||||
case IMX_PLLV3_ENET:
|
||||
ops = &clk_pllv3_enet_ops;
|
||||
break;
|
||||
default:
|
||||
ops = &clk_pllv3_ops;
|
||||
}
|
||||
pll->base = base;
|
||||
pll->div_mask = div_mask;
|
||||
|
||||
init.name = name;
|
||||
init.ops = ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
pll->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &pll->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(pll);
|
||||
|
||||
return clk;
|
||||
}
|
@@ -1,412 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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 as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk.h>
|
||||
#include <dt-bindings/clock/vf610-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define CCM_CCR (ccm_base + 0x00)
|
||||
#define CCM_CSR (ccm_base + 0x04)
|
||||
#define CCM_CCSR (ccm_base + 0x08)
|
||||
#define CCM_CACRR (ccm_base + 0x0c)
|
||||
#define CCM_CSCMR1 (ccm_base + 0x10)
|
||||
#define CCM_CSCDR1 (ccm_base + 0x14)
|
||||
#define CCM_CSCDR2 (ccm_base + 0x18)
|
||||
#define CCM_CSCDR3 (ccm_base + 0x1c)
|
||||
#define CCM_CSCMR2 (ccm_base + 0x20)
|
||||
#define CCM_CSCDR4 (ccm_base + 0x24)
|
||||
#define CCM_CLPCR (ccm_base + 0x2c)
|
||||
#define CCM_CISR (ccm_base + 0x30)
|
||||
#define CCM_CIMR (ccm_base + 0x34)
|
||||
#define CCM_CGPR (ccm_base + 0x3c)
|
||||
#define CCM_CCGR0 (ccm_base + 0x40)
|
||||
#define CCM_CCGR1 (ccm_base + 0x44)
|
||||
#define CCM_CCGR2 (ccm_base + 0x48)
|
||||
#define CCM_CCGR3 (ccm_base + 0x4c)
|
||||
#define CCM_CCGR4 (ccm_base + 0x50)
|
||||
#define CCM_CCGR5 (ccm_base + 0x54)
|
||||
#define CCM_CCGR6 (ccm_base + 0x58)
|
||||
#define CCM_CCGR7 (ccm_base + 0x5c)
|
||||
#define CCM_CCGR8 (ccm_base + 0x60)
|
||||
#define CCM_CCGR9 (ccm_base + 0x64)
|
||||
#define CCM_CCGR10 (ccm_base + 0x68)
|
||||
#define CCM_CCGR11 (ccm_base + 0x6c)
|
||||
#define CCM_CMEOR0 (ccm_base + 0x70)
|
||||
#define CCM_CMEOR1 (ccm_base + 0x74)
|
||||
#define CCM_CMEOR2 (ccm_base + 0x78)
|
||||
#define CCM_CMEOR3 (ccm_base + 0x7c)
|
||||
#define CCM_CMEOR4 (ccm_base + 0x80)
|
||||
#define CCM_CMEOR5 (ccm_base + 0x84)
|
||||
#define CCM_CPPDSR (ccm_base + 0x88)
|
||||
#define CCM_CCOWR (ccm_base + 0x8c)
|
||||
#define CCM_CCPGR0 (ccm_base + 0x90)
|
||||
#define CCM_CCPGR1 (ccm_base + 0x94)
|
||||
#define CCM_CCPGR2 (ccm_base + 0x98)
|
||||
#define CCM_CCPGR3 (ccm_base + 0x9c)
|
||||
|
||||
#define CCM_CCGRx_CGn(n) ((n) * 2)
|
||||
|
||||
#define PFD_PLL1_BASE (anatop_base + 0x2b0)
|
||||
#define PFD_PLL2_BASE (anatop_base + 0x100)
|
||||
#define PFD_PLL3_BASE (anatop_base + 0xf0)
|
||||
#define PLL1_CTRL (anatop_base + 0x270)
|
||||
#define PLL2_CTRL (anatop_base + 0x30)
|
||||
#define PLL3_CTRL (anatop_base + 0x10)
|
||||
#define PLL4_CTRL (anatop_base + 0x70)
|
||||
#define PLL5_CTRL (anatop_base + 0xe0)
|
||||
#define PLL6_CTRL (anatop_base + 0xa0)
|
||||
#define PLL7_CTRL (anatop_base + 0x20)
|
||||
#define ANA_MISC1 (anatop_base + 0x160)
|
||||
|
||||
static void __iomem *anatop_base;
|
||||
static void __iomem *ccm_base;
|
||||
|
||||
/* sources for multiplexer clocks, this is used multiple times */
|
||||
static const char *fast_sels[] = { "firc", "fxosc", };
|
||||
static const char *slow_sels[] = { "sirc_32k", "sxosc", };
|
||||
static const char *pll1_sels[] = { "pll1_sys", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", };
|
||||
static const char *pll2_sels[] = { "pll2_bus", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", };
|
||||
static const char *pll_bypass_src_sels[] = { "fast_clk_sel", "lvds1_in", };
|
||||
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
|
||||
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
|
||||
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
|
||||
static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
|
||||
static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
|
||||
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
|
||||
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
|
||||
static const char *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_bus", "pll1_pfd_sel", "pll3_usb_otg", };
|
||||
static const char *ddr_sels[] = { "pll2_pfd2", "sys_sel", };
|
||||
static const char *rmii_sels[] = { "enet_ext", "audio_ext", "enet_50m", "enet_25m", };
|
||||
static const char *enet_ts_sels[] = { "enet_ext", "fxosc", "audio_ext", "usb", "enet_ts", "enet_25m", "enet_50m", };
|
||||
static const char *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", };
|
||||
static const char *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", };
|
||||
static const char *nfc_sels[] = { "platform_bus", "pll1_pfd1", "pll3_pfd1", "pll3_pfd3", };
|
||||
static const char *qspi_sels[] = { "pll3_usb_otg", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", };
|
||||
static const char *esdhc_sels[] = { "pll3_usb_otg", "pll3_pfd3", "pll1_pfd3", "platform_bus", };
|
||||
static const char *dcu_sels[] = { "pll1_pfd2", "pll3_usb_otg", };
|
||||
static const char *gpu_sels[] = { "pll2_pfd2", "pll3_pfd2", };
|
||||
static const char *vadc_sels[] = { "pll6_video_div", "pll3_usb_otg_div", "pll3_usb_otg", };
|
||||
/* FTM counter clock source, not module clock */
|
||||
static const char *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ext", };
|
||||
static const char *ftm_fix_sels[] = { "sxosc", "ipg_bus", };
|
||||
|
||||
|
||||
static struct clk_div_table pll4_audio_div_table[] = {
|
||||
{ .val = 0, .div = 1 },
|
||||
{ .val = 1, .div = 2 },
|
||||
{ .val = 2, .div = 6 },
|
||||
{ .val = 3, .div = 8 },
|
||||
{ .val = 4, .div = 10 },
|
||||
{ .val = 5, .div = 12 },
|
||||
{ .val = 6, .div = 14 },
|
||||
{ .val = 7, .div = 16 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk *clk[VF610_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static unsigned int const clks_init_on[] __initconst = {
|
||||
VF610_CLK_SYS_BUS,
|
||||
VF610_CLK_DDR_SEL,
|
||||
};
|
||||
|
||||
static struct clk * __init vf610_get_fixed_clock(
|
||||
struct device_node *ccm_node, const char *name)
|
||||
{
|
||||
struct clk *clk = of_clk_get_by_name(ccm_node, name);
|
||||
|
||||
/* Backward compatibility if device tree is missing clks assignments */
|
||||
if (IS_ERR(clk))
|
||||
clk = imx_obtain_fixed_clock(name, 0);
|
||||
return clk;
|
||||
};
|
||||
|
||||
static void __init vf610_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
struct device_node *np;
|
||||
int i;
|
||||
|
||||
clk[VF610_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
|
||||
clk[VF610_CLK_SIRC_128K] = imx_clk_fixed("sirc_128k", 128000);
|
||||
clk[VF610_CLK_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000);
|
||||
clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000);
|
||||
|
||||
clk[VF610_CLK_SXOSC] = vf610_get_fixed_clock(ccm_node, "sxosc");
|
||||
clk[VF610_CLK_FXOSC] = vf610_get_fixed_clock(ccm_node, "fxosc");
|
||||
clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(ccm_node, "audio_ext");
|
||||
clk[VF610_CLK_ENET_EXT] = vf610_get_fixed_clock(ccm_node, "enet_ext");
|
||||
|
||||
/* Clock source from external clock via LVDs PAD */
|
||||
clk[VF610_CLK_ANACLK1] = vf610_get_fixed_clock(ccm_node, "anaclk1");
|
||||
|
||||
clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop");
|
||||
anatop_base = of_iomap(np, 0);
|
||||
BUG_ON(!anatop_base);
|
||||
|
||||
np = ccm_node;
|
||||
ccm_base = of_iomap(np, 0);
|
||||
BUG_ON(!ccm_base);
|
||||
|
||||
clk[VF610_CLK_SLOW_CLK_SEL] = imx_clk_mux("slow_clk_sel", CCM_CCSR, 4, 1, slow_sels, ARRAY_SIZE(slow_sels));
|
||||
clk[VF610_CLK_FASK_CLK_SEL] = imx_clk_mux("fast_clk_sel", CCM_CCSR, 5, 1, fast_sels, ARRAY_SIZE(fast_sels));
|
||||
|
||||
clk[VF610_CLK_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", PLL1_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[VF610_CLK_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", PLL2_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[VF610_CLK_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", PLL3_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[VF610_CLK_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", PLL4_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[VF610_CLK_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", PLL5_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[VF610_CLK_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", PLL6_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
clk[VF610_CLK_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", PLL7_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
|
||||
|
||||
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_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_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);
|
||||
clk[VF610_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", PLL3_CTRL, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[VF610_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", PLL4_CTRL, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[VF610_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", PLL5_CTRL, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[VF610_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", PLL6_CTRL, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
clk[VF610_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", PLL7_CTRL, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
|
||||
|
||||
/* Do not bypass PLLs initially */
|
||||
clk_set_parent(clk[VF610_PLL1_BYPASS], clk[VF610_CLK_PLL1]);
|
||||
clk_set_parent(clk[VF610_PLL2_BYPASS], clk[VF610_CLK_PLL2]);
|
||||
clk_set_parent(clk[VF610_PLL3_BYPASS], clk[VF610_CLK_PLL3]);
|
||||
clk_set_parent(clk[VF610_PLL4_BYPASS], clk[VF610_CLK_PLL4]);
|
||||
clk_set_parent(clk[VF610_PLL5_BYPASS], clk[VF610_CLK_PLL5]);
|
||||
clk_set_parent(clk[VF610_PLL6_BYPASS], clk[VF610_CLK_PLL6]);
|
||||
clk_set_parent(clk[VF610_PLL7_BYPASS], clk[VF610_CLK_PLL7]);
|
||||
|
||||
clk[VF610_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", PLL1_CTRL, 13);
|
||||
clk[VF610_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", PLL2_CTRL, 13);
|
||||
clk[VF610_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", PLL3_CTRL, 13);
|
||||
clk[VF610_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", PLL4_CTRL, 13);
|
||||
clk[VF610_CLK_PLL5_ENET] = imx_clk_gate("pll5_enet", "pll5_bypass", PLL5_CTRL, 13);
|
||||
clk[VF610_CLK_PLL6_VIDEO] = imx_clk_gate("pll6_video", "pll6_bypass", PLL6_CTRL, 13);
|
||||
clk[VF610_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", PLL7_CTRL, 13);
|
||||
|
||||
clk[VF610_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", ANA_MISC1, 12, BIT(10));
|
||||
|
||||
clk[VF610_CLK_PLL1_PFD1] = imx_clk_pfd("pll1_pfd1", "pll1_sys", PFD_PLL1_BASE, 0);
|
||||
clk[VF610_CLK_PLL1_PFD2] = imx_clk_pfd("pll1_pfd2", "pll1_sys", PFD_PLL1_BASE, 1);
|
||||
clk[VF610_CLK_PLL1_PFD3] = imx_clk_pfd("pll1_pfd3", "pll1_sys", PFD_PLL1_BASE, 2);
|
||||
clk[VF610_CLK_PLL1_PFD4] = imx_clk_pfd("pll1_pfd4", "pll1_sys", PFD_PLL1_BASE, 3);
|
||||
|
||||
clk[VF610_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus", PFD_PLL2_BASE, 0);
|
||||
clk[VF610_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus", PFD_PLL2_BASE, 1);
|
||||
clk[VF610_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3", "pll2_bus", PFD_PLL2_BASE, 2);
|
||||
clk[VF610_CLK_PLL2_PFD4] = imx_clk_pfd("pll2_pfd4", "pll2_bus", PFD_PLL2_BASE, 3);
|
||||
|
||||
clk[VF610_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", PFD_PLL3_BASE, 0);
|
||||
clk[VF610_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", PFD_PLL3_BASE, 1);
|
||||
clk[VF610_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", PFD_PLL3_BASE, 2);
|
||||
clk[VF610_CLK_PLL3_PFD4] = imx_clk_pfd("pll3_pfd4", "pll3_usb_otg", PFD_PLL3_BASE, 3);
|
||||
|
||||
clk[VF610_CLK_PLL1_PFD_SEL] = imx_clk_mux("pll1_pfd_sel", CCM_CCSR, 16, 3, pll1_sels, 5);
|
||||
clk[VF610_CLK_PLL2_PFD_SEL] = imx_clk_mux("pll2_pfd_sel", CCM_CCSR, 19, 3, pll2_sels, 5);
|
||||
clk[VF610_CLK_SYS_SEL] = imx_clk_mux("sys_sel", CCM_CCSR, 0, 3, sys_sels, ARRAY_SIZE(sys_sels));
|
||||
clk[VF610_CLK_DDR_SEL] = imx_clk_mux("ddr_sel", CCM_CCSR, 6, 1, ddr_sels, ARRAY_SIZE(ddr_sels));
|
||||
clk[VF610_CLK_SYS_BUS] = imx_clk_divider("sys_bus", "sys_sel", CCM_CACRR, 0, 3);
|
||||
clk[VF610_CLK_PLATFORM_BUS] = imx_clk_divider("platform_bus", "sys_bus", CCM_CACRR, 3, 3);
|
||||
clk[VF610_CLK_IPG_BUS] = imx_clk_divider("ipg_bus", "platform_bus", CCM_CACRR, 11, 2);
|
||||
|
||||
clk[VF610_CLK_PLL3_MAIN_DIV] = imx_clk_divider("pll3_usb_otg_div", "pll3_usb_otg", CCM_CACRR, 20, 1);
|
||||
clk[VF610_CLK_PLL4_MAIN_DIV] = clk_register_divider_table(NULL, "pll4_audio_div", "pll4_audio", 0, CCM_CACRR, 6, 3, 0, pll4_audio_div_table, &imx_ccm_lock);
|
||||
clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1);
|
||||
|
||||
clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6);
|
||||
clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6);
|
||||
|
||||
clk[VF610_CLK_USBC0] = imx_clk_gate2("usbc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(4));
|
||||
clk[VF610_CLK_USBC1] = imx_clk_gate2("usbc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(4));
|
||||
|
||||
clk[VF610_CLK_QSPI0_SEL] = imx_clk_mux("qspi0_sel", CCM_CSCMR1, 22, 2, qspi_sels, 4);
|
||||
clk[VF610_CLK_QSPI0_EN] = imx_clk_gate("qspi0_en", "qspi0_sel", CCM_CSCDR3, 4);
|
||||
clk[VF610_CLK_QSPI0_X4_DIV] = imx_clk_divider("qspi0_x4", "qspi0_en", CCM_CSCDR3, 0, 2);
|
||||
clk[VF610_CLK_QSPI0_X2_DIV] = imx_clk_divider("qspi0_x2", "qspi0_x4", CCM_CSCDR3, 2, 1);
|
||||
clk[VF610_CLK_QSPI0_X1_DIV] = imx_clk_divider("qspi0_x1", "qspi0_x2", CCM_CSCDR3, 3, 1);
|
||||
clk[VF610_CLK_QSPI0] = imx_clk_gate2("qspi0", "qspi0_x1", CCM_CCGR2, CCM_CCGRx_CGn(4));
|
||||
|
||||
clk[VF610_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", CCM_CSCMR1, 24, 2, qspi_sels, 4);
|
||||
clk[VF610_CLK_QSPI1_EN] = imx_clk_gate("qspi1_en", "qspi1_sel", CCM_CSCDR3, 12);
|
||||
clk[VF610_CLK_QSPI1_X4_DIV] = imx_clk_divider("qspi1_x4", "qspi1_en", CCM_CSCDR3, 8, 2);
|
||||
clk[VF610_CLK_QSPI1_X2_DIV] = imx_clk_divider("qspi1_x2", "qspi1_x4", CCM_CSCDR3, 10, 1);
|
||||
clk[VF610_CLK_QSPI1_X1_DIV] = imx_clk_divider("qspi1_x1", "qspi1_x2", CCM_CSCDR3, 11, 1);
|
||||
clk[VF610_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_x1", CCM_CCGR8, CCM_CCGRx_CGn(4));
|
||||
|
||||
clk[VF610_CLK_ENET_50M] = imx_clk_fixed_factor("enet_50m", "pll5_enet", 1, 10);
|
||||
clk[VF610_CLK_ENET_25M] = imx_clk_fixed_factor("enet_25m", "pll5_enet", 1, 20);
|
||||
clk[VF610_CLK_ENET_SEL] = imx_clk_mux("enet_sel", CCM_CSCMR2, 4, 2, rmii_sels, 4);
|
||||
clk[VF610_CLK_ENET_TS_SEL] = imx_clk_mux("enet_ts_sel", CCM_CSCMR2, 0, 3, enet_ts_sels, 7);
|
||||
clk[VF610_CLK_ENET] = imx_clk_gate("enet", "enet_sel", CCM_CSCDR1, 24);
|
||||
clk[VF610_CLK_ENET_TS] = imx_clk_gate("enet_ts", "enet_ts_sel", CCM_CSCDR1, 23);
|
||||
clk[VF610_CLK_ENET0] = imx_clk_gate2("enet0", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(0));
|
||||
clk[VF610_CLK_ENET1] = imx_clk_gate2("enet1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(1));
|
||||
|
||||
clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7));
|
||||
|
||||
clk[VF610_CLK_UART0] = imx_clk_gate2("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7));
|
||||
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));
|
||||
|
||||
clk[VF610_CLK_DSPI0] = imx_clk_gate2("dspi0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(12));
|
||||
clk[VF610_CLK_DSPI1] = imx_clk_gate2("dspi1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(13));
|
||||
clk[VF610_CLK_DSPI2] = imx_clk_gate2("dspi2", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(12));
|
||||
clk[VF610_CLK_DSPI3] = imx_clk_gate2("dspi3", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(13));
|
||||
|
||||
clk[VF610_CLK_WDT] = imx_clk_gate2("wdt", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(14));
|
||||
|
||||
clk[VF610_CLK_ESDHC0_SEL] = imx_clk_mux("esdhc0_sel", CCM_CSCMR1, 16, 2, esdhc_sels, 4);
|
||||
clk[VF610_CLK_ESDHC0_EN] = imx_clk_gate("esdhc0_en", "esdhc0_sel", CCM_CSCDR2, 28);
|
||||
clk[VF610_CLK_ESDHC0_DIV] = imx_clk_divider("esdhc0_div", "esdhc0_en", CCM_CSCDR2, 16, 4);
|
||||
clk[VF610_CLK_ESDHC0] = imx_clk_gate2("eshc0", "esdhc0_div", CCM_CCGR7, CCM_CCGRx_CGn(1));
|
||||
|
||||
clk[VF610_CLK_ESDHC1_SEL] = imx_clk_mux("esdhc1_sel", CCM_CSCMR1, 18, 2, esdhc_sels, 4);
|
||||
clk[VF610_CLK_ESDHC1_EN] = imx_clk_gate("esdhc1_en", "esdhc1_sel", CCM_CSCDR2, 29);
|
||||
clk[VF610_CLK_ESDHC1_DIV] = imx_clk_divider("esdhc1_div", "esdhc1_en", CCM_CSCDR2, 20, 4);
|
||||
clk[VF610_CLK_ESDHC1] = imx_clk_gate2("eshc1", "esdhc1_div", CCM_CCGR7, CCM_CCGRx_CGn(2));
|
||||
|
||||
/*
|
||||
* ftm_ext_clk and ftm_fix_clk are FTM timer counter's
|
||||
* selectable clock sources, both use a common enable bit
|
||||
* in CCM_CSCDR1, selecting "dummy" clock as parent of
|
||||
* "ftm0_ext_fix" make it serve only for enable/disable.
|
||||
*/
|
||||
clk[VF610_CLK_FTM0_EXT_SEL] = imx_clk_mux("ftm0_ext_sel", CCM_CSCMR2, 6, 2, ftm_ext_sels, 4);
|
||||
clk[VF610_CLK_FTM0_FIX_SEL] = imx_clk_mux("ftm0_fix_sel", CCM_CSCMR2, 14, 1, ftm_fix_sels, 2);
|
||||
clk[VF610_CLK_FTM0_EXT_FIX_EN] = imx_clk_gate("ftm0_ext_fix_en", "dummy", CCM_CSCDR1, 25);
|
||||
clk[VF610_CLK_FTM1_EXT_SEL] = imx_clk_mux("ftm1_ext_sel", CCM_CSCMR2, 8, 2, ftm_ext_sels, 4);
|
||||
clk[VF610_CLK_FTM1_FIX_SEL] = imx_clk_mux("ftm1_fix_sel", CCM_CSCMR2, 15, 1, ftm_fix_sels, 2);
|
||||
clk[VF610_CLK_FTM1_EXT_FIX_EN] = imx_clk_gate("ftm1_ext_fix_en", "dummy", CCM_CSCDR1, 26);
|
||||
clk[VF610_CLK_FTM2_EXT_SEL] = imx_clk_mux("ftm2_ext_sel", CCM_CSCMR2, 10, 2, ftm_ext_sels, 4);
|
||||
clk[VF610_CLK_FTM2_FIX_SEL] = imx_clk_mux("ftm2_fix_sel", CCM_CSCMR2, 16, 1, ftm_fix_sels, 2);
|
||||
clk[VF610_CLK_FTM2_EXT_FIX_EN] = imx_clk_gate("ftm2_ext_fix_en", "dummy", CCM_CSCDR1, 27);
|
||||
clk[VF610_CLK_FTM3_EXT_SEL] = imx_clk_mux("ftm3_ext_sel", CCM_CSCMR2, 12, 2, ftm_ext_sels, 4);
|
||||
clk[VF610_CLK_FTM3_FIX_SEL] = imx_clk_mux("ftm3_fix_sel", CCM_CSCMR2, 17, 1, ftm_fix_sels, 2);
|
||||
clk[VF610_CLK_FTM3_EXT_FIX_EN] = imx_clk_gate("ftm3_ext_fix_en", "dummy", CCM_CSCDR1, 28);
|
||||
|
||||
/* ftm(n)_clk are FTM module operation clock */
|
||||
clk[VF610_CLK_FTM0] = imx_clk_gate2("ftm0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(8));
|
||||
clk[VF610_CLK_FTM1] = imx_clk_gate2("ftm1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(9));
|
||||
clk[VF610_CLK_FTM2] = imx_clk_gate2("ftm2", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(8));
|
||||
clk[VF610_CLK_FTM3] = imx_clk_gate2("ftm3", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(9));
|
||||
|
||||
clk[VF610_CLK_DCU0_SEL] = imx_clk_mux("dcu0_sel", CCM_CSCMR1, 28, 1, dcu_sels, 2);
|
||||
clk[VF610_CLK_DCU0_EN] = imx_clk_gate("dcu0_en", "dcu0_sel", CCM_CSCDR3, 19);
|
||||
clk[VF610_CLK_DCU0_DIV] = imx_clk_divider("dcu0_div", "dcu0_en", CCM_CSCDR3, 16, 3);
|
||||
clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "dcu0_div", CCM_CCGR3, CCM_CCGRx_CGn(8));
|
||||
clk[VF610_CLK_DCU1_SEL] = imx_clk_mux("dcu1_sel", CCM_CSCMR1, 29, 1, dcu_sels, 2);
|
||||
clk[VF610_CLK_DCU1_EN] = imx_clk_gate("dcu1_en", "dcu1_sel", CCM_CSCDR3, 23);
|
||||
clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3);
|
||||
clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8));
|
||||
|
||||
clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4);
|
||||
clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30);
|
||||
clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4);
|
||||
clk[VF610_CLK_ESAI] = imx_clk_gate2("esai", "esai_div", CCM_CCGR4, CCM_CCGRx_CGn(2));
|
||||
|
||||
clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4);
|
||||
clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16);
|
||||
clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4);
|
||||
clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "sai0_div", CCM_CCGR0, CCM_CCGRx_CGn(15));
|
||||
|
||||
clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4);
|
||||
clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17);
|
||||
clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4);
|
||||
clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "sai1_div", CCM_CCGR1, CCM_CCGRx_CGn(0));
|
||||
|
||||
clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4);
|
||||
clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18);
|
||||
clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4);
|
||||
clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "sai2_div", CCM_CCGR1, CCM_CCGRx_CGn(1));
|
||||
|
||||
clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4);
|
||||
clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19);
|
||||
clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4);
|
||||
clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "sai3_div", CCM_CCGR1, CCM_CCGRx_CGn(2));
|
||||
|
||||
clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4);
|
||||
clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9);
|
||||
clk[VF610_CLK_NFC_PRE_DIV] = imx_clk_divider("nfc_pre_div", "nfc_en", CCM_CSCDR3, 13, 3);
|
||||
clk[VF610_CLK_NFC_FRAC_DIV] = imx_clk_divider("nfc_frac_div", "nfc_pre_div", CCM_CSCDR2, 4, 4);
|
||||
clk[VF610_CLK_NFC] = imx_clk_gate2("nfc", "nfc_frac_div", CCM_CCGR10, CCM_CCGRx_CGn(0));
|
||||
|
||||
clk[VF610_CLK_GPU_SEL] = imx_clk_mux("gpu_sel", CCM_CSCMR1, 14, 1, gpu_sels, 2);
|
||||
clk[VF610_CLK_GPU_EN] = imx_clk_gate("gpu_en", "gpu_sel", CCM_CSCDR2, 10);
|
||||
clk[VF610_CLK_GPU2D] = imx_clk_gate2("gpu", "gpu_en", CCM_CCGR8, CCM_CCGRx_CGn(15));
|
||||
|
||||
clk[VF610_CLK_VADC_SEL] = imx_clk_mux("vadc_sel", CCM_CSCMR1, 8, 2, vadc_sels, 3);
|
||||
clk[VF610_CLK_VADC_EN] = imx_clk_gate("vadc_en", "vadc_sel", CCM_CSCDR1, 22);
|
||||
clk[VF610_CLK_VADC_DIV] = imx_clk_divider("vadc_div", "vadc_en", CCM_CSCDR1, 20, 2);
|
||||
clk[VF610_CLK_VADC_DIV_HALF] = imx_clk_fixed_factor("vadc_div_half", "vadc_div", 1, 2);
|
||||
clk[VF610_CLK_VADC] = imx_clk_gate2("vadc", "vadc_div", CCM_CCGR8, CCM_CCGRx_CGn(7));
|
||||
|
||||
clk[VF610_CLK_ADC0] = imx_clk_gate2("adc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(11));
|
||||
clk[VF610_CLK_ADC1] = imx_clk_gate2("adc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(11));
|
||||
clk[VF610_CLK_DAC0] = imx_clk_gate2("dac0", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(12));
|
||||
clk[VF610_CLK_DAC1] = imx_clk_gate2("dac1", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(13));
|
||||
|
||||
clk[VF610_CLK_ASRC] = imx_clk_gate2("asrc", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(1));
|
||||
|
||||
clk[VF610_CLK_FLEXCAN0_EN] = imx_clk_gate("flexcan0_en", "ipg_bus", CCM_CSCDR2, 11);
|
||||
clk[VF610_CLK_FLEXCAN0] = imx_clk_gate2("flexcan0", "flexcan0_en", CCM_CCGR0, CCM_CCGRx_CGn(0));
|
||||
clk[VF610_CLK_FLEXCAN1_EN] = imx_clk_gate("flexcan1_en", "ipg_bus", CCM_CSCDR2, 12);
|
||||
clk[VF610_CLK_FLEXCAN1] = imx_clk_gate2("flexcan1", "flexcan1_en", CCM_CCGR9, CCM_CCGRx_CGn(4));
|
||||
|
||||
clk[VF610_CLK_DMAMUX0] = imx_clk_gate2("dmamux0", "platform_bus", CCM_CCGR0, CCM_CCGRx_CGn(4));
|
||||
clk[VF610_CLK_DMAMUX1] = imx_clk_gate2("dmamux1", "platform_bus", CCM_CCGR0, CCM_CCGRx_CGn(5));
|
||||
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]);
|
||||
clk_set_rate(clk[VF610_CLK_QSPI0_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_SEL]) / 2);
|
||||
clk_set_rate(clk[VF610_CLK_QSPI0_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X4_DIV]) / 2);
|
||||
clk_set_rate(clk[VF610_CLK_QSPI0_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X2_DIV]) / 2);
|
||||
|
||||
clk_set_parent(clk[VF610_CLK_QSPI1_SEL], clk[VF610_CLK_PLL1_PFD4]);
|
||||
clk_set_rate(clk[VF610_CLK_QSPI1_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_SEL]) / 2);
|
||||
clk_set_rate(clk[VF610_CLK_QSPI1_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X4_DIV]) / 2);
|
||||
clk_set_rate(clk[VF610_CLK_QSPI1_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X2_DIV]) / 2);
|
||||
|
||||
clk_set_parent(clk[VF610_CLK_SAI0_SEL], clk[VF610_CLK_AUDIO_EXT]);
|
||||
clk_set_parent(clk[VF610_CLK_SAI1_SEL], clk[VF610_CLK_AUDIO_EXT]);
|
||||
clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]);
|
||||
clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
|
||||
clk_prepare_enable(clk[clks_init_on[i]]);
|
||||
|
||||
/* Add the clocks to provider list */
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(vf610, "fsl,vf610-ccm", vf610_clocks_init);
|
@@ -1,75 +0,0 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "clk.h"
|
||||
|
||||
DEFINE_SPINLOCK(imx_ccm_lock);
|
||||
|
||||
void __init imx_check_clocks(struct clk *clks[], unsigned int count)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (IS_ERR(clks[i]))
|
||||
pr_err("i.MX clk %u: register failed with %ld\n",
|
||||
i, PTR_ERR(clks[i]));
|
||||
}
|
||||
|
||||
static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name)
|
||||
{
|
||||
struct of_phandle_args phandle;
|
||||
struct clk *clk = ERR_PTR(-ENODEV);
|
||||
char *path;
|
||||
|
||||
path = kasprintf(GFP_KERNEL, "/clocks/%s", name);
|
||||
if (!path)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
phandle.np = of_find_node_by_path(path);
|
||||
kfree(path);
|
||||
|
||||
if (phandle.np) {
|
||||
clk = of_clk_get_from_provider(&phandle);
|
||||
of_node_put(phandle.np);
|
||||
}
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk * __init imx_obtain_fixed_clock(
|
||||
const char *name, unsigned long rate)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = imx_obtain_fixed_clock_from_dt(name);
|
||||
if (IS_ERR(clk))
|
||||
clk = imx_clk_fixed(name, rate);
|
||||
return clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* This fixups the register CCM_CSCMR1 write value.
|
||||
* The write/read/divider values of the aclk_podf field
|
||||
* of that register have the relationship described by
|
||||
* the following table:
|
||||
*
|
||||
* write value read value divider
|
||||
* 3b'000 3b'110 7
|
||||
* 3b'001 3b'111 8
|
||||
* 3b'010 3b'100 5
|
||||
* 3b'011 3b'101 6
|
||||
* 3b'100 3b'010 3
|
||||
* 3b'101 3b'011 4
|
||||
* 3b'110 3b'000 1
|
||||
* 3b'111 3b'001 2(default)
|
||||
*
|
||||
* That's why we do the xor operation below.
|
||||
*/
|
||||
#define CSCMR1_FIXUP 0x00600000
|
||||
|
||||
void imx_cscmr1_fixup(u32 *val)
|
||||
{
|
||||
*val ^= CSCMR1_FIXUP;
|
||||
return;
|
||||
}
|
@@ -1,139 +0,0 @@
|
||||
#ifndef __MACH_IMX_CLK_H
|
||||
#define __MACH_IMX_CLK_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
extern spinlock_t imx_ccm_lock;
|
||||
|
||||
void imx_check_clocks(struct clk *clks[], unsigned int count);
|
||||
|
||||
extern void imx_cscmr1_fixup(u32 *val);
|
||||
|
||||
struct clk *imx_clk_pllv1(const char *name, const char *parent,
|
||||
void __iomem *base);
|
||||
|
||||
struct clk *imx_clk_pllv2(const char *name, const char *parent,
|
||||
void __iomem *base);
|
||||
|
||||
enum imx_pllv3_type {
|
||||
IMX_PLLV3_GENERIC,
|
||||
IMX_PLLV3_SYS,
|
||||
IMX_PLLV3_USB,
|
||||
IMX_PLLV3_USB_VF610,
|
||||
IMX_PLLV3_AV,
|
||||
IMX_PLLV3_ENET,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
|
||||
const char *parent_name, void __iomem *base, u32 div_mask);
|
||||
|
||||
struct clk *clk_register_gate2(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx,
|
||||
u8 clk_gate_flags, spinlock_t *lock,
|
||||
unsigned int *share_count);
|
||||
|
||||
struct clk * imx_obtain_fixed_clock(
|
||||
const char *name, unsigned long rate);
|
||||
|
||||
struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u32 exclusive_mask);
|
||||
|
||||
static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift)
|
||||
{
|
||||
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, 0, &imx_ccm_lock, NULL);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_gate2_shared(const char *name,
|
||||
const char *parent, void __iomem *reg, u8 shift,
|
||||
unsigned int *share_count)
|
||||
{
|
||||
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, 0, &imx_ccm_lock, share_count);
|
||||
}
|
||||
|
||||
struct clk *imx_clk_pfd(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 idx);
|
||||
|
||||
struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
void __iomem *busy_reg, u8 busy_shift);
|
||||
|
||||
struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
|
||||
u8 width, void __iomem *busy_reg, u8 busy_shift,
|
||||
const char **parent_names, int num_parents);
|
||||
|
||||
struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
void (*fixup)(u32 *val));
|
||||
|
||||
struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents,
|
||||
int num_parents, void (*fixup)(u32 *val));
|
||||
|
||||
static inline struct clk *imx_clk_fixed(const char *name, int rate)
|
||||
{
|
||||
return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_divider(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u8 width)
|
||||
{
|
||||
return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_divider_flags(const char *name,
|
||||
const char *parent, void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_register_divider(NULL, name, parent, flags,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_gate(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift)
|
||||
{
|
||||
return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift)
|
||||
{
|
||||
return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents, int num_parents)
|
||||
{
|
||||
return clk_register_mux(NULL, name, parents, num_parents,
|
||||
CLK_SET_RATE_NO_REPARENT, reg, shift,
|
||||
width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_mux_flags(const char *name,
|
||||
void __iomem *reg, u8 shift, u8 width, const char **parents,
|
||||
int num_parents, unsigned long flags)
|
||||
{
|
||||
return clk_register_mux(NULL, name, parents, num_parents,
|
||||
flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0,
|
||||
&imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_fixed_factor(const char *name,
|
||||
const char *parent, unsigned int mult, unsigned int div)
|
||||
{
|
||||
return clk_register_fixed_factor(NULL, name, parent,
|
||||
CLK_SET_RATE_PARENT, mult, div);
|
||||
}
|
||||
|
||||
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
|
||||
struct clk *div, struct clk *mux, struct clk *pll,
|
||||
struct clk *step);
|
||||
|
||||
#endif
|
@@ -44,7 +44,6 @@ void imx27_soc_init(void);
|
||||
void imx31_soc_init(void);
|
||||
void imx35_soc_init(void);
|
||||
void epit_timer_init(void __iomem *base, int irq);
|
||||
void mxc_timer_init(void __iomem *, int);
|
||||
int mx1_clocks_init(unsigned long fref);
|
||||
int mx21_clocks_init(unsigned long lref, unsigned long fref);
|
||||
int mx27_clocks_init(unsigned long fref);
|
||||
@@ -56,13 +55,10 @@ struct platform_device *mxc_register_gpio(char *name, int id,
|
||||
void mxc_set_cpu_type(unsigned int type);
|
||||
void mxc_restart(enum reboot_mode, const char *);
|
||||
void mxc_arch_reset_init(void __iomem *);
|
||||
int mx51_revision(void);
|
||||
int mx53_revision(void);
|
||||
void imx_set_aips(void __iomem *);
|
||||
void imx_aips_allow_unprivileged_access(const char *compat);
|
||||
int mxc_device_init(void);
|
||||
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);
|
||||
@@ -87,7 +83,6 @@ enum mx3_cpu_pwr_mode {
|
||||
};
|
||||
|
||||
void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
|
||||
void imx_print_silicon_rev(const char *cpu, int srev);
|
||||
|
||||
void imx_enable_cpu(int cpu, bool enable);
|
||||
void imx_set_cpu_jump(int cpu, void *jump_addr);
|
||||
@@ -111,7 +106,7 @@ void imx_gpc_hwirq_unmask(unsigned int hwirq);
|
||||
void imx_anatop_init(void);
|
||||
void imx_anatop_pre_suspend(void);
|
||||
void imx_anatop_post_resume(void);
|
||||
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
|
||||
int imx6_set_lpm(enum mxc_cpu_pwr_mode mode);
|
||||
void imx6q_set_int_mem_clk_lpm(bool enable);
|
||||
void imx6sl_set_wait_clk(bool enter);
|
||||
int imx_mmdc_get_ddr_type(void);
|
||||
@@ -121,26 +116,28 @@ int imx_cpu_kill(unsigned int cpu);
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
void v7_cpu_resume(void);
|
||||
void imx53_suspend(void __iomem *ocram_vbase);
|
||||
extern const u32 imx53_suspend_sz;
|
||||
void imx6_suspend(void __iomem *ocram_vbase);
|
||||
#else
|
||||
static inline void v7_cpu_resume(void) {}
|
||||
static inline void imx53_suspend(void __iomem *ocram_vbase) {}
|
||||
static const u32 imx53_suspend_sz;
|
||||
static inline void imx6_suspend(void __iomem *ocram_vbase) {}
|
||||
#endif
|
||||
|
||||
void imx6_pm_ccm_init(const char *ccm_compat);
|
||||
void imx6q_pm_init(void);
|
||||
void imx6dl_pm_init(void);
|
||||
void imx6sl_pm_init(void);
|
||||
void imx6sx_pm_init(void);
|
||||
void imx6q_pm_set_ccm_base(void __iomem *base);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void imx51_pm_init(void);
|
||||
void imx53_pm_init(void);
|
||||
void imx5_pm_set_ccm_base(void __iomem *base);
|
||||
#else
|
||||
static inline void imx51_pm_init(void) {}
|
||||
static inline void imx53_pm_init(void) {}
|
||||
static inline void imx5_pm_set_ccm_base(void __iomem *base) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NEON
|
||||
|
@@ -130,6 +130,9 @@ struct device * __init imx_soc_device_init(void)
|
||||
case MXC_CPU_IMX6Q:
|
||||
soc_id = "i.MX6Q";
|
||||
break;
|
||||
case MXC_CPU_IMX7D:
|
||||
soc_id = "i.MX7D";
|
||||
break;
|
||||
default:
|
||||
soc_id = "Unknown";
|
||||
}
|
||||
|
@@ -27,9 +27,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev,
|
||||
*/
|
||||
if (!spin_trylock(&master_lock))
|
||||
goto idle;
|
||||
imx6q_set_lpm(WAIT_UNCLOCKED);
|
||||
imx6_set_lpm(WAIT_UNCLOCKED);
|
||||
cpu_do_idle();
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
imx6_set_lpm(WAIT_CLOCKED);
|
||||
spin_unlock(&master_lock);
|
||||
goto done;
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@
|
||||
static int imx6sl_enter_wait(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int index)
|
||||
{
|
||||
imx6q_set_lpm(WAIT_UNCLOCKED);
|
||||
imx6_set_lpm(WAIT_UNCLOCKED);
|
||||
/*
|
||||
* Software workaround for ERR005311, see function
|
||||
* description for details.
|
||||
@@ -24,7 +24,7 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev,
|
||||
imx6sl_set_wait_clk(true);
|
||||
cpu_do_idle();
|
||||
imx6sl_set_wait_clk(false);
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
imx6_set_lpm(WAIT_CLOCKED);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ static int imx6sx_idle_finish(unsigned long val)
|
||||
static int imx6sx_enter_wait(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int index)
|
||||
{
|
||||
imx6q_set_lpm(WAIT_UNCLOCKED);
|
||||
imx6_set_lpm(WAIT_UNCLOCKED);
|
||||
|
||||
switch (index) {
|
||||
case 1:
|
||||
@@ -50,7 +50,7 @@ static int imx6sx_enter_wait(struct cpuidle_device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
imx6_set_lpm(WAIT_CLOCKED);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
@@ -227,7 +227,7 @@ static int imx_gpc_domain_alloc(struct irq_domain *domain,
|
||||
return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops imx_gpc_domain_ops = {
|
||||
static const struct irq_domain_ops imx_gpc_domain_ops = {
|
||||
.xlate = imx_gpc_domain_xlate,
|
||||
.alloc = imx_gpc_domain_alloc,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
|
@@ -22,6 +22,7 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/io.h>
|
||||
#include <soc/imx/revision.h>
|
||||
#endif
|
||||
#include <asm/sizes.h>
|
||||
|
||||
|
@@ -40,7 +40,7 @@ static DEFINE_SPINLOCK(gpio_mux_lock);
|
||||
|
||||
#define IOMUX_REG_MASK (IOMUX_PADNUM_MASK & ~0x3)
|
||||
|
||||
static unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG];
|
||||
static DECLARE_BITMAP(mxc_pin_alloc_map, NB_PORTS * 32);
|
||||
/*
|
||||
* set the mode for a IOMUX pin.
|
||||
*/
|
||||
|
@@ -393,6 +393,7 @@ static void __init imx6q_init_irq(void)
|
||||
imx_init_l2cache();
|
||||
imx_src_init();
|
||||
irqchip_init();
|
||||
imx6_pm_ccm_init("fsl,imx6q-ccm");
|
||||
}
|
||||
|
||||
static const char * const imx6q_dt_compat[] __initconst = {
|
||||
|
@@ -66,6 +66,7 @@ static void __init imx6sl_init_irq(void)
|
||||
imx_init_l2cache();
|
||||
imx_src_init();
|
||||
irqchip_init();
|
||||
imx6_pm_ccm_init("fsl,imx6sl-ccm");
|
||||
}
|
||||
|
||||
static const char * const imx6sl_dt_compat[] __initconst = {
|
||||
|
@@ -86,6 +86,7 @@ static void __init imx6sx_init_irq(void)
|
||||
imx_init_l2cache();
|
||||
imx_src_init();
|
||||
irqchip_init();
|
||||
imx6_pm_ccm_init("fsl,imx6sx-ccm");
|
||||
}
|
||||
|
||||
static void __init imx6sx_init_late(void)
|
||||
|
43
arch/arm/mach-imx/mach-imx7d.c
Normal file
43
arch/arm/mach-imx/mach-imx7d.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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/irqchip.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void __init imx7d_init_machine(void)
|
||||
{
|
||||
struct device *parent;
|
||||
|
||||
parent = imx_soc_device_init();
|
||||
if (parent == NULL)
|
||||
pr_warn("failed to initialize soc device\n");
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
imx_anatop_init();
|
||||
}
|
||||
|
||||
static void __init imx7d_init_irq(void)
|
||||
{
|
||||
imx_init_revision_from_anatop();
|
||||
imx_src_init();
|
||||
irqchip_init();
|
||||
}
|
||||
|
||||
static const char *imx7d_dt_compat[] __initconst = {
|
||||
"fsl,imx7d",
|
||||
NULL,
|
||||
};
|
||||
|
||||
DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
|
||||
.init_irq = imx7d_init_irq,
|
||||
.init_machine = imx7d_init_machine,
|
||||
.dt_compat = imx7d_dt_compat,
|
||||
MACHINE_END
|
@@ -17,6 +17,7 @@ static const char * const vf610_dt_compat[] __initconst = {
|
||||
"fsl,vf510",
|
||||
"fsl,vf600",
|
||||
"fsl,vf610",
|
||||
"fsl,vf610m4",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@@ -17,6 +17,8 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MMDC_MAPSR 0x404
|
||||
#define BP_MMDC_MAPSR_PSD 0
|
||||
#define BP_MMDC_MAPSR_PSS 4
|
||||
|
@@ -231,8 +231,4 @@
|
||||
#define MX27_DMA_REQ_SDHC3 36
|
||||
#define MX27_DMA_REQ_NFC 37
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern int mx27_revision(void);
|
||||
#endif
|
||||
|
||||
#endif /* ifndef __MACH_MX27_H__ */
|
||||
|
@@ -185,11 +185,4 @@
|
||||
|
||||
#define MX3x_PROD_SIGNATURE 0x1 /* For MX31 */
|
||||
|
||||
/* Mandatory defines used globally */
|
||||
|
||||
#if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
|
||||
extern int mx35_revision(void);
|
||||
extern int mx31_revision(void);
|
||||
#endif
|
||||
|
||||
#endif /* ifndef __MACH_MX3x_H__ */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007, 2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
* Copyright 2004-2007, 2010-2015 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -38,22 +38,7 @@
|
||||
#define MXC_CPU_IMX6DL 0x61
|
||||
#define MXC_CPU_IMX6SX 0x62
|
||||
#define MXC_CPU_IMX6Q 0x63
|
||||
|
||||
#define IMX_CHIP_REVISION_1_0 0x10
|
||||
#define IMX_CHIP_REVISION_1_1 0x11
|
||||
#define IMX_CHIP_REVISION_1_2 0x12
|
||||
#define IMX_CHIP_REVISION_1_3 0x13
|
||||
#define IMX_CHIP_REVISION_1_4 0x14
|
||||
#define IMX_CHIP_REVISION_1_5 0x15
|
||||
#define IMX_CHIP_REVISION_2_0 0x20
|
||||
#define IMX_CHIP_REVISION_2_1 0x21
|
||||
#define IMX_CHIP_REVISION_2_2 0x22
|
||||
#define IMX_CHIP_REVISION_2_3 0x23
|
||||
#define IMX_CHIP_REVISION_3_0 0x30
|
||||
#define IMX_CHIP_REVISION_3_1 0x31
|
||||
#define IMX_CHIP_REVISION_3_2 0x32
|
||||
#define IMX_CHIP_REVISION_3_3 0x33
|
||||
#define IMX_CHIP_REVISION_UNKNOWN 0xff
|
||||
#define MXC_CPU_IMX7D 0x72
|
||||
|
||||
#define IMX_DDR_TYPE_LPDDR2 1
|
||||
|
||||
@@ -185,6 +170,11 @@ static inline bool cpu_is_imx6q(void)
|
||||
return __mxc_cpu_type == MXC_CPU_IMX6Q;
|
||||
}
|
||||
|
||||
static inline bool cpu_is_imx7d(void)
|
||||
{
|
||||
return __mxc_cpu_type == MXC_CPU_IMX7D;
|
||||
}
|
||||
|
||||
struct cpu_op {
|
||||
u32 cpu_rate;
|
||||
};
|
||||
|
@@ -13,7 +13,14 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/fncpy.h>
|
||||
#include <asm/system_misc.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
@@ -49,29 +56,91 @@
|
||||
*/
|
||||
#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
|
||||
|
||||
struct imx5_suspend_io_state {
|
||||
u32 offset;
|
||||
u32 clear;
|
||||
u32 set;
|
||||
u32 saved_value;
|
||||
};
|
||||
|
||||
struct imx5_pm_data {
|
||||
phys_addr_t ccm_addr;
|
||||
phys_addr_t cortex_addr;
|
||||
phys_addr_t gpc_addr;
|
||||
phys_addr_t m4if_addr;
|
||||
phys_addr_t iomuxc_addr;
|
||||
void (*suspend_asm)(void __iomem *ocram_vbase);
|
||||
const u32 *suspend_asm_sz;
|
||||
const struct imx5_suspend_io_state *suspend_io_config;
|
||||
int suspend_io_count;
|
||||
};
|
||||
|
||||
static const struct imx5_suspend_io_state imx53_suspend_io_config[] = {
|
||||
#define MX53_DSE_HIGHZ_MASK (0x7 << 19)
|
||||
{.offset = 0x584, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM0 */
|
||||
{.offset = 0x594, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM1 */
|
||||
{.offset = 0x560, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM2 */
|
||||
{.offset = 0x554, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM3 */
|
||||
{.offset = 0x574, .clear = MX53_DSE_HIGHZ_MASK}, /* CAS */
|
||||
{.offset = 0x588, .clear = MX53_DSE_HIGHZ_MASK}, /* RAS */
|
||||
{.offset = 0x578, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_0 */
|
||||
{.offset = 0x570, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_1 */
|
||||
|
||||
{.offset = 0x580, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT0 */
|
||||
{.offset = 0x564, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT1 */
|
||||
{.offset = 0x57c, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS0 */
|
||||
{.offset = 0x590, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS1 */
|
||||
{.offset = 0x568, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS2 */
|
||||
{.offset = 0x558, .clear = MX53_DSE_HIGHZ_MASK}, /* SDSQ3 */
|
||||
{.offset = 0x6f0, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_ADDS */
|
||||
{.offset = 0x718, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_BODS */
|
||||
{.offset = 0x71c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B1DS */
|
||||
{.offset = 0x728, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B2DS */
|
||||
{.offset = 0x72c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B3DS */
|
||||
|
||||
/* Controls the CKE signal which is required to leave self refresh */
|
||||
{.offset = 0x720, .clear = MX53_DSE_HIGHZ_MASK, .set = 1 << 19}, /* CTLDS */
|
||||
};
|
||||
|
||||
static const struct imx5_pm_data imx51_pm_data __initconst = {
|
||||
.ccm_addr = 0x73fd4000,
|
||||
.cortex_addr = 0x83fa0000,
|
||||
.gpc_addr = 0x73fd8000,
|
||||
};
|
||||
|
||||
static const struct imx5_pm_data imx53_pm_data __initconst = {
|
||||
.ccm_addr = 0x53fd4000,
|
||||
.cortex_addr = 0x63fa0000,
|
||||
.gpc_addr = 0x53fd8000,
|
||||
.m4if_addr = 0x63fd8000,
|
||||
.iomuxc_addr = 0x53fa8000,
|
||||
.suspend_asm = &imx53_suspend,
|
||||
.suspend_asm_sz = &imx53_suspend_sz,
|
||||
.suspend_io_config = imx53_suspend_io_config,
|
||||
.suspend_io_count = ARRAY_SIZE(imx53_suspend_io_config),
|
||||
};
|
||||
|
||||
#define MX5_MAX_SUSPEND_IOSTATE ARRAY_SIZE(imx53_suspend_io_config)
|
||||
|
||||
/*
|
||||
* This structure is for passing necessary data for low level ocram
|
||||
* suspend code(arch/arm/mach-imx/suspend-imx53.S), if this struct
|
||||
* definition is changed, the offset definition in that file
|
||||
* must be also changed accordingly otherwise, the suspend to ocram
|
||||
* function will be broken!
|
||||
*/
|
||||
struct imx5_cpu_suspend_info {
|
||||
void __iomem *m4if_base;
|
||||
void __iomem *iomuxc_base;
|
||||
u32 io_count;
|
||||
struct imx5_suspend_io_state io_state[MX5_MAX_SUSPEND_IOSTATE];
|
||||
} __aligned(8);
|
||||
|
||||
static void __iomem *ccm_base;
|
||||
static void __iomem *cortex_base;
|
||||
static void __iomem *gpc_base;
|
||||
|
||||
void __init imx5_pm_set_ccm_base(void __iomem *base)
|
||||
{
|
||||
ccm_base = base;
|
||||
}
|
||||
static void __iomem *suspend_ocram_base;
|
||||
static void (*imx5_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
|
||||
|
||||
/*
|
||||
* set cpu low power mode before WFI instruction. This function is called
|
||||
@@ -161,8 +230,15 @@ static int mx5_suspend_enter(suspend_state_t state)
|
||||
/*clear the EMPGC0/1 bits */
|
||||
__raw_writel(0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
|
||||
__raw_writel(0, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
|
||||
|
||||
if (imx5_suspend_in_ocram_fn)
|
||||
imx5_suspend_in_ocram_fn(suspend_ocram_base);
|
||||
else
|
||||
cpu_do_idle();
|
||||
|
||||
} else {
|
||||
cpu_do_idle();
|
||||
}
|
||||
cpu_do_idle();
|
||||
|
||||
/* return registers to default idle state */
|
||||
mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
|
||||
@@ -194,6 +270,111 @@ static void imx5_pm_idle(void)
|
||||
imx5_cpu_do_idle();
|
||||
}
|
||||
|
||||
static int __init imx_suspend_alloc_ocram(
|
||||
size_t size,
|
||||
void __iomem **virt_out,
|
||||
phys_addr_t *phys_out)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct platform_device *pdev;
|
||||
struct gen_pool *ocram_pool;
|
||||
unsigned long ocram_base;
|
||||
void __iomem *virt;
|
||||
phys_addr_t phys;
|
||||
int ret = 0;
|
||||
|
||||
/* Copied from imx6: TODO factorize */
|
||||
node = of_find_compatible_node(NULL, NULL, "mmio-sram");
|
||||
if (!node) {
|
||||
pr_warn("%s: failed to find ocram node!\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdev = of_find_device_by_node(node);
|
||||
if (!pdev) {
|
||||
pr_warn("%s: failed to find ocram device!\n", __func__);
|
||||
ret = -ENODEV;
|
||||
goto put_node;
|
||||
}
|
||||
|
||||
ocram_pool = dev_get_gen_pool(&pdev->dev);
|
||||
if (!ocram_pool) {
|
||||
pr_warn("%s: ocram pool unavailable!\n", __func__);
|
||||
ret = -ENODEV;
|
||||
goto put_node;
|
||||
}
|
||||
|
||||
ocram_base = gen_pool_alloc(ocram_pool, size);
|
||||
if (!ocram_base) {
|
||||
pr_warn("%s: unable to alloc ocram!\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto put_node;
|
||||
}
|
||||
|
||||
phys = gen_pool_virt_to_phys(ocram_pool, ocram_base);
|
||||
virt = __arm_ioremap_exec(phys, size, false);
|
||||
if (phys_out)
|
||||
*phys_out = phys;
|
||||
if (virt_out)
|
||||
*virt_out = virt;
|
||||
|
||||
put_node:
|
||||
of_node_put(node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init imx5_suspend_init(const struct imx5_pm_data *soc_data)
|
||||
{
|
||||
struct imx5_cpu_suspend_info *suspend_info;
|
||||
int ret;
|
||||
/* Need this to avoid compile error due to const typeof in fncpy.h */
|
||||
void (*suspend_asm)(void __iomem *) = soc_data->suspend_asm;
|
||||
|
||||
if (!suspend_asm)
|
||||
return 0;
|
||||
|
||||
if (!soc_data->suspend_asm_sz || !*soc_data->suspend_asm_sz)
|
||||
return -EINVAL;
|
||||
|
||||
ret = imx_suspend_alloc_ocram(
|
||||
*soc_data->suspend_asm_sz + sizeof(*suspend_info),
|
||||
&suspend_ocram_base, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
suspend_info = suspend_ocram_base;
|
||||
|
||||
suspend_info->io_count = soc_data->suspend_io_count;
|
||||
memcpy(suspend_info->io_state, soc_data->suspend_io_config,
|
||||
sizeof(*suspend_info->io_state) * soc_data->suspend_io_count);
|
||||
|
||||
suspend_info->m4if_base = ioremap(soc_data->m4if_addr, SZ_16K);
|
||||
if (!suspend_info->m4if_base) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_map_m4if;
|
||||
}
|
||||
|
||||
suspend_info->iomuxc_base = ioremap(soc_data->iomuxc_addr, SZ_16K);
|
||||
if (!suspend_info->iomuxc_base) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_map_iomuxc;
|
||||
}
|
||||
|
||||
imx5_suspend_in_ocram_fn = fncpy(
|
||||
suspend_ocram_base + sizeof(*suspend_info),
|
||||
suspend_asm,
|
||||
*soc_data->suspend_asm_sz);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_map_iomuxc:
|
||||
iounmap(suspend_info->m4if_base);
|
||||
|
||||
failed_map_m4if:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
|
||||
{
|
||||
int ret;
|
||||
@@ -208,6 +389,7 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
|
||||
|
||||
arm_pm_idle = imx5_pm_idle;
|
||||
|
||||
ccm_base = ioremap(data->ccm_addr, SZ_16K);
|
||||
cortex_base = ioremap(data->cortex_addr, SZ_16K);
|
||||
gpc_base = ioremap(data->gpc_addr, SZ_16K);
|
||||
WARN_ON(!ccm_base || !cortex_base || !gpc_base);
|
||||
@@ -219,6 +401,11 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
|
||||
if (ret)
|
||||
pr_warn("%s: cpuidle init failed %d\n", __func__, ret);
|
||||
|
||||
ret = imx5_suspend_init(data);
|
||||
if (ret)
|
||||
pr_warn("%s: No DDR LPM support with suspend %d!\n",
|
||||
__func__, ret);
|
||||
|
||||
suspend_set_ops(&mx5_suspend_ops);
|
||||
|
||||
return 0;
|
||||
@@ -226,10 +413,12 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
|
||||
|
||||
void __init imx51_pm_init(void)
|
||||
{
|
||||
imx5_pm_common_init(&imx51_pm_data);
|
||||
if (IS_ENABLED(CONFIG_SOC_IMX51))
|
||||
imx5_pm_common_init(&imx51_pm_data);
|
||||
}
|
||||
|
||||
void __init imx53_pm_init(void)
|
||||
{
|
||||
imx5_pm_common_init(&imx53_pm_data);
|
||||
if (IS_ENABLED(CONFIG_SOC_IMX53))
|
||||
imx5_pm_common_init(&imx53_pm_data);
|
||||
}
|
||||
|
@@ -255,7 +255,7 @@ static void imx6q_enable_wb(bool enable)
|
||||
writel_relaxed(val, ccm_base + CCR);
|
||||
}
|
||||
|
||||
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
|
||||
int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
|
||||
{
|
||||
u32 val = readl_relaxed(ccm_base + CLPCR);
|
||||
|
||||
@@ -340,7 +340,7 @@ static int imx6q_pm_enter(suspend_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case PM_SUSPEND_STANDBY:
|
||||
imx6q_set_lpm(STOP_POWER_ON);
|
||||
imx6_set_lpm(STOP_POWER_ON);
|
||||
imx6q_set_int_mem_clk_lpm(true);
|
||||
imx_gpc_pre_suspend(false);
|
||||
if (cpu_is_imx6sl())
|
||||
@@ -350,10 +350,10 @@ static int imx6q_pm_enter(suspend_state_t state)
|
||||
if (cpu_is_imx6sl())
|
||||
imx6sl_set_wait_clk(false);
|
||||
imx_gpc_post_resume();
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
imx6_set_lpm(WAIT_CLOCKED);
|
||||
break;
|
||||
case PM_SUSPEND_MEM:
|
||||
imx6q_set_lpm(STOP_POWER_OFF);
|
||||
imx6_set_lpm(STOP_POWER_OFF);
|
||||
imx6q_set_int_mem_clk_lpm(false);
|
||||
imx6q_enable_wb(true);
|
||||
/*
|
||||
@@ -373,7 +373,7 @@ static int imx6q_pm_enter(suspend_state_t state)
|
||||
imx6_enable_rbc(false);
|
||||
imx6q_enable_wb(false);
|
||||
imx6q_set_int_mem_clk_lpm(true);
|
||||
imx6q_set_lpm(WAIT_CLOCKED);
|
||||
imx6_set_lpm(WAIT_CLOCKED);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -392,11 +392,6 @@ static const struct platform_suspend_ops imx6q_pm_ops = {
|
||||
.valid = imx6q_pm_valid,
|
||||
};
|
||||
|
||||
void __init imx6q_pm_set_ccm_base(void __iomem *base)
|
||||
{
|
||||
ccm_base = base;
|
||||
}
|
||||
|
||||
static int __init imx6_pm_get_base(struct imx6_pm_base *base,
|
||||
const char *compat)
|
||||
{
|
||||
@@ -482,8 +477,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
|
||||
|
||||
/*
|
||||
* ccm physical address is not used by asm code currently,
|
||||
* so get ccm virtual address directly, as we already have
|
||||
* it from ccm driver.
|
||||
* so get ccm virtual address directly.
|
||||
*/
|
||||
pm_info->ccm_base.vbase = ccm_base;
|
||||
|
||||
@@ -568,7 +562,7 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata
|
||||
|
||||
/*
|
||||
* This is for SW workaround step #1 of ERR007265, see comments
|
||||
* in imx6q_set_lpm for details of this errata.
|
||||
* in imx6_set_lpm for details of this errata.
|
||||
* Force IOMUXC irq pending, so that the interrupt to GPC can be
|
||||
* used to deassert dsm_request signal when the signal gets
|
||||
* asserted unexpectedly.
|
||||
@@ -579,6 +573,24 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata
|
||||
IMX6Q_GPR1_GINT);
|
||||
}
|
||||
|
||||
void __init imx6_pm_ccm_init(const char *ccm_compat)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 val;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, ccm_compat);
|
||||
ccm_base = of_iomap(np, 0);
|
||||
BUG_ON(!ccm_base);
|
||||
|
||||
/*
|
||||
* Initialize CCM_CLPCR_LPM into RUN mode to avoid ARM core
|
||||
* clock being shut down unexpectedly by WAIT mode.
|
||||
*/
|
||||
val = readl_relaxed(ccm_base + CLPCR);
|
||||
val &= ~BM_CLPCR_LPM;
|
||||
writel_relaxed(val, ccm_base + CLPCR);
|
||||
}
|
||||
|
||||
void __init imx6q_pm_init(void)
|
||||
{
|
||||
imx6_pm_common_init(&imx6q_pm_data);
|
||||
|
139
arch/arm/mach-imx/suspend-imx53.S
Normal file
139
arch/arm/mach-imx/suspend-imx53.S
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#define M4IF_MCR0_OFFSET (0x008C)
|
||||
#define M4IF_MCR0_FDVFS (0x1 << 11)
|
||||
#define M4IF_MCR0_FDVACK (0x1 << 27)
|
||||
|
||||
.align 3
|
||||
|
||||
/*
|
||||
* ==================== low level suspend ====================
|
||||
*
|
||||
* On entry
|
||||
* r0: pm_info structure address;
|
||||
*
|
||||
* suspend ocram space layout:
|
||||
* ======================== high address ======================
|
||||
* .
|
||||
* .
|
||||
* .
|
||||
* ^
|
||||
* ^
|
||||
* ^
|
||||
* imx53_suspend code
|
||||
* PM_INFO structure(imx53_suspend_info)
|
||||
* ======================== low address =======================
|
||||
*/
|
||||
|
||||
/* Offsets of members of struct imx53_suspend_info */
|
||||
#define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0
|
||||
#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4
|
||||
#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8
|
||||
#define SUSPEND_INFO_MX53_IO_STATE_OFFSET 0xc
|
||||
|
||||
ENTRY(imx53_suspend)
|
||||
stmfd sp!, {r4,r5,r6,r7}
|
||||
|
||||
/* Save pad config */
|
||||
ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
|
||||
cmp r1, #0
|
||||
beq skip_pad_conf_1
|
||||
|
||||
add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
|
||||
ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
|
||||
|
||||
1:
|
||||
ldr r5, [r2], #12 /* IOMUXC register offset */
|
||||
ldr r6, [r3, r5] /* current value */
|
||||
str r6, [r2], #4 /* save area */
|
||||
subs r1, r1, #1
|
||||
bne 1b
|
||||
|
||||
skip_pad_conf_1:
|
||||
/* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */
|
||||
ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
|
||||
ldr r2,[r1, #M4IF_MCR0_OFFSET]
|
||||
orr r2, r2, #M4IF_MCR0_FDVFS
|
||||
str r2,[r1, #M4IF_MCR0_OFFSET]
|
||||
|
||||
/* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */
|
||||
wait_sr_ack:
|
||||
ldr r2,[r1, #M4IF_MCR0_OFFSET]
|
||||
ands r2, r2, #M4IF_MCR0_FDVACK
|
||||
beq wait_sr_ack
|
||||
|
||||
/* Set pad config */
|
||||
ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
|
||||
cmp r1, #0
|
||||
beq skip_pad_conf_2
|
||||
|
||||
add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
|
||||
ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
|
||||
|
||||
2:
|
||||
ldr r5, [r2], #4 /* IOMUXC register offset */
|
||||
ldr r6, [r2], #4 /* clear */
|
||||
ldr r7, [r3, r5]
|
||||
bic r7, r7, r6
|
||||
ldr r6, [r2], #8 /* set */
|
||||
orr r7, r7, r6
|
||||
str r7, [r3, r5]
|
||||
subs r1, r1, #1
|
||||
bne 2b
|
||||
|
||||
skip_pad_conf_2:
|
||||
/* Zzz, enter stop mode */
|
||||
wfi
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
/* Restore pad config */
|
||||
ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
|
||||
cmp r1, #0
|
||||
beq skip_pad_conf_3
|
||||
|
||||
add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
|
||||
ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
|
||||
|
||||
3:
|
||||
ldr r5, [r2], #12 /* IOMUXC register offset */
|
||||
ldr r6, [r2], #4 /* saved value */
|
||||
str r6, [r3, r5]
|
||||
subs r1, r1, #1
|
||||
bne 3b
|
||||
|
||||
skip_pad_conf_3:
|
||||
/* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */
|
||||
ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
|
||||
ldr r2,[r1, #M4IF_MCR0_OFFSET]
|
||||
bic r2, r2, #M4IF_MCR0_FDVFS
|
||||
str r2,[r1, #M4IF_MCR0_OFFSET]
|
||||
|
||||
/* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */
|
||||
wait_ar_ack:
|
||||
ldr r2,[r1, #M4IF_MCR0_OFFSET]
|
||||
ands r2, r2, #M4IF_MCR0_FDVACK
|
||||
bne wait_ar_ack
|
||||
|
||||
/* Restore registers */
|
||||
ldmfd sp!, {r4,r5,r6,r7}
|
||||
mov pc, lr
|
||||
|
||||
ENDPROC(imx53_suspend)
|
||||
|
||||
ENTRY(imx53_suspend_sz)
|
||||
.word . - imx53_suspend
|
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
* linux/arch/arm/plat-mxc/time.c
|
||||
*
|
||||
* Copyright (C) 2000-2001 Deep Blue Solutions
|
||||
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
|
||||
* Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
|
||||
* Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
/*
|
||||
* There are 2 versions of the timer hardware on Freescale MXC hardware.
|
||||
* Version 1: MX1/MXL, MX21, MX27.
|
||||
* Version 2: MX25, MX31, MX35, MX37, MX51
|
||||
*/
|
||||
|
||||
/* defines common for all i.MX */
|
||||
#define MXC_TCTL 0x00
|
||||
#define MXC_TCTL_TEN (1 << 0) /* Enable module */
|
||||
#define MXC_TPRER 0x04
|
||||
|
||||
/* MX1, MX21, MX27 */
|
||||
#define MX1_2_TCTL_CLK_PCLK1 (1 << 1)
|
||||
#define MX1_2_TCTL_IRQEN (1 << 4)
|
||||
#define MX1_2_TCTL_FRR (1 << 8)
|
||||
#define MX1_2_TCMP 0x08
|
||||
#define MX1_2_TCN 0x10
|
||||
#define MX1_2_TSTAT 0x14
|
||||
|
||||
/* MX21, MX27 */
|
||||
#define MX2_TSTAT_CAPT (1 << 1)
|
||||
#define MX2_TSTAT_COMP (1 << 0)
|
||||
|
||||
/* MX31, MX35, MX25, MX5, MX6 */
|
||||
#define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */
|
||||
#define V2_TCTL_CLK_IPG (1 << 6)
|
||||
#define V2_TCTL_CLK_PER (2 << 6)
|
||||
#define V2_TCTL_CLK_OSC_DIV8 (5 << 6)
|
||||
#define V2_TCTL_FRR (1 << 9)
|
||||
#define V2_TCTL_24MEN (1 << 10)
|
||||
#define V2_TPRER_PRE24M 12
|
||||
#define V2_IR 0x0c
|
||||
#define V2_TSTAT 0x08
|
||||
#define V2_TSTAT_OF1 (1 << 0)
|
||||
#define V2_TCN 0x24
|
||||
#define V2_TCMP 0x10
|
||||
|
||||
#define V2_TIMER_RATE_OSC_DIV8 3000000
|
||||
|
||||
#define timer_is_v1() (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
|
||||
#define timer_is_v2() (!timer_is_v1())
|
||||
|
||||
static struct clock_event_device clockevent_mxc;
|
||||
static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
|
||||
|
||||
static void __iomem *timer_base;
|
||||
|
||||
static inline void gpt_irq_disable(void)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
if (timer_is_v2())
|
||||
__raw_writel(0, timer_base + V2_IR);
|
||||
else {
|
||||
tmp = __raw_readl(timer_base + MXC_TCTL);
|
||||
__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gpt_irq_enable(void)
|
||||
{
|
||||
if (timer_is_v2())
|
||||
__raw_writel(1<<0, timer_base + V2_IR);
|
||||
else {
|
||||
__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
|
||||
timer_base + MXC_TCTL);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpt_irq_acknowledge(void)
|
||||
{
|
||||
if (timer_is_v1()) {
|
||||
if (cpu_is_mx1())
|
||||
__raw_writel(0, timer_base + MX1_2_TSTAT);
|
||||
else
|
||||
__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
|
||||
timer_base + MX1_2_TSTAT);
|
||||
} else if (timer_is_v2())
|
||||
__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
|
||||
}
|
||||
|
||||
static void __iomem *sched_clock_reg;
|
||||
|
||||
static u64 notrace mxc_read_sched_clock(void)
|
||||
{
|
||||
return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
|
||||
}
|
||||
|
||||
static struct delay_timer imx_delay_timer;
|
||||
|
||||
static unsigned long imx_read_current_timer(void)
|
||||
{
|
||||
return __raw_readl(sched_clock_reg);
|
||||
}
|
||||
|
||||
static int __init mxc_clocksource_init(struct clk *timer_clk)
|
||||
{
|
||||
unsigned int c = clk_get_rate(timer_clk);
|
||||
void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
|
||||
|
||||
imx_delay_timer.read_current_timer = &imx_read_current_timer;
|
||||
imx_delay_timer.freq = c;
|
||||
register_current_timer_delay(&imx_delay_timer);
|
||||
|
||||
sched_clock_reg = reg;
|
||||
|
||||
sched_clock_register(mxc_read_sched_clock, 32, c);
|
||||
return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
|
||||
clocksource_mmio_readl_up);
|
||||
}
|
||||
|
||||
/* clock event */
|
||||
|
||||
static int mx1_2_set_next_event(unsigned long evt,
|
||||
struct clock_event_device *unused)
|
||||
{
|
||||
unsigned long tcmp;
|
||||
|
||||
tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
|
||||
|
||||
__raw_writel(tcmp, timer_base + MX1_2_TCMP);
|
||||
|
||||
return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
|
||||
-ETIME : 0;
|
||||
}
|
||||
|
||||
static int v2_set_next_event(unsigned long evt,
|
||||
struct clock_event_device *unused)
|
||||
{
|
||||
unsigned long tcmp;
|
||||
|
||||
tcmp = __raw_readl(timer_base + V2_TCN) + evt;
|
||||
|
||||
__raw_writel(tcmp, timer_base + V2_TCMP);
|
||||
|
||||
return evt < 0x7fffffff &&
|
||||
(int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
|
||||
-ETIME : 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char *clock_event_mode_label[] = {
|
||||
[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
|
||||
[CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
|
||||
[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
|
||||
[CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED",
|
||||
[CLOCK_EVT_MODE_RESUME] = "CLOCK_EVT_MODE_RESUME",
|
||||
};
|
||||
#endif /* DEBUG */
|
||||
|
||||
static void mxc_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* The timer interrupt generation is disabled at least
|
||||
* for enough time to call mxc_set_next_event()
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
/* Disable interrupt in GPT module */
|
||||
gpt_irq_disable();
|
||||
|
||||
if (mode != clockevent_mode) {
|
||||
/* Set event time into far-far future */
|
||||
if (timer_is_v2())
|
||||
__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
|
||||
timer_base + V2_TCMP);
|
||||
else
|
||||
__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
|
||||
timer_base + MX1_2_TCMP);
|
||||
|
||||
/* Clear pending interrupt */
|
||||
gpt_irq_acknowledge();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
|
||||
clock_event_mode_label[clockevent_mode],
|
||||
clock_event_mode_label[mode]);
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* Remember timer mode */
|
||||
clockevent_mode = mode;
|
||||
local_irq_restore(flags);
|
||||
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
|
||||
"supported for i.MX\n");
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
/*
|
||||
* Do not put overhead of interrupt enable/disable into
|
||||
* mxc_set_next_event(), the core has about 4 minutes
|
||||
* to call mxc_set_next_event() or shutdown clock after
|
||||
* mode switching
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
gpt_irq_enable();
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
/* Left event sources disabled, no more interrupts appear */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ handler for the timer
|
||||
*/
|
||||
static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = &clockevent_mxc;
|
||||
uint32_t tstat;
|
||||
|
||||
if (timer_is_v2())
|
||||
tstat = __raw_readl(timer_base + V2_TSTAT);
|
||||
else
|
||||
tstat = __raw_readl(timer_base + MX1_2_TSTAT);
|
||||
|
||||
gpt_irq_acknowledge();
|
||||
|
||||
evt->event_handler(evt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irqaction mxc_timer_irq = {
|
||||
.name = "i.MX Timer Tick",
|
||||
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
||||
.handler = mxc_timer_interrupt,
|
||||
};
|
||||
|
||||
static struct clock_event_device clockevent_mxc = {
|
||||
.name = "mxc_timer1",
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_mode = mxc_set_mode,
|
||||
.set_next_event = mx1_2_set_next_event,
|
||||
.rating = 200,
|
||||
};
|
||||
|
||||
static int __init mxc_clockevent_init(struct clk *timer_clk)
|
||||
{
|
||||
if (timer_is_v2())
|
||||
clockevent_mxc.set_next_event = v2_set_next_event;
|
||||
|
||||
clockevent_mxc.cpumask = cpumask_of(0);
|
||||
clockevents_config_and_register(&clockevent_mxc,
|
||||
clk_get_rate(timer_clk),
|
||||
0xff, 0xfffffffe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init _mxc_timer_init(int irq,
|
||||
struct clk *clk_per, struct clk *clk_ipg)
|
||||
{
|
||||
uint32_t tctl_val;
|
||||
|
||||
if (IS_ERR(clk_per)) {
|
||||
pr_err("i.MX timer: unable to get clk\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IS_ERR(clk_ipg))
|
||||
clk_prepare_enable(clk_ipg);
|
||||
|
||||
clk_prepare_enable(clk_per);
|
||||
|
||||
/*
|
||||
* Initialise to a known state (all timers off, and timing reset)
|
||||
*/
|
||||
|
||||
__raw_writel(0, timer_base + MXC_TCTL);
|
||||
__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
|
||||
|
||||
if (timer_is_v2()) {
|
||||
tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
|
||||
if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) {
|
||||
tctl_val |= V2_TCTL_CLK_OSC_DIV8;
|
||||
if (cpu_is_imx6dl() || cpu_is_imx6sx()) {
|
||||
/* 24 / 8 = 3 MHz */
|
||||
__raw_writel(7 << V2_TPRER_PRE24M,
|
||||
timer_base + MXC_TPRER);
|
||||
tctl_val |= V2_TCTL_24MEN;
|
||||
}
|
||||
} else {
|
||||
tctl_val |= V2_TCTL_CLK_PER;
|
||||
}
|
||||
} else {
|
||||
tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
|
||||
}
|
||||
|
||||
__raw_writel(tctl_val, timer_base + MXC_TCTL);
|
||||
|
||||
/* init and register the timer to the framework */
|
||||
mxc_clocksource_init(clk_per);
|
||||
mxc_clockevent_init(clk_per);
|
||||
|
||||
/* Make irqs happen */
|
||||
setup_irq(irq, &mxc_timer_irq);
|
||||
}
|
||||
|
||||
void __init mxc_timer_init(void __iomem *base, int irq)
|
||||
{
|
||||
struct clk *clk_per = clk_get_sys("imx-gpt.0", "per");
|
||||
struct clk *clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
|
||||
|
||||
timer_base = base;
|
||||
|
||||
_mxc_timer_init(irq, clk_per, clk_ipg);
|
||||
}
|
||||
|
||||
static void __init mxc_timer_init_dt(struct device_node *np)
|
||||
{
|
||||
struct clk *clk_per, *clk_ipg;
|
||||
int irq;
|
||||
|
||||
if (timer_base)
|
||||
return;
|
||||
|
||||
timer_base = of_iomap(np, 0);
|
||||
WARN_ON(!timer_base);
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
|
||||
clk_ipg = of_clk_get_by_name(np, "ipg");
|
||||
|
||||
/* Try osc_per first, and fall back to per otherwise */
|
||||
clk_per = of_clk_get_by_name(np, "osc_per");
|
||||
if (IS_ERR(clk_per))
|
||||
clk_per = of_clk_get_by_name(np, "per");
|
||||
|
||||
_mxc_timer_init(irq, clk_per, clk_ipg);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(mx1_timer, "fsl,imx1-gpt", mxc_timer_init_dt);
|
||||
CLOCKSOURCE_OF_DECLARE(mx25_timer, "fsl,imx25-gpt", mxc_timer_init_dt);
|
||||
CLOCKSOURCE_OF_DECLARE(mx50_timer, "fsl,imx50-gpt", mxc_timer_init_dt);
|
||||
CLOCKSOURCE_OF_DECLARE(mx51_timer, "fsl,imx51-gpt", mxc_timer_init_dt);
|
||||
CLOCKSOURCE_OF_DECLARE(mx53_timer, "fsl,imx53-gpt", mxc_timer_init_dt);
|
||||
CLOCKSOURCE_OF_DECLARE(mx6q_timer, "fsl,imx6q-gpt", mxc_timer_init_dt);
|
||||
CLOCKSOURCE_OF_DECLARE(mx6sl_timer, "fsl,imx6sl-gpt", mxc_timer_init_dt);
|
||||
CLOCKSOURCE_OF_DECLARE(mx6sx_timer, "fsl,imx6sx-gpt", mxc_timer_init_dt);
|
Reference in New Issue
Block a user