18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2016 Zhang, Keguang <keguang.zhang@gmail.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 78c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <loongson1.h> 128c2ecf20Sopenharmony_ci#include "clk.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define OSC (33 * 1000000) 158c2ecf20Sopenharmony_ci#define DIV_APB 2 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(_lock); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, 208c2ecf20Sopenharmony_ci unsigned long parent_rate) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci u32 pll, rate; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci pll = __raw_readl(LS1X_CLK_PLL_FREQ); 258c2ecf20Sopenharmony_ci rate = 12 + (pll & GENMASK(5, 0)); 268c2ecf20Sopenharmony_ci rate *= OSC; 278c2ecf20Sopenharmony_ci rate >>= 1; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci return rate; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const struct clk_ops ls1x_pll_clk_ops = { 338c2ecf20Sopenharmony_ci .recalc_rate = ls1x_pll_recalc_rate, 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic const char *const cpu_parents[] = { "cpu_clk_div", "osc_clk", }; 378c2ecf20Sopenharmony_cistatic const char *const ahb_parents[] = { "ahb_clk_div", "osc_clk", }; 388c2ecf20Sopenharmony_cistatic const char *const dc_parents[] = { "dc_clk_div", "osc_clk", }; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_civoid __init ls1x_clk_init(void) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct clk_hw *hw; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); 458c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "osc_clk", NULL); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* clock derived from 33 MHz OSC clk */ 488c2ecf20Sopenharmony_ci hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", 498c2ecf20Sopenharmony_ci &ls1x_pll_clk_ops, 0); 508c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "pll_clk", NULL); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* clock derived from PLL clk */ 538c2ecf20Sopenharmony_ci /* _____ 548c2ecf20Sopenharmony_ci * _______________________| | 558c2ecf20Sopenharmony_ci * OSC ___/ | MUX |___ CPU CLK 568c2ecf20Sopenharmony_ci * \___ PLL ___ CPU DIV ___| | 578c2ecf20Sopenharmony_ci * |_____| 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", 608c2ecf20Sopenharmony_ci CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, 618c2ecf20Sopenharmony_ci DIV_CPU_SHIFT, DIV_CPU_WIDTH, 628c2ecf20Sopenharmony_ci CLK_DIVIDER_ONE_BASED | 638c2ecf20Sopenharmony_ci CLK_DIVIDER_ROUND_CLOSEST, &_lock); 648c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); 658c2ecf20Sopenharmony_ci hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, 668c2ecf20Sopenharmony_ci ARRAY_SIZE(cpu_parents), 678c2ecf20Sopenharmony_ci CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, 688c2ecf20Sopenharmony_ci BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); 698c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "cpu_clk", NULL); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* _____ 728c2ecf20Sopenharmony_ci * _______________________| | 738c2ecf20Sopenharmony_ci * OSC ___/ | MUX |___ DC CLK 748c2ecf20Sopenharmony_ci * \___ PLL ___ DC DIV ___| | 758c2ecf20Sopenharmony_ci * |_____| 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", 788c2ecf20Sopenharmony_ci 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, 798c2ecf20Sopenharmony_ci DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); 808c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "dc_clk_div", NULL); 818c2ecf20Sopenharmony_ci hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, 828c2ecf20Sopenharmony_ci ARRAY_SIZE(dc_parents), 838c2ecf20Sopenharmony_ci CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, 848c2ecf20Sopenharmony_ci BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); 858c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "dc_clk", NULL); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* _____ 888c2ecf20Sopenharmony_ci * _______________________| | 898c2ecf20Sopenharmony_ci * OSC ___/ | MUX |___ DDR CLK 908c2ecf20Sopenharmony_ci * \___ PLL ___ DDR DIV ___| | 918c2ecf20Sopenharmony_ci * |_____| 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", 948c2ecf20Sopenharmony_ci 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, 958c2ecf20Sopenharmony_ci DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, 968c2ecf20Sopenharmony_ci &_lock); 978c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); 988c2ecf20Sopenharmony_ci hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, 998c2ecf20Sopenharmony_ci ARRAY_SIZE(ahb_parents), 1008c2ecf20Sopenharmony_ci CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, 1018c2ecf20Sopenharmony_ci BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); 1028c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ahb_clk", NULL); 1038c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ls1x-dma", NULL); 1048c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "stmmaceth", NULL); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* clock derived from AHB clk */ 1078c2ecf20Sopenharmony_ci /* APB clk is always half of the AHB clk */ 1088c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 1098c2ecf20Sopenharmony_ci DIV_APB); 1108c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "apb_clk", NULL); 1118c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); 1128c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); 1138c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ls1x-nand", NULL); 1148c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); 1158c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ls1x-spi", NULL); 1168c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); 1178c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "serial8250", NULL); 1188c2ecf20Sopenharmony_ci} 119