149815399SPaul Walmsley /* 249815399SPaul Walmsley * OMAP2xxx PRM module functions 349815399SPaul Walmsley * 449815399SPaul Walmsley * Copyright (C) 2010-2012 Texas Instruments, Inc. 549815399SPaul Walmsley * Copyright (C) 2010 Nokia Corporation 649815399SPaul Walmsley * Benoît Cousson 749815399SPaul Walmsley * Paul Walmsley 849815399SPaul Walmsley * Rajendra Nayak <rnayak@ti.com> 949815399SPaul Walmsley * 1049815399SPaul Walmsley * This program is free software; you can redistribute it and/or modify 1149815399SPaul Walmsley * it under the terms of the GNU General Public License version 2 as 1249815399SPaul Walmsley * published by the Free Software Foundation. 1349815399SPaul Walmsley */ 1449815399SPaul Walmsley 1549815399SPaul Walmsley #include <linux/kernel.h> 1649815399SPaul Walmsley #include <linux/errno.h> 1749815399SPaul Walmsley #include <linux/err.h> 1849815399SPaul Walmsley #include <linux/io.h> 1949815399SPaul Walmsley #include <linux/irq.h> 2049815399SPaul Walmsley 2149815399SPaul Walmsley #include "common.h" 2249815399SPaul Walmsley #include <plat/cpu.h> 2349815399SPaul Walmsley 2449815399SPaul Walmsley #include "vp.h" 2549815399SPaul Walmsley #include "powerdomain.h" 264bd5259eSPaul Walmsley #include "clockdomain.h" 2749815399SPaul Walmsley #include "prm2xxx.h" 2849815399SPaul Walmsley #include "cm2xxx_3xxx.h" 2949815399SPaul Walmsley #include "prm-regbits-24xx.h" 3049815399SPaul Walmsley 312bb2a5d3SPaul Walmsley /* 322bb2a5d3SPaul Walmsley * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP 332bb2a5d3SPaul Walmsley * hardware register (which are specific to the OMAP2xxx SoCs) to 342bb2a5d3SPaul Walmsley * reset source ID bit shifts (which is an OMAP SoC-independent 352bb2a5d3SPaul Walmsley * enumeration) 362bb2a5d3SPaul Walmsley */ 372bb2a5d3SPaul Walmsley static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = { 382bb2a5d3SPaul Walmsley { OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT }, 392bb2a5d3SPaul Walmsley { OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT }, 402bb2a5d3SPaul Walmsley { OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT }, 412bb2a5d3SPaul Walmsley { OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, 422bb2a5d3SPaul Walmsley { OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT }, 432bb2a5d3SPaul Walmsley { OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT }, 442bb2a5d3SPaul Walmsley { -1, -1 }, 452bb2a5d3SPaul Walmsley }; 462bb2a5d3SPaul Walmsley 472bb2a5d3SPaul Walmsley /** 482bb2a5d3SPaul Walmsley * omap2xxx_prm_read_reset_sources - return the last SoC reset source 492bb2a5d3SPaul Walmsley * 502bb2a5d3SPaul Walmsley * Return a u32 representing the last reset sources of the SoC. The 512bb2a5d3SPaul Walmsley * returned reset source bits are standardized across OMAP SoCs. 522bb2a5d3SPaul Walmsley */ 532bb2a5d3SPaul Walmsley static u32 omap2xxx_prm_read_reset_sources(void) 542bb2a5d3SPaul Walmsley { 552bb2a5d3SPaul Walmsley struct prm_reset_src_map *p; 562bb2a5d3SPaul Walmsley u32 r = 0; 572bb2a5d3SPaul Walmsley u32 v; 582bb2a5d3SPaul Walmsley 592bb2a5d3SPaul Walmsley v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST); 602bb2a5d3SPaul Walmsley 612bb2a5d3SPaul Walmsley p = omap2xxx_prm_reset_src_map; 622bb2a5d3SPaul Walmsley while (p->reg_shift >= 0 && p->std_shift >= 0) { 632bb2a5d3SPaul Walmsley if (v & (1 << p->reg_shift)) 642bb2a5d3SPaul Walmsley r |= 1 << p->std_shift; 652bb2a5d3SPaul Walmsley p++; 662bb2a5d3SPaul Walmsley } 672bb2a5d3SPaul Walmsley 682bb2a5d3SPaul Walmsley return r; 692bb2a5d3SPaul Walmsley } 702bb2a5d3SPaul Walmsley 71d08cce6aSPaul Walmsley /** 72d08cce6aSPaul Walmsley * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC 73d08cce6aSPaul Walmsley * 74d08cce6aSPaul Walmsley * Set the DPLL reset bit, which should reboot the SoC. This is the 75d08cce6aSPaul Walmsley * recommended way to restart the SoC. No return value. 76d08cce6aSPaul Walmsley */ 77d08cce6aSPaul Walmsley void omap2xxx_prm_dpll_reset(void) 78d08cce6aSPaul Walmsley { 79d08cce6aSPaul Walmsley omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, 80d08cce6aSPaul Walmsley OMAP2_RM_RSTCTRL); 81d08cce6aSPaul Walmsley /* OCP barrier */ 82d08cce6aSPaul Walmsley omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL); 83d08cce6aSPaul Walmsley } 84d08cce6aSPaul Walmsley 854bd5259eSPaul Walmsley int omap2xxx_clkdm_sleep(struct clockdomain *clkdm) 864bd5259eSPaul Walmsley { 874bd5259eSPaul Walmsley omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 884bd5259eSPaul Walmsley clkdm->pwrdm.ptr->prcm_offs, 894bd5259eSPaul Walmsley OMAP2_PM_PWSTCTRL); 904bd5259eSPaul Walmsley return 0; 914bd5259eSPaul Walmsley } 924bd5259eSPaul Walmsley 934bd5259eSPaul Walmsley int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm) 944bd5259eSPaul Walmsley { 954bd5259eSPaul Walmsley omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 964bd5259eSPaul Walmsley clkdm->pwrdm.ptr->prcm_offs, 974bd5259eSPaul Walmsley OMAP2_PM_PWSTCTRL); 984bd5259eSPaul Walmsley return 0; 994bd5259eSPaul Walmsley } 1004bd5259eSPaul Walmsley 10149815399SPaul Walmsley struct pwrdm_ops omap2_pwrdm_operations = { 10249815399SPaul Walmsley .pwrdm_set_next_pwrst = omap2_pwrdm_set_next_pwrst, 10349815399SPaul Walmsley .pwrdm_read_next_pwrst = omap2_pwrdm_read_next_pwrst, 10449815399SPaul Walmsley .pwrdm_read_pwrst = omap2_pwrdm_read_pwrst, 10549815399SPaul Walmsley .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, 10649815399SPaul Walmsley .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, 10749815399SPaul Walmsley .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst, 10849815399SPaul Walmsley .pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst, 10949815399SPaul Walmsley .pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst, 11049815399SPaul Walmsley .pwrdm_wait_transition = omap2_pwrdm_wait_transition, 11149815399SPaul Walmsley }; 1122bb2a5d3SPaul Walmsley 1132bb2a5d3SPaul Walmsley /* 1142bb2a5d3SPaul Walmsley * 1152bb2a5d3SPaul Walmsley */ 1162bb2a5d3SPaul Walmsley 1172bb2a5d3SPaul Walmsley static struct prm_ll_data omap2xxx_prm_ll_data = { 1182bb2a5d3SPaul Walmsley .read_reset_sources = &omap2xxx_prm_read_reset_sources, 1192bb2a5d3SPaul Walmsley }; 1202bb2a5d3SPaul Walmsley 12163a293e0SPaul Walmsley int __init omap2xxx_prm_init(void) 1222bb2a5d3SPaul Walmsley { 1232bb2a5d3SPaul Walmsley if (!cpu_is_omap24xx()) 1242bb2a5d3SPaul Walmsley return 0; 1252bb2a5d3SPaul Walmsley 1262bb2a5d3SPaul Walmsley return prm_register(&omap2xxx_prm_ll_data); 1272bb2a5d3SPaul Walmsley } 1282bb2a5d3SPaul Walmsley 1292bb2a5d3SPaul Walmsley static void __exit omap2xxx_prm_exit(void) 1302bb2a5d3SPaul Walmsley { 1312bb2a5d3SPaul Walmsley if (!cpu_is_omap24xx()) 1322bb2a5d3SPaul Walmsley return; 1332bb2a5d3SPaul Walmsley 1342bb2a5d3SPaul Walmsley /* Should never happen */ 1352bb2a5d3SPaul Walmsley WARN(prm_unregister(&omap2xxx_prm_ll_data), 1362bb2a5d3SPaul Walmsley "%s: prm_ll_data function pointer mismatch\n", __func__); 1372bb2a5d3SPaul Walmsley } 1382bb2a5d3SPaul Walmsley __exitcall(omap2xxx_prm_exit); 139