Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
0004  *
0005  * Authors:
0006  *   Serge Semin <Sergey.Semin@baikalelectronics.ru>
0007  *   Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>
0008  *
0009  * Baikal-T1 CCU PLL clocks driver
0010  */
0011 
0012 #define pr_fmt(fmt) "bt1-ccu-pll: " fmt
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/printk.h>
0016 #include <linux/slab.h>
0017 #include <linux/clk-provider.h>
0018 #include <linux/mfd/syscon.h>
0019 #include <linux/of.h>
0020 #include <linux/of_address.h>
0021 #include <linux/ioport.h>
0022 #include <linux/regmap.h>
0023 
0024 #include <dt-bindings/clock/bt1-ccu.h>
0025 
0026 #include "ccu-pll.h"
0027 
0028 #define CCU_CPU_PLL_BASE        0x000
0029 #define CCU_SATA_PLL_BASE       0x008
0030 #define CCU_DDR_PLL_BASE        0x010
0031 #define CCU_PCIE_PLL_BASE       0x018
0032 #define CCU_ETH_PLL_BASE        0x020
0033 
0034 #define CCU_PLL_INFO(_id, _name, _pname, _base, _flags) \
0035     {                       \
0036         .id = _id,              \
0037         .name = _name,              \
0038         .parent_name = _pname,          \
0039         .base = _base,              \
0040         .flags = _flags             \
0041     }
0042 
0043 #define CCU_PLL_NUM         ARRAY_SIZE(pll_info)
0044 
0045 struct ccu_pll_info {
0046     unsigned int id;
0047     const char *name;
0048     const char *parent_name;
0049     unsigned int base;
0050     unsigned long flags;
0051 };
0052 
0053 /*
0054  * Alas we have to mark all PLLs as critical. CPU and DDR PLLs are sources of
0055  * CPU cores and DDR controller reference clocks, due to which they obviously
0056  * shouldn't be ever gated. SATA and PCIe PLLs are the parents of APB-bus and
0057  * DDR controller AXI-bus clocks. If they are gated the system will be
0058  * unusable. Moreover disabling SATA and Ethernet PLLs causes automatic reset
0059  * of the corresponding subsystems. So until we aren't ready to re-initialize
0060  * all the devices consuming those PLLs, they will be marked as critical too.
0061  */
0062 static const struct ccu_pll_info pll_info[] = {
0063     CCU_PLL_INFO(CCU_CPU_PLL, "cpu_pll", "ref_clk", CCU_CPU_PLL_BASE,
0064              CLK_IS_CRITICAL),
0065     CCU_PLL_INFO(CCU_SATA_PLL, "sata_pll", "ref_clk", CCU_SATA_PLL_BASE,
0066              CLK_IS_CRITICAL | CLK_SET_RATE_GATE),
0067     CCU_PLL_INFO(CCU_DDR_PLL, "ddr_pll", "ref_clk", CCU_DDR_PLL_BASE,
0068              CLK_IS_CRITICAL | CLK_SET_RATE_GATE),
0069     CCU_PLL_INFO(CCU_PCIE_PLL, "pcie_pll", "ref_clk", CCU_PCIE_PLL_BASE,
0070              CLK_IS_CRITICAL),
0071     CCU_PLL_INFO(CCU_ETH_PLL, "eth_pll", "ref_clk", CCU_ETH_PLL_BASE,
0072              CLK_IS_CRITICAL | CLK_SET_RATE_GATE)
0073 };
0074 
0075 struct ccu_pll_data {
0076     struct device_node *np;
0077     struct regmap *sys_regs;
0078     struct ccu_pll *plls[CCU_PLL_NUM];
0079 };
0080 
0081 static struct ccu_pll *ccu_pll_find_desc(struct ccu_pll_data *data,
0082                      unsigned int clk_id)
0083 {
0084     struct ccu_pll *pll;
0085     int idx;
0086 
0087     for (idx = 0; idx < CCU_PLL_NUM; ++idx) {
0088         pll = data->plls[idx];
0089         if (pll && pll->id == clk_id)
0090             return pll;
0091     }
0092 
0093     return ERR_PTR(-EINVAL);
0094 }
0095 
0096 static struct ccu_pll_data *ccu_pll_create_data(struct device_node *np)
0097 {
0098     struct ccu_pll_data *data;
0099 
0100     data = kzalloc(sizeof(*data), GFP_KERNEL);
0101     if (!data)
0102         return ERR_PTR(-ENOMEM);
0103 
0104     data->np = np;
0105 
0106     return data;
0107 }
0108 
0109 static void ccu_pll_free_data(struct ccu_pll_data *data)
0110 {
0111     kfree(data);
0112 }
0113 
0114 static int ccu_pll_find_sys_regs(struct ccu_pll_data *data)
0115 {
0116     data->sys_regs = syscon_node_to_regmap(data->np->parent);
0117     if (IS_ERR(data->sys_regs)) {
0118         pr_err("Failed to find syscon regs for '%s'\n",
0119             of_node_full_name(data->np));
0120         return PTR_ERR(data->sys_regs);
0121     }
0122 
0123     return 0;
0124 }
0125 
0126 static struct clk_hw *ccu_pll_of_clk_hw_get(struct of_phandle_args *clkspec,
0127                         void *priv)
0128 {
0129     struct ccu_pll_data *data = priv;
0130     struct ccu_pll *pll;
0131     unsigned int clk_id;
0132 
0133     clk_id = clkspec->args[0];
0134     pll = ccu_pll_find_desc(data, clk_id);
0135     if (IS_ERR(pll)) {
0136         pr_info("Invalid PLL clock ID %d specified\n", clk_id);
0137         return ERR_CAST(pll);
0138     }
0139 
0140     return ccu_pll_get_clk_hw(pll);
0141 }
0142 
0143 static int ccu_pll_clk_register(struct ccu_pll_data *data)
0144 {
0145     int idx, ret;
0146 
0147     for (idx = 0; idx < CCU_PLL_NUM; ++idx) {
0148         const struct ccu_pll_info *info = &pll_info[idx];
0149         struct ccu_pll_init_data init = {0};
0150 
0151         init.id = info->id;
0152         init.name = info->name;
0153         init.parent_name = info->parent_name;
0154         init.base = info->base;
0155         init.sys_regs = data->sys_regs;
0156         init.np = data->np;
0157         init.flags = info->flags;
0158 
0159         data->plls[idx] = ccu_pll_hw_register(&init);
0160         if (IS_ERR(data->plls[idx])) {
0161             ret = PTR_ERR(data->plls[idx]);
0162             pr_err("Couldn't register PLL hw '%s'\n",
0163                 init.name);
0164             goto err_hw_unregister;
0165         }
0166     }
0167 
0168     ret = of_clk_add_hw_provider(data->np, ccu_pll_of_clk_hw_get, data);
0169     if (ret) {
0170         pr_err("Couldn't register PLL provider of '%s'\n",
0171             of_node_full_name(data->np));
0172         goto err_hw_unregister;
0173     }
0174 
0175     return 0;
0176 
0177 err_hw_unregister:
0178     for (--idx; idx >= 0; --idx)
0179         ccu_pll_hw_unregister(data->plls[idx]);
0180 
0181     return ret;
0182 }
0183 
0184 static __init void ccu_pll_init(struct device_node *np)
0185 {
0186     struct ccu_pll_data *data;
0187     int ret;
0188 
0189     data = ccu_pll_create_data(np);
0190     if (IS_ERR(data))
0191         return;
0192 
0193     ret = ccu_pll_find_sys_regs(data);
0194     if (ret)
0195         goto err_free_data;
0196 
0197     ret = ccu_pll_clk_register(data);
0198     if (ret)
0199         goto err_free_data;
0200 
0201     return;
0202 
0203 err_free_data:
0204     ccu_pll_free_data(data);
0205 }
0206 CLK_OF_DECLARE(ccu_pll, "baikal,bt1-ccu-pll", ccu_pll_init);