clk-loongson1b.c (4026B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2012-2016 Zhang, Keguang <keguang.zhang@gmail.com> 4 */ 5 6#include <linux/clkdev.h> 7#include <linux/clk-provider.h> 8#include <linux/io.h> 9#include <linux/err.h> 10 11#include <loongson1.h> 12#include "clk.h" 13 14#define OSC (33 * 1000000) 15#define DIV_APB 2 16 17static DEFINE_SPINLOCK(_lock); 18 19static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, 20 unsigned long parent_rate) 21{ 22 u32 pll, rate; 23 24 pll = __raw_readl(LS1X_CLK_PLL_FREQ); 25 rate = 12 + (pll & GENMASK(5, 0)); 26 rate *= OSC; 27 rate >>= 1; 28 29 return rate; 30} 31 32static const struct clk_ops ls1x_pll_clk_ops = { 33 .recalc_rate = ls1x_pll_recalc_rate, 34}; 35 36static const char *const cpu_parents[] = { "cpu_clk_div", "osc_clk", }; 37static const char *const ahb_parents[] = { "ahb_clk_div", "osc_clk", }; 38static const char *const dc_parents[] = { "dc_clk_div", "osc_clk", }; 39 40void __init ls1x_clk_init(void) 41{ 42 struct clk_hw *hw; 43 44 hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); 45 clk_hw_register_clkdev(hw, "osc_clk", NULL); 46 47 /* clock derived from 33 MHz OSC clk */ 48 hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", 49 &ls1x_pll_clk_ops, 0); 50 clk_hw_register_clkdev(hw, "pll_clk", NULL); 51 52 /* clock derived from PLL clk */ 53 /* _____ 54 * _______________________| | 55 * OSC ___/ | MUX |___ CPU CLK 56 * \___ PLL ___ CPU DIV ___| | 57 * |_____| 58 */ 59 hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", 60 CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, 61 DIV_CPU_SHIFT, DIV_CPU_WIDTH, 62 CLK_DIVIDER_ONE_BASED | 63 CLK_DIVIDER_ROUND_CLOSEST, &_lock); 64 clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); 65 hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, 66 ARRAY_SIZE(cpu_parents), 67 CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, 68 BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); 69 clk_hw_register_clkdev(hw, "cpu_clk", NULL); 70 71 /* _____ 72 * _______________________| | 73 * OSC ___/ | MUX |___ DC CLK 74 * \___ PLL ___ DC DIV ___| | 75 * |_____| 76 */ 77 hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", 78 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, 79 DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); 80 clk_hw_register_clkdev(hw, "dc_clk_div", NULL); 81 hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, 82 ARRAY_SIZE(dc_parents), 83 CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, 84 BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); 85 clk_hw_register_clkdev(hw, "dc_clk", NULL); 86 87 /* _____ 88 * _______________________| | 89 * OSC ___/ | MUX |___ DDR CLK 90 * \___ PLL ___ DDR DIV ___| | 91 * |_____| 92 */ 93 hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", 94 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, 95 DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, 96 &_lock); 97 clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); 98 hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, 99 ARRAY_SIZE(ahb_parents), 100 CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, 101 BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); 102 clk_hw_register_clkdev(hw, "ahb_clk", NULL); 103 clk_hw_register_clkdev(hw, "ls1x-dma", NULL); 104 clk_hw_register_clkdev(hw, "stmmaceth", NULL); 105 106 /* clock derived from AHB clk */ 107 /* APB clk is always half of the AHB clk */ 108 hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 109 DIV_APB); 110 clk_hw_register_clkdev(hw, "apb_clk", NULL); 111 clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); 112 clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); 113 clk_hw_register_clkdev(hw, "ls1x-nand", NULL); 114 clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); 115 clk_hw_register_clkdev(hw, "ls1x-spi", NULL); 116 clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); 117 clk_hw_register_clkdev(hw, "serial8250", NULL); 118}