cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

prm33xx.c (11214B)


      1/*
      2 * AM33XX PRM functions
      3 *
      4 * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
      5 *
      6 * This program is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU General Public License as
      8 * published by the Free Software Foundation version 2.
      9 *
     10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     11 * kind, whether express or implied; without even the implied warranty
     12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 */
     15
     16#include <linux/kernel.h>
     17#include <linux/types.h>
     18#include <linux/errno.h>
     19#include <linux/err.h>
     20#include <linux/io.h>
     21
     22#include "powerdomain.h"
     23#include "prm33xx.h"
     24#include "prm-regbits-33xx.h"
     25
     26#define AM33XX_PRM_RSTCTRL_OFFSET		0x0000
     27
     28#define AM33XX_RST_GLOBAL_WARM_SW_MASK		(1 << 0)
     29
     30/* Read a register in a PRM instance */
     31static u32 am33xx_prm_read_reg(s16 inst, u16 idx)
     32{
     33	return readl_relaxed(prm_base.va + inst + idx);
     34}
     35
     36/* Write into a register in a PRM instance */
     37static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx)
     38{
     39	writel_relaxed(val, prm_base.va + inst + idx);
     40}
     41
     42/* Read-modify-write a register in PRM. Caller must lock */
     43static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
     44{
     45	u32 v;
     46
     47	v = am33xx_prm_read_reg(inst, idx);
     48	v &= ~mask;
     49	v |= bits;
     50	am33xx_prm_write_reg(v, inst, idx);
     51
     52	return v;
     53}
     54
     55/**
     56 * am33xx_prm_is_hardreset_asserted - read the HW reset line state of
     57 * submodules contained in the hwmod module
     58 * @shift: register bit shift corresponding to the reset line to check
     59 * @part: PRM partition, ignored for AM33xx
     60 * @inst: CM instance register offset (*_INST macro)
     61 * @rstctrl_offs: RM_RSTCTRL register address offset for this module
     62 *
     63 * Returns 1 if the (sub)module hardreset line is currently asserted,
     64 * 0 if the (sub)module hardreset line is not currently asserted, or
     65 * -EINVAL upon parameter error.
     66 */
     67static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
     68					    u16 rstctrl_offs)
     69{
     70	u32 v;
     71
     72	v = am33xx_prm_read_reg(inst, rstctrl_offs);
     73	v &= 1 << shift;
     74	v >>= shift;
     75
     76	return v;
     77}
     78
     79/**
     80 * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule
     81 * @shift: register bit shift corresponding to the reset line to assert
     82 * @part: CM partition, ignored for AM33xx
     83 * @inst: CM instance register offset (*_INST macro)
     84 * @rstctrl_reg: RM_RSTCTRL register address for this module
     85 *
     86 * Some IPs like dsp, ipu or iva contain processors that require an HW
     87 * reset line to be asserted / deasserted in order to fully enable the
     88 * IP.  These modules may have multiple hard-reset lines that reset
     89 * different 'submodules' inside the IP block.  This function will
     90 * place the submodule into reset.  Returns 0 upon success or -EINVAL
     91 * upon an argument error.
     92 */
     93static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst,
     94				       u16 rstctrl_offs)
     95{
     96	u32 mask = 1 << shift;
     97
     98	am33xx_prm_rmw_reg_bits(mask, mask, inst, rstctrl_offs);
     99
    100	return 0;
    101}
    102
    103/**
    104 * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and
    105 * wait
    106 * @shift: register bit shift corresponding to the reset line to deassert
    107 * @st_shift: reset status register bit shift corresponding to the reset line
    108 * @part: PRM partition, not used for AM33xx
    109 * @inst: CM instance register offset (*_INST macro)
    110 * @rstctrl_reg: RM_RSTCTRL register address for this module
    111 * @rstst_reg: RM_RSTST register address for this module
    112 *
    113 * Some IPs like dsp, ipu or iva contain processors that require an HW
    114 * reset line to be asserted / deasserted in order to fully enable the
    115 * IP.  These modules may have multiple hard-reset lines that reset
    116 * different 'submodules' inside the IP block.  This function will
    117 * take the submodule out of reset and wait until the PRCM indicates
    118 * that the reset has completed before returning.  Returns 0 upon success or
    119 * -EINVAL upon an argument error, -EEXIST if the submodule was already out
    120 * of reset, or -EBUSY if the submodule did not exit reset promptly.
    121 */
    122static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
    123					 s16 inst, u16 rstctrl_offs,
    124					 u16 rstst_offs)
    125{
    126	int c;
    127	u32 mask = 1 << st_shift;
    128
    129	/* Check the current status to avoid  de-asserting the line twice */
    130	if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0)
    131		return -EEXIST;
    132
    133	/* Clear the reset status by writing 1 to the status bit */
    134	am33xx_prm_rmw_reg_bits(0xffffffff, mask, inst, rstst_offs);
    135
    136	/* de-assert the reset control line */
    137	mask = 1 << shift;
    138
    139	am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs);
    140
    141	/* wait the status to be set */
    142	omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst,
    143							   rstst_offs),
    144			  MAX_MODULE_HARDRESET_WAIT, c);
    145
    146	return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
    147}
    148
    149static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
    150{
    151	am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK,
    152				(pwrst << OMAP_POWERSTATE_SHIFT),
    153				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
    154	return 0;
    155}
    156
    157static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
    158{
    159	u32 v;
    160
    161	v = am33xx_prm_read_reg(pwrdm->prcm_offs,  pwrdm->pwrstctrl_offs);
    162	v &= OMAP_POWERSTATE_MASK;
    163	v >>= OMAP_POWERSTATE_SHIFT;
    164
    165	return v;
    166}
    167
    168static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
    169{
    170	u32 v;
    171
    172	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
    173	v &= OMAP_POWERSTATEST_MASK;
    174	v >>= OMAP_POWERSTATEST_SHIFT;
    175
    176	return v;
    177}
    178
    179static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
    180{
    181	am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
    182				(1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT),
    183				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
    184	return 0;
    185}
    186
    187static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
    188{
    189	am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK,
    190				AM33XX_LASTPOWERSTATEENTERED_MASK,
    191				pwrdm->prcm_offs, pwrdm->pwrstst_offs);
    192	return 0;
    193}
    194
    195static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
    196{
    197	u32 m;
    198
    199	m = pwrdm->logicretstate_mask;
    200	if (!m)
    201		return -EINVAL;
    202
    203	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
    204				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
    205
    206	return 0;
    207}
    208
    209static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
    210{
    211	u32 v;
    212
    213	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
    214	v &= AM33XX_LOGICSTATEST_MASK;
    215	v >>= AM33XX_LOGICSTATEST_SHIFT;
    216
    217	return v;
    218}
    219
    220static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
    221{
    222	u32 v, m;
    223
    224	m = pwrdm->logicretstate_mask;
    225	if (!m)
    226		return -EINVAL;
    227
    228	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
    229	v &= m;
    230	v >>= __ffs(m);
    231
    232	return v;
    233}
    234
    235static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
    236		u8 pwrst)
    237{
    238	u32 m;
    239
    240	m = pwrdm->mem_on_mask[bank];
    241	if (!m)
    242		return -EINVAL;
    243
    244	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
    245				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
    246
    247	return 0;
    248}
    249
    250static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
    251					u8 pwrst)
    252{
    253	u32 m;
    254
    255	m = pwrdm->mem_ret_mask[bank];
    256	if (!m)
    257		return -EINVAL;
    258
    259	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
    260				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
    261
    262	return 0;
    263}
    264
    265static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
    266{
    267	u32 m, v;
    268
    269	m = pwrdm->mem_pwrst_mask[bank];
    270	if (!m)
    271		return -EINVAL;
    272
    273	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
    274	v &= m;
    275	v >>= __ffs(m);
    276
    277	return v;
    278}
    279
    280static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
    281{
    282	u32 m, v;
    283
    284	m = pwrdm->mem_retst_mask[bank];
    285	if (!m)
    286		return -EINVAL;
    287
    288	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
    289	v &= m;
    290	v >>= __ffs(m);
    291
    292	return v;
    293}
    294
    295static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm)
    296{
    297	u32 c = 0;
    298
    299	/*
    300	 * REVISIT: pwrdm_wait_transition() may be better implemented
    301	 * via a callback and a periodic timer check -- how long do we expect
    302	 * powerdomain transitions to take?
    303	 */
    304
    305	/* XXX Is this udelay() value meaningful? */
    306	while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs)
    307			& OMAP_INTRANSITION_MASK) &&
    308			(c++ < PWRDM_TRANSITION_BAILOUT))
    309		udelay(1);
    310
    311	if (c > PWRDM_TRANSITION_BAILOUT) {
    312		pr_err("powerdomain: %s: waited too long to complete transition\n",
    313		       pwrdm->name);
    314		return -EAGAIN;
    315	}
    316
    317	pr_debug("powerdomain: completed transition in %d loops\n", c);
    318
    319	return 0;
    320}
    321
    322static int am33xx_check_vcvp(void)
    323{
    324	/* No VC/VP on am33xx devices */
    325	return 0;
    326}
    327
    328/**
    329 * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset
    330 *
    331 * Immediately reboots the device through warm reset.
    332 */
    333static void am33xx_prm_global_warm_sw_reset(void)
    334{
    335	am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK,
    336				AM33XX_RST_GLOBAL_WARM_SW_MASK,
    337				AM33XX_PRM_DEVICE_MOD,
    338				AM33XX_PRM_RSTCTRL_OFFSET);
    339
    340	/* OCP barrier */
    341	(void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD,
    342				  AM33XX_PRM_RSTCTRL_OFFSET);
    343}
    344
    345static void am33xx_pwrdm_save_context(struct powerdomain *pwrdm)
    346{
    347	pwrdm->context = am33xx_prm_read_reg(pwrdm->prcm_offs,
    348						pwrdm->pwrstctrl_offs);
    349	/*
    350	 * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
    351	 * reading back a 1 indicates a request in progress.
    352	 */
    353	pwrdm->context &= ~AM33XX_LOWPOWERSTATECHANGE_MASK;
    354}
    355
    356static void am33xx_pwrdm_restore_context(struct powerdomain *pwrdm)
    357{
    358	int st, ctrl;
    359
    360	st = am33xx_prm_read_reg(pwrdm->prcm_offs,
    361				 pwrdm->pwrstst_offs);
    362
    363	am33xx_prm_write_reg(pwrdm->context, pwrdm->prcm_offs,
    364			     pwrdm->pwrstctrl_offs);
    365
    366	/* Make sure we only wait for a transition if there is one */
    367	st &= OMAP_POWERSTATEST_MASK;
    368	ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
    369
    370	if (st != ctrl)
    371		am33xx_pwrdm_wait_transition(pwrdm);
    372}
    373
    374struct pwrdm_ops am33xx_pwrdm_operations = {
    375	.pwrdm_set_next_pwrst		= am33xx_pwrdm_set_next_pwrst,
    376	.pwrdm_read_next_pwrst		= am33xx_pwrdm_read_next_pwrst,
    377	.pwrdm_read_pwrst		= am33xx_pwrdm_read_pwrst,
    378	.pwrdm_set_logic_retst		= am33xx_pwrdm_set_logic_retst,
    379	.pwrdm_read_logic_pwrst		= am33xx_pwrdm_read_logic_pwrst,
    380	.pwrdm_read_logic_retst		= am33xx_pwrdm_read_logic_retst,
    381	.pwrdm_clear_all_prev_pwrst	= am33xx_pwrdm_clear_all_prev_pwrst,
    382	.pwrdm_set_lowpwrstchange	= am33xx_pwrdm_set_lowpwrstchange,
    383	.pwrdm_read_mem_pwrst		= am33xx_pwrdm_read_mem_pwrst,
    384	.pwrdm_read_mem_retst		= am33xx_pwrdm_read_mem_retst,
    385	.pwrdm_set_mem_onst		= am33xx_pwrdm_set_mem_onst,
    386	.pwrdm_set_mem_retst		= am33xx_pwrdm_set_mem_retst,
    387	.pwrdm_wait_transition		= am33xx_pwrdm_wait_transition,
    388	.pwrdm_has_voltdm		= am33xx_check_vcvp,
    389	.pwrdm_save_context		= am33xx_pwrdm_save_context,
    390	.pwrdm_restore_context		= am33xx_pwrdm_restore_context,
    391};
    392
    393static struct prm_ll_data am33xx_prm_ll_data = {
    394	.assert_hardreset		= am33xx_prm_assert_hardreset,
    395	.deassert_hardreset		= am33xx_prm_deassert_hardreset,
    396	.is_hardreset_asserted		= am33xx_prm_is_hardreset_asserted,
    397	.reset_system			= am33xx_prm_global_warm_sw_reset,
    398};
    399
    400int __init am33xx_prm_init(const struct omap_prcm_init_data *data)
    401{
    402	return prm_register(&am33xx_prm_ll_data);
    403}
    404
    405static void __exit am33xx_prm_exit(void)
    406{
    407	prm_unregister(&am33xx_prm_ll_data);
    408}
    409__exitcall(am33xx_prm_exit);