1 /*
2 * AM33XX PRM instance functions
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated - http://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 */
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>
22 #include "common.h"
24 #include "prm33xx.h"
25 #include "prminst33xx.h"
26 #include "prm-regbits-33xx.h"
28 #define AM33XX_PRM_MOD_SIZE 0x100
29 #define AM33XX_PRM_MOD_START AM33XX_PRM_PER_MOD
30 #define PRM_REG_SZ 0x4
32 /*
33 * PRM Offsets are screwed up, and they are not consistent across modules.
34 * Below are the offsets for PWRSTCTRL and PWRSTST for respective modules.
35 */
36 static u16 off_fixup[][4] = {
37 /* PRM_PER_MOD: 0x0C, 0x08, 0x00, 0x04 */
38 {
39 AM33XX_PM_PER_PWRSTCTRL_OFFSET,
40 AM33XX_PM_PER_PWRSTST_OFFSET,
41 AM33XX_RM_PER_RSTCTRL_OFFSET,
42 AM33XX_RM_PER_RSTST_OFFSET,
43 },
44 /* PRM_WKUP_MOD: 0x04, 0x08, 0x00, 0x0C */
45 {
46 AM33XX_PM_WKUP_PWRSTCTRL_OFFSET,
47 AM33XX_PM_WKUP_PWRSTST_OFFSET,
48 AM33XX_RM_WKUP_RSTCTRL_OFFSET,
49 AM33XX_RM_WKUP_RSTST_OFFSET,
50 },
51 /* AM33XX_PRM_MPU_MOD: 0x00, 0x04, 0x08, NA */
52 {
53 AM33XX_PM_MPU_PWRSTCTRL_OFFSET,
54 AM33XX_PM_MPU_PWRSTST_OFFSET,
55 AM33XX_RM_MPU_RSTST_OFFSET,
56 AM33XX_RM_MPU_RSTST_OFFSET,
57 },
58 /* PRM_DEVICE_MOD: NA, NA, 0x00, 0x08 */
59 {
60 0x0,
61 0x0,
62 AM33XX_PRM_RSTCTRL_OFFSET,
63 AM33XX_PRM_RSTST_OFFSET,
64 },
65 /* PRM_RTC_MOD: 0x00, 0x04, NA, NA */
66 {
67 AM33XX_PM_RTC_PWRSTCTRL_OFFSET,
68 AM33XX_PM_RTC_PWRSTST_OFFSET,
69 0x0,
70 0x0,
71 },
72 /* PRM_GFX_MOD: 0x00, 0x10, 0x04, 0x14 */
73 {
74 AM33XX_PM_GFX_PWRSTCTRL_OFFSET,
75 AM33XX_PM_GFX_PWRSTST_OFFSET,
76 AM33XX_RM_GFX_RSTCTRL_OFFSET,
77 AM33XX_RM_GFX_RSTST_OFFSET,
78 },
79 /* PRM_CEFUSE_MOD: 0x00, 0x04, NA, NA */
80 {
81 AM33XX_PM_CEFUSE_PWRSTCTRL_OFFSET,
82 AM33XX_PM_CEFUSE_PWRSTST_OFFSET,
83 0x0,
84 0x0,
85 },
86 };
88 /* Read a register in a PRM instance */
89 u32 am33xx_prminst_read_inst_reg(s16 inst, u16 idx)
90 {
91 int i = (inst - AM33XX_PRM_MOD_START) / AM33XX_PRM_MOD_SIZE;
93 return __raw_readl(prm_base + inst + off_fixup[i][idx / PRM_REG_SZ]);
94 }
96 /* Write into a register in a PRM instance */
97 void am33xx_prminst_write_inst_reg(u32 val, s16 inst, u16 idx)
98 {
99 int i = (inst - AM33XX_PRM_MOD_START) / AM33XX_PRM_MOD_SIZE;
101 __raw_writel(val, prm_base + inst + off_fixup[i][idx / PRM_REG_SZ]);
102 }
104 /* Read-modify-write a register in PRM. Caller must lock */
105 u32 am33xx_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
106 {
107 u32 v;
109 v = am33xx_prminst_read_inst_reg(inst, idx);
110 v &= ~mask;
111 v |= bits;
112 am33xx_prminst_write_inst_reg(v, inst, idx);
114 return v;
115 }
117 /**
118 * am33xx_prminst_is_hardreset_asserted - read the HW reset line state of
119 * submodules contained in the hwmod module
120 * @prm_mod: PRM submodule base (e.g. CORE_MOD)
121 * @idx: register bit offset for calculating correct offset
122 * @mask: register bit mask
123 *
124 * Returns 1 if the (sub)module hardreset line is currently asserted,
125 * 0 if the (sub)module hardreset line is not currently asserted, or
126 * -EINVAL if called while running on a non-OMAP2/3 chip.
127 */
129 u32 am33xx_prminst_is_hardreset_asserted(s16 prm_mod, s16 idx, u32 mask)
130 {
131 u32 v;
133 v = am33xx_prminst_read_inst_reg(prm_mod, idx);
134 v &= mask;
135 v >>= __ffs(mask);
137 return v;
138 }
140 /**
141 * am33xx_prminst_assert_hardreset - assert the HW reset line of a submodule
142 * @prm_mod: PRM submodule base (e.g. GFX_MOD)
143 * @shift: register bit shift corresponding to the reset line to assert
144 *
145 * Some IPs like iva or PRUSS contain processors that require an HW
146 * reset line to be asserted / deasserted in order to fully enable the
147 * IP. These modules may have multiple hard-reset lines that reset
148 * different 'submodules' inside the IP block. This function will
149 * place the submodule into reset. Returns 0 upon success or -EINVAL
150 * upon an argument error.
151 */
153 int am33xx_prminst_assert_hardreset(s16 prm_mod, u8 shift)
154 {
155 u32 mask;
157 if (!cpu_is_am33xx())
158 return -EINVAL;
160 mask = 1 << shift;
161 /* assert the reset control line */
162 am33xx_prminst_rmw_inst_reg_bits(mask, mask, prm_mod, AM33XX_PM_RSTCTRL);
164 return 0;
165 }
167 /**
168 * am33xx_prminst_deassert_hardreset - deassert a submodule hardreset line and
169 * wait
170 * @prm_mod: PRM submodule base (e.g. CORE_MOD)
171 * @rst_shift: register bit shift corresponding to the reset line to deassert
172 * @st_shift: register bit shift for the status of the deasserted submodule
173 *
174 * Some IPs like SGX, PRUSS and M3 contain processors that require an HW
175 * reset line to be asserted / deasserted in order to fully enable the
176 * IP.
177 * This function will take the submodule out of reset and wait until the
178 * PRCM indicates that the reset has completed before returning.
179 * Returns 0 upon success or -EINVAL upon an argument error,
180 * -EEXIST if the submodule was already out of reset, or -EBUSY if the
181 * submodule did not exit reset promptly.
182 */
183 int am33xx_prminst_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift)
184 {
185 u32 rst, st;
187 if (!cpu_is_am33xx())
188 return -EINVAL;
190 rst = 1 << rst_shift;
191 st = 1 << st_shift;
193 /* Clear the reset status by writing 1 to the status bit */
194 am33xx_prminst_rmw_inst_reg_bits(0xffffffff, st, prm_mod,
195 AM33XX_PM_RSTST);
196 /* de-assert the reset control line */
197 am33xx_prminst_rmw_inst_reg_bits(rst, 0, prm_mod, AM33XX_PM_RSTCTRL);
198 /* TODO: wait the status to be set */
200 return 0;
201 }