14ed37394SMagnus Damm /* 24ed37394SMagnus Damm * arch/sh/kernel/cpu/sh4a/clock-sh7366.c 34ed37394SMagnus Damm * 44ed37394SMagnus Damm * SH7366 clock framework support 54ed37394SMagnus Damm * 64ed37394SMagnus Damm * Copyright (C) 2009 Magnus Damm 74ed37394SMagnus Damm * 84ed37394SMagnus Damm * This program is free software; you can redistribute it and/or modify 94ed37394SMagnus Damm * it under the terms of the GNU General Public License as published by 104ed37394SMagnus Damm * the Free Software Foundation; either version 2 of the License 114ed37394SMagnus Damm * 124ed37394SMagnus Damm * This program is distributed in the hope that it will be useful, 134ed37394SMagnus Damm * but WITHOUT ANY WARRANTY; without even the implied warranty of 144ed37394SMagnus Damm * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 154ed37394SMagnus Damm * GNU General Public License for more details. 164ed37394SMagnus Damm * 174ed37394SMagnus Damm * You should have received a copy of the GNU General Public License 184ed37394SMagnus Damm * along with this program; if not, write to the Free Software 194ed37394SMagnus Damm * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 204ed37394SMagnus Damm */ 214ed37394SMagnus Damm #include <linux/init.h> 224ed37394SMagnus Damm #include <linux/kernel.h> 234ed37394SMagnus Damm #include <linux/io.h> 24098ec49bSMagnus Damm #include <asm/clkdev.h> 254ed37394SMagnus Damm #include <asm/clock.h> 264ed37394SMagnus Damm 274ed37394SMagnus Damm /* SH7366 registers */ 284ed37394SMagnus Damm #define FRQCR 0xa4150000 294ed37394SMagnus Damm #define VCLKCR 0xa4150004 304ed37394SMagnus Damm #define SCLKACR 0xa4150008 314ed37394SMagnus Damm #define SCLKBCR 0xa415000c 324ed37394SMagnus Damm #define PLLCR 0xa4150024 334ed37394SMagnus Damm #define MSTPCR0 0xa4150030 344ed37394SMagnus Damm #define MSTPCR1 0xa4150034 354ed37394SMagnus Damm #define MSTPCR2 0xa4150038 364ed37394SMagnus Damm #define DLLFRQ 0xa4150050 374ed37394SMagnus Damm 384ed37394SMagnus Damm /* Fixed 32 KHz root clock for RTC and Power Management purposes */ 394ed37394SMagnus Damm static struct clk r_clk = { 404ed37394SMagnus Damm .name = "rclk", 414ed37394SMagnus Damm .id = -1, 424ed37394SMagnus Damm .rate = 32768, 434ed37394SMagnus Damm }; 444ed37394SMagnus Damm 454ed37394SMagnus Damm /* 464ed37394SMagnus Damm * Default rate for the root input clock, reset this with clk_set_rate() 474ed37394SMagnus Damm * from the platform code. 484ed37394SMagnus Damm */ 494ed37394SMagnus Damm struct clk extal_clk = { 504ed37394SMagnus Damm .name = "extal", 514ed37394SMagnus Damm .id = -1, 524ed37394SMagnus Damm .rate = 33333333, 534ed37394SMagnus Damm }; 544ed37394SMagnus Damm 554ed37394SMagnus Damm /* The dll block multiplies the 32khz r_clk, may be used instead of extal */ 564ed37394SMagnus Damm static unsigned long dll_recalc(struct clk *clk) 574ed37394SMagnus Damm { 584ed37394SMagnus Damm unsigned long mult; 594ed37394SMagnus Damm 604ed37394SMagnus Damm if (__raw_readl(PLLCR) & 0x1000) 614ed37394SMagnus Damm mult = __raw_readl(DLLFRQ); 624ed37394SMagnus Damm else 634ed37394SMagnus Damm mult = 0; 644ed37394SMagnus Damm 654ed37394SMagnus Damm return clk->parent->rate * mult; 664ed37394SMagnus Damm } 674ed37394SMagnus Damm 684ed37394SMagnus Damm static struct clk_ops dll_clk_ops = { 694ed37394SMagnus Damm .recalc = dll_recalc, 704ed37394SMagnus Damm }; 714ed37394SMagnus Damm 724ed37394SMagnus Damm static struct clk dll_clk = { 734ed37394SMagnus Damm .name = "dll_clk", 744ed37394SMagnus Damm .id = -1, 754ed37394SMagnus Damm .ops = &dll_clk_ops, 764ed37394SMagnus Damm .parent = &r_clk, 774ed37394SMagnus Damm .flags = CLK_ENABLE_ON_INIT, 784ed37394SMagnus Damm }; 794ed37394SMagnus Damm 804ed37394SMagnus Damm static unsigned long pll_recalc(struct clk *clk) 814ed37394SMagnus Damm { 824ed37394SMagnus Damm unsigned long mult = 1; 834ed37394SMagnus Damm unsigned long div = 1; 844ed37394SMagnus Damm 854ed37394SMagnus Damm if (__raw_readl(PLLCR) & 0x4000) 864ed37394SMagnus Damm mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1); 874ed37394SMagnus Damm else 884ed37394SMagnus Damm div = 2; 894ed37394SMagnus Damm 904ed37394SMagnus Damm return (clk->parent->rate * mult) / div; 914ed37394SMagnus Damm } 924ed37394SMagnus Damm 934ed37394SMagnus Damm static struct clk_ops pll_clk_ops = { 944ed37394SMagnus Damm .recalc = pll_recalc, 954ed37394SMagnus Damm }; 964ed37394SMagnus Damm 974ed37394SMagnus Damm static struct clk pll_clk = { 984ed37394SMagnus Damm .name = "pll_clk", 994ed37394SMagnus Damm .id = -1, 1004ed37394SMagnus Damm .ops = &pll_clk_ops, 1014ed37394SMagnus Damm .flags = CLK_ENABLE_ON_INIT, 1024ed37394SMagnus Damm }; 1034ed37394SMagnus Damm 1044ed37394SMagnus Damm struct clk *main_clks[] = { 1054ed37394SMagnus Damm &r_clk, 1064ed37394SMagnus Damm &extal_clk, 1074ed37394SMagnus Damm &dll_clk, 1084ed37394SMagnus Damm &pll_clk, 1094ed37394SMagnus Damm }; 1104ed37394SMagnus Damm 1114ed37394SMagnus Damm static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 1124ed37394SMagnus Damm static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 }; 1134ed37394SMagnus Damm 1140a5f337eSMagnus Damm static struct clk_div_mult_table div4_div_mult_table = { 1154ed37394SMagnus Damm .divisors = divisors, 1164ed37394SMagnus Damm .nr_divisors = ARRAY_SIZE(divisors), 1174ed37394SMagnus Damm .multipliers = multipliers, 1184ed37394SMagnus Damm .nr_multipliers = ARRAY_SIZE(multipliers), 1194ed37394SMagnus Damm }; 1204ed37394SMagnus Damm 1210a5f337eSMagnus Damm static struct clk_div4_table div4_table = { 1220a5f337eSMagnus Damm .div_mult_table = &div4_div_mult_table, 1230a5f337eSMagnus Damm }; 1240a5f337eSMagnus Damm 1254ed37394SMagnus Damm enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, 1264ed37394SMagnus Damm DIV4_SIUA, DIV4_SIUB, DIV4_NR }; 1274ed37394SMagnus Damm 1284ed37394SMagnus Damm #define DIV4(_str, _reg, _bit, _mask, _flags) \ 1294ed37394SMagnus Damm SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags) 1304ed37394SMagnus Damm 1314ed37394SMagnus Damm struct clk div4_clks[DIV4_NR] = { 1324ed37394SMagnus Damm [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT), 1334ed37394SMagnus Damm [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT), 1344ed37394SMagnus Damm [DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT), 1354ed37394SMagnus Damm [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT), 1364ed37394SMagnus Damm [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT), 1374ed37394SMagnus Damm [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0), 1384ed37394SMagnus Damm [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0), 1394ed37394SMagnus Damm [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0), 1404ed37394SMagnus Damm }; 1414ed37394SMagnus Damm 142098ec49bSMagnus Damm enum { DIV6_V, DIV6_NR }; 143098ec49bSMagnus Damm 144098ec49bSMagnus Damm struct clk div6_clks[DIV6_NR] = { 1459e1985e1SMagnus Damm [DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0), 1464ed37394SMagnus Damm }; 1474ed37394SMagnus Damm 1484ed37394SMagnus Damm #define MSTP(_str, _parent, _reg, _bit, _flags) \ 1494ed37394SMagnus Damm SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags) 1504ed37394SMagnus Damm 1514780683aSMagnus Damm enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026, 1524780683aSMagnus Damm MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016, 1534780683aSMagnus Damm MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010, 1544780683aSMagnus Damm MSTP007, MSTP006, MSTP005, MSTP002, MSTP001, 1554780683aSMagnus Damm MSTP109, MSTP100, 1564780683aSMagnus Damm MSTP227, MSTP226, MSTP224, MSTP223, MSTP222, MSTP218, MSTP217, 1574780683aSMagnus Damm MSTP211, MSTP207, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, 1584780683aSMagnus Damm MSTP_NR }; 1594780683aSMagnus Damm 1604780683aSMagnus Damm static struct clk mstp_clks[MSTP_NR] = { 1614ed37394SMagnus Damm /* See page 52 of Datasheet V0.40: Overview -> Block Diagram */ 1624780683aSMagnus Damm [MSTP031] = MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT), 1634780683aSMagnus Damm [MSTP030] = MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT), 1644780683aSMagnus Damm [MSTP029] = MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT), 1654780683aSMagnus Damm [MSTP028] = MSTP("rsmem0", &div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT), 1664780683aSMagnus Damm [MSTP026] = MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT), 1674780683aSMagnus Damm [MSTP023] = MSTP("intc3", &div4_clks[DIV4_P], MSTPCR0, 23, 0), 1684780683aSMagnus Damm [MSTP022] = MSTP("intc0", &div4_clks[DIV4_P], MSTPCR0, 22, 0), 1694780683aSMagnus Damm [MSTP021] = MSTP("dmac0", &div4_clks[DIV4_P], MSTPCR0, 21, 0), 1704780683aSMagnus Damm [MSTP020] = MSTP("sh0", &div4_clks[DIV4_P], MSTPCR0, 20, 0), 1714780683aSMagnus Damm [MSTP019] = MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0), 1724780683aSMagnus Damm [MSTP017] = MSTP("ubc0", &div4_clks[DIV4_P], MSTPCR0, 17, 0), 1734780683aSMagnus Damm [MSTP015] = MSTP("tmu_fck", &div4_clks[DIV4_P], MSTPCR0, 15, 0), 1744780683aSMagnus Damm [MSTP014] = MSTP("cmt_fck", &r_clk, MSTPCR0, 14, 0), 1754780683aSMagnus Damm [MSTP013] = MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0), 1764780683aSMagnus Damm [MSTP011] = MSTP("mfi0", &div4_clks[DIV4_P], MSTPCR0, 11, 0), 1774780683aSMagnus Damm [MSTP010] = MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0), 1784780683aSMagnus Damm [MSTP007] = SH_CLK_MSTP32("sci_fck", 0, &div4_clks[DIV4_P], MSTPCR0, 7, 0), 1794780683aSMagnus Damm [MSTP006] = SH_CLK_MSTP32("sci_fck", 1, &div4_clks[DIV4_P], MSTPCR0, 6, 0), 1804780683aSMagnus Damm [MSTP005] = SH_CLK_MSTP32("sci_fck", 2, &div4_clks[DIV4_P], MSTPCR0, 5, 0), 1814780683aSMagnus Damm [MSTP002] = MSTP("msiof0", &div4_clks[DIV4_P], MSTPCR0, 2, 0), 1824780683aSMagnus Damm [MSTP001] = MSTP("sbr0", &div4_clks[DIV4_P], MSTPCR0, 1, 0), 1834ed37394SMagnus Damm 1844780683aSMagnus Damm [MSTP109] = MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0), 1854ed37394SMagnus Damm 1864780683aSMagnus Damm [MSTP227] = MSTP("icb0", &div4_clks[DIV4_P], MSTPCR2, 27, 0), 1874780683aSMagnus Damm [MSTP226] = MSTP("meram0", &div4_clks[DIV4_P], MSTPCR2, 26, 0), 1884780683aSMagnus Damm [MSTP224] = MSTP("dacy1", &div4_clks[DIV4_P], MSTPCR2, 24, 0), 1894780683aSMagnus Damm [MSTP223] = MSTP("dacy0", &div4_clks[DIV4_P], MSTPCR2, 23, 0), 1904780683aSMagnus Damm [MSTP222] = MSTP("tsif0", &div4_clks[DIV4_P], MSTPCR2, 22, 0), 1914780683aSMagnus Damm [MSTP218] = MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0), 1924780683aSMagnus Damm [MSTP217] = MSTP("mmcif0", &div4_clks[DIV4_P], MSTPCR2, 17, 0), 1934780683aSMagnus Damm [MSTP211] = MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0), 1944780683aSMagnus Damm [MSTP207] = MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT), 1954780683aSMagnus Damm [MSTP205] = MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0), 1964780683aSMagnus Damm [MSTP204] = MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0), 1974780683aSMagnus Damm [MSTP203] = MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0), 1984780683aSMagnus Damm [MSTP202] = MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT), 1994780683aSMagnus Damm [MSTP201] = MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT), 2004780683aSMagnus Damm [MSTP200] = MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0), 2014ed37394SMagnus Damm }; 2024ed37394SMagnus Damm 203098ec49bSMagnus Damm #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } 204098ec49bSMagnus Damm 205098ec49bSMagnus Damm static struct clk_lookup lookups[] = { 206098ec49bSMagnus Damm /* DIV6 clocks */ 207098ec49bSMagnus Damm CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]), 208098ec49bSMagnus Damm }; 209098ec49bSMagnus Damm 2104ed37394SMagnus Damm int __init arch_clk_init(void) 2114ed37394SMagnus Damm { 2124ed37394SMagnus Damm int k, ret = 0; 2134ed37394SMagnus Damm 2144ed37394SMagnus Damm /* autodetect extal or dll configuration */ 2154ed37394SMagnus Damm if (__raw_readl(PLLCR) & 0x1000) 2164ed37394SMagnus Damm pll_clk.parent = &dll_clk; 2174ed37394SMagnus Damm else 2184ed37394SMagnus Damm pll_clk.parent = &extal_clk; 2194ed37394SMagnus Damm 2204ed37394SMagnus Damm for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) 2214ed37394SMagnus Damm ret = clk_register(main_clks[k]); 2224ed37394SMagnus Damm 223098ec49bSMagnus Damm clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 224098ec49bSMagnus Damm 2254ed37394SMagnus Damm if (!ret) 2264ed37394SMagnus Damm ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); 2274ed37394SMagnus Damm 2284ed37394SMagnus Damm if (!ret) 229098ec49bSMagnus Damm ret = sh_clk_div6_register(div6_clks, DIV6_NR); 2304ed37394SMagnus Damm 2314ed37394SMagnus Damm if (!ret) 2324780683aSMagnus Damm ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); 2334ed37394SMagnus Damm 2344ed37394SMagnus Damm return ret; 2354ed37394SMagnus Damm } 236