Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Marvell Armada CP110 System Controller
0004  *
0005  * Copyright (C) 2016 Marvell
0006  *
0007  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
0008  *
0009  */
0010 
0011 /*
0012  * CP110 has 6 core clocks:
0013  *
0014  *  - PLL0      (1 Ghz)
0015  *    - PPv2 core   (1/3 PLL0)
0016  *    - x2 Core     (1/2 PLL0)
0017  *  - Core      (1/2 x2 Core)
0018  *    - SDIO        (2/5 PLL0)
0019  *
0020  *  - NAND clock, which is either:
0021  *    - Equal to SDIO clock
0022  *    - 2/5 PLL0
0023  *
0024  * CP110 has 32 gateable clocks, for the various peripherals in the IP.
0025  */
0026 
0027 #define pr_fmt(fmt) "cp110-system-controller: " fmt
0028 
0029 #include "armada_ap_cp_helper.h"
0030 #include <linux/clk-provider.h>
0031 #include <linux/mfd/syscon.h>
0032 #include <linux/init.h>
0033 #include <linux/of.h>
0034 #include <linux/platform_device.h>
0035 #include <linux/regmap.h>
0036 #include <linux/slab.h>
0037 
0038 #define CP110_PM_CLOCK_GATING_REG   0x220
0039 #define CP110_NAND_FLASH_CLK_CTRL_REG   0x700
0040 #define    NF_CLOCK_SEL_400_MASK    BIT(0)
0041 
0042 enum {
0043     CP110_CLK_TYPE_CORE,
0044     CP110_CLK_TYPE_GATABLE,
0045 };
0046 
0047 #define CP110_MAX_CORE_CLOCKS       6
0048 #define CP110_MAX_GATABLE_CLOCKS    32
0049 
0050 #define CP110_CLK_NUM \
0051     (CP110_MAX_CORE_CLOCKS + CP110_MAX_GATABLE_CLOCKS)
0052 
0053 #define CP110_CORE_PLL0         0
0054 #define CP110_CORE_PPV2         1
0055 #define CP110_CORE_X2CORE       2
0056 #define CP110_CORE_CORE         3
0057 #define CP110_CORE_NAND         4
0058 #define CP110_CORE_SDIO         5
0059 
0060 /* A number of gateable clocks need special handling */
0061 #define CP110_GATE_AUDIO        0
0062 #define CP110_GATE_COMM_UNIT        1
0063 #define CP110_GATE_NAND         2
0064 #define CP110_GATE_PPV2         3
0065 #define CP110_GATE_SDIO         4
0066 #define CP110_GATE_MG           5
0067 #define CP110_GATE_MG_CORE      6
0068 #define CP110_GATE_XOR1         7
0069 #define CP110_GATE_XOR0         8
0070 #define CP110_GATE_GOP_DP       9
0071 #define CP110_GATE_PCIE_X1_0        11
0072 #define CP110_GATE_PCIE_X1_1        12
0073 #define CP110_GATE_PCIE_X4      13
0074 #define CP110_GATE_PCIE_XOR     14
0075 #define CP110_GATE_SATA         15
0076 #define CP110_GATE_SATA_USB     16
0077 #define CP110_GATE_MAIN         17
0078 #define CP110_GATE_SDMMC_GOP        18
0079 #define CP110_GATE_SLOW_IO      21
0080 #define CP110_GATE_USB3H0       22
0081 #define CP110_GATE_USB3H1       23
0082 #define CP110_GATE_USB3DEV      24
0083 #define CP110_GATE_EIP150       25
0084 #define CP110_GATE_EIP197       26
0085 
0086 static const char * const gate_base_names[] = {
0087     [CP110_GATE_AUDIO]  = "audio",
0088     [CP110_GATE_COMM_UNIT]  = "communit",
0089     [CP110_GATE_NAND]   = "nand",
0090     [CP110_GATE_PPV2]   = "ppv2",
0091     [CP110_GATE_SDIO]   = "sdio",
0092     [CP110_GATE_MG]     = "mg-domain",
0093     [CP110_GATE_MG_CORE]    = "mg-core",
0094     [CP110_GATE_XOR1]   = "xor1",
0095     [CP110_GATE_XOR0]   = "xor0",
0096     [CP110_GATE_GOP_DP] = "gop-dp",
0097     [CP110_GATE_PCIE_X1_0]  = "pcie_x10",
0098     [CP110_GATE_PCIE_X1_1]  = "pcie_x11",
0099     [CP110_GATE_PCIE_X4]    = "pcie_x4",
0100     [CP110_GATE_PCIE_XOR]   = "pcie-xor",
0101     [CP110_GATE_SATA]   = "sata",
0102     [CP110_GATE_SATA_USB]   = "sata-usb",
0103     [CP110_GATE_MAIN]   = "main",
0104     [CP110_GATE_SDMMC_GOP]  = "sd-mmc-gop",
0105     [CP110_GATE_SLOW_IO]    = "slow-io",
0106     [CP110_GATE_USB3H0] = "usb3h0",
0107     [CP110_GATE_USB3H1] = "usb3h1",
0108     [CP110_GATE_USB3DEV]    = "usb3dev",
0109     [CP110_GATE_EIP150] = "eip150",
0110     [CP110_GATE_EIP197] = "eip197"
0111 };
0112 
0113 struct cp110_gate_clk {
0114     struct clk_hw hw;
0115     struct regmap *regmap;
0116     u8 bit_idx;
0117 };
0118 
0119 #define to_cp110_gate_clk(hw) container_of(hw, struct cp110_gate_clk, hw)
0120 
0121 static int cp110_gate_enable(struct clk_hw *hw)
0122 {
0123     struct cp110_gate_clk *gate = to_cp110_gate_clk(hw);
0124 
0125     regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG,
0126                BIT(gate->bit_idx), BIT(gate->bit_idx));
0127 
0128     return 0;
0129 }
0130 
0131 static void cp110_gate_disable(struct clk_hw *hw)
0132 {
0133     struct cp110_gate_clk *gate = to_cp110_gate_clk(hw);
0134 
0135     regmap_update_bits(gate->regmap, CP110_PM_CLOCK_GATING_REG,
0136                BIT(gate->bit_idx), 0);
0137 }
0138 
0139 static int cp110_gate_is_enabled(struct clk_hw *hw)
0140 {
0141     struct cp110_gate_clk *gate = to_cp110_gate_clk(hw);
0142     u32 val;
0143 
0144     regmap_read(gate->regmap, CP110_PM_CLOCK_GATING_REG, &val);
0145 
0146     return val & BIT(gate->bit_idx);
0147 }
0148 
0149 static const struct clk_ops cp110_gate_ops = {
0150     .enable = cp110_gate_enable,
0151     .disable = cp110_gate_disable,
0152     .is_enabled = cp110_gate_is_enabled,
0153 };
0154 
0155 static struct clk_hw *cp110_register_gate(const char *name,
0156                       const char *parent_name,
0157                       struct regmap *regmap, u8 bit_idx)
0158 {
0159     struct cp110_gate_clk *gate;
0160     struct clk_hw *hw;
0161     struct clk_init_data init;
0162     int ret;
0163 
0164     gate = kzalloc(sizeof(*gate), GFP_KERNEL);
0165     if (!gate)
0166         return ERR_PTR(-ENOMEM);
0167 
0168     memset(&init, 0, sizeof(init));
0169 
0170     init.name = name;
0171     init.ops = &cp110_gate_ops;
0172     init.parent_names = &parent_name;
0173     init.num_parents = 1;
0174 
0175     gate->regmap = regmap;
0176     gate->bit_idx = bit_idx;
0177     gate->hw.init = &init;
0178 
0179     hw = &gate->hw;
0180     ret = clk_hw_register(NULL, hw);
0181     if (ret) {
0182         kfree(gate);
0183         hw = ERR_PTR(ret);
0184     }
0185 
0186     return hw;
0187 }
0188 
0189 static void cp110_unregister_gate(struct clk_hw *hw)
0190 {
0191     clk_hw_unregister(hw);
0192     kfree(to_cp110_gate_clk(hw));
0193 }
0194 
0195 static struct clk_hw *cp110_of_clk_get(struct of_phandle_args *clkspec,
0196                        void *data)
0197 {
0198     struct clk_hw_onecell_data *clk_data = data;
0199     unsigned int type = clkspec->args[0];
0200     unsigned int idx = clkspec->args[1];
0201 
0202     if (type == CP110_CLK_TYPE_CORE) {
0203         if (idx >= CP110_MAX_CORE_CLOCKS)
0204             return ERR_PTR(-EINVAL);
0205         return clk_data->hws[idx];
0206     } else if (type == CP110_CLK_TYPE_GATABLE) {
0207         if (idx >= CP110_MAX_GATABLE_CLOCKS)
0208             return ERR_PTR(-EINVAL);
0209         return clk_data->hws[CP110_MAX_CORE_CLOCKS + idx];
0210     }
0211 
0212     return ERR_PTR(-EINVAL);
0213 }
0214 
0215 static int cp110_syscon_common_probe(struct platform_device *pdev,
0216                      struct device_node *syscon_node)
0217 {
0218     struct regmap *regmap;
0219     struct device *dev = &pdev->dev;
0220     struct device_node *np = dev->of_node;
0221     const char *ppv2_name, *pll0_name, *core_name, *x2core_name, *nand_name,
0222         *sdio_name;
0223     struct clk_hw_onecell_data *cp110_clk_data;
0224     struct clk_hw *hw, **cp110_clks;
0225     u32 nand_clk_ctrl;
0226     int i, ret;
0227     char *gate_name[ARRAY_SIZE(gate_base_names)];
0228 
0229     regmap = syscon_node_to_regmap(syscon_node);
0230     if (IS_ERR(regmap))
0231         return PTR_ERR(regmap);
0232 
0233     ret = regmap_read(regmap, CP110_NAND_FLASH_CLK_CTRL_REG,
0234               &nand_clk_ctrl);
0235     if (ret)
0236         return ret;
0237 
0238     cp110_clk_data = devm_kzalloc(dev, struct_size(cp110_clk_data, hws,
0239                                CP110_CLK_NUM),
0240                       GFP_KERNEL);
0241     if (!cp110_clk_data)
0242         return -ENOMEM;
0243 
0244     cp110_clks = cp110_clk_data->hws;
0245     cp110_clk_data->num = CP110_CLK_NUM;
0246 
0247     /* Register the PLL0 which is the root of the hw tree */
0248     pll0_name = ap_cp_unique_name(dev, syscon_node, "pll0");
0249     hw = clk_hw_register_fixed_rate(NULL, pll0_name, NULL, 0,
0250                     1000 * 1000 * 1000);
0251     if (IS_ERR(hw)) {
0252         ret = PTR_ERR(hw);
0253         goto fail_pll0;
0254     }
0255 
0256     cp110_clks[CP110_CORE_PLL0] = hw;
0257 
0258     /* PPv2 is PLL0/3 */
0259     ppv2_name = ap_cp_unique_name(dev, syscon_node, "ppv2-core");
0260     hw = clk_hw_register_fixed_factor(NULL, ppv2_name, pll0_name, 0, 1, 3);
0261     if (IS_ERR(hw)) {
0262         ret = PTR_ERR(hw);
0263         goto fail_ppv2;
0264     }
0265 
0266     cp110_clks[CP110_CORE_PPV2] = hw;
0267 
0268     /* X2CORE clock is PLL0/2 */
0269     x2core_name = ap_cp_unique_name(dev, syscon_node, "x2core");
0270     hw = clk_hw_register_fixed_factor(NULL, x2core_name, pll0_name,
0271                       0, 1, 2);
0272     if (IS_ERR(hw)) {
0273         ret = PTR_ERR(hw);
0274         goto fail_eip;
0275     }
0276 
0277     cp110_clks[CP110_CORE_X2CORE] = hw;
0278 
0279     /* Core clock is X2CORE/2 */
0280     core_name = ap_cp_unique_name(dev, syscon_node, "core");
0281     hw = clk_hw_register_fixed_factor(NULL, core_name, x2core_name,
0282                       0, 1, 2);
0283     if (IS_ERR(hw)) {
0284         ret = PTR_ERR(hw);
0285         goto fail_core;
0286     }
0287 
0288     cp110_clks[CP110_CORE_CORE] = hw;
0289     /* NAND can be either PLL0/2.5 or core clock */
0290     nand_name = ap_cp_unique_name(dev, syscon_node, "nand-core");
0291     if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK)
0292         hw = clk_hw_register_fixed_factor(NULL, nand_name,
0293                            pll0_name, 0, 2, 5);
0294     else
0295         hw = clk_hw_register_fixed_factor(NULL, nand_name,
0296                            core_name, 0, 1, 1);
0297     if (IS_ERR(hw)) {
0298         ret = PTR_ERR(hw);
0299         goto fail_nand;
0300     }
0301 
0302     cp110_clks[CP110_CORE_NAND] = hw;
0303 
0304     /* SDIO clock is PLL0/2.5 */
0305     sdio_name = ap_cp_unique_name(dev, syscon_node, "sdio-core");
0306     hw = clk_hw_register_fixed_factor(NULL, sdio_name,
0307                       pll0_name, 0, 2, 5);
0308     if (IS_ERR(hw)) {
0309         ret = PTR_ERR(hw);
0310         goto fail_sdio;
0311     }
0312 
0313     cp110_clks[CP110_CORE_SDIO] = hw;
0314 
0315     /* create the unique name for all the gate clocks */
0316     for (i = 0; i < ARRAY_SIZE(gate_base_names); i++)
0317         gate_name[i] =  ap_cp_unique_name(dev, syscon_node,
0318                           gate_base_names[i]);
0319 
0320     for (i = 0; i < ARRAY_SIZE(gate_base_names); i++) {
0321         const char *parent;
0322 
0323         if (gate_name[i] == NULL)
0324             continue;
0325 
0326         switch (i) {
0327         case CP110_GATE_NAND:
0328             parent = nand_name;
0329             break;
0330         case CP110_GATE_MG:
0331         case CP110_GATE_GOP_DP:
0332         case CP110_GATE_PPV2:
0333             parent = ppv2_name;
0334             break;
0335         case CP110_GATE_SDIO:
0336             parent = sdio_name;
0337             break;
0338         case CP110_GATE_MAIN:
0339         case CP110_GATE_PCIE_XOR:
0340         case CP110_GATE_PCIE_X4:
0341         case CP110_GATE_EIP150:
0342         case CP110_GATE_EIP197:
0343             parent = x2core_name;
0344             break;
0345         default:
0346             parent = core_name;
0347             break;
0348         }
0349         hw = cp110_register_gate(gate_name[i], parent, regmap, i);
0350 
0351         if (IS_ERR(hw)) {
0352             ret = PTR_ERR(hw);
0353             goto fail_gate;
0354         }
0355 
0356         cp110_clks[CP110_MAX_CORE_CLOCKS + i] = hw;
0357     }
0358 
0359     ret = of_clk_add_hw_provider(np, cp110_of_clk_get, cp110_clk_data);
0360     if (ret)
0361         goto fail_clk_add;
0362 
0363     platform_set_drvdata(pdev, cp110_clks);
0364 
0365     return 0;
0366 
0367 fail_clk_add:
0368 fail_gate:
0369     for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) {
0370         hw = cp110_clks[CP110_MAX_CORE_CLOCKS + i];
0371 
0372         if (hw)
0373             cp110_unregister_gate(hw);
0374     }
0375 
0376     clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_SDIO]);
0377 fail_sdio:
0378     clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]);
0379 fail_nand:
0380     clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]);
0381 fail_core:
0382     clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_X2CORE]);
0383 fail_eip:
0384     clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]);
0385 fail_ppv2:
0386     clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_PLL0]);
0387 fail_pll0:
0388     return ret;
0389 }
0390 
0391 static int cp110_syscon_legacy_clk_probe(struct platform_device *pdev)
0392 {
0393     dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n");
0394     dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n");
0395     dev_warn(&pdev->dev, FW_WARN
0396          "This binding won't be supported in future kernels\n");
0397 
0398     return cp110_syscon_common_probe(pdev, pdev->dev.of_node);
0399 }
0400 
0401 static int cp110_clk_probe(struct platform_device *pdev)
0402 {
0403     return cp110_syscon_common_probe(pdev, pdev->dev.of_node->parent);
0404 }
0405 
0406 static const struct of_device_id cp110_syscon_legacy_of_match[] = {
0407     { .compatible = "marvell,cp110-system-controller0", },
0408     { }
0409 };
0410 
0411 static struct platform_driver cp110_syscon_legacy_driver = {
0412     .probe = cp110_syscon_legacy_clk_probe,
0413     .driver     = {
0414         .name   = "marvell-cp110-system-controller0",
0415         .of_match_table = cp110_syscon_legacy_of_match,
0416         .suppress_bind_attrs = true,
0417     },
0418 };
0419 builtin_platform_driver(cp110_syscon_legacy_driver);
0420 
0421 static const struct of_device_id cp110_clock_of_match[] = {
0422     { .compatible = "marvell,cp110-clock", },
0423     { }
0424 };
0425 
0426 static struct platform_driver cp110_clock_driver = {
0427     .probe = cp110_clk_probe,
0428     .driver     = {
0429         .name   = "marvell-cp110-clock",
0430         .of_match_table = cp110_clock_of_match,
0431         .suppress_bind_attrs = true,
0432     },
0433 };
0434 builtin_platform_driver(cp110_clock_driver);