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;
}
Ejemplo n.º 6
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)
		;
}