Path: blob/master/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
17525 views
/*1* arch/sh/kernel/cpu/sh4a/clock-sh7724.c2*3* SH7724 clock framework support4*5* Copyright (C) 2009 Magnus Damm6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License as published by9* the Free Software Foundation; either version 2 of the License10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA19*/20#include <linux/init.h>21#include <linux/kernel.h>22#include <linux/io.h>23#include <linux/clk.h>24#include <linux/clkdev.h>25#include <asm/clock.h>26#include <asm/hwblk.h>27#include <cpu/sh7724.h>2829/* SH7724 registers */30#define FRQCRA 0xa415000031#define FRQCRB 0xa415000432#define VCLKCR 0xa415004833#define FCLKACR 0xa415000834#define FCLKBCR 0xa415000c35#define IRDACLKCR 0xa415001836#define PLLCR 0xa415002437#define SPUCLKCR 0xa415003c38#define FLLFRQ 0xa415005039#define LSTATS 0xa41500604041/* Fixed 32 KHz root clock for RTC and Power Management purposes */42static struct clk r_clk = {43.rate = 32768,44};4546/*47* Default rate for the root input clock, reset this with clk_set_rate()48* from the platform code.49*/50static struct clk extal_clk = {51.rate = 33333333,52};5354/* The fll multiplies the 32khz r_clk, may be used instead of extal */55static unsigned long fll_recalc(struct clk *clk)56{57unsigned long mult = 0;58unsigned long div = 1;5960if (__raw_readl(PLLCR) & 0x1000)61mult = __raw_readl(FLLFRQ) & 0x3ff;6263if (__raw_readl(FLLFRQ) & 0x4000)64div = 2;6566return (clk->parent->rate * mult) / div;67}6869static struct clk_ops fll_clk_ops = {70.recalc = fll_recalc,71};7273static struct clk fll_clk = {74.ops = &fll_clk_ops,75.parent = &r_clk,76.flags = CLK_ENABLE_ON_INIT,77};7879static unsigned long pll_recalc(struct clk *clk)80{81unsigned long mult = 1;8283if (__raw_readl(PLLCR) & 0x4000)84mult = (((__raw_readl(FRQCRA) >> 24) & 0x3f) + 1) * 2;8586return clk->parent->rate * mult;87}8889static struct clk_ops pll_clk_ops = {90.recalc = pll_recalc,91};9293static struct clk pll_clk = {94.ops = &pll_clk_ops,95.flags = CLK_ENABLE_ON_INIT,96};9798/* A fixed divide-by-3 block use by the div6 clocks */99static unsigned long div3_recalc(struct clk *clk)100{101return clk->parent->rate / 3;102}103104static struct clk_ops div3_clk_ops = {105.recalc = div3_recalc,106};107108static struct clk div3_clk = {109.ops = &div3_clk_ops,110.parent = &pll_clk,111};112113/* External input clock (pin name: FSIMCKA/FSIMCKB ) */114struct clk sh7724_fsimcka_clk = {115};116117struct clk sh7724_fsimckb_clk = {118};119120static struct clk *main_clks[] = {121&r_clk,122&extal_clk,123&fll_clk,124&pll_clk,125&div3_clk,126&sh7724_fsimcka_clk,127&sh7724_fsimckb_clk,128};129130static void div4_kick(struct clk *clk)131{132unsigned long value;133134/* set KICK bit in FRQCRA to update hardware setting */135value = __raw_readl(FRQCRA);136value |= (1 << 31);137__raw_writel(value, FRQCRA);138}139140static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 0, 24, 32, 36, 48, 0, 72 };141142static struct clk_div_mult_table div4_div_mult_table = {143.divisors = divisors,144.nr_divisors = ARRAY_SIZE(divisors),145};146147static struct clk_div4_table div4_table = {148.div_mult_table = &div4_div_mult_table,149.kick = div4_kick,150};151152enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_P, DIV4_M1, DIV4_NR };153154#define DIV4(_reg, _bit, _mask, _flags) \155SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)156157struct clk div4_clks[DIV4_NR] = {158[DIV4_I] = DIV4(FRQCRA, 20, 0x2f7d, CLK_ENABLE_ON_INIT),159[DIV4_SH] = DIV4(FRQCRA, 12, 0x2f7c, CLK_ENABLE_ON_INIT),160[DIV4_B] = DIV4(FRQCRA, 8, 0x2f7c, CLK_ENABLE_ON_INIT),161[DIV4_P] = DIV4(FRQCRA, 0, 0x2f7c, 0),162[DIV4_M1] = DIV4(FRQCRB, 4, 0x2f7c, CLK_ENABLE_ON_INIT),163};164165enum { DIV6_V, DIV6_I, DIV6_S, DIV6_NR };166167static struct clk div6_clks[DIV6_NR] = {168[DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),169[DIV6_I] = SH_CLK_DIV6(&div3_clk, IRDACLKCR, 0),170[DIV6_S] = SH_CLK_DIV6(&div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),171};172173enum { DIV6_FA, DIV6_FB, DIV6_REPARENT_NR };174175/* Indices are important - they are the actual src selecting values */176static struct clk *fclkacr_parent[] = {177[0] = &div3_clk,178[1] = NULL,179[2] = &sh7724_fsimcka_clk,180[3] = NULL,181};182183static struct clk *fclkbcr_parent[] = {184[0] = &div3_clk,185[1] = NULL,186[2] = &sh7724_fsimckb_clk,187[3] = NULL,188};189190static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {191[DIV6_FA] = SH_CLK_DIV6_EXT(&div3_clk, FCLKACR, 0,192fclkacr_parent, ARRAY_SIZE(fclkacr_parent), 6, 2),193[DIV6_FB] = SH_CLK_DIV6_EXT(&div3_clk, FCLKBCR, 0,194fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),195};196197static struct clk mstp_clks[HWBLK_NR] = {198SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),199SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),200SH_HWBLK_CLK(HWBLK_OC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),201SH_HWBLK_CLK(HWBLK_RSMEM, &div4_clks[DIV4_B], CLK_ENABLE_ON_INIT),202SH_HWBLK_CLK(HWBLK_ILMEM, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),203SH_HWBLK_CLK(HWBLK_L2C, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),204SH_HWBLK_CLK(HWBLK_FPU, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),205SH_HWBLK_CLK(HWBLK_INTC, &div4_clks[DIV4_P], CLK_ENABLE_ON_INIT),206SH_HWBLK_CLK(HWBLK_DMAC0, &div4_clks[DIV4_B], 0),207SH_HWBLK_CLK(HWBLK_SHYWAY, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),208SH_HWBLK_CLK(HWBLK_HUDI, &div4_clks[DIV4_P], 0),209SH_HWBLK_CLK(HWBLK_UBC, &div4_clks[DIV4_I], 0),210SH_HWBLK_CLK(HWBLK_TMU0, &div4_clks[DIV4_P], 0),211SH_HWBLK_CLK(HWBLK_CMT, &r_clk, 0),212SH_HWBLK_CLK(HWBLK_RWDT, &r_clk, 0),213SH_HWBLK_CLK(HWBLK_DMAC1, &div4_clks[DIV4_B], 0),214SH_HWBLK_CLK(HWBLK_TMU1, &div4_clks[DIV4_P], 0),215SH_HWBLK_CLK(HWBLK_SCIF0, &div4_clks[DIV4_P], 0),216SH_HWBLK_CLK(HWBLK_SCIF1, &div4_clks[DIV4_P], 0),217SH_HWBLK_CLK(HWBLK_SCIF2, &div4_clks[DIV4_P], 0),218SH_HWBLK_CLK(HWBLK_SCIF3, &div4_clks[DIV4_B], 0),219SH_HWBLK_CLK(HWBLK_SCIF4, &div4_clks[DIV4_B], 0),220SH_HWBLK_CLK(HWBLK_SCIF5, &div4_clks[DIV4_B], 0),221SH_HWBLK_CLK(HWBLK_MSIOF0, &div4_clks[DIV4_B], 0),222SH_HWBLK_CLK(HWBLK_MSIOF1, &div4_clks[DIV4_B], 0),223224SH_HWBLK_CLK(HWBLK_KEYSC, &r_clk, 0),225SH_HWBLK_CLK(HWBLK_RTC, &r_clk, 0),226SH_HWBLK_CLK(HWBLK_IIC0, &div4_clks[DIV4_P], 0),227SH_HWBLK_CLK(HWBLK_IIC1, &div4_clks[DIV4_P], 0),228229SH_HWBLK_CLK(HWBLK_MMC, &div4_clks[DIV4_B], 0),230SH_HWBLK_CLK(HWBLK_ETHER, &div4_clks[DIV4_B], 0),231SH_HWBLK_CLK(HWBLK_ATAPI, &div4_clks[DIV4_B], 0),232SH_HWBLK_CLK(HWBLK_TPU, &div4_clks[DIV4_B], 0),233SH_HWBLK_CLK(HWBLK_IRDA, &div4_clks[DIV4_P], 0),234SH_HWBLK_CLK(HWBLK_TSIF, &div4_clks[DIV4_B], 0),235SH_HWBLK_CLK(HWBLK_USB1, &div4_clks[DIV4_B], 0),236SH_HWBLK_CLK(HWBLK_USB0, &div4_clks[DIV4_B], 0),237SH_HWBLK_CLK(HWBLK_2DG, &div4_clks[DIV4_B], 0),238SH_HWBLK_CLK(HWBLK_SDHI0, &div4_clks[DIV4_B], 0),239SH_HWBLK_CLK(HWBLK_SDHI1, &div4_clks[DIV4_B], 0),240SH_HWBLK_CLK(HWBLK_VEU1, &div4_clks[DIV4_B], 0),241SH_HWBLK_CLK(HWBLK_CEU1, &div4_clks[DIV4_B], 0),242SH_HWBLK_CLK(HWBLK_BEU1, &div4_clks[DIV4_B], 0),243SH_HWBLK_CLK(HWBLK_2DDMAC, &div4_clks[DIV4_SH], 0),244SH_HWBLK_CLK(HWBLK_SPU, &div4_clks[DIV4_B], 0),245SH_HWBLK_CLK(HWBLK_JPU, &div4_clks[DIV4_B], 0),246SH_HWBLK_CLK(HWBLK_VOU, &div4_clks[DIV4_B], 0),247SH_HWBLK_CLK(HWBLK_BEU0, &div4_clks[DIV4_B], 0),248SH_HWBLK_CLK(HWBLK_CEU0, &div4_clks[DIV4_B], 0),249SH_HWBLK_CLK(HWBLK_VEU0, &div4_clks[DIV4_B], 0),250SH_HWBLK_CLK(HWBLK_VPU, &div4_clks[DIV4_B], 0),251SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),252};253254#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }255256static struct clk_lookup lookups[] = {257/* main clocks */258CLKDEV_CON_ID("rclk", &r_clk),259CLKDEV_CON_ID("extal", &extal_clk),260CLKDEV_CON_ID("fll_clk", &fll_clk),261CLKDEV_CON_ID("pll_clk", &pll_clk),262CLKDEV_CON_ID("div3_clk", &div3_clk),263264/* DIV4 clocks */265CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),266CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),267CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),268CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),269CLKDEV_CON_ID("vpu_clk", &div4_clks[DIV4_M1]),270271/* DIV6 clocks */272CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),273CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FA]),274CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FB]),275CLKDEV_CON_ID("irda_clk", &div6_clks[DIV6_I]),276CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_S]),277278/* MSTP clocks */279CLKDEV_CON_ID("tlb0", &mstp_clks[HWBLK_TLB]),280CLKDEV_CON_ID("ic0", &mstp_clks[HWBLK_IC]),281CLKDEV_CON_ID("oc0", &mstp_clks[HWBLK_OC]),282CLKDEV_CON_ID("rs0", &mstp_clks[HWBLK_RSMEM]),283CLKDEV_CON_ID("ilmem0", &mstp_clks[HWBLK_ILMEM]),284CLKDEV_CON_ID("l2c0", &mstp_clks[HWBLK_L2C]),285CLKDEV_CON_ID("fpu0", &mstp_clks[HWBLK_FPU]),286CLKDEV_CON_ID("intc0", &mstp_clks[HWBLK_INTC]),287CLKDEV_CON_ID("dmac0", &mstp_clks[HWBLK_DMAC0]),288CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),289CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),290CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),291{292/* TMU0 */293.dev_id = "sh_tmu.0",294.con_id = "tmu_fck",295.clk = &mstp_clks[HWBLK_TMU0],296}, {297/* TMU1 */298.dev_id = "sh_tmu.1",299.con_id = "tmu_fck",300.clk = &mstp_clks[HWBLK_TMU0],301}, {302/* TMU2 */303.dev_id = "sh_tmu.2",304.con_id = "tmu_fck",305.clk = &mstp_clks[HWBLK_TMU0],306}, {307/* TMU3 */308.dev_id = "sh_tmu.3",309.con_id = "tmu_fck",310.clk = &mstp_clks[HWBLK_TMU1],311},312CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),313CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),314CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),315{316/* TMU4 */317.dev_id = "sh_tmu.4",318.con_id = "tmu_fck",319.clk = &mstp_clks[HWBLK_TMU1],320}, {321/* TMU5 */322.dev_id = "sh_tmu.5",323.con_id = "tmu_fck",324.clk = &mstp_clks[HWBLK_TMU1],325}, {326/* SCIF0 */327.dev_id = "sh-sci.0",328.con_id = "sci_fck",329.clk = &mstp_clks[HWBLK_SCIF0],330}, {331/* SCIF1 */332.dev_id = "sh-sci.1",333.con_id = "sci_fck",334.clk = &mstp_clks[HWBLK_SCIF1],335}, {336/* SCIF2 */337.dev_id = "sh-sci.2",338.con_id = "sci_fck",339.clk = &mstp_clks[HWBLK_SCIF2],340}, {341/* SCIF3 */342.dev_id = "sh-sci.3",343.con_id = "sci_fck",344.clk = &mstp_clks[HWBLK_SCIF3],345}, {346/* SCIF4 */347.dev_id = "sh-sci.4",348.con_id = "sci_fck",349.clk = &mstp_clks[HWBLK_SCIF4],350}, {351/* SCIF5 */352.dev_id = "sh-sci.5",353.con_id = "sci_fck",354.clk = &mstp_clks[HWBLK_SCIF5],355},356CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),357CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),358CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),359CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),360CLKDEV_CON_ID("i2c0", &mstp_clks[HWBLK_IIC0]),361CLKDEV_CON_ID("i2c1", &mstp_clks[HWBLK_IIC1]),362CLKDEV_CON_ID("mmc0", &mstp_clks[HWBLK_MMC]),363CLKDEV_CON_ID("eth0", &mstp_clks[HWBLK_ETHER]),364CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),365CLKDEV_CON_ID("tpu0", &mstp_clks[HWBLK_TPU]),366CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),367CLKDEV_CON_ID("tsif0", &mstp_clks[HWBLK_TSIF]),368CLKDEV_CON_ID("usb1", &mstp_clks[HWBLK_USB1]),369CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB0]),370CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),371CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI0]),372CLKDEV_CON_ID("sdhi1", &mstp_clks[HWBLK_SDHI1]),373CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU1]),374CLKDEV_CON_ID("ceu1", &mstp_clks[HWBLK_CEU1]),375CLKDEV_CON_ID("beu1", &mstp_clks[HWBLK_BEU1]),376CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]),377CLKDEV_CON_ID("spu0", &mstp_clks[HWBLK_SPU]),378CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),379CLKDEV_CON_ID("vou0", &mstp_clks[HWBLK_VOU]),380CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]),381CLKDEV_CON_ID("ceu0", &mstp_clks[HWBLK_CEU0]),382CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]),383CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),384CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),385};386387int __init arch_clk_init(void)388{389int k, ret = 0;390391/* autodetect extal or fll configuration */392if (__raw_readl(PLLCR) & 0x1000)393pll_clk.parent = &fll_clk;394else395pll_clk.parent = &extal_clk;396397for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)398ret = clk_register(main_clks[k]);399400clkdev_add_table(lookups, ARRAY_SIZE(lookups));401402if (!ret)403ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);404405if (!ret)406ret = sh_clk_div6_register(div6_clks, DIV6_NR);407408if (!ret)409ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);410411if (!ret)412ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);413414return ret;415}416417418