162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/sh/kernel/cpu/sh4a/clock-sh7366.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * SH7366 clock framework support 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2009 Magnus Damm 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/clkdev.h> 1362306a36Sopenharmony_ci#include <asm/clock.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* SH7366 registers */ 1662306a36Sopenharmony_ci#define FRQCR 0xa4150000 1762306a36Sopenharmony_ci#define VCLKCR 0xa4150004 1862306a36Sopenharmony_ci#define SCLKACR 0xa4150008 1962306a36Sopenharmony_ci#define SCLKBCR 0xa415000c 2062306a36Sopenharmony_ci#define PLLCR 0xa4150024 2162306a36Sopenharmony_ci#define MSTPCR0 0xa4150030 2262306a36Sopenharmony_ci#define MSTPCR1 0xa4150034 2362306a36Sopenharmony_ci#define MSTPCR2 0xa4150038 2462306a36Sopenharmony_ci#define DLLFRQ 0xa4150050 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Fixed 32 KHz root clock for RTC and Power Management purposes */ 2762306a36Sopenharmony_cistatic struct clk r_clk = { 2862306a36Sopenharmony_ci .rate = 32768, 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Default rate for the root input clock, reset this with clk_set_rate() 3362306a36Sopenharmony_ci * from the platform code. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cistruct clk extal_clk = { 3662306a36Sopenharmony_ci .rate = 33333333, 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* The dll block multiplies the 32khz r_clk, may be used instead of extal */ 4062306a36Sopenharmony_cistatic unsigned long dll_recalc(struct clk *clk) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci unsigned long mult; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (__raw_readl(PLLCR) & 0x1000) 4562306a36Sopenharmony_ci mult = __raw_readl(DLLFRQ); 4662306a36Sopenharmony_ci else 4762306a36Sopenharmony_ci mult = 0; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return clk->parent->rate * mult; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic struct sh_clk_ops dll_clk_ops = { 5362306a36Sopenharmony_ci .recalc = dll_recalc, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic struct clk dll_clk = { 5762306a36Sopenharmony_ci .ops = &dll_clk_ops, 5862306a36Sopenharmony_ci .parent = &r_clk, 5962306a36Sopenharmony_ci .flags = CLK_ENABLE_ON_INIT, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic unsigned long pll_recalc(struct clk *clk) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci unsigned long mult = 1; 6562306a36Sopenharmony_ci unsigned long div = 1; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (__raw_readl(PLLCR) & 0x4000) 6862306a36Sopenharmony_ci mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1); 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci div = 2; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return (clk->parent->rate * mult) / div; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic struct sh_clk_ops pll_clk_ops = { 7662306a36Sopenharmony_ci .recalc = pll_recalc, 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic struct clk pll_clk = { 8062306a36Sopenharmony_ci .ops = &pll_clk_ops, 8162306a36Sopenharmony_ci .flags = CLK_ENABLE_ON_INIT, 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistruct clk *main_clks[] = { 8562306a36Sopenharmony_ci &r_clk, 8662306a36Sopenharmony_ci &extal_clk, 8762306a36Sopenharmony_ci &dll_clk, 8862306a36Sopenharmony_ci &pll_clk, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 9262306a36Sopenharmony_cistatic int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 }; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic struct clk_div_mult_table div4_div_mult_table = { 9562306a36Sopenharmony_ci .divisors = divisors, 9662306a36Sopenharmony_ci .nr_divisors = ARRAY_SIZE(divisors), 9762306a36Sopenharmony_ci .multipliers = multipliers, 9862306a36Sopenharmony_ci .nr_multipliers = ARRAY_SIZE(multipliers), 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic struct clk_div4_table div4_table = { 10262306a36Sopenharmony_ci .div_mult_table = &div4_div_mult_table, 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cienum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, 10662306a36Sopenharmony_ci DIV4_SIUA, DIV4_SIUB, DIV4_NR }; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define DIV4(_reg, _bit, _mask, _flags) \ 10962306a36Sopenharmony_ci SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct clk div4_clks[DIV4_NR] = { 11262306a36Sopenharmony_ci [DIV4_I] = DIV4(FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT), 11362306a36Sopenharmony_ci [DIV4_U] = DIV4(FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT), 11462306a36Sopenharmony_ci [DIV4_SH] = DIV4(FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT), 11562306a36Sopenharmony_ci [DIV4_B] = DIV4(FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT), 11662306a36Sopenharmony_ci [DIV4_B3] = DIV4(FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT), 11762306a36Sopenharmony_ci [DIV4_P] = DIV4(FRQCR, 0, 0x1fff, 0), 11862306a36Sopenharmony_ci [DIV4_SIUA] = DIV4(SCLKACR, 0, 0x1fff, 0), 11962306a36Sopenharmony_ci [DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x1fff, 0), 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cienum { DIV6_V, DIV6_NR }; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct clk div6_clks[DIV6_NR] = { 12562306a36Sopenharmony_ci [DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0), 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#define MSTP(_parent, _reg, _bit, _flags) \ 12962306a36Sopenharmony_ci SH_CLK_MSTP32(_parent, _reg, _bit, _flags) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cienum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026, 13262306a36Sopenharmony_ci MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016, 13362306a36Sopenharmony_ci MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010, 13462306a36Sopenharmony_ci MSTP007, MSTP006, MSTP005, MSTP002, MSTP001, 13562306a36Sopenharmony_ci MSTP109, MSTP100, 13662306a36Sopenharmony_ci MSTP227, MSTP226, MSTP224, MSTP223, MSTP222, MSTP218, MSTP217, 13762306a36Sopenharmony_ci MSTP211, MSTP207, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, 13862306a36Sopenharmony_ci MSTP_NR }; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic struct clk mstp_clks[MSTP_NR] = { 14162306a36Sopenharmony_ci /* See page 52 of Datasheet V0.40: Overview -> Block Diagram */ 14262306a36Sopenharmony_ci [MSTP031] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT), 14362306a36Sopenharmony_ci [MSTP030] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT), 14462306a36Sopenharmony_ci [MSTP029] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT), 14562306a36Sopenharmony_ci [MSTP028] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT), 14662306a36Sopenharmony_ci [MSTP026] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT), 14762306a36Sopenharmony_ci [MSTP023] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 23, 0), 14862306a36Sopenharmony_ci [MSTP022] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 22, 0), 14962306a36Sopenharmony_ci [MSTP021] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 21, 0), 15062306a36Sopenharmony_ci [MSTP020] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 20, 0), 15162306a36Sopenharmony_ci [MSTP019] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0), 15262306a36Sopenharmony_ci [MSTP017] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 17, 0), 15362306a36Sopenharmony_ci [MSTP015] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0), 15462306a36Sopenharmony_ci [MSTP014] = MSTP(&r_clk, MSTPCR0, 14, 0), 15562306a36Sopenharmony_ci [MSTP013] = MSTP(&r_clk, MSTPCR0, 13, 0), 15662306a36Sopenharmony_ci [MSTP011] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 11, 0), 15762306a36Sopenharmony_ci [MSTP010] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0), 15862306a36Sopenharmony_ci [MSTP007] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0), 15962306a36Sopenharmony_ci [MSTP006] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 6, 0), 16062306a36Sopenharmony_ci [MSTP005] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 5, 0), 16162306a36Sopenharmony_ci [MSTP002] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 2, 0), 16262306a36Sopenharmony_ci [MSTP001] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 1, 0), 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci [MSTP109] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0), 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci [MSTP227] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 27, 0), 16762306a36Sopenharmony_ci [MSTP226] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 26, 0), 16862306a36Sopenharmony_ci [MSTP224] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0), 16962306a36Sopenharmony_ci [MSTP223] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 23, 0), 17062306a36Sopenharmony_ci [MSTP222] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 22, 0), 17162306a36Sopenharmony_ci [MSTP218] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 18, 0), 17262306a36Sopenharmony_ci [MSTP217] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 17, 0), 17362306a36Sopenharmony_ci [MSTP211] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 11, 0), 17462306a36Sopenharmony_ci [MSTP207] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT), 17562306a36Sopenharmony_ci [MSTP205] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0), 17662306a36Sopenharmony_ci [MSTP204] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0), 17762306a36Sopenharmony_ci [MSTP203] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0), 17862306a36Sopenharmony_ci [MSTP202] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT), 17962306a36Sopenharmony_ci [MSTP201] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT), 18062306a36Sopenharmony_ci [MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0), 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic struct clk_lookup lookups[] = { 18462306a36Sopenharmony_ci /* main clocks */ 18562306a36Sopenharmony_ci CLKDEV_CON_ID("rclk", &r_clk), 18662306a36Sopenharmony_ci CLKDEV_CON_ID("extal", &extal_clk), 18762306a36Sopenharmony_ci CLKDEV_CON_ID("dll_clk", &dll_clk), 18862306a36Sopenharmony_ci CLKDEV_CON_ID("pll_clk", &pll_clk), 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* DIV4 clocks */ 19162306a36Sopenharmony_ci CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), 19262306a36Sopenharmony_ci CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]), 19362306a36Sopenharmony_ci CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]), 19462306a36Sopenharmony_ci CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]), 19562306a36Sopenharmony_ci CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]), 19662306a36Sopenharmony_ci CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]), 19762306a36Sopenharmony_ci CLKDEV_CON_ID("siua_clk", &div4_clks[DIV4_SIUA]), 19862306a36Sopenharmony_ci CLKDEV_CON_ID("siub_clk", &div4_clks[DIV4_SIUB]), 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* DIV6 clocks */ 20162306a36Sopenharmony_ci CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]), 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* MSTP32 clocks */ 20462306a36Sopenharmony_ci CLKDEV_CON_ID("tlb0", &mstp_clks[MSTP031]), 20562306a36Sopenharmony_ci CLKDEV_CON_ID("ic0", &mstp_clks[MSTP030]), 20662306a36Sopenharmony_ci CLKDEV_CON_ID("oc0", &mstp_clks[MSTP029]), 20762306a36Sopenharmony_ci CLKDEV_CON_ID("rsmem0", &mstp_clks[MSTP028]), 20862306a36Sopenharmony_ci CLKDEV_CON_ID("xymem0", &mstp_clks[MSTP026]), 20962306a36Sopenharmony_ci CLKDEV_CON_ID("intc3", &mstp_clks[MSTP023]), 21062306a36Sopenharmony_ci CLKDEV_CON_ID("intc0", &mstp_clks[MSTP022]), 21162306a36Sopenharmony_ci CLKDEV_CON_ID("dmac0", &mstp_clks[MSTP021]), 21262306a36Sopenharmony_ci CLKDEV_CON_ID("sh0", &mstp_clks[MSTP020]), 21362306a36Sopenharmony_ci CLKDEV_CON_ID("hudi0", &mstp_clks[MSTP019]), 21462306a36Sopenharmony_ci CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP017]), 21562306a36Sopenharmony_ci CLKDEV_CON_ID("tmu_fck", &mstp_clks[MSTP015]), 21662306a36Sopenharmony_ci CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[MSTP014]), 21762306a36Sopenharmony_ci CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]), 21862306a36Sopenharmony_ci CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]), 21962306a36Sopenharmony_ci CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]), 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]), 22262306a36Sopenharmony_ci CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]), 22362306a36Sopenharmony_ci CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]), 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]), 22662306a36Sopenharmony_ci CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]), 22762306a36Sopenharmony_ci CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]), 22862306a36Sopenharmony_ci CLKDEV_CON_ID("icb0", &mstp_clks[MSTP227]), 22962306a36Sopenharmony_ci CLKDEV_CON_ID("meram0", &mstp_clks[MSTP226]), 23062306a36Sopenharmony_ci CLKDEV_CON_ID("dacy1", &mstp_clks[MSTP224]), 23162306a36Sopenharmony_ci CLKDEV_CON_ID("dacy0", &mstp_clks[MSTP223]), 23262306a36Sopenharmony_ci CLKDEV_CON_ID("tsif0", &mstp_clks[MSTP222]), 23362306a36Sopenharmony_ci CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]), 23462306a36Sopenharmony_ci CLKDEV_CON_ID("mmcif0", &mstp_clks[MSTP217]), 23562306a36Sopenharmony_ci CLKDEV_CON_ID("usbf0", &mstp_clks[MSTP211]), 23662306a36Sopenharmony_ci CLKDEV_CON_ID("veu1", &mstp_clks[MSTP207]), 23762306a36Sopenharmony_ci CLKDEV_CON_ID("vou0", &mstp_clks[MSTP205]), 23862306a36Sopenharmony_ci CLKDEV_CON_ID("beu0", &mstp_clks[MSTP204]), 23962306a36Sopenharmony_ci CLKDEV_CON_ID("ceu0", &mstp_clks[MSTP203]), 24062306a36Sopenharmony_ci CLKDEV_CON_ID("veu0", &mstp_clks[MSTP202]), 24162306a36Sopenharmony_ci CLKDEV_CON_ID("vpu0", &mstp_clks[MSTP201]), 24262306a36Sopenharmony_ci CLKDEV_CON_ID("lcdc0", &mstp_clks[MSTP200]), 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciint __init arch_clk_init(void) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci int k, ret = 0; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* autodetect extal or dll configuration */ 25062306a36Sopenharmony_ci if (__raw_readl(PLLCR) & 0x1000) 25162306a36Sopenharmony_ci pll_clk.parent = &dll_clk; 25262306a36Sopenharmony_ci else 25362306a36Sopenharmony_ci pll_clk.parent = &extal_clk; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) 25662306a36Sopenharmony_ci ret = clk_register(main_clks[k]); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (!ret) 26162306a36Sopenharmony_ci ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!ret) 26462306a36Sopenharmony_ci ret = sh_clk_div6_register(div6_clks, DIV6_NR); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!ret) 26762306a36Sopenharmony_ci ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return ret; 27062306a36Sopenharmony_ci} 271