1 /* 2 * OMAP4 PRM instance functions 3 * 4 * Copyright (C) 2009 Nokia Corporation 5 * Copyright (C) 2011 Texas Instruments, Inc. 6 * Paul Walmsley 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/types.h> 15 #include <linux/errno.h> 16 #include <linux/err.h> 17 #include <linux/io.h> 18 19 #include "iomap.h" 20 #include "common.h" 21 #include "prcm-common.h" 22 #include "prm44xx.h" 23 #include "prm54xx.h" 24 #include "prm7xx.h" 25 #include "prminst44xx.h" 26 #include "prm-regbits-44xx.h" 27 #include "prcm44xx.h" 28 #include "prcm43xx.h" 29 #include "prcm_mpu44xx.h" 30 #include "soc.h" 31 32 static void __iomem *_prm_bases[OMAP4_MAX_PRCM_PARTITIONS]; 33 34 /** 35 * omap_prm_base_init - Populates the prm partitions 36 * 37 * Populates the base addresses of the _prm_bases 38 * array used for read/write of prm module registers. 39 */ 40 void omap_prm_base_init(void) 41 { 42 _prm_bases[OMAP4430_PRM_PARTITION] = prm_base; 43 _prm_bases[OMAP4430_PRCM_MPU_PARTITION] = prcm_mpu_base; 44 } 45 46 /* Read a register in a PRM instance */ 47 u32 omap4_prminst_read_inst_reg(u8 part, s16 inst, u16 idx) 48 { 49 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || 50 part == OMAP4430_INVALID_PRCM_PARTITION || 51 !_prm_bases[part]); 52 return __raw_readl(_prm_bases[part] + inst + idx); 53 } 54 55 /* Write into a register in a PRM instance */ 56 void omap4_prminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx) 57 { 58 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || 59 part == OMAP4430_INVALID_PRCM_PARTITION || 60 !_prm_bases[part]); 61 __raw_writel(val, _prm_bases[part] + inst + idx); 62 } 63 64 /* Read-modify-write a register in PRM. Caller must lock */ 65 u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst, 66 u16 idx) 67 { 68 u32 v; 69 70 v = omap4_prminst_read_inst_reg(part, inst, idx); 71 v &= ~mask; 72 v |= bits; 73 omap4_prminst_write_inst_reg(v, part, inst, idx); 74 75 return v; 76 } 77 78 /* 79 * Address offset (in bytes) between the reset control and the reset 80 * status registers: 4 bytes on OMAP4 81 */ 82 #define OMAP4_RST_CTRL_ST_OFFSET 4 83 84 /** 85 * omap4_prminst_is_hardreset_asserted - read the HW reset line state of 86 * submodules contained in the hwmod module 87 * @rstctrl_reg: RM_RSTCTRL register address for this module 88 * @shift: register bit shift corresponding to the reset line to check 89 * 90 * Returns 1 if the (sub)module hardreset line is currently asserted, 91 * 0 if the (sub)module hardreset line is not currently asserted, or 92 * -EINVAL upon parameter error. 93 */ 94 int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst, 95 u16 rstctrl_offs) 96 { 97 u32 v; 98 99 v = omap4_prminst_read_inst_reg(part, inst, rstctrl_offs); 100 v &= 1 << shift; 101 v >>= shift; 102 103 return v; 104 } 105 106 /** 107 * omap4_prminst_assert_hardreset - assert the HW reset line of a submodule 108 * @rstctrl_reg: RM_RSTCTRL register address for this module 109 * @shift: register bit shift corresponding to the reset line to assert 110 * 111 * Some IPs like dsp, ipu or iva contain processors that require an HW 112 * reset line to be asserted / deasserted in order to fully enable the 113 * IP. These modules may have multiple hard-reset lines that reset 114 * different 'submodules' inside the IP block. This function will 115 * place the submodule into reset. Returns 0 upon success or -EINVAL 116 * upon an argument error. 117 */ 118 int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, 119 u16 rstctrl_offs) 120 { 121 u32 mask = 1 << shift; 122 123 omap4_prminst_rmw_inst_reg_bits(mask, mask, part, inst, rstctrl_offs); 124 125 return 0; 126 } 127 128 /** 129 * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and 130 * wait 131 * @rstctrl_reg: RM_RSTCTRL register address for this module 132 * @shift: register bit shift corresponding to the reset line to deassert 133 * 134 * Some IPs like dsp, ipu or iva contain processors that require an HW 135 * reset line to be asserted / deasserted in order to fully enable the 136 * IP. These modules may have multiple hard-reset lines that reset 137 * different 'submodules' inside the IP block. This function will 138 * take the submodule out of reset and wait until the PRCM indicates 139 * that the reset has completed before returning. Returns 0 upon success or 140 * -EINVAL upon an argument error, -EEXIST if the submodule was already out 141 * of reset, or -EBUSY if the submodule did not exit reset promptly. 142 */ 143 int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, 144 u16 rstctrl_offs) 145 { 146 int c; 147 u32 mask = 1 << shift; 148 u16 rstst_offs = rstctrl_offs + OMAP4_RST_CTRL_ST_OFFSET; 149 150 /* Check the current status to avoid de-asserting the line twice */ 151 if (omap4_prminst_is_hardreset_asserted(shift, part, inst, 152 rstctrl_offs) == 0) 153 return -EEXIST; 154 155 /* Clear the reset status by writing 1 to the status bit */ 156 omap4_prminst_rmw_inst_reg_bits(0xffffffff, mask, part, inst, 157 rstst_offs); 158 /* de-assert the reset control line */ 159 omap4_prminst_rmw_inst_reg_bits(mask, 0, part, inst, rstctrl_offs); 160 /* wait the status to be set */ 161 omap_test_timeout(omap4_prminst_is_hardreset_asserted(shift, part, inst, 162 rstst_offs), 163 MAX_MODULE_HARDRESET_WAIT, c); 164 165 return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; 166 } 167 168 169 void omap4_prminst_global_warm_sw_reset(void) 170 { 171 u32 v; 172 s16 dev_inst; 173 174 if (cpu_is_omap44xx()) 175 dev_inst = OMAP4430_PRM_DEVICE_INST; 176 else if (soc_is_omap54xx()) 177 dev_inst = OMAP54XX_PRM_DEVICE_INST; 178 else if (soc_is_dra7xx()) 179 dev_inst = DRA7XX_PRM_DEVICE_INST; 180 else if (soc_is_am43xx()) 181 dev_inst = AM43XX_PRM_DEVICE_INST; 182 else 183 return; 184 185 v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, dev_inst, 186 OMAP4_PRM_RSTCTRL_OFFSET); 187 v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK; 188 omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION, 189 dev_inst, 190 OMAP4_PRM_RSTCTRL_OFFSET); 191 192 /* OCP barrier */ 193 v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, 194 dev_inst, 195 OMAP4_PRM_RSTCTRL_OFFSET); 196 } 197