12ace831fSPaul Walmsley /* 22ace831fSPaul Walmsley * OMAP4 CM instance functions 32ace831fSPaul Walmsley * 42ace831fSPaul Walmsley * Copyright (C) 2009 Nokia Corporation 54bd5259eSPaul Walmsley * Copyright (C) 2008-2011 Texas Instruments, Inc. 62ace831fSPaul Walmsley * Paul Walmsley 74bd5259eSPaul Walmsley * Rajendra Nayak <rnayak@ti.com> 82ace831fSPaul Walmsley * 92ace831fSPaul Walmsley * This program is free software; you can redistribute it and/or modify 102ace831fSPaul Walmsley * it under the terms of the GNU General Public License version 2 as 112ace831fSPaul Walmsley * published by the Free Software Foundation. 122ace831fSPaul Walmsley * 132ace831fSPaul Walmsley * This is needed since CM instances can be in the PRM, PRCM_MPU, CM1, 142ace831fSPaul Walmsley * or CM2 hardware modules. For example, the EMU_CM CM instance is in 152ace831fSPaul Walmsley * the PRM hardware module. What a mess... 162ace831fSPaul Walmsley */ 172ace831fSPaul Walmsley 182ace831fSPaul Walmsley #include <linux/kernel.h> 192ace831fSPaul Walmsley #include <linux/types.h> 202ace831fSPaul Walmsley #include <linux/errno.h> 212ace831fSPaul Walmsley #include <linux/err.h> 222ace831fSPaul Walmsley #include <linux/io.h> 232ace831fSPaul Walmsley 24ee0839c2STony Lindgren #include "iomap.h" 254e65331cSTony Lindgren #include "common.h" 264bd5259eSPaul Walmsley #include "clockdomain.h" 272ace831fSPaul Walmsley #include "cm.h" 282ace831fSPaul Walmsley #include "cm1_44xx.h" 292ace831fSPaul Walmsley #include "cm2_44xx.h" 302ace831fSPaul Walmsley #include "cm44xx.h" 312ace831fSPaul Walmsley #include "cminst44xx.h" 32bd2122caSPaul Walmsley #include "cm-regbits-34xx.h" 332ace831fSPaul Walmsley #include "cm-regbits-44xx.h" 342ace831fSPaul Walmsley #include "prcm44xx.h" 352ace831fSPaul Walmsley #include "prm44xx.h" 362ace831fSPaul Walmsley #include "prcm_mpu44xx.h" 37610eb8c2SR Sricharan #include "prcm-common.h" 382ace831fSPaul Walmsley 39d0f0631dSBenoit Cousson /* 40d0f0631dSBenoit Cousson * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield: 41d0f0631dSBenoit Cousson * 42d0f0631dSBenoit Cousson * 0x0 func: Module is fully functional, including OCP 43d0f0631dSBenoit Cousson * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep 44d0f0631dSBenoit Cousson * abortion 45d0f0631dSBenoit Cousson * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if 46d0f0631dSBenoit Cousson * using separate functional clock 47d0f0631dSBenoit Cousson * 0x3 disabled: Module is disabled and cannot be accessed 48d0f0631dSBenoit Cousson * 49d0f0631dSBenoit Cousson */ 50d0f0631dSBenoit Cousson #define CLKCTRL_IDLEST_FUNCTIONAL 0x0 51d0f0631dSBenoit Cousson #define CLKCTRL_IDLEST_INTRANSITION 0x1 52d0f0631dSBenoit Cousson #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2 53d0f0631dSBenoit Cousson #define CLKCTRL_IDLEST_DISABLED 0x3 54d0f0631dSBenoit Cousson 55610eb8c2SR Sricharan static void __iomem *_cm_bases[OMAP4_MAX_PRCM_PARTITIONS]; 56610eb8c2SR Sricharan 57610eb8c2SR Sricharan /** 58610eb8c2SR Sricharan * omap_cm_base_init - Populates the cm partitions 59610eb8c2SR Sricharan * 60610eb8c2SR Sricharan * Populates the base addresses of the _cm_bases 61610eb8c2SR Sricharan * array used for read/write of cm module registers. 62610eb8c2SR Sricharan */ 63610eb8c2SR Sricharan void omap_cm_base_init(void) 64610eb8c2SR Sricharan { 65610eb8c2SR Sricharan _cm_bases[OMAP4430_PRM_PARTITION] = prm_base; 66610eb8c2SR Sricharan _cm_bases[OMAP4430_CM1_PARTITION] = cm_base; 67610eb8c2SR Sricharan _cm_bases[OMAP4430_CM2_PARTITION] = cm2_base; 68610eb8c2SR Sricharan _cm_bases[OMAP4430_PRCM_MPU_PARTITION] = prcm_mpu_base; 69610eb8c2SR Sricharan } 702ace831fSPaul Walmsley 71d0f0631dSBenoit Cousson /* Private functions */ 72d0f0631dSBenoit Cousson 73d0f0631dSBenoit Cousson /** 74d0f0631dSBenoit Cousson * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield 75d0f0631dSBenoit Cousson * @part: PRCM partition ID that the CM_CLKCTRL register exists in 76d0f0631dSBenoit Cousson * @inst: CM instance register offset (*_INST macro) 77d0f0631dSBenoit Cousson * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 78d0f0631dSBenoit Cousson * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 79d0f0631dSBenoit Cousson * 80d0f0631dSBenoit Cousson * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to 81d0f0631dSBenoit Cousson * bit 0. 82d0f0631dSBenoit Cousson */ 83d0f0631dSBenoit Cousson static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) 84d0f0631dSBenoit Cousson { 85d0f0631dSBenoit Cousson u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs); 86d0f0631dSBenoit Cousson v &= OMAP4430_IDLEST_MASK; 87d0f0631dSBenoit Cousson v >>= OMAP4430_IDLEST_SHIFT; 88d0f0631dSBenoit Cousson return v; 89d0f0631dSBenoit Cousson } 90d0f0631dSBenoit Cousson 91d0f0631dSBenoit Cousson /** 92d0f0631dSBenoit Cousson * _is_module_ready - can module registers be accessed without causing an abort? 93d0f0631dSBenoit Cousson * @part: PRCM partition ID that the CM_CLKCTRL register exists in 94d0f0631dSBenoit Cousson * @inst: CM instance register offset (*_INST macro) 95d0f0631dSBenoit Cousson * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 96d0f0631dSBenoit Cousson * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 97d0f0631dSBenoit Cousson * 98d0f0631dSBenoit Cousson * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either 99d0f0631dSBenoit Cousson * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. 100d0f0631dSBenoit Cousson */ 101d0f0631dSBenoit Cousson static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) 102d0f0631dSBenoit Cousson { 103d0f0631dSBenoit Cousson u32 v; 104d0f0631dSBenoit Cousson 105d0f0631dSBenoit Cousson v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs); 106d0f0631dSBenoit Cousson 107d0f0631dSBenoit Cousson return (v == CLKCTRL_IDLEST_FUNCTIONAL || 108d0f0631dSBenoit Cousson v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; 109d0f0631dSBenoit Cousson } 110d0f0631dSBenoit Cousson 111d0f0631dSBenoit Cousson /* Public functions */ 112d0f0631dSBenoit Cousson 1132ace831fSPaul Walmsley /* Read a register in a CM instance */ 114d3f5d551SAnkur Kishore u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) 1152ace831fSPaul Walmsley { 1162ace831fSPaul Walmsley BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || 1172ace831fSPaul Walmsley part == OMAP4430_INVALID_PRCM_PARTITION || 1182ace831fSPaul Walmsley !_cm_bases[part]); 119edfaf05cSVictor Kamensky return readl_relaxed(_cm_bases[part] + inst + idx); 1202ace831fSPaul Walmsley } 1212ace831fSPaul Walmsley 1222ace831fSPaul Walmsley /* Write into a register in a CM instance */ 123d3f5d551SAnkur Kishore void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) 1242ace831fSPaul Walmsley { 1252ace831fSPaul Walmsley BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || 1262ace831fSPaul Walmsley part == OMAP4430_INVALID_PRCM_PARTITION || 1272ace831fSPaul Walmsley !_cm_bases[part]); 128edfaf05cSVictor Kamensky writel_relaxed(val, _cm_bases[part] + inst + idx); 1292ace831fSPaul Walmsley } 1302ace831fSPaul Walmsley 1312ace831fSPaul Walmsley /* Read-modify-write a register in CM1. Caller must lock */ 132d3f5d551SAnkur Kishore u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, 1332ace831fSPaul Walmsley s16 idx) 1342ace831fSPaul Walmsley { 1352ace831fSPaul Walmsley u32 v; 1362ace831fSPaul Walmsley 1372ace831fSPaul Walmsley v = omap4_cminst_read_inst_reg(part, inst, idx); 1382ace831fSPaul Walmsley v &= ~mask; 1392ace831fSPaul Walmsley v |= bits; 1402ace831fSPaul Walmsley omap4_cminst_write_inst_reg(v, part, inst, idx); 1412ace831fSPaul Walmsley 1422ace831fSPaul Walmsley return v; 1432ace831fSPaul Walmsley } 1442ace831fSPaul Walmsley 145d3f5d551SAnkur Kishore u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) 14604eb7773SRajendra Nayak { 14704eb7773SRajendra Nayak return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx); 14804eb7773SRajendra Nayak } 14904eb7773SRajendra Nayak 150d3f5d551SAnkur Kishore u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) 15104eb7773SRajendra Nayak { 15204eb7773SRajendra Nayak return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx); 15304eb7773SRajendra Nayak } 15404eb7773SRajendra Nayak 15504eb7773SRajendra Nayak u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) 15604eb7773SRajendra Nayak { 15704eb7773SRajendra Nayak u32 v; 15804eb7773SRajendra Nayak 15904eb7773SRajendra Nayak v = omap4_cminst_read_inst_reg(part, inst, idx); 16004eb7773SRajendra Nayak v &= mask; 16104eb7773SRajendra Nayak v >>= __ffs(mask); 16204eb7773SRajendra Nayak 16304eb7773SRajendra Nayak return v; 16404eb7773SRajendra Nayak } 16504eb7773SRajendra Nayak 166bd2122caSPaul Walmsley /* 167bd2122caSPaul Walmsley * 168bd2122caSPaul Walmsley */ 169bd2122caSPaul Walmsley 170bd2122caSPaul Walmsley /** 171bd2122caSPaul Walmsley * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield 172bd2122caSPaul Walmsley * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted) 173bd2122caSPaul Walmsley * @part: PRCM partition ID that the CM_CLKSTCTRL register exists in 174bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 175bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 176bd2122caSPaul Walmsley * 177bd2122caSPaul Walmsley * @c must be the unshifted value for CLKTRCTRL - i.e., this function 178bd2122caSPaul Walmsley * will handle the shift itself. 179bd2122caSPaul Walmsley */ 180d3f5d551SAnkur Kishore static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs) 181bd2122caSPaul Walmsley { 182bd2122caSPaul Walmsley u32 v; 183bd2122caSPaul Walmsley 184bd2122caSPaul Walmsley v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL); 185bd2122caSPaul Walmsley v &= ~OMAP4430_CLKTRCTRL_MASK; 186bd2122caSPaul Walmsley v |= c << OMAP4430_CLKTRCTRL_SHIFT; 187bd2122caSPaul Walmsley omap4_cminst_write_inst_reg(v, part, inst, cdoffs + OMAP4_CM_CLKSTCTRL); 188bd2122caSPaul Walmsley } 189bd2122caSPaul Walmsley 190bd2122caSPaul Walmsley /** 191bd2122caSPaul Walmsley * omap4_cminst_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode? 192bd2122caSPaul Walmsley * @part: PRCM partition ID that the CM_CLKSTCTRL register exists in 193bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 194bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 195bd2122caSPaul Walmsley * 196bd2122caSPaul Walmsley * Returns true if the clockdomain referred to by (@part, @inst, @cdoffs) 197bd2122caSPaul Walmsley * is in hardware-supervised idle mode, or 0 otherwise. 198bd2122caSPaul Walmsley */ 199d3f5d551SAnkur Kishore bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) 200bd2122caSPaul Walmsley { 201bd2122caSPaul Walmsley u32 v; 202bd2122caSPaul Walmsley 203bd2122caSPaul Walmsley v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL); 204bd2122caSPaul Walmsley v &= OMAP4430_CLKTRCTRL_MASK; 205bd2122caSPaul Walmsley v >>= OMAP4430_CLKTRCTRL_SHIFT; 206bd2122caSPaul Walmsley 207bd2122caSPaul Walmsley return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false; 208bd2122caSPaul Walmsley } 209bd2122caSPaul Walmsley 210bd2122caSPaul Walmsley /** 211bd2122caSPaul Walmsley * omap4_cminst_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode 212bd2122caSPaul Walmsley * @part: PRCM partition ID that the clockdomain registers exist in 213bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 214bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 215bd2122caSPaul Walmsley * 216bd2122caSPaul Walmsley * Put a clockdomain referred to by (@part, @inst, @cdoffs) into 217bd2122caSPaul Walmsley * hardware-supervised idle mode. No return value. 218bd2122caSPaul Walmsley */ 219d3f5d551SAnkur Kishore void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) 220bd2122caSPaul Walmsley { 221bd2122caSPaul Walmsley _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs); 222bd2122caSPaul Walmsley } 223bd2122caSPaul Walmsley 224bd2122caSPaul Walmsley /** 225bd2122caSPaul Walmsley * omap4_cminst_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode 226bd2122caSPaul Walmsley * @part: PRCM partition ID that the clockdomain registers exist in 227bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 228bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 229bd2122caSPaul Walmsley * 230bd2122caSPaul Walmsley * Put a clockdomain referred to by (@part, @inst, @cdoffs) into 231bd2122caSPaul Walmsley * software-supervised idle mode, i.e., controlled manually by the 232bd2122caSPaul Walmsley * Linux OMAP clockdomain code. No return value. 233bd2122caSPaul Walmsley */ 234d3f5d551SAnkur Kishore void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) 235bd2122caSPaul Walmsley { 236bd2122caSPaul Walmsley _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs); 237bd2122caSPaul Walmsley } 238bd2122caSPaul Walmsley 239bd2122caSPaul Walmsley /** 240bd2122caSPaul Walmsley * omap4_cminst_clkdm_force_sleep - try to take a clockdomain out of idle 241bd2122caSPaul Walmsley * @part: PRCM partition ID that the clockdomain registers exist in 242bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 243bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 244bd2122caSPaul Walmsley * 245bd2122caSPaul Walmsley * Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle, 246bd2122caSPaul Walmsley * waking it up. No return value. 247bd2122caSPaul Walmsley */ 248d3f5d551SAnkur Kishore void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) 249bd2122caSPaul Walmsley { 250bd2122caSPaul Walmsley _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs); 251bd2122caSPaul Walmsley } 252bd2122caSPaul Walmsley 253bd2122caSPaul Walmsley /* 254bd2122caSPaul Walmsley * 255bd2122caSPaul Walmsley */ 2562ace831fSPaul Walmsley 257f67f04baSDave Gerlach void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) 258f67f04baSDave Gerlach { 259f67f04baSDave Gerlach _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs); 260f67f04baSDave Gerlach } 261f67f04baSDave Gerlach 2622ace831fSPaul Walmsley /** 263d0f0631dSBenoit Cousson * omap4_cminst_wait_module_ready - wait for a module to be in 'func' state 264d0f0631dSBenoit Cousson * @part: PRCM partition ID that the CM_CLKCTRL register exists in 265d0f0631dSBenoit Cousson * @inst: CM instance register offset (*_INST macro) 266d0f0631dSBenoit Cousson * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 267d0f0631dSBenoit Cousson * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 2682ace831fSPaul Walmsley * 2692ace831fSPaul Walmsley * Wait for the module IDLEST to be functional. If the idle state is in any 2702ace831fSPaul Walmsley * the non functional state (trans, idle or disabled), module and thus the 2712ace831fSPaul Walmsley * sysconfig cannot be accessed and will probably lead to an "imprecise 2722ace831fSPaul Walmsley * external abort" 2732ace831fSPaul Walmsley */ 274d0f0631dSBenoit Cousson int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, 275d0f0631dSBenoit Cousson u16 clkctrl_offs) 2762ace831fSPaul Walmsley { 2772ace831fSPaul Walmsley int i = 0; 2782ace831fSPaul Walmsley 279d0f0631dSBenoit Cousson if (!clkctrl_offs) 2802ace831fSPaul Walmsley return 0; 2812ace831fSPaul Walmsley 282d0f0631dSBenoit Cousson omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs), 2832ace831fSPaul Walmsley MAX_MODULE_READY_TIME, i); 2842ace831fSPaul Walmsley 2852ace831fSPaul Walmsley return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 2862ace831fSPaul Walmsley } 2872ace831fSPaul Walmsley 28811b10341SBenoit Cousson /** 28911b10341SBenoit Cousson * omap4_cminst_wait_module_idle - wait for a module to be in 'disabled' 29011b10341SBenoit Cousson * state 29111b10341SBenoit Cousson * @part: PRCM partition ID that the CM_CLKCTRL register exists in 29211b10341SBenoit Cousson * @inst: CM instance register offset (*_INST macro) 29311b10341SBenoit Cousson * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 29411b10341SBenoit Cousson * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 29511b10341SBenoit Cousson * 29611b10341SBenoit Cousson * Wait for the module IDLEST to be disabled. Some PRCM transition, 29711b10341SBenoit Cousson * like reset assertion or parent clock de-activation must wait the 29811b10341SBenoit Cousson * module to be fully disabled. 29911b10341SBenoit Cousson */ 30011b10341SBenoit Cousson int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) 30111b10341SBenoit Cousson { 30211b10341SBenoit Cousson int i = 0; 30311b10341SBenoit Cousson 30411b10341SBenoit Cousson if (!clkctrl_offs) 30511b10341SBenoit Cousson return 0; 30611b10341SBenoit Cousson 30711b10341SBenoit Cousson omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) == 30811b10341SBenoit Cousson CLKCTRL_IDLEST_DISABLED), 309b8f15b7eSPaul Walmsley MAX_MODULE_DISABLE_TIME, i); 31011b10341SBenoit Cousson 311b8f15b7eSPaul Walmsley return (i < MAX_MODULE_DISABLE_TIME) ? 0 : -EBUSY; 31211b10341SBenoit Cousson } 313288d6a16SBenoit Cousson 314288d6a16SBenoit Cousson /** 315288d6a16SBenoit Cousson * omap4_cminst_module_enable - Enable the modulemode inside CLKCTRL 316288d6a16SBenoit Cousson * @mode: Module mode (SW or HW) 317288d6a16SBenoit Cousson * @part: PRCM partition ID that the CM_CLKCTRL register exists in 318288d6a16SBenoit Cousson * @inst: CM instance register offset (*_INST macro) 319288d6a16SBenoit Cousson * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 320288d6a16SBenoit Cousson * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 321288d6a16SBenoit Cousson * 322288d6a16SBenoit Cousson * No return value. 323288d6a16SBenoit Cousson */ 324288d6a16SBenoit Cousson void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, 325288d6a16SBenoit Cousson u16 clkctrl_offs) 326288d6a16SBenoit Cousson { 327288d6a16SBenoit Cousson u32 v; 328288d6a16SBenoit Cousson 329288d6a16SBenoit Cousson v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs); 330288d6a16SBenoit Cousson v &= ~OMAP4430_MODULEMODE_MASK; 331288d6a16SBenoit Cousson v |= mode << OMAP4430_MODULEMODE_SHIFT; 332288d6a16SBenoit Cousson omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs); 333288d6a16SBenoit Cousson } 334288d6a16SBenoit Cousson 335288d6a16SBenoit Cousson /** 336288d6a16SBenoit Cousson * omap4_cminst_module_disable - Disable the module inside CLKCTRL 337288d6a16SBenoit Cousson * @part: PRCM partition ID that the CM_CLKCTRL register exists in 338288d6a16SBenoit Cousson * @inst: CM instance register offset (*_INST macro) 339288d6a16SBenoit Cousson * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 340288d6a16SBenoit Cousson * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) 341288d6a16SBenoit Cousson * 342288d6a16SBenoit Cousson * No return value. 343288d6a16SBenoit Cousson */ 344288d6a16SBenoit Cousson void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, 345288d6a16SBenoit Cousson u16 clkctrl_offs) 346288d6a16SBenoit Cousson { 347288d6a16SBenoit Cousson u32 v; 348288d6a16SBenoit Cousson 349288d6a16SBenoit Cousson v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs); 350288d6a16SBenoit Cousson v &= ~OMAP4430_MODULEMODE_MASK; 351288d6a16SBenoit Cousson omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs); 352288d6a16SBenoit Cousson } 3534bd5259eSPaul Walmsley 3544bd5259eSPaul Walmsley /* 3554bd5259eSPaul Walmsley * Clockdomain low-level functions 3564bd5259eSPaul Walmsley */ 3574bd5259eSPaul Walmsley 3584bd5259eSPaul Walmsley static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1, 3594bd5259eSPaul Walmsley struct clockdomain *clkdm2) 3604bd5259eSPaul Walmsley { 3614bd5259eSPaul Walmsley omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit), 3624bd5259eSPaul Walmsley clkdm1->prcm_partition, 3634bd5259eSPaul Walmsley clkdm1->cm_inst, clkdm1->clkdm_offs + 3644bd5259eSPaul Walmsley OMAP4_CM_STATICDEP); 3654bd5259eSPaul Walmsley return 0; 3664bd5259eSPaul Walmsley } 3674bd5259eSPaul Walmsley 3684bd5259eSPaul Walmsley static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1, 3694bd5259eSPaul Walmsley struct clockdomain *clkdm2) 3704bd5259eSPaul Walmsley { 3714bd5259eSPaul Walmsley omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit), 3724bd5259eSPaul Walmsley clkdm1->prcm_partition, 3734bd5259eSPaul Walmsley clkdm1->cm_inst, clkdm1->clkdm_offs + 3744bd5259eSPaul Walmsley OMAP4_CM_STATICDEP); 3754bd5259eSPaul Walmsley return 0; 3764bd5259eSPaul Walmsley } 3774bd5259eSPaul Walmsley 3784bd5259eSPaul Walmsley static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1, 3794bd5259eSPaul Walmsley struct clockdomain *clkdm2) 3804bd5259eSPaul Walmsley { 3814bd5259eSPaul Walmsley return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition, 3824bd5259eSPaul Walmsley clkdm1->cm_inst, 3834bd5259eSPaul Walmsley clkdm1->clkdm_offs + 3844bd5259eSPaul Walmsley OMAP4_CM_STATICDEP, 3854bd5259eSPaul Walmsley (1 << clkdm2->dep_bit)); 3864bd5259eSPaul Walmsley } 3874bd5259eSPaul Walmsley 3884bd5259eSPaul Walmsley static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm) 3894bd5259eSPaul Walmsley { 3904bd5259eSPaul Walmsley struct clkdm_dep *cd; 3914bd5259eSPaul Walmsley u32 mask = 0; 3924bd5259eSPaul Walmsley 3934bd5259eSPaul Walmsley if (!clkdm->prcm_partition) 3944bd5259eSPaul Walmsley return 0; 3954bd5259eSPaul Walmsley 3964bd5259eSPaul Walmsley for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { 3974bd5259eSPaul Walmsley if (!cd->clkdm) 3984bd5259eSPaul Walmsley continue; /* only happens if data is erroneous */ 3994bd5259eSPaul Walmsley 4004bd5259eSPaul Walmsley mask |= 1 << cd->clkdm->dep_bit; 40192493870SPaul Walmsley cd->wkdep_usecount = 0; 4024bd5259eSPaul Walmsley } 4034bd5259eSPaul Walmsley 4044bd5259eSPaul Walmsley omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition, 4054bd5259eSPaul Walmsley clkdm->cm_inst, clkdm->clkdm_offs + 4064bd5259eSPaul Walmsley OMAP4_CM_STATICDEP); 4074bd5259eSPaul Walmsley return 0; 4084bd5259eSPaul Walmsley } 4094bd5259eSPaul Walmsley 4104bd5259eSPaul Walmsley static int omap4_clkdm_sleep(struct clockdomain *clkdm) 4114bd5259eSPaul Walmsley { 412f67f04baSDave Gerlach if (clkdm->flags & CLKDM_CAN_HWSUP) 4134bd5259eSPaul Walmsley omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition, 414f67f04baSDave Gerlach clkdm->cm_inst, 415f67f04baSDave Gerlach clkdm->clkdm_offs); 416f67f04baSDave Gerlach else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP) 417f67f04baSDave Gerlach omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition, 418f67f04baSDave Gerlach clkdm->cm_inst, 419f67f04baSDave Gerlach clkdm->clkdm_offs); 420f67f04baSDave Gerlach else 421f67f04baSDave Gerlach return -EINVAL; 422f67f04baSDave Gerlach 4234bd5259eSPaul Walmsley return 0; 4244bd5259eSPaul Walmsley } 4254bd5259eSPaul Walmsley 4264bd5259eSPaul Walmsley static int omap4_clkdm_wakeup(struct clockdomain *clkdm) 4274bd5259eSPaul Walmsley { 4284bd5259eSPaul Walmsley omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition, 4294bd5259eSPaul Walmsley clkdm->cm_inst, clkdm->clkdm_offs); 4304bd5259eSPaul Walmsley return 0; 4314bd5259eSPaul Walmsley } 4324bd5259eSPaul Walmsley 4334bd5259eSPaul Walmsley static void omap4_clkdm_allow_idle(struct clockdomain *clkdm) 4344bd5259eSPaul Walmsley { 4354bd5259eSPaul Walmsley omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition, 4364bd5259eSPaul Walmsley clkdm->cm_inst, clkdm->clkdm_offs); 4374bd5259eSPaul Walmsley } 4384bd5259eSPaul Walmsley 4394bd5259eSPaul Walmsley static void omap4_clkdm_deny_idle(struct clockdomain *clkdm) 4404bd5259eSPaul Walmsley { 4414bd5259eSPaul Walmsley if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) 4424bd5259eSPaul Walmsley omap4_clkdm_wakeup(clkdm); 4434bd5259eSPaul Walmsley else 4444bd5259eSPaul Walmsley omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition, 4454bd5259eSPaul Walmsley clkdm->cm_inst, 4464bd5259eSPaul Walmsley clkdm->clkdm_offs); 4474bd5259eSPaul Walmsley } 4484bd5259eSPaul Walmsley 4494bd5259eSPaul Walmsley static int omap4_clkdm_clk_enable(struct clockdomain *clkdm) 4504bd5259eSPaul Walmsley { 4514bd5259eSPaul Walmsley if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) 4524bd5259eSPaul Walmsley return omap4_clkdm_wakeup(clkdm); 4534bd5259eSPaul Walmsley 4544bd5259eSPaul Walmsley return 0; 4554bd5259eSPaul Walmsley } 4564bd5259eSPaul Walmsley 4574bd5259eSPaul Walmsley static int omap4_clkdm_clk_disable(struct clockdomain *clkdm) 4584bd5259eSPaul Walmsley { 4594bd5259eSPaul Walmsley bool hwsup = false; 4604bd5259eSPaul Walmsley 4614bd5259eSPaul Walmsley if (!clkdm->prcm_partition) 4624bd5259eSPaul Walmsley return 0; 4634bd5259eSPaul Walmsley 4644bd5259eSPaul Walmsley /* 4654bd5259eSPaul Walmsley * The CLKDM_MISSING_IDLE_REPORTING flag documentation has 4664bd5259eSPaul Walmsley * more details on the unpleasant problem this is working 4674bd5259eSPaul Walmsley * around 4684bd5259eSPaul Walmsley */ 4694bd5259eSPaul Walmsley if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING && 4704bd5259eSPaul Walmsley !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { 4714bd5259eSPaul Walmsley omap4_clkdm_allow_idle(clkdm); 4724bd5259eSPaul Walmsley return 0; 4734bd5259eSPaul Walmsley } 4744bd5259eSPaul Walmsley 4754bd5259eSPaul Walmsley hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition, 4764bd5259eSPaul Walmsley clkdm->cm_inst, clkdm->clkdm_offs); 4774bd5259eSPaul Walmsley 4784bd5259eSPaul Walmsley if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) 4794bd5259eSPaul Walmsley omap4_clkdm_sleep(clkdm); 4804bd5259eSPaul Walmsley 4814bd5259eSPaul Walmsley return 0; 4824bd5259eSPaul Walmsley } 4834bd5259eSPaul Walmsley 4844bd5259eSPaul Walmsley struct clkdm_ops omap4_clkdm_operations = { 4854bd5259eSPaul Walmsley .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep, 4864bd5259eSPaul Walmsley .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep, 4874bd5259eSPaul Walmsley .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep, 4884bd5259eSPaul Walmsley .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps, 4894bd5259eSPaul Walmsley .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep, 4904bd5259eSPaul Walmsley .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep, 4914bd5259eSPaul Walmsley .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep, 4924bd5259eSPaul Walmsley .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps, 4934bd5259eSPaul Walmsley .clkdm_sleep = omap4_clkdm_sleep, 4944bd5259eSPaul Walmsley .clkdm_wakeup = omap4_clkdm_wakeup, 4954bd5259eSPaul Walmsley .clkdm_allow_idle = omap4_clkdm_allow_idle, 4964bd5259eSPaul Walmsley .clkdm_deny_idle = omap4_clkdm_deny_idle, 4974bd5259eSPaul Walmsley .clkdm_clk_enable = omap4_clkdm_clk_enable, 4984bd5259eSPaul Walmsley .clkdm_clk_disable = omap4_clkdm_clk_disable, 4994bd5259eSPaul Walmsley }; 500c9218fe6SAmbresh K 501c9218fe6SAmbresh K struct clkdm_ops am43xx_clkdm_operations = { 502c9218fe6SAmbresh K .clkdm_sleep = omap4_clkdm_sleep, 503c9218fe6SAmbresh K .clkdm_wakeup = omap4_clkdm_wakeup, 504c9218fe6SAmbresh K .clkdm_allow_idle = omap4_clkdm_allow_idle, 505c9218fe6SAmbresh K .clkdm_deny_idle = omap4_clkdm_deny_idle, 506c9218fe6SAmbresh K .clkdm_clk_enable = omap4_clkdm_clk_enable, 507c9218fe6SAmbresh K .clkdm_clk_disable = omap4_clkdm_clk_disable, 508c9218fe6SAmbresh K }; 509