18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Zynq PLL driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Xilinx 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Sören Brinkmann <soren.brinkmann@xilinx.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/clk/zynq.h> 108c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/** 158c2ecf20Sopenharmony_ci * struct zynq_pll 168c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 178c2ecf20Sopenharmony_ci * @pll_ctrl: PLL control register 188c2ecf20Sopenharmony_ci * @pll_status: PLL status register 198c2ecf20Sopenharmony_ci * @lock: Register lock 208c2ecf20Sopenharmony_ci * @lockbit: Indicates the associated PLL_LOCKED bit in the PLL status 218c2ecf20Sopenharmony_ci * register. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistruct zynq_pll { 248c2ecf20Sopenharmony_ci struct clk_hw hw; 258c2ecf20Sopenharmony_ci void __iomem *pll_ctrl; 268c2ecf20Sopenharmony_ci void __iomem *pll_status; 278c2ecf20Sopenharmony_ci spinlock_t *lock; 288c2ecf20Sopenharmony_ci u8 lockbit; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci#define to_zynq_pll(_hw) container_of(_hw, struct zynq_pll, hw) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Register bitfield defines */ 338c2ecf20Sopenharmony_ci#define PLLCTRL_FBDIV_MASK 0x7f000 348c2ecf20Sopenharmony_ci#define PLLCTRL_FBDIV_SHIFT 12 358c2ecf20Sopenharmony_ci#define PLLCTRL_BPQUAL_MASK (1 << 3) 368c2ecf20Sopenharmony_ci#define PLLCTRL_PWRDWN_MASK 2 378c2ecf20Sopenharmony_ci#define PLLCTRL_PWRDWN_SHIFT 1 388c2ecf20Sopenharmony_ci#define PLLCTRL_RESET_MASK 1 398c2ecf20Sopenharmony_ci#define PLLCTRL_RESET_SHIFT 0 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define PLL_FBDIV_MIN 13 428c2ecf20Sopenharmony_ci#define PLL_FBDIV_MAX 66 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/** 458c2ecf20Sopenharmony_ci * zynq_pll_round_rate() - Round a clock frequency 468c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 478c2ecf20Sopenharmony_ci * @rate: Desired clock frequency 488c2ecf20Sopenharmony_ci * @prate: Clock frequency of parent clock 498c2ecf20Sopenharmony_ci * Returns frequency closest to @rate the hardware can generate. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate, 528c2ecf20Sopenharmony_ci unsigned long *prate) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci u32 fbdiv; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci fbdiv = DIV_ROUND_CLOSEST(rate, *prate); 578c2ecf20Sopenharmony_ci if (fbdiv < PLL_FBDIV_MIN) 588c2ecf20Sopenharmony_ci fbdiv = PLL_FBDIV_MIN; 598c2ecf20Sopenharmony_ci else if (fbdiv > PLL_FBDIV_MAX) 608c2ecf20Sopenharmony_ci fbdiv = PLL_FBDIV_MAX; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return *prate * fbdiv; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/** 668c2ecf20Sopenharmony_ci * zynq_pll_recalc_rate() - Recalculate clock frequency 678c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 688c2ecf20Sopenharmony_ci * @parent_rate: Clock frequency of parent clock 698c2ecf20Sopenharmony_ci * Returns current clock frequency. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistatic unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, 728c2ecf20Sopenharmony_ci unsigned long parent_rate) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct zynq_pll *clk = to_zynq_pll(hw); 758c2ecf20Sopenharmony_ci u32 fbdiv; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * makes probably sense to redundantly save fbdiv in the struct 798c2ecf20Sopenharmony_ci * zynq_pll to save the IO access. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> 828c2ecf20Sopenharmony_ci PLLCTRL_FBDIV_SHIFT; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return parent_rate * fbdiv; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * zynq_pll_is_enabled - Check if a clock is enabled 898c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 908c2ecf20Sopenharmony_ci * Returns 1 if the clock is enabled, 0 otherwise. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * Not sure this is a good idea, but since disabled means bypassed for 938c2ecf20Sopenharmony_ci * this clock implementation we say we are always enabled. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_cistatic int zynq_pll_is_enabled(struct clk_hw *hw) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci unsigned long flags = 0; 988c2ecf20Sopenharmony_ci u32 reg; 998c2ecf20Sopenharmony_ci struct zynq_pll *clk = to_zynq_pll(hw); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci spin_lock_irqsave(clk->lock, flags); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci reg = readl(clk->pll_ctrl); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(clk->lock, flags); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return !(reg & (PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK)); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/** 1118c2ecf20Sopenharmony_ci * zynq_pll_enable - Enable clock 1128c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 1138c2ecf20Sopenharmony_ci * Returns 0 on success 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cistatic int zynq_pll_enable(struct clk_hw *hw) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci unsigned long flags = 0; 1188c2ecf20Sopenharmony_ci u32 reg; 1198c2ecf20Sopenharmony_ci struct zynq_pll *clk = to_zynq_pll(hw); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (zynq_pll_is_enabled(hw)) 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci pr_info("PLL: enable\n"); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Power up PLL and wait for lock */ 1278c2ecf20Sopenharmony_ci spin_lock_irqsave(clk->lock, flags); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci reg = readl(clk->pll_ctrl); 1308c2ecf20Sopenharmony_ci reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK); 1318c2ecf20Sopenharmony_ci writel(reg, clk->pll_ctrl); 1328c2ecf20Sopenharmony_ci while (!(readl(clk->pll_status) & (1 << clk->lockbit))) 1338c2ecf20Sopenharmony_ci ; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(clk->lock, flags); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/** 1418c2ecf20Sopenharmony_ci * zynq_pll_disable - Disable clock 1428c2ecf20Sopenharmony_ci * @hw: Handle between common and hardware-specific interfaces 1438c2ecf20Sopenharmony_ci * Returns 0 on success 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistatic void zynq_pll_disable(struct clk_hw *hw) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci unsigned long flags = 0; 1488c2ecf20Sopenharmony_ci u32 reg; 1498c2ecf20Sopenharmony_ci struct zynq_pll *clk = to_zynq_pll(hw); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (!zynq_pll_is_enabled(hw)) 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci pr_info("PLL: shutdown\n"); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* shut down PLL */ 1578c2ecf20Sopenharmony_ci spin_lock_irqsave(clk->lock, flags); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci reg = readl(clk->pll_ctrl); 1608c2ecf20Sopenharmony_ci reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK; 1618c2ecf20Sopenharmony_ci writel(reg, clk->pll_ctrl); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(clk->lock, flags); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic const struct clk_ops zynq_pll_ops = { 1678c2ecf20Sopenharmony_ci .enable = zynq_pll_enable, 1688c2ecf20Sopenharmony_ci .disable = zynq_pll_disable, 1698c2ecf20Sopenharmony_ci .is_enabled = zynq_pll_is_enabled, 1708c2ecf20Sopenharmony_ci .round_rate = zynq_pll_round_rate, 1718c2ecf20Sopenharmony_ci .recalc_rate = zynq_pll_recalc_rate 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/** 1758c2ecf20Sopenharmony_ci * clk_register_zynq_pll() - Register PLL with the clock framework 1768c2ecf20Sopenharmony_ci * @name PLL name 1778c2ecf20Sopenharmony_ci * @parent Parent clock name 1788c2ecf20Sopenharmony_ci * @pll_ctrl Pointer to PLL control register 1798c2ecf20Sopenharmony_ci * @pll_status Pointer to PLL status register 1808c2ecf20Sopenharmony_ci * @lock_index Bit index to this PLL's lock status bit in @pll_status 1818c2ecf20Sopenharmony_ci * @lock Register lock 1828c2ecf20Sopenharmony_ci * Returns handle to the registered clock. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistruct clk *clk_register_zynq_pll(const char *name, const char *parent, 1858c2ecf20Sopenharmony_ci void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, 1868c2ecf20Sopenharmony_ci spinlock_t *lock) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct zynq_pll *pll; 1898c2ecf20Sopenharmony_ci struct clk *clk; 1908c2ecf20Sopenharmony_ci u32 reg; 1918c2ecf20Sopenharmony_ci const char *parent_arr[1] = {parent}; 1928c2ecf20Sopenharmony_ci unsigned long flags = 0; 1938c2ecf20Sopenharmony_ci struct clk_init_data initd = { 1948c2ecf20Sopenharmony_ci .name = name, 1958c2ecf20Sopenharmony_ci .parent_names = parent_arr, 1968c2ecf20Sopenharmony_ci .ops = &zynq_pll_ops, 1978c2ecf20Sopenharmony_ci .num_parents = 1, 1988c2ecf20Sopenharmony_ci .flags = 0 1998c2ecf20Sopenharmony_ci }; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci pll = kmalloc(sizeof(*pll), GFP_KERNEL); 2028c2ecf20Sopenharmony_ci if (!pll) 2038c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* Populate the struct */ 2068c2ecf20Sopenharmony_ci pll->hw.init = &initd; 2078c2ecf20Sopenharmony_ci pll->pll_ctrl = pll_ctrl; 2088c2ecf20Sopenharmony_ci pll->pll_status = pll_status; 2098c2ecf20Sopenharmony_ci pll->lockbit = lock_index; 2108c2ecf20Sopenharmony_ci pll->lock = lock; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci spin_lock_irqsave(pll->lock, flags); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci reg = readl(pll->pll_ctrl); 2158c2ecf20Sopenharmony_ci reg &= ~PLLCTRL_BPQUAL_MASK; 2168c2ecf20Sopenharmony_ci writel(reg, pll->pll_ctrl); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(pll->lock, flags); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci clk = clk_register(NULL, &pll->hw); 2218c2ecf20Sopenharmony_ci if (WARN_ON(IS_ERR(clk))) 2228c2ecf20Sopenharmony_ci goto free_pll; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return clk; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cifree_pll: 2278c2ecf20Sopenharmony_ci kfree(pll); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return clk; 2308c2ecf20Sopenharmony_ci} 231