Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/bits.h>
0003 #include <linux/clk.h>
0004 #include <linux/clk-provider.h>
0005 #include <linux/err.h>
0006 #include <linux/io.h>
0007 #include <linux/module.h>
0008 #include <linux/of.h>
0009 #include <linux/slab.h>
0010 #include <linux/spinlock.h>
0011 #include "clk.h"
0012 
0013 #define CCM_CCDR            0x4
0014 #define CCDR_MMDC_CH0_MASK      BIT(17)
0015 #define CCDR_MMDC_CH1_MASK      BIT(16)
0016 
0017 DEFINE_SPINLOCK(imx_ccm_lock);
0018 EXPORT_SYMBOL_GPL(imx_ccm_lock);
0019 
0020 bool mcore_booted;
0021 EXPORT_SYMBOL_GPL(mcore_booted);
0022 
0023 void imx_unregister_clocks(struct clk *clks[], unsigned int count)
0024 {
0025     unsigned int i;
0026 
0027     for (i = 0; i < count; i++)
0028         clk_unregister(clks[i]);
0029 }
0030 
0031 void imx_unregister_hw_clocks(struct clk_hw *hws[], unsigned int count)
0032 {
0033     unsigned int i;
0034 
0035     for (i = 0; i < count; i++)
0036         clk_hw_unregister(hws[i]);
0037 }
0038 EXPORT_SYMBOL_GPL(imx_unregister_hw_clocks);
0039 
0040 void imx_mmdc_mask_handshake(void __iomem *ccm_base,
0041                     unsigned int chn)
0042 {
0043     unsigned int reg;
0044 
0045     reg = readl_relaxed(ccm_base + CCM_CCDR);
0046     reg |= chn == 0 ? CCDR_MMDC_CH0_MASK : CCDR_MMDC_CH1_MASK;
0047     writel_relaxed(reg, ccm_base + CCM_CCDR);
0048 }
0049 
0050 void imx_check_clocks(struct clk *clks[], unsigned int count)
0051 {
0052     unsigned i;
0053 
0054     for (i = 0; i < count; i++)
0055         if (IS_ERR(clks[i]))
0056             pr_err("i.MX clk %u: register failed with %ld\n",
0057                    i, PTR_ERR(clks[i]));
0058 }
0059 
0060 void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
0061 {
0062     unsigned int i;
0063 
0064     for (i = 0; i < count; i++)
0065         if (IS_ERR(clks[i]))
0066             pr_err("i.MX clk %u: register failed with %ld\n",
0067                    i, PTR_ERR(clks[i]));
0068 }
0069 EXPORT_SYMBOL_GPL(imx_check_clk_hws);
0070 
0071 static struct clk *imx_obtain_fixed_clock_from_dt(const char *name)
0072 {
0073     struct of_phandle_args phandle;
0074     struct clk *clk = ERR_PTR(-ENODEV);
0075     char *path;
0076 
0077     path = kasprintf(GFP_KERNEL, "/clocks/%s", name);
0078     if (!path)
0079         return ERR_PTR(-ENOMEM);
0080 
0081     phandle.np = of_find_node_by_path(path);
0082     kfree(path);
0083 
0084     if (phandle.np) {
0085         clk = of_clk_get_from_provider(&phandle);
0086         of_node_put(phandle.np);
0087     }
0088     return clk;
0089 }
0090 
0091 struct clk *imx_obtain_fixed_clock(
0092             const char *name, unsigned long rate)
0093 {
0094     struct clk *clk;
0095 
0096     clk = imx_obtain_fixed_clock_from_dt(name);
0097     if (IS_ERR(clk))
0098         clk = imx_clk_fixed(name, rate);
0099     return clk;
0100 }
0101 
0102 struct clk_hw *imx_obtain_fixed_clock_hw(
0103             const char *name, unsigned long rate)
0104 {
0105     struct clk *clk;
0106 
0107     clk = imx_obtain_fixed_clock_from_dt(name);
0108     if (IS_ERR(clk))
0109         clk = imx_clk_fixed(name, rate);
0110     return __clk_get_hw(clk);
0111 }
0112 
0113 struct clk_hw * imx_obtain_fixed_clk_hw(struct device_node *np,
0114                     const char *name)
0115 {
0116     struct clk *clk;
0117 
0118     clk = of_clk_get_by_name(np, name);
0119     if (IS_ERR(clk))
0120         return ERR_PTR(-ENOENT);
0121 
0122     return __clk_get_hw(clk);
0123 }
0124 EXPORT_SYMBOL_GPL(imx_obtain_fixed_clk_hw);
0125 
0126 /*
0127  * This fixups the register CCM_CSCMR1 write value.
0128  * The write/read/divider values of the aclk_podf field
0129  * of that register have the relationship described by
0130  * the following table:
0131  *
0132  * write value       read value        divider
0133  * 3b'000            3b'110            7
0134  * 3b'001            3b'111            8
0135  * 3b'010            3b'100            5
0136  * 3b'011            3b'101            6
0137  * 3b'100            3b'010            3
0138  * 3b'101            3b'011            4
0139  * 3b'110            3b'000            1
0140  * 3b'111            3b'001            2(default)
0141  *
0142  * That's why we do the xor operation below.
0143  */
0144 #define CSCMR1_FIXUP    0x00600000
0145 
0146 void imx_cscmr1_fixup(u32 *val)
0147 {
0148     *val ^= CSCMR1_FIXUP;
0149     return;
0150 }
0151 
0152 #ifndef MODULE
0153 
0154 static bool imx_keep_uart_clocks;
0155 static int imx_enabled_uart_clocks;
0156 static struct clk **imx_uart_clocks;
0157 
0158 static int __init imx_keep_uart_clocks_param(char *str)
0159 {
0160     imx_keep_uart_clocks = 1;
0161 
0162     return 0;
0163 }
0164 __setup_param("earlycon", imx_keep_uart_earlycon,
0165           imx_keep_uart_clocks_param, 0);
0166 __setup_param("earlyprintk", imx_keep_uart_earlyprintk,
0167           imx_keep_uart_clocks_param, 0);
0168 
0169 void imx_register_uart_clocks(unsigned int clk_count)
0170 {
0171     imx_enabled_uart_clocks = 0;
0172 
0173 /* i.MX boards use device trees now.  For build tests without CONFIG_OF, do nothing */
0174 #ifdef CONFIG_OF
0175     if (imx_keep_uart_clocks) {
0176         int i;
0177 
0178         imx_uart_clocks = kcalloc(clk_count, sizeof(struct clk *), GFP_KERNEL);
0179         if (!imx_uart_clocks)
0180             return;
0181 
0182         if (!of_stdout)
0183             return;
0184 
0185         for (i = 0; i < clk_count; i++) {
0186             imx_uart_clocks[imx_enabled_uart_clocks] = of_clk_get(of_stdout, i);
0187 
0188             /* Stop if there are no more of_stdout references */
0189             if (IS_ERR(imx_uart_clocks[imx_enabled_uart_clocks]))
0190                 return;
0191 
0192             /* Only enable the clock if it's not NULL */
0193             if (imx_uart_clocks[imx_enabled_uart_clocks])
0194                 clk_prepare_enable(imx_uart_clocks[imx_enabled_uart_clocks++]);
0195         }
0196     }
0197 #endif
0198 }
0199 
0200 static int __init imx_clk_disable_uart(void)
0201 {
0202     if (imx_keep_uart_clocks && imx_enabled_uart_clocks) {
0203         int i;
0204 
0205         for (i = 0; i < imx_enabled_uart_clocks; i++) {
0206             clk_disable_unprepare(imx_uart_clocks[i]);
0207             clk_put(imx_uart_clocks[i]);
0208         }
0209         kfree(imx_uart_clocks);
0210     }
0211 
0212     return 0;
0213 }
0214 late_initcall_sync(imx_clk_disable_uart);
0215 #endif
0216 
0217 MODULE_LICENSE("GPL v2");