dpll_params = ti_pipe3_get_dpll_params(phy); if (!dpll_params) return -EINVAL;
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
val &= ~PLL_REGN_MASK;
val |= dpll_params->n << PLL_REGN_SHIFT;
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
val &= ~PLL_SELFREQDCO_MASK;
val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
val &= ~PLL_REGM_MASK;
val |= dpll_params->m << PLL_REGM_SHIFT;
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
val &= ~PLL_REGM_F_MASK;
val |= dpll_params->mf << PLL_REGM_F_SHIFT;
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
val &= ~PLL_SD_MASK;
val |= dpll_params->sd << PLL_SD_SHIFT;
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_TRIM);
val &= ~MEM_DLL_TRIM_SEL_MASK;
val |= s->dll_trim_sel << MEM_DLL_TRIM_SHIFT;
ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_TRIM, val);
val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DLL);
val &= ~MEM_DLL_PHINT_RATE_MASK;
val |= s->dll_phint_rate << MEM_DLL_PHINT_RATE_SHIFT;
ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DLL, val);
if (phy->mode == PIPE3_MODE_SATA) {
val = ti_pipe3_readl(phy->phy_rx,
SATA_PHY_RX_IO_AND_A2D_OVERRIDES);
val &= ~MEM_CDR_LOS_SOURCE_MASK;
ti_pipe3_writel(phy->phy_rx, SATA_PHY_RX_IO_AND_A2D_OVERRIDES,
val);
}
}
staticint ti_pipe3_init(struct phy *x)
{ struct ti_pipe3 *phy = phy_get_drvdata(x);
u32 val; int ret = 0;
ti_pipe3_enable_clocks(phy); /* *Setpcie_pcsregisterto0x96forproperfunctioningofphy *asrecommendedinAM572xTRMSPRUHZ6,section18.5.2.2,table *18-1804.
*/ if (phy->mode == PIPE3_MODE_PCIE) { if (!phy->pcs_syscon) {
omap_control_pcie_pcs(phy->control_dev, 0x96); return0;
}
val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT;
ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg,
PCIE_PCS_MASK, val); return ret;
}
/* Bring it out of IDLE if it is IDLE */
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); if (val & PLL_IDLE) {
val &= ~PLL_IDLE;
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
ret = ti_pipe3_dpll_wait_lock(phy);
}
/* SATA has issues if re-programmed when locked */
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); if ((val & PLL_LOCK) && phy->mode == PIPE3_MODE_SATA) return ret;
/* Program the DPLL */
ret = ti_pipe3_dpll_program(phy); if (ret) {
ti_pipe3_disable_clocks(phy); return -EINVAL;
}
/* If dpll_reset_syscon is not present we wont power down SATA DPLL *duetoErratai783
*/ if (phy->mode == PIPE3_MODE_SATA && !phy->dpll_reset_syscon) return0;
/* PCIe doesn't have internal DPLL */ if (phy->mode != PIPE3_MODE_PCIE) { /* Put DPLL in IDLE mode */
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
val |= PLL_IDLE;
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
/* wait for LDO and Oscillator to power down */
timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME); do {
cpu_relax();
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN)) break;
} while (!time_after(jiffies, timeout));
if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
val); return -EBUSY;
}
}
/* i783: SATA needs control bit toggle after PLL unlock */ if (phy->mode == PIPE3_MODE_SATA) {
regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET);
regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
SATA_PLL_SOFT_RESET, 0);
}
phy->refclk = devm_clk_get(dev, "refclk"); if (IS_ERR(phy->refclk)) {
dev_err(dev, "unable to get refclk\n"); /* older DTBs have missing refclk in SATA PHY *sodon'tbailoutincaseofSATAPHY.
*/ if (phy->mode != PIPE3_MODE_SATA) return PTR_ERR(phy->refclk);
}
if (phy->mode != PIPE3_MODE_SATA) {
phy->wkupclk = devm_clk_get(dev, "wkupclk"); if (IS_ERR(phy->wkupclk)) {
dev_err(dev, "unable to get wkupclk\n"); return PTR_ERR(phy->wkupclk);
}
} else {
phy->wkupclk = ERR_PTR(-ENODEV);
}
if (phy->mode != PIPE3_MODE_PCIE || phy->phy_power_syscon) {
phy->sys_clk = devm_clk_get(dev, "sysclk"); if (IS_ERR(phy->sys_clk)) {
dev_err(dev, "unable to get sysclk\n"); return -EINVAL;
}
}
if (phy->mode == PIPE3_MODE_PCIE) {
clk = devm_clk_get(dev, "dpll_ref"); if (IS_ERR(clk)) {
dev_err(dev, "unable to get dpll ref clk\n"); return PTR_ERR(clk);
}
clk_set_rate(clk, 1500000000);
clk = devm_clk_get(dev, "dpll_ref_m2"); if (IS_ERR(clk)) {
dev_err(dev, "unable to get dpll ref m2 clk\n"); return PTR_ERR(clk);
}
clk_set_rate(clk, 100000000);
clk = devm_clk_get(dev, "phy-div"); if (IS_ERR(clk)) {
dev_err(dev, "unable to get phy-div clk\n"); return PTR_ERR(clk);
}
clk_set_rate(clk, 100000000);
phy->div_clk = devm_clk_get(dev, "div-clk"); if (IS_ERR(phy->div_clk)) {
dev_err(dev, "unable to get div-clk\n"); return PTR_ERR(phy->div_clk);
}
} else {
phy->div_clk = ERR_PTR(-ENODEV);
}
phy->phy_power_syscon = syscon_regmap_lookup_by_phandle(node, "syscon-phy-power"); if (IS_ERR(phy->phy_power_syscon)) {
dev_dbg(dev, "can't get syscon-phy-power, using control device\n");
phy->phy_power_syscon = NULL;
} else { if (of_property_read_u32_index(node, "syscon-phy-power", 1,
&phy->power_reg)) {
dev_err(dev, "couldn't get power reg. offset\n"); return -EINVAL;
}
}
if (!phy->phy_power_syscon) {
control_node = of_parse_phandle(node, "ctrl-module", 0); if (!control_node) {
dev_err(dev, "Failed to get control device phandle\n"); return -EINVAL;
}
control_pdev = of_find_device_by_node(control_node);
of_node_put(control_node); if (!control_pdev) {
dev_err(dev, "Failed to get control device\n"); return -EINVAL;
}
phy->control_dev = &control_pdev->dev;
ret = devm_add_action_or_reset(dev, ti_pipe3_put_device,
phy->control_dev); if (ret) return ret;
}
if (phy->mode == PIPE3_MODE_PCIE) {
phy->pcs_syscon = syscon_regmap_lookup_by_phandle(node, "syscon-pcs"); if (IS_ERR(phy->pcs_syscon)) {
dev_dbg(dev, "can't get syscon-pcs, using omap control\n");
phy->pcs_syscon = NULL;
} else { if (of_property_read_u32_index(node, "syscon-pcs", 1,
&phy->pcie_pcs_reg)) {
dev_err(dev, "couldn't get pcie pcs reg. offset\n"); return -EINVAL;
}
}
}
if (phy->mode == PIPE3_MODE_SATA) {
phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node, "syscon-pllreset"); if (IS_ERR(phy->dpll_reset_syscon)) {
dev_info(dev, "can't get syscon-pllreset, sata dpll won't idle\n");
phy->dpll_reset_syscon = NULL;
} else { if (of_property_read_u32_index(node, "syscon-pllreset", 1,
&phy->dpll_reset_reg)) {
dev_err(dev, "couldn't get pllreset reg. offset\n"); return -EINVAL;
}
}
}
staticint ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
{ int ret = 0;
if (!IS_ERR(phy->refclk)) {
ret = clk_prepare_enable(phy->refclk); if (ret) {
dev_err(phy->dev, "Failed to enable refclk %d\n", ret); return ret;
}
}
if (!IS_ERR(phy->wkupclk)) {
ret = clk_prepare_enable(phy->wkupclk); if (ret) {
dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); goto disable_refclk;
}
}
if (!IS_ERR(phy->div_clk)) {
ret = clk_prepare_enable(phy->div_clk); if (ret) {
dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); goto disable_wkupclk;
}
}
return0;
disable_wkupclk: if (!IS_ERR(phy->wkupclk))
clk_disable_unprepare(phy->wkupclk);
disable_refclk: if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk);
return ret;
}
staticvoid ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
{ if (!IS_ERR(phy->wkupclk))
clk_disable_unprepare(phy->wkupclk); if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk); if (!IS_ERR(phy->div_clk))
clk_disable_unprepare(phy->div_clk);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.