From: Matt Wagantall <mattw@xxxxxxxxxxxxxx> The generic 'clock-local' driver is introduced to facilitate sharing of common code among local clock drivers for different SoCs. Presently, only 7x30 makes use of this driver. SoC-independent code is implemented in clock-local.c, while SoC-specific code is implemented in other clock-* files (ex. clock-7x30.c). Reviewed-by: Saravana Kannan <skannan@xxxxxxxxxxxxxx> Signed-off-by: Matt Wagantall <mattw@xxxxxxxxxxxxxx> Signed-off-by: Stephen Boyd <sboyd@xxxxxxxxxxxxxx> --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/clock-7x30.c | 1462 +++++++++++++-------------------------- arch/arm/mach-msm/clock-7x30.h | 230 +++---- arch/arm/mach-msm/clock-local.c | 679 ++++++++++++++++++ arch/arm/mach-msm/clock-local.h | 232 +++++++ 5 files changed, 1516 insertions(+), 1088 deletions(-) create mode 100644 arch/arm/mach-msm/clock-local.c create mode 100644 arch/arm/mach-msm/clock-local.h diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8588b57..33f0c39 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -2,6 +2,7 @@ obj-y += io.o idle.o timer.o ifdef CONFIG_MSM_PROC_COMM obj-$(CONFIG_DEBUG_FS) += clock-debug.o endif +obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o obj-$(CONFIG_ARCH_MSM7X30) += clock-7x30.o ifndef CONFIG_ARCH_MSM8X60 obj-y += acpuclock-arm11.o diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c index beca3a6..0637bee 100644 --- a/arch/arm/mach-msm/clock-7x30.c +++ b/arch/arm/mach-msm/clock-7x30.c @@ -29,16 +29,13 @@ #include <mach/clk.h> #include "clock.h" +#include "clock-local.h" #include "clock-7x30.h" #include "clock-pcom.h" #include "proc_comm.h" -#define REG_BASE(off) (MSM_CLK_CTL_BASE + off) -#define REG(off) (MSM_CLK_CTL_SH2_BASE + off) -#define MNCNTR_EN_MASK B(8) -#define MNCNTR_RST_MASK B(7) -#define MNCNTR_MODE_MASK BM(6, 5) -#define MNCNTR_MODE BVAL(6, 5, 0x2) /* Dual-edge mode. */ +#define REG_BASE(off) (MSM_CLK_CTL_BASE + (off)) +#define REG(off) (MSM_CLK_CTL_SH2_BASE + (off)) /* Shadow-region 2 (SH2) registers. */ #define QUP_I2C_NS_REG REG(0x04F0) @@ -106,1142 +103,597 @@ #define SH2_OWN_ROW1_BASE_REG REG_BASE(0x041C) #define SH2_OWN_ROW2_BASE_REG REG_BASE(0x0424) -struct clk_freq_tbl { - uint32_t freq_hz; - uint32_t src; - uint32_t md_val; - uint32_t ns_val; - uint32_t mode; - unsigned msmc1; -}; - -struct clk_local { - uint32_t count; - uint32_t type; - void __iomem *md_reg; - void __iomem *ns_reg; - uint32_t freq_mask; - uint32_t br_en_mask; - uint32_t root_en_mask; - int parent; - uint32_t *children; - const struct clk_freq_tbl *freq_tbl; - const struct clk_freq_tbl *current_freq; - void __iomem *halt_reg; - uint32_t halt_mask; - uint32_t test_vector; -}; - - -enum { - SRC_PLL0 = 4, /* Modem PLL */ - SRC_PLL1 = 1, /* Global PLL */ - SRC_PLL3 = 3, /* Multimedia/Peripheral PLL or Backup PLL1 */ - SRC_PLL4 = 2, /* Display PLL */ - SRC_LPXO = 6, /* Low power XO. */ - SRC_TCXO = 0, /* Used for sources that always source from tcxo */ - SRC_AXI = 100, /* Used for rates that sync to AXI */ - SRC_NONE /* Used for sources that can't be turned on/off. */ -}; - -static uint32_t src_pll_tbl[] = { - [SRC_PLL0] = PLL_0, - [SRC_PLL1] = PLL_1, - [SRC_PLL3] = PLL_3, - [SRC_PLL4] = PLL_4, -}; - -#define B(x) BIT(x) -#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) -#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb)) +/* MUX source input identifiers. */ +#define SRC_SEL_PLL0 4 /* Modem PLL */ +#define SRC_SEL_PLL1 1 /* Global PLL */ +#define SRC_SEL_PLL3 3 /* Multimedia/Peripheral PLL or Backup PLL1 */ +#define SRC_SEL_PLL4 2 /* Display PLL */ +#define SRC_SEL_LPXO 6 /* Low-power XO */ +#define SRC_SEL_TCXO 0 /* Used for sources that always source from TCXO */ +#define SRC_SEL_AXI 0 /* Used for rates that sync to AXI */ + +/* Source name to PLL mappings. */ +#define SRC_PLL0 PLL_0 +#define SRC_PLL1 PLL_1 +#define SRC_PLL3 PLL_3 +#define SRC_PLL4 PLL_4 +#define SRC_LPXO LPXO +#define SRC_TCXO TCXO +#define SRC_AXI AXI + +/* Clock declaration macros. */ +#define MN_MODE_DUAL_EDGE 0x2 #define MD8(m, n) (BVAL(15, 8, m) | BVAL(7, 0, ~(n))) -#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m))) +#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m)) | BVAL(6, 5, \ + (MN_MODE_DUAL_EDGE * !!(n)))) #define MD16(m, n) (BVAL(31, 16, m) | BVAL(15, 0, ~(n))) -#define N16(m, n) (BVAL(31, 16, ~(n-m))) +#define N16(m, n) (BVAL(31, 16, ~(n-m)) | BVAL(6, 5, \ + (MN_MODE_DUAL_EDGE * !!(n)))) #define SPDIV(s, d) (BVAL(4, 3, d-1) | BVAL(2, 0, s)) #define SDIV(s, d) (BVAL(6, 3, d-1) | BVAL(2, 0, s)) #define F_MASK_BASIC (BM(6, 3)|BM(2, 0)) -#define F_MASK_MND16 (BM(31, 16)|BM(4, 3)|BM(2, 0)) -#define F_MASK_MND8(m, l) (BM(m, l)|BM(4, 3)|BM(2, 0)) - -#define F_RAW(f, s, m_v, n_v, mde, v) { \ - .freq_hz = f, \ - .src = s, \ - .md_val = m_v, \ - .ns_val = n_v, \ - .mode = mde, \ - .msmc1 = v \ - } +#define F_MASK_MND16 (BM(31, 16)|BM(6, 5)|BM(4, 3)|BM(2, 0)) +#define F_MASK_MND8(m, l) (BM(m, l)|BM(6, 5)|BM(4, 3)|BM(2, 0)) -#define FREQ_END 0 -#define F_BASIC(f, s, div, v) F_RAW(f, s, 0, SDIV(s, div), 0, v) +/* + * Clock frequency definitions and macros + */ +#define F_BASIC(f, s, div, v) \ + F_RAW(f, SRC_##s, 0, SDIV(SRC_SEL_##s, div), 0, 0, v, NULL) #define F_MND16(f, s, div, m, n, v) \ - F_RAW(f, s, MD16(m, n), N16(m, n)|SPDIV(s, div), !!(n), v) + F_RAW(f, SRC_##s, MD16(m, n), N16(m, n)|SPDIV(SRC_SEL_##s, div), \ + 0, (B(8) * !!(n)), v, NULL) #define F_MND8(f, nmsb, nlsb, s, div, m, n, v) \ - F_RAW(f, s, MD8(m, n), N8(nmsb, nlsb, m, n)|SPDIV(s, div), !!(n), v) -#define F_END F_RAW(FREQ_END, SRC_NONE, 0, 0, 0, MSMC1_END) - -static const struct clk_freq_tbl clk_tbl_csi[] = { - F_MND8(153600000, 24, 17, SRC_PLL1, 2, 2, 5, NOMINAL), - F_MND8(192000000, 24, 17, SRC_PLL1, 4, 0, 0, NOMINAL), - F_MND8(384000000, 24, 17, SRC_PLL1, 2, 0, 0, NOMINAL), + F_RAW(f, SRC_##s, MD8(m, n), \ + N8(nmsb, nlsb, m, n)|SPDIV(SRC_SEL_##s, div), 0, \ + (B(8) * !!(n)), v, NULL) + +static struct clk_freq_tbl clk_tbl_csi[] = { + F_MND8(153600000, 24, 17, PLL1, 2, 2, 5, NOMINAL), + F_MND8(192000000, 24, 17, PLL1, 4, 0, 0, NOMINAL), + F_MND8(384000000, 24, 17, PLL1, 2, 0, 0, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_tcxo[] = { - F_RAW(19200000, SRC_TCXO, 0, 0, 0, NOMINAL), +static struct clk_freq_tbl clk_tbl_tcxo[] = { + F_RAW(19200000, SRC_TCXO, 0, 0, 0, 0, NOMINAL, NULL), F_END, }; -static const struct clk_freq_tbl clk_tbl_axi[] = { - F_RAW(1, SRC_AXI, 0, 0, 0, NOMINAL), +static struct clk_freq_tbl clk_tbl_axi[] = { + F_RAW(1, SRC_AXI, 0, 0, 0, 0, NOMINAL, NULL), F_END, }; -static const struct clk_freq_tbl clk_tbl_uartdm[] = { - F_MND16( 3686400, SRC_PLL3, 3, 3, 200, NOMINAL), - F_MND16( 7372800, SRC_PLL3, 3, 3, 100, NOMINAL), - F_MND16(14745600, SRC_PLL3, 3, 3, 50, NOMINAL), - F_MND16(32000000, SRC_PLL3, 3, 25, 192, NOMINAL), - F_MND16(40000000, SRC_PLL3, 3, 125, 768, NOMINAL), - F_MND16(46400000, SRC_PLL3, 3, 145, 768, NOMINAL), - F_MND16(48000000, SRC_PLL3, 3, 25, 128, NOMINAL), - F_MND16(51200000, SRC_PLL3, 3, 5, 24, NOMINAL), - F_MND16(56000000, SRC_PLL3, 3, 175, 768, NOMINAL), - F_MND16(58982400, SRC_PLL3, 3, 6, 25, NOMINAL), - F_MND16(64000000, SRC_PLL1, 4, 1, 3, NOMINAL), +static struct clk_freq_tbl clk_tbl_uartdm[] = { + F_MND16( 3686400, PLL3, 3, 3, 200, NOMINAL), + F_MND16( 7372800, PLL3, 3, 3, 100, NOMINAL), + F_MND16(14745600, PLL3, 3, 3, 50, NOMINAL), + F_MND16(32000000, PLL3, 3, 25, 192, NOMINAL), + F_MND16(40000000, PLL3, 3, 125, 768, NOMINAL), + F_MND16(46400000, PLL3, 3, 145, 768, NOMINAL), + F_MND16(48000000, PLL3, 3, 25, 128, NOMINAL), + F_MND16(51200000, PLL3, 3, 5, 24, NOMINAL), + F_MND16(56000000, PLL3, 3, 175, 768, NOMINAL), + F_MND16(58982400, PLL3, 3, 6, 25, NOMINAL), + F_MND16(64000000, PLL1, 4, 1, 3, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_mdh[] = { - F_BASIC( 49150000, SRC_PLL3, 15, NOMINAL), - F_BASIC( 92160000, SRC_PLL3, 8, NOMINAL), - F_BASIC(122880000, SRC_PLL3, 6, NOMINAL), - F_BASIC(184320000, SRC_PLL3, 4, NOMINAL), - F_BASIC(245760000, SRC_PLL3, 3, NOMINAL), - F_BASIC(368640000, SRC_PLL3, 2, NOMINAL), - F_BASIC(384000000, SRC_PLL1, 2, NOMINAL), - F_BASIC(445500000, SRC_PLL4, 2, NOMINAL), +static struct clk_freq_tbl clk_tbl_mdh[] = { + F_BASIC( 49150000, PLL3, 15, NOMINAL), + F_BASIC( 92160000, PLL3, 8, NOMINAL), + F_BASIC(122880000, PLL3, 6, NOMINAL), + F_BASIC(184320000, PLL3, 4, NOMINAL), + F_BASIC(245760000, PLL3, 3, NOMINAL), + F_BASIC(368640000, PLL3, 2, NOMINAL), + F_BASIC(384000000, PLL1, 2, NOMINAL), + F_BASIC(445500000, PLL4, 2, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_grp[] = { - F_BASIC( 24576000, SRC_LPXO, 1, NOMINAL), - F_BASIC( 46080000, SRC_PLL3, 16, NOMINAL), - F_BASIC( 49152000, SRC_PLL3, 15, NOMINAL), - F_BASIC( 52662875, SRC_PLL3, 14, NOMINAL), - F_BASIC( 56713846, SRC_PLL3, 13, NOMINAL), - F_BASIC( 61440000, SRC_PLL3, 12, NOMINAL), - F_BASIC( 67025454, SRC_PLL3, 11, NOMINAL), - F_BASIC( 73728000, SRC_PLL3, 10, NOMINAL), - F_BASIC( 81920000, SRC_PLL3, 9, NOMINAL), - F_BASIC( 92160000, SRC_PLL3, 8, NOMINAL), - F_BASIC(105325714, SRC_PLL3, 7, NOMINAL), - F_BASIC(122880000, SRC_PLL3, 6, NOMINAL), - F_BASIC(147456000, SRC_PLL3, 5, NOMINAL), - F_BASIC(184320000, SRC_PLL3, 4, NOMINAL), - F_BASIC(192000000, SRC_PLL1, 4, NOMINAL), - F_BASIC(245760000, SRC_PLL3, 3, HIGH), +static struct clk_freq_tbl clk_tbl_grp[] = { + F_BASIC( 24576000, LPXO, 1, NOMINAL), + F_BASIC( 46080000, PLL3, 16, NOMINAL), + F_BASIC( 49152000, PLL3, 15, NOMINAL), + F_BASIC( 52662875, PLL3, 14, NOMINAL), + F_BASIC( 56713846, PLL3, 13, NOMINAL), + F_BASIC( 61440000, PLL3, 12, NOMINAL), + F_BASIC( 67025454, PLL3, 11, NOMINAL), + F_BASIC( 73728000, PLL3, 10, NOMINAL), + F_BASIC( 81920000, PLL3, 9, NOMINAL), + F_BASIC( 92160000, PLL3, 8, NOMINAL), + F_BASIC(105325714, PLL3, 7, NOMINAL), + F_BASIC(122880000, PLL3, 6, NOMINAL), + F_BASIC(147456000, PLL3, 5, NOMINAL), + F_BASIC(184320000, PLL3, 4, NOMINAL), + F_BASIC(192000000, PLL1, 4, NOMINAL), + F_BASIC(245760000, PLL3, 3, HIGH), /* Sync to AXI. Hence this "rate" is not fixed. */ - F_RAW(1, SRC_AXI, 0, B(14), 0, NOMINAL), + F_RAW(1, SRC_AXI, 0, B(14), 0, 0, NOMINAL, NULL), F_END, }; -static const struct clk_freq_tbl clk_tbl_sdc1_3[] = { - F_MND8( 144000, 19, 12, SRC_LPXO, 1, 1, 171, NOMINAL), - F_MND8( 400000, 19, 12, SRC_LPXO, 1, 2, 123, NOMINAL), - F_MND8(16027000, 19, 12, SRC_PLL3, 3, 14, 215, NOMINAL), - F_MND8(17000000, 19, 12, SRC_PLL3, 4, 19, 206, NOMINAL), - F_MND8(20480000, 19, 12, SRC_PLL3, 4, 23, 212, NOMINAL), - F_MND8(24576000, 19, 12, SRC_LPXO, 1, 0, 0, NOMINAL), - F_MND8(49152000, 19, 12, SRC_PLL3, 3, 1, 5, NOMINAL), +static struct clk_freq_tbl clk_tbl_sdc1_3[] = { + F_MND8( 144000, 19, 12, LPXO, 1, 1, 171, NOMINAL), + F_MND8( 400000, 19, 12, LPXO, 1, 2, 123, NOMINAL), + F_MND8(16027000, 19, 12, PLL3, 3, 14, 215, NOMINAL), + F_MND8(17000000, 19, 12, PLL3, 4, 19, 206, NOMINAL), + F_MND8(20480000, 19, 12, PLL3, 4, 23, 212, NOMINAL), + F_MND8(24576000, 19, 12, LPXO, 1, 0, 0, NOMINAL), + F_MND8(49152000, 19, 12, PLL3, 3, 1, 5, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_sdc2_4[] = { - F_MND8( 144000, 20, 13, SRC_LPXO, 1, 1, 171, NOMINAL), - F_MND8( 400000, 20, 13, SRC_LPXO, 1, 2, 123, NOMINAL), - F_MND8(16027000, 20, 13, SRC_PLL3, 3, 14, 215, NOMINAL), - F_MND8(17000000, 20, 13, SRC_PLL3, 4, 19, 206, NOMINAL), - F_MND8(20480000, 20, 13, SRC_PLL3, 4, 23, 212, NOMINAL), - F_MND8(24576000, 20, 13, SRC_LPXO, 1, 0, 0, NOMINAL), - F_MND8(49152000, 20, 13, SRC_PLL3, 3, 1, 5, NOMINAL), +static struct clk_freq_tbl clk_tbl_sdc2_4[] = { + F_MND8( 144000, 20, 13, LPXO, 1, 1, 171, NOMINAL), + F_MND8( 400000, 20, 13, LPXO, 1, 2, 123, NOMINAL), + F_MND8(16027000, 20, 13, PLL3, 3, 14, 215, NOMINAL), + F_MND8(17000000, 20, 13, PLL3, 4, 19, 206, NOMINAL), + F_MND8(20480000, 20, 13, PLL3, 4, 23, 212, NOMINAL), + F_MND8(24576000, 20, 13, LPXO, 1, 0, 0, NOMINAL), + F_MND8(49152000, 20, 13, PLL3, 3, 1, 5, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_mdp_core[] = { - F_BASIC( 46080000, SRC_PLL3, 16, NOMINAL), - F_BASIC( 49152000, SRC_PLL3, 15, NOMINAL), - F_BASIC( 52663000, SRC_PLL3, 14, NOMINAL), - F_BASIC( 92160000, SRC_PLL3, 8, NOMINAL), - F_BASIC(122880000, SRC_PLL3, 6, NOMINAL), - F_BASIC(147456000, SRC_PLL3, 5, NOMINAL), - F_BASIC(153600000, SRC_PLL1, 5, NOMINAL), - F_BASIC(192000000, SRC_PLL1, 4, HIGH), +static struct clk_freq_tbl clk_tbl_mdp_core[] = { + F_BASIC( 46080000, PLL3, 16, NOMINAL), + F_BASIC( 49152000, PLL3, 15, NOMINAL), + F_BASIC( 52663000, PLL3, 14, NOMINAL), + F_BASIC( 92160000, PLL3, 8, NOMINAL), + F_BASIC(122880000, PLL3, 6, NOMINAL), + F_BASIC(147456000, PLL3, 5, NOMINAL), + F_BASIC(153600000, PLL1, 5, NOMINAL), + F_BASIC(192000000, PLL1, 4, HIGH), F_END, }; -static const struct clk_freq_tbl clk_tbl_mdp_lcdc[] = { - F_MND16(24576000, SRC_LPXO, 1, 0, 0, NOMINAL), - F_MND16(30720000, SRC_PLL3, 4, 1, 6, NOMINAL), - F_MND16(32768000, SRC_PLL3, 3, 2, 15, NOMINAL), - F_MND16(40960000, SRC_PLL3, 2, 1, 9, NOMINAL), - F_MND16(73728000, SRC_PLL3, 2, 1, 5, NOMINAL), +static struct clk_freq_tbl clk_tbl_mdp_lcdc[] = { + F_MND16(24576000, LPXO, 1, 0, 0, NOMINAL), + F_MND16(30720000, PLL3, 4, 1, 6, NOMINAL), + F_MND16(32768000, PLL3, 3, 2, 15, NOMINAL), + F_MND16(40960000, PLL3, 2, 1, 9, NOMINAL), + F_MND16(73728000, PLL3, 2, 1, 5, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_mdp_vsync[] = { - F_RAW(24576000, SRC_LPXO, 0, 0, 0, NOMINAL), +static struct clk_freq_tbl clk_tbl_mdp_vsync[] = { + F_RAW(24576000, SRC_LPXO, 0, 0, 0, 0, NOMINAL, NULL), F_END, }; -static const struct clk_freq_tbl clk_tbl_mi2s_codec[] = { - F_MND16( 2048000, SRC_LPXO, 4, 1, 3, NOMINAL), - F_MND16(12288000, SRC_LPXO, 2, 0, 0, NOMINAL), +static struct clk_freq_tbl clk_tbl_mi2s_codec[] = { + F_MND16( 2048000, LPXO, 4, 1, 3, NOMINAL), + F_MND16(12288000, LPXO, 2, 0, 0, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_mi2s[] = { - F_MND16(12288000, SRC_LPXO, 2, 0, 0, NOMINAL), +static struct clk_freq_tbl clk_tbl_mi2s[] = { + F_MND16(12288000, LPXO, 2, 0, 0, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_midi[] = { - F_MND8(98304000, 19, 12, SRC_PLL3, 3, 2, 5, NOMINAL), +static struct clk_freq_tbl clk_tbl_midi[] = { + F_MND8(98304000, 19, 12, PLL3, 3, 2, 5, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_sdac[] = { - F_MND16( 256000, SRC_LPXO, 4, 1, 24, NOMINAL), - F_MND16( 352800, SRC_LPXO, 1, 147, 10240, NOMINAL), - F_MND16( 384000, SRC_LPXO, 4, 1, 16, NOMINAL), - F_MND16( 512000, SRC_LPXO, 4, 1, 12, NOMINAL), - F_MND16( 705600, SRC_LPXO, 1, 147, 5120, NOMINAL), - F_MND16( 768000, SRC_LPXO, 4, 1, 8, NOMINAL), - F_MND16(1024000, SRC_LPXO, 4, 1, 6, NOMINAL), - F_MND16(1411200, SRC_LPXO, 1, 147, 2560, NOMINAL), - F_MND16(1536000, SRC_LPXO, 4, 1, 4, NOMINAL), +static struct clk_freq_tbl clk_tbl_sdac[] = { + F_MND16( 256000, LPXO, 4, 1, 24, NOMINAL), + F_MND16( 352800, LPXO, 1, 147, 10240, NOMINAL), + F_MND16( 384000, LPXO, 4, 1, 16, NOMINAL), + F_MND16( 512000, LPXO, 4, 1, 12, NOMINAL), + F_MND16( 705600, LPXO, 1, 147, 5120, NOMINAL), + F_MND16( 768000, LPXO, 4, 1, 8, NOMINAL), + F_MND16(1024000, LPXO, 4, 1, 6, NOMINAL), + F_MND16(1411200, LPXO, 1, 147, 2560, NOMINAL), + F_MND16(1536000, LPXO, 4, 1, 4, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_tv[] = { - F_MND8(27000000, 23, 16, SRC_PLL4, 2, 2, 33, NOMINAL), - F_MND8(74250000, 23, 16, SRC_PLL4, 2, 1, 6, NOMINAL), +static struct clk_freq_tbl clk_tbl_tv[] = { + F_MND8(27000000, 23, 16, PLL4, 2, 2, 33, NOMINAL), + F_MND8(74250000, 23, 16, PLL4, 2, 1, 6, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_usb[] = { - F_MND8(60000000, 23, 16, SRC_PLL1, 2, 5, 32, NOMINAL), +static struct clk_freq_tbl clk_tbl_usb[] = { + F_MND8(60000000, 23, 16, PLL1, 2, 5, 32, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_vfe_jpeg[] = { - F_MND16( 36864000, SRC_PLL3, 4, 1, 5, NOMINAL), - F_MND16( 46080000, SRC_PLL3, 4, 1, 4, NOMINAL), - F_MND16( 61440000, SRC_PLL3, 4, 1, 3, NOMINAL), - F_MND16( 73728000, SRC_PLL3, 2, 1, 5, NOMINAL), - F_MND16( 81920000, SRC_PLL3, 3, 1, 3, NOMINAL), - F_MND16( 92160000, SRC_PLL3, 4, 1, 2, NOMINAL), - F_MND16( 98304000, SRC_PLL3, 3, 2, 5, NOMINAL), - F_MND16(105326000, SRC_PLL3, 2, 2, 7, NOMINAL), - F_MND16(122880000, SRC_PLL3, 2, 1, 3, NOMINAL), - F_MND16(147456000, SRC_PLL3, 2, 2, 5, NOMINAL), - F_MND16(153600000, SRC_PLL1, 2, 2, 5, NOMINAL), +static struct clk_freq_tbl clk_tbl_vfe_jpeg[] = { + F_MND16( 36864000, PLL3, 4, 1, 5, NOMINAL), + F_MND16( 46080000, PLL3, 4, 1, 4, NOMINAL), + F_MND16( 61440000, PLL3, 4, 1, 3, NOMINAL), + F_MND16( 73728000, PLL3, 2, 1, 5, NOMINAL), + F_MND16( 81920000, PLL3, 3, 1, 3, NOMINAL), + F_MND16( 92160000, PLL3, 4, 1, 2, NOMINAL), + F_MND16( 98304000, PLL3, 3, 2, 5, NOMINAL), + F_MND16(105326000, PLL3, 2, 2, 7, NOMINAL), + F_MND16(122880000, PLL3, 2, 1, 3, NOMINAL), + F_MND16(147456000, PLL3, 2, 2, 5, NOMINAL), + F_MND16(153600000, PLL1, 2, 2, 5, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_cam[] = { - F_MND16( 6000000, SRC_PLL1, 4, 1, 32, NOMINAL), - F_MND16( 8000000, SRC_PLL1, 4, 1, 24, NOMINAL), - F_MND16(12000000, SRC_PLL1, 4, 1, 16, NOMINAL), - F_MND16(16000000, SRC_PLL1, 4, 1, 12, NOMINAL), - F_MND16(19200000, SRC_PLL1, 4, 1, 10, NOMINAL), - F_MND16(24000000, SRC_PLL1, 4, 1, 8, NOMINAL), - F_MND16(32000000, SRC_PLL1, 4, 1, 6, NOMINAL), - F_MND16(48000000, SRC_PLL1, 4, 1, 4, NOMINAL), - F_MND16(64000000, SRC_PLL1, 4, 1, 3, NOMINAL), +static struct clk_freq_tbl clk_tbl_cam[] = { + F_MND16( 6000000, PLL1, 4, 1, 32, NOMINAL), + F_MND16( 8000000, PLL1, 4, 1, 24, NOMINAL), + F_MND16(12000000, PLL1, 4, 1, 16, NOMINAL), + F_MND16(16000000, PLL1, 4, 1, 12, NOMINAL), + F_MND16(19200000, PLL1, 4, 1, 10, NOMINAL), + F_MND16(24000000, PLL1, 4, 1, 8, NOMINAL), + F_MND16(32000000, PLL1, 4, 1, 6, NOMINAL), + F_MND16(48000000, PLL1, 4, 1, 4, NOMINAL), + F_MND16(64000000, PLL1, 4, 1, 3, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_vpe[] = { - F_MND8( 24576000, 22, 15, SRC_LPXO, 1, 0, 0, NOMINAL), - F_MND8( 30720000, 22, 15, SRC_PLL3, 4, 1, 6, NOMINAL), - F_MND8( 61440000, 22, 15, SRC_PLL3, 4, 1, 3, NOMINAL), - F_MND8( 81920000, 22, 15, SRC_PLL3, 3, 1, 3, NOMINAL), - F_MND8(122880000, 22, 15, SRC_PLL3, 3, 1, 2, NOMINAL), - F_MND8(147456000, 22, 15, SRC_PLL3, 1, 1, 5, NOMINAL), - F_MND8(153600000, 22, 15, SRC_PLL1, 1, 1, 5, NOMINAL), +static struct clk_freq_tbl clk_tbl_vpe[] = { + F_MND8( 24576000, 22, 15, LPXO, 1, 0, 0, NOMINAL), + F_MND8( 30720000, 22, 15, PLL3, 4, 1, 6, NOMINAL), + F_MND8( 61440000, 22, 15, PLL3, 4, 1, 3, NOMINAL), + F_MND8( 81920000, 22, 15, PLL3, 3, 1, 3, NOMINAL), + F_MND8(122880000, 22, 15, PLL3, 3, 1, 2, NOMINAL), + F_MND8(147456000, 22, 15, PLL3, 1, 1, 5, NOMINAL), + F_MND8(153600000, 22, 15, PLL1, 1, 1, 5, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_mfc[] = { - F_MND8( 24576000, 24, 17, SRC_LPXO, 1, 0, 0, NOMINAL), - F_MND8( 30720000, 24, 17, SRC_PLL3, 4, 1, 6, NOMINAL), - F_MND8( 61440000, 24, 17, SRC_PLL3, 4, 1, 3, NOMINAL), - F_MND8( 81920000, 24, 17, SRC_PLL3, 3, 1, 3, NOMINAL), - F_MND8(122880000, 24, 17, SRC_PLL3, 3, 1, 2, NOMINAL), - F_MND8(147456000, 24, 17, SRC_PLL3, 1, 1, 5, NOMINAL), - F_MND8(153600000, 24, 17, SRC_PLL1, 1, 1, 5, NOMINAL), - F_MND8(170667000, 24, 17, SRC_PLL1, 1, 2, 9, NOMINAL), +static struct clk_freq_tbl clk_tbl_mfc[] = { + F_MND8( 24576000, 24, 17, LPXO, 1, 0, 0, NOMINAL), + F_MND8( 30720000, 24, 17, PLL3, 4, 1, 6, NOMINAL), + F_MND8( 61440000, 24, 17, PLL3, 4, 1, 3, NOMINAL), + F_MND8( 81920000, 24, 17, PLL3, 3, 1, 3, NOMINAL), + F_MND8(122880000, 24, 17, PLL3, 3, 1, 2, NOMINAL), + F_MND8(147456000, 24, 17, PLL3, 1, 1, 5, NOMINAL), + F_MND8(153600000, 24, 17, PLL1, 1, 1, 5, NOMINAL), + F_MND8(170667000, 24, 17, PLL1, 1, 2, 9, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_spi[] = { - F_MND8( 9963243, 19, 12, SRC_PLL3, 4, 7, 129, NOMINAL), - F_MND8(26331429, 19, 12, SRC_PLL3, 4, 34, 241, NOMINAL), +static struct clk_freq_tbl clk_tbl_spi[] = { + F_MND8( 9963243, 19, 12, PLL3, 4, 7, 129, NOMINAL), + F_MND8(26331429, 19, 12, PLL3, 4, 34, 241, NOMINAL), F_END, }; -static const struct clk_freq_tbl clk_tbl_lpa_codec[] = { - F_RAW(1, SRC_NONE, 0, 0, 0, MSMC1_END), /* src = MI2S_CODEC_RX */ - F_RAW(2, SRC_NONE, 0, 1, 0, MSMC1_END), /* src = ECODEC_CIF */ - F_RAW(3, SRC_NONE, 0, 2, 0, MSMC1_END), /* src = MI2S */ - F_RAW(4, SRC_NONE, 0, 3, 0, MSMC1_END), /* src = SDAC */ +static struct clk_freq_tbl clk_tbl_lpa_codec[] = { + F_RAW(1, SRC_NONE, 0, 0, 0, 0, LOW, NULL), /* src = MI2S_CODEC_RX */ + F_RAW(2, SRC_NONE, 0, 1, 0, 0, LOW, NULL), /* src = ECODEC_CIF */ + F_RAW(3, SRC_NONE, 0, 2, 0, 0, LOW, NULL), /* src = MI2S */ + F_RAW(4, SRC_NONE, 0, 3, 0, 0, LOW, NULL), /* src = SDAC */ F_END, }; -static struct clk_freq_tbl dummy_freq = F_END; - -#define MND 1 /* Integer predivider and fractional MN:D divider. */ -#define BASIC 2 /* Integer divider. */ -#define NORATE 3 /* Just on/off. */ - -#define C(x) L_7X30_##x##_CLK - -#define CLK_LOCAL(id, t, md, ns, f_msk, br, root, tbl, \ - par, chld_lst, h, hm, tv) \ - [C(id)] = { \ - .type = t, \ - .md_reg = md, \ - .ns_reg = ns, \ - .freq_mask = f_msk, \ - .br_en_mask = br, \ - .root_en_mask = root, \ - .parent = C(par), \ - .children = chld_lst, \ - .freq_tbl = tbl, \ - .current_freq = &dummy_freq, \ - .halt_reg = h, \ - .halt_mask = hm, \ - .test_vector = tv, \ - } - -#define CLK_BASIC(id, ns, br, root, tbl, par, h, hm, tv) \ - CLK_LOCAL(id, BASIC, 0, ns, F_MASK_BASIC, br, root, tbl, \ - par, NULL, h, hm, tv) -#define CLK_MND8_P(id, ns, m, l, br, root, tbl, par, chld_lst, h, hm, tv) \ - CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND8(m, l), br, root, \ - tbl, par, chld_lst, h, hm, tv) -#define CLK_MND8(id, ns, m, l, br, root, tbl, chld_lst, h, hm, tv) \ - CLK_MND8_P(id, ns, m, l, br, root, tbl, NONE, chld_lst, \ - h, hm, tv) -#define CLK_MND16(id, ns, br, root, tbl, par, chld_lst, h, hm, tv) \ - CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND16, br, root, tbl, \ - par, chld_lst, h, hm, tv) -#define CLK_1RATE(id, ns, br, root, tbl, h, hm, tv) \ - CLK_LOCAL(id, BASIC, 0, ns, 0, br, root, tbl, NONE, NULL, \ - h, hm, tv) -#define CLK_SLAVE(id, ns, br, par, h, hm, tv) \ - CLK_LOCAL(id, NORATE, 0, ns, 0, br, 0, NULL, par, NULL, \ - h, hm, tv) -#define CLK_NORATE(id, ns, br, root, h, hm, tv) \ - CLK_LOCAL(id, NORATE, 0, ns, 0, br, root, NULL, NONE, NULL, \ - h, hm, tv) -#define CLK_GLBL(id, glbl, br, h, hm, tv) \ - CLK_LOCAL(id, NORATE, 0, glbl, 0, br, 0, NULL, GLBL_ROOT, \ - NULL, h, hm, tv) -#define CLK_BRIDGE(id, glbl, br, par, h, hm, tv) \ - CLK_LOCAL(id, NORATE, 0, glbl, 0, br, 0, NULL, par, NULL, \ - h, hm, tv) - -static uint32_t *pll_status_addr[NUM_PLL] = { - [PLL_0] = PLL0_STATUS_BASE_REG, - [PLL_1] = PLL1_STATUS_BASE_REG, - [PLL_2] = PLL2_STATUS_BASE_REG, - [PLL_3] = PLL3_STATUS_BASE_REG, - [PLL_4] = PLL4_STATUS_BASE_REG, - [PLL_5] = PLL5_STATUS_BASE_REG, - [PLL_6] = PLL6_STATUS_BASE_REG, -}; - -static uint32_t pll_count[NUM_PLL]; - -static uint32_t chld_grp_3d_src[] = {C(IMEM), C(GRP_3D), C(NONE)}; -static uint32_t chld_mdp_lcdc_p[] = {C(MDP_LCDC_PAD_PCLK), C(NONE)}; -static uint32_t chld_mfc[] = {C(MFC_DIV2), C(NONE)}; -static uint32_t chld_mi2s_codec_rx[] = {C(MI2S_CODEC_RX_S), C(NONE)}; -static uint32_t chld_mi2s_codec_tx[] = {C(MI2S_CODEC_TX_S), C(NONE)}; -static uint32_t chld_mi2s[] = {C(MI2S_S), C(NONE)}; -static uint32_t chld_sdac[] = {C(SDAC_M), C(NONE)}; -static uint32_t chld_tv[] = {C(TV_DAC), C(TV_ENC), C(TSIF_REF), - C(HDMI), C(NONE)}; -static uint32_t chld_usb_src[] = {C(USB_HS), C(USB_HS_CORE), +/* + * Clock children lists + */ +static const uint32_t chld_grp_3d_src[] = {C(IMEM), C(GRP_3D), C(NONE)}; +static const uint32_t chld_mdp_lcdc_p[] = {C(MDP_LCDC_PAD_PCLK), C(NONE)}; +static const uint32_t chld_mfc[] = {C(MFC_DIV2), C(NONE)}; +static const uint32_t chld_mi2s_codec_rx[] = {C(MI2S_CODEC_RX_S), C(NONE)}; +static const uint32_t chld_mi2s_codec_tx[] = {C(MI2S_CODEC_TX_S), C(NONE)}; +static const uint32_t chld_mi2s[] = {C(MI2S_S), C(NONE)}; +static const uint32_t chld_sdac[] = {C(SDAC_M), C(NONE)}; +static const uint32_t chld_tv[] = {C(TV_DAC), C(TV_ENC), C(HDMI), + C(TSIF_REF), C(NONE)}; +static const uint32_t chld_usb_src[] = {C(USB_HS), C(USB_HS_CORE), C(USB_HS2), C(USB_HS2_CORE), C(USB_HS3), C(USB_HS3_CORE), C(NONE)}; -static uint32_t chld_vfe[] = {C(VFE_MDC), C(VFE_CAMIF), C(CSI0_VFE), +static uint32_t const chld_vfe[] = {C(VFE_MDC), C(VFE_CAMIF), C(CSI0_VFE), C(NONE)}; -static struct clk_local clk_local_tbl[] = { +/* + * Clock declaration macros + */ +#define CLK_BASIC(id, ns, br, root, tbl, par, h_r, h_c, h_b, tv) \ + CLK(id, BASIC, ns, ns, NULL, NULL, 0, h_r, h_c, \ + h_b, br, root, F_MASK_BASIC, 0, set_rate_basic, tbl, \ + NULL, par, NULL, tv) +#define CLK_MND8_P(id, ns, m, l, br, root, tbl, par, chld_lst, \ + h_r, h_c, h_b, tv) \ + CLK(id, MND, ns, ns, (ns-4), NULL, 0, h_r, h_c, \ + h_b, br, root, F_MASK_MND8(m, l), 0, set_rate_mnd, \ + tbl, NULL, par, chld_lst, tv) +#define CLK_MND8(id, ns, m, l, br, root, tbl, chld_lst, h_r, h_c, h_b, tv) \ + CLK_MND8_P(id, ns, m, l, br, root, tbl, NONE, chld_lst, \ + h_r, h_c, h_b, tv) +#define CLK_MND16(id, ns, br, root, tbl, par, chld_lst, h_r, h_c, h_b, tv) \ + CLK(id, MND, ns, ns, (ns-4), NULL, 0, h_r, h_c, \ + h_b, br, root, F_MASK_MND16, 0, set_rate_mnd, tbl, \ + NULL, par, chld_lst, tv) +#define CLK_1RATE(id, ns, br, root, tbl, h_r, h_c, h_b, tv) \ + CLK(id, BASIC, NULL, ns, NULL, NULL, 0, h_r, h_c, \ + h_b, br, root, 0, 0, set_rate_nop, tbl, \ + NULL, NONE, NULL, tv) +#define CLK_SLAVE(id, ns, br, par, h_r, h_c, h_b, tv) \ + CLK(id, NORATE, NULL, ns, NULL, NULL, 0, h_r, h_c, \ + h_b, br, 0, 0, 0, NULL, NULL, NULL, par, NULL, tv) +#define CLK_NORATE(id, ns, br, root, h_r, h_c, h_b, tv) \ + CLK(id, NORATE, NULL, ns, NULL, NULL, 0, h_r, h_c, \ + h_b, br, root, 0, 0, NULL, NULL, NULL, NONE, NULL, tv) +#define CLK_GLBL(id, glbl, br, h_r, h_c, h_b, tv) \ + CLK(id, NORATE, NULL, glbl, NULL, NULL, 0, h_r, h_c, \ + h_b, br, 0, 0, 0, NULL, NULL, NULL, NONE, NULL, tv) +#define CLK_BRIDGE(id, glbl, br, par, h_r, h_c, h_b, tv) \ + CLK(id, NORATE, NULL, glbl, NULL, NULL, 0, h_r, h_c, \ + h_b, br, 0, 0, 0, NULL, NULL, NULL, par, NULL, tv) + +/* + * Clock table + */ +struct clk_local soc_clk_local_tbl[] = { CLK_NORATE(MDC, MDC_NS_REG, B(9), B(11), - CLK_HALT_STATEA_REG, 10, 0x4D56), + CLK_HALT_STATEA_REG, HALT, 10, 0x4D56), CLK_NORATE(LPA_CORE, LPA_NS_REG, B(5), 0, - CLK_HALT_STATEC_REG, 5, 0x0E), + CLK_HALT_STATEC_REG, HALT, 5, 0x0E), CLK_1RATE(I2C, I2C_NS_REG, B(9), B(11), clk_tbl_tcxo, - CLK_HALT_STATEA_REG, 15, 0x4D4D), + CLK_HALT_STATEA_REG, HALT, 15, 0x4D4D), CLK_1RATE(I2C_2, I2C_2_NS_REG, B(0), B(2), clk_tbl_tcxo, - CLK_HALT_STATEC_REG, 2, 0x0B), + CLK_HALT_STATEC_REG, HALT, 2, 0x0B), CLK_1RATE(QUP_I2C, QUP_I2C_NS_REG, B(0), B(2), clk_tbl_tcxo, - CLK_HALT_STATEB_REG, 31, 0x1C), + CLK_HALT_STATEB_REG, HALT, 31, 0x1C), CLK_1RATE(UART1, UART_NS_REG, B(5), B(4), clk_tbl_tcxo, - CLK_HALT_STATEB_REG, 7, 0x4D6F), + CLK_HALT_STATEB_REG, HALT, 7, 0x4D6F), CLK_1RATE(UART2, UART2_NS_REG, B(5), B(4), clk_tbl_tcxo, - CLK_HALT_STATEB_REG, 5, 0x4D71), + CLK_HALT_STATEB_REG, HALT, 5, 0x4D71), CLK_BASIC(EMDH, EMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A, - NULL, 0, 0x4F00), + NULL, DELAY, 0, 0x4F00), CLK_BASIC(PMDH, PMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A, - NULL, 0, 0x5500), + NULL, DELAY, 0, 0x5500), CLK_BASIC(MDP, MDP_NS_REG, B(9), B(11), clk_tbl_mdp_core, AXI_MDP, - CLK_HALT_STATEB_REG, 16, 0x5400), + CLK_HALT_STATEB_REG, HALT, 16, 0x5400), CLK_MND8_P(VPE, VPE_NS_REG, 22, 15, B(9), B(11), clk_tbl_vpe, - AXI_VPE, NULL, CLK_HALT_STATEC_REG, 10, 0x6C00), + AXI_VPE, NULL, CLK_HALT_STATEC_REG, HALT, 10, 0x6C00), CLK_MND8_P(MFC, MFC_NS_REG, 24, 17, B(9), B(11), clk_tbl_mfc, AXI_MFC, chld_mfc, CLK_HALT_STATEC_REG, - 12, 0x38), + HALT, 12, 0x38), CLK_SLAVE(MFC_DIV2, MFC_NS_REG, B(15), MFC, CLK_HALT_STATEC_REG, - 11, 0x1F), + HALT, 11, 0x1F), CLK_MND8(SDC1, SDCn_NS_REG(1), 19, 12, B(9), B(11), clk_tbl_sdc1_3, - NULL, CLK_HALT_STATEA_REG, 1, 0x4D62), + NULL, CLK_HALT_STATEA_REG, HALT, 1, 0x4D62), CLK_MND8(SDC2, SDCn_NS_REG(2), 20, 13, B(9), B(11), clk_tbl_sdc2_4, - NULL, CLK_HALT_STATEA_REG, 0, 0x4D64), + NULL, CLK_HALT_STATEA_REG, HALT, 0, 0x4D64), CLK_MND8(SDC3, SDCn_NS_REG(3), 19, 12, B(9), B(11), clk_tbl_sdc1_3, - NULL, CLK_HALT_STATEB_REG, 24, 0x4D7A), + NULL, CLK_HALT_STATEB_REG, HALT, 24, 0x4D7A), CLK_MND8(SDC4, SDCn_NS_REG(4), 20, 13, B(9), B(11), clk_tbl_sdc2_4, - NULL, CLK_HALT_STATEB_REG, 25, 0x4D7C), + NULL, CLK_HALT_STATEB_REG, HALT, 25, 0x4D7C), CLK_MND8(SPI, SPI_NS_REG, 19, 12, B(9), B(11), clk_tbl_spi, NULL, - CLK_HALT_STATEC_REG, 0, 0x09), + CLK_HALT_STATEC_REG, HALT, 0, 0x09), CLK_MND8(MIDI, MIDI_NS_REG, 19, 12, B(9), B(11), clk_tbl_midi, NULL, - CLK_HALT_STATEC_REG, 1, 0x0A), + CLK_HALT_STATEC_REG, HALT, 1, 0x0A), CLK_MND8_P(USB_HS_SRC, USBH_NS_REG, 23, 16, 0, B(11), clk_tbl_usb, - AXI_LI_ADSP_A, chld_usb_src, NULL, 0, 0), + AXI_LI_ADSP_A, chld_usb_src, NULL, NOCHECK, 0, 0), CLK_SLAVE(USB_HS, USBH_NS_REG, B(9), USB_HS_SRC, - CLK_HALT_STATEB_REG, 26, 0x4D7F), + CLK_HALT_STATEB_REG, HALT, 26, 0x4D7F), CLK_SLAVE(USB_HS_CORE, USBH_NS_REG, B(13), USB_HS_SRC, - CLK_HALT_STATEA_REG, 27, 0x14), + CLK_HALT_STATEA_REG, HALT, 27, 0x14), CLK_SLAVE(USB_HS2, USBH2_NS_REG, B(9), USB_HS_SRC, - CLK_HALT_STATEB_REG, 3, 0x4D73), + CLK_HALT_STATEB_REG, HALT, 3, 0x4D73), CLK_SLAVE(USB_HS2_CORE, USBH2_NS_REG, B(4), USB_HS_SRC, - CLK_HALT_STATEA_REG, 28, 0x15), + CLK_HALT_STATEA_REG, HALT, 28, 0x15), CLK_SLAVE(USB_HS3, USBH3_NS_REG, B(9), USB_HS_SRC, - CLK_HALT_STATEB_REG, 2, 0x4D74), + CLK_HALT_STATEB_REG, HALT, 2, 0x4D74), CLK_SLAVE(USB_HS3_CORE, USBH3_NS_REG, B(4), USB_HS_SRC, - CLK_HALT_STATEA_REG, 29, 0x16), + CLK_HALT_STATEA_REG, HALT, 29, 0x16), CLK_MND8(TV, TV_NS_REG, 23, 16, 0, B(11), clk_tbl_tv, chld_tv, - NULL, 0, 0), + NULL, NOCHECK, 0, 0), CLK_SLAVE(HDMI, HDMI_NS_REG, B(9), TV, - CLK_HALT_STATEC_REG, 7, 0x13), + CLK_HALT_STATEC_REG, HALT, 7, 0x13), CLK_SLAVE(TV_DAC, TV_NS_REG, B(12), TV, - CLK_HALT_STATEB_REG, 27, 0x4D6C), + CLK_HALT_STATEB_REG, HALT, 27, 0x4D6C), CLK_SLAVE(TV_ENC, TV_NS_REG, B(9), TV, - CLK_HALT_STATEB_REG, 10, 0x4D6B), + CLK_HALT_STATEB_REG, HALT, 10, 0x4D6B), /* Hacking root & branch into one param. */ CLK_SLAVE(TSIF_REF, TSIF_NS_REG, B(9)|B(11), TV, - CLK_HALT_STATEB_REG, 11, 0x4D6A), + CLK_HALT_STATEB_REG, HALT, 11, 0x4D6A), CLK_MND16(UART1DM, UART1DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE, - NULL, CLK_HALT_STATEB_REG, 6, 0x4D70), + NULL, CLK_HALT_STATEB_REG, HALT, 6, 0x4D70), CLK_MND16(UART2DM, UART2DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE, - NULL, CLK_HALT_STATEB_REG, 23, 0x4D7D), + NULL, CLK_HALT_STATEB_REG, HALT, 23, 0x4D7D), CLK_MND16(JPEG, JPEG_NS_REG, B(9), B(11), clk_tbl_vfe_jpeg, AXI_LI_JPEG, - NULL, CLK_HALT_STATEB_REG, 1, 0x6000), + NULL, CLK_HALT_STATEB_REG, HALT, 1, 0x6000), CLK_MND16(CAM_M, CAM_NS_REG, 0, B(9), clk_tbl_cam, NONE, NULL, - NULL, 0, 0x4D44), + NULL, DELAY, 0, 0x4D44), CLK_MND16(VFE, CAM_VFE_NS_REG, B(9), B(13), clk_tbl_vfe_jpeg, AXI_LI_VFE, chld_vfe, CLK_HALT_STATEB_REG, - 0, 0x4D76), + HALT, 0, 0x4D76), CLK_SLAVE(VFE_MDC, CAM_VFE_NS_REG, B(11), VFE, CLK_HALT_STATEA_REG, - 9, 0x4D57), + HALT, 9, 0x4D57), CLK_SLAVE(VFE_CAMIF, CAM_VFE_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG, - 13, 0x7000), + HALT, 13, 0x7000), CLK_SLAVE(CSI0_VFE, CSI_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG, - 16, 0), + HALT, 16, 0), CLK_MND16(SDAC, SDAC_NS_REG, B(9), B(11), clk_tbl_sdac, - NONE, chld_sdac, CLK_HALT_STATEA_REG, 2, 0x4D60), + NONE, chld_sdac, CLK_HALT_STATEA_REG, HALT, 2, 0x4D60), CLK_SLAVE(SDAC_M, SDAC_NS_REG, B(12), SDAC, CLK_HALT_STATEB_REG, - 17, 0x4D66), + HALT, 17, 0x4D66), CLK_MND16(MDP_LCDC_PCLK, MDP_LCDC_NS_REG, B(9), B(11), clk_tbl_mdp_lcdc, NONE, chld_mdp_lcdc_p, - CLK_HALT_STATEB_REG, 28, 0x4200), + CLK_HALT_STATEB_REG, HALT, 28, 0x4200), CLK_SLAVE(MDP_LCDC_PAD_PCLK, MDP_LCDC_NS_REG, B(12), MDP_LCDC_PCLK, - CLK_HALT_STATEB_REG, 29, 0x4100), + CLK_HALT_STATEB_REG, HALT, 29, 0x4100), CLK_1RATE(MDP_VSYNC, MDP_VSYNC_REG, B(0), 0, clk_tbl_mdp_vsync, - CLK_HALT_STATEB_REG, 30, 0x4D53), + CLK_HALT_STATEB_REG, HALT, 30, 0x4D53), CLK_MND16(MI2S_CODEC_RX_M, MI2S_RX_NS_REG, B(12), B(11), clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_rx, - CLK_HALT_STATEA_REG, 12, 0x4D4E), + CLK_HALT_STATEA_REG, HALT, 12, 0x4D4E), CLK_SLAVE(MI2S_CODEC_RX_S, MI2S_RX_NS_REG, B(9), MI2S_CODEC_RX_M, - CLK_HALT_STATEA_REG, 13, 0x4D4F), + CLK_HALT_STATEA_REG, HALT, 13, 0x4D4F), CLK_MND16(MI2S_CODEC_TX_M, MI2S_TX_NS_REG, B(12), B(11), clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_tx, - CLK_HALT_STATEC_REG, 8, 0x4D50), + CLK_HALT_STATEC_REG, HALT, 8, 0x4D50), CLK_SLAVE(MI2S_CODEC_TX_S, MI2S_TX_NS_REG, B(9), MI2S_CODEC_TX_M, - CLK_HALT_STATEA_REG, 11, 0x17), + CLK_HALT_STATEA_REG, HALT, 11, 0x17), CLK_MND16(MI2S_M, MI2S_NS_REG, B(12), B(11), clk_tbl_mi2s, NONE, chld_mi2s, CLK_HALT_STATEC_REG, - 4, 0x0D), + HALT, 4, 0x0D), CLK_SLAVE(MI2S_S, MI2S_NS_REG, B(9), MI2S_M, CLK_HALT_STATEC_REG, - 3, 0), - - CLK_LOCAL(GRP_2D, BASIC, 0, GRP_2D_NS_REG, F_MASK_BASIC | (7 << 12), - B(7), B(11), clk_tbl_grp, AXI_GRP_2D, NULL, - CLK_HALT_STATEA_REG, 31, 0x5C00), - CLK_LOCAL(GRP_3D_SRC, BASIC, 0, GRP_NS_REG, F_MASK_BASIC | (7 << 12), - 0, B(11), clk_tbl_grp, AXI_LI_GRP, chld_grp_3d_src, - 0, 0, 0), + HALT, 3, 0), + + CLK(GRP_2D, BASIC, GRP_2D_NS_REG, GRP_2D_NS_REG, NULL, NULL, 0, + CLK_HALT_STATEA_REG, HALT, 31, B(7), B(11), + F_MASK_BASIC | (7 << 12), 0, set_rate_basic, + clk_tbl_grp, NULL, AXI_GRP_2D, NULL, 0x5C00), + CLK(GRP_3D_SRC, BASIC, GRP_NS_REG, GRP_NS_REG, NULL, NULL, 0, + NULL, NOCHECK, 0, 0, B(11), F_MASK_BASIC | (7 << 12), + 0, set_rate_basic, clk_tbl_grp, NULL, AXI_LI_GRP, + chld_grp_3d_src, 0), CLK_SLAVE(GRP_3D, GRP_NS_REG, B(7), GRP_3D_SRC, CLK_HALT_STATEB_REG, - 18, 0x5E00), + HALT, 18, 0x5E00), CLK_SLAVE(IMEM, GRP_NS_REG, B(9), GRP_3D_SRC, CLK_HALT_STATEB_REG, - 19, 0x5F00), - CLK_LOCAL(LPA_CODEC, BASIC, 0, LPA_NS_REG, BM(1, 0), B(9), 0, - clk_tbl_lpa_codec, NONE, NULL, CLK_HALT_STATEC_REG, - 6, 0x0F), + HALT, 19, 0x5F00), + CLK(LPA_CODEC, BASIC, LPA_NS_REG, LPA_NS_REG, NULL, NULL, 0, + CLK_HALT_STATEC_REG, HALT, 6, B(9), 0, BM(1, 0), 0, + set_rate_basic, clk_tbl_lpa_codec, NULL, NONE, NULL, + 0x0F), CLK_MND8(CSI0, CSI_NS_REG, 24, 17, B(9), B(11), clk_tbl_csi, NULL, - CLK_HALT_STATEC_REG, 17, 0x5F00), + CLK_HALT_STATEC_REG, HALT, 17, 0x5F00), /* For global clocks to be on we must have GLBL_ROOT_ENA set */ CLK_1RATE(GLBL_ROOT, GLBL_CLK_ENA_SC_REG, 0, B(29), clk_tbl_axi, - NULL, 0, 0), + NULL, NOCHECK, 0, 0), /* Peripheral bus clocks. */ CLK_BRIDGE(ADM, GLBL_CLK_ENA_SC_REG, B(5), AXI_LI_APPS, - GLBL_CLK_STATE_REG, 5, 0x4000), + GLBL_CLK_STATE_REG, HALT_VOTED, 5, 0x4000), CLK_GLBL(ADM_P, GLBL_CLK_ENA_2_SC_REG, B(15), - GLBL_CLK_STATE_2_REG, 15, 0x11), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 15, 0x11), CLK_GLBL(CE, GLBL_CLK_ENA_SC_REG, B(6), - GLBL_CLK_STATE_REG, 6, 0x4D43), + GLBL_CLK_STATE_REG, HALT_VOTED, 6, 0x4D43), CLK_GLBL(CAMIF_PAD_P, GLBL_CLK_ENA_SC_REG, B(9), - GLBL_CLK_STATE_REG, 9, 0x1A), + GLBL_CLK_STATE_REG, HALT_VOTED, 9, 0x1A), CLK_GLBL(CSI0_P, GLBL_CLK_ENA_SC_REG, B(30), - GLBL_CLK_STATE_REG, 30, 0), + GLBL_CLK_STATE_REG, HALT_VOTED, 30, 0), CLK_GLBL(EMDH_P, GLBL_CLK_ENA_2_SC_REG, B(3), - GLBL_CLK_STATE_2_REG, 3, 0x03), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 3, 0x03), CLK_GLBL(GRP_2D_P, GLBL_CLK_ENA_SC_REG, B(24), - GLBL_CLK_STATE_REG, 24, 0x4D4C), + GLBL_CLK_STATE_REG, HALT_VOTED, 24, 0x4D4C), CLK_GLBL(GRP_3D_P, GLBL_CLK_ENA_2_SC_REG, B(17), - GLBL_CLK_STATE_2_REG, 17, 0x4D67), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 17, 0x4D67), CLK_GLBL(JPEG_P, GLBL_CLK_ENA_2_SC_REG, B(24), - GLBL_CLK_STATE_2_REG, 24, 0x4D5E), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 24, 0x4D5E), CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC_REG, B(7), - GLBL_CLK_STATE_2_REG, 7, 0x07), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 7, 0x07), CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC_REG, B(6), - GLBL_CLK_STATE_2_REG, 6, 0x06), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 6, 0x06), CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC_REG, B(26), - GLBL_CLK_STATE_2_REG, 26, 0x4D75), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 26, 0x4D75), CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC_REG, B(4), - GLBL_CLK_STATE_2_REG, 4, 0x04), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 4, 0x04), CLK_GLBL(ROTATOR_IMEM, GLBL_CLK_ENA_2_SC_REG, B(23), - GLBL_CLK_STATE_2_REG, 23, 0x6600), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 23, 0x6600), CLK_GLBL(ROTATOR_P, GLBL_CLK_ENA_2_SC_REG, B(25), - GLBL_CLK_STATE_2_REG, 25, 0x4D6D), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 25, 0x4D6D), CLK_GLBL(SDC1_P, GLBL_CLK_ENA_SC_REG, B(7), - GLBL_CLK_STATE_REG, 7, 0x4D61), + GLBL_CLK_STATE_REG, HALT_VOTED, 7, 0x4D61), CLK_GLBL(SDC2_P, GLBL_CLK_ENA_SC_REG, B(8), - GLBL_CLK_STATE_REG, 8, 0x4F63), + GLBL_CLK_STATE_REG, HALT_VOTED, 8, 0x4F63), CLK_GLBL(SDC3_P, GLBL_CLK_ENA_SC_REG, B(27), - GLBL_CLK_STATE_REG, 27, 0x4D79), + GLBL_CLK_STATE_REG, HALT_VOTED, 27, 0x4D79), CLK_GLBL(SDC4_P, GLBL_CLK_ENA_SC_REG, B(28), - GLBL_CLK_STATE_REG, 28, 0x4D7B), + GLBL_CLK_STATE_REG, HALT_VOTED, 28, 0x4D7B), CLK_GLBL(SPI_P, GLBL_CLK_ENA_2_SC_REG, B(10), - GLBL_CLK_STATE_2_REG, 10, 0x18), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 10, 0x18), CLK_GLBL(TSIF_P, GLBL_CLK_ENA_SC_REG, B(18), - GLBL_CLK_STATE_REG, 18, 0x4D65), + GLBL_CLK_STATE_REG, HALT_VOTED, 18, 0x4D65), CLK_GLBL(UART1DM_P, GLBL_CLK_ENA_SC_REG, B(17), - GLBL_CLK_STATE_REG, 17, 0x4D5C), + GLBL_CLK_STATE_REG, HALT_VOTED, 17, 0x4D5C), CLK_GLBL(UART2DM_P, GLBL_CLK_ENA_SC_REG, B(26), - GLBL_CLK_STATE_REG, 26, 0x4D7E), + GLBL_CLK_STATE_REG, HALT_VOTED, 26, 0x4D7E), CLK_GLBL(USB_HS2_P, GLBL_CLK_ENA_2_SC_REG, B(8), - GLBL_CLK_STATE_2_REG, 8, 0x08), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 8, 0x08), CLK_GLBL(USB_HS3_P, GLBL_CLK_ENA_2_SC_REG, B(9), - GLBL_CLK_STATE_2_REG, 9, 0x10), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 9, 0x10), CLK_GLBL(USB_HS_P, GLBL_CLK_ENA_SC_REG, B(25), - GLBL_CLK_STATE_REG, 25, 0x4D58), + GLBL_CLK_STATE_REG, HALT_VOTED, 25, 0x4D58), CLK_GLBL(VFE_P, GLBL_CLK_ENA_2_SC_REG, B(27), - GLBL_CLK_STATE_2_REG, 27, 0x4D55), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 27, 0x4D55), /* AXI bridge clocks. */ CLK_BRIDGE(AXI_LI_APPS, GLBL_CLK_ENA_SC_REG, B(2), GLBL_ROOT, - GLBL_CLK_STATE_REG, 2, 0x4900), + GLBL_CLK_STATE_REG, HALT_VOTED, 2, 0x4900), CLK_BRIDGE(AXI_LI_ADSP_A, GLBL_CLK_ENA_2_SC_REG, B(14), AXI_LI_APPS, - GLBL_CLK_STATE_2_REG, 14, 0x6400), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 14, 0x6400), CLK_BRIDGE(AXI_LI_JPEG, GLBL_CLK_ENA_2_SC_REG, B(19), AXI_LI_APPS, - GLBL_CLK_STATE_2_REG, 19, 0x4E00), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 19, 0x4E00), CLK_BRIDGE(AXI_LI_VFE, GLBL_CLK_ENA_SC_REG, B(23), AXI_LI_APPS, - GLBL_CLK_STATE_REG, 23, 0x5B00), + GLBL_CLK_STATE_REG, HALT_VOTED, 23, 0x5B00), CLK_BRIDGE(AXI_MDP, GLBL_CLK_ENA_2_SC_REG, B(29), AXI_LI_APPS, - GLBL_CLK_STATE_2_REG, 29, 0x6B00), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 29, 0x6B00), CLK_BRIDGE(AXI_IMEM, GLBL_CLK_ENA_2_SC_REG, B(18), GLBL_ROOT, - GLBL_CLK_STATE_2_REG, 18, 0x4B00), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 18, 0x4B00), CLK_BRIDGE(AXI_LI_VG, GLBL_CLK_ENA_SC_REG, B(3), GLBL_ROOT, - GLBL_CLK_STATE_REG, 3, 0x4700), + GLBL_CLK_STATE_REG, HALT_VOTED, 3, 0x4700), CLK_BRIDGE(AXI_GRP_2D, GLBL_CLK_ENA_SC_REG, B(21), AXI_LI_VG, - GLBL_CLK_STATE_REG, 21, 0x5900), + GLBL_CLK_STATE_REG, HALT_VOTED, 21, 0x5900), CLK_BRIDGE(AXI_LI_GRP, GLBL_CLK_ENA_SC_REG, B(22), AXI_LI_VG, - GLBL_CLK_STATE_REG, 22, 0x5A00), + GLBL_CLK_STATE_REG, HALT_VOTED, 22, 0x5A00), CLK_BRIDGE(AXI_MFC, GLBL_CLK_ENA_2_SC_REG, B(20), AXI_LI_VG, - GLBL_CLK_STATE_2_REG, 20, 0x6A00), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 20, 0x6A00), CLK_BRIDGE(AXI_ROTATOR, GLBL_CLK_ENA_2_SC_REG, B(22), AXI_LI_VG, - GLBL_CLK_STATE_2_REG, 22, 0x4300), + GLBL_CLK_STATE_2_REG, HALT_VOTED, 22, 0x4300), CLK_BRIDGE(AXI_VPE, GLBL_CLK_ENA_2_SC_REG, B(21), AXI_LI_VG, - GLBL_CLK_STATE_2_REG, 21, 0x6700), -}; - -static DEFINE_SPINLOCK(clock_reg_lock); -static DEFINE_SPINLOCK(pll_vote_lock); - -enum { - TCXO, - LPXO, - NUM_XO + GLBL_CLK_STATE_2_REG, HALT_VOTED, 21, 0x6700), }; -static unsigned xo_votes[NUM_XO]; /* Tracks the number of users for each XO */ - -/* Map PLLs to which XO they use */ -static const unsigned pll_to_xo[] = { - [PLL_0] = TCXO, - [PLL_1] = TCXO, - [PLL_2] = TCXO, - [PLL_3] = LPXO, - [PLL_4] = LPXO, - [PLL_5] = TCXO, - [PLL_6] = TCXO, -}; - -static void vote_for_xo(unsigned xo) -{ - BUG_ON(xo >= NUM_XO); - - if (!xo_votes[xo]) { - int enable = 1; - unsigned p_xo = xo; - msm_proc_comm(PCOM_CLKCTL_RPC_SRC_REQUEST, &p_xo, &enable); - } - xo_votes[xo]++; -} - -static void unvote_for_xo(unsigned xo) -{ - BUG_ON(xo >= NUM_XO); - if (xo_votes[xo]) { - xo_votes[xo]--; - } else { - pr_warning("%s: Reference count mismatch!\n", __func__); - return; - } - - if (xo_votes[xo] == 0) { - int enable = 0; - msm_proc_comm(PCOM_CLKCTL_RPC_SRC_REQUEST, &xo, &enable); - } -} - -#define PLL_ACTIVE_MASK B(16) -void pll_enable(uint32_t pll) -{ - uint32_t reg_val; - unsigned long flags; - - BUG_ON(pll >= NUM_PLL); - - spin_lock_irqsave(&pll_vote_lock, flags); - if (!pll_count[pll]) { - vote_for_xo(pll_to_xo[pll]); - reg_val = readl(PLL_ENA_REG); - reg_val |= (1 << pll); - writel(reg_val, PLL_ENA_REG); - } - pll_count[pll]++; - spin_unlock_irqrestore(&pll_vote_lock, flags); - - /* Wait until PLL is enabled. */ - while ((readl(pll_status_addr[pll]) & PLL_ACTIVE_MASK) == 0) - cpu_relax(); -} - -void pll_disable(uint32_t pll) -{ - uint32_t reg_val; - unsigned long flags; - - BUG_ON(pll >= NUM_PLL); - - spin_lock_irqsave(&pll_vote_lock, flags); - if (pll_count[pll]) { - pll_count[pll]--; - } else { - pr_warning("Reference count mismatch in PLL disable!\n"); - goto out; - } - - if (pll_count[pll] == 0) { - reg_val = readl(PLL_ENA_REG); - reg_val &= ~(1 << pll); - writel(reg_val, PLL_ENA_REG); - unvote_for_xo(pll_to_xo[pll]); - } -out: - spin_unlock_irqrestore(&pll_vote_lock, flags); -} - -static void src_enable(uint32_t src) -{ - switch (src) { - case SRC_NONE: - /* - * SRC_NONE is used as a placeholder for some freqencies that - * don't have any direct PLL dependency. Instead they source - * off an external/internal clock which takes care of any - * PLL or XO dependency. - */ - break; - case SRC_TCXO: - vote_for_xo(TCXO); - break; - case SRC_AXI: - case SRC_LPXO: - /* - * AXI could use LPXO or TCXO. Map it to LPXO to make sure - * there is at least once XO available for the AXI (LPXO is - * the lower powered one so just use that). - */ - vote_for_xo(LPXO); - break; - default: - pll_enable(src_pll_tbl[src]); - break; - } -} - -static void src_disable(uint32_t src) -{ - switch (src) { - case SRC_NONE: - /* - * SRC_NONE is used as a placeholder for some freqencies that - * don't have any direct PLL dependency. Instead they source - * off an external/internal clock which takes care of any - * PLL or XO dependency. - */ - break; - case SRC_TCXO: - unvote_for_xo(TCXO); - break; - case SRC_AXI: - case SRC_LPXO: - /* - * AXI could use LPXO or TCXO. Map it to LPXO to make sure - * there is at least once XO available for the AXI (LPXO is - * the lower powered one so just use that). - */ - unvote_for_xo(LPXO); - break; - default: - pll_disable(src_pll_tbl[src]); - break; - } -} - -static unsigned msmc1_votes[MSMC1_END]; -static unsigned msmc1_level; +/* + * SoC-specific functions required by clock-local driver + */ -static int update_msmc1(void) +/* Update the sys_vdd voltage given a level. */ +int soc_update_sys_vdd(enum sys_vdd_level level) { - int err, target, mvolts; - - if (msmc1_votes[HIGH]) - target = 1200; - else if (msmc1_votes[NOMINAL]) - target = 1100; - else - target = 1000; - - if (target == msmc1_level) - return 0; - - mvolts = target; - err = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_MSMC1, &mvolts, NULL); - if (err) + int rc, target_mv; + static const int mv[NUM_SYS_VDD_LEVELS] = { + [NONE...LOW] = 1000, + [NOMINAL] = 1100, + [HIGH] = 1200, + }; + + target_mv = mv[level]; + rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_MSMC1, &target_mv, NULL); + if (rc) goto out; - - if (mvolts) { - err = -EINVAL; + if (target_mv) { + rc = -EINVAL; goto out; } - msmc1_level = target; out: - return err; -} - -static void unvote_msmc1(unsigned level) -{ - if (level >= ARRAY_SIZE(msmc1_votes)) - return; - - if (msmc1_votes[level]) { - msmc1_votes[level]--; - } else { - pr_warning("%s: Reference counts are incorrect\n", __func__); - return; - } - - update_msmc1(); -} - -static int vote_msmc1(unsigned level) -{ - int ret; - - if (level >= ARRAY_SIZE(msmc1_votes)) - return 0; - - msmc1_votes[level]++; - ret = update_msmc1(); - if (ret) - msmc1_votes[level]--; - - return ret; -} - -/* - * SoC specific register-based control of clocks. - */ -static int _soc_clk_enable(unsigned id) -{ - struct clk_local *t = &clk_local_tbl[id]; - void *ns_reg = t->ns_reg; - uint32_t reg_val = 0; - - WARN((t->type != NORATE) && (t->current_freq == &dummy_freq), - "Attempting to enable clock %d before setting its rate. " - "Set the rate first!\n", id); - - reg_val = readl(ns_reg); - if (t->type == MND) { - /* mode can be either 0 or 1. So the R-value of the - * expression will evaluate to MNCNTR_EN_MASK or 0. This - * avoids the need for a "if(mode == 1)". A "&" will not work - * here. */ - reg_val |= (MNCNTR_EN_MASK * t->current_freq->mode); - writel(reg_val, ns_reg); - } - if (t->root_en_mask) { - reg_val |= t->root_en_mask; - writel(reg_val, ns_reg); - } - if (t->br_en_mask) { - reg_val |= t->br_en_mask; - writel(reg_val, ns_reg); - } - if (t->halt_reg) { - uint32_t halted, count = 0; - - /* Wait for the halt bit to clear, but timeout after 100usecs - * since the halt bit may be buggy. */ - while ((halted = readl(t->halt_reg) & BIT(t->halt_mask)) - && count++ < 100) - udelay(1); - if (halted) - pr_warning("%s: clock %d never turned on\n", __func__, - id); - } - return 0; -} - -static void _soc_clk_disable(unsigned id) -{ - struct clk_local *t = &clk_local_tbl[id]; - void *ns_reg = t->ns_reg; - uint32_t reg_val = 0; - - reg_val = readl(ns_reg); - - if (t->br_en_mask) { - reg_val &= ~(t->br_en_mask); - writel(reg_val, ns_reg); - } - if (t->halt_reg) { - uint32_t halted, count = 0; - - /* Wait for the halt bit to be set, but timeout after 100usecs - * since the halt bit may be buggy. */ - while (!(halted = readl(t->halt_reg) & BIT(t->halt_mask)) - && count++ < 100) - udelay(1); - if (!halted) - pr_warning("%s: clock %d never turned off\n", __func__, - id); - } - if (t->root_en_mask) { - reg_val &= ~(t->root_en_mask); - writel(reg_val, ns_reg); - } - if (t->type == MND) { - reg_val &= ~MNCNTR_EN_MASK; - writel(reg_val, ns_reg); - } + return rc; } -static int soc_clk_enable_nolock(unsigned id) -{ - struct clk_local *t = &clk_local_tbl[id]; - int ret = 0; - - if (!t->count) { - ret = vote_msmc1(t->current_freq->msmc1); - if (ret) - return ret; - if (t->parent != C(NONE)) { - ret = soc_clk_enable_nolock(t->parent); - if (ret) - return ret; - } - src_enable(t->current_freq->src); - ret = _soc_clk_enable(id); - } - t->count++; - - return ret; -} - -static void soc_clk_disable_nolock(unsigned id) -{ - struct clk_local *t = &clk_local_tbl[id]; - - if (!t->count) { - pr_warning("Reference count mismatch in clock disable!\n"); - return; - } - if (t->count) - t->count--; - if (t->count == 0) { - _soc_clk_disable(id); - src_disable(t->current_freq->src); - unvote_msmc1(t->current_freq->msmc1); - if (t->parent != C(NONE)) - soc_clk_disable_nolock(t->parent); - } - - return; -} - -static int update_pwr_rail(unsigned id, int enable) +/* Enable/disable a power rail associated with a clock. */ +int soc_set_pwr_rail(unsigned id, int enable) { /* TODO: Implement internal power rail control */ return 0; } -static int soc_clk_enable(unsigned id) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&clock_reg_lock, flags); - ret = soc_clk_enable_nolock(id); - if (ret) - goto unlock; - /* - * The modem might modify the register bits for the clock branch when - * the rail is enabled/disabled, so enable the rail inside the lock - * instead of outside it. - */ - ret = update_pwr_rail(id, 1); - if (ret) - soc_clk_disable_nolock(id); -unlock: - spin_unlock_irqrestore(&clock_reg_lock, flags); - - return ret; -} - -static void soc_clk_disable(unsigned id) -{ - unsigned long flags; - - spin_lock_irqsave(&clock_reg_lock, flags); - update_pwr_rail(id, 0); - soc_clk_disable_nolock(id); - spin_unlock_irqrestore(&clock_reg_lock, flags); -} - -static void soc_clk_auto_off(unsigned id) -{ - unsigned long flags; - - spin_lock_irqsave(&clock_reg_lock, flags); - _soc_clk_disable(id); - spin_unlock_irqrestore(&clock_reg_lock, flags); -} - -static long soc_clk_round_rate(unsigned id, unsigned rate) -{ - struct clk_local *t = &clk_local_tbl[id]; - const struct clk_freq_tbl *f; - - if (t->type != MND && t->type != BASIC) - return -EINVAL; - - for (f = t->freq_tbl; f->freq_hz != FREQ_END; f++) - if (f->freq_hz >= rate) - return f->freq_hz; - - return -EPERM; -} - -static int soc_clk_set_rate(unsigned id, unsigned rate) -{ - struct clk_local *t = &clk_local_tbl[id]; - const struct clk_freq_tbl *cf; - const struct clk_freq_tbl *nf; - uint32_t *chld = t->children; - void *ns_reg = t->ns_reg; - void *md_reg = t->md_reg; - uint32_t reg_val = 0; - int i, ret = 0; - unsigned long flags; - long rounded; - - rounded = soc_clk_round_rate(id, rate); - if (rounded != rate) - pr_warning("Use clk_round_rate() before clk_set_rate() with " - "clock %u\n", id); - rate = rounded; - - if (t->type != MND && t->type != BASIC) - return -EPERM; - - spin_lock_irqsave(&clock_reg_lock, flags); - cf = t->current_freq; - - if (rate == cf->freq_hz) - goto release_lock; - - for (nf = t->freq_tbl; nf->freq_hz != FREQ_END; nf++) - if (nf->freq_hz == rate) - break; - - if (nf->freq_hz == FREQ_END) { - ret = -EINVAL; - goto release_lock; - } - - if (t->freq_mask == 0) { - t->current_freq = nf; - goto release_lock; - } - - /* Disable all branches before changing rate to prevent jitter. */ - for (i = 0; chld && chld[i] != C(NONE); i++) { - struct clk_local *ch = &clk_local_tbl[chld[i]]; - /* Don't bother turning off if it is already off. - * Checking ch->count is cheaper (cache) than reading and - * writing to a register (uncached/unbuffered). */ - if (ch->count) { - reg_val = readl(ch->ns_reg); - reg_val &= ~(ch->br_en_mask); - writel(reg_val, ch->ns_reg); - } - } - - if (t->count) { - _soc_clk_disable(id); - - ret = vote_msmc1(nf->msmc1); - if (ret) - goto msmc1_err; - /* Turn on PLL of the new freq. */ - src_enable(nf->src); - } - - /* Some clocks share the same register, so must be careful when - * assuming a register doesn't need to be re-read. */ - reg_val = readl(ns_reg); - if (t->type == MND) { - reg_val |= MNCNTR_RST_MASK; - writel(reg_val, ns_reg); - /* TODO: Currently writing 0's into reserved bits for 8-bit - * MND. Can be avoided by adding md_mask. */ - if (nf->mode) - writel(nf->md_val, md_reg); - reg_val &= ~MNCNTR_MODE_MASK; - reg_val |= (MNCNTR_MODE * nf->mode); - } - reg_val &= ~(t->freq_mask); - reg_val |= nf->ns_val; - writel(reg_val, ns_reg); - - if (t->type == MND) { - reg_val &= ~MNCNTR_RST_MASK; - writel(reg_val, ns_reg); - } - - if (t->count) { - /* Turn off PLL of the old freq. */ - src_disable(cf->src); - unvote_msmc1(cf->msmc1); - } - - /* Current freq must be updated before _soc_clk_enable() is called to - * make sure the MNCNTR_E bit is set correctly. */ - t->current_freq = nf; - -msmc1_err: - if (t->count) - _soc_clk_enable(id); - /* Enable only branches that were ON before. */ - for (i = 0; chld && chld[i] != C(NONE); i++) { - struct clk_local *ch = &clk_local_tbl[chld[i]]; - if (ch->count) { - reg_val = readl(ch->ns_reg); - reg_val |= ch->br_en_mask; - writel(reg_val, ch->ns_reg); - } - } - -release_lock: - spin_unlock_irqrestore(&clock_reg_lock, flags); - return ret; -} - -static int soc_clk_set_min_rate(unsigned id, unsigned rate) -{ - long rounded = soc_clk_round_rate(id, rate); - return soc_clk_set_rate(id, rounded); -} - -static int soc_clk_set_max_rate(unsigned id, unsigned rate) -{ - return -EPERM; -} - -static int soc_clk_set_flags(unsigned id, unsigned clk_flags) +/* Implementation for clk_set_flags(). */ +int soc_clk_set_flags(unsigned id, unsigned clk_flags) { uint32_t regval, ret = 0; unsigned long flags; - spin_lock_irqsave(&clock_reg_lock, flags); + spin_lock_irqsave(&local_clock_reg_lock, flags); switch (id) { case C(VFE): regval = readl(CAM_VFE_NS_REG); @@ -1261,50 +713,102 @@ static int soc_clk_set_flags(unsigned id, unsigned clk_flags) default: ret = -EPERM; } - spin_unlock_irqrestore(&clock_reg_lock, flags); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); return ret; } -static unsigned soc_clk_get_rate(unsigned id) +/* Enable function for TCXO and LPXO. */ +static int soc_xo_enable(unsigned src, unsigned enable) { - struct clk_local *t = &clk_local_tbl[id]; - unsigned long flags; - unsigned ret = 0; + unsigned pcom_xo_id; - if (t->type == NORATE) + if (src == TCXO) + pcom_xo_id = 0; + else if (src == LPXO) + pcom_xo_id = 1; + else return 0; - spin_lock_irqsave(&clock_reg_lock, flags); - ret = t->current_freq->freq_hz; - spin_unlock_irqrestore(&clock_reg_lock, flags); - - /* Return 0 if the rate has never been set. Might not be correct, - * but it's good enough. */ - if (ret == FREQ_END) - ret = 0; - - return ret; + return msm_proc_comm(PCOM_CLKCTL_RPC_SRC_REQUEST, &pcom_xo_id, &enable); } -static unsigned soc_clk_is_enabled(unsigned id) +/* Enable function for PLLs. */ +static int soc_pll_enable(unsigned src, unsigned enable) { - return !!(clk_local_tbl[id].count); -} + static const struct pll_ena { + uint32_t *const reg; + const uint32_t mask; + } soc_pll_ena[NUM_SRC] = { + [PLL_0] = {PLL_ENA_REG, B(0)}, + [PLL_1] = {PLL_ENA_REG, B(1)}, + [PLL_2] = {PLL_ENA_REG, B(2)}, + [PLL_3] = {PLL_ENA_REG, B(3)}, + [PLL_4] = {PLL_ENA_REG, B(4)}, + [PLL_5] = {PLL_ENA_REG, B(5)}, + [PLL_6] = {PLL_ENA_REG, B(6)}, + }; + uint32_t *const soc_pll_status_reg[NUM_SRC] = { + + [PLL_0] = PLL0_STATUS_BASE_REG, + [PLL_1] = PLL1_STATUS_BASE_REG, + [PLL_2] = PLL2_STATUS_BASE_REG, + [PLL_3] = PLL3_STATUS_BASE_REG, + [PLL_4] = PLL4_STATUS_BASE_REG, + [PLL_5] = PLL5_STATUS_BASE_REG, + [PLL_6] = PLL6_STATUS_BASE_REG, + }; + uint32_t reg_val; + reg_val = readl(soc_pll_ena[src].reg); -struct clk_ops clk_ops_7x30 = { - .enable = soc_clk_enable, - .disable = soc_clk_disable, - .auto_off = soc_clk_auto_off, - .set_rate = soc_clk_set_rate, - .set_min_rate = soc_clk_set_min_rate, - .set_max_rate = soc_clk_set_max_rate, - .reset = pc_clk_reset, - .set_flags = soc_clk_set_flags, - .get_rate = soc_clk_get_rate, - .is_enabled = soc_clk_is_enabled, - .round_rate = soc_clk_round_rate, + if (enable) + reg_val |= soc_pll_ena[src].mask; + else + reg_val &= ~(soc_pll_ena[src].mask); + + writel(reg_val, soc_pll_ena[src].reg); + + if (enable) { + /* Wait until PLL is enabled */ + while ((readl(soc_pll_status_reg[src]) & B(16)) == 0) + cpu_relax(); + } + + return 0; +} + +struct clk_source soc_clk_sources[NUM_SRC] = { + [TCXO] = { .enable_func = soc_xo_enable, + .par = SRC_NONE, + }, + [LPXO] = { .enable_func = soc_xo_enable, + .par = SRC_NONE, + }, + [AXI] = { .enable_func = NULL, + .par = LPXO, + }, + [PLL_0] = { .enable_func = soc_pll_enable, + .par = TCXO, + }, + [PLL_1] = { .enable_func = soc_pll_enable, + .par = TCXO, + }, + [PLL_2] = { .enable_func = soc_pll_enable, + .par = TCXO, + }, + [PLL_3] = { .enable_func = soc_pll_enable, + .par = LPXO, + }, + [PLL_4] = { .enable_func = soc_pll_enable, + .par = LPXO, + }, + [PLL_5] = { .enable_func = soc_pll_enable, + .par = TCXO, + }, + [PLL_6] = { .enable_func = soc_pll_enable, + .par = TCXO, + }, }; /* @@ -1454,6 +958,22 @@ static bool __init clk_is_local(uint32_t id) return *reg & bit; } +/* SoC-specific clk_ops initialization. */ +void __init msm_clk_soc_set_ops(struct clk *clk) +{ + if (!clk->ops) { + if (clk_is_local(clk->id)) + clk->ops = &soc_clk_ops_7x30; + else { + clk->ops = &clk_ops_pcom; + clk->id = clk->remote_id; + } + } +} + +/* + * Miscellaneous clock register initializations + */ static const struct reg_init { const void __iomem *reg; uint32_t mask; @@ -1490,21 +1010,7 @@ static const struct reg_init { {USBH3_NS_REG, B(6), B(6)}, }; -/* SoC-specific clk_ops initialization. */ -void __init msm_clk_soc_set_ops(struct clk *clk) -{ - if (!clk->ops) { - if (clk_is_local(clk->id)) - clk->ops = &clk_ops_7x30; - else { - clk->ops = &clk_ops_pcom; - clk->id = clk->remote_id; - } - } -} - -#define set_1rate(clk) \ - soc_clk_set_rate(C(clk), clk_local_tbl[C(clk)].freq_tbl->freq_hz) +/* Local clock driver initialization. */ void __init msm_clk_soc_init(void) { int i; @@ -1522,10 +1028,10 @@ void __init msm_clk_soc_init(void) * USB HS core clocks. */ for (i = 0; chld_usb_src[i] != C(NONE); i++) if (clk_is_local(chld_usb_src[i])) - _soc_clk_disable(chld_usb_src[i]); + local_clk_disable_reg(chld_usb_src[i]); if (clk_is_local(C(USB_HS_SRC))) - soc_clk_set_rate(C(USB_HS_SRC), clk_tbl_usb[0].freq_hz); + local_clk_set_rate(C(USB_HS_SRC), clk_tbl_usb[0].freq_hz); for (i = 0; i < ARRAY_SIZE(ri_list); i++) { val = readl(ri_list[i].reg); @@ -1546,5 +1052,23 @@ void __init msm_clk_soc_init(void) set_1rate(GLBL_ROOT); /* Sync the GRP2D clock to AXI */ - soc_clk_set_rate(C(GRP_2D), 1); + local_clk_set_rate(C(GRP_2D), 1); } + + +/* + * Clock operation handler registration + */ +struct clk_ops soc_clk_ops_7x30 = { + .enable = local_clk_enable, + .disable = local_clk_disable, + .auto_off = local_clk_auto_off, + .set_rate = local_clk_set_rate, + .set_min_rate = local_clk_set_min_rate, + .set_max_rate = local_clk_set_max_rate, + .get_rate = local_clk_get_rate, + .is_enabled = local_clk_is_enabled, + .round_rate = local_clk_round_rate, + .reset = pc_clk_reset, + .set_flags = soc_clk_set_flags, +}; diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h index d41acb7..01c49c7 100644 --- a/arch/arm/mach-msm/clock-7x30.h +++ b/arch/arm/mach-msm/clock-7x30.h @@ -31,116 +31,112 @@ #define __ARCH_ARM_MACH_MSM_CLOCK_7X30_H enum { - L_7X30_NONE_CLK = -1, - L_7X30_ADM_CLK, - L_7X30_ADM_P_CLK, - L_7X30_CE_CLK, - L_7X30_I2C_CLK, - L_7X30_I2C_2_CLK, - L_7X30_QUP_I2C_CLK, - L_7X30_UART1DM_CLK, - L_7X30_UART1DM_P_CLK, - L_7X30_UART2DM_CLK, - L_7X30_UART2DM_P_CLK, - L_7X30_EMDH_CLK, - L_7X30_EMDH_P_CLK, - L_7X30_PMDH_CLK, - L_7X30_PMDH_P_CLK, - L_7X30_GRP_2D_CLK, - L_7X30_GRP_2D_P_CLK, - L_7X30_GRP_3D_SRC_CLK, - L_7X30_GRP_3D_CLK, - L_7X30_GRP_3D_P_CLK, - L_7X30_IMEM_CLK, - L_7X30_SDC1_CLK, - L_7X30_SDC1_P_CLK, - L_7X30_SDC2_CLK, - L_7X30_SDC2_P_CLK, - L_7X30_SDC3_CLK, - L_7X30_SDC3_P_CLK, - L_7X30_SDC4_CLK, - L_7X30_SDC4_P_CLK, - L_7X30_MDP_CLK, - L_7X30_MDP_P_CLK, - L_7X30_MDP_LCDC_PCLK_CLK, - L_7X30_MDP_LCDC_PAD_PCLK_CLK, - L_7X30_MDP_VSYNC_CLK, - L_7X30_MI2S_CODEC_RX_M_CLK, - L_7X30_MI2S_CODEC_RX_S_CLK, - L_7X30_MI2S_CODEC_TX_M_CLK, - L_7X30_MI2S_CODEC_TX_S_CLK, - L_7X30_MI2S_M_CLK, - L_7X30_MI2S_S_CLK, - L_7X30_LPA_CODEC_CLK, - L_7X30_LPA_CORE_CLK, - L_7X30_LPA_P_CLK, - L_7X30_MIDI_CLK, - L_7X30_MDC_CLK, - L_7X30_ROTATOR_IMEM_CLK, - L_7X30_ROTATOR_P_CLK, - L_7X30_SDAC_M_CLK, - L_7X30_SDAC_CLK, - L_7X30_UART1_CLK, - L_7X30_UART2_CLK, - L_7X30_UART3_CLK, - L_7X30_TV_CLK, - L_7X30_TV_DAC_CLK, - L_7X30_TV_ENC_CLK, - L_7X30_HDMI_CLK, - L_7X30_TSIF_REF_CLK, - L_7X30_TSIF_P_CLK, - L_7X30_USB_HS_SRC_CLK, - L_7X30_USB_HS_CLK, - L_7X30_USB_HS_CORE_CLK, - L_7X30_USB_HS_P_CLK, - L_7X30_USB_HS2_CLK, - L_7X30_USB_HS2_CORE_CLK, - L_7X30_USB_HS2_P_CLK, - L_7X30_USB_HS3_CLK, - L_7X30_USB_HS3_CORE_CLK, - L_7X30_USB_HS3_P_CLK, - L_7X30_VFE_CLK, - L_7X30_VFE_P_CLK, - L_7X30_VFE_MDC_CLK, - L_7X30_VFE_CAMIF_CLK, - L_7X30_CAMIF_PAD_P_CLK, - L_7X30_CAM_M_CLK, - L_7X30_JPEG_CLK, - L_7X30_JPEG_P_CLK, - L_7X30_VPE_CLK, - L_7X30_MFC_CLK, - L_7X30_MFC_DIV2_CLK, - L_7X30_MFC_P_CLK, - L_7X30_SPI_CLK, - L_7X30_SPI_P_CLK, - L_7X30_CSI0_CLK, - L_7X30_CSI0_VFE_CLK, - L_7X30_CSI0_P_CLK, - L_7X30_CSI1_CLK, - L_7X30_CSI1_VFE_CLK, - L_7X30_CSI1_P_CLK, - L_7X30_GLBL_ROOT_CLK, + L_ADM_CLK, + L_ADM_P_CLK, + L_CE_CLK, + L_I2C_CLK, + L_I2C_2_CLK, + L_QUP_I2C_CLK, + L_UART1DM_CLK, + L_UART1DM_P_CLK, + L_UART2DM_CLK, + L_UART2DM_P_CLK, + L_EMDH_CLK, + L_EMDH_P_CLK, + L_PMDH_CLK, + L_PMDH_P_CLK, + L_GRP_2D_CLK, + L_GRP_2D_P_CLK, + L_GRP_3D_SRC_CLK, + L_GRP_3D_CLK, + L_GRP_3D_P_CLK, + L_IMEM_CLK, + L_SDC1_CLK, + L_SDC1_P_CLK, + L_SDC2_CLK, + L_SDC2_P_CLK, + L_SDC3_CLK, + L_SDC3_P_CLK, + L_SDC4_CLK, + L_SDC4_P_CLK, + L_MDP_CLK, + L_MDP_P_CLK, + L_MDP_LCDC_PCLK_CLK, + L_MDP_LCDC_PAD_PCLK_CLK, + L_MDP_VSYNC_CLK, + L_MI2S_CODEC_RX_M_CLK, + L_MI2S_CODEC_RX_S_CLK, + L_MI2S_CODEC_TX_M_CLK, + L_MI2S_CODEC_TX_S_CLK, + L_MI2S_M_CLK, + L_MI2S_S_CLK, + L_LPA_CODEC_CLK, + L_LPA_CORE_CLK, + L_LPA_P_CLK, + L_MIDI_CLK, + L_MDC_CLK, + L_ROTATOR_IMEM_CLK, + L_ROTATOR_P_CLK, + L_SDAC_M_CLK, + L_SDAC_CLK, + L_UART1_CLK, + L_UART2_CLK, + L_UART3_CLK, + L_TV_CLK, + L_TV_DAC_CLK, + L_TV_ENC_CLK, + L_HDMI_CLK, + L_TSIF_REF_CLK, + L_TSIF_P_CLK, + L_USB_HS_SRC_CLK, + L_USB_HS_CLK, + L_USB_HS_CORE_CLK, + L_USB_HS_P_CLK, + L_USB_HS2_CLK, + L_USB_HS2_CORE_CLK, + L_USB_HS2_P_CLK, + L_USB_HS3_CLK, + L_USB_HS3_CORE_CLK, + L_USB_HS3_P_CLK, + L_VFE_CLK, + L_VFE_P_CLK, + L_VFE_MDC_CLK, + L_VFE_CAMIF_CLK, + L_CAMIF_PAD_P_CLK, + L_CAM_M_CLK, + L_JPEG_CLK, + L_JPEG_P_CLK, + L_VPE_CLK, + L_MFC_CLK, + L_MFC_DIV2_CLK, + L_MFC_P_CLK, + L_SPI_CLK, + L_SPI_P_CLK, + L_CSI0_CLK, + L_CSI0_VFE_CLK, + L_CSI0_P_CLK, + L_CSI1_CLK, + L_CSI1_VFE_CLK, + L_CSI1_P_CLK, + L_GLBL_ROOT_CLK, - L_7X30_AXI_LI_VG_CLK, - L_7X30_AXI_LI_GRP_CLK, - L_7X30_AXI_LI_JPEG_CLK, - L_7X30_AXI_GRP_2D_CLK, - L_7X30_AXI_MFC_CLK, - L_7X30_AXI_VPE_CLK, - L_7X30_AXI_LI_VFE_CLK, - L_7X30_AXI_LI_APPS_CLK, - L_7X30_AXI_MDP_CLK, - L_7X30_AXI_IMEM_CLK, - L_7X30_AXI_LI_ADSP_A_CLK, - L_7X30_AXI_ROTATOR_CLK, + L_AXI_LI_VG_CLK, + L_AXI_LI_GRP_CLK, + L_AXI_LI_JPEG_CLK, + L_AXI_GRP_2D_CLK, + L_AXI_MFC_CLK, + L_AXI_VPE_CLK, + L_AXI_LI_VFE_CLK, + L_AXI_LI_APPS_CLK, + L_AXI_MDP_CLK, + L_AXI_IMEM_CLK, + L_AXI_LI_ADSP_A_CLK, + L_AXI_ROTATOR_CLK, - L_7X30_NR_CLKS + L_NR_CLKS }; -void pll_enable(uint32_t pll); -void pll_disable(uint32_t pll); - -enum { +enum clk_sources { PLL_0 = 0, PLL_1, PLL_2, @@ -148,22 +144,18 @@ enum { PLL_4, PLL_5, PLL_6, - NUM_PLL -}; - -enum { - LOW, - NOMINAL, - HIGH, - MSMC1_END + AXI, + LPXO, + TCXO, + NUM_SRC }; extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable); -extern struct clk_ops clk_ops_7x30; +extern struct clk_ops soc_clk_ops_7x30; #define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \ .name = clk_name, \ - .id = L_7X30_##clk_id, \ + .id = L_##clk_id, \ .remote_id = P_##clk_id, \ .flags = clk_flags, \ .dev = clk_dev, \ @@ -172,7 +164,7 @@ extern struct clk_ops clk_ops_7x30; #define CLK_7X30S(clk_name, l_id, r_id, clk_dev, clk_flags) { \ .name = clk_name, \ - .id = L_7X30_##l_id, \ + .id = L_##l_id, \ .remote_id = P_##r_id, \ .flags = clk_flags, \ .dev = clk_dev, \ @@ -181,11 +173,11 @@ extern struct clk_ops clk_ops_7x30; #define CLK_7X30L(clk_name, l_id, clk_dev, clk_flags) { \ .name = clk_name, \ - .id = L_7X30_##l_id, \ + .id = L_##l_id, \ .flags = clk_flags, \ .dev = clk_dev, \ .dbg_name = #l_id, \ - .ops = &clk_ops_7x30, \ + .ops = &soc_clk_ops_7x30, \ } #endif diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c new file mode 100644 index 0000000..d6eb6c6 --- /dev/null +++ b/arch/arm/mach-msm/clock-local.c @@ -0,0 +1,679 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/ctype.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <mach/msm_iomap.h> +#include <mach/clk.h> + +#include "clock.h" +#include "clock-local.h" + +/* When enabling/disabling a clock, check the halt bit up to this number + * number of times (with a 1 us delay in between) before continuing. */ +#define HALT_CHECK_MAX_LOOPS 100 +/* For clock without halt checking, wait this long after enables/disables. */ +#define HALT_CHECK_DELAY_US 10 + +DEFINE_SPINLOCK(local_clock_reg_lock); +struct clk_freq_tbl local_dummy_freq = F_END; + +#define MAX_SOURCES 20 +static int src_votes[MAX_SOURCES]; +static DEFINE_SPINLOCK(src_vote_lock); + +unsigned local_sys_vdd_votes[NUM_SYS_VDD_LEVELS]; +static DEFINE_SPINLOCK(sys_vdd_vote_lock); + +static int local_clk_enable_nolock(unsigned id); +static int local_clk_disable_nolock(unsigned id); +static int local_src_enable_nolock(int src); +static int local_src_disable_nolock(int src); + +/* + * Common Set-Rate Functions + */ +/* For clocks with integer dividers only. */ +void set_rate_basic(struct clk_local *clk, struct clk_freq_tbl *nf) +{ + uint32_t reg_val; + + reg_val = readl(clk->ns_reg); + reg_val &= ~(clk->ns_mask); + reg_val |= nf->ns_val; + writel(reg_val, clk->ns_reg); +} + +/* For clocks with MND dividers. */ +void set_rate_mnd(struct clk_local *clk, struct clk_freq_tbl *nf) +{ + uint32_t ns_reg_val, cc_reg_val; + + /* Assert MND reset. */ + ns_reg_val = readl(clk->ns_reg); + ns_reg_val |= B(7); + writel(ns_reg_val, clk->ns_reg); + + /* Program M and D values. */ + writel(nf->md_val, clk->md_reg); + + /* Program NS register. */ + ns_reg_val &= ~(clk->ns_mask); + ns_reg_val |= nf->ns_val; + writel(ns_reg_val, clk->ns_reg); + + /* If the clock has a separate CC register, program it. */ + if (clk->ns_reg != clk->cc_reg) { + cc_reg_val = readl(clk->cc_reg); + cc_reg_val &= ~(clk->cc_mask); + cc_reg_val |= nf->cc_val; + writel(cc_reg_val, clk->cc_reg); + } + + /* Deassert MND reset. */ + ns_reg_val &= ~B(7); + writel(ns_reg_val, clk->ns_reg); +} + +void set_rate_nop(struct clk_local *clk, struct clk_freq_tbl *nf) +{ + /* Nothing to do for fixed-rate clocks. */ +} + +/* + * SYS_VDD voting functions + */ + +/* Update system voltage level given the current votes. */ +static int local_update_sys_vdd(void) +{ + static int cur_level = NUM_SYS_VDD_LEVELS; + int level, rc = 0; + + if (local_sys_vdd_votes[HIGH]) + level = HIGH; + else if (local_sys_vdd_votes[NOMINAL]) + level = NOMINAL; + else if (local_sys_vdd_votes[LOW]) + level = LOW; + else + level = NONE; + + if (level == cur_level) + return rc; + + rc = soc_update_sys_vdd(level); + if (!rc) + cur_level = level; + + return rc; +} + +/* Vote for a system voltage level. */ +int local_vote_sys_vdd(unsigned level) +{ + int rc = 0; + unsigned long flags; + + /* Bounds checking. */ + if (level >= ARRAY_SIZE(local_sys_vdd_votes)) + return -EINVAL; + + spin_lock_irqsave(&sys_vdd_vote_lock, flags); + local_sys_vdd_votes[level]++; + rc = local_update_sys_vdd(); + if (rc) + local_sys_vdd_votes[level]--; + spin_unlock_irqrestore(&sys_vdd_vote_lock, flags); + + return rc; +} + +/* Remove vote for a system voltage level. */ +int local_unvote_sys_vdd(unsigned level) +{ + int rc = 0; + unsigned long flags; + + /* Bounds checking. */ + if (level >= ARRAY_SIZE(local_sys_vdd_votes)) + return -EINVAL; + + spin_lock_irqsave(&sys_vdd_vote_lock, flags); + if (local_sys_vdd_votes[level]) + local_sys_vdd_votes[level]--; + else { + pr_warning("%s: Reference counts are incorrect for level %d!\n", + __func__, level); + goto out; + } + + rc = local_update_sys_vdd(); + if (rc) + local_sys_vdd_votes[level]++; +out: + spin_unlock_irqrestore(&sys_vdd_vote_lock, flags); + return rc; +} + +/* + * Clock source (PLL/XO) control functions + */ + +/* Enable clock source without taking the lock. */ +static int local_src_enable_nolock(int src) +{ + int rc = 0; + + if (!src_votes[src]) { + if (soc_clk_sources[src].par != SRC_NONE) + rc = local_src_enable_nolock(soc_clk_sources[src].par); + if (rc) + goto err_par; + /* Perform source-specific enable operations. */ + if (soc_clk_sources[src].enable_func) + rc = soc_clk_sources[src].enable_func(src, 1); + if (rc) + goto err_enable; + } + src_votes[src]++; + + return rc; + +err_enable: + if (soc_clk_sources[src].par != SRC_NONE) + local_src_disable_nolock(soc_clk_sources[src].par); +err_par: + return rc; +} + +/* Enable clock source. */ +int local_src_enable(int src) +{ + int rc = 0; + unsigned long flags; + + if (src == SRC_NONE) + return rc; + + spin_lock_irqsave(&src_vote_lock, flags); + rc = local_src_enable_nolock(src); + spin_unlock_irqrestore(&src_vote_lock, flags); + + return rc; +} + +/* Disable clock source without taking the lock. */ +static int local_src_disable_nolock(int src) +{ + int rc = 0; + + if (src_votes[src] > 0) + src_votes[src]--; + else { + pr_warning("%s: Reference counts are incorrect for " + "src %d!\n", __func__, src); + return rc; + } + + if (src_votes[src] == 0) { + /* Perform source-specific disable operations. */ + if (soc_clk_sources[src].enable_func) + rc = soc_clk_sources[src].enable_func(src, 0); + if (rc) + goto err_disable; + if (soc_clk_sources[src].par != SRC_NONE) + rc = local_src_disable_nolock(soc_clk_sources[src].par); + if (rc) + goto err_disable_par; + + } + + return rc; + +err_disable_par: + soc_clk_sources[src].enable_func(src, 1); +err_disable: + src_votes[src]++; + return rc; +} + +/* Disable clock source. */ +int local_src_disable(int src) +{ + int rc = 0; + unsigned long flags; + + if (src == SRC_NONE) + return rc; + + spin_lock_irqsave(&src_vote_lock, flags); + rc = local_src_disable_nolock(src); + spin_unlock_irqrestore(&src_vote_lock, flags); + + return rc; +} + +/* + * Clock enable/disable functions + */ + +/* Return non-zero if a clock status registers shows the clock is halted. */ +static int local_clk_is_halted(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + int invert = (clk->halt_check == ENABLE); + int status_bit = readl(clk->halt_reg) & B(clk->halt_bit); + return invert ? !status_bit : status_bit; +} + +/* Perform any register operations required to enable the clock. */ +void local_clk_enable_reg(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + void *reg = clk->cc_reg; + uint32_t reg_val; + + WARN((clk->type != NORATE) && (clk->current_freq == &local_dummy_freq), + "Attempting to enable clock %d before setting its rate. " + "Set the rate first!\n", id); + + /* Enable MN counter, if applicable. */ + reg_val = readl(reg); + if (clk->type == MND) { + reg_val |= clk->current_freq->mnd_en_mask; + writel(reg_val, reg); + } + /* Enable root. */ + if (clk->root_en_mask) { + reg_val |= clk->root_en_mask; + writel(reg_val, reg); + } + /* Enable branch. */ + if (clk->br_en_mask) { + reg_val |= clk->br_en_mask; + writel(reg_val, reg); + } + + /* Wait for clock to enable before returning. */ + if (clk->halt_check == DELAY) + udelay(HALT_CHECK_DELAY_US); + else if (clk->halt_check == ENABLE || clk->halt_check == HALT + || clk->halt_check == ENABLE_VOTED + || clk->halt_check == HALT_VOTED) { + int count; + + /* Wait up to HALT_CHECK_MAX_LOOPS for clock to enable. */ + for (count = HALT_CHECK_MAX_LOOPS; local_clk_is_halted(id) + && count > 0; count--) + udelay(1); + if (count == 0) + pr_warning("%s: clock %d status stuck at 'off' (bit %d " + "of 0x%p).\n", __func__, id, clk->halt_bit, + clk->halt_reg); + } +} + +/* Perform any register operations required to enable the clock. */ +void local_clk_disable_reg(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + void *reg = clk->cc_reg; + uint32_t reg_val; + + /* Disable branch. */ + reg_val = readl(reg); + if (clk->br_en_mask) { + reg_val &= ~(clk->br_en_mask); + writel(reg_val, reg); + } + + /* Wait for clock to disable before continuing. */ + if (clk->halt_check == DELAY || clk->halt_check == ENABLE_VOTED + || clk->halt_check == HALT_VOTED) + udelay(HALT_CHECK_DELAY_US); + else if (clk->halt_check == ENABLE || clk->halt_check == HALT) { + int count; + + /* Wait up to HALT_CHECK_MAX_LOOPS for clock to disable. */ + for (count = HALT_CHECK_MAX_LOOPS; !local_clk_is_halted(id) + && count > 0; count--) + udelay(1); + if (count == 0) + pr_warning("%s: clock %d status stuck at 'on' (bit %d " + "of 0x%p).\n", __func__, id, clk->halt_bit, + clk->halt_reg); + } + + /* Disable root. */ + if (clk->root_en_mask) { + reg_val &= ~(clk->root_en_mask); + writel(reg_val, reg); + } + /* Disable MN counter, if applicable. */ + if (clk->type == MND) { + reg_val &= ~(clk->current_freq->mnd_en_mask); + writel(reg_val, reg); + } +} + +/* Enable a clock with no locking, enabling parent clocks as needed. */ +static int local_clk_enable_nolock(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + int rc = 0; + + if (clk->type == RESET) + return -EPERM; + + if (!clk->count) { + rc = local_vote_sys_vdd(clk->current_freq->sys_vdd); + if (rc) + goto err_vdd; + if (clk->parent != C(NONE)) { + rc = local_clk_enable_nolock(clk->parent); + if (rc) + goto err_par; + } + rc = local_src_enable(clk->current_freq->src); + if (rc) + goto err_src; + local_clk_enable_reg(id); + } + clk->count++; + + return rc; + +err_src: + if (clk->parent != C(NONE)) + rc = local_clk_disable_nolock(clk->parent); +err_par: + local_unvote_sys_vdd(clk->current_freq->sys_vdd); +err_vdd: + return rc; +} + +/* Disable a clock with no locking, disabling unused parents, too. */ +static int local_clk_disable_nolock(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + int rc = 0; + + if (clk->count > 0) + clk->count--; + else { + pr_warning("%s: Reference counts are incorrect for clock %d!\n", + __func__, id); + return rc; + } + + if (clk->count == 0) { + local_clk_disable_reg(id); + rc = local_src_disable(clk->current_freq->src); + if (rc) + goto err_src; + if (clk->parent != C(NONE)) + rc = local_clk_disable_nolock(clk->parent); + if (rc) + goto err_par; + rc = local_unvote_sys_vdd(clk->current_freq->sys_vdd); + if (rc) + goto err_vdd; + } + + return rc; + +err_vdd: + if (clk->parent != C(NONE)) + rc = local_clk_enable_nolock(clk->parent); +err_par: + local_src_enable(clk->current_freq->src); +err_src: + local_clk_enable_reg(id); + clk->count++; + + return rc; +} + +/* Enable a clock and any related power rail. */ +int local_clk_enable(unsigned id) +{ + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + rc = local_clk_enable_nolock(id); + if (rc) + goto unlock; + /* + * With remote rail control, the remote processor might modify + * the clock control register when the rail is enabled/disabled. + * Enable the rail inside the lock to protect against this. + */ + rc = soc_set_pwr_rail(id, 1); + if (rc) + local_clk_disable_nolock(id); +unlock: + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + return rc; +} + +/* Disable a clock and any related power rail. */ +void local_clk_disable(unsigned id) +{ + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + soc_set_pwr_rail(id, 0); + local_clk_disable_nolock(id); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +/* Turn off a clock at boot, without checking refcounts or disabling parents. */ +void local_clk_auto_off(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + unsigned long flags; + + if (clk->type == RESET) + return; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + local_clk_disable_reg(id); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); +} + +/* + * Frequency-related functions + */ + +/* Set a clock's frequency. */ +static int _local_clk_set_rate(unsigned id, struct clk_freq_tbl *nf) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + struct clk_freq_tbl *cf; + const int32_t *chld = clk->children; + int i, rc = 0; + unsigned long flags; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + + /* Check if frequency is actually changed. */ + cf = clk->current_freq; + if (nf == cf) + goto release_lock; + + /* Disable branch if clock isn't dual-banked with a glitch-free MUX. */ + if (clk->banked_mnd_masks == NULL) { + /* Disable all branches to prevent glitches. */ + for (i = 0; chld && chld[i] != C(NONE); i++) { + struct clk_local *ch = &soc_clk_local_tbl[chld[i]]; + /* Don't bother turning off if it is already off. + * Checking ch->count is cheaper (cache) than reading + * and writing to a register (uncached/unbuffered). */ + if (ch->count) + local_clk_disable_reg(chld[i]); + } + if (clk->count) + local_clk_disable_reg(id); + } + + if (clk->count) { + /* Vote for voltage and source for new freq. */ + rc = local_vote_sys_vdd(nf->sys_vdd); + if (rc) + goto sys_vdd_vote_failed; + rc = local_src_enable(nf->src); + if (rc) { + local_unvote_sys_vdd(nf->sys_vdd); + goto src_enable_failed; + } + } + + /* Perform clock-specific frequency switch operations. */ + BUG_ON(!clk->set_rate); + clk->set_rate(clk, nf); + + /* Release requirements of the old freq. */ + if (clk->count) { + local_src_disable(cf->src); + local_unvote_sys_vdd(cf->sys_vdd); + } + + /* Current freq must be updated before local_clk_enable_reg() + * is called to make sure the MNCNTR_EN bit is set correctly. */ + clk->current_freq = nf; + +src_enable_failed: +sys_vdd_vote_failed: + /* Enable any clocks that were disabled. */ + if (clk->banked_mnd_masks == NULL) { + if (clk->count) + local_clk_enable_reg(id); + /* Enable only branches that were ON before. */ + for (i = 0; chld && chld[i] != C(NONE); i++) { + struct clk_local *ch = &soc_clk_local_tbl[chld[i]]; + if (ch->count) + local_clk_enable_reg(chld[i]); + } + } + +release_lock: + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + return rc; +} + +/* Set a clock to an exact rate. */ +int local_clk_set_rate(unsigned id, unsigned rate) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + struct clk_freq_tbl *nf; + + if (clk->type == NORATE || clk->type == RESET) + return -EPERM; + + for (nf = clk->freq_tbl; nf->freq_hz != FREQ_END + && nf->freq_hz != rate; nf++) + ; + + if (nf->freq_hz == FREQ_END) + return -EINVAL; + + return _local_clk_set_rate(id, nf); +} + +/* Set a clock to a rate greater than some minimum. */ +int local_clk_set_min_rate(unsigned id, unsigned rate) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + struct clk_freq_tbl *nf; + + if (clk->type == NORATE || clk->type == RESET) + return -EPERM; + + for (nf = clk->freq_tbl; nf->freq_hz != FREQ_END + && nf->freq_hz < rate; nf++) + ; + + if (nf->freq_hz == FREQ_END) + return -EINVAL; + + return _local_clk_set_rate(id, nf); +} + +/* Set a clock to a maximum rate. */ +int local_clk_set_max_rate(unsigned id, unsigned rate) +{ + return -EPERM; +} + +/* Get the currently-set rate of a clock in Hz. */ +unsigned local_clk_get_rate(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + unsigned long flags; + unsigned ret = 0; + + if (clk->type == NORATE || clk->type == RESET) + return 0; + + spin_lock_irqsave(&local_clock_reg_lock, flags); + ret = clk->current_freq->freq_hz; + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + + /* Return 0 if the rate has never been set. Might not be correct, + * but it's good enough. */ + if (ret == FREQ_END) + ret = 0; + + return ret; +} + +/* Check if a clock is currently enabled. */ +unsigned local_clk_is_enabled(unsigned id) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + + if (clk->type == RESET) + return -EPERM; + + return !!(soc_clk_local_tbl[id].count); +} + +/* Return a supported rate that's at least the specified rate. */ +long local_clk_round_rate(unsigned id, unsigned rate) +{ + struct clk_local *clk = &soc_clk_local_tbl[id]; + struct clk_freq_tbl *f; + + if (clk->type == NORATE || clk->type == RESET) + return -EINVAL; + + for (f = clk->freq_tbl; f->freq_hz != FREQ_END; f++) + if (f->freq_hz >= rate) + return f->freq_hz; + + return -EPERM; +} diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h new file mode 100644 index 0000000..ebefad5 --- /dev/null +++ b/arch/arm/mach-msm/clock-local.h @@ -0,0 +1,232 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H +#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H + +#include <linux/spinlock.h> +#include "clock.h" + +/* + * Bit manipulation macros + */ +#define B(x) BIT(x) +#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) +#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb)) + +/* + * Clock types + */ +#define MND 1 /* Integer predivider and fractional MN:D divider. */ +#define BASIC 2 /* Integer divider. */ +#define NORATE 3 /* Just on/off. */ +#define RESET 4 /* Reset only. */ + +/* + * IDs for invalid sources, source selects, and XOs + */ +#define SRC_NONE -1 +#define SRC_SEL_NONE -1 +#define XO_NONE -1 + +/* + * Halt/Status Checking Mode Macros + */ +#define NOCHECK 0 /* No bit to check, do nothing */ +#define HALT 1 /* Bit pol: 1 = halted */ +#define HALT_VOTED 2 /* Bit pol: 1 = halted; delay on disable */ +#define ENABLE 3 /* Bit pol: 1 = running */ +#define ENABLE_VOTED 4 /* Bit pol: 1 = running; delay on disable */ +#define DELAY 5 /* No bit to check, just delay */ + +/* + * Generic frequency-definition structs and macros + */ +struct clk_freq_tbl { + const uint32_t freq_hz; + const int src; + const uint32_t md_val; + const uint32_t ns_val; + const uint32_t cc_val; + uint32_t mnd_en_mask; + const unsigned sys_vdd; + void *const extra_freq_data; +}; + +/* Some clocks have two banks to avoid glitches when switching frequencies. + * The unused bank is programmed while running on the other bank, and + * switched to afterwards. The following two structs describe the banks. */ +struct bank_mask_info { + void *const md_reg; + const uint32_t ns_mask; + const uint32_t rst_mask; + const uint32_t mnd_en_mask; + const uint32_t mode_mask; +}; + +struct banked_mnd_masks { + const uint32_t bank_sel_mask; + const struct bank_mask_info bank0_mask; + const struct bank_mask_info bank1_mask; +}; + +#define F_RAW(f, s, m_v, n_v, c_v, m_m, v, e) { \ + .freq_hz = f, \ + .src = s, \ + .md_val = m_v, \ + .ns_val = n_v, \ + .cc_val = c_v, \ + .mnd_en_mask = m_m, \ + .sys_vdd = v, \ + .extra_freq_data = e, \ + } +#define FREQ_END (UINT_MAX-1) +#define F_END F_RAW(FREQ_END, SRC_NONE, 0, 0, 0, 0, LOW, NULL) +#define PLL_RATE(l, m, n, v, d) { l, m, n, v, (d>>1) } + +/* + * Generic clock-definition struct and macros + */ +struct clk_local { + int count; + const uint32_t type; + void *const ns_reg; + void *const cc_reg; + void *const md_reg; + void *const reset_reg; + void *const halt_reg; + const uint32_t reset_mask; + const uint16_t halt_check; + const uint16_t halt_bit; + const uint32_t br_en_mask; + const uint32_t root_en_mask; + const uint32_t ns_mask; + const uint32_t cc_mask; + const uint32_t test_vector; + struct banked_mnd_masks *const banked_mnd_masks; + const int parent; + const uint32_t *const children; + void (*set_rate)(struct clk_local *, struct clk_freq_tbl *); + struct clk_freq_tbl *const freq_tbl; + struct clk_freq_tbl *current_freq; +}; + +#define C(x) L_##x##_CLK +#define L_NONE_CLK -1 +#define CLK(id, t, ns_r, cc_r, md_r, r_r, r_m, h_r, h_c, h_b, br, root, \ + n_m, c_m, s_fn, tbl, bmnd, par, chld_lst, tv) \ + [C(id)] = { \ + .type = t, \ + .ns_reg = ns_r, \ + .cc_reg = cc_r, \ + .md_reg = md_r, \ + .reset_reg = r_r, \ + .halt_reg = h_r, \ + .halt_check = h_c, \ + .halt_bit = h_b, \ + .reset_mask = r_m, \ + .br_en_mask = br, \ + .root_en_mask = root, \ + .ns_mask = n_m, \ + .cc_mask = c_m, \ + .test_vector = tv, \ + .banked_mnd_masks = bmnd, \ + .parent = C(par), \ + .children = chld_lst, \ + .set_rate = s_fn, \ + .freq_tbl = tbl, \ + .current_freq = &local_dummy_freq, \ + } + +/* + * Convenience macros + */ +#define set_1rate(clk) \ + local_clk_set_rate(C(clk), soc_clk_local_tbl[C(clk)].freq_tbl->freq_hz) + +/* + * SYS_VDD voltage levels + */ +enum sys_vdd_level { + NONE, + LOW, + NOMINAL, + HIGH, + NUM_SYS_VDD_LEVELS +}; + +/* + * Clock source descriptions + */ +struct clk_source { + int (*enable_func)(unsigned src, unsigned enable); + const signed par; +}; + +/* + * Variables from SoC-specific clock drivers + */ +extern struct clk_local soc_clk_local_tbl[]; +extern struct clk_source soc_clk_sources[]; + +/* + * Variables from clock-local driver + */ +extern spinlock_t local_clock_reg_lock; +extern struct clk_freq_tbl local_dummy_freq; + +/* + * Local-clock APIs + */ +int local_src_enable(int src); +int local_src_disable(int src); +void local_clk_enable_reg(unsigned id); +void local_clk_disable_reg(unsigned id); +int local_vote_sys_vdd(enum sys_vdd_level level); +int local_unvote_sys_vdd(enum sys_vdd_level level); + +/* + * clk_ops APIs + */ +int local_clk_enable(unsigned id); +void local_clk_disable(unsigned id); +void local_clk_auto_off(unsigned id); +int local_clk_set_rate(unsigned id, unsigned rate); +int local_clk_set_min_rate(unsigned id, unsigned rate); +int local_clk_set_max_rate(unsigned id, unsigned rate); +unsigned local_clk_get_rate(unsigned id); +unsigned local_clk_is_enabled(unsigned id); +long local_clk_round_rate(unsigned id, unsigned rate); + +/* + * Required SoC-specific functions, implemented for every supported SoC + */ +int soc_update_sys_vdd(enum sys_vdd_level level); +int soc_set_pwr_rail(unsigned id, int enable); +int soc_clk_set_flags(unsigned id, unsigned flags); +int soc_clk_reset(unsigned id, enum clk_reset_action action); + +/* + * Generic set-rate implementations + */ +void set_rate_basic(struct clk_local *clk, struct clk_freq_tbl *nf); +void set_rate_mnd(struct clk_local *clk, struct clk_freq_tbl *nf); +void set_rate_nop(struct clk_local *clk, struct clk_freq_tbl *nf); + +#endif /* __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_H */ + -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html