Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2021 Linaro Ltd.
0004  * Copyright (C) 2021 Dávid Virág <virag.david003@gmail.com>
0005  * Author: Sam Protsenko <semen.protsenko@linaro.org>
0006  * Author: Dávid Virág <virag.david003@gmail.com>
0007  *
0008  * This file contains shared functions used by some arm64 Exynos SoCs,
0009  * such as Exynos7885 or Exynos850 to register and init CMUs.
0010  */
0011 #include <linux/clk.h>
0012 #include <linux/of_address.h>
0013 
0014 #include "clk-exynos-arm64.h"
0015 
0016 /* Gate register bits */
0017 #define GATE_MANUAL     BIT(20)
0018 #define GATE_ENABLE_HWACG   BIT(28)
0019 
0020 /* Gate register offsets range */
0021 #define GATE_OFF_START      0x2000
0022 #define GATE_OFF_END        0x2fff
0023 
0024 /**
0025  * exynos_arm64_init_clocks - Set clocks initial configuration
0026  * @np:         CMU device tree node with "reg" property (CMU addr)
0027  * @reg_offs:       Register offsets array for clocks to init
0028  * @reg_offs_len:   Number of register offsets in reg_offs array
0029  *
0030  * Set manual control mode for all gate clocks.
0031  */
0032 static void __init exynos_arm64_init_clocks(struct device_node *np,
0033         const unsigned long *reg_offs, size_t reg_offs_len)
0034 {
0035     void __iomem *reg_base;
0036     size_t i;
0037 
0038     reg_base = of_iomap(np, 0);
0039     if (!reg_base)
0040         panic("%s: failed to map registers\n", __func__);
0041 
0042     for (i = 0; i < reg_offs_len; ++i) {
0043         void __iomem *reg = reg_base + reg_offs[i];
0044         u32 val;
0045 
0046         /* Modify only gate clock registers */
0047         if (reg_offs[i] < GATE_OFF_START || reg_offs[i] > GATE_OFF_END)
0048             continue;
0049 
0050         val = readl(reg);
0051         val |= GATE_MANUAL;
0052         val &= ~GATE_ENABLE_HWACG;
0053         writel(val, reg);
0054     }
0055 
0056     iounmap(reg_base);
0057 }
0058 
0059 /**
0060  * exynos_arm64_register_cmu - Register specified Exynos CMU domain
0061  * @dev:    Device object; may be NULL if this function is not being
0062  *      called from platform driver probe function
0063  * @np:     CMU device tree node
0064  * @cmu:    CMU data
0065  *
0066  * Register specified CMU domain, which includes next steps:
0067  *
0068  * 1. Enable parent clock of @cmu CMU
0069  * 2. Set initial registers configuration for @cmu CMU clocks
0070  * 3. Register @cmu CMU clocks using Samsung clock framework API
0071  */
0072 void __init exynos_arm64_register_cmu(struct device *dev,
0073         struct device_node *np, const struct samsung_cmu_info *cmu)
0074 {
0075     /* Keep CMU parent clock running (needed for CMU registers access) */
0076     if (cmu->clk_name) {
0077         struct clk *parent_clk;
0078 
0079         if (dev)
0080             parent_clk = clk_get(dev, cmu->clk_name);
0081         else
0082             parent_clk = of_clk_get_by_name(np, cmu->clk_name);
0083 
0084         if (IS_ERR(parent_clk)) {
0085             pr_err("%s: could not find bus clock %s; err = %ld\n",
0086                    __func__, cmu->clk_name, PTR_ERR(parent_clk));
0087         } else {
0088             clk_prepare_enable(parent_clk);
0089         }
0090     }
0091 
0092     exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
0093     samsung_cmu_register_one(np, cmu);
0094 }