1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20be1621aSBenoît Cousson /*
30be1621aSBenoît Cousson * OMAP4 PRM module functions
40be1621aSBenoît Cousson *
52bb2a5d3SPaul Walmsley * Copyright (C) 2011-2012 Texas Instruments, Inc.
60be1621aSBenoît Cousson * Copyright (C) 2010 Nokia Corporation
70be1621aSBenoît Cousson * Benoît Cousson
80be1621aSBenoît Cousson * Paul Walmsley
949815399SPaul Walmsley * Rajendra Nayak <rnayak@ti.com>
100be1621aSBenoît Cousson */
110be1621aSBenoît Cousson
12a9f73632SKeerthy #include <linux/cpu_pm.h>
130be1621aSBenoît Cousson #include <linux/kernel.h>
140be1621aSBenoît Cousson #include <linux/delay.h>
150be1621aSBenoît Cousson #include <linux/errno.h>
160be1621aSBenoît Cousson #include <linux/err.h>
172ace831fSPaul Walmsley #include <linux/io.h>
18a8f83aefSNishanth Menon #include <linux/of_irq.h>
19cc843711SKeerthy #include <linux/of.h>
200be1621aSBenoît Cousson
21dbc04161STony Lindgren #include "soc.h"
22ee0839c2STony Lindgren #include "iomap.h"
23ee0839c2STony Lindgren #include "common.h"
2458aaa599SKevin Hilman #include "vp.h"
25d198b514SPaul Walmsley #include "prm44xx.h"
26cc843711SKeerthy #include "prcm43xx.h"
270be1621aSBenoît Cousson #include "prm-regbits-44xx.h"
284bb73adeSKevin Hilman #include "prcm44xx.h"
294bb73adeSKevin Hilman #include "prminst44xx.h"
3049815399SPaul Walmsley #include "powerdomain.h"
31a9f73632SKeerthy #include "pm.h"
320be1621aSBenoît Cousson
332bb2a5d3SPaul Walmsley /* Static data */
342bb2a5d3SPaul Walmsley
3528db51f4STero Kristo static void omap44xx_prm_read_pending_irqs(unsigned long *events);
3628db51f4STero Kristo static void omap44xx_prm_ocp_barrier(void);
3728db51f4STero Kristo static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
3828db51f4STero Kristo static void omap44xx_prm_restore_irqen(u32 *saved_mask);
394984eeafSTero Kristo static void omap44xx_prm_reconfigure_io_chain(void);
4028db51f4STero Kristo
412f31b516STero Kristo static const struct omap_prcm_irq omap4_prcm_irqs[] = {
422f31b516STero Kristo OMAP_PRCM_IRQ("io", 9, 1),
432f31b516STero Kristo };
442f31b516STero Kristo
452f31b516STero Kristo static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
462f31b516STero Kristo .ack = OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
472f31b516STero Kristo .mask = OMAP4_PRM_IRQENABLE_MPU_OFFSET,
48fac03f12SKeerthy .pm_ctrl = OMAP4_PRM_IO_PMCTRL_OFFSET,
492f31b516STero Kristo .nr_regs = 2,
502f31b516STero Kristo .irqs = omap4_prcm_irqs,
512f31b516STero Kristo .nr_irqs = ARRAY_SIZE(omap4_prcm_irqs),
522f31b516STero Kristo .read_pending_irqs = &omap44xx_prm_read_pending_irqs,
532f31b516STero Kristo .ocp_barrier = &omap44xx_prm_ocp_barrier,
542f31b516STero Kristo .save_and_clear_irqen = &omap44xx_prm_save_and_clear_irqen,
552f31b516STero Kristo .restore_irqen = &omap44xx_prm_restore_irqen,
5681243651STero Kristo .reconfigure_io_chain = &omap44xx_prm_reconfigure_io_chain,
572f31b516STero Kristo };
582f31b516STero Kristo
59e37fbf05SDave Gerlach struct omap_prm_irq_context {
60e37fbf05SDave Gerlach unsigned long irq_enable;
61e37fbf05SDave Gerlach unsigned long pm_ctrl;
62e37fbf05SDave Gerlach };
63e37fbf05SDave Gerlach
64e37fbf05SDave Gerlach static struct omap_prm_irq_context omap_prm_context;
65e37fbf05SDave Gerlach
662bb2a5d3SPaul Walmsley /*
672bb2a5d3SPaul Walmsley * omap44xx_prm_reset_src_map - map from bits in the PRM_RSTST
682bb2a5d3SPaul Walmsley * hardware register (which are specific to OMAP44xx SoCs) to reset
692bb2a5d3SPaul Walmsley * source ID bit shifts (which is an OMAP SoC-independent
702bb2a5d3SPaul Walmsley * enumeration)
712bb2a5d3SPaul Walmsley */
722bb2a5d3SPaul Walmsley static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = {
7362bafd1aSIvan Khoronzhuk { OMAP4430_GLOBAL_WARM_SW_RST_SHIFT,
742bb2a5d3SPaul Walmsley OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT },
7562bafd1aSIvan Khoronzhuk { OMAP4430_GLOBAL_COLD_RST_SHIFT,
762bb2a5d3SPaul Walmsley OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT },
772bb2a5d3SPaul Walmsley { OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT,
782bb2a5d3SPaul Walmsley OMAP_SECU_VIOL_RST_SRC_ID_SHIFT },
792bb2a5d3SPaul Walmsley { OMAP4430_MPU_WDT_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT },
802bb2a5d3SPaul Walmsley { OMAP4430_SECURE_WDT_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT },
812bb2a5d3SPaul Walmsley { OMAP4430_EXTERNAL_WARM_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT },
822bb2a5d3SPaul Walmsley { OMAP4430_VDD_MPU_VOLT_MGR_RST_SHIFT,
832bb2a5d3SPaul Walmsley OMAP_VDD_MPU_VM_RST_SRC_ID_SHIFT },
842bb2a5d3SPaul Walmsley { OMAP4430_VDD_IVA_VOLT_MGR_RST_SHIFT,
852bb2a5d3SPaul Walmsley OMAP_VDD_IVA_VM_RST_SRC_ID_SHIFT },
862bb2a5d3SPaul Walmsley { OMAP4430_VDD_CORE_VOLT_MGR_RST_SHIFT,
872bb2a5d3SPaul Walmsley OMAP_VDD_CORE_VM_RST_SRC_ID_SHIFT },
882bb2a5d3SPaul Walmsley { OMAP4430_ICEPICK_RST_SHIFT, OMAP_ICEPICK_RST_SRC_ID_SHIFT },
892bb2a5d3SPaul Walmsley { OMAP4430_C2C_RST_SHIFT, OMAP_C2C_RST_SRC_ID_SHIFT },
902bb2a5d3SPaul Walmsley { -1, -1 },
912bb2a5d3SPaul Walmsley };
922bb2a5d3SPaul Walmsley
932ace831fSPaul Walmsley /* PRM low-level functions */
942ace831fSPaul Walmsley
952ace831fSPaul Walmsley /* Read a register in a CM/PRM instance in the PRM module */
omap4_prm_read_inst_reg(s16 inst,u16 reg)96f3f220f0STero Kristo static u32 omap4_prm_read_inst_reg(s16 inst, u16 reg)
972ace831fSPaul Walmsley {
9890129336STero Kristo return readl_relaxed(prm_base.va + inst + reg);
992ace831fSPaul Walmsley }
1002ace831fSPaul Walmsley
1012ace831fSPaul Walmsley /* Write into a register in a CM/PRM instance in the PRM module */
omap4_prm_write_inst_reg(u32 val,s16 inst,u16 reg)102f3f220f0STero Kristo static void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg)
1032ace831fSPaul Walmsley {
10490129336STero Kristo writel_relaxed(val, prm_base.va + inst + reg);
1052ace831fSPaul Walmsley }
1062ace831fSPaul Walmsley
1072ace831fSPaul Walmsley /* Read-modify-write a register in a PRM module. Caller must lock */
omap4_prm_rmw_inst_reg_bits(u32 mask,u32 bits,s16 inst,s16 reg)108f3f220f0STero Kristo static u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg)
1092ace831fSPaul Walmsley {
1102ace831fSPaul Walmsley u32 v;
1112ace831fSPaul Walmsley
1122ace831fSPaul Walmsley v = omap4_prm_read_inst_reg(inst, reg);
1132ace831fSPaul Walmsley v &= ~mask;
1142ace831fSPaul Walmsley v |= bits;
1152ace831fSPaul Walmsley omap4_prm_write_inst_reg(v, inst, reg);
1162ace831fSPaul Walmsley
1172ace831fSPaul Walmsley return v;
1182ace831fSPaul Walmsley }
11958aaa599SKevin Hilman
12058aaa599SKevin Hilman /* PRM VP */
12158aaa599SKevin Hilman
12258aaa599SKevin Hilman /*
12358aaa599SKevin Hilman * struct omap4_vp - OMAP4 VP register access description.
12458aaa599SKevin Hilman * @irqstatus_mpu: offset to IRQSTATUS_MPU register for VP
12558aaa599SKevin Hilman * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg
12658aaa599SKevin Hilman */
12758aaa599SKevin Hilman struct omap4_vp {
12858aaa599SKevin Hilman u32 irqstatus_mpu;
12958aaa599SKevin Hilman u32 tranxdone_status;
13058aaa599SKevin Hilman };
13158aaa599SKevin Hilman
13258aaa599SKevin Hilman static struct omap4_vp omap4_vp[] = {
13358aaa599SKevin Hilman [OMAP4_VP_VDD_MPU_ID] = {
13458aaa599SKevin Hilman .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET,
13558aaa599SKevin Hilman .tranxdone_status = OMAP4430_VP_MPU_TRANXDONE_ST_MASK,
13658aaa599SKevin Hilman },
13758aaa599SKevin Hilman [OMAP4_VP_VDD_IVA_ID] = {
13858aaa599SKevin Hilman .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
13958aaa599SKevin Hilman .tranxdone_status = OMAP4430_VP_IVA_TRANXDONE_ST_MASK,
14058aaa599SKevin Hilman },
14158aaa599SKevin Hilman [OMAP4_VP_VDD_CORE_ID] = {
14258aaa599SKevin Hilman .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
14358aaa599SKevin Hilman .tranxdone_status = OMAP4430_VP_CORE_TRANXDONE_ST_MASK,
14458aaa599SKevin Hilman },
14558aaa599SKevin Hilman };
14658aaa599SKevin Hilman
omap4_prm_vp_check_txdone(u8 vp_id)147e9f1ddcdSTero Kristo static u32 omap4_prm_vp_check_txdone(u8 vp_id)
14858aaa599SKevin Hilman {
14958aaa599SKevin Hilman struct omap4_vp *vp = &omap4_vp[vp_id];
15058aaa599SKevin Hilman u32 irqstatus;
15158aaa599SKevin Hilman
15258aaa599SKevin Hilman irqstatus = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
15358aaa599SKevin Hilman OMAP4430_PRM_OCP_SOCKET_INST,
15458aaa599SKevin Hilman vp->irqstatus_mpu);
15558aaa599SKevin Hilman return irqstatus & vp->tranxdone_status;
15658aaa599SKevin Hilman }
15758aaa599SKevin Hilman
omap4_prm_vp_clear_txdone(u8 vp_id)158e9f1ddcdSTero Kristo static void omap4_prm_vp_clear_txdone(u8 vp_id)
15958aaa599SKevin Hilman {
16058aaa599SKevin Hilman struct omap4_vp *vp = &omap4_vp[vp_id];
16158aaa599SKevin Hilman
16258aaa599SKevin Hilman omap4_prminst_write_inst_reg(vp->tranxdone_status,
16358aaa599SKevin Hilman OMAP4430_PRM_PARTITION,
16458aaa599SKevin Hilman OMAP4430_PRM_OCP_SOCKET_INST,
16558aaa599SKevin Hilman vp->irqstatus_mpu);
16658aaa599SKevin Hilman };
1674bb73adeSKevin Hilman
omap4_prm_vcvp_read(u8 offset)1684bb73adeSKevin Hilman u32 omap4_prm_vcvp_read(u8 offset)
1694bb73adeSKevin Hilman {
170390ddc19SNishanth Menon s32 inst = omap4_prmst_get_prm_dev_inst();
171390ddc19SNishanth Menon
172390ddc19SNishanth Menon if (inst == PRM_INSTANCE_UNKNOWN)
173390ddc19SNishanth Menon return 0;
174390ddc19SNishanth Menon
1754bb73adeSKevin Hilman return omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
176390ddc19SNishanth Menon inst, offset);
1774bb73adeSKevin Hilman }
1784bb73adeSKevin Hilman
omap4_prm_vcvp_write(u32 val,u8 offset)1794bb73adeSKevin Hilman void omap4_prm_vcvp_write(u32 val, u8 offset)
1804bb73adeSKevin Hilman {
181390ddc19SNishanth Menon s32 inst = omap4_prmst_get_prm_dev_inst();
182390ddc19SNishanth Menon
183390ddc19SNishanth Menon if (inst == PRM_INSTANCE_UNKNOWN)
184390ddc19SNishanth Menon return;
185390ddc19SNishanth Menon
1864bb73adeSKevin Hilman omap4_prminst_write_inst_reg(val, OMAP4430_PRM_PARTITION,
187390ddc19SNishanth Menon inst, offset);
1884bb73adeSKevin Hilman }
1894bb73adeSKevin Hilman
omap4_prm_vcvp_rmw(u32 mask,u32 bits,u8 offset)1904bb73adeSKevin Hilman u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
1914bb73adeSKevin Hilman {
192390ddc19SNishanth Menon s32 inst = omap4_prmst_get_prm_dev_inst();
193390ddc19SNishanth Menon
194390ddc19SNishanth Menon if (inst == PRM_INSTANCE_UNKNOWN)
195390ddc19SNishanth Menon return 0;
196390ddc19SNishanth Menon
1974bb73adeSKevin Hilman return omap4_prminst_rmw_inst_reg_bits(mask, bits,
1984bb73adeSKevin Hilman OMAP4430_PRM_PARTITION,
199390ddc19SNishanth Menon inst,
2004bb73adeSKevin Hilman offset);
2014bb73adeSKevin Hilman }
20226c98c56SPaul Walmsley
_read_pending_irq_reg(u16 irqen_offs,u16 irqst_offs)20326c98c56SPaul Walmsley static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs)
20426c98c56SPaul Walmsley {
20526c98c56SPaul Walmsley u32 mask, st;
20626c98c56SPaul Walmsley
20726c98c56SPaul Walmsley /* XXX read mask from RAM? */
208553e3222STero Kristo mask = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
209553e3222STero Kristo irqen_offs);
210553e3222STero Kristo st = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, irqst_offs);
21126c98c56SPaul Walmsley
21226c98c56SPaul Walmsley return mask & st;
21326c98c56SPaul Walmsley }
21426c98c56SPaul Walmsley
21526c98c56SPaul Walmsley /**
21626c98c56SPaul Walmsley * omap44xx_prm_read_pending_irqs - read pending PRM MPU IRQs into @events
21726c98c56SPaul Walmsley * @events: ptr to two consecutive u32s, preallocated by caller
21826c98c56SPaul Walmsley *
21926c98c56SPaul Walmsley * Read PRM_IRQSTATUS_MPU* bits, AND'ed with the currently-enabled PRM
22026c98c56SPaul Walmsley * MPU IRQs, and store the result into the two u32s pointed to by @events.
22126c98c56SPaul Walmsley * No return value.
22226c98c56SPaul Walmsley */
omap44xx_prm_read_pending_irqs(unsigned long * events)22328db51f4STero Kristo static void omap44xx_prm_read_pending_irqs(unsigned long *events)
22426c98c56SPaul Walmsley {
2258d4be7d8SKeerthy int i;
22626c98c56SPaul Walmsley
2278d4be7d8SKeerthy for (i = 0; i < omap4_prcm_irq_setup.nr_regs; i++)
2288d4be7d8SKeerthy events[i] = _read_pending_irq_reg(omap4_prcm_irq_setup.mask +
2298d4be7d8SKeerthy i * 4, omap4_prcm_irq_setup.ack + i * 4);
23026c98c56SPaul Walmsley }
23126c98c56SPaul Walmsley
23226c98c56SPaul Walmsley /**
23326c98c56SPaul Walmsley * omap44xx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete
23426c98c56SPaul Walmsley *
23526c98c56SPaul Walmsley * Force any buffered writes to the PRM IP block to complete. Needed
23626c98c56SPaul Walmsley * by the PRM IRQ handler, which reads and writes directly to the IP
23726c98c56SPaul Walmsley * block, to avoid race conditions after acknowledging or clearing IRQ
23826c98c56SPaul Walmsley * bits. No return value.
23926c98c56SPaul Walmsley */
omap44xx_prm_ocp_barrier(void)24028db51f4STero Kristo static void omap44xx_prm_ocp_barrier(void)
24126c98c56SPaul Walmsley {
242553e3222STero Kristo omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
24326c98c56SPaul Walmsley OMAP4_REVISION_PRM_OFFSET);
24426c98c56SPaul Walmsley }
24591285b6fSTero Kristo
24691285b6fSTero Kristo /**
24791285b6fSTero Kristo * omap44xx_prm_save_and_clear_irqen - save/clear PRM_IRQENABLE_MPU* regs
24891285b6fSTero Kristo * @saved_mask: ptr to a u32 array to save IRQENABLE bits
24991285b6fSTero Kristo *
25091285b6fSTero Kristo * Save the PRM_IRQENABLE_MPU and PRM_IRQENABLE_MPU_2 registers to
25191285b6fSTero Kristo * @saved_mask. @saved_mask must be allocated by the caller.
25291285b6fSTero Kristo * Intended to be used in the PRM interrupt handler suspend callback.
25391285b6fSTero Kristo * The OCP barrier is needed to ensure the write to disable PRM
25491285b6fSTero Kristo * interrupts reaches the PRM before returning; otherwise, spurious
25591285b6fSTero Kristo * interrupts might occur. No return value.
25691285b6fSTero Kristo */
omap44xx_prm_save_and_clear_irqen(u32 * saved_mask)25728db51f4STero Kristo static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
25891285b6fSTero Kristo {
2598d4be7d8SKeerthy int i;
2608d4be7d8SKeerthy u16 reg;
26191285b6fSTero Kristo
2628d4be7d8SKeerthy for (i = 0; i < omap4_prcm_irq_setup.nr_regs; i++) {
2638d4be7d8SKeerthy reg = omap4_prcm_irq_setup.mask + i * 4;
2648d4be7d8SKeerthy
2658d4be7d8SKeerthy saved_mask[i] =
2668d4be7d8SKeerthy omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
2678d4be7d8SKeerthy reg);
2688d4be7d8SKeerthy omap4_prm_write_inst_reg(0, OMAP4430_PRM_OCP_SOCKET_INST, reg);
2698d4be7d8SKeerthy }
27091285b6fSTero Kristo
27191285b6fSTero Kristo /* OCP barrier */
272553e3222STero Kristo omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
27391285b6fSTero Kristo OMAP4_REVISION_PRM_OFFSET);
27491285b6fSTero Kristo }
27591285b6fSTero Kristo
27691285b6fSTero Kristo /**
27791285b6fSTero Kristo * omap44xx_prm_restore_irqen - set PRM_IRQENABLE_MPU* registers from args
27891285b6fSTero Kristo * @saved_mask: ptr to a u32 array of IRQENABLE bits saved previously
27991285b6fSTero Kristo *
28091285b6fSTero Kristo * Restore the PRM_IRQENABLE_MPU and PRM_IRQENABLE_MPU_2 registers from
28191285b6fSTero Kristo * @saved_mask. Intended to be used in the PRM interrupt handler resume
28291285b6fSTero Kristo * callback to restore values saved by omap44xx_prm_save_and_clear_irqen().
28391285b6fSTero Kristo * No OCP barrier should be needed here; any pending PRM interrupts will fire
28491285b6fSTero Kristo * once the writes reach the PRM. No return value.
28591285b6fSTero Kristo */
omap44xx_prm_restore_irqen(u32 * saved_mask)28628db51f4STero Kristo static void omap44xx_prm_restore_irqen(u32 *saved_mask)
28791285b6fSTero Kristo {
2888d4be7d8SKeerthy int i;
2898d4be7d8SKeerthy
2908d4be7d8SKeerthy for (i = 0; i < omap4_prcm_irq_setup.nr_regs; i++)
2918d4be7d8SKeerthy omap4_prm_write_inst_reg(saved_mask[i],
2928d4be7d8SKeerthy OMAP4430_PRM_OCP_SOCKET_INST,
2938d4be7d8SKeerthy omap4_prcm_irq_setup.mask + i * 4);
29491285b6fSTero Kristo }
2952f31b516STero Kristo
296dea6200bSRajendra Nayak /**
297dea6200bSRajendra Nayak * omap44xx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
298dea6200bSRajendra Nayak *
299dea6200bSRajendra Nayak * Clear any previously-latched I/O wakeup events and ensure that the
300dea6200bSRajendra Nayak * I/O wakeup gates are aligned with the current mux settings. Works
301dea6200bSRajendra Nayak * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then
302dea6200bSRajendra Nayak * deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted.
303dea6200bSRajendra Nayak * No return value. XXX Are the final two steps necessary?
304dea6200bSRajendra Nayak */
omap44xx_prm_reconfigure_io_chain(void)3054984eeafSTero Kristo static void omap44xx_prm_reconfigure_io_chain(void)
306dea6200bSRajendra Nayak {
307dea6200bSRajendra Nayak int i = 0;
308390ddc19SNishanth Menon s32 inst = omap4_prmst_get_prm_dev_inst();
309390ddc19SNishanth Menon
310390ddc19SNishanth Menon if (inst == PRM_INSTANCE_UNKNOWN)
311390ddc19SNishanth Menon return;
312dea6200bSRajendra Nayak
313dea6200bSRajendra Nayak /* Trigger WUCLKIN enable */
314dea6200bSRajendra Nayak omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK,
315dea6200bSRajendra Nayak OMAP4430_WUCLK_CTRL_MASK,
316390ddc19SNishanth Menon inst,
317fac03f12SKeerthy omap4_prcm_irq_setup.pm_ctrl);
318dea6200bSRajendra Nayak omap_test_timeout(
319390ddc19SNishanth Menon (((omap4_prm_read_inst_reg(inst,
320fac03f12SKeerthy omap4_prcm_irq_setup.pm_ctrl) &
321dea6200bSRajendra Nayak OMAP4430_WUCLK_STATUS_MASK) >>
322dea6200bSRajendra Nayak OMAP4430_WUCLK_STATUS_SHIFT) == 1),
323dea6200bSRajendra Nayak MAX_IOPAD_LATCH_TIME, i);
324dea6200bSRajendra Nayak if (i == MAX_IOPAD_LATCH_TIME)
325dea6200bSRajendra Nayak pr_warn("PRM: I/O chain clock line assertion timed out\n");
326dea6200bSRajendra Nayak
327dea6200bSRajendra Nayak /* Trigger WUCLKIN disable */
328dea6200bSRajendra Nayak omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, 0x0,
329390ddc19SNishanth Menon inst,
330fac03f12SKeerthy omap4_prcm_irq_setup.pm_ctrl);
331dea6200bSRajendra Nayak omap_test_timeout(
332390ddc19SNishanth Menon (((omap4_prm_read_inst_reg(inst,
333fac03f12SKeerthy omap4_prcm_irq_setup.pm_ctrl) &
334dea6200bSRajendra Nayak OMAP4430_WUCLK_STATUS_MASK) >>
335dea6200bSRajendra Nayak OMAP4430_WUCLK_STATUS_SHIFT) == 0),
336dea6200bSRajendra Nayak MAX_IOPAD_LATCH_TIME, i);
337dea6200bSRajendra Nayak if (i == MAX_IOPAD_LATCH_TIME)
338dea6200bSRajendra Nayak pr_warn("PRM: I/O chain clock line deassertion timed out\n");
339dea6200bSRajendra Nayak
340dea6200bSRajendra Nayak return;
341dea6200bSRajendra Nayak }
342dea6200bSRajendra Nayak
3438a680ea2STero Kristo /**
344c5b39558STony Lindgren * omap44xx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
345c5b39558STony Lindgren *
346c5b39558STony Lindgren * Activates the I/O wakeup event latches and allows events logged by
347c5b39558STony Lindgren * those latches to signal a wakeup event to the PRCM. For I/O wakeups
348c5b39558STony Lindgren * to occur, WAKEUPENABLE bits must be set in the pad mux registers, and
349c5b39558STony Lindgren * omap44xx_prm_reconfigure_io_chain() must be called. No return value.
350c5b39558STony Lindgren */
omap44xx_prm_enable_io_wakeup(void)351eef3dc34SNathan Chancellor static void omap44xx_prm_enable_io_wakeup(void)
352c5b39558STony Lindgren {
353c5b39558STony Lindgren s32 inst = omap4_prmst_get_prm_dev_inst();
354c5b39558STony Lindgren
355c5b39558STony Lindgren if (inst == PRM_INSTANCE_UNKNOWN)
356c5b39558STony Lindgren return;
357c5b39558STony Lindgren
358c5b39558STony Lindgren omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
359c5b39558STony Lindgren OMAP4430_GLOBAL_WUEN_MASK,
360c5b39558STony Lindgren inst,
361c5b39558STony Lindgren omap4_prcm_irq_setup.pm_ctrl);
362c5b39558STony Lindgren }
363c5b39558STony Lindgren
364c5b39558STony Lindgren /**
3652bb2a5d3SPaul Walmsley * omap44xx_prm_read_reset_sources - return the last SoC reset source
3662bb2a5d3SPaul Walmsley *
3672bb2a5d3SPaul Walmsley * Return a u32 representing the last reset sources of the SoC. The
3682bb2a5d3SPaul Walmsley * returned reset source bits are standardized across OMAP SoCs.
3692bb2a5d3SPaul Walmsley */
omap44xx_prm_read_reset_sources(void)3702bb2a5d3SPaul Walmsley static u32 omap44xx_prm_read_reset_sources(void)
3712bb2a5d3SPaul Walmsley {
3722bb2a5d3SPaul Walmsley struct prm_reset_src_map *p;
3732bb2a5d3SPaul Walmsley u32 r = 0;
3742bb2a5d3SPaul Walmsley u32 v;
375390ddc19SNishanth Menon s32 inst = omap4_prmst_get_prm_dev_inst();
3762bb2a5d3SPaul Walmsley
377390ddc19SNishanth Menon if (inst == PRM_INSTANCE_UNKNOWN)
378390ddc19SNishanth Menon return 0;
379390ddc19SNishanth Menon
380390ddc19SNishanth Menon
381390ddc19SNishanth Menon v = omap4_prm_read_inst_reg(inst,
3822bb2a5d3SPaul Walmsley OMAP4_RM_RSTST);
3832bb2a5d3SPaul Walmsley
3842bb2a5d3SPaul Walmsley p = omap44xx_prm_reset_src_map;
3852bb2a5d3SPaul Walmsley while (p->reg_shift >= 0 && p->std_shift >= 0) {
3862bb2a5d3SPaul Walmsley if (v & (1 << p->reg_shift))
3872bb2a5d3SPaul Walmsley r |= 1 << p->std_shift;
3882bb2a5d3SPaul Walmsley p++;
3892bb2a5d3SPaul Walmsley }
3902bb2a5d3SPaul Walmsley
3912bb2a5d3SPaul Walmsley return r;
3922bb2a5d3SPaul Walmsley }
3932bb2a5d3SPaul Walmsley
394e6d3a8b0SRajendra Nayak /**
395e6d3a8b0SRajendra Nayak * omap44xx_prm_was_any_context_lost_old - was module hardware context lost?
396e6d3a8b0SRajendra Nayak * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION)
397e6d3a8b0SRajendra Nayak * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST)
398e6d3a8b0SRajendra Nayak * @idx: CONTEXT register offset
399e6d3a8b0SRajendra Nayak *
400e6d3a8b0SRajendra Nayak * Return 1 if any bits were set in the *_CONTEXT_* register
401e6d3a8b0SRajendra Nayak * identified by (@part, @inst, @idx), which means that some context
402e6d3a8b0SRajendra Nayak * was lost for that module; otherwise, return 0.
403e6d3a8b0SRajendra Nayak */
omap44xx_prm_was_any_context_lost_old(u8 part,s16 inst,u16 idx)404e6d3a8b0SRajendra Nayak static bool omap44xx_prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx)
405e6d3a8b0SRajendra Nayak {
406e6d3a8b0SRajendra Nayak return (omap4_prminst_read_inst_reg(part, inst, idx)) ? 1 : 0;
407e6d3a8b0SRajendra Nayak }
408e6d3a8b0SRajendra Nayak
409e6d3a8b0SRajendra Nayak /**
410e6d3a8b0SRajendra Nayak * omap44xx_prm_clear_context_lost_flags_old - clear context loss flags
411e6d3a8b0SRajendra Nayak * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION)
412e6d3a8b0SRajendra Nayak * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST)
413e6d3a8b0SRajendra Nayak * @idx: CONTEXT register offset
414e6d3a8b0SRajendra Nayak *
415e6d3a8b0SRajendra Nayak * Clear hardware context loss bits for the module identified by
416e6d3a8b0SRajendra Nayak * (@part, @inst, @idx). No return value. XXX Writes to reserved bits;
417e6d3a8b0SRajendra Nayak * is there a way to avoid this?
418e6d3a8b0SRajendra Nayak */
omap44xx_prm_clear_context_loss_flags_old(u8 part,s16 inst,u16 idx)419e6d3a8b0SRajendra Nayak static void omap44xx_prm_clear_context_loss_flags_old(u8 part, s16 inst,
420e6d3a8b0SRajendra Nayak u16 idx)
421e6d3a8b0SRajendra Nayak {
422e6d3a8b0SRajendra Nayak omap4_prminst_write_inst_reg(0xffffffff, part, inst, idx);
423e6d3a8b0SRajendra Nayak }
424e6d3a8b0SRajendra Nayak
42549815399SPaul Walmsley /* Powerdomain low-level functions */
42649815399SPaul Walmsley
omap4_pwrdm_set_next_pwrst(struct powerdomain * pwrdm,u8 pwrst)42749815399SPaul Walmsley static int omap4_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
42849815399SPaul Walmsley {
42949815399SPaul Walmsley omap4_prminst_rmw_inst_reg_bits(OMAP_POWERSTATE_MASK,
43049815399SPaul Walmsley (pwrst << OMAP_POWERSTATE_SHIFT),
43149815399SPaul Walmsley pwrdm->prcm_partition,
43249815399SPaul Walmsley pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
43349815399SPaul Walmsley return 0;
43449815399SPaul Walmsley }
43549815399SPaul Walmsley
omap4_pwrdm_read_next_pwrst(struct powerdomain * pwrdm)43649815399SPaul Walmsley static int omap4_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
43749815399SPaul Walmsley {
43849815399SPaul Walmsley u32 v;
43949815399SPaul Walmsley
44049815399SPaul Walmsley v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
44149815399SPaul Walmsley OMAP4_PM_PWSTCTRL);
44249815399SPaul Walmsley v &= OMAP_POWERSTATE_MASK;
44349815399SPaul Walmsley v >>= OMAP_POWERSTATE_SHIFT;
44449815399SPaul Walmsley
44549815399SPaul Walmsley return v;
44649815399SPaul Walmsley }
44749815399SPaul Walmsley
omap4_pwrdm_read_pwrst(struct powerdomain * pwrdm)44849815399SPaul Walmsley static int omap4_pwrdm_read_pwrst(struct powerdomain *pwrdm)
44949815399SPaul Walmsley {
45049815399SPaul Walmsley u32 v;
45149815399SPaul Walmsley
45249815399SPaul Walmsley v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
45349815399SPaul Walmsley OMAP4_PM_PWSTST);
45449815399SPaul Walmsley v &= OMAP_POWERSTATEST_MASK;
45549815399SPaul Walmsley v >>= OMAP_POWERSTATEST_SHIFT;
45649815399SPaul Walmsley
45749815399SPaul Walmsley return v;
45849815399SPaul Walmsley }
45949815399SPaul Walmsley
omap4_pwrdm_read_prev_pwrst(struct powerdomain * pwrdm)46049815399SPaul Walmsley static int omap4_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
46149815399SPaul Walmsley {
46249815399SPaul Walmsley u32 v;
46349815399SPaul Walmsley
46449815399SPaul Walmsley v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
46549815399SPaul Walmsley OMAP4_PM_PWSTST);
46649815399SPaul Walmsley v &= OMAP4430_LASTPOWERSTATEENTERED_MASK;
46749815399SPaul Walmsley v >>= OMAP4430_LASTPOWERSTATEENTERED_SHIFT;
46849815399SPaul Walmsley
46949815399SPaul Walmsley return v;
47049815399SPaul Walmsley }
47149815399SPaul Walmsley
omap4_pwrdm_set_lowpwrstchange(struct powerdomain * pwrdm)47249815399SPaul Walmsley static int omap4_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
47349815399SPaul Walmsley {
47449815399SPaul Walmsley omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOWPOWERSTATECHANGE_MASK,
47549815399SPaul Walmsley (1 << OMAP4430_LOWPOWERSTATECHANGE_SHIFT),
47649815399SPaul Walmsley pwrdm->prcm_partition,
47749815399SPaul Walmsley pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL);
47849815399SPaul Walmsley return 0;
47949815399SPaul Walmsley }
48049815399SPaul Walmsley
omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain * pwrdm)48149815399SPaul Walmsley static int omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
48249815399SPaul Walmsley {
48349815399SPaul Walmsley omap4_prminst_rmw_inst_reg_bits(OMAP4430_LASTPOWERSTATEENTERED_MASK,
48449815399SPaul Walmsley OMAP4430_LASTPOWERSTATEENTERED_MASK,
48549815399SPaul Walmsley pwrdm->prcm_partition,
48649815399SPaul Walmsley pwrdm->prcm_offs, OMAP4_PM_PWSTST);
48749815399SPaul Walmsley return 0;
48849815399SPaul Walmsley }
48949815399SPaul Walmsley
omap4_pwrdm_set_logic_retst(struct powerdomain * pwrdm,u8 pwrst)49049815399SPaul Walmsley static int omap4_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
49149815399SPaul Walmsley {
49249815399SPaul Walmsley u32 v;
49349815399SPaul Walmsley
49449815399SPaul Walmsley v = pwrst << __ffs(OMAP4430_LOGICRETSTATE_MASK);
49549815399SPaul Walmsley omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOGICRETSTATE_MASK, v,
49649815399SPaul Walmsley pwrdm->prcm_partition, pwrdm->prcm_offs,
49749815399SPaul Walmsley OMAP4_PM_PWSTCTRL);
49849815399SPaul Walmsley
49949815399SPaul Walmsley return 0;
50049815399SPaul Walmsley }
50149815399SPaul Walmsley
omap4_pwrdm_set_mem_onst(struct powerdomain * pwrdm,u8 bank,u8 pwrst)50249815399SPaul Walmsley static int omap4_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
50349815399SPaul Walmsley u8 pwrst)
50449815399SPaul Walmsley {
50549815399SPaul Walmsley u32 m;
50649815399SPaul Walmsley
50749815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_onstate_mask(bank);
50849815399SPaul Walmsley
50949815399SPaul Walmsley omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
51049815399SPaul Walmsley pwrdm->prcm_partition, pwrdm->prcm_offs,
51149815399SPaul Walmsley OMAP4_PM_PWSTCTRL);
51249815399SPaul Walmsley
51349815399SPaul Walmsley return 0;
51449815399SPaul Walmsley }
51549815399SPaul Walmsley
omap4_pwrdm_set_mem_retst(struct powerdomain * pwrdm,u8 bank,u8 pwrst)51649815399SPaul Walmsley static int omap4_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
51749815399SPaul Walmsley u8 pwrst)
51849815399SPaul Walmsley {
51949815399SPaul Walmsley u32 m;
52049815399SPaul Walmsley
52149815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
52249815399SPaul Walmsley
52349815399SPaul Walmsley omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)),
52449815399SPaul Walmsley pwrdm->prcm_partition, pwrdm->prcm_offs,
52549815399SPaul Walmsley OMAP4_PM_PWSTCTRL);
52649815399SPaul Walmsley
52749815399SPaul Walmsley return 0;
52849815399SPaul Walmsley }
52949815399SPaul Walmsley
omap4_pwrdm_read_logic_pwrst(struct powerdomain * pwrdm)53049815399SPaul Walmsley static int omap4_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
53149815399SPaul Walmsley {
53249815399SPaul Walmsley u32 v;
53349815399SPaul Walmsley
53449815399SPaul Walmsley v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
53549815399SPaul Walmsley OMAP4_PM_PWSTST);
53649815399SPaul Walmsley v &= OMAP4430_LOGICSTATEST_MASK;
53749815399SPaul Walmsley v >>= OMAP4430_LOGICSTATEST_SHIFT;
53849815399SPaul Walmsley
53949815399SPaul Walmsley return v;
54049815399SPaul Walmsley }
54149815399SPaul Walmsley
omap4_pwrdm_read_logic_retst(struct powerdomain * pwrdm)54249815399SPaul Walmsley static int omap4_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
54349815399SPaul Walmsley {
54449815399SPaul Walmsley u32 v;
54549815399SPaul Walmsley
54649815399SPaul Walmsley v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
54749815399SPaul Walmsley OMAP4_PM_PWSTCTRL);
54849815399SPaul Walmsley v &= OMAP4430_LOGICRETSTATE_MASK;
54949815399SPaul Walmsley v >>= OMAP4430_LOGICRETSTATE_SHIFT;
55049815399SPaul Walmsley
55149815399SPaul Walmsley return v;
55249815399SPaul Walmsley }
55349815399SPaul Walmsley
55449815399SPaul Walmsley /**
55549815399SPaul Walmsley * omap4_pwrdm_read_prev_logic_pwrst - read the previous logic powerstate
55649815399SPaul Walmsley * @pwrdm: struct powerdomain * to read the state for
55749815399SPaul Walmsley *
55849815399SPaul Walmsley * Reads the previous logic powerstate for a powerdomain. This
55949815399SPaul Walmsley * function must determine the previous logic powerstate by first
56049815399SPaul Walmsley * checking the previous powerstate for the domain. If that was OFF,
56149815399SPaul Walmsley * then logic has been lost. If previous state was RETENTION, the
56249815399SPaul Walmsley * function reads the setting for the next retention logic state to
56349815399SPaul Walmsley * see the actual value. In every other case, the logic is
56449815399SPaul Walmsley * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
56549815399SPaul Walmsley * depending whether the logic was retained or not.
56649815399SPaul Walmsley */
omap4_pwrdm_read_prev_logic_pwrst(struct powerdomain * pwrdm)56749815399SPaul Walmsley static int omap4_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
56849815399SPaul Walmsley {
56949815399SPaul Walmsley int state;
57049815399SPaul Walmsley
57149815399SPaul Walmsley state = omap4_pwrdm_read_prev_pwrst(pwrdm);
57249815399SPaul Walmsley
57349815399SPaul Walmsley if (state == PWRDM_POWER_OFF)
57449815399SPaul Walmsley return PWRDM_POWER_OFF;
57549815399SPaul Walmsley
57649815399SPaul Walmsley if (state != PWRDM_POWER_RET)
57749815399SPaul Walmsley return PWRDM_POWER_RET;
57849815399SPaul Walmsley
57949815399SPaul Walmsley return omap4_pwrdm_read_logic_retst(pwrdm);
58049815399SPaul Walmsley }
58149815399SPaul Walmsley
omap4_pwrdm_read_mem_pwrst(struct powerdomain * pwrdm,u8 bank)58249815399SPaul Walmsley static int omap4_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
58349815399SPaul Walmsley {
58449815399SPaul Walmsley u32 m, v;
58549815399SPaul Walmsley
58649815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_stst_mask(bank);
58749815399SPaul Walmsley
58849815399SPaul Walmsley v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
58949815399SPaul Walmsley OMAP4_PM_PWSTST);
59049815399SPaul Walmsley v &= m;
59149815399SPaul Walmsley v >>= __ffs(m);
59249815399SPaul Walmsley
59349815399SPaul Walmsley return v;
59449815399SPaul Walmsley }
59549815399SPaul Walmsley
omap4_pwrdm_read_mem_retst(struct powerdomain * pwrdm,u8 bank)59649815399SPaul Walmsley static int omap4_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
59749815399SPaul Walmsley {
59849815399SPaul Walmsley u32 m, v;
59949815399SPaul Walmsley
60049815399SPaul Walmsley m = omap2_pwrdm_get_mem_bank_retst_mask(bank);
60149815399SPaul Walmsley
60249815399SPaul Walmsley v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs,
60349815399SPaul Walmsley OMAP4_PM_PWSTCTRL);
60449815399SPaul Walmsley v &= m;
60549815399SPaul Walmsley v >>= __ffs(m);
60649815399SPaul Walmsley
60749815399SPaul Walmsley return v;
60849815399SPaul Walmsley }
60949815399SPaul Walmsley
61049815399SPaul Walmsley /**
61149815399SPaul Walmsley * omap4_pwrdm_read_prev_mem_pwrst - reads the previous memory powerstate
61249815399SPaul Walmsley * @pwrdm: struct powerdomain * to read mem powerstate for
61349815399SPaul Walmsley * @bank: memory bank index
61449815399SPaul Walmsley *
61549815399SPaul Walmsley * Reads the previous memory powerstate for a powerdomain. This
61649815399SPaul Walmsley * function must determine the previous memory powerstate by first
61749815399SPaul Walmsley * checking the previous powerstate for the domain. If that was OFF,
61849815399SPaul Walmsley * then logic has been lost. If previous state was RETENTION, the
61949815399SPaul Walmsley * function reads the setting for the next memory retention state to
62049815399SPaul Walmsley * see the actual value. In every other case, the logic is
62149815399SPaul Walmsley * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
62249815399SPaul Walmsley * depending whether logic was retained or not.
62349815399SPaul Walmsley */
omap4_pwrdm_read_prev_mem_pwrst(struct powerdomain * pwrdm,u8 bank)62449815399SPaul Walmsley static int omap4_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
62549815399SPaul Walmsley {
62649815399SPaul Walmsley int state;
62749815399SPaul Walmsley
62849815399SPaul Walmsley state = omap4_pwrdm_read_prev_pwrst(pwrdm);
62949815399SPaul Walmsley
63049815399SPaul Walmsley if (state == PWRDM_POWER_OFF)
63149815399SPaul Walmsley return PWRDM_POWER_OFF;
63249815399SPaul Walmsley
63349815399SPaul Walmsley if (state != PWRDM_POWER_RET)
63449815399SPaul Walmsley return PWRDM_POWER_RET;
63549815399SPaul Walmsley
63649815399SPaul Walmsley return omap4_pwrdm_read_mem_retst(pwrdm, bank);
63749815399SPaul Walmsley }
63849815399SPaul Walmsley
omap4_pwrdm_wait_transition(struct powerdomain * pwrdm)63949815399SPaul Walmsley static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
64049815399SPaul Walmsley {
64149815399SPaul Walmsley u32 c = 0;
64249815399SPaul Walmsley
64349815399SPaul Walmsley /*
64449815399SPaul Walmsley * REVISIT: pwrdm_wait_transition() may be better implemented
64549815399SPaul Walmsley * via a callback and a periodic timer check -- how long do we expect
64649815399SPaul Walmsley * powerdomain transitions to take?
64749815399SPaul Walmsley */
64849815399SPaul Walmsley
64949815399SPaul Walmsley /* XXX Is this udelay() value meaningful? */
65049815399SPaul Walmsley while ((omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
65149815399SPaul Walmsley pwrdm->prcm_offs,
65249815399SPaul Walmsley OMAP4_PM_PWSTST) &
65349815399SPaul Walmsley OMAP_INTRANSITION_MASK) &&
65449815399SPaul Walmsley (c++ < PWRDM_TRANSITION_BAILOUT))
65549815399SPaul Walmsley udelay(1);
65649815399SPaul Walmsley
65749815399SPaul Walmsley if (c > PWRDM_TRANSITION_BAILOUT) {
65849815399SPaul Walmsley pr_err("powerdomain: %s: waited too long to complete transition\n",
65949815399SPaul Walmsley pwrdm->name);
66049815399SPaul Walmsley return -EAGAIN;
66149815399SPaul Walmsley }
66249815399SPaul Walmsley
66349815399SPaul Walmsley pr_debug("powerdomain: completed transition in %d loops\n", c);
66449815399SPaul Walmsley
66549815399SPaul Walmsley return 0;
66649815399SPaul Walmsley }
66749815399SPaul Walmsley
omap4_check_vcvp(void)6689a4e301dSRajendra Nayak static int omap4_check_vcvp(void)
6699a4e301dSRajendra Nayak {
6703381eb47STero Kristo if (prm_features & PRM_HAS_VOLTAGE)
6719a4e301dSRajendra Nayak return 1;
6723381eb47STero Kristo
6733381eb47STero Kristo return 0;
6749a4e301dSRajendra Nayak }
6759a4e301dSRajendra Nayak
676485995b0SRuss Dill /**
677485995b0SRuss Dill * omap4_pwrdm_save_context - Saves the powerdomain state
678485995b0SRuss Dill * @pwrdm: pointer to individual powerdomain
679485995b0SRuss Dill *
680485995b0SRuss Dill * The function saves the powerdomain state control information.
681485995b0SRuss Dill * This is needed in rtc+ddr modes where we lose powerdomain context.
682485995b0SRuss Dill */
omap4_pwrdm_save_context(struct powerdomain * pwrdm)683485995b0SRuss Dill static void omap4_pwrdm_save_context(struct powerdomain *pwrdm)
684485995b0SRuss Dill {
685485995b0SRuss Dill pwrdm->context = omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
686485995b0SRuss Dill pwrdm->prcm_offs,
687485995b0SRuss Dill pwrdm->pwrstctrl_offs);
688485995b0SRuss Dill
689485995b0SRuss Dill /*
690485995b0SRuss Dill * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
691485995b0SRuss Dill * reading back a 1 indicates a request in progress.
692485995b0SRuss Dill */
693485995b0SRuss Dill pwrdm->context &= ~OMAP4430_LOWPOWERSTATECHANGE_MASK;
694485995b0SRuss Dill }
695485995b0SRuss Dill
696485995b0SRuss Dill /**
697485995b0SRuss Dill * omap4_pwrdm_restore_context - Restores the powerdomain state
698485995b0SRuss Dill * @pwrdm: pointer to individual powerdomain
699485995b0SRuss Dill *
700485995b0SRuss Dill * The function restores the powerdomain state control information.
701485995b0SRuss Dill * This is needed in rtc+ddr modes where we lose powerdomain context.
702485995b0SRuss Dill */
omap4_pwrdm_restore_context(struct powerdomain * pwrdm)703485995b0SRuss Dill static void omap4_pwrdm_restore_context(struct powerdomain *pwrdm)
704485995b0SRuss Dill {
705485995b0SRuss Dill int st, ctrl;
706485995b0SRuss Dill
707485995b0SRuss Dill st = omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
708485995b0SRuss Dill pwrdm->prcm_offs,
709485995b0SRuss Dill pwrdm->pwrstctrl_offs);
710485995b0SRuss Dill
711485995b0SRuss Dill omap4_prminst_write_inst_reg(pwrdm->context,
712485995b0SRuss Dill pwrdm->prcm_partition,
713485995b0SRuss Dill pwrdm->prcm_offs,
714485995b0SRuss Dill pwrdm->pwrstctrl_offs);
715485995b0SRuss Dill
716485995b0SRuss Dill /* Make sure we only wait for a transition if there is one */
717485995b0SRuss Dill st &= OMAP_POWERSTATEST_MASK;
718485995b0SRuss Dill ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
719485995b0SRuss Dill
720485995b0SRuss Dill if (st != ctrl)
721485995b0SRuss Dill omap4_pwrdm_wait_transition(pwrdm);
722485995b0SRuss Dill }
723485995b0SRuss Dill
72449815399SPaul Walmsley struct pwrdm_ops omap4_pwrdm_operations = {
72549815399SPaul Walmsley .pwrdm_set_next_pwrst = omap4_pwrdm_set_next_pwrst,
72649815399SPaul Walmsley .pwrdm_read_next_pwrst = omap4_pwrdm_read_next_pwrst,
72749815399SPaul Walmsley .pwrdm_read_pwrst = omap4_pwrdm_read_pwrst,
72849815399SPaul Walmsley .pwrdm_read_prev_pwrst = omap4_pwrdm_read_prev_pwrst,
72949815399SPaul Walmsley .pwrdm_set_lowpwrstchange = omap4_pwrdm_set_lowpwrstchange,
73049815399SPaul Walmsley .pwrdm_clear_all_prev_pwrst = omap4_pwrdm_clear_all_prev_pwrst,
73149815399SPaul Walmsley .pwrdm_set_logic_retst = omap4_pwrdm_set_logic_retst,
73249815399SPaul Walmsley .pwrdm_read_logic_pwrst = omap4_pwrdm_read_logic_pwrst,
73349815399SPaul Walmsley .pwrdm_read_prev_logic_pwrst = omap4_pwrdm_read_prev_logic_pwrst,
73449815399SPaul Walmsley .pwrdm_read_logic_retst = omap4_pwrdm_read_logic_retst,
73549815399SPaul Walmsley .pwrdm_read_mem_pwrst = omap4_pwrdm_read_mem_pwrst,
73649815399SPaul Walmsley .pwrdm_read_mem_retst = omap4_pwrdm_read_mem_retst,
73749815399SPaul Walmsley .pwrdm_read_prev_mem_pwrst = omap4_pwrdm_read_prev_mem_pwrst,
73849815399SPaul Walmsley .pwrdm_set_mem_onst = omap4_pwrdm_set_mem_onst,
73949815399SPaul Walmsley .pwrdm_set_mem_retst = omap4_pwrdm_set_mem_retst,
74049815399SPaul Walmsley .pwrdm_wait_transition = omap4_pwrdm_wait_transition,
7419a4e301dSRajendra Nayak .pwrdm_has_voltdm = omap4_check_vcvp,
742485995b0SRuss Dill .pwrdm_save_context = omap4_pwrdm_save_context,
743485995b0SRuss Dill .pwrdm_restore_context = omap4_pwrdm_restore_context,
74449815399SPaul Walmsley };
74549815399SPaul Walmsley
746c5b39558STony Lindgren static int omap44xx_prm_late_init(void);
747c5b39558STony Lindgren
prm_save_context(void)748*89ffcdbaSBen Dooks static void prm_save_context(void)
749e37fbf05SDave Gerlach {
750e37fbf05SDave Gerlach omap_prm_context.irq_enable =
751e37fbf05SDave Gerlach omap4_prm_read_inst_reg(AM43XX_PRM_OCP_SOCKET_INST,
752e37fbf05SDave Gerlach omap4_prcm_irq_setup.mask);
753e37fbf05SDave Gerlach
754e37fbf05SDave Gerlach omap_prm_context.pm_ctrl =
755e37fbf05SDave Gerlach omap4_prm_read_inst_reg(AM43XX_PRM_DEVICE_INST,
756e37fbf05SDave Gerlach omap4_prcm_irq_setup.pm_ctrl);
757e37fbf05SDave Gerlach }
758e37fbf05SDave Gerlach
prm_restore_context(void)759*89ffcdbaSBen Dooks static void prm_restore_context(void)
760e37fbf05SDave Gerlach {
761e37fbf05SDave Gerlach omap4_prm_write_inst_reg(omap_prm_context.irq_enable,
762e37fbf05SDave Gerlach OMAP4430_PRM_OCP_SOCKET_INST,
763e37fbf05SDave Gerlach omap4_prcm_irq_setup.mask);
764e37fbf05SDave Gerlach
765e37fbf05SDave Gerlach omap4_prm_write_inst_reg(omap_prm_context.pm_ctrl,
766e37fbf05SDave Gerlach AM43XX_PRM_DEVICE_INST,
767e37fbf05SDave Gerlach omap4_prcm_irq_setup.pm_ctrl);
768e37fbf05SDave Gerlach }
769e37fbf05SDave Gerlach
cpu_notifier(struct notifier_block * nb,unsigned long cmd,void * v)770a9f73632SKeerthy static int cpu_notifier(struct notifier_block *nb, unsigned long cmd, void *v)
771a9f73632SKeerthy {
772a9f73632SKeerthy switch (cmd) {
773a9f73632SKeerthy case CPU_CLUSTER_PM_ENTER:
774a9f73632SKeerthy if (enable_off_mode)
775a9f73632SKeerthy prm_save_context();
776a9f73632SKeerthy break;
777a9f73632SKeerthy case CPU_CLUSTER_PM_EXIT:
778a9f73632SKeerthy if (enable_off_mode)
779a9f73632SKeerthy prm_restore_context();
780a9f73632SKeerthy break;
781a9f73632SKeerthy }
782a9f73632SKeerthy
783a9f73632SKeerthy return NOTIFY_OK;
784a9f73632SKeerthy }
785a9f73632SKeerthy
7862bb2a5d3SPaul Walmsley /*
7872bb2a5d3SPaul Walmsley * XXX document
7882bb2a5d3SPaul Walmsley */
7892bb2a5d3SPaul Walmsley static struct prm_ll_data omap44xx_prm_ll_data = {
7902bb2a5d3SPaul Walmsley .read_reset_sources = &omap44xx_prm_read_reset_sources,
791e6d3a8b0SRajendra Nayak .was_any_context_lost_old = &omap44xx_prm_was_any_context_lost_old,
792e6d3a8b0SRajendra Nayak .clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old,
793c5b39558STony Lindgren .late_init = &omap44xx_prm_late_init,
794efd44dc3STero Kristo .assert_hardreset = omap4_prminst_assert_hardreset,
79537fb59d7STero Kristo .deassert_hardreset = omap4_prminst_deassert_hardreset,
7961bc28b34STero Kristo .is_hardreset_asserted = omap4_prminst_is_hardreset_asserted,
79761c8621eSTero Kristo .reset_system = omap4_prminst_global_warm_sw_reset,
798e9f1ddcdSTero Kristo .vp_check_txdone = omap4_prm_vp_check_txdone,
799e9f1ddcdSTero Kristo .vp_clear_txdone = omap4_prm_vp_clear_txdone,
8002bb2a5d3SPaul Walmsley };
80149815399SPaul Walmsley
802219595b6STero Kristo static const struct omap_prcm_init_data *prm_init_data;
803219595b6STero Kristo
omap44xx_prm_init(const struct omap_prcm_init_data * data)804ab7b2ffcSTero Kristo int __init omap44xx_prm_init(const struct omap_prcm_init_data *data)
8052f31b516STero Kristo {
806a9f73632SKeerthy static struct notifier_block nb;
8074e3870f3STero Kristo omap_prm_base_init();
8084e3870f3STero Kristo
809219595b6STero Kristo prm_init_data = data;
810219595b6STero Kristo
8118b5b9a22STero Kristo if (data->flags & PRM_HAS_IO_WAKEUP)
8122541d15fSTero Kristo prm_features |= PRM_HAS_IO_WAKEUP;
813139563adSPaul Walmsley
8148b5b9a22STero Kristo if (data->flags & PRM_HAS_VOLTAGE)
8153381eb47STero Kristo prm_features |= PRM_HAS_VOLTAGE;
8163381eb47STero Kristo
81748e0c114STero Kristo omap4_prminst_set_prm_dev_inst(data->device_inst_offset);
81848e0c114STero Kristo
819cc843711SKeerthy /* Add AM437X specific differences */
820cc843711SKeerthy if (of_device_is_compatible(data->np, "ti,am4-prcm")) {
821cc843711SKeerthy omap4_prcm_irq_setup.nr_irqs = 1;
822cc843711SKeerthy omap4_prcm_irq_setup.nr_regs = 1;
823cc843711SKeerthy omap4_prcm_irq_setup.pm_ctrl = AM43XX_PRM_IO_PMCTRL_OFFSET;
824cc843711SKeerthy omap4_prcm_irq_setup.ack = AM43XX_PRM_IRQSTATUS_MPU_OFFSET;
825cc843711SKeerthy omap4_prcm_irq_setup.mask = AM43XX_PRM_IRQENABLE_MPU_OFFSET;
826cc843711SKeerthy }
827cc843711SKeerthy
828a9f73632SKeerthy /* Only AM43XX can lose prm context during rtc-ddr suspend */
829a9f73632SKeerthy if (soc_is_am43xx()) {
830a9f73632SKeerthy nb.notifier_call = cpu_notifier;
831a9f73632SKeerthy cpu_pm_register_notifier(&nb);
832a9f73632SKeerthy }
833a9f73632SKeerthy
83463a293e0SPaul Walmsley return prm_register(&omap44xx_prm_ll_data);
83563a293e0SPaul Walmsley }
83663a293e0SPaul Walmsley
omap44xx_prm_late_init(void)837c5b39558STony Lindgren static int omap44xx_prm_late_init(void)
838c5b39558STony Lindgren {
839c5b39558STony Lindgren int irq_num;
840c5b39558STony Lindgren
841c5b39558STony Lindgren if (!(prm_features & PRM_HAS_IO_WAKEUP))
842c5b39558STony Lindgren return 0;
843c5b39558STony Lindgren
844c5b39558STony Lindgren irq_num = of_irq_get(prm_init_data->np, 0);
845c5b39558STony Lindgren if (irq_num == -EPROBE_DEFER)
846c5b39558STony Lindgren return irq_num;
847c5b39558STony Lindgren
848c5b39558STony Lindgren omap4_prcm_irq_setup.irq = irq_num;
849c5b39558STony Lindgren
850c5b39558STony Lindgren omap44xx_prm_enable_io_wakeup();
851c5b39558STony Lindgren
852c5b39558STony Lindgren return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
853c5b39558STony Lindgren }
854c5b39558STony Lindgren
omap44xx_prm_exit(void)8552bb2a5d3SPaul Walmsley static void __exit omap44xx_prm_exit(void)
8562bb2a5d3SPaul Walmsley {
857d8871cd2STero Kristo prm_unregister(&omap44xx_prm_ll_data);
8582bb2a5d3SPaul Walmsley }
8592bb2a5d3SPaul Walmsley __exitcall(omap44xx_prm_exit);
860