linux/arch/sh/kernel/cpu/sh4a/clock-sh7366.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * arch/sh/kernel/cpu/sh4a/clock-sh7366.c
   4 *
   5 * SH7366 clock framework support
   6 *
   7 * Copyright (C) 2009 Magnus Damm
   8 */
   9#include <linux/init.h>
  10#include <linux/kernel.h>
  11#include <linux/io.h>
  12#include <linux/clkdev.h>
  13#include <asm/clock.h>
  14
  15/* SH7366 registers */
  16#define FRQCR           0xa4150000
  17#define VCLKCR          0xa4150004
  18#define SCLKACR         0xa4150008
  19#define SCLKBCR         0xa415000c
  20#define PLLCR           0xa4150024
  21#define MSTPCR0         0xa4150030
  22#define MSTPCR1         0xa4150034
  23#define MSTPCR2         0xa4150038
  24#define DLLFRQ          0xa4150050
  25
  26/* Fixed 32 KHz root clock for RTC and Power Management purposes */
  27static struct clk r_clk = {
  28        .rate           = 32768,
  29};
  30
  31/*
  32 * Default rate for the root input clock, reset this with clk_set_rate()
  33 * from the platform code.
  34 */
  35struct clk extal_clk = {
  36        .rate           = 33333333,
  37};
  38
  39/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
  40static unsigned long dll_recalc(struct clk *clk)
  41{
  42        unsigned long mult;
  43
  44        if (__raw_readl(PLLCR) & 0x1000)
  45                mult = __raw_readl(DLLFRQ);
  46        else
  47                mult = 0;
  48
  49        return clk->parent->rate * mult;
  50}
  51
  52static struct sh_clk_ops dll_clk_ops = {
  53        .recalc         = dll_recalc,
  54};
  55
  56static struct clk dll_clk = {
  57        .ops            = &dll_clk_ops,
  58        .parent         = &r_clk,
  59        .flags          = CLK_ENABLE_ON_INIT,
  60};
  61
  62static unsigned long pll_recalc(struct clk *clk)
  63{
  64        unsigned long mult = 1;
  65        unsigned long div = 1;
  66
  67        if (__raw_readl(PLLCR) & 0x4000)
  68                mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
  69        else
  70                div = 2;
  71
  72        return (clk->parent->rate * mult) / div;
  73}
  74
  75static struct sh_clk_ops pll_clk_ops = {
  76        .recalc         = pll_recalc,
  77};
  78
  79static struct clk pll_clk = {
  80        .ops            = &pll_clk_ops,
  81        .flags          = CLK_ENABLE_ON_INIT,
  82};
  83
  84struct clk *main_clks[] = {
  85        &r_clk,
  86        &extal_clk,
  87        &dll_clk,
  88        &pll_clk,
  89};
  90
  91static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
  92static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
  93
  94static struct clk_div_mult_table div4_div_mult_table = {
  95        .divisors = divisors,
  96        .nr_divisors = ARRAY_SIZE(divisors),
  97        .multipliers = multipliers,
  98        .nr_multipliers = ARRAY_SIZE(multipliers),
  99};
 100
 101static struct clk_div4_table div4_table = {
 102        .div_mult_table = &div4_div_mult_table,
 103};
 104
 105enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
 106       DIV4_SIUA, DIV4_SIUB, DIV4_NR };
 107
 108#define DIV4(_reg, _bit, _mask, _flags) \
 109  SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
 110
 111struct clk div4_clks[DIV4_NR] = {
 112        [DIV4_I] = DIV4(FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
 113        [DIV4_U] = DIV4(FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
 114        [DIV4_SH] = DIV4(FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
 115        [DIV4_B] = DIV4(FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
 116        [DIV4_B3] = DIV4(FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
 117        [DIV4_P] = DIV4(FRQCR, 0, 0x1fff, 0),
 118        [DIV4_SIUA] = DIV4(SCLKACR, 0, 0x1fff, 0),
 119        [DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x1fff, 0),
 120};
 121
 122enum { DIV6_V, DIV6_NR };
 123
 124struct clk div6_clks[DIV6_NR] = {
 125        [DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
 126};
 127
 128#define MSTP(_parent, _reg, _bit, _flags) \
 129  SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
 130
 131enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026,
 132       MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016,
 133       MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010,
 134       MSTP007, MSTP006, MSTP005, MSTP002, MSTP001,
 135       MSTP109, MSTP100,
 136       MSTP227, MSTP226, MSTP224, MSTP223, MSTP222, MSTP218, MSTP217,
 137       MSTP211, MSTP207, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
 138       MSTP_NR };
 139
 140static struct clk mstp_clks[MSTP_NR] = {
 141        /* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
 142        [MSTP031] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
 143        [MSTP030] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
 144        [MSTP029] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
 145        [MSTP028] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
 146        [MSTP026] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
 147        [MSTP023] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
 148        [MSTP022] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
 149        [MSTP021] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
 150        [MSTP020] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 20, 0),
 151        [MSTP019] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
 152        [MSTP017] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 17, 0),
 153        [MSTP015] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
 154        [MSTP014] = MSTP(&r_clk, MSTPCR0, 14, 0),
 155        [MSTP013] = MSTP(&r_clk, MSTPCR0, 13, 0),
 156        [MSTP011] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
 157        [MSTP010] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
 158        [MSTP007] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
 159        [MSTP006] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
 160        [MSTP005] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
 161        [MSTP002] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
 162        [MSTP001] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
 163
 164        [MSTP109] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
 165
 166        [MSTP227] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 27, 0),
 167        [MSTP226] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 26, 0),
 168        [MSTP224] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
 169        [MSTP223] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 23, 0),
 170        [MSTP222] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 22, 0),
 171        [MSTP218] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
 172        [MSTP217] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 17, 0),
 173        [MSTP211] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
 174        [MSTP207] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT),
 175        [MSTP205] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
 176        [MSTP204] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
 177        [MSTP203] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
 178        [MSTP202] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
 179        [MSTP201] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
 180        [MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
 181};
 182
 183static struct clk_lookup lookups[] = {
 184        /* main clocks */
 185        CLKDEV_CON_ID("rclk", &r_clk),
 186        CLKDEV_CON_ID("extal", &extal_clk),
 187        CLKDEV_CON_ID("dll_clk", &dll_clk),
 188        CLKDEV_CON_ID("pll_clk", &pll_clk),
 189
 190        /* DIV4 clocks */
 191        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 192        CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
 193        CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
 194        CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
 195        CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]),
 196        CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
 197        CLKDEV_CON_ID("siua_clk", &div4_clks[DIV4_SIUA]),
 198        CLKDEV_CON_ID("siub_clk", &div4_clks[DIV4_SIUB]),
 199
 200        /* DIV6 clocks */
 201        CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
 202
 203        /* MSTP32 clocks */
 204        CLKDEV_CON_ID("tlb0", &mstp_clks[MSTP031]),
 205        CLKDEV_CON_ID("ic0", &mstp_clks[MSTP030]),
 206        CLKDEV_CON_ID("oc0", &mstp_clks[MSTP029]),
 207        CLKDEV_CON_ID("rsmem0", &mstp_clks[MSTP028]),
 208        CLKDEV_CON_ID("xymem0", &mstp_clks[MSTP026]),
 209        CLKDEV_CON_ID("intc3", &mstp_clks[MSTP023]),
 210        CLKDEV_CON_ID("intc0", &mstp_clks[MSTP022]),
 211        CLKDEV_CON_ID("dmac0", &mstp_clks[MSTP021]),
 212        CLKDEV_CON_ID("sh0", &mstp_clks[MSTP020]),
 213        CLKDEV_CON_ID("hudi0", &mstp_clks[MSTP019]),
 214        CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP017]),
 215        CLKDEV_CON_ID("tmu_fck", &mstp_clks[MSTP015]),
 216        CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[MSTP014]),
 217        CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
 218        CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
 219        CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
 220
 221        CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
 222        CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
 223        CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
 224
 225        CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
 226        CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
 227        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
 228        CLKDEV_CON_ID("icb0", &mstp_clks[MSTP227]),
 229        CLKDEV_CON_ID("meram0", &mstp_clks[MSTP226]),
 230        CLKDEV_CON_ID("dacy1", &mstp_clks[MSTP224]),
 231        CLKDEV_CON_ID("dacy0", &mstp_clks[MSTP223]),
 232        CLKDEV_CON_ID("tsif0", &mstp_clks[MSTP222]),
 233        CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]),
 234        CLKDEV_CON_ID("mmcif0", &mstp_clks[MSTP217]),
 235        CLKDEV_CON_ID("usbf0", &mstp_clks[MSTP211]),
 236        CLKDEV_CON_ID("veu1", &mstp_clks[MSTP207]),
 237        CLKDEV_CON_ID("vou0", &mstp_clks[MSTP205]),
 238        CLKDEV_CON_ID("beu0", &mstp_clks[MSTP204]),
 239        CLKDEV_CON_ID("ceu0", &mstp_clks[MSTP203]),
 240        CLKDEV_CON_ID("veu0", &mstp_clks[MSTP202]),
 241        CLKDEV_CON_ID("vpu0", &mstp_clks[MSTP201]),
 242        CLKDEV_CON_ID("lcdc0", &mstp_clks[MSTP200]),
 243};
 244
 245int __init arch_clk_init(void)
 246{
 247        int k, ret = 0;
 248
 249        /* autodetect extal or dll configuration */
 250        if (__raw_readl(PLLCR) & 0x1000)
 251                pll_clk.parent = &dll_clk;
 252        else
 253                pll_clk.parent = &extal_clk;
 254
 255        for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
 256                ret = clk_register(main_clks[k]);
 257
 258        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 259
 260        if (!ret)
 261                ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
 262
 263        if (!ret)
 264                ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 265
 266        if (!ret)
 267                ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
 268
 269        return ret;
 270}
 271