static int __alpha_pll_enable(struct alpha_pll_clk *pll, int enable_output) { int rc; u32 mode; mode = readl_relaxed(MODE_REG(pll)); mode |= PLL_BYPASSNL; writel_relaxed(mode, MODE_REG(pll)); /* * H/W requires a 5us delay between disabling the bypass and * de-asserting the reset. */ mb(); udelay(5); mode |= PLL_RESET_N; writel_relaxed(mode, MODE_REG(pll)); rc = wait_for_update(pll); if (rc < 0) return rc; /* Enable PLL output. */ if (enable_output) { mode |= PLL_OUTCTRL; writel_relaxed(mode, MODE_REG(pll)); } /* Ensure that the write above goes through before returning. */ mb(); return 0; }
static int alpha_pll_dynamic_update(struct alpha_pll_clk *pll) { u32 regval; /* Latch the input to the PLL */ regval = readl_relaxed(MODE_REG(pll)); regval |= pll->masks->update_mask; writel_relaxed(regval, MODE_REG(pll)); /* Wait for 2 reference cycle before checking ACK bit */ udelay(1); if (!(readl_relaxed(MODE_REG(pll)) & ALPHA_PLL_ACK_LATCH)) { WARN(1, "%s: PLL latch failed. Output may be unstable!\n", pll->c.dbg_name); return -EINVAL; } /* Return latch input to 0 */ regval = readl_relaxed(MODE_REG(pll)); regval &= ~pll->masks->update_mask; writel_relaxed(regval, MODE_REG(pll)); /* Wait for PLL output to stabilize */ udelay(100); return 0; }
static enum handoff alpha_pll_handoff(struct clk *c) { struct alpha_pll_clk *pll = to_alpha_pll_clk(c); struct alpha_pll_masks *masks = pll->masks; u64 a_val; u32 alpha_en, l_val, regval; /* Set the PLL_HW_UPDATE_LOGIC_BYPASS bit before continuing */ if (pll->dynamic_update) { regval = readl_relaxed(MODE_REG(pll)); regval |= ALPHA_PLL_HW_UPDATE_LOGIC_BYPASS; writel_relaxed(regval, MODE_REG(pll)); } update_vco_tbl(pll); if (!is_locked(pll)) { if (pll->slew) { if (c->rate && dyna_alpha_pll_set_rate(c, c->rate)) WARN(1, "%s: Failed to configure rate\n", c->dbg_name); } else { if (c->rate && alpha_pll_set_rate(c, c->rate)) WARN(1, "%s: Failed to configure rate\n", c->dbg_name); } __init_alpha_pll(c); return HANDOFF_DISABLED_CLK; } else if (pll->fsm_en_mask && !is_fsm_mode(MODE_REG(pll))) { WARN(1, "%s should be in FSM mode but is not\n", c->dbg_name); } l_val = readl_relaxed(L_REG(pll)); /* read u64 in two steps to satisfy alignment constraint */ a_val = readl_relaxed(A_REG(pll) + 0x4); a_val = a_val << 32 | readl_relaxed(A_REG(pll)); /* get upper 32 bits */ a_val = a_val >> (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); alpha_en = readl_relaxed(ALPHA_EN_REG(pll)); alpha_en &= masks->alpha_en_mask; if (!alpha_en) a_val = 0; c->rate = compute_rate(pll, l_val, a_val); /* * Unconditionally vote for the PLL; it might be on because of * another master's vote. */ if (pll->fsm_en_mask) __alpha_pll_vote_enable(pll); return HANDOFF_ENABLED_CLK; }
static void __alpha_pll_disable(struct alpha_pll_clk *pll) { u32 mode; mode = readl_relaxed(MODE_REG(pll)); mode &= ~PLL_OUTCTRL; writel_relaxed(mode, MODE_REG(pll)); /* Delay of 2 output clock ticks required until output is disabled */ mb(); udelay(1); mode &= ~(PLL_BYPASSNL | PLL_RESET_N); writel_relaxed(mode, MODE_REG(pll)); }
static int alpha_pll_enable_hwfsm(struct clk *c) { u32 mode; struct alpha_pll_clk *pll = to_alpha_pll_clk(c); /* Re-enable HW FSM mode, clear OFFLINE request */ mode = readl_relaxed(MODE_REG(pll)); mode |= PLL_FSM_ENA_BIT; mode &= ~PLL_OFFLINE_REQ_BIT; writel_relaxed(mode, MODE_REG(pll)); /* Make sure enable request goes through before waiting for update */ mb(); if (wait_for_update(pll) < 0) panic("PLL %s failed to lock", c->dbg_name); return 0; }
static void __init_alpha_pll(struct clk *c) { struct alpha_pll_clk *pll = to_alpha_pll_clk(c); struct alpha_pll_masks *masks = pll->masks; u32 regval; if (masks->output_mask && pll->enable_config) { regval = readl_relaxed(OUTPUT_REG(pll)); regval &= ~masks->output_mask; regval |= pll->enable_config; writel_relaxed(regval, OUTPUT_REG(pll)); } if (masks->post_div_mask) { regval = readl_relaxed(USER_CTL_LO_REG(pll)); regval &= ~masks->post_div_mask; regval |= pll->post_div_config; writel_relaxed(regval, USER_CTL_LO_REG(pll)); } if (pll->slew) { regval = readl_relaxed(USER_CTL_HI_REG(pll)); regval &= ~PLL_LATCH_INTERFACE; writel_relaxed(regval, USER_CTL_HI_REG(pll)); } if (masks->config_ctl_mask) { regval = readl_relaxed(CFG_CTL_REG(pll)); regval &= ~masks->config_ctl_mask; regval |= pll->config_ctl_val; writel_relaxed(regval, CFG_CTL_REG(pll)); } if (masks->test_ctl_lo_mask) { regval = readl_relaxed(TEST_CTL_LO_REG(pll)); regval &= ~masks->test_ctl_lo_mask; regval |= pll->test_ctl_lo_val; writel_relaxed(regval, TEST_CTL_LO_REG(pll)); } if (masks->test_ctl_hi_mask) { regval = readl_relaxed(TEST_CTL_HI_REG(pll)); regval &= ~masks->test_ctl_hi_mask; regval |= pll->test_ctl_hi_val; writel_relaxed(regval, TEST_CTL_HI_REG(pll)); } if (pll->fsm_en_mask) __set_fsm_mode(MODE_REG(pll)); pll->inited = true; }
static void __fabia_alpha_pll_disable(struct alpha_pll_clk *pll) { u32 mode; /* Disable PLL outputs */ mode = readl_relaxed(MODE_REG(pll)); mode &= ~PLL_OUTCTRL; writel_relaxed(mode, MODE_REG(pll)); /* Disable the main PLL output */ mode = readl_relaxed(FABIA_USER_CTL_LO_REG(pll)); mode &= ~FABIA_PLL_OUT_MAIN; writel_relaxed(mode, FABIA_USER_CTL_LO_REG(pll)); /* Place PLL is the OFF state */ mode = readl_relaxed(MODE_REG(pll)); mode &= ~PLL_RESET_N; writel_relaxed(mode, MODE_REG(pll)); /* Place the PLL mode in STANDBY */ writel_relaxed(FABIA_PLL_STANDBY, FABIA_PLL_OPMODE(pll)); }
static enum handoff fabia_alpha_pll_handoff(struct clk *c) { struct alpha_pll_clk *pll = to_alpha_pll_clk(c); u64 a_val; u32 l_val, regval; /* Set the PLL_HW_UPDATE_LOGIC_BYPASS bit before continuing */ regval = readl_relaxed(MODE_REG(pll)); regval |= ALPHA_PLL_HW_UPDATE_LOGIC_BYPASS; writel_relaxed(regval, MODE_REG(pll)); if (!is_locked(pll)) { if (c->rate && fabia_alpha_pll_set_rate(c, c->rate)) WARN(1, "%s: Failed to configure rate\n", c->dbg_name); __init_alpha_pll(c); return HANDOFF_DISABLED_CLK; } else if (pll->fsm_en_mask && !is_fsm_mode(MODE_REG(pll))) { WARN(1, "%s should be in FSM mode but is not\n", c->dbg_name); } l_val = readl_relaxed(FABIA_L_REG(pll)); if (pll->fabia_frac_offset) a_val = readl_relaxed(FABIA_FRAC_OFF(pll)); else a_val = readl_relaxed(FABIA_FRAC_REG(pll)); c->rate = compute_rate(pll, l_val, a_val); /* * Unconditionally vote for the PLL; it might be on because of * another master's vote. */ if (pll->fsm_en_mask) __alpha_pll_vote_enable(pll); return HANDOFF_ENABLED_CLK; }
static void __iomem *alpha_pll_list_registers(struct clk *clk, int n, struct clk_register_data **regs, u32 *size) { struct alpha_pll_clk *pll = to_alpha_pll_clk(clk); static struct clk_register_data data[] = { {"PLL_MODE", 0x0}, {"PLL_L_VAL", 0x4}, {"PLL_ALPHA_VAL", 0x8}, {"PLL_ALPHA_VAL_U", 0xC}, {"PLL_USER_CTL", 0x10}, {"PLL_CONFIG_CTL", 0x18}, }; if (n) return ERR_PTR(-EINVAL); *regs = data; *size = ARRAY_SIZE(data); return MODE_REG(pll); }
static int __fabia_alpha_pll_enable(struct alpha_pll_clk *pll) { int rc; u32 mode; /* Disable PLL output */ mode = readl_relaxed(MODE_REG(pll)); mode &= ~PLL_OUTCTRL; writel_relaxed(mode, MODE_REG(pll)); /* Set operation mode to STANDBY */ writel_relaxed(FABIA_PLL_STANDBY, FABIA_PLL_OPMODE(pll)); /* PLL should be in STANDBY mode before continuing */ mb(); /* Bring PLL out of reset */ mode = readl_relaxed(MODE_REG(pll)); mode |= PLL_RESET_N; writel_relaxed(mode, MODE_REG(pll)); /* Set operation mode to RUN */ writel_relaxed(FABIA_PLL_RUN, FABIA_PLL_OPMODE(pll)); rc = wait_for_update(pll); if (rc < 0) return rc; /* Enable the main PLL output */ mode = readl_relaxed(FABIA_USER_CTL_LO_REG(pll)); mode |= FABIA_PLL_OUT_MAIN; writel_relaxed(mode, FABIA_USER_CTL_LO_REG(pll)); /* Enable PLL outputs */ mode = readl_relaxed(MODE_REG(pll)); mode |= PLL_OUTCTRL; writel_relaxed(mode, MODE_REG(pll)); /* Ensure that the write above goes through before returning. */ mb(); return 0; }
static void alpha_pll_disable_hwfsm(struct clk *c) { u32 mode; struct alpha_pll_clk *pll = to_alpha_pll_clk(c); /* Request PLL_OFFLINE and wait for ack */ mode = readl_relaxed(MODE_REG(pll)); writel_relaxed(mode | PLL_OFFLINE_REQ_BIT, MODE_REG(pll)); while (!(readl_relaxed(MODE_REG(pll)) & PLL_OFFLINE_ACK_BIT)) ; /* Disable HW FSM */ mode = readl_relaxed(MODE_REG(pll)); mode &= ~PLL_FSM_ENA_BIT; if (pll->offline_bit_workaround) mode &= ~PLL_OFFLINE_REQ_BIT; writel_relaxed(mode, MODE_REG(pll)); while (readl_relaxed(MODE_REG(pll)) & PLL_ACTIVE_FLAG) ; }