msm: clock-8960: Support QDSS clocks
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index e875b0a..178f140 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -50,6 +50,7 @@
#define CLK_HALT_DFAB_STATE_REG REG(0x2FC8)
#define CLK_HALT_MSS_SMPSS_MISC_STATE_REG REG(0x2FDC)
#define CLK_HALT_SFPB_MISC_STATE_REG REG(0x2FD8)
+#define CLK_HALT_AFAB_SFAB_STATEB_REG REG(0x2FC4)
#define CLK_TEST_REG REG(0x2FA0)
#define GSBIn_HCLK_CTL_REG(n) REG(0x29C0+(0x20*((n)-1)))
#define GSBIn_QUP_APPS_MD_REG(n) REG(0x29C8+(0x20*((n)-1)))
@@ -75,6 +76,22 @@
#define BB_PLL14_STATUS_REG REG(0x31D8)
#define PLLTEST_PAD_CFG_REG REG(0x2FA4)
#define PMEM_ACLK_CTL_REG REG(0x25A0)
+#define QDSS_AT_CLK_SRC0_NS_REG REG(0x2180)
+#define QDSS_AT_CLK_SRC1_NS_REG REG(0x2184)
+#define QDSS_AT_CLK_SRC_CTL_REG REG(0x2188)
+#define QDSS_AT_CLK_NS_REG REG(0x218C)
+#define QDSS_HCLK_CTL_REG REG(0x22A0)
+#define QDSS_RESETS_REG REG(0x2260)
+#define QDSS_STM_CLK_CTL_REG REG(0x2060)
+#define QDSS_TRACECLKIN_CLK_SRC0_NS_REG REG(0x21A0)
+#define QDSS_TRACECLKIN_CLK_SRC1_NS_REG REG(0x21A4)
+#define QDSS_TRACECLKIN_CLK_SRC_CTL_REG REG(0x21A8)
+#define QDSS_TRACECLKIN_CTL_REG REG(0x21AC)
+#define QDSS_TSCTR_CLK_SRC0_NS_REG REG(0x21C0)
+#define QDSS_TSCTR_CLK_SRC1_NS_REG REG(0x21C4)
+#define QDSS_TSCTR_CLK_SRC_CTL_REG REG(0x21C8)
+#define QDSS_TSCTR_CLK_SRC_CTL_REG REG(0x21C8)
+#define QDSS_TSCTR_CTL_REG REG(0x21CC)
#define RINGOSC_NS_REG REG(0x2DC0)
#define RINGOSC_STATUS_REG REG(0x2DCC)
#define RINGOSC_TCXO_CTL_REG REG(0x2DC4)
@@ -1143,6 +1160,261 @@
static CLK_GSBI_QUP(gsbi11_qup, 11, CLK_HALT_CFPB_STATEC_REG, 15);
static CLK_GSBI_QUP(gsbi12_qup, 12, CLK_HALT_CFPB_STATEC_REG, 11);
+#define F_QDSS(f, s, d, v) \
+ { \
+ .freq_hz = f, \
+ .src_clk = &s##_clk.c, \
+ .ns_val = NS_DIVSRC(6, 3, d, 2, 0, s##_to_bb_mux), \
+ .sys_vdd = v, \
+ }
+static struct clk_freq_tbl clk_tbl_qdss[] = {
+ F_QDSS(128000000, pll8, 3, LOW),
+ F_QDSS(300000000, pll3, 4, NOMINAL),
+ F_END
+};
+
+struct qdss_bank {
+ const u32 bank_sel_mask;
+ void __iomem *const ns_reg;
+ const u32 ns_mask;
+};
+
+static void set_rate_qdss(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+{
+ const struct qdss_bank *bank = clk->bank_info;
+ u32 reg, bank_sel_mask = bank->bank_sel_mask;
+
+ /* Switch to bank 0 (always sourced from PXO) */
+ reg = readl_relaxed(clk->ns_reg);
+ reg &= ~bank_sel_mask;
+ writel_relaxed(reg, clk->ns_reg);
+ /*
+ * Wait at least 6 cycles of slowest bank's clock for the glitch-free
+ * MUX to fully switch sources.
+ */
+ mb();
+ udelay(1);
+
+ /* Set source and divider */
+ reg = readl_relaxed(bank->ns_reg);
+ reg &= ~bank->ns_mask;
+ reg |= nf->ns_val;
+ writel_relaxed(reg, bank->ns_reg);
+
+ /* Switch to reprogrammed bank */
+ reg = readl_relaxed(clk->ns_reg);
+ reg |= bank_sel_mask;
+ writel_relaxed(reg, clk->ns_reg);
+ /*
+ * Wait at least 6 cycles of slowest bank's clock for the glitch-free
+ * MUX to fully switch sources.
+ */
+ mb();
+ udelay(1);
+}
+
+#define QDSS_CLK_ROOT_ENA BIT(1)
+
+static int qdss_clk_enable(struct clk *c)
+{
+ struct rcg_clk *clk = to_rcg_clk(c);
+ const struct qdss_bank *bank = clk->bank_info;
+ u32 reg, bank_sel_mask = bank->bank_sel_mask;
+ int ret;
+
+ /* Switch to bank 1 */
+ reg = readl_relaxed(clk->ns_reg);
+ reg |= bank_sel_mask;
+ writel_relaxed(reg, clk->ns_reg);
+ /* Enable root */
+ reg |= QDSS_CLK_ROOT_ENA;
+ writel_relaxed(reg, clk->ns_reg);
+
+ ret = rcg_clk_enable(c);
+ if (ret) {
+ /* Disable root */
+ reg = readl_relaxed(clk->ns_reg);
+ reg &= ~QDSS_CLK_ROOT_ENA;
+ writel_relaxed(reg, clk->ns_reg);
+ /* Switch to bank 0 */
+ reg &= ~bank_sel_mask;
+ writel_relaxed(reg, clk->ns_reg);
+ }
+ return ret;
+}
+
+static void qdss_clk_disable(struct clk *c)
+{
+ struct rcg_clk *clk = to_rcg_clk(c);
+ const struct qdss_bank *bank = clk->bank_info;
+ u32 reg, bank_sel_mask = bank->bank_sel_mask;
+
+ rcg_clk_disable(c);
+ /* Disable root */
+ reg = readl_relaxed(clk->ns_reg);
+ reg &= ~QDSS_CLK_ROOT_ENA;
+ writel_relaxed(reg, clk->ns_reg);
+ /* Switch to bank 0 */
+ reg &= ~bank_sel_mask;
+ writel_relaxed(reg, clk->ns_reg);
+}
+
+static void qdss_clk_auto_off(struct clk *c)
+{
+ struct rcg_clk *clk = to_rcg_clk(c);
+ const struct qdss_bank *bank = clk->bank_info;
+ u32 reg, bank_sel_mask = bank->bank_sel_mask;
+
+ rcg_clk_auto_off(c);
+ /* Disable root */
+ reg = readl_relaxed(clk->ns_reg);
+ reg &= ~QDSS_CLK_ROOT_ENA;
+ writel_relaxed(reg, clk->ns_reg);
+ /* Switch to bank 0 */
+ reg &= ~bank_sel_mask;
+ writel_relaxed(reg, clk->ns_reg);
+}
+
+static struct clk_ops clk_ops_qdss = {
+ .enable = qdss_clk_enable,
+ .disable = qdss_clk_disable,
+ .auto_off = qdss_clk_auto_off,
+ .set_rate = rcg_clk_set_rate,
+ .set_min_rate = rcg_clk_set_min_rate,
+ .get_rate = rcg_clk_get_rate,
+ .list_rate = rcg_clk_list_rate,
+ .is_enabled = rcg_clk_is_enabled,
+ .round_rate = rcg_clk_round_rate,
+ .reset = soc_clk_reset,
+ .is_local = local_clk_is_local,
+ .get_parent = rcg_clk_get_parent,
+};
+
+static struct qdss_bank bdiv_info_qdss = {
+ .bank_sel_mask = BIT(0),
+ .ns_reg = QDSS_AT_CLK_SRC1_NS_REG,
+ .ns_mask = BM(6, 0),
+};
+
+static struct rcg_clk qdss_at_clk = {
+ .b = {
+ .ctl_reg = QDSS_AT_CLK_NS_REG,
+ .en_mask = BIT(6),
+ .reset_reg = QDSS_RESETS_REG,
+ .reset_mask = BIT(0),
+ .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+ .halt_bit = 10,
+ .halt_check = HALT_VOTED,
+ },
+ .ns_reg = QDSS_AT_CLK_SRC_CTL_REG,
+ .set_rate = set_rate_qdss,
+ .freq_tbl = clk_tbl_qdss,
+ .bank_info = &bdiv_info_qdss,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "qdss_at_clk",
+ .ops = &clk_ops_qdss,
+ CLK_INIT(qdss_at_clk.c),
+ },
+};
+
+static struct branch_clk qdss_pclkdbg_clk = {
+ .b = {
+ .ctl_reg = QDSS_AT_CLK_NS_REG,
+ .en_mask = BIT(4),
+ .reset_reg = QDSS_RESETS_REG,
+ .reset_mask = BIT(0),
+ .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+ .halt_bit = 9,
+ .halt_check = HALT_VOTED
+ },
+ .parent = &qdss_at_clk.c,
+ .c = {
+ .dbg_name = "qdss_pclkdbg_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(qdss_pclkdbg_clk.c),
+ },
+};
+
+static struct qdss_bank bdiv_info_qdss_trace = {
+ .bank_sel_mask = BIT(0),
+ .ns_reg = QDSS_TRACECLKIN_CLK_SRC1_NS_REG,
+ .ns_mask = BM(6, 0),
+};
+
+static struct rcg_clk qdss_traceclkin_clk = {
+ .b = {
+ .ctl_reg = QDSS_TRACECLKIN_CTL_REG,
+ .en_mask = BIT(4),
+ .reset_reg = QDSS_RESETS_REG,
+ .reset_mask = BIT(0),
+ .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+ .halt_bit = 8,
+ .halt_check = HALT_VOTED,
+ },
+ .ns_reg = QDSS_TRACECLKIN_CLK_SRC_CTL_REG,
+ .set_rate = set_rate_qdss,
+ .freq_tbl = clk_tbl_qdss,
+ .bank_info = &bdiv_info_qdss_trace,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "qdss_traceclkin_clk",
+ .ops = &clk_ops_qdss,
+ CLK_INIT(qdss_traceclkin_clk.c),
+ },
+};
+
+static struct clk_freq_tbl clk_tbl_qdss_tsctr[] = {
+ F_QDSS(200000000, pll3, 6, LOW),
+ F_QDSS(400000000, pll3, 3, NOMINAL),
+ F_END
+};
+
+static struct qdss_bank bdiv_info_qdss_tsctr = {
+ .bank_sel_mask = BIT(0),
+ .ns_reg = QDSS_TSCTR_CLK_SRC1_NS_REG,
+ .ns_mask = BM(6, 0),
+};
+
+static struct rcg_clk qdss_tsctr_clk = {
+ .b = {
+ .ctl_reg = QDSS_TSCTR_CTL_REG,
+ .en_mask = BIT(4),
+ .reset_reg = QDSS_RESETS_REG,
+ .reset_mask = BIT(3),
+ .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+ .halt_bit = 7,
+ .halt_check = HALT_VOTED,
+ },
+ .ns_reg = QDSS_TSCTR_CLK_SRC_CTL_REG,
+ .set_rate = set_rate_qdss,
+ .freq_tbl = clk_tbl_qdss_tsctr,
+ .bank_info = &bdiv_info_qdss_tsctr,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "qdss_tsctr_clk",
+ .ops = &clk_ops_qdss,
+ CLK_INIT(qdss_tsctr_clk.c),
+ },
+};
+
+static struct branch_clk qdss_stm_clk = {
+ .b = {
+ .ctl_reg = QDSS_STM_CLK_CTL_REG,
+ .en_mask = BIT(4),
+ .reset_reg = QDSS_RESETS_REG,
+ .reset_mask = BIT(1),
+ .halt_reg = CLK_HALT_AFAB_SFAB_STATEB_REG,
+ .halt_bit = 20,
+ .halt_check = HALT_VOTED,
+ },
+ .c = {
+ .dbg_name = "qdss_stm_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(qdss_stm_clk.c),
+ },
+};
+
#define F_PDM(f, s, d, v) \
{ \
.freq_hz = f, \
@@ -1835,6 +2107,23 @@
},
};
+static struct branch_clk qdss_p_clk = {
+ .b = {
+ .ctl_reg = QDSS_HCLK_CTL_REG,
+ .en_mask = BIT(4),
+ .halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
+ .halt_bit = 11,
+ .halt_check = HALT_VOTED,
+ .reset_reg = QDSS_RESETS_REG,
+ .reset_mask = BIT(2),
+ },
+ .c = {
+ .dbg_name = "qdss_p_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(qdss_p_clk.c),
+ },
+};
+
static struct branch_clk tsif_p_clk = {
.b = {
.ctl_reg = TSIF_HCLK_CTL_REG,
@@ -3819,6 +4108,7 @@
static DEFINE_CLK_MEASURE(krait1_m_clk);
static struct measure_sel measure_mux[] = {
+ { TEST_PER_LS(0x05), &qdss_p_clk.c },
{ TEST_PER_LS(0x08), &slimbus_xo_src_clk.c },
{ TEST_PER_LS(0x12), &sdc1_p_clk.c },
{ TEST_PER_LS(0x13), &sdc1_clk.c },
@@ -3905,6 +4195,11 @@
{ TEST_PER_HS(0x2A), &adm0_clk.c },
{ TEST_PER_HS(0x34), &ebi1_clk.c },
{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
+ { TEST_PER_HS(0x48), &qdss_at_clk.c },
+ { TEST_PER_HS(0x49), &qdss_pclkdbg_clk.c },
+ { TEST_PER_HS(0x4A), &qdss_traceclkin_clk.c },
+ { TEST_PER_HS(0x4B), &qdss_tsctr_clk.c },
+ { TEST_PER_HS(0x4F), &qdss_stm_clk.c },
{ TEST_PER_HS(0x50), &usb_hsic_hsic_clk.c },
{ TEST_MM_LS(0x00), &dsi1_byte_clk.c },
@@ -4305,6 +4600,12 @@
CLK_LOOKUP("mdp_clk", mdp_clk.c, NULL),
CLK_LOOKUP("mdp_vsync_clk", mdp_vsync_clk.c, NULL),
CLK_LOOKUP("lut_mdp", lut_mdp_clk.c, NULL),
+ CLK_LOOKUP("qdss_pclk", qdss_p_clk.c, NULL),
+ CLK_LOOKUP("qdss_at_clk", qdss_at_clk.c, NULL),
+ CLK_LOOKUP("qdss_pclkdbg_clk", qdss_pclkdbg_clk.c, NULL),
+ CLK_LOOKUP("qdss_traceclkin_clk", qdss_traceclkin_clk.c, NULL),
+ CLK_LOOKUP("qdss_tsctr_clk", qdss_tsctr_clk.c, NULL),
+ CLK_LOOKUP("qdss_stm_clk", qdss_stm_clk.c, NULL),
CLK_LOOKUP("rot_clk", rot_clk.c, NULL),
CLK_LOOKUP("tv_src_clk", tv_src_clk.c, NULL),
CLK_LOOKUP("tv_enc_clk", tv_enc_clk.c, NULL),