Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Marvell Armada 370 SoC clocks
0004  *
0005  * Copyright (C) 2012 Marvell
0006  *
0007  * Gregory CLEMENT <gregory.clement@free-electrons.com>
0008  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
0009  * Andrew Lunn <andrew@lunn.ch>
0010  *
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/clk-provider.h>
0015 #include <linux/io.h>
0016 #include <linux/of.h>
0017 #include "common.h"
0018 
0019 /*
0020  * Core Clocks
0021  */
0022 
0023 #define SARL                0   /* Low part [0:31] */
0024 #define  SARL_A370_SSCG_ENABLE      BIT(10)
0025 #define  SARL_A370_PCLK_FREQ_OPT    11
0026 #define  SARL_A370_PCLK_FREQ_OPT_MASK   0xF
0027 #define  SARL_A370_FAB_FREQ_OPT     15
0028 #define  SARL_A370_FAB_FREQ_OPT_MASK    0x1F
0029 #define  SARL_A370_TCLK_FREQ_OPT    20
0030 #define  SARL_A370_TCLK_FREQ_OPT_MASK   0x1
0031 
0032 enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK };
0033 
0034 static const struct coreclk_ratio a370_coreclk_ratios[] __initconst = {
0035     { .id = A370_CPU_TO_NBCLK, .name = "nbclk" },
0036     { .id = A370_CPU_TO_HCLK, .name = "hclk" },
0037     { .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" },
0038 };
0039 
0040 static const u32 a370_tclk_freqs[] __initconst = {
0041     166000000,
0042     200000000,
0043 };
0044 
0045 static u32 __init a370_get_tclk_freq(void __iomem *sar)
0046 {
0047     u8 tclk_freq_select = 0;
0048 
0049     tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) &
0050                 SARL_A370_TCLK_FREQ_OPT_MASK);
0051     return a370_tclk_freqs[tclk_freq_select];
0052 }
0053 
0054 static const u32 a370_cpu_freqs[] __initconst = {
0055     400000000,
0056     533000000,
0057     667000000,
0058     800000000,
0059     1000000000,
0060     1067000000,
0061     1200000000,
0062 };
0063 
0064 static u32 __init a370_get_cpu_freq(void __iomem *sar)
0065 {
0066     u32 cpu_freq;
0067     u8 cpu_freq_select = 0;
0068 
0069     cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
0070                SARL_A370_PCLK_FREQ_OPT_MASK);
0071     if (cpu_freq_select >= ARRAY_SIZE(a370_cpu_freqs)) {
0072         pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
0073         cpu_freq = 0;
0074     } else
0075         cpu_freq = a370_cpu_freqs[cpu_freq_select];
0076 
0077     return cpu_freq;
0078 }
0079 
0080 static const int a370_nbclk_ratios[32][2] __initconst = {
0081     {0, 1}, {1, 2}, {2, 2}, {2, 2},
0082     {1, 2}, {1, 2}, {1, 1}, {2, 3},
0083     {0, 1}, {1, 2}, {2, 4}, {0, 1},
0084     {1, 2}, {0, 1}, {0, 1}, {2, 2},
0085     {0, 1}, {0, 1}, {0, 1}, {1, 1},
0086     {2, 3}, {0, 1}, {0, 1}, {0, 1},
0087     {0, 1}, {0, 1}, {0, 1}, {1, 1},
0088     {0, 1}, {0, 1}, {0, 1}, {0, 1},
0089 };
0090 
0091 static const int a370_hclk_ratios[32][2] __initconst = {
0092     {0, 1}, {1, 2}, {2, 6}, {2, 3},
0093     {1, 3}, {1, 4}, {1, 2}, {2, 6},
0094     {0, 1}, {1, 6}, {2, 10}, {0, 1},
0095     {1, 4}, {0, 1}, {0, 1}, {2, 5},
0096     {0, 1}, {0, 1}, {0, 1}, {1, 2},
0097     {2, 6}, {0, 1}, {0, 1}, {0, 1},
0098     {0, 1}, {0, 1}, {0, 1}, {1, 1},
0099     {0, 1}, {0, 1}, {0, 1}, {0, 1},
0100 };
0101 
0102 static const int a370_dramclk_ratios[32][2] __initconst = {
0103     {0, 1}, {1, 2}, {2, 3}, {2, 3},
0104     {1, 3}, {1, 2}, {1, 2}, {2, 6},
0105     {0, 1}, {1, 3}, {2, 5}, {0, 1},
0106     {1, 4}, {0, 1}, {0, 1}, {2, 5},
0107     {0, 1}, {0, 1}, {0, 1}, {1, 1},
0108     {2, 3}, {0, 1}, {0, 1}, {0, 1},
0109     {0, 1}, {0, 1}, {0, 1}, {1, 1},
0110     {0, 1}, {0, 1}, {0, 1}, {0, 1},
0111 };
0112 
0113 static void __init a370_get_clk_ratio(
0114     void __iomem *sar, int id, int *mult, int *div)
0115 {
0116     u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
0117         SARL_A370_FAB_FREQ_OPT_MASK);
0118 
0119     switch (id) {
0120     case A370_CPU_TO_NBCLK:
0121         *mult = a370_nbclk_ratios[opt][0];
0122         *div = a370_nbclk_ratios[opt][1];
0123         break;
0124     case A370_CPU_TO_HCLK:
0125         *mult = a370_hclk_ratios[opt][0];
0126         *div = a370_hclk_ratios[opt][1];
0127         break;
0128     case A370_CPU_TO_DRAMCLK:
0129         *mult = a370_dramclk_ratios[opt][0];
0130         *div = a370_dramclk_ratios[opt][1];
0131         break;
0132     }
0133 }
0134 
0135 static bool a370_is_sscg_enabled(void __iomem *sar)
0136 {
0137     return !(readl(sar) & SARL_A370_SSCG_ENABLE);
0138 }
0139 
0140 static const struct coreclk_soc_desc a370_coreclks = {
0141     .get_tclk_freq = a370_get_tclk_freq,
0142     .get_cpu_freq = a370_get_cpu_freq,
0143     .get_clk_ratio = a370_get_clk_ratio,
0144     .is_sscg_enabled = a370_is_sscg_enabled,
0145     .fix_sscg_deviation = kirkwood_fix_sscg_deviation,
0146     .ratios = a370_coreclk_ratios,
0147     .num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
0148 };
0149 
0150 /*
0151  * Clock Gating Control
0152  */
0153 
0154 static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
0155     { "audio", NULL, 0, 0 },
0156     { "pex0_en", NULL, 1, 0 },
0157     { "pex1_en", NULL,  2, 0 },
0158     { "ge1", NULL, 3, 0 },
0159     { "ge0", NULL, 4, 0 },
0160     { "pex0", "pex0_en", 5, 0 },
0161     { "pex1", "pex1_en", 9, 0 },
0162     { "sata0", NULL, 15, 0 },
0163     { "sdio", NULL, 17, 0 },
0164     { "crypto", NULL, 23, CLK_IGNORE_UNUSED },
0165     { "tdm", NULL, 25, 0 },
0166     { "ddr", NULL, 28, CLK_IGNORE_UNUSED },
0167     { "sata1", NULL, 30, 0 },
0168     { }
0169 };
0170 
0171 static void __init a370_clk_init(struct device_node *np)
0172 {
0173     struct device_node *cgnp =
0174         of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock");
0175 
0176     mvebu_coreclk_setup(np, &a370_coreclks);
0177 
0178     if (cgnp) {
0179         mvebu_clk_gating_setup(cgnp, a370_gating_desc);
0180         of_node_put(cgnp);
0181     }
0182 }
0183 CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
0184