From: Stephen Boyd <sboyd@codeaurora.org>
To: linux-arm-msm@vger.kernel.org
Cc: "Saravana Kannan" <skannan@codeaurora.org>,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
"David Brown" <davidb@codeaurora.org>,
"Brian Swetland" <swetland@google.com>,
"Arve Hj�nnev�g" <arve@android.com>
Subject: [PATCH 05/22] msm: clock-7x30: Add 7x30 local clock driver
Date: Thu, 16 Dec 2010 16:49:49 -0800 [thread overview]
Message-ID: <1292547006-19741-6-git-send-email-sboyd@codeaurora.org> (raw)
In-Reply-To: <1292547006-19741-1-git-send-email-sboyd@codeaurora.org>
From: Saravana Kannan <skannan@codeaurora.org>
Support locally controllable clocks on the 7x30 target.
Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
arch/arm/mach-msm/Makefile | 1 +
arch/arm/mach-msm/clock-7x30.c | 1550 ++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-msm/clock-7x30.h | 38 +-
arch/arm/mach-msm/clock.c | 13 +-
arch/arm/mach-msm/clock.h | 12 +
arch/arm/mach-msm/proc_comm.h | 1 +
6 files changed, 1599 insertions(+), 16 deletions(-)
create mode 100644 arch/arm/mach-msm/clock-7x30.c
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index dc8ef08..8588b57 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-7x30.o
ifndef CONFIG_ARCH_MSM8X60
obj-y += acpuclock-arm11.o
obj-y += dma.o
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
new file mode 100644
index 0000000..beca3a6
--- /dev/null
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -0,0 +1,1550 @@
+/* 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-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. */
+
+/* Shadow-region 2 (SH2) registers. */
+#define QUP_I2C_NS_REG REG(0x04F0)
+#define CAM_NS_REG REG(0x0374)
+#define CAM_VFE_NS_REG REG(0x0044)
+#define CLK_HALT_STATEA_REG REG(0x0108)
+#define CLK_HALT_STATEB_REG REG(0x010C)
+#define CLK_HALT_STATEC_REG REG(0x02D4)
+#define CSI_NS_REG REG(0x0174)
+#define EMDH_NS_REG REG(0x0050)
+#define GLBL_CLK_ENA_2_SC_REG REG(0x03C0)
+#define GLBL_CLK_ENA_SC_REG REG(0x03BC)
+#define GLBL_CLK_STATE_2_REG REG(0x037C)
+#define GLBL_CLK_STATE_REG REG(0x0004)
+#define GRP_2D_NS_REG REG(0x0034)
+#define GRP_NS_REG REG(0x0084)
+#define HDMI_NS_REG REG(0x0484)
+#define I2C_2_NS_REG REG(0x02D8)
+#define I2C_NS_REG REG(0x0068)
+#define JPEG_NS_REG REG(0x0164)
+#define LPA_CORE_CLK_MA0_REG REG(0x04F4)
+#define LPA_CORE_CLK_MA2_REG REG(0x04FC)
+#define LPA_NS_REG REG(0x02E8)
+#define MDC_NS_REG REG(0x007C)
+#define MDP_LCDC_NS_REG REG(0x0390)
+#define MDP_NS_REG REG(0x014C)
+#define MDP_VSYNC_REG REG(0x0460)
+#define MFC_NS_REG REG(0x0154)
+#define MI2S_CODEC_RX_DIV_REG REG(0x02EC)
+#define MI2S_CODEC_TX_DIV_REG REG(0x02F0)
+#define MI2S_DIV_REG REG(0x02E4)
+#define MI2S_NS_REG REG(0x02E0)
+#define MI2S_RX_NS_REG REG(0x0070)
+#define MI2S_TX_NS_REG REG(0x0078)
+#define MIDI_NS_REG REG(0x02D0)
+#define PLL_ENA_REG REG(0x0264)
+#define PMDH_NS_REG REG(0x008C)
+#define SDAC_NS_REG REG(0x009C)
+#define SDCn_NS_REG(n) REG(0x00A4+(0x8*((n)-1)))
+#define SPI_NS_REG REG(0x02C8)
+#define TSIF_NS_REG REG(0x00C4)
+#define TV_NS_REG REG(0x00CC)
+#define UART1DM_NS_REG REG(0x00D4)
+#define UART2DM_NS_REG REG(0x00DC)
+#define UART2_NS_REG REG(0x0464)
+#define UART_NS_REG REG(0x00E0)
+#define USBH2_NS_REG REG(0x046C)
+#define USBH3_NS_REG REG(0x0470)
+#define USBH_MD_REG REG(0x02BC)
+#define USBH_NS_REG REG(0x02C0)
+#define VPE_NS_REG REG(0x015C)
+
+/* Registers in the base (non-shadow) region. */
+#define PLL0_STATUS_BASE_REG REG_BASE(0x0318)
+#define PLL1_STATUS_BASE_REG REG_BASE(0x0334)
+#define PLL2_STATUS_BASE_REG REG_BASE(0x0350)
+#define PLL3_STATUS_BASE_REG REG_BASE(0x036C)
+#define PLL4_STATUS_BASE_REG REG_BASE(0x0254)
+#define PLL5_STATUS_BASE_REG REG_BASE(0x0258)
+#define PLL6_STATUS_BASE_REG REG_BASE(0x04EC)
+#define SH2_OWN_APPS1_BASE_REG REG_BASE(0x040C)
+#define SH2_OWN_APPS2_BASE_REG REG_BASE(0x0414)
+#define SH2_OWN_APPS3_BASE_REG REG_BASE(0x0444)
+#define SH2_OWN_GLBL_BASE_REG REG_BASE(0x0404)
+#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))
+
+#define MD8(m, n) (BVAL(15, 8, m) | BVAL(7, 0, ~(n)))
+#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m)))
+#define MD16(m, n) (BVAL(31, 16, m) | BVAL(15, 0, ~(n)))
+#define N16(m, n) (BVAL(31, 16, ~(n-m)))
+#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 FREQ_END 0
+#define F_BASIC(f, s, div, v) F_RAW(f, s, 0, SDIV(s, div), 0, v)
+#define F_MND16(f, s, div, m, n, v) \
+ F_RAW(f, s, MD16(m, n), N16(m, n)|SPDIV(s, div), !!(n), v)
+#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_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_tcxo[] = {
+ F_RAW(19200000, SRC_TCXO, 0, 0, 0, NOMINAL),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_axi[] = {
+ F_RAW(1, SRC_AXI, 0, 0, 0, NOMINAL),
+ 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),
+ 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),
+ 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),
+ /* Sync to AXI. Hence this "rate" is not fixed. */
+ F_RAW(1, SRC_AXI, 0, B(14), 0, NOMINAL),
+ 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),
+ 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),
+ 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),
+ 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),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
+ F_RAW(24576000, SRC_LPXO, 0, 0, 0, NOMINAL),
+ 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),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_mi2s[] = {
+ F_MND16(12288000, SRC_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),
+ 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),
+ 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),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_usb[] = {
+ F_MND8(60000000, 23, 16, SRC_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),
+ 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),
+ 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),
+ 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),
+ 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),
+ 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 */
+ 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),
+ 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),
+ C(NONE)};
+
+static struct clk_local clk_local_tbl[] = {
+ CLK_NORATE(MDC, MDC_NS_REG, B(9), B(11),
+ CLK_HALT_STATEA_REG, 10, 0x4D56),
+ CLK_NORATE(LPA_CORE, LPA_NS_REG, B(5), 0,
+ CLK_HALT_STATEC_REG, 5, 0x0E),
+
+ CLK_1RATE(I2C, I2C_NS_REG, B(9), B(11), clk_tbl_tcxo,
+ CLK_HALT_STATEA_REG, 15, 0x4D4D),
+ CLK_1RATE(I2C_2, I2C_2_NS_REG, B(0), B(2), clk_tbl_tcxo,
+ CLK_HALT_STATEC_REG, 2, 0x0B),
+ CLK_1RATE(QUP_I2C, QUP_I2C_NS_REG, B(0), B(2), clk_tbl_tcxo,
+ CLK_HALT_STATEB_REG, 31, 0x1C),
+ CLK_1RATE(UART1, UART_NS_REG, B(5), B(4), clk_tbl_tcxo,
+ CLK_HALT_STATEB_REG, 7, 0x4D6F),
+ CLK_1RATE(UART2, UART2_NS_REG, B(5), B(4), clk_tbl_tcxo,
+ CLK_HALT_STATEB_REG, 5, 0x4D71),
+
+ CLK_BASIC(EMDH, EMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A,
+ NULL, 0, 0x4F00),
+ CLK_BASIC(PMDH, PMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A,
+ NULL, 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_MND8_P(VPE, VPE_NS_REG, 22, 15, B(9), B(11), clk_tbl_vpe,
+ AXI_VPE, NULL, CLK_HALT_STATEC_REG, 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),
+ CLK_SLAVE(MFC_DIV2, MFC_NS_REG, B(15), MFC, CLK_HALT_STATEC_REG,
+ 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),
+ CLK_MND8(SDC2, SDCn_NS_REG(2), 20, 13, B(9), B(11), clk_tbl_sdc2_4,
+ NULL, CLK_HALT_STATEA_REG, 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),
+ CLK_MND8(SDC4, SDCn_NS_REG(4), 20, 13, B(9), B(11), clk_tbl_sdc2_4,
+ NULL, CLK_HALT_STATEB_REG, 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_MND8(MIDI, MIDI_NS_REG, 19, 12, B(9), B(11), clk_tbl_midi, NULL,
+ CLK_HALT_STATEC_REG, 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),
+ CLK_SLAVE(USB_HS, USBH_NS_REG, B(9), USB_HS_SRC,
+ CLK_HALT_STATEB_REG, 26, 0x4D7F),
+ CLK_SLAVE(USB_HS_CORE, USBH_NS_REG, B(13), USB_HS_SRC,
+ CLK_HALT_STATEA_REG, 27, 0x14),
+ CLK_SLAVE(USB_HS2, USBH2_NS_REG, B(9), USB_HS_SRC,
+ CLK_HALT_STATEB_REG, 3, 0x4D73),
+ CLK_SLAVE(USB_HS2_CORE, USBH2_NS_REG, B(4), USB_HS_SRC,
+ CLK_HALT_STATEA_REG, 28, 0x15),
+ CLK_SLAVE(USB_HS3, USBH3_NS_REG, B(9), USB_HS_SRC,
+ CLK_HALT_STATEB_REG, 2, 0x4D74),
+ CLK_SLAVE(USB_HS3_CORE, USBH3_NS_REG, B(4), USB_HS_SRC,
+ CLK_HALT_STATEA_REG, 29, 0x16),
+ CLK_MND8(TV, TV_NS_REG, 23, 16, 0, B(11), clk_tbl_tv, chld_tv,
+ NULL, 0, 0),
+ CLK_SLAVE(HDMI, HDMI_NS_REG, B(9), TV,
+ CLK_HALT_STATEC_REG, 7, 0x13),
+ CLK_SLAVE(TV_DAC, TV_NS_REG, B(12), TV,
+ CLK_HALT_STATEB_REG, 27, 0x4D6C),
+ CLK_SLAVE(TV_ENC, TV_NS_REG, B(9), TV,
+ CLK_HALT_STATEB_REG, 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_MND16(UART1DM, UART1DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE,
+ NULL, CLK_HALT_STATEB_REG, 6, 0x4D70),
+ CLK_MND16(UART2DM, UART2DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE,
+ NULL, CLK_HALT_STATEB_REG, 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),
+ CLK_MND16(CAM_M, CAM_NS_REG, 0, B(9), clk_tbl_cam, NONE, NULL,
+ NULL, 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),
+ CLK_SLAVE(VFE_MDC, CAM_VFE_NS_REG, B(11), VFE, CLK_HALT_STATEA_REG,
+ 9, 0x4D57),
+ CLK_SLAVE(VFE_CAMIF, CAM_VFE_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG,
+ 13, 0x7000),
+ CLK_SLAVE(CSI0_VFE, CSI_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG,
+ 16, 0),
+
+ CLK_MND16(SDAC, SDAC_NS_REG, B(9), B(11), clk_tbl_sdac,
+ NONE, chld_sdac, CLK_HALT_STATEA_REG, 2, 0x4D60),
+ CLK_SLAVE(SDAC_M, SDAC_NS_REG, B(12), SDAC, CLK_HALT_STATEB_REG,
+ 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_SLAVE(MDP_LCDC_PAD_PCLK, MDP_LCDC_NS_REG, B(12), MDP_LCDC_PCLK,
+ CLK_HALT_STATEB_REG, 29, 0x4100),
+ CLK_1RATE(MDP_VSYNC, MDP_VSYNC_REG, B(0), 0, clk_tbl_mdp_vsync,
+ CLK_HALT_STATEB_REG, 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_SLAVE(MI2S_CODEC_RX_S, MI2S_RX_NS_REG, B(9), MI2S_CODEC_RX_M,
+ CLK_HALT_STATEA_REG, 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_SLAVE(MI2S_CODEC_TX_S, MI2S_TX_NS_REG, B(9), MI2S_CODEC_TX_M,
+ CLK_HALT_STATEA_REG, 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),
+ 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),
+ CLK_SLAVE(GRP_3D, GRP_NS_REG, B(7), GRP_3D_SRC, CLK_HALT_STATEB_REG,
+ 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),
+
+ CLK_MND8(CSI0, CSI_NS_REG, 24, 17, B(9), B(11), clk_tbl_csi, NULL,
+ CLK_HALT_STATEC_REG, 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),
+
+ /* Peripheral bus clocks. */
+ CLK_BRIDGE(ADM, GLBL_CLK_ENA_SC_REG, B(5), AXI_LI_APPS,
+ GLBL_CLK_STATE_REG, 5, 0x4000),
+ CLK_GLBL(ADM_P, GLBL_CLK_ENA_2_SC_REG, B(15),
+ GLBL_CLK_STATE_2_REG, 15, 0x11),
+ CLK_GLBL(CE, GLBL_CLK_ENA_SC_REG, B(6),
+ GLBL_CLK_STATE_REG, 6, 0x4D43),
+ CLK_GLBL(CAMIF_PAD_P, GLBL_CLK_ENA_SC_REG, B(9),
+ GLBL_CLK_STATE_REG, 9, 0x1A),
+ CLK_GLBL(CSI0_P, GLBL_CLK_ENA_SC_REG, B(30),
+ GLBL_CLK_STATE_REG, 30, 0),
+ CLK_GLBL(EMDH_P, GLBL_CLK_ENA_2_SC_REG, B(3),
+ GLBL_CLK_STATE_2_REG, 3, 0x03),
+ CLK_GLBL(GRP_2D_P, GLBL_CLK_ENA_SC_REG, B(24),
+ GLBL_CLK_STATE_REG, 24, 0x4D4C),
+ CLK_GLBL(GRP_3D_P, GLBL_CLK_ENA_2_SC_REG, B(17),
+ GLBL_CLK_STATE_2_REG, 17, 0x4D67),
+ CLK_GLBL(JPEG_P, GLBL_CLK_ENA_2_SC_REG, B(24),
+ GLBL_CLK_STATE_2_REG, 24, 0x4D5E),
+ CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC_REG, B(7),
+ GLBL_CLK_STATE_2_REG, 7, 0x07),
+ CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC_REG, B(6),
+ GLBL_CLK_STATE_2_REG, 6, 0x06),
+ CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC_REG, B(26),
+ GLBL_CLK_STATE_2_REG, 26, 0x4D75),
+ CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC_REG, B(4),
+ GLBL_CLK_STATE_2_REG, 4, 0x04),
+ CLK_GLBL(ROTATOR_IMEM, GLBL_CLK_ENA_2_SC_REG, B(23),
+ GLBL_CLK_STATE_2_REG, 23, 0x6600),
+ CLK_GLBL(ROTATOR_P, GLBL_CLK_ENA_2_SC_REG, B(25),
+ GLBL_CLK_STATE_2_REG, 25, 0x4D6D),
+ CLK_GLBL(SDC1_P, GLBL_CLK_ENA_SC_REG, B(7),
+ GLBL_CLK_STATE_REG, 7, 0x4D61),
+ CLK_GLBL(SDC2_P, GLBL_CLK_ENA_SC_REG, B(8),
+ GLBL_CLK_STATE_REG, 8, 0x4F63),
+ CLK_GLBL(SDC3_P, GLBL_CLK_ENA_SC_REG, B(27),
+ GLBL_CLK_STATE_REG, 27, 0x4D79),
+ CLK_GLBL(SDC4_P, GLBL_CLK_ENA_SC_REG, B(28),
+ GLBL_CLK_STATE_REG, 28, 0x4D7B),
+ CLK_GLBL(SPI_P, GLBL_CLK_ENA_2_SC_REG, B(10),
+ GLBL_CLK_STATE_2_REG, 10, 0x18),
+ CLK_GLBL(TSIF_P, GLBL_CLK_ENA_SC_REG, B(18),
+ GLBL_CLK_STATE_REG, 18, 0x4D65),
+ CLK_GLBL(UART1DM_P, GLBL_CLK_ENA_SC_REG, B(17),
+ GLBL_CLK_STATE_REG, 17, 0x4D5C),
+ CLK_GLBL(UART2DM_P, GLBL_CLK_ENA_SC_REG, B(26),
+ GLBL_CLK_STATE_REG, 26, 0x4D7E),
+ CLK_GLBL(USB_HS2_P, GLBL_CLK_ENA_2_SC_REG, B(8),
+ GLBL_CLK_STATE_2_REG, 8, 0x08),
+ CLK_GLBL(USB_HS3_P, GLBL_CLK_ENA_2_SC_REG, B(9),
+ GLBL_CLK_STATE_2_REG, 9, 0x10),
+ CLK_GLBL(USB_HS_P, GLBL_CLK_ENA_SC_REG, B(25),
+ GLBL_CLK_STATE_REG, 25, 0x4D58),
+ CLK_GLBL(VFE_P, GLBL_CLK_ENA_2_SC_REG, B(27),
+ GLBL_CLK_STATE_2_REG, 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),
+ CLK_BRIDGE(AXI_LI_ADSP_A, GLBL_CLK_ENA_2_SC_REG, B(14), AXI_LI_APPS,
+ GLBL_CLK_STATE_2_REG, 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),
+ CLK_BRIDGE(AXI_LI_VFE, GLBL_CLK_ENA_SC_REG, B(23), AXI_LI_APPS,
+ GLBL_CLK_STATE_REG, 23, 0x5B00),
+ CLK_BRIDGE(AXI_MDP, GLBL_CLK_ENA_2_SC_REG, B(29), AXI_LI_APPS,
+ GLBL_CLK_STATE_2_REG, 29, 0x6B00),
+
+ CLK_BRIDGE(AXI_IMEM, GLBL_CLK_ENA_2_SC_REG, B(18), GLBL_ROOT,
+ GLBL_CLK_STATE_2_REG, 18, 0x4B00),
+
+ CLK_BRIDGE(AXI_LI_VG, GLBL_CLK_ENA_SC_REG, B(3), GLBL_ROOT,
+ GLBL_CLK_STATE_REG, 3, 0x4700),
+ CLK_BRIDGE(AXI_GRP_2D, GLBL_CLK_ENA_SC_REG, B(21), AXI_LI_VG,
+ GLBL_CLK_STATE_REG, 21, 0x5900),
+ CLK_BRIDGE(AXI_LI_GRP, GLBL_CLK_ENA_SC_REG, B(22), AXI_LI_VG,
+ GLBL_CLK_STATE_REG, 22, 0x5A00),
+ CLK_BRIDGE(AXI_MFC, GLBL_CLK_ENA_2_SC_REG, B(20), AXI_LI_VG,
+ GLBL_CLK_STATE_2_REG, 20, 0x6A00),
+ CLK_BRIDGE(AXI_ROTATOR, GLBL_CLK_ENA_2_SC_REG, B(22), AXI_LI_VG,
+ GLBL_CLK_STATE_2_REG, 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
+};
+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;
+
+static int update_msmc1(void)
+{
+ 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)
+ goto out;
+
+ if (mvolts) {
+ err = -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);
+ }
+}
+
+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)
+{
+ /* 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)
+{
+ uint32_t regval, ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_reg_lock, flags);
+ switch (id) {
+ case C(VFE):
+ regval = readl(CAM_VFE_NS_REG);
+ /* Flag values chosen for backward compatibility
+ * with proc_comm remote clock control. */
+ if (clk_flags == 0x00000100) {
+ /* Select external source. */
+ regval |= B(14);
+ } else if (clk_flags == 0x00000200) {
+ /* Select internal source. */
+ regval &= ~B(14);
+ } else
+ ret = -EINVAL;
+
+ writel(regval, CAM_VFE_NS_REG);
+ break;
+ default:
+ ret = -EPERM;
+ }
+ spin_unlock_irqrestore(&clock_reg_lock, flags);
+
+ return ret;
+}
+
+static unsigned soc_clk_get_rate(unsigned id)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ unsigned long flags;
+ unsigned ret = 0;
+
+ if (t->type == NORATE)
+ 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;
+}
+
+static unsigned soc_clk_is_enabled(unsigned id)
+{
+ return !!(clk_local_tbl[id].count);
+}
+
+
+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,
+};
+
+/*
+ * Clock ownership detection code
+ */
+
+enum {
+ SH2_OWN_GLBL,
+ SH2_OWN_APPS1,
+ SH2_OWN_APPS2,
+ SH2_OWN_ROW1,
+ SH2_OWN_ROW2,
+ SH2_OWN_APPS3,
+ NUM_OWNERSHIP
+};
+static __initdata uint32_t ownership_regs[NUM_OWNERSHIP];
+
+static void __init cache_ownership(void)
+{
+ ownership_regs[SH2_OWN_GLBL] = readl(SH2_OWN_GLBL_BASE_REG);
+ ownership_regs[SH2_OWN_APPS1] = readl(SH2_OWN_APPS1_BASE_REG);
+ ownership_regs[SH2_OWN_APPS2] = readl(SH2_OWN_APPS2_BASE_REG);
+ ownership_regs[SH2_OWN_ROW1] = readl(SH2_OWN_ROW1_BASE_REG);
+ ownership_regs[SH2_OWN_ROW2] = readl(SH2_OWN_ROW2_BASE_REG);
+ ownership_regs[SH2_OWN_APPS3] = readl(SH2_OWN_APPS3_BASE_REG);
+}
+
+static void __init print_ownership(void)
+{
+ pr_info("Clock ownership\n");
+ pr_info(" GLBL : %08x\n", ownership_regs[SH2_OWN_GLBL]);
+ pr_info(" APPS : %08x %08x %08x\n", ownership_regs[SH2_OWN_APPS1],
+ ownership_regs[SH2_OWN_APPS2], ownership_regs[SH2_OWN_APPS3]);
+ pr_info(" ROW : %08x %08x\n", ownership_regs[SH2_OWN_ROW1],
+ ownership_regs[SH2_OWN_ROW2]);
+}
+
+/*
+ * This is a many-to-one mapping since we don't know how the remote clock code
+ * has decided to handle the dependencies between clocks for a particular
+ * hardware block. We determine the ownership for all the clocks on a block by
+ * checking the ownership bit of one register (usually the ns register).
+ */
+#define O(x) (&ownership_regs[(x)])
+static const struct clk_local_ownership {
+ const uint32_t *reg;
+ const uint32_t bit;
+} ownership_map[] __initconst = {
+ [C(GRP_2D)] = { O(SH2_OWN_APPS1), B(6) },
+ [C(GRP_2D_P)] = { O(SH2_OWN_APPS1), B(6) },
+ [C(HDMI)] = { O(SH2_OWN_APPS1), B(31) },
+ [C(JPEG)] = { O(SH2_OWN_APPS1), B(0) },
+ [C(JPEG_P)] = { O(SH2_OWN_APPS1), B(0) },
+ [C(LPA_CODEC)] = { O(SH2_OWN_APPS1), B(23) },
+ [C(LPA_CORE)] = { O(SH2_OWN_APPS1), B(23) },
+ [C(LPA_P)] = { O(SH2_OWN_APPS1), B(23) },
+ [C(MI2S_M)] = { O(SH2_OWN_APPS1), B(28) },
+ [C(MI2S_S)] = { O(SH2_OWN_APPS1), B(28) },
+ [C(MI2S_CODEC_RX_M)] = { O(SH2_OWN_APPS1), B(12) },
+ [C(MI2S_CODEC_RX_S)] = { O(SH2_OWN_APPS1), B(12) },
+ [C(MI2S_CODEC_TX_M)] = { O(SH2_OWN_APPS1), B(14) },
+ [C(MI2S_CODEC_TX_S)] = { O(SH2_OWN_APPS1), B(14) },
+ [C(MIDI)] = { O(SH2_OWN_APPS1), B(22) },
+ [C(SDAC)] = { O(SH2_OWN_APPS1), B(26) },
+ [C(SDAC_M)] = { O(SH2_OWN_APPS1), B(26) },
+ [C(VFE)] = { O(SH2_OWN_APPS1), B(8) },
+ [C(VFE_CAMIF)] = { O(SH2_OWN_APPS1), B(8) },
+ [C(VFE_MDC)] = { O(SH2_OWN_APPS1), B(8) },
+ [C(VFE_P)] = { O(SH2_OWN_APPS1), B(8) },
+
+ [C(GRP_3D)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(GRP_3D_P)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(GRP_3D_SRC)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(IMEM)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(MDP_LCDC_PAD_PCLK)] = { O(SH2_OWN_APPS2), B(4) },
+ [C(MDP_LCDC_PCLK)] = { O(SH2_OWN_APPS2), B(4) },
+ [C(MDP_P)] = { O(SH2_OWN_APPS2), B(4) },
+ [C(MDP_VSYNC)] = { O(SH2_OWN_APPS2), B(28) },
+ [C(TSIF_REF)] = { O(SH2_OWN_APPS2), B(5) },
+ [C(TSIF_P)] = { O(SH2_OWN_APPS2), B(5) },
+ [C(TV)] = { O(SH2_OWN_APPS2), B(2) },
+ [C(TV_DAC)] = { O(SH2_OWN_APPS2), B(2) },
+ [C(TV_ENC)] = { O(SH2_OWN_APPS2), B(2) },
+
+ [C(EMDH)] = { O(SH2_OWN_ROW1), B(7) },
+ [C(EMDH_P)] = { O(SH2_OWN_ROW1), B(7) },
+ [C(I2C)] = { O(SH2_OWN_ROW1), B(11) },
+ [C(I2C_2)] = { O(SH2_OWN_ROW1), B(12) },
+ [C(MDC)] = { O(SH2_OWN_ROW1), B(17) },
+ [C(PMDH)] = { O(SH2_OWN_ROW1), B(19) },
+ [C(PMDH_P)] = { O(SH2_OWN_ROW1), B(19) },
+ [C(SDC1)] = { O(SH2_OWN_ROW1), B(23) },
+ [C(SDC1_P)] = { O(SH2_OWN_ROW1), B(23) },
+ [C(SDC2)] = { O(SH2_OWN_ROW1), B(25) },
+ [C(SDC2_P)] = { O(SH2_OWN_ROW1), B(25) },
+ [C(SDC3)] = { O(SH2_OWN_ROW1), B(27) },
+ [C(SDC3_P)] = { O(SH2_OWN_ROW1), B(27) },
+ [C(SDC4)] = { O(SH2_OWN_ROW1), B(29) },
+ [C(SDC4_P)] = { O(SH2_OWN_ROW1), B(29) },
+ [C(UART2)] = { O(SH2_OWN_ROW1), B(0) },
+ [C(USB_HS2)] = { O(SH2_OWN_ROW1), B(2) },
+ [C(USB_HS2_CORE)] = { O(SH2_OWN_ROW1), B(2) },
+ [C(USB_HS2_P)] = { O(SH2_OWN_ROW1), B(2) },
+ [C(USB_HS3)] = { O(SH2_OWN_ROW1), B(4) },
+ [C(USB_HS3_CORE)] = { O(SH2_OWN_ROW1), B(4) },
+ [C(USB_HS3_P)] = { O(SH2_OWN_ROW1), B(4) },
+
+ [C(QUP_I2C)] = { O(SH2_OWN_ROW2), B(3) },
+ [C(SPI)] = { O(SH2_OWN_ROW2), B(1) },
+ [C(SPI_P)] = { O(SH2_OWN_ROW2), B(1) },
+ [C(UART1)] = { O(SH2_OWN_ROW2), B(9) },
+ [C(UART1DM)] = { O(SH2_OWN_ROW2), B(6) },
+ [C(UART1DM_P)] = { O(SH2_OWN_ROW2), B(6) },
+ [C(UART2DM)] = { O(SH2_OWN_ROW2), B(8) },
+ [C(UART2DM_P)] = { O(SH2_OWN_ROW2), B(8) },
+ [C(USB_HS)] = { O(SH2_OWN_ROW2), B(11) },
+ [C(USB_HS_CORE)] = { O(SH2_OWN_ROW2), B(11) },
+ [C(USB_HS_SRC)] = { O(SH2_OWN_ROW2), B(11) },
+ [C(USB_HS_P)] = { O(SH2_OWN_ROW2), B(11) },
+
+ [C(CAM_M)] = { O(SH2_OWN_APPS3), B(6) },
+ [C(CAMIF_PAD_P)] = { O(SH2_OWN_APPS3), B(6) },
+ [C(CSI0)] = { O(SH2_OWN_APPS3), B(11) },
+ [C(CSI0_VFE)] = { O(SH2_OWN_APPS3), B(11) },
+ [C(CSI0_P)] = { O(SH2_OWN_APPS3), B(11) },
+ [C(MDP)] = { O(SH2_OWN_APPS3), B(0) },
+ [C(MFC)] = { O(SH2_OWN_APPS3), B(2) },
+ [C(MFC_DIV2)] = { O(SH2_OWN_APPS3), B(2) },
+ [C(MFC_P)] = { O(SH2_OWN_APPS3), B(2) },
+ [C(VPE)] = { O(SH2_OWN_APPS3), B(4) },
+
+ [C(ADM)] = { O(SH2_OWN_GLBL), B(8) },
+ [C(ADM_P)] = { O(SH2_OWN_GLBL), B(13) },
+ [C(CE)] = { O(SH2_OWN_GLBL), B(8) },
+ [C(AXI_ROTATOR)] = { O(SH2_OWN_GLBL), B(13) },
+ [C(ROTATOR_IMEM)] = { O(SH2_OWN_GLBL), B(13) },
+ [C(ROTATOR_P)] = { O(SH2_OWN_GLBL), B(13) },
+};
+
+static bool __init clk_is_local(uint32_t id)
+{
+ uint32_t bit = ownership_map[id].bit;
+ const uint32_t *reg = ownership_map[id].reg;
+
+ BUG_ON(id >= ARRAY_SIZE(ownership_map) || !reg);
+
+ return *reg & bit;
+}
+
+static const struct reg_init {
+ const void __iomem *reg;
+ uint32_t mask;
+ uint32_t val;
+} ri_list[] __initconst = {
+ /* Enable UMDX_P clock. Known to causes issues, so never turn off. */
+ {GLBL_CLK_ENA_2_SC_REG, B(2), B(2)},
+
+ {EMDH_NS_REG, BM(18, 17) , BVAL(18, 17, 0x3)}, /* RX div = div-4. */
+ {PMDH_NS_REG, BM(18, 17), BVAL(18, 17, 0x3)}, /* RX div = div-4. */
+ /* MI2S_CODEC_RX_S src = MI2S_CODEC_RX_M. */
+ {MI2S_RX_NS_REG, B(14), 0x0},
+ /* MI2S_CODEC_TX_S src = MI2S_CODEC_TX_M. */
+ {MI2S_TX_NS_REG, B(14), 0x0},
+ {MI2S_NS_REG, B(14), 0x0}, /* MI2S_S src = MI2S_M. */
+ /* Allow DSP to decide the LPA CORE src. */
+ {LPA_CORE_CLK_MA0_REG, B(0), B(0)},
+ {LPA_CORE_CLK_MA2_REG, B(0), B(0)},
+ {MI2S_CODEC_RX_DIV_REG, 0xF, 0xD}, /* MI2S_CODEC_RX_S div = div-8. */
+ {MI2S_CODEC_TX_DIV_REG, 0xF, 0xD}, /* MI2S_CODEC_TX_S div = div-8. */
+ {MI2S_DIV_REG, 0xF, 0x7}, /* MI2S_S div = div-8. */
+ {MDC_NS_REG, 0x3, 0x3}, /* MDC src = external MDH src. */
+ {SDAC_NS_REG, BM(15, 14), 0x0}, /* SDAC div = div-1. */
+ /* Disable sources TCXO/5 & TCXO/6. UART1 src = TCXO*/
+ {UART_NS_REG, BM(26, 25) | BM(2, 0), 0x0},
+ {MDP_VSYNC_REG, 0xC, 0x4}, /* MDP VSYNC src = LPXO. */
+ /* HDMI div = div-1, non-inverted. tv_enc_src = tv_clk_src */
+ {HDMI_NS_REG, 0x7, 0x0},
+ {TV_NS_REG, BM(15, 14), 0x0}, /* tv_clk_src_div2 = div-1 */
+
+ /* USBH core clocks src = USB_HS_SRC. */
+ {USBH_NS_REG, B(15), B(15)},
+ {USBH2_NS_REG, B(6), B(6)},
+ {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)
+void __init msm_clk_soc_init(void)
+{
+ int i;
+ uint32_t val;
+
+ cache_ownership();
+ print_ownership();
+
+ /* When we have no local clock control, the rest of the code in this
+ * function is a NOP since writes to shadow regions that we don't own
+ * are ignored. */
+
+ /* Disable all the child clocks of USB_HS_SRC. This needs to be done
+ * before the register init loop since it changes the source of the
+ * 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]);
+
+ if (clk_is_local(C(USB_HS_SRC)))
+ soc_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);
+ val &= ~ri_list[i].mask;
+ val |= ri_list[i].val;
+ writel(val, ri_list[i].reg);
+ }
+
+ set_1rate(I2C);
+ set_1rate(I2C_2);
+ set_1rate(QUP_I2C);
+ set_1rate(UART1);
+ set_1rate(UART2);
+ set_1rate(MI2S_M);
+ set_1rate(MIDI);
+ set_1rate(MDP_VSYNC);
+ set_1rate(LPA_CODEC);
+ set_1rate(GLBL_ROOT);
+
+ /* Sync the GRP2D clock to AXI */
+ soc_clk_set_rate(C(GRP_2D), 1);
+}
diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h
index e16f72f..d41acb7 100644
--- a/arch/arm/mach-msm/clock-7x30.h
+++ b/arch/arm/mach-msm/clock-7x30.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -33,6 +33,8 @@
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,
@@ -135,17 +137,30 @@ enum {
L_7X30_NR_CLKS
};
-struct clk_ops;
-extern struct clk_ops clk_ops_7x30;
-
-struct clk_ops *clk_7x30_is_local(uint32_t id);
-int clk_7x30_init(void);
-
void pll_enable(uint32_t pll);
void pll_disable(uint32_t pll);
+enum {
+ PLL_0 = 0,
+ PLL_1,
+ PLL_2,
+ PLL_3,
+ PLL_4,
+ PLL_5,
+ PLL_6,
+ NUM_PLL
+};
+
+enum {
+ LOW,
+ NOMINAL,
+ HIGH,
+ MSMC1_END
+};
+
extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable);
+extern struct clk_ops clk_ops_7x30;
#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \
.name = clk_name, \
.id = L_7X30_##clk_id, \
@@ -164,5 +179,14 @@ extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable);
.dbg_name = #l_id, \
}
+#define CLK_7X30L(clk_name, l_id, clk_dev, clk_flags) { \
+ .name = clk_name, \
+ .id = L_7X30_##l_id, \
+ .flags = clk_flags, \
+ .dev = clk_dev, \
+ .dbg_name = #l_id, \
+ .ops = &clk_ops_7x30, \
+ }
+
#endif
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 8c2b4dd..56c7549 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -162,21 +162,16 @@ EXPORT_SYMBOL(clk_set_flags);
*/
static struct clk *ebi1_clk;
-static void __init set_clock_ops(struct clk *clk)
-{
- if (!clk->ops) {
- clk->ops = &clk_ops_pcom;
- clk->id = clk->remote_id;
- }
-}
-
void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks)
{
unsigned n;
+ /* Do SoC-speficic clock init operations. */
+ msm_clk_soc_init();
+
mutex_lock(&clocks_mutex);
for (n = 0; n < num_clocks; n++) {
- set_clock_ops(&clock_tbl[n]);
+ msm_clk_soc_set_ops(&clock_tbl[n]);
list_add_tail(&clock_tbl[n].list, &clocks);
}
mutex_unlock(&clocks_mutex);
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 70216b0..4841ab6 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -62,6 +62,18 @@ struct clk {
#define CLK_MAX CLKFLAG_MAX
#define CLK_MINMAX (CLK_MIN | CLK_MAX)
+#ifdef CONFIG_ARCH_MSM7X30
+void __init msm_clk_soc_set_ops(struct clk *clk);
+#else
+static inline void __init msm_clk_soc_set_ops(struct clk *clk) { }
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+void __init msm_clk_soc_init(void);
+#else
+static inline void __init msm_clk_soc_init(void) { }
+#endif
+
#ifdef CONFIG_DEBUG_FS
int __init clock_debug_init(void);
int __init clock_debug_add(struct clk *clock);
diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h
index 12da4ca..e2f2d5a 100644
--- a/arch/arm/mach-msm/proc_comm.h
+++ b/arch/arm/mach-msm/proc_comm.h
@@ -137,6 +137,7 @@ enum {
PCOM_CLKCTL_RPC_RAIL_DISABLE,
PCOM_CLKCTL_RPC_RAIL_CONTROL,
PCOM_CLKCTL_RPC_MIN_MSMC1,
+ PCOM_CLKCTL_RPC_SRC_REQUEST,
PCOM_NUM_CMDS,
};
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
WARNING: multiple messages have this Message-ID (diff)
From: sboyd@codeaurora.org (Stephen Boyd)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 05/22] msm: clock-7x30: Add 7x30 local clock driver
Date: Thu, 16 Dec 2010 16:49:49 -0800 [thread overview]
Message-ID: <1292547006-19741-6-git-send-email-sboyd@codeaurora.org> (raw)
In-Reply-To: <1292547006-19741-1-git-send-email-sboyd@codeaurora.org>
From: Saravana Kannan <skannan@codeaurora.org>
Support locally controllable clocks on the 7x30 target.
Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
arch/arm/mach-msm/Makefile | 1 +
arch/arm/mach-msm/clock-7x30.c | 1550 ++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-msm/clock-7x30.h | 38 +-
arch/arm/mach-msm/clock.c | 13 +-
arch/arm/mach-msm/clock.h | 12 +
arch/arm/mach-msm/proc_comm.h | 1 +
6 files changed, 1599 insertions(+), 16 deletions(-)
create mode 100644 arch/arm/mach-msm/clock-7x30.c
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index dc8ef08..8588b57 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-7x30.o
ifndef CONFIG_ARCH_MSM8X60
obj-y += acpuclock-arm11.o
obj-y += dma.o
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
new file mode 100644
index 0000000..beca3a6
--- /dev/null
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -0,0 +1,1550 @@
+/* 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-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. */
+
+/* Shadow-region 2 (SH2) registers. */
+#define QUP_I2C_NS_REG REG(0x04F0)
+#define CAM_NS_REG REG(0x0374)
+#define CAM_VFE_NS_REG REG(0x0044)
+#define CLK_HALT_STATEA_REG REG(0x0108)
+#define CLK_HALT_STATEB_REG REG(0x010C)
+#define CLK_HALT_STATEC_REG REG(0x02D4)
+#define CSI_NS_REG REG(0x0174)
+#define EMDH_NS_REG REG(0x0050)
+#define GLBL_CLK_ENA_2_SC_REG REG(0x03C0)
+#define GLBL_CLK_ENA_SC_REG REG(0x03BC)
+#define GLBL_CLK_STATE_2_REG REG(0x037C)
+#define GLBL_CLK_STATE_REG REG(0x0004)
+#define GRP_2D_NS_REG REG(0x0034)
+#define GRP_NS_REG REG(0x0084)
+#define HDMI_NS_REG REG(0x0484)
+#define I2C_2_NS_REG REG(0x02D8)
+#define I2C_NS_REG REG(0x0068)
+#define JPEG_NS_REG REG(0x0164)
+#define LPA_CORE_CLK_MA0_REG REG(0x04F4)
+#define LPA_CORE_CLK_MA2_REG REG(0x04FC)
+#define LPA_NS_REG REG(0x02E8)
+#define MDC_NS_REG REG(0x007C)
+#define MDP_LCDC_NS_REG REG(0x0390)
+#define MDP_NS_REG REG(0x014C)
+#define MDP_VSYNC_REG REG(0x0460)
+#define MFC_NS_REG REG(0x0154)
+#define MI2S_CODEC_RX_DIV_REG REG(0x02EC)
+#define MI2S_CODEC_TX_DIV_REG REG(0x02F0)
+#define MI2S_DIV_REG REG(0x02E4)
+#define MI2S_NS_REG REG(0x02E0)
+#define MI2S_RX_NS_REG REG(0x0070)
+#define MI2S_TX_NS_REG REG(0x0078)
+#define MIDI_NS_REG REG(0x02D0)
+#define PLL_ENA_REG REG(0x0264)
+#define PMDH_NS_REG REG(0x008C)
+#define SDAC_NS_REG REG(0x009C)
+#define SDCn_NS_REG(n) REG(0x00A4+(0x8*((n)-1)))
+#define SPI_NS_REG REG(0x02C8)
+#define TSIF_NS_REG REG(0x00C4)
+#define TV_NS_REG REG(0x00CC)
+#define UART1DM_NS_REG REG(0x00D4)
+#define UART2DM_NS_REG REG(0x00DC)
+#define UART2_NS_REG REG(0x0464)
+#define UART_NS_REG REG(0x00E0)
+#define USBH2_NS_REG REG(0x046C)
+#define USBH3_NS_REG REG(0x0470)
+#define USBH_MD_REG REG(0x02BC)
+#define USBH_NS_REG REG(0x02C0)
+#define VPE_NS_REG REG(0x015C)
+
+/* Registers in the base (non-shadow) region. */
+#define PLL0_STATUS_BASE_REG REG_BASE(0x0318)
+#define PLL1_STATUS_BASE_REG REG_BASE(0x0334)
+#define PLL2_STATUS_BASE_REG REG_BASE(0x0350)
+#define PLL3_STATUS_BASE_REG REG_BASE(0x036C)
+#define PLL4_STATUS_BASE_REG REG_BASE(0x0254)
+#define PLL5_STATUS_BASE_REG REG_BASE(0x0258)
+#define PLL6_STATUS_BASE_REG REG_BASE(0x04EC)
+#define SH2_OWN_APPS1_BASE_REG REG_BASE(0x040C)
+#define SH2_OWN_APPS2_BASE_REG REG_BASE(0x0414)
+#define SH2_OWN_APPS3_BASE_REG REG_BASE(0x0444)
+#define SH2_OWN_GLBL_BASE_REG REG_BASE(0x0404)
+#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))
+
+#define MD8(m, n) (BVAL(15, 8, m) | BVAL(7, 0, ~(n)))
+#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m)))
+#define MD16(m, n) (BVAL(31, 16, m) | BVAL(15, 0, ~(n)))
+#define N16(m, n) (BVAL(31, 16, ~(n-m)))
+#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 FREQ_END 0
+#define F_BASIC(f, s, div, v) F_RAW(f, s, 0, SDIV(s, div), 0, v)
+#define F_MND16(f, s, div, m, n, v) \
+ F_RAW(f, s, MD16(m, n), N16(m, n)|SPDIV(s, div), !!(n), v)
+#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_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_tcxo[] = {
+ F_RAW(19200000, SRC_TCXO, 0, 0, 0, NOMINAL),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_axi[] = {
+ F_RAW(1, SRC_AXI, 0, 0, 0, NOMINAL),
+ 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),
+ 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),
+ 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),
+ /* Sync to AXI. Hence this "rate" is not fixed. */
+ F_RAW(1, SRC_AXI, 0, B(14), 0, NOMINAL),
+ 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),
+ 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),
+ 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),
+ 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),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
+ F_RAW(24576000, SRC_LPXO, 0, 0, 0, NOMINAL),
+ 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),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_mi2s[] = {
+ F_MND16(12288000, SRC_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),
+ 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),
+ 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),
+ F_END,
+};
+
+static const struct clk_freq_tbl clk_tbl_usb[] = {
+ F_MND8(60000000, 23, 16, SRC_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),
+ 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),
+ 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),
+ 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),
+ 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),
+ 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 */
+ 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),
+ 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),
+ C(NONE)};
+
+static struct clk_local clk_local_tbl[] = {
+ CLK_NORATE(MDC, MDC_NS_REG, B(9), B(11),
+ CLK_HALT_STATEA_REG, 10, 0x4D56),
+ CLK_NORATE(LPA_CORE, LPA_NS_REG, B(5), 0,
+ CLK_HALT_STATEC_REG, 5, 0x0E),
+
+ CLK_1RATE(I2C, I2C_NS_REG, B(9), B(11), clk_tbl_tcxo,
+ CLK_HALT_STATEA_REG, 15, 0x4D4D),
+ CLK_1RATE(I2C_2, I2C_2_NS_REG, B(0), B(2), clk_tbl_tcxo,
+ CLK_HALT_STATEC_REG, 2, 0x0B),
+ CLK_1RATE(QUP_I2C, QUP_I2C_NS_REG, B(0), B(2), clk_tbl_tcxo,
+ CLK_HALT_STATEB_REG, 31, 0x1C),
+ CLK_1RATE(UART1, UART_NS_REG, B(5), B(4), clk_tbl_tcxo,
+ CLK_HALT_STATEB_REG, 7, 0x4D6F),
+ CLK_1RATE(UART2, UART2_NS_REG, B(5), B(4), clk_tbl_tcxo,
+ CLK_HALT_STATEB_REG, 5, 0x4D71),
+
+ CLK_BASIC(EMDH, EMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A,
+ NULL, 0, 0x4F00),
+ CLK_BASIC(PMDH, PMDH_NS_REG, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A,
+ NULL, 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_MND8_P(VPE, VPE_NS_REG, 22, 15, B(9), B(11), clk_tbl_vpe,
+ AXI_VPE, NULL, CLK_HALT_STATEC_REG, 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),
+ CLK_SLAVE(MFC_DIV2, MFC_NS_REG, B(15), MFC, CLK_HALT_STATEC_REG,
+ 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),
+ CLK_MND8(SDC2, SDCn_NS_REG(2), 20, 13, B(9), B(11), clk_tbl_sdc2_4,
+ NULL, CLK_HALT_STATEA_REG, 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),
+ CLK_MND8(SDC4, SDCn_NS_REG(4), 20, 13, B(9), B(11), clk_tbl_sdc2_4,
+ NULL, CLK_HALT_STATEB_REG, 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_MND8(MIDI, MIDI_NS_REG, 19, 12, B(9), B(11), clk_tbl_midi, NULL,
+ CLK_HALT_STATEC_REG, 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),
+ CLK_SLAVE(USB_HS, USBH_NS_REG, B(9), USB_HS_SRC,
+ CLK_HALT_STATEB_REG, 26, 0x4D7F),
+ CLK_SLAVE(USB_HS_CORE, USBH_NS_REG, B(13), USB_HS_SRC,
+ CLK_HALT_STATEA_REG, 27, 0x14),
+ CLK_SLAVE(USB_HS2, USBH2_NS_REG, B(9), USB_HS_SRC,
+ CLK_HALT_STATEB_REG, 3, 0x4D73),
+ CLK_SLAVE(USB_HS2_CORE, USBH2_NS_REG, B(4), USB_HS_SRC,
+ CLK_HALT_STATEA_REG, 28, 0x15),
+ CLK_SLAVE(USB_HS3, USBH3_NS_REG, B(9), USB_HS_SRC,
+ CLK_HALT_STATEB_REG, 2, 0x4D74),
+ CLK_SLAVE(USB_HS3_CORE, USBH3_NS_REG, B(4), USB_HS_SRC,
+ CLK_HALT_STATEA_REG, 29, 0x16),
+ CLK_MND8(TV, TV_NS_REG, 23, 16, 0, B(11), clk_tbl_tv, chld_tv,
+ NULL, 0, 0),
+ CLK_SLAVE(HDMI, HDMI_NS_REG, B(9), TV,
+ CLK_HALT_STATEC_REG, 7, 0x13),
+ CLK_SLAVE(TV_DAC, TV_NS_REG, B(12), TV,
+ CLK_HALT_STATEB_REG, 27, 0x4D6C),
+ CLK_SLAVE(TV_ENC, TV_NS_REG, B(9), TV,
+ CLK_HALT_STATEB_REG, 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_MND16(UART1DM, UART1DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE,
+ NULL, CLK_HALT_STATEB_REG, 6, 0x4D70),
+ CLK_MND16(UART2DM, UART2DM_NS_REG, B(9), B(11), clk_tbl_uartdm, NONE,
+ NULL, CLK_HALT_STATEB_REG, 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),
+ CLK_MND16(CAM_M, CAM_NS_REG, 0, B(9), clk_tbl_cam, NONE, NULL,
+ NULL, 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),
+ CLK_SLAVE(VFE_MDC, CAM_VFE_NS_REG, B(11), VFE, CLK_HALT_STATEA_REG,
+ 9, 0x4D57),
+ CLK_SLAVE(VFE_CAMIF, CAM_VFE_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG,
+ 13, 0x7000),
+ CLK_SLAVE(CSI0_VFE, CSI_NS_REG, B(15), VFE, CLK_HALT_STATEC_REG,
+ 16, 0),
+
+ CLK_MND16(SDAC, SDAC_NS_REG, B(9), B(11), clk_tbl_sdac,
+ NONE, chld_sdac, CLK_HALT_STATEA_REG, 2, 0x4D60),
+ CLK_SLAVE(SDAC_M, SDAC_NS_REG, B(12), SDAC, CLK_HALT_STATEB_REG,
+ 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_SLAVE(MDP_LCDC_PAD_PCLK, MDP_LCDC_NS_REG, B(12), MDP_LCDC_PCLK,
+ CLK_HALT_STATEB_REG, 29, 0x4100),
+ CLK_1RATE(MDP_VSYNC, MDP_VSYNC_REG, B(0), 0, clk_tbl_mdp_vsync,
+ CLK_HALT_STATEB_REG, 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_SLAVE(MI2S_CODEC_RX_S, MI2S_RX_NS_REG, B(9), MI2S_CODEC_RX_M,
+ CLK_HALT_STATEA_REG, 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_SLAVE(MI2S_CODEC_TX_S, MI2S_TX_NS_REG, B(9), MI2S_CODEC_TX_M,
+ CLK_HALT_STATEA_REG, 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),
+ 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),
+ CLK_SLAVE(GRP_3D, GRP_NS_REG, B(7), GRP_3D_SRC, CLK_HALT_STATEB_REG,
+ 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),
+
+ CLK_MND8(CSI0, CSI_NS_REG, 24, 17, B(9), B(11), clk_tbl_csi, NULL,
+ CLK_HALT_STATEC_REG, 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),
+
+ /* Peripheral bus clocks. */
+ CLK_BRIDGE(ADM, GLBL_CLK_ENA_SC_REG, B(5), AXI_LI_APPS,
+ GLBL_CLK_STATE_REG, 5, 0x4000),
+ CLK_GLBL(ADM_P, GLBL_CLK_ENA_2_SC_REG, B(15),
+ GLBL_CLK_STATE_2_REG, 15, 0x11),
+ CLK_GLBL(CE, GLBL_CLK_ENA_SC_REG, B(6),
+ GLBL_CLK_STATE_REG, 6, 0x4D43),
+ CLK_GLBL(CAMIF_PAD_P, GLBL_CLK_ENA_SC_REG, B(9),
+ GLBL_CLK_STATE_REG, 9, 0x1A),
+ CLK_GLBL(CSI0_P, GLBL_CLK_ENA_SC_REG, B(30),
+ GLBL_CLK_STATE_REG, 30, 0),
+ CLK_GLBL(EMDH_P, GLBL_CLK_ENA_2_SC_REG, B(3),
+ GLBL_CLK_STATE_2_REG, 3, 0x03),
+ CLK_GLBL(GRP_2D_P, GLBL_CLK_ENA_SC_REG, B(24),
+ GLBL_CLK_STATE_REG, 24, 0x4D4C),
+ CLK_GLBL(GRP_3D_P, GLBL_CLK_ENA_2_SC_REG, B(17),
+ GLBL_CLK_STATE_2_REG, 17, 0x4D67),
+ CLK_GLBL(JPEG_P, GLBL_CLK_ENA_2_SC_REG, B(24),
+ GLBL_CLK_STATE_2_REG, 24, 0x4D5E),
+ CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC_REG, B(7),
+ GLBL_CLK_STATE_2_REG, 7, 0x07),
+ CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC_REG, B(6),
+ GLBL_CLK_STATE_2_REG, 6, 0x06),
+ CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC_REG, B(26),
+ GLBL_CLK_STATE_2_REG, 26, 0x4D75),
+ CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC_REG, B(4),
+ GLBL_CLK_STATE_2_REG, 4, 0x04),
+ CLK_GLBL(ROTATOR_IMEM, GLBL_CLK_ENA_2_SC_REG, B(23),
+ GLBL_CLK_STATE_2_REG, 23, 0x6600),
+ CLK_GLBL(ROTATOR_P, GLBL_CLK_ENA_2_SC_REG, B(25),
+ GLBL_CLK_STATE_2_REG, 25, 0x4D6D),
+ CLK_GLBL(SDC1_P, GLBL_CLK_ENA_SC_REG, B(7),
+ GLBL_CLK_STATE_REG, 7, 0x4D61),
+ CLK_GLBL(SDC2_P, GLBL_CLK_ENA_SC_REG, B(8),
+ GLBL_CLK_STATE_REG, 8, 0x4F63),
+ CLK_GLBL(SDC3_P, GLBL_CLK_ENA_SC_REG, B(27),
+ GLBL_CLK_STATE_REG, 27, 0x4D79),
+ CLK_GLBL(SDC4_P, GLBL_CLK_ENA_SC_REG, B(28),
+ GLBL_CLK_STATE_REG, 28, 0x4D7B),
+ CLK_GLBL(SPI_P, GLBL_CLK_ENA_2_SC_REG, B(10),
+ GLBL_CLK_STATE_2_REG, 10, 0x18),
+ CLK_GLBL(TSIF_P, GLBL_CLK_ENA_SC_REG, B(18),
+ GLBL_CLK_STATE_REG, 18, 0x4D65),
+ CLK_GLBL(UART1DM_P, GLBL_CLK_ENA_SC_REG, B(17),
+ GLBL_CLK_STATE_REG, 17, 0x4D5C),
+ CLK_GLBL(UART2DM_P, GLBL_CLK_ENA_SC_REG, B(26),
+ GLBL_CLK_STATE_REG, 26, 0x4D7E),
+ CLK_GLBL(USB_HS2_P, GLBL_CLK_ENA_2_SC_REG, B(8),
+ GLBL_CLK_STATE_2_REG, 8, 0x08),
+ CLK_GLBL(USB_HS3_P, GLBL_CLK_ENA_2_SC_REG, B(9),
+ GLBL_CLK_STATE_2_REG, 9, 0x10),
+ CLK_GLBL(USB_HS_P, GLBL_CLK_ENA_SC_REG, B(25),
+ GLBL_CLK_STATE_REG, 25, 0x4D58),
+ CLK_GLBL(VFE_P, GLBL_CLK_ENA_2_SC_REG, B(27),
+ GLBL_CLK_STATE_2_REG, 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),
+ CLK_BRIDGE(AXI_LI_ADSP_A, GLBL_CLK_ENA_2_SC_REG, B(14), AXI_LI_APPS,
+ GLBL_CLK_STATE_2_REG, 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),
+ CLK_BRIDGE(AXI_LI_VFE, GLBL_CLK_ENA_SC_REG, B(23), AXI_LI_APPS,
+ GLBL_CLK_STATE_REG, 23, 0x5B00),
+ CLK_BRIDGE(AXI_MDP, GLBL_CLK_ENA_2_SC_REG, B(29), AXI_LI_APPS,
+ GLBL_CLK_STATE_2_REG, 29, 0x6B00),
+
+ CLK_BRIDGE(AXI_IMEM, GLBL_CLK_ENA_2_SC_REG, B(18), GLBL_ROOT,
+ GLBL_CLK_STATE_2_REG, 18, 0x4B00),
+
+ CLK_BRIDGE(AXI_LI_VG, GLBL_CLK_ENA_SC_REG, B(3), GLBL_ROOT,
+ GLBL_CLK_STATE_REG, 3, 0x4700),
+ CLK_BRIDGE(AXI_GRP_2D, GLBL_CLK_ENA_SC_REG, B(21), AXI_LI_VG,
+ GLBL_CLK_STATE_REG, 21, 0x5900),
+ CLK_BRIDGE(AXI_LI_GRP, GLBL_CLK_ENA_SC_REG, B(22), AXI_LI_VG,
+ GLBL_CLK_STATE_REG, 22, 0x5A00),
+ CLK_BRIDGE(AXI_MFC, GLBL_CLK_ENA_2_SC_REG, B(20), AXI_LI_VG,
+ GLBL_CLK_STATE_2_REG, 20, 0x6A00),
+ CLK_BRIDGE(AXI_ROTATOR, GLBL_CLK_ENA_2_SC_REG, B(22), AXI_LI_VG,
+ GLBL_CLK_STATE_2_REG, 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
+};
+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@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;
+
+static int update_msmc1(void)
+{
+ 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)
+ goto out;
+
+ if (mvolts) {
+ err = -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);
+ }
+}
+
+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)
+{
+ /* 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)
+{
+ uint32_t regval, ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_reg_lock, flags);
+ switch (id) {
+ case C(VFE):
+ regval = readl(CAM_VFE_NS_REG);
+ /* Flag values chosen for backward compatibility
+ * with proc_comm remote clock control. */
+ if (clk_flags == 0x00000100) {
+ /* Select external source. */
+ regval |= B(14);
+ } else if (clk_flags == 0x00000200) {
+ /* Select internal source. */
+ regval &= ~B(14);
+ } else
+ ret = -EINVAL;
+
+ writel(regval, CAM_VFE_NS_REG);
+ break;
+ default:
+ ret = -EPERM;
+ }
+ spin_unlock_irqrestore(&clock_reg_lock, flags);
+
+ return ret;
+}
+
+static unsigned soc_clk_get_rate(unsigned id)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ unsigned long flags;
+ unsigned ret = 0;
+
+ if (t->type == NORATE)
+ 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;
+}
+
+static unsigned soc_clk_is_enabled(unsigned id)
+{
+ return !!(clk_local_tbl[id].count);
+}
+
+
+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,
+};
+
+/*
+ * Clock ownership detection code
+ */
+
+enum {
+ SH2_OWN_GLBL,
+ SH2_OWN_APPS1,
+ SH2_OWN_APPS2,
+ SH2_OWN_ROW1,
+ SH2_OWN_ROW2,
+ SH2_OWN_APPS3,
+ NUM_OWNERSHIP
+};
+static __initdata uint32_t ownership_regs[NUM_OWNERSHIP];
+
+static void __init cache_ownership(void)
+{
+ ownership_regs[SH2_OWN_GLBL] = readl(SH2_OWN_GLBL_BASE_REG);
+ ownership_regs[SH2_OWN_APPS1] = readl(SH2_OWN_APPS1_BASE_REG);
+ ownership_regs[SH2_OWN_APPS2] = readl(SH2_OWN_APPS2_BASE_REG);
+ ownership_regs[SH2_OWN_ROW1] = readl(SH2_OWN_ROW1_BASE_REG);
+ ownership_regs[SH2_OWN_ROW2] = readl(SH2_OWN_ROW2_BASE_REG);
+ ownership_regs[SH2_OWN_APPS3] = readl(SH2_OWN_APPS3_BASE_REG);
+}
+
+static void __init print_ownership(void)
+{
+ pr_info("Clock ownership\n");
+ pr_info(" GLBL : %08x\n", ownership_regs[SH2_OWN_GLBL]);
+ pr_info(" APPS : %08x %08x %08x\n", ownership_regs[SH2_OWN_APPS1],
+ ownership_regs[SH2_OWN_APPS2], ownership_regs[SH2_OWN_APPS3]);
+ pr_info(" ROW : %08x %08x\n", ownership_regs[SH2_OWN_ROW1],
+ ownership_regs[SH2_OWN_ROW2]);
+}
+
+/*
+ * This is a many-to-one mapping since we don't know how the remote clock code
+ * has decided to handle the dependencies between clocks for a particular
+ * hardware block. We determine the ownership for all the clocks on a block by
+ * checking the ownership bit of one register (usually the ns register).
+ */
+#define O(x) (&ownership_regs[(x)])
+static const struct clk_local_ownership {
+ const uint32_t *reg;
+ const uint32_t bit;
+} ownership_map[] __initconst = {
+ [C(GRP_2D)] = { O(SH2_OWN_APPS1), B(6) },
+ [C(GRP_2D_P)] = { O(SH2_OWN_APPS1), B(6) },
+ [C(HDMI)] = { O(SH2_OWN_APPS1), B(31) },
+ [C(JPEG)] = { O(SH2_OWN_APPS1), B(0) },
+ [C(JPEG_P)] = { O(SH2_OWN_APPS1), B(0) },
+ [C(LPA_CODEC)] = { O(SH2_OWN_APPS1), B(23) },
+ [C(LPA_CORE)] = { O(SH2_OWN_APPS1), B(23) },
+ [C(LPA_P)] = { O(SH2_OWN_APPS1), B(23) },
+ [C(MI2S_M)] = { O(SH2_OWN_APPS1), B(28) },
+ [C(MI2S_S)] = { O(SH2_OWN_APPS1), B(28) },
+ [C(MI2S_CODEC_RX_M)] = { O(SH2_OWN_APPS1), B(12) },
+ [C(MI2S_CODEC_RX_S)] = { O(SH2_OWN_APPS1), B(12) },
+ [C(MI2S_CODEC_TX_M)] = { O(SH2_OWN_APPS1), B(14) },
+ [C(MI2S_CODEC_TX_S)] = { O(SH2_OWN_APPS1), B(14) },
+ [C(MIDI)] = { O(SH2_OWN_APPS1), B(22) },
+ [C(SDAC)] = { O(SH2_OWN_APPS1), B(26) },
+ [C(SDAC_M)] = { O(SH2_OWN_APPS1), B(26) },
+ [C(VFE)] = { O(SH2_OWN_APPS1), B(8) },
+ [C(VFE_CAMIF)] = { O(SH2_OWN_APPS1), B(8) },
+ [C(VFE_MDC)] = { O(SH2_OWN_APPS1), B(8) },
+ [C(VFE_P)] = { O(SH2_OWN_APPS1), B(8) },
+
+ [C(GRP_3D)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(GRP_3D_P)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(GRP_3D_SRC)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(IMEM)] = { O(SH2_OWN_APPS2), B(0) },
+ [C(MDP_LCDC_PAD_PCLK)] = { O(SH2_OWN_APPS2), B(4) },
+ [C(MDP_LCDC_PCLK)] = { O(SH2_OWN_APPS2), B(4) },
+ [C(MDP_P)] = { O(SH2_OWN_APPS2), B(4) },
+ [C(MDP_VSYNC)] = { O(SH2_OWN_APPS2), B(28) },
+ [C(TSIF_REF)] = { O(SH2_OWN_APPS2), B(5) },
+ [C(TSIF_P)] = { O(SH2_OWN_APPS2), B(5) },
+ [C(TV)] = { O(SH2_OWN_APPS2), B(2) },
+ [C(TV_DAC)] = { O(SH2_OWN_APPS2), B(2) },
+ [C(TV_ENC)] = { O(SH2_OWN_APPS2), B(2) },
+
+ [C(EMDH)] = { O(SH2_OWN_ROW1), B(7) },
+ [C(EMDH_P)] = { O(SH2_OWN_ROW1), B(7) },
+ [C(I2C)] = { O(SH2_OWN_ROW1), B(11) },
+ [C(I2C_2)] = { O(SH2_OWN_ROW1), B(12) },
+ [C(MDC)] = { O(SH2_OWN_ROW1), B(17) },
+ [C(PMDH)] = { O(SH2_OWN_ROW1), B(19) },
+ [C(PMDH_P)] = { O(SH2_OWN_ROW1), B(19) },
+ [C(SDC1)] = { O(SH2_OWN_ROW1), B(23) },
+ [C(SDC1_P)] = { O(SH2_OWN_ROW1), B(23) },
+ [C(SDC2)] = { O(SH2_OWN_ROW1), B(25) },
+ [C(SDC2_P)] = { O(SH2_OWN_ROW1), B(25) },
+ [C(SDC3)] = { O(SH2_OWN_ROW1), B(27) },
+ [C(SDC3_P)] = { O(SH2_OWN_ROW1), B(27) },
+ [C(SDC4)] = { O(SH2_OWN_ROW1), B(29) },
+ [C(SDC4_P)] = { O(SH2_OWN_ROW1), B(29) },
+ [C(UART2)] = { O(SH2_OWN_ROW1), B(0) },
+ [C(USB_HS2)] = { O(SH2_OWN_ROW1), B(2) },
+ [C(USB_HS2_CORE)] = { O(SH2_OWN_ROW1), B(2) },
+ [C(USB_HS2_P)] = { O(SH2_OWN_ROW1), B(2) },
+ [C(USB_HS3)] = { O(SH2_OWN_ROW1), B(4) },
+ [C(USB_HS3_CORE)] = { O(SH2_OWN_ROW1), B(4) },
+ [C(USB_HS3_P)] = { O(SH2_OWN_ROW1), B(4) },
+
+ [C(QUP_I2C)] = { O(SH2_OWN_ROW2), B(3) },
+ [C(SPI)] = { O(SH2_OWN_ROW2), B(1) },
+ [C(SPI_P)] = { O(SH2_OWN_ROW2), B(1) },
+ [C(UART1)] = { O(SH2_OWN_ROW2), B(9) },
+ [C(UART1DM)] = { O(SH2_OWN_ROW2), B(6) },
+ [C(UART1DM_P)] = { O(SH2_OWN_ROW2), B(6) },
+ [C(UART2DM)] = { O(SH2_OWN_ROW2), B(8) },
+ [C(UART2DM_P)] = { O(SH2_OWN_ROW2), B(8) },
+ [C(USB_HS)] = { O(SH2_OWN_ROW2), B(11) },
+ [C(USB_HS_CORE)] = { O(SH2_OWN_ROW2), B(11) },
+ [C(USB_HS_SRC)] = { O(SH2_OWN_ROW2), B(11) },
+ [C(USB_HS_P)] = { O(SH2_OWN_ROW2), B(11) },
+
+ [C(CAM_M)] = { O(SH2_OWN_APPS3), B(6) },
+ [C(CAMIF_PAD_P)] = { O(SH2_OWN_APPS3), B(6) },
+ [C(CSI0)] = { O(SH2_OWN_APPS3), B(11) },
+ [C(CSI0_VFE)] = { O(SH2_OWN_APPS3), B(11) },
+ [C(CSI0_P)] = { O(SH2_OWN_APPS3), B(11) },
+ [C(MDP)] = { O(SH2_OWN_APPS3), B(0) },
+ [C(MFC)] = { O(SH2_OWN_APPS3), B(2) },
+ [C(MFC_DIV2)] = { O(SH2_OWN_APPS3), B(2) },
+ [C(MFC_P)] = { O(SH2_OWN_APPS3), B(2) },
+ [C(VPE)] = { O(SH2_OWN_APPS3), B(4) },
+
+ [C(ADM)] = { O(SH2_OWN_GLBL), B(8) },
+ [C(ADM_P)] = { O(SH2_OWN_GLBL), B(13) },
+ [C(CE)] = { O(SH2_OWN_GLBL), B(8) },
+ [C(AXI_ROTATOR)] = { O(SH2_OWN_GLBL), B(13) },
+ [C(ROTATOR_IMEM)] = { O(SH2_OWN_GLBL), B(13) },
+ [C(ROTATOR_P)] = { O(SH2_OWN_GLBL), B(13) },
+};
+
+static bool __init clk_is_local(uint32_t id)
+{
+ uint32_t bit = ownership_map[id].bit;
+ const uint32_t *reg = ownership_map[id].reg;
+
+ BUG_ON(id >= ARRAY_SIZE(ownership_map) || !reg);
+
+ return *reg & bit;
+}
+
+static const struct reg_init {
+ const void __iomem *reg;
+ uint32_t mask;
+ uint32_t val;
+} ri_list[] __initconst = {
+ /* Enable UMDX_P clock. Known to causes issues, so never turn off. */
+ {GLBL_CLK_ENA_2_SC_REG, B(2), B(2)},
+
+ {EMDH_NS_REG, BM(18, 17) , BVAL(18, 17, 0x3)}, /* RX div = div-4. */
+ {PMDH_NS_REG, BM(18, 17), BVAL(18, 17, 0x3)}, /* RX div = div-4. */
+ /* MI2S_CODEC_RX_S src = MI2S_CODEC_RX_M. */
+ {MI2S_RX_NS_REG, B(14), 0x0},
+ /* MI2S_CODEC_TX_S src = MI2S_CODEC_TX_M. */
+ {MI2S_TX_NS_REG, B(14), 0x0},
+ {MI2S_NS_REG, B(14), 0x0}, /* MI2S_S src = MI2S_M. */
+ /* Allow DSP to decide the LPA CORE src. */
+ {LPA_CORE_CLK_MA0_REG, B(0), B(0)},
+ {LPA_CORE_CLK_MA2_REG, B(0), B(0)},
+ {MI2S_CODEC_RX_DIV_REG, 0xF, 0xD}, /* MI2S_CODEC_RX_S div = div-8. */
+ {MI2S_CODEC_TX_DIV_REG, 0xF, 0xD}, /* MI2S_CODEC_TX_S div = div-8. */
+ {MI2S_DIV_REG, 0xF, 0x7}, /* MI2S_S div = div-8. */
+ {MDC_NS_REG, 0x3, 0x3}, /* MDC src = external MDH src. */
+ {SDAC_NS_REG, BM(15, 14), 0x0}, /* SDAC div = div-1. */
+ /* Disable sources TCXO/5 & TCXO/6. UART1 src = TCXO*/
+ {UART_NS_REG, BM(26, 25) | BM(2, 0), 0x0},
+ {MDP_VSYNC_REG, 0xC, 0x4}, /* MDP VSYNC src = LPXO. */
+ /* HDMI div = div-1, non-inverted. tv_enc_src = tv_clk_src */
+ {HDMI_NS_REG, 0x7, 0x0},
+ {TV_NS_REG, BM(15, 14), 0x0}, /* tv_clk_src_div2 = div-1 */
+
+ /* USBH core clocks src = USB_HS_SRC. */
+ {USBH_NS_REG, B(15), B(15)},
+ {USBH2_NS_REG, B(6), B(6)},
+ {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)
+void __init msm_clk_soc_init(void)
+{
+ int i;
+ uint32_t val;
+
+ cache_ownership();
+ print_ownership();
+
+ /* When we have no local clock control, the rest of the code in this
+ * function is a NOP since writes to shadow regions that we don't own
+ * are ignored. */
+
+ /* Disable all the child clocks of USB_HS_SRC. This needs to be done
+ * before the register init loop since it changes the source of the
+ * 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]);
+
+ if (clk_is_local(C(USB_HS_SRC)))
+ soc_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);
+ val &= ~ri_list[i].mask;
+ val |= ri_list[i].val;
+ writel(val, ri_list[i].reg);
+ }
+
+ set_1rate(I2C);
+ set_1rate(I2C_2);
+ set_1rate(QUP_I2C);
+ set_1rate(UART1);
+ set_1rate(UART2);
+ set_1rate(MI2S_M);
+ set_1rate(MIDI);
+ set_1rate(MDP_VSYNC);
+ set_1rate(LPA_CODEC);
+ set_1rate(GLBL_ROOT);
+
+ /* Sync the GRP2D clock to AXI */
+ soc_clk_set_rate(C(GRP_2D), 1);
+}
diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h
index e16f72f..d41acb7 100644
--- a/arch/arm/mach-msm/clock-7x30.h
+++ b/arch/arm/mach-msm/clock-7x30.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -33,6 +33,8 @@
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,
@@ -135,17 +137,30 @@ enum {
L_7X30_NR_CLKS
};
-struct clk_ops;
-extern struct clk_ops clk_ops_7x30;
-
-struct clk_ops *clk_7x30_is_local(uint32_t id);
-int clk_7x30_init(void);
-
void pll_enable(uint32_t pll);
void pll_disable(uint32_t pll);
+enum {
+ PLL_0 = 0,
+ PLL_1,
+ PLL_2,
+ PLL_3,
+ PLL_4,
+ PLL_5,
+ PLL_6,
+ NUM_PLL
+};
+
+enum {
+ LOW,
+ NOMINAL,
+ HIGH,
+ MSMC1_END
+};
+
extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable);
+extern struct clk_ops clk_ops_7x30;
#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \
.name = clk_name, \
.id = L_7X30_##clk_id, \
@@ -164,5 +179,14 @@ extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable);
.dbg_name = #l_id, \
}
+#define CLK_7X30L(clk_name, l_id, clk_dev, clk_flags) { \
+ .name = clk_name, \
+ .id = L_7X30_##l_id, \
+ .flags = clk_flags, \
+ .dev = clk_dev, \
+ .dbg_name = #l_id, \
+ .ops = &clk_ops_7x30, \
+ }
+
#endif
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 8c2b4dd..56c7549 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -162,21 +162,16 @@ EXPORT_SYMBOL(clk_set_flags);
*/
static struct clk *ebi1_clk;
-static void __init set_clock_ops(struct clk *clk)
-{
- if (!clk->ops) {
- clk->ops = &clk_ops_pcom;
- clk->id = clk->remote_id;
- }
-}
-
void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks)
{
unsigned n;
+ /* Do SoC-speficic clock init operations. */
+ msm_clk_soc_init();
+
mutex_lock(&clocks_mutex);
for (n = 0; n < num_clocks; n++) {
- set_clock_ops(&clock_tbl[n]);
+ msm_clk_soc_set_ops(&clock_tbl[n]);
list_add_tail(&clock_tbl[n].list, &clocks);
}
mutex_unlock(&clocks_mutex);
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 70216b0..4841ab6 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -62,6 +62,18 @@ struct clk {
#define CLK_MAX CLKFLAG_MAX
#define CLK_MINMAX (CLK_MIN | CLK_MAX)
+#ifdef CONFIG_ARCH_MSM7X30
+void __init msm_clk_soc_set_ops(struct clk *clk);
+#else
+static inline void __init msm_clk_soc_set_ops(struct clk *clk) { }
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+void __init msm_clk_soc_init(void);
+#else
+static inline void __init msm_clk_soc_init(void) { }
+#endif
+
#ifdef CONFIG_DEBUG_FS
int __init clock_debug_init(void);
int __init clock_debug_add(struct clk *clock);
diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h
index 12da4ca..e2f2d5a 100644
--- a/arch/arm/mach-msm/proc_comm.h
+++ b/arch/arm/mach-msm/proc_comm.h
@@ -137,6 +137,7 @@ enum {
PCOM_CLKCTL_RPC_RAIL_DISABLE,
PCOM_CLKCTL_RPC_RAIL_CONTROL,
PCOM_CLKCTL_RPC_MIN_MSMC1,
+ PCOM_CLKCTL_RPC_SRC_REQUEST,
PCOM_NUM_CMDS,
};
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
next prev parent reply other threads:[~2010-12-17 0:50 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-17 0:49 [PATCH 00/22] MSM clock driver updates Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 01/22] msm: clock: Remove unused code and definitions Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 02/22] msm: clock: Move debugfs code from clock.c to clock-debug.c Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 03/22] msm: clock: Invert debugfs directory layout Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 04/22] msm: clock: Add support for more proc_comm clocks Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd [this message]
2010-12-17 0:49 ` [PATCH 05/22] msm: clock-7x30: Add 7x30 local clock driver Stephen Boyd
2010-12-17 0:49 ` [PATCH 06/22] msm: clock-7x30: Update clock table Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 07/22] msm: clock: Refactor clock-7x30 into generic clock-local driver Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 08/22] msm: clock-8x60: Add msm8x60 local clock driver Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 09/22] msm: clock: Remove references to clk_ops_pcom Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 10/22] msm: Move 8x60 to the real clock driver Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 11/22] msm: clock Add debugfs interface to measure clock rates Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 12/22] msm: clock: Add list_rate debugfs nodes for locally-controlled clocks Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 13/22] msm: clock: Push down clock count and locking into sub drivers Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 14/22] msm: clock: Support clk_set_parent() clk_ops Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:49 ` [PATCH 15/22] msm: clock-pcom: Add pbus specific clock ops Stephen Boyd
2010-12-17 0:49 ` Stephen Boyd
2010-12-17 0:50 ` [PATCH 16/22] msm: clock: Implement rate voting Stephen Boyd
2010-12-17 0:50 ` Stephen Boyd
2010-12-17 0:50 ` [PATCH 17/22] msm: Migrate to clock " Stephen Boyd
2010-12-17 0:50 ` Stephen Boyd
2010-12-17 0:50 ` [PATCH 18/22] msm: clock: Migrate to clkdev Stephen Boyd
2010-12-17 0:50 ` Stephen Boyd
2010-12-17 0:50 ` [PATCH 19/22] msm: iommu: Add bus clocks to platform data Stephen Boyd
2010-12-17 0:50 ` Stephen Boyd
2010-12-17 0:50 ` [PATCH 20/22] msm: iommu: Clock control for the IOMMU driver Stephen Boyd
2010-12-17 0:50 ` Stephen Boyd
2010-12-17 0:50 ` [PATCH 21/22] msm: iommu: Rework clock logic and add IOMMU bus clock control Stephen Boyd
2010-12-17 0:50 ` Stephen Boyd
2010-12-17 0:50 ` [PATCH 22/22] msm: clock-8x60: Don't keep IOMMU clocks on at boot Stephen Boyd
2010-12-17 0:50 ` Stephen Boyd
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1292547006-19741-6-git-send-email-sboyd@codeaurora.org \
--to=sboyd@codeaurora.org \
--cc=arve@android.com \
--cc=davidb@codeaurora.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=skannan@codeaurora.org \
--cc=swetland@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.