1c521dc02SMagnus Damm /* 2c521dc02SMagnus Damm * arch/sh/kernel/cpu/sh4a/clock-sh7723.c 3c521dc02SMagnus Damm * 4c521dc02SMagnus Damm * SH7723 clock framework support 5c521dc02SMagnus Damm * 6c521dc02SMagnus Damm * Copyright (C) 2009 Magnus Damm 7c521dc02SMagnus Damm * 8c521dc02SMagnus Damm * This program is free software; you can redistribute it and/or modify 9c521dc02SMagnus Damm * it under the terms of the GNU General Public License as published by 10c521dc02SMagnus Damm * the Free Software Foundation; either version 2 of the License 11c521dc02SMagnus Damm * 12c521dc02SMagnus Damm * This program is distributed in the hope that it will be useful, 13c521dc02SMagnus Damm * but WITHOUT ANY WARRANTY; without even the implied warranty of 14c521dc02SMagnus Damm * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15c521dc02SMagnus Damm * GNU General Public License for more details. 16c521dc02SMagnus Damm * 17c521dc02SMagnus Damm * You should have received a copy of the GNU General Public License 18c521dc02SMagnus Damm * along with this program; if not, write to the Free Software 19c521dc02SMagnus Damm * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20c521dc02SMagnus Damm */ 21c521dc02SMagnus Damm #include <linux/init.h> 22c521dc02SMagnus Damm #include <linux/kernel.h> 23c521dc02SMagnus Damm #include <linux/io.h> 24f4221802SPaul Mundt #include <linux/clk.h> 25f4221802SPaul Mundt #include <asm/clkdev.h> 26c521dc02SMagnus Damm #include <asm/clock.h> 272094e504SMagnus Damm #include <asm/hwblk.h> 282094e504SMagnus Damm #include <cpu/sh7723.h> 29c521dc02SMagnus Damm 30c521dc02SMagnus Damm /* SH7723 registers */ 31c521dc02SMagnus Damm #define FRQCR 0xa4150000 32c521dc02SMagnus Damm #define VCLKCR 0xa4150004 33c521dc02SMagnus Damm #define SCLKACR 0xa4150008 34c521dc02SMagnus Damm #define SCLKBCR 0xa415000c 35c521dc02SMagnus Damm #define IRDACLKCR 0xa4150018 36c521dc02SMagnus Damm #define PLLCR 0xa4150024 37c521dc02SMagnus Damm #define DLLFRQ 0xa4150050 38c521dc02SMagnus Damm 39c521dc02SMagnus Damm /* Fixed 32 KHz root clock for RTC and Power Management purposes */ 40c521dc02SMagnus Damm static struct clk r_clk = { 41c521dc02SMagnus Damm .name = "rclk", 42c521dc02SMagnus Damm .id = -1, 43c521dc02SMagnus Damm .rate = 32768, 44c521dc02SMagnus Damm }; 45c521dc02SMagnus Damm 46c521dc02SMagnus Damm /* 47c521dc02SMagnus Damm * Default rate for the root input clock, reset this with clk_set_rate() 48c521dc02SMagnus Damm * from the platform code. 49c521dc02SMagnus Damm */ 50c521dc02SMagnus Damm struct clk extal_clk = { 51c521dc02SMagnus Damm .name = "extal", 52c521dc02SMagnus Damm .id = -1, 53c521dc02SMagnus Damm .rate = 33333333, 54c521dc02SMagnus Damm }; 55c521dc02SMagnus Damm 56c521dc02SMagnus Damm /* The dll multiplies the 32khz r_clk, may be used instead of extal */ 57c521dc02SMagnus Damm static unsigned long dll_recalc(struct clk *clk) 58c521dc02SMagnus Damm { 59c521dc02SMagnus Damm unsigned long mult; 60c521dc02SMagnus Damm 61c521dc02SMagnus Damm if (__raw_readl(PLLCR) & 0x1000) 62c521dc02SMagnus Damm mult = __raw_readl(DLLFRQ); 63c521dc02SMagnus Damm else 64c521dc02SMagnus Damm mult = 0; 65c521dc02SMagnus Damm 66c521dc02SMagnus Damm return clk->parent->rate * mult; 67c521dc02SMagnus Damm } 68c521dc02SMagnus Damm 69c521dc02SMagnus Damm static struct clk_ops dll_clk_ops = { 70c521dc02SMagnus Damm .recalc = dll_recalc, 71c521dc02SMagnus Damm }; 72c521dc02SMagnus Damm 73c521dc02SMagnus Damm static struct clk dll_clk = { 74c521dc02SMagnus Damm .name = "dll_clk", 75c521dc02SMagnus Damm .id = -1, 76c521dc02SMagnus Damm .ops = &dll_clk_ops, 77c521dc02SMagnus Damm .parent = &r_clk, 78c521dc02SMagnus Damm .flags = CLK_ENABLE_ON_INIT, 79c521dc02SMagnus Damm }; 80c521dc02SMagnus Damm 81c521dc02SMagnus Damm static unsigned long pll_recalc(struct clk *clk) 82c521dc02SMagnus Damm { 83c521dc02SMagnus Damm unsigned long mult = 1; 84c521dc02SMagnus Damm unsigned long div = 1; 85c521dc02SMagnus Damm 86c521dc02SMagnus Damm if (__raw_readl(PLLCR) & 0x4000) 87c521dc02SMagnus Damm mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1); 88c521dc02SMagnus Damm else 89c521dc02SMagnus Damm div = 2; 90c521dc02SMagnus Damm 91c521dc02SMagnus Damm return (clk->parent->rate * mult) / div; 92c521dc02SMagnus Damm } 93c521dc02SMagnus Damm 94c521dc02SMagnus Damm static struct clk_ops pll_clk_ops = { 95c521dc02SMagnus Damm .recalc = pll_recalc, 96c521dc02SMagnus Damm }; 97c521dc02SMagnus Damm 98c521dc02SMagnus Damm static struct clk pll_clk = { 99c521dc02SMagnus Damm .name = "pll_clk", 100c521dc02SMagnus Damm .id = -1, 101c521dc02SMagnus Damm .ops = &pll_clk_ops, 102c521dc02SMagnus Damm .flags = CLK_ENABLE_ON_INIT, 103c521dc02SMagnus Damm }; 104c521dc02SMagnus Damm 105c521dc02SMagnus Damm struct clk *main_clks[] = { 106c521dc02SMagnus Damm &r_clk, 107c521dc02SMagnus Damm &extal_clk, 108c521dc02SMagnus Damm &dll_clk, 109c521dc02SMagnus Damm &pll_clk, 110c521dc02SMagnus Damm }; 111c521dc02SMagnus Damm 112c521dc02SMagnus Damm static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 113c521dc02SMagnus Damm static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 }; 114c521dc02SMagnus Damm 1150a5f337eSMagnus Damm static struct clk_div_mult_table div4_div_mult_table = { 116c521dc02SMagnus Damm .divisors = divisors, 117c521dc02SMagnus Damm .nr_divisors = ARRAY_SIZE(divisors), 118c521dc02SMagnus Damm .multipliers = multipliers, 119c521dc02SMagnus Damm .nr_multipliers = ARRAY_SIZE(multipliers), 120c521dc02SMagnus Damm }; 121c521dc02SMagnus Damm 1220a5f337eSMagnus Damm static struct clk_div4_table div4_table = { 1230a5f337eSMagnus Damm .div_mult_table = &div4_div_mult_table, 1240a5f337eSMagnus Damm }; 1250a5f337eSMagnus Damm 126801cd56eSMagnus Damm enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, DIV4_NR }; 127c521dc02SMagnus Damm 128c521dc02SMagnus Damm #define DIV4(_str, _reg, _bit, _mask, _flags) \ 129c521dc02SMagnus Damm SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags) 130c521dc02SMagnus Damm 131c521dc02SMagnus Damm struct clk div4_clks[DIV4_NR] = { 132c521dc02SMagnus Damm [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x0dbf, CLK_ENABLE_ON_INIT), 133c521dc02SMagnus Damm [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x0dbf, CLK_ENABLE_ON_INIT), 134c521dc02SMagnus Damm [DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x0dbf, CLK_ENABLE_ON_INIT), 135c521dc02SMagnus Damm [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x0dbf, CLK_ENABLE_ON_INIT), 136c521dc02SMagnus Damm [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x0db4, CLK_ENABLE_ON_INIT), 137c521dc02SMagnus Damm [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x0dbf, 0), 138801cd56eSMagnus Damm }; 139801cd56eSMagnus Damm 140801cd56eSMagnus Damm enum { DIV4_IRDA, DIV4_ENABLE_NR }; 141801cd56eSMagnus Damm 142801cd56eSMagnus Damm struct clk div4_enable_clks[DIV4_ENABLE_NR] = { 143c521dc02SMagnus Damm [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x0dbf, 0), 144c521dc02SMagnus Damm }; 145c521dc02SMagnus Damm 146801cd56eSMagnus Damm enum { DIV4_SIUA, DIV4_SIUB, DIV4_REPARENT_NR }; 147801cd56eSMagnus Damm 148801cd56eSMagnus Damm struct clk div4_reparent_clks[DIV4_REPARENT_NR] = { 149801cd56eSMagnus Damm [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x0dbf, 0), 150801cd56eSMagnus Damm [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x0dbf, 0), 151801cd56eSMagnus Damm }; 152c521dc02SMagnus Damm struct clk div6_clks[] = { 153c521dc02SMagnus Damm SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0), 154c521dc02SMagnus Damm }; 155c521dc02SMagnus Damm 1562094e504SMagnus Damm #define R_CLK (&r_clk) 1572094e504SMagnus Damm #define P_CLK (&div4_clks[DIV4_P]) 1582094e504SMagnus Damm #define B_CLK (&div4_clks[DIV4_B]) 1592094e504SMagnus Damm #define U_CLK (&div4_clks[DIV4_U]) 1602094e504SMagnus Damm #define I_CLK (&div4_clks[DIV4_I]) 1612094e504SMagnus Damm #define SH_CLK (&div4_clks[DIV4_SH]) 162c521dc02SMagnus Damm 163c521dc02SMagnus Damm static struct clk mstp_clks[] = { 164c521dc02SMagnus Damm /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */ 1652094e504SMagnus Damm SH_HWBLK_CLK("tlb0", -1, I_CLK, HWBLK_TLB, CLK_ENABLE_ON_INIT), 1662094e504SMagnus Damm SH_HWBLK_CLK("ic0", -1, I_CLK, HWBLK_IC, CLK_ENABLE_ON_INIT), 1672094e504SMagnus Damm SH_HWBLK_CLK("oc0", -1, I_CLK, HWBLK_OC, CLK_ENABLE_ON_INIT), 1682094e504SMagnus Damm SH_HWBLK_CLK("l2c0", -1, SH_CLK, HWBLK_L2C, CLK_ENABLE_ON_INIT), 1692094e504SMagnus Damm SH_HWBLK_CLK("ilmem0", -1, I_CLK, HWBLK_ILMEM, CLK_ENABLE_ON_INIT), 1702094e504SMagnus Damm SH_HWBLK_CLK("fpu0", -1, I_CLK, HWBLK_FPU, CLK_ENABLE_ON_INIT), 1712094e504SMagnus Damm SH_HWBLK_CLK("intc0", -1, I_CLK, HWBLK_INTC, CLK_ENABLE_ON_INIT), 1722094e504SMagnus Damm SH_HWBLK_CLK("dmac0", -1, B_CLK, HWBLK_DMAC0, 0), 1732094e504SMagnus Damm SH_HWBLK_CLK("sh0", -1, SH_CLK, HWBLK_SHYWAY, CLK_ENABLE_ON_INIT), 1742094e504SMagnus Damm SH_HWBLK_CLK("hudi0", -1, P_CLK, HWBLK_HUDI, 0), 1752094e504SMagnus Damm SH_HWBLK_CLK("ubc0", -1, I_CLK, HWBLK_UBC, 0), 176f4221802SPaul Mundt SH_HWBLK_CLK("tmu012_fck", -1, P_CLK, HWBLK_TMU0, 0), 177f4221802SPaul Mundt SH_HWBLK_CLK("cmt_fck", -1, R_CLK, HWBLK_CMT, 0), 1782094e504SMagnus Damm SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0), 1792094e504SMagnus Damm SH_HWBLK_CLK("dmac1", -1, B_CLK, HWBLK_DMAC1, 0), 180f4221802SPaul Mundt SH_HWBLK_CLK("tmu345_fck", -1, P_CLK, HWBLK_TMU1, 0), 1812094e504SMagnus Damm SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0), 182*e4e06697SMagnus Damm SH_HWBLK_CLK("sci_fck", -1, P_CLK, HWBLK_SCIF0, 0), 183*e4e06697SMagnus Damm SH_HWBLK_CLK("sci_fck", -1, P_CLK, HWBLK_SCIF1, 0), 184*e4e06697SMagnus Damm SH_HWBLK_CLK("sci_fck", -1, P_CLK, HWBLK_SCIF2, 0), 185*e4e06697SMagnus Damm SH_HWBLK_CLK("sci_fck", -1, B_CLK, HWBLK_SCIF3, 0), 186*e4e06697SMagnus Damm SH_HWBLK_CLK("sci_fck", -1, B_CLK, HWBLK_SCIF4, 0), 187*e4e06697SMagnus Damm SH_HWBLK_CLK("sci_fck", -1, B_CLK, HWBLK_SCIF5, 0), 1882094e504SMagnus Damm SH_HWBLK_CLK("msiof0", -1, B_CLK, HWBLK_MSIOF0, 0), 1892094e504SMagnus Damm SH_HWBLK_CLK("msiof1", -1, B_CLK, HWBLK_MSIOF1, 0), 1902094e504SMagnus Damm SH_HWBLK_CLK("meram0", -1, SH_CLK, HWBLK_MERAM, 0), 191c521dc02SMagnus Damm 1922094e504SMagnus Damm SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0), 1932094e504SMagnus Damm SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0), 194c521dc02SMagnus Damm 1952094e504SMagnus Damm SH_HWBLK_CLK("atapi0", -1, SH_CLK, HWBLK_ATAPI, 0), 1962094e504SMagnus Damm SH_HWBLK_CLK("adc0", -1, P_CLK, HWBLK_ADC, 0), 1972094e504SMagnus Damm SH_HWBLK_CLK("tpu0", -1, B_CLK, HWBLK_TPU, 0), 1982094e504SMagnus Damm SH_HWBLK_CLK("irda0", -1, P_CLK, HWBLK_IRDA, 0), 1992094e504SMagnus Damm SH_HWBLK_CLK("tsif0", -1, B_CLK, HWBLK_TSIF, 0), 2002094e504SMagnus Damm SH_HWBLK_CLK("icb0", -1, B_CLK, HWBLK_ICB, CLK_ENABLE_ON_INIT), 2012094e504SMagnus Damm SH_HWBLK_CLK("sdhi0", -1, B_CLK, HWBLK_SDHI0, 0), 2022094e504SMagnus Damm SH_HWBLK_CLK("sdhi1", -1, B_CLK, HWBLK_SDHI1, 0), 2032094e504SMagnus Damm SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0), 2042094e504SMagnus Damm SH_HWBLK_CLK("usb0", -1, B_CLK, HWBLK_USB, 0), 2052094e504SMagnus Damm SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0), 2062094e504SMagnus Damm SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0), 207cc58f597SMagnus Damm SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU2H1, 0), 2082094e504SMagnus Damm SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0), 2092094e504SMagnus Damm SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0), 2102094e504SMagnus Damm SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0), 211cc58f597SMagnus Damm SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU2H0, 0), 212cc58f597SMagnus Damm SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, 0), 2132094e504SMagnus Damm SH_HWBLK_CLK("lcdc0", -1, B_CLK, HWBLK_LCDC, 0), 214c521dc02SMagnus Damm }; 215c521dc02SMagnus Damm 216f4221802SPaul Mundt static struct clk_lookup lookups[] = { 217f4221802SPaul Mundt { 218f4221802SPaul Mundt /* TMU0 */ 219f4221802SPaul Mundt .dev_id = "sh_tmu.0", 220f4221802SPaul Mundt .con_id = "tmu_fck", 221f3d51e13SMagnus Damm .clk = &mstp_clks[HWBLK_TMU0], 222f4221802SPaul Mundt }, { 223f4221802SPaul Mundt /* TMU1 */ 224f4221802SPaul Mundt .dev_id = "sh_tmu.1", 225f4221802SPaul Mundt .con_id = "tmu_fck", 226f3d51e13SMagnus Damm .clk = &mstp_clks[HWBLK_TMU0], 227f4221802SPaul Mundt }, { 228f4221802SPaul Mundt /* TMU2 */ 229f4221802SPaul Mundt .dev_id = "sh_tmu.2", 230f4221802SPaul Mundt .con_id = "tmu_fck", 231f3d51e13SMagnus Damm .clk = &mstp_clks[HWBLK_TMU0], 232f4221802SPaul Mundt }, { 233f4221802SPaul Mundt /* TMU3 */ 234f4221802SPaul Mundt .dev_id = "sh_tmu.3", 235f4221802SPaul Mundt .con_id = "tmu_fck", 236f3d51e13SMagnus Damm .clk = &mstp_clks[HWBLK_TMU1], 237f4221802SPaul Mundt }, { 238f4221802SPaul Mundt /* TMU4 */ 239f4221802SPaul Mundt .dev_id = "sh_tmu.4", 240f4221802SPaul Mundt .con_id = "tmu_fck", 241f3d51e13SMagnus Damm .clk = &mstp_clks[HWBLK_TMU1], 242f4221802SPaul Mundt }, { 243f4221802SPaul Mundt /* TMU5 */ 244f4221802SPaul Mundt .dev_id = "sh_tmu.5", 245f4221802SPaul Mundt .con_id = "tmu_fck", 246f3d51e13SMagnus Damm .clk = &mstp_clks[HWBLK_TMU1], 247*e4e06697SMagnus Damm }, { 248*e4e06697SMagnus Damm /* SCIF0 */ 249*e4e06697SMagnus Damm .dev_id = "sh-sci.0", 250*e4e06697SMagnus Damm .con_id = "sci_fck", 251*e4e06697SMagnus Damm .clk = &mstp_clks[HWBLK_SCIF0], 252*e4e06697SMagnus Damm }, { 253*e4e06697SMagnus Damm /* SCIF1 */ 254*e4e06697SMagnus Damm .dev_id = "sh-sci.1", 255*e4e06697SMagnus Damm .con_id = "sci_fck", 256*e4e06697SMagnus Damm .clk = &mstp_clks[HWBLK_SCIF1], 257*e4e06697SMagnus Damm }, { 258*e4e06697SMagnus Damm /* SCIF2 */ 259*e4e06697SMagnus Damm .dev_id = "sh-sci.2", 260*e4e06697SMagnus Damm .con_id = "sci_fck", 261*e4e06697SMagnus Damm .clk = &mstp_clks[HWBLK_SCIF2], 262*e4e06697SMagnus Damm }, { 263*e4e06697SMagnus Damm /* SCIF3 */ 264*e4e06697SMagnus Damm .dev_id = "sh-sci.3", 265*e4e06697SMagnus Damm .con_id = "sci_fck", 266*e4e06697SMagnus Damm .clk = &mstp_clks[HWBLK_SCIF3], 267*e4e06697SMagnus Damm }, { 268*e4e06697SMagnus Damm /* SCIF4 */ 269*e4e06697SMagnus Damm .dev_id = "sh-sci.4", 270*e4e06697SMagnus Damm .con_id = "sci_fck", 271*e4e06697SMagnus Damm .clk = &mstp_clks[HWBLK_SCIF4], 272*e4e06697SMagnus Damm }, { 273*e4e06697SMagnus Damm /* SCIF5 */ 274*e4e06697SMagnus Damm .dev_id = "sh-sci.5", 275*e4e06697SMagnus Damm .con_id = "sci_fck", 276*e4e06697SMagnus Damm .clk = &mstp_clks[HWBLK_SCIF5], 277f4221802SPaul Mundt }, 278f4221802SPaul Mundt }; 279f4221802SPaul Mundt 280c521dc02SMagnus Damm int __init arch_clk_init(void) 281c521dc02SMagnus Damm { 282c521dc02SMagnus Damm int k, ret = 0; 283c521dc02SMagnus Damm 284c521dc02SMagnus Damm /* autodetect extal or dll configuration */ 285c521dc02SMagnus Damm if (__raw_readl(PLLCR) & 0x1000) 286c521dc02SMagnus Damm pll_clk.parent = &dll_clk; 287c521dc02SMagnus Damm else 288c521dc02SMagnus Damm pll_clk.parent = &extal_clk; 289c521dc02SMagnus Damm 290c521dc02SMagnus Damm for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) 291f4221802SPaul Mundt ret |= clk_register(main_clks[k]); 292f4221802SPaul Mundt 293f4221802SPaul Mundt clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 294c521dc02SMagnus Damm 295c521dc02SMagnus Damm if (!ret) 296c521dc02SMagnus Damm ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); 297c521dc02SMagnus Damm 298c521dc02SMagnus Damm if (!ret) 299801cd56eSMagnus Damm ret = sh_clk_div4_enable_register(div4_enable_clks, 300801cd56eSMagnus Damm DIV4_ENABLE_NR, &div4_table); 301801cd56eSMagnus Damm 302801cd56eSMagnus Damm if (!ret) 303801cd56eSMagnus Damm ret = sh_clk_div4_reparent_register(div4_reparent_clks, 304801cd56eSMagnus Damm DIV4_REPARENT_NR, &div4_table); 305801cd56eSMagnus Damm 306801cd56eSMagnus Damm if (!ret) 307c521dc02SMagnus Damm ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); 308c521dc02SMagnus Damm 309c521dc02SMagnus Damm if (!ret) 310f3d51e13SMagnus Damm ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR); 311c521dc02SMagnus Damm 312c521dc02SMagnus Damm return ret; 313c521dc02SMagnus Damm } 314