Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2012-2016 Zhang, Keguang <keguang.zhang@gmail.com>
0004  */
0005 
0006 #include <linux/clkdev.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/io.h>
0009 #include <linux/err.h>
0010 
0011 #include <loongson1.h>
0012 #include "clk.h"
0013 
0014 #define OSC     (33 * 1000000)
0015 #define DIV_APB     2
0016 
0017 static DEFINE_SPINLOCK(_lock);
0018 
0019 static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw,
0020                       unsigned long parent_rate)
0021 {
0022     u32 pll, rate;
0023 
0024     pll = __raw_readl(LS1X_CLK_PLL_FREQ);
0025     rate = 12 + (pll & GENMASK(5, 0));
0026     rate *= OSC;
0027     rate >>= 1;
0028 
0029     return rate;
0030 }
0031 
0032 static const struct clk_ops ls1x_pll_clk_ops = {
0033     .recalc_rate = ls1x_pll_recalc_rate,
0034 };
0035 
0036 static const char *const cpu_parents[] = { "cpu_clk_div", "osc_clk", };
0037 static const char *const ahb_parents[] = { "ahb_clk_div", "osc_clk", };
0038 static const char *const dc_parents[] = { "dc_clk_div", "osc_clk", };
0039 
0040 void __init ls1x_clk_init(void)
0041 {
0042     struct clk_hw *hw;
0043 
0044     hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC);
0045     clk_hw_register_clkdev(hw, "osc_clk", NULL);
0046 
0047     /* clock derived from 33 MHz OSC clk */
0048     hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk",
0049                  &ls1x_pll_clk_ops, 0);
0050     clk_hw_register_clkdev(hw, "pll_clk", NULL);
0051 
0052     /* clock derived from PLL clk */
0053     /*                                 _____
0054      *         _______________________|     |
0055      * OSC ___/                       | MUX |___ CPU CLK
0056      *        \___ PLL ___ CPU DIV ___|     |
0057      *                                |_____|
0058      */
0059     hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk",
0060                    CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV,
0061                    DIV_CPU_SHIFT, DIV_CPU_WIDTH,
0062                    CLK_DIVIDER_ONE_BASED |
0063                    CLK_DIVIDER_ROUND_CLOSEST, &_lock);
0064     clk_hw_register_clkdev(hw, "cpu_clk_div", NULL);
0065     hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents,
0066                    ARRAY_SIZE(cpu_parents),
0067                    CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV,
0068                    BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock);
0069     clk_hw_register_clkdev(hw, "cpu_clk", NULL);
0070 
0071     /*                                 _____
0072      *         _______________________|     |
0073      * OSC ___/                       | MUX |___ DC  CLK
0074      *        \___ PLL ___ DC  DIV ___|     |
0075      *                                |_____|
0076      */
0077     hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk",
0078                    0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT,
0079                    DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
0080     clk_hw_register_clkdev(hw, "dc_clk_div", NULL);
0081     hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents,
0082                    ARRAY_SIZE(dc_parents),
0083                    CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV,
0084                    BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock);
0085     clk_hw_register_clkdev(hw, "dc_clk", NULL);
0086 
0087     /*                                 _____
0088      *         _______________________|     |
0089      * OSC ___/                       | MUX |___ DDR CLK
0090      *        \___ PLL ___ DDR DIV ___|     |
0091      *                                |_____|
0092      */
0093     hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk",
0094                    0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT,
0095                    DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED,
0096                    &_lock);
0097     clk_hw_register_clkdev(hw, "ahb_clk_div", NULL);
0098     hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents,
0099                    ARRAY_SIZE(ahb_parents),
0100                    CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV,
0101                    BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock);
0102     clk_hw_register_clkdev(hw, "ahb_clk", NULL);
0103     clk_hw_register_clkdev(hw, "ls1x-dma", NULL);
0104     clk_hw_register_clkdev(hw, "stmmaceth", NULL);
0105 
0106     /* clock derived from AHB clk */
0107     /* APB clk is always half of the AHB clk */
0108     hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1,
0109                     DIV_APB);
0110     clk_hw_register_clkdev(hw, "apb_clk", NULL);
0111     clk_hw_register_clkdev(hw, "ls1x-ac97", NULL);
0112     clk_hw_register_clkdev(hw, "ls1x-i2c", NULL);
0113     clk_hw_register_clkdev(hw, "ls1x-nand", NULL);
0114     clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL);
0115     clk_hw_register_clkdev(hw, "ls1x-spi", NULL);
0116     clk_hw_register_clkdev(hw, "ls1x-wdt", NULL);
0117     clk_hw_register_clkdev(hw, "serial8250", NULL);
0118 }