143049b0cSAndrew Bresticker /* 243049b0cSAndrew Bresticker * Copyright (C) 2014 Google, Inc. 343049b0cSAndrew Bresticker * 443049b0cSAndrew Bresticker * This program is free software; you can redistribute it and/or modify it 543049b0cSAndrew Bresticker * under the terms and conditions of the GNU General Public License, 643049b0cSAndrew Bresticker * version 2, as published by the Free Software Foundation. 743049b0cSAndrew Bresticker */ 843049b0cSAndrew Bresticker 943049b0cSAndrew Bresticker #include <linux/clk-provider.h> 1043049b0cSAndrew Bresticker #include <linux/io.h> 1143049b0cSAndrew Bresticker #include <linux/kernel.h> 1243049b0cSAndrew Bresticker #include <linux/slab.h> 1343049b0cSAndrew Bresticker 1443049b0cSAndrew Bresticker #include "clk.h" 1543049b0cSAndrew Bresticker 1643049b0cSAndrew Bresticker #define PLL_STATUS 0x0 1743049b0cSAndrew Bresticker #define PLL_STATUS_LOCK BIT(0) 1843049b0cSAndrew Bresticker 1943049b0cSAndrew Bresticker #define PLL_CTRL1 0x4 2043049b0cSAndrew Bresticker #define PLL_CTRL1_REFDIV_SHIFT 0 2143049b0cSAndrew Bresticker #define PLL_CTRL1_REFDIV_MASK 0x3f 2243049b0cSAndrew Bresticker #define PLL_CTRL1_FBDIV_SHIFT 6 2343049b0cSAndrew Bresticker #define PLL_CTRL1_FBDIV_MASK 0xfff 2443049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV1_SHIFT 18 2543049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV1_MASK 0x7 2643049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV2_SHIFT 21 2743049b0cSAndrew Bresticker #define PLL_INT_CTRL1_POSTDIV2_MASK 0x7 2843049b0cSAndrew Bresticker #define PLL_INT_CTRL1_PD BIT(24) 2943049b0cSAndrew Bresticker #define PLL_INT_CTRL1_DSMPD BIT(25) 3043049b0cSAndrew Bresticker #define PLL_INT_CTRL1_FOUTPOSTDIVPD BIT(26) 3143049b0cSAndrew Bresticker #define PLL_INT_CTRL1_FOUTVCOPD BIT(27) 3243049b0cSAndrew Bresticker 3343049b0cSAndrew Bresticker #define PLL_CTRL2 0x8 3443049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_FRAC_SHIFT 0 3543049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_FRAC_MASK 0xffffff 3643049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV1_SHIFT 24 3743049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV1_MASK 0x7 3843049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV2_SHIFT 27 3943049b0cSAndrew Bresticker #define PLL_FRAC_CTRL2_POSTDIV2_MASK 0x7 4043049b0cSAndrew Bresticker #define PLL_INT_CTRL2_BYPASS BIT(28) 4143049b0cSAndrew Bresticker 4243049b0cSAndrew Bresticker #define PLL_CTRL3 0xc 4343049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_PD BIT(0) 4443049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_DACPD BIT(1) 4543049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_DSMPD BIT(2) 4643049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_FOUTPOSTDIVPD BIT(3) 4743049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_FOUT4PHASEPD BIT(4) 4843049b0cSAndrew Bresticker #define PLL_FRAC_CTRL3_FOUTVCOPD BIT(5) 4943049b0cSAndrew Bresticker 5043049b0cSAndrew Bresticker #define PLL_CTRL4 0x10 5143049b0cSAndrew Bresticker #define PLL_FRAC_CTRL4_BYPASS BIT(28) 5243049b0cSAndrew Bresticker 5343049b0cSAndrew Bresticker struct pistachio_clk_pll { 5443049b0cSAndrew Bresticker struct clk_hw hw; 5543049b0cSAndrew Bresticker void __iomem *base; 5643049b0cSAndrew Bresticker struct pistachio_pll_rate_table *rates; 5743049b0cSAndrew Bresticker unsigned int nr_rates; 5843049b0cSAndrew Bresticker }; 5943049b0cSAndrew Bresticker 6043049b0cSAndrew Bresticker static inline u32 pll_readl(struct pistachio_clk_pll *pll, u32 reg) 6143049b0cSAndrew Bresticker { 6243049b0cSAndrew Bresticker return readl(pll->base + reg); 6343049b0cSAndrew Bresticker } 6443049b0cSAndrew Bresticker 6543049b0cSAndrew Bresticker static inline void pll_writel(struct pistachio_clk_pll *pll, u32 val, u32 reg) 6643049b0cSAndrew Bresticker { 6743049b0cSAndrew Bresticker writel(val, pll->base + reg); 6843049b0cSAndrew Bresticker } 6943049b0cSAndrew Bresticker 70*4f4adfbfSEzequiel Garcia static inline void pll_lock(struct pistachio_clk_pll *pll) 71*4f4adfbfSEzequiel Garcia { 72*4f4adfbfSEzequiel Garcia while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK)) 73*4f4adfbfSEzequiel Garcia cpu_relax(); 74*4f4adfbfSEzequiel Garcia } 75*4f4adfbfSEzequiel Garcia 7643049b0cSAndrew Bresticker static inline u32 do_div_round_closest(u64 dividend, u32 divisor) 7743049b0cSAndrew Bresticker { 7843049b0cSAndrew Bresticker dividend += divisor / 2; 7943049b0cSAndrew Bresticker do_div(dividend, divisor); 8043049b0cSAndrew Bresticker 8143049b0cSAndrew Bresticker return dividend; 8243049b0cSAndrew Bresticker } 8343049b0cSAndrew Bresticker 8443049b0cSAndrew Bresticker static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw) 8543049b0cSAndrew Bresticker { 8643049b0cSAndrew Bresticker return container_of(hw, struct pistachio_clk_pll, hw); 8743049b0cSAndrew Bresticker } 8843049b0cSAndrew Bresticker 8943049b0cSAndrew Bresticker static struct pistachio_pll_rate_table * 9043049b0cSAndrew Bresticker pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, 9143049b0cSAndrew Bresticker unsigned long fout) 9243049b0cSAndrew Bresticker { 9343049b0cSAndrew Bresticker unsigned int i; 9443049b0cSAndrew Bresticker 9543049b0cSAndrew Bresticker for (i = 0; i < pll->nr_rates; i++) { 9643049b0cSAndrew Bresticker if (pll->rates[i].fref == fref && pll->rates[i].fout == fout) 9743049b0cSAndrew Bresticker return &pll->rates[i]; 9843049b0cSAndrew Bresticker } 9943049b0cSAndrew Bresticker 10043049b0cSAndrew Bresticker return NULL; 10143049b0cSAndrew Bresticker } 10243049b0cSAndrew Bresticker 10343049b0cSAndrew Bresticker static long pll_round_rate(struct clk_hw *hw, unsigned long rate, 10443049b0cSAndrew Bresticker unsigned long *parent_rate) 10543049b0cSAndrew Bresticker { 10643049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 10743049b0cSAndrew Bresticker unsigned int i; 10843049b0cSAndrew Bresticker 10943049b0cSAndrew Bresticker for (i = 0; i < pll->nr_rates; i++) { 11043049b0cSAndrew Bresticker if (i > 0 && pll->rates[i].fref == *parent_rate && 11143049b0cSAndrew Bresticker pll->rates[i].fout <= rate) 11243049b0cSAndrew Bresticker return pll->rates[i - 1].fout; 11343049b0cSAndrew Bresticker } 11443049b0cSAndrew Bresticker 11543049b0cSAndrew Bresticker return pll->rates[0].fout; 11643049b0cSAndrew Bresticker } 11743049b0cSAndrew Bresticker 11843049b0cSAndrew Bresticker static int pll_gf40lp_frac_enable(struct clk_hw *hw) 11943049b0cSAndrew Bresticker { 12043049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 12143049b0cSAndrew Bresticker u32 val; 12243049b0cSAndrew Bresticker 12343049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL3); 12443049b0cSAndrew Bresticker val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_DACPD | 12543049b0cSAndrew Bresticker PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD | 12643049b0cSAndrew Bresticker PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD); 12743049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL3); 12843049b0cSAndrew Bresticker 12943049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL4); 13043049b0cSAndrew Bresticker val &= ~PLL_FRAC_CTRL4_BYPASS; 13143049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL4); 13243049b0cSAndrew Bresticker 13343049b0cSAndrew Bresticker return 0; 13443049b0cSAndrew Bresticker } 13543049b0cSAndrew Bresticker 13643049b0cSAndrew Bresticker static void pll_gf40lp_frac_disable(struct clk_hw *hw) 13743049b0cSAndrew Bresticker { 13843049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 13943049b0cSAndrew Bresticker u32 val; 14043049b0cSAndrew Bresticker 14143049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL3); 14243049b0cSAndrew Bresticker val |= PLL_FRAC_CTRL3_PD; 14343049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL3); 14443049b0cSAndrew Bresticker } 14543049b0cSAndrew Bresticker 14643049b0cSAndrew Bresticker static int pll_gf40lp_frac_is_enabled(struct clk_hw *hw) 14743049b0cSAndrew Bresticker { 14843049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 14943049b0cSAndrew Bresticker 15043049b0cSAndrew Bresticker return !(pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_PD); 15143049b0cSAndrew Bresticker } 15243049b0cSAndrew Bresticker 15343049b0cSAndrew Bresticker static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, 15443049b0cSAndrew Bresticker unsigned long parent_rate) 15543049b0cSAndrew Bresticker { 15643049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 15743049b0cSAndrew Bresticker struct pistachio_pll_rate_table *params; 15843049b0cSAndrew Bresticker bool was_enabled; 15943049b0cSAndrew Bresticker u32 val; 16043049b0cSAndrew Bresticker 16143049b0cSAndrew Bresticker params = pll_get_params(pll, parent_rate, rate); 16243049b0cSAndrew Bresticker if (!params) 16343049b0cSAndrew Bresticker return -EINVAL; 16443049b0cSAndrew Bresticker 16543049b0cSAndrew Bresticker was_enabled = pll_gf40lp_frac_is_enabled(hw); 16643049b0cSAndrew Bresticker if (!was_enabled) 16743049b0cSAndrew Bresticker pll_gf40lp_frac_enable(hw); 16843049b0cSAndrew Bresticker 16943049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL1); 17043049b0cSAndrew Bresticker val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) | 17143049b0cSAndrew Bresticker (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT)); 17243049b0cSAndrew Bresticker val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) | 17343049b0cSAndrew Bresticker (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT); 17443049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL1); 17543049b0cSAndrew Bresticker 17643049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL2); 17743049b0cSAndrew Bresticker val &= ~((PLL_FRAC_CTRL2_FRAC_MASK << PLL_FRAC_CTRL2_FRAC_SHIFT) | 17843049b0cSAndrew Bresticker (PLL_FRAC_CTRL2_POSTDIV1_MASK << 17943049b0cSAndrew Bresticker PLL_FRAC_CTRL2_POSTDIV1_SHIFT) | 18043049b0cSAndrew Bresticker (PLL_FRAC_CTRL2_POSTDIV2_MASK << 18143049b0cSAndrew Bresticker PLL_FRAC_CTRL2_POSTDIV2_SHIFT)); 18243049b0cSAndrew Bresticker val |= (params->frac << PLL_FRAC_CTRL2_FRAC_SHIFT) | 18343049b0cSAndrew Bresticker (params->postdiv1 << PLL_FRAC_CTRL2_POSTDIV1_SHIFT) | 18443049b0cSAndrew Bresticker (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT); 18543049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL2); 18643049b0cSAndrew Bresticker 187*4f4adfbfSEzequiel Garcia pll_lock(pll); 18843049b0cSAndrew Bresticker 18943049b0cSAndrew Bresticker if (!was_enabled) 19043049b0cSAndrew Bresticker pll_gf40lp_frac_disable(hw); 19143049b0cSAndrew Bresticker 19243049b0cSAndrew Bresticker return 0; 19343049b0cSAndrew Bresticker } 19443049b0cSAndrew Bresticker 19543049b0cSAndrew Bresticker static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw, 19643049b0cSAndrew Bresticker unsigned long parent_rate) 19743049b0cSAndrew Bresticker { 19843049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 19943049b0cSAndrew Bresticker u32 val, prediv, fbdiv, frac, postdiv1, postdiv2; 20043049b0cSAndrew Bresticker u64 rate = parent_rate; 20143049b0cSAndrew Bresticker 20243049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL1); 20343049b0cSAndrew Bresticker prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK; 20443049b0cSAndrew Bresticker fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK; 20543049b0cSAndrew Bresticker 20643049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL2); 20743049b0cSAndrew Bresticker postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) & 20843049b0cSAndrew Bresticker PLL_FRAC_CTRL2_POSTDIV1_MASK; 20943049b0cSAndrew Bresticker postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) & 21043049b0cSAndrew Bresticker PLL_FRAC_CTRL2_POSTDIV2_MASK; 21143049b0cSAndrew Bresticker frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK; 21243049b0cSAndrew Bresticker 21343049b0cSAndrew Bresticker rate *= (fbdiv << 24) + frac; 21443049b0cSAndrew Bresticker rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24); 21543049b0cSAndrew Bresticker 21643049b0cSAndrew Bresticker return rate; 21743049b0cSAndrew Bresticker } 21843049b0cSAndrew Bresticker 21943049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_frac_ops = { 22043049b0cSAndrew Bresticker .enable = pll_gf40lp_frac_enable, 22143049b0cSAndrew Bresticker .disable = pll_gf40lp_frac_disable, 22243049b0cSAndrew Bresticker .is_enabled = pll_gf40lp_frac_is_enabled, 22343049b0cSAndrew Bresticker .recalc_rate = pll_gf40lp_frac_recalc_rate, 22443049b0cSAndrew Bresticker .round_rate = pll_round_rate, 22543049b0cSAndrew Bresticker .set_rate = pll_gf40lp_frac_set_rate, 22643049b0cSAndrew Bresticker }; 22743049b0cSAndrew Bresticker 22843049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_frac_fixed_ops = { 22943049b0cSAndrew Bresticker .enable = pll_gf40lp_frac_enable, 23043049b0cSAndrew Bresticker .disable = pll_gf40lp_frac_disable, 23143049b0cSAndrew Bresticker .is_enabled = pll_gf40lp_frac_is_enabled, 23243049b0cSAndrew Bresticker .recalc_rate = pll_gf40lp_frac_recalc_rate, 23343049b0cSAndrew Bresticker }; 23443049b0cSAndrew Bresticker 23543049b0cSAndrew Bresticker static int pll_gf40lp_laint_enable(struct clk_hw *hw) 23643049b0cSAndrew Bresticker { 23743049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 23843049b0cSAndrew Bresticker u32 val; 23943049b0cSAndrew Bresticker 24043049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL1); 24143049b0cSAndrew Bresticker val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_DSMPD | 24243049b0cSAndrew Bresticker PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD); 24343049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL1); 24443049b0cSAndrew Bresticker 24543049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL2); 24643049b0cSAndrew Bresticker val &= ~PLL_INT_CTRL2_BYPASS; 24743049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL2); 24843049b0cSAndrew Bresticker 24943049b0cSAndrew Bresticker return 0; 25043049b0cSAndrew Bresticker } 25143049b0cSAndrew Bresticker 25243049b0cSAndrew Bresticker static void pll_gf40lp_laint_disable(struct clk_hw *hw) 25343049b0cSAndrew Bresticker { 25443049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 25543049b0cSAndrew Bresticker u32 val; 25643049b0cSAndrew Bresticker 25743049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL1); 25843049b0cSAndrew Bresticker val |= PLL_INT_CTRL1_PD; 25943049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL1); 26043049b0cSAndrew Bresticker } 26143049b0cSAndrew Bresticker 26243049b0cSAndrew Bresticker static int pll_gf40lp_laint_is_enabled(struct clk_hw *hw) 26343049b0cSAndrew Bresticker { 26443049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 26543049b0cSAndrew Bresticker 26643049b0cSAndrew Bresticker return !(pll_readl(pll, PLL_CTRL1) & PLL_INT_CTRL1_PD); 26743049b0cSAndrew Bresticker } 26843049b0cSAndrew Bresticker 26943049b0cSAndrew Bresticker static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate, 27043049b0cSAndrew Bresticker unsigned long parent_rate) 27143049b0cSAndrew Bresticker { 27243049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 27343049b0cSAndrew Bresticker struct pistachio_pll_rate_table *params; 27443049b0cSAndrew Bresticker bool was_enabled; 27543049b0cSAndrew Bresticker u32 val; 27643049b0cSAndrew Bresticker 27743049b0cSAndrew Bresticker params = pll_get_params(pll, parent_rate, rate); 27843049b0cSAndrew Bresticker if (!params) 27943049b0cSAndrew Bresticker return -EINVAL; 28043049b0cSAndrew Bresticker 28143049b0cSAndrew Bresticker was_enabled = pll_gf40lp_laint_is_enabled(hw); 28243049b0cSAndrew Bresticker if (!was_enabled) 28343049b0cSAndrew Bresticker pll_gf40lp_laint_enable(hw); 28443049b0cSAndrew Bresticker 28543049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL1); 28643049b0cSAndrew Bresticker val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) | 28743049b0cSAndrew Bresticker (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT) | 28843049b0cSAndrew Bresticker (PLL_INT_CTRL1_POSTDIV1_MASK << PLL_INT_CTRL1_POSTDIV1_SHIFT) | 28943049b0cSAndrew Bresticker (PLL_INT_CTRL1_POSTDIV2_MASK << PLL_INT_CTRL1_POSTDIV2_SHIFT)); 29043049b0cSAndrew Bresticker val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) | 29143049b0cSAndrew Bresticker (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT) | 29243049b0cSAndrew Bresticker (params->postdiv1 << PLL_INT_CTRL1_POSTDIV1_SHIFT) | 29343049b0cSAndrew Bresticker (params->postdiv2 << PLL_INT_CTRL1_POSTDIV2_SHIFT); 29443049b0cSAndrew Bresticker pll_writel(pll, val, PLL_CTRL1); 29543049b0cSAndrew Bresticker 296*4f4adfbfSEzequiel Garcia pll_lock(pll); 29743049b0cSAndrew Bresticker 29843049b0cSAndrew Bresticker if (!was_enabled) 29943049b0cSAndrew Bresticker pll_gf40lp_laint_disable(hw); 30043049b0cSAndrew Bresticker 30143049b0cSAndrew Bresticker return 0; 30243049b0cSAndrew Bresticker } 30343049b0cSAndrew Bresticker 30443049b0cSAndrew Bresticker static unsigned long pll_gf40lp_laint_recalc_rate(struct clk_hw *hw, 30543049b0cSAndrew Bresticker unsigned long parent_rate) 30643049b0cSAndrew Bresticker { 30743049b0cSAndrew Bresticker struct pistachio_clk_pll *pll = to_pistachio_pll(hw); 30843049b0cSAndrew Bresticker u32 val, prediv, fbdiv, postdiv1, postdiv2; 30943049b0cSAndrew Bresticker u64 rate = parent_rate; 31043049b0cSAndrew Bresticker 31143049b0cSAndrew Bresticker val = pll_readl(pll, PLL_CTRL1); 31243049b0cSAndrew Bresticker prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK; 31343049b0cSAndrew Bresticker fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK; 31443049b0cSAndrew Bresticker postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) & 31543049b0cSAndrew Bresticker PLL_INT_CTRL1_POSTDIV1_MASK; 31643049b0cSAndrew Bresticker postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) & 31743049b0cSAndrew Bresticker PLL_INT_CTRL1_POSTDIV2_MASK; 31843049b0cSAndrew Bresticker 31943049b0cSAndrew Bresticker rate *= fbdiv; 32043049b0cSAndrew Bresticker rate = do_div_round_closest(rate, prediv * postdiv1 * postdiv2); 32143049b0cSAndrew Bresticker 32243049b0cSAndrew Bresticker return rate; 32343049b0cSAndrew Bresticker } 32443049b0cSAndrew Bresticker 32543049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_laint_ops = { 32643049b0cSAndrew Bresticker .enable = pll_gf40lp_laint_enable, 32743049b0cSAndrew Bresticker .disable = pll_gf40lp_laint_disable, 32843049b0cSAndrew Bresticker .is_enabled = pll_gf40lp_laint_is_enabled, 32943049b0cSAndrew Bresticker .recalc_rate = pll_gf40lp_laint_recalc_rate, 33043049b0cSAndrew Bresticker .round_rate = pll_round_rate, 33143049b0cSAndrew Bresticker .set_rate = pll_gf40lp_laint_set_rate, 33243049b0cSAndrew Bresticker }; 33343049b0cSAndrew Bresticker 33443049b0cSAndrew Bresticker static struct clk_ops pll_gf40lp_laint_fixed_ops = { 33543049b0cSAndrew Bresticker .enable = pll_gf40lp_laint_enable, 33643049b0cSAndrew Bresticker .disable = pll_gf40lp_laint_disable, 33743049b0cSAndrew Bresticker .is_enabled = pll_gf40lp_laint_is_enabled, 33843049b0cSAndrew Bresticker .recalc_rate = pll_gf40lp_laint_recalc_rate, 33943049b0cSAndrew Bresticker }; 34043049b0cSAndrew Bresticker 34143049b0cSAndrew Bresticker static struct clk *pll_register(const char *name, const char *parent_name, 34243049b0cSAndrew Bresticker unsigned long flags, void __iomem *base, 34343049b0cSAndrew Bresticker enum pistachio_pll_type type, 34443049b0cSAndrew Bresticker struct pistachio_pll_rate_table *rates, 34543049b0cSAndrew Bresticker unsigned int nr_rates) 34643049b0cSAndrew Bresticker { 34743049b0cSAndrew Bresticker struct pistachio_clk_pll *pll; 34843049b0cSAndrew Bresticker struct clk_init_data init; 34943049b0cSAndrew Bresticker struct clk *clk; 35043049b0cSAndrew Bresticker 35143049b0cSAndrew Bresticker pll = kzalloc(sizeof(*pll), GFP_KERNEL); 35243049b0cSAndrew Bresticker if (!pll) 35343049b0cSAndrew Bresticker return ERR_PTR(-ENOMEM); 35443049b0cSAndrew Bresticker 35543049b0cSAndrew Bresticker init.name = name; 35643049b0cSAndrew Bresticker init.flags = flags | CLK_GET_RATE_NOCACHE; 35743049b0cSAndrew Bresticker init.parent_names = &parent_name; 35843049b0cSAndrew Bresticker init.num_parents = 1; 35943049b0cSAndrew Bresticker 36043049b0cSAndrew Bresticker switch (type) { 36143049b0cSAndrew Bresticker case PLL_GF40LP_FRAC: 36243049b0cSAndrew Bresticker if (rates) 36343049b0cSAndrew Bresticker init.ops = &pll_gf40lp_frac_ops; 36443049b0cSAndrew Bresticker else 36543049b0cSAndrew Bresticker init.ops = &pll_gf40lp_frac_fixed_ops; 36643049b0cSAndrew Bresticker break; 36743049b0cSAndrew Bresticker case PLL_GF40LP_LAINT: 36843049b0cSAndrew Bresticker if (rates) 36943049b0cSAndrew Bresticker init.ops = &pll_gf40lp_laint_ops; 37043049b0cSAndrew Bresticker else 37143049b0cSAndrew Bresticker init.ops = &pll_gf40lp_laint_fixed_ops; 37243049b0cSAndrew Bresticker break; 37343049b0cSAndrew Bresticker default: 37443049b0cSAndrew Bresticker pr_err("Unrecognized PLL type %u\n", type); 37543049b0cSAndrew Bresticker kfree(pll); 37643049b0cSAndrew Bresticker return ERR_PTR(-EINVAL); 37743049b0cSAndrew Bresticker } 37843049b0cSAndrew Bresticker 37943049b0cSAndrew Bresticker pll->hw.init = &init; 38043049b0cSAndrew Bresticker pll->base = base; 38143049b0cSAndrew Bresticker pll->rates = rates; 38243049b0cSAndrew Bresticker pll->nr_rates = nr_rates; 38343049b0cSAndrew Bresticker 38443049b0cSAndrew Bresticker clk = clk_register(NULL, &pll->hw); 38543049b0cSAndrew Bresticker if (IS_ERR(clk)) 38643049b0cSAndrew Bresticker kfree(pll); 38743049b0cSAndrew Bresticker 38843049b0cSAndrew Bresticker return clk; 38943049b0cSAndrew Bresticker } 39043049b0cSAndrew Bresticker 39143049b0cSAndrew Bresticker void pistachio_clk_register_pll(struct pistachio_clk_provider *p, 39243049b0cSAndrew Bresticker struct pistachio_pll *pll, 39343049b0cSAndrew Bresticker unsigned int num) 39443049b0cSAndrew Bresticker { 39543049b0cSAndrew Bresticker struct clk *clk; 39643049b0cSAndrew Bresticker unsigned int i; 39743049b0cSAndrew Bresticker 39843049b0cSAndrew Bresticker for (i = 0; i < num; i++) { 39943049b0cSAndrew Bresticker clk = pll_register(pll[i].name, pll[i].parent, 40043049b0cSAndrew Bresticker 0, p->base + pll[i].reg_base, 40143049b0cSAndrew Bresticker pll[i].type, pll[i].rates, 40243049b0cSAndrew Bresticker pll[i].nr_rates); 40343049b0cSAndrew Bresticker p->clk_data.clks[pll[i].id] = clk; 40443049b0cSAndrew Bresticker } 40543049b0cSAndrew Bresticker } 406