18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Default clock type 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005-2008, 2015 Texas Instruments, Inc. 58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2010 Nokia Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contacts: 88c2ecf20Sopenharmony_ci * Richard Woodruff <r-woodruff2@ti.com> 98c2ecf20Sopenharmony_ci * Paul Walmsley 108c2ecf20Sopenharmony_ci * Tero Kristo <t-kristo@ti.com> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 138c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 148c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any 178c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty 188c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 198c2ecf20Sopenharmony_ci * GNU General Public License for more details. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/kernel.h> 238c2ecf20Sopenharmony_ci#include <linux/errno.h> 248c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 258c2ecf20Sopenharmony_ci#include <linux/io.h> 268c2ecf20Sopenharmony_ci#include <linux/clk/ti.h> 278c2ecf20Sopenharmony_ci#include <linux/delay.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "clock.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait 338c2ecf20Sopenharmony_ci * for a module to indicate that it is no longer in idle 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci#define MAX_MODULE_ENABLE_WAIT 100000 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * CM module register offsets, used for calculating the companion 398c2ecf20Sopenharmony_ci * register addresses. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci#define CM_FCLKEN 0x0000 428c2ecf20Sopenharmony_ci#define CM_ICLKEN 0x0010 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/** 458c2ecf20Sopenharmony_ci * _wait_idlest_generic - wait for a module to leave the idle state 468c2ecf20Sopenharmony_ci * @clk: module clock to wait for (needed for register offsets) 478c2ecf20Sopenharmony_ci * @reg: virtual address of module IDLEST register 488c2ecf20Sopenharmony_ci * @mask: value to mask against to determine if the module is active 498c2ecf20Sopenharmony_ci * @idlest: idle state indicator (0 or 1) for the clock 508c2ecf20Sopenharmony_ci * @name: name of the clock (for printk) 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * Wait for a module to leave idle, where its idle-status register is 538c2ecf20Sopenharmony_ci * not inside the CM module. Returns 1 if the module left idle 548c2ecf20Sopenharmony_ci * promptly, or 0 if the module did not leave idle before the timeout 558c2ecf20Sopenharmony_ci * elapsed. XXX Deprecated - should be moved into drivers for the 568c2ecf20Sopenharmony_ci * individual IP block that the IDLEST register exists in. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic int _wait_idlest_generic(struct clk_hw_omap *clk, 598c2ecf20Sopenharmony_ci struct clk_omap_reg *reg, 608c2ecf20Sopenharmony_ci u32 mask, u8 idlest, const char *name) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci int i = 0, ena = 0; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci ena = (idlest) ? 0 : mask; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* Wait until module enters enabled state */ 678c2ecf20Sopenharmony_ci for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) { 688c2ecf20Sopenharmony_ci if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena) 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci udelay(1); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (i < MAX_MODULE_ENABLE_WAIT) 748c2ecf20Sopenharmony_ci pr_debug("omap clock: module associated with clock %s ready after %d loops\n", 758c2ecf20Sopenharmony_ci name, i); 768c2ecf20Sopenharmony_ci else 778c2ecf20Sopenharmony_ci pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n", 788c2ecf20Sopenharmony_ci name, MAX_MODULE_ENABLE_WAIT); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** 848c2ecf20Sopenharmony_ci * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE 858c2ecf20Sopenharmony_ci * @clk: struct clk * belonging to the module 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * If the necessary clocks for the OMAP hardware IP block that 888c2ecf20Sopenharmony_ci * corresponds to clock @clk are enabled, then wait for the module to 898c2ecf20Sopenharmony_ci * indicate readiness (i.e., to leave IDLE). This code does not 908c2ecf20Sopenharmony_ci * belong in the clock code and will be moved in the medium term to 918c2ecf20Sopenharmony_ci * module-dependent code. No return value. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cistatic void _omap2_module_wait_ready(struct clk_hw_omap *clk) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct clk_omap_reg companion_reg, idlest_reg; 968c2ecf20Sopenharmony_ci u8 other_bit, idlest_bit, idlest_val, idlest_reg_id; 978c2ecf20Sopenharmony_ci s16 prcm_mod; 988c2ecf20Sopenharmony_ci int r; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Not all modules have multiple clocks that their IDLEST depends on */ 1018c2ecf20Sopenharmony_ci if (clk->ops->find_companion) { 1028c2ecf20Sopenharmony_ci clk->ops->find_companion(clk, &companion_reg, &other_bit); 1038c2ecf20Sopenharmony_ci if (!(ti_clk_ll_ops->clk_readl(&companion_reg) & 1048c2ecf20Sopenharmony_ci (1 << other_bit))) 1058c2ecf20Sopenharmony_ci return; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); 1098c2ecf20Sopenharmony_ci r = ti_clk_ll_ops->cm_split_idlest_reg(&idlest_reg, &prcm_mod, 1108c2ecf20Sopenharmony_ci &idlest_reg_id); 1118c2ecf20Sopenharmony_ci if (r) { 1128c2ecf20Sopenharmony_ci /* IDLEST register not in the CM module */ 1138c2ecf20Sopenharmony_ci _wait_idlest_generic(clk, &idlest_reg, (1 << idlest_bit), 1148c2ecf20Sopenharmony_ci idlest_val, clk_hw_get_name(&clk->hw)); 1158c2ecf20Sopenharmony_ci } else { 1168c2ecf20Sopenharmony_ci ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id, 1178c2ecf20Sopenharmony_ci idlest_bit); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/** 1228c2ecf20Sopenharmony_ci * omap2_clk_dflt_find_companion - find companion clock to @clk 1238c2ecf20Sopenharmony_ci * @clk: struct clk * to find the companion clock of 1248c2ecf20Sopenharmony_ci * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in 1258c2ecf20Sopenharmony_ci * @other_bit: u8 ** to return the companion clock bit shift in 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * Note: We don't need special code here for INVERT_ENABLE for the 1288c2ecf20Sopenharmony_ci * time being since INVERT_ENABLE only applies to clocks enabled by 1298c2ecf20Sopenharmony_ci * CM_CLKEN_PLL 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's 1328c2ecf20Sopenharmony_ci * just a matter of XORing the bits. 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * Some clocks don't have companion clocks. For example, modules with 1358c2ecf20Sopenharmony_ci * only an interface clock (such as MAILBOXES) don't have a companion 1368c2ecf20Sopenharmony_ci * clock. Right now, this code relies on the hardware exporting a bit 1378c2ecf20Sopenharmony_ci * in the correct companion register that indicates that the 1388c2ecf20Sopenharmony_ci * nonexistent 'companion clock' is active. Future patches will 1398c2ecf20Sopenharmony_ci * associate this type of code with per-module data structures to 1408c2ecf20Sopenharmony_ci * avoid this issue, and remove the casts. No return value. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_civoid omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, 1438c2ecf20Sopenharmony_ci struct clk_omap_reg *other_reg, 1448c2ecf20Sopenharmony_ci u8 *other_bit) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci memcpy(other_reg, &clk->enable_reg, sizeof(*other_reg)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes 1508c2ecf20Sopenharmony_ci * it's just a matter of XORing the bits. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci other_reg->offset ^= (CM_FCLKEN ^ CM_ICLKEN); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci *other_bit = clk->enable_bit; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/** 1588c2ecf20Sopenharmony_ci * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk 1598c2ecf20Sopenharmony_ci * @clk: struct clk * to find IDLEST info for 1608c2ecf20Sopenharmony_ci * @idlest_reg: void __iomem ** to return the CM_IDLEST va in 1618c2ecf20Sopenharmony_ci * @idlest_bit: u8 * to return the CM_IDLEST bit shift in 1628c2ecf20Sopenharmony_ci * @idlest_val: u8 * to return the idle status indicator 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * Return the CM_IDLEST register address and bit shift corresponding 1658c2ecf20Sopenharmony_ci * to the module that "owns" this clock. This default code assumes 1668c2ecf20Sopenharmony_ci * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that 1678c2ecf20Sopenharmony_ci * the IDLEST register address ID corresponds to the CM_*CLKEN 1688c2ecf20Sopenharmony_ci * register address ID (e.g., that CM_FCLKEN2 corresponds to 1698c2ecf20Sopenharmony_ci * CM_IDLEST2). This is not true for all modules. No return value. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_civoid omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, 1728c2ecf20Sopenharmony_ci struct clk_omap_reg *idlest_reg, u8 *idlest_bit, 1738c2ecf20Sopenharmony_ci u8 *idlest_val) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg)); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci idlest_reg->offset &= ~0xf0; 1788c2ecf20Sopenharmony_ci idlest_reg->offset |= 0x20; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci *idlest_bit = clk->enable_bit; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * 24xx uses 0 to indicate not ready, and 1 to indicate ready. 1848c2ecf20Sopenharmony_ci * 34xx reverses this, just to keep us on our toes 1858c2ecf20Sopenharmony_ci * AM35xx uses both, depending on the module. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci *idlest_val = ti_clk_get_features()->cm_idlest_val; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/** 1918c2ecf20Sopenharmony_ci * omap2_dflt_clk_enable - enable a clock in the hardware 1928c2ecf20Sopenharmony_ci * @hw: struct clk_hw * of the clock to enable 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Enable the clock @hw in the hardware. We first call into the OMAP 1958c2ecf20Sopenharmony_ci * clockdomain code to "enable" the corresponding clockdomain if this 1968c2ecf20Sopenharmony_ci * is the first enabled user of the clockdomain. Then program the 1978c2ecf20Sopenharmony_ci * hardware to enable the clock. Then wait for the IP block that uses 1988c2ecf20Sopenharmony_ci * this clock to leave idle (if applicable). Returns the error value 1998c2ecf20Sopenharmony_ci * from clkdm_clk_enable() if it terminated with an error, or -EINVAL 2008c2ecf20Sopenharmony_ci * if @hw has a null clock enable_reg, or zero upon success. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ciint omap2_dflt_clk_enable(struct clk_hw *hw) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct clk_hw_omap *clk; 2058c2ecf20Sopenharmony_ci u32 v; 2068c2ecf20Sopenharmony_ci int ret = 0; 2078c2ecf20Sopenharmony_ci bool clkdm_control; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) 2108c2ecf20Sopenharmony_ci clkdm_control = false; 2118c2ecf20Sopenharmony_ci else 2128c2ecf20Sopenharmony_ci clkdm_control = true; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci clk = to_clk_hw_omap(hw); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (clkdm_control && clk->clkdm) { 2178c2ecf20Sopenharmony_ci ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); 2188c2ecf20Sopenharmony_ci if (ret) { 2198c2ecf20Sopenharmony_ci WARN(1, 2208c2ecf20Sopenharmony_ci "%s: could not enable %s's clockdomain %s: %d\n", 2218c2ecf20Sopenharmony_ci __func__, clk_hw_get_name(hw), 2228c2ecf20Sopenharmony_ci clk->clkdm_name, ret); 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* FIXME should not have INVERT_ENABLE bit here */ 2288c2ecf20Sopenharmony_ci v = ti_clk_ll_ops->clk_readl(&clk->enable_reg); 2298c2ecf20Sopenharmony_ci if (clk->flags & INVERT_ENABLE) 2308c2ecf20Sopenharmony_ci v &= ~(1 << clk->enable_bit); 2318c2ecf20Sopenharmony_ci else 2328c2ecf20Sopenharmony_ci v |= (1 << clk->enable_bit); 2338c2ecf20Sopenharmony_ci ti_clk_ll_ops->clk_writel(v, &clk->enable_reg); 2348c2ecf20Sopenharmony_ci v = ti_clk_ll_ops->clk_readl(&clk->enable_reg); /* OCP barrier */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (clk->ops && clk->ops->find_idlest) 2378c2ecf20Sopenharmony_ci _omap2_module_wait_ready(clk); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/** 2438c2ecf20Sopenharmony_ci * omap2_dflt_clk_disable - disable a clock in the hardware 2448c2ecf20Sopenharmony_ci * @hw: struct clk_hw * of the clock to disable 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci * Disable the clock @hw in the hardware, and call into the OMAP 2478c2ecf20Sopenharmony_ci * clockdomain code to "disable" the corresponding clockdomain if all 2488c2ecf20Sopenharmony_ci * clocks/hwmods in that clockdomain are now disabled. No return 2498c2ecf20Sopenharmony_ci * value. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_civoid omap2_dflt_clk_disable(struct clk_hw *hw) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct clk_hw_omap *clk; 2548c2ecf20Sopenharmony_ci u32 v; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci clk = to_clk_hw_omap(hw); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci v = ti_clk_ll_ops->clk_readl(&clk->enable_reg); 2598c2ecf20Sopenharmony_ci if (clk->flags & INVERT_ENABLE) 2608c2ecf20Sopenharmony_ci v |= (1 << clk->enable_bit); 2618c2ecf20Sopenharmony_ci else 2628c2ecf20Sopenharmony_ci v &= ~(1 << clk->enable_bit); 2638c2ecf20Sopenharmony_ci ti_clk_ll_ops->clk_writel(v, &clk->enable_reg); 2648c2ecf20Sopenharmony_ci /* No OCP barrier needed here since it is a disable operation */ 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) && 2678c2ecf20Sopenharmony_ci clk->clkdm) 2688c2ecf20Sopenharmony_ci ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/** 2728c2ecf20Sopenharmony_ci * omap2_dflt_clk_is_enabled - is clock enabled in the hardware? 2738c2ecf20Sopenharmony_ci * @hw: struct clk_hw * to check 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * Return 1 if the clock represented by @hw is enabled in the 2768c2ecf20Sopenharmony_ci * hardware, or 0 otherwise. Intended for use in the struct 2778c2ecf20Sopenharmony_ci * clk_ops.is_enabled function pointer. 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ciint omap2_dflt_clk_is_enabled(struct clk_hw *hw) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct clk_hw_omap *clk = to_clk_hw_omap(hw); 2828c2ecf20Sopenharmony_ci u32 v; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci v = ti_clk_ll_ops->clk_readl(&clk->enable_reg); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (clk->flags & INVERT_ENABLE) 2878c2ecf20Sopenharmony_ci v ^= BIT(clk->enable_bit); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci v &= BIT(clk->enable_bit); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return v ? 1 : 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_wait = { 2958c2ecf20Sopenharmony_ci .find_idlest = omap2_clk_dflt_find_idlest, 2968c2ecf20Sopenharmony_ci .find_companion = omap2_clk_dflt_find_companion, 2978c2ecf20Sopenharmony_ci}; 298