12ace831fSPaul Walmsley /* 22ace831fSPaul Walmsley * OMAP4 CM instance functions 32ace831fSPaul Walmsley * 42ace831fSPaul Walmsley * Copyright (C) 2009 Nokia Corporation 52ace831fSPaul Walmsley * Paul Walmsley 62ace831fSPaul Walmsley * 72ace831fSPaul Walmsley * This program is free software; you can redistribute it and/or modify 82ace831fSPaul Walmsley * it under the terms of the GNU General Public License version 2 as 92ace831fSPaul Walmsley * published by the Free Software Foundation. 102ace831fSPaul Walmsley * 112ace831fSPaul Walmsley * This is needed since CM instances can be in the PRM, PRCM_MPU, CM1, 122ace831fSPaul Walmsley * or CM2 hardware modules. For example, the EMU_CM CM instance is in 132ace831fSPaul Walmsley * the PRM hardware module. What a mess... 142ace831fSPaul Walmsley */ 152ace831fSPaul Walmsley 162ace831fSPaul Walmsley #include <linux/kernel.h> 172ace831fSPaul Walmsley #include <linux/types.h> 182ace831fSPaul Walmsley #include <linux/errno.h> 192ace831fSPaul Walmsley #include <linux/err.h> 202ace831fSPaul Walmsley #include <linux/io.h> 212ace831fSPaul Walmsley 222ace831fSPaul Walmsley #include <plat/common.h> 232ace831fSPaul Walmsley 242ace831fSPaul Walmsley #include "cm.h" 252ace831fSPaul Walmsley #include "cm1_44xx.h" 262ace831fSPaul Walmsley #include "cm2_44xx.h" 272ace831fSPaul Walmsley #include "cm44xx.h" 282ace831fSPaul Walmsley #include "cminst44xx.h" 29bd2122caSPaul Walmsley #include "cm-regbits-34xx.h" 302ace831fSPaul Walmsley #include "cm-regbits-44xx.h" 312ace831fSPaul Walmsley #include "prcm44xx.h" 322ace831fSPaul Walmsley #include "prm44xx.h" 332ace831fSPaul Walmsley #include "prcm_mpu44xx.h" 342ace831fSPaul Walmsley 352ace831fSPaul Walmsley static u32 _cm_bases[OMAP4_MAX_PRCM_PARTITIONS] = { 362ace831fSPaul Walmsley [OMAP4430_INVALID_PRCM_PARTITION] = 0, 372ace831fSPaul Walmsley [OMAP4430_PRM_PARTITION] = OMAP4430_PRM_BASE, 382ace831fSPaul Walmsley [OMAP4430_CM1_PARTITION] = OMAP4430_CM1_BASE, 392ace831fSPaul Walmsley [OMAP4430_CM2_PARTITION] = OMAP4430_CM2_BASE, 402ace831fSPaul Walmsley [OMAP4430_SCRM_PARTITION] = 0, 412ace831fSPaul Walmsley [OMAP4430_PRCM_MPU_PARTITION] = OMAP4430_PRCM_MPU_BASE, 422ace831fSPaul Walmsley }; 432ace831fSPaul Walmsley 442ace831fSPaul Walmsley /* Read a register in a CM instance */ 452ace831fSPaul Walmsley u32 omap4_cminst_read_inst_reg(u8 part, s16 inst, u16 idx) 462ace831fSPaul Walmsley { 472ace831fSPaul Walmsley BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || 482ace831fSPaul Walmsley part == OMAP4430_INVALID_PRCM_PARTITION || 492ace831fSPaul Walmsley !_cm_bases[part]); 502ace831fSPaul Walmsley return __raw_readl(OMAP2_L4_IO_ADDRESS(_cm_bases[part] + inst + idx)); 512ace831fSPaul Walmsley } 522ace831fSPaul Walmsley 532ace831fSPaul Walmsley /* Write into a register in a CM instance */ 542ace831fSPaul Walmsley void omap4_cminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx) 552ace831fSPaul Walmsley { 562ace831fSPaul Walmsley BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || 572ace831fSPaul Walmsley part == OMAP4430_INVALID_PRCM_PARTITION || 582ace831fSPaul Walmsley !_cm_bases[part]); 592ace831fSPaul Walmsley __raw_writel(val, OMAP2_L4_IO_ADDRESS(_cm_bases[part] + inst + idx)); 602ace831fSPaul Walmsley } 612ace831fSPaul Walmsley 622ace831fSPaul Walmsley /* Read-modify-write a register in CM1. Caller must lock */ 632ace831fSPaul Walmsley u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst, 642ace831fSPaul Walmsley s16 idx) 652ace831fSPaul Walmsley { 662ace831fSPaul Walmsley u32 v; 672ace831fSPaul Walmsley 682ace831fSPaul Walmsley v = omap4_cminst_read_inst_reg(part, inst, idx); 692ace831fSPaul Walmsley v &= ~mask; 702ace831fSPaul Walmsley v |= bits; 712ace831fSPaul Walmsley omap4_cminst_write_inst_reg(v, part, inst, idx); 722ace831fSPaul Walmsley 732ace831fSPaul Walmsley return v; 742ace831fSPaul Walmsley } 752ace831fSPaul Walmsley 7604eb7773SRajendra Nayak u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, s16 inst, s16 idx) 7704eb7773SRajendra Nayak { 7804eb7773SRajendra Nayak return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx); 7904eb7773SRajendra Nayak } 8004eb7773SRajendra Nayak 8104eb7773SRajendra Nayak u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, s16 inst, s16 idx) 8204eb7773SRajendra Nayak { 8304eb7773SRajendra Nayak return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx); 8404eb7773SRajendra Nayak } 8504eb7773SRajendra Nayak 8604eb7773SRajendra Nayak u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) 8704eb7773SRajendra Nayak { 8804eb7773SRajendra Nayak u32 v; 8904eb7773SRajendra Nayak 9004eb7773SRajendra Nayak v = omap4_cminst_read_inst_reg(part, inst, idx); 9104eb7773SRajendra Nayak v &= mask; 9204eb7773SRajendra Nayak v >>= __ffs(mask); 9304eb7773SRajendra Nayak 9404eb7773SRajendra Nayak return v; 9504eb7773SRajendra Nayak } 9604eb7773SRajendra Nayak 97bd2122caSPaul Walmsley /* 98bd2122caSPaul Walmsley * 99bd2122caSPaul Walmsley */ 100bd2122caSPaul Walmsley 101bd2122caSPaul Walmsley /** 102bd2122caSPaul Walmsley * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield 103bd2122caSPaul Walmsley * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted) 104bd2122caSPaul Walmsley * @part: PRCM partition ID that the CM_CLKSTCTRL register exists in 105bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 106bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 107bd2122caSPaul Walmsley * 108bd2122caSPaul Walmsley * @c must be the unshifted value for CLKTRCTRL - i.e., this function 109bd2122caSPaul Walmsley * will handle the shift itself. 110bd2122caSPaul Walmsley */ 111bd2122caSPaul Walmsley static void _clktrctrl_write(u8 c, u8 part, s16 inst, u16 cdoffs) 112bd2122caSPaul Walmsley { 113bd2122caSPaul Walmsley u32 v; 114bd2122caSPaul Walmsley 115bd2122caSPaul Walmsley v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL); 116bd2122caSPaul Walmsley v &= ~OMAP4430_CLKTRCTRL_MASK; 117bd2122caSPaul Walmsley v |= c << OMAP4430_CLKTRCTRL_SHIFT; 118bd2122caSPaul Walmsley omap4_cminst_write_inst_reg(v, part, inst, cdoffs + OMAP4_CM_CLKSTCTRL); 119bd2122caSPaul Walmsley } 120bd2122caSPaul Walmsley 121bd2122caSPaul Walmsley /** 122bd2122caSPaul Walmsley * omap4_cminst_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode? 123bd2122caSPaul Walmsley * @part: PRCM partition ID that the CM_CLKSTCTRL register exists in 124bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 125bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 126bd2122caSPaul Walmsley * 127bd2122caSPaul Walmsley * Returns true if the clockdomain referred to by (@part, @inst, @cdoffs) 128bd2122caSPaul Walmsley * is in hardware-supervised idle mode, or 0 otherwise. 129bd2122caSPaul Walmsley */ 130bd2122caSPaul Walmsley bool omap4_cminst_is_clkdm_in_hwsup(u8 part, s16 inst, u16 cdoffs) 131bd2122caSPaul Walmsley { 132bd2122caSPaul Walmsley u32 v; 133bd2122caSPaul Walmsley 134bd2122caSPaul Walmsley v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL); 135bd2122caSPaul Walmsley v &= OMAP4430_CLKTRCTRL_MASK; 136bd2122caSPaul Walmsley v >>= OMAP4430_CLKTRCTRL_SHIFT; 137bd2122caSPaul Walmsley 138bd2122caSPaul Walmsley return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false; 139bd2122caSPaul Walmsley } 140bd2122caSPaul Walmsley 141bd2122caSPaul Walmsley /** 142bd2122caSPaul Walmsley * omap4_cminst_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode 143bd2122caSPaul Walmsley * @part: PRCM partition ID that the clockdomain registers exist in 144bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 145bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 146bd2122caSPaul Walmsley * 147bd2122caSPaul Walmsley * Put a clockdomain referred to by (@part, @inst, @cdoffs) into 148bd2122caSPaul Walmsley * hardware-supervised idle mode. No return value. 149bd2122caSPaul Walmsley */ 150bd2122caSPaul Walmsley void omap4_cminst_clkdm_enable_hwsup(u8 part, s16 inst, u16 cdoffs) 151bd2122caSPaul Walmsley { 152bd2122caSPaul Walmsley _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs); 153bd2122caSPaul Walmsley } 154bd2122caSPaul Walmsley 155bd2122caSPaul Walmsley /** 156bd2122caSPaul Walmsley * omap4_cminst_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode 157bd2122caSPaul Walmsley * @part: PRCM partition ID that the clockdomain registers exist in 158bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 159bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 160bd2122caSPaul Walmsley * 161bd2122caSPaul Walmsley * Put a clockdomain referred to by (@part, @inst, @cdoffs) into 162bd2122caSPaul Walmsley * software-supervised idle mode, i.e., controlled manually by the 163bd2122caSPaul Walmsley * Linux OMAP clockdomain code. No return value. 164bd2122caSPaul Walmsley */ 165bd2122caSPaul Walmsley void omap4_cminst_clkdm_disable_hwsup(u8 part, s16 inst, u16 cdoffs) 166bd2122caSPaul Walmsley { 167bd2122caSPaul Walmsley _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs); 168bd2122caSPaul Walmsley } 169bd2122caSPaul Walmsley 170bd2122caSPaul Walmsley /** 171bd2122caSPaul Walmsley * omap4_cminst_clkdm_force_sleep - try to put a clockdomain into idle 172bd2122caSPaul Walmsley * @part: PRCM partition ID that the clockdomain registers exist in 173bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 174bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 175bd2122caSPaul Walmsley * 176bd2122caSPaul Walmsley * Put a clockdomain referred to by (@part, @inst, @cdoffs) into idle 177bd2122caSPaul Walmsley * No return value. 178bd2122caSPaul Walmsley */ 179bd2122caSPaul Walmsley void omap4_cminst_clkdm_force_sleep(u8 part, s16 inst, u16 cdoffs) 180bd2122caSPaul Walmsley { 181bd2122caSPaul Walmsley _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs); 182bd2122caSPaul Walmsley } 183bd2122caSPaul Walmsley 184bd2122caSPaul Walmsley /** 185bd2122caSPaul Walmsley * omap4_cminst_clkdm_force_sleep - try to take a clockdomain out of idle 186bd2122caSPaul Walmsley * @part: PRCM partition ID that the clockdomain registers exist in 187bd2122caSPaul Walmsley * @inst: CM instance register offset (*_INST macro) 188bd2122caSPaul Walmsley * @cdoffs: Clockdomain register offset (*_CDOFFS macro) 189bd2122caSPaul Walmsley * 190bd2122caSPaul Walmsley * Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle, 191bd2122caSPaul Walmsley * waking it up. No return value. 192bd2122caSPaul Walmsley */ 193bd2122caSPaul Walmsley void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs) 194bd2122caSPaul Walmsley { 195bd2122caSPaul Walmsley _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs); 196bd2122caSPaul Walmsley } 197bd2122caSPaul Walmsley 198bd2122caSPaul Walmsley /* 199bd2122caSPaul Walmsley * 200bd2122caSPaul Walmsley */ 2012ace831fSPaul Walmsley 2022ace831fSPaul Walmsley /** 2032ace831fSPaul Walmsley * omap4_cm_wait_module_ready - wait for a module to be in 'func' state 2042ace831fSPaul Walmsley * @clkctrl_reg: CLKCTRL module address 2052ace831fSPaul Walmsley * 2062ace831fSPaul Walmsley * Wait for the module IDLEST to be functional. If the idle state is in any 2072ace831fSPaul Walmsley * the non functional state (trans, idle or disabled), module and thus the 2082ace831fSPaul Walmsley * sysconfig cannot be accessed and will probably lead to an "imprecise 2092ace831fSPaul Walmsley * external abort" 2102ace831fSPaul Walmsley * 2112ace831fSPaul Walmsley * Module idle state: 2122ace831fSPaul Walmsley * 0x0 func: Module is fully functional, including OCP 2132ace831fSPaul Walmsley * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep 2142ace831fSPaul Walmsley * abortion 2152ace831fSPaul Walmsley * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if 2162ace831fSPaul Walmsley * using separate functional clock 2172ace831fSPaul Walmsley * 0x3 disabled: Module is disabled and cannot be accessed 2182ace831fSPaul Walmsley * 2192ace831fSPaul Walmsley */ 2202ace831fSPaul Walmsley int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg) 2212ace831fSPaul Walmsley { 2222ace831fSPaul Walmsley int i = 0; 2232ace831fSPaul Walmsley 2242ace831fSPaul Walmsley if (!clkctrl_reg) 2252ace831fSPaul Walmsley return 0; 2262ace831fSPaul Walmsley 2272ace831fSPaul Walmsley omap_test_timeout(( 2282ace831fSPaul Walmsley ((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) == 0) || 2292ace831fSPaul Walmsley (((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) >> 2302ace831fSPaul Walmsley OMAP4430_IDLEST_SHIFT) == 0x2)), 2312ace831fSPaul Walmsley MAX_MODULE_READY_TIME, i); 2322ace831fSPaul Walmsley 2332ace831fSPaul Walmsley return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 2342ace831fSPaul Walmsley } 2352ace831fSPaul Walmsley 236