Commit 397ee6685dbe3d1dd7b002bcf6231d969080ab0c

Authored by Keerthy
Committed by Greg Kroah-Hartman
1 parent fa036ea44c

bus: omap_l3_noc: Add resume hook to restore context

commit 61b43d4e919e8fa5e10c77ee32ba328da07e0264 upstream.

On certain SoCs such as AM437x SoC, L3_noc error registers are
maintained in power domain such as per domain which looses context as part
of low power state such as RTC+DDR mode. On these platforms when we
mask interrupts which we cannot handle, the source of these interrupts
still remain on resume, however, the flag mux registers now contain
their reset value (unmasked) - this breaks the system with infinite
interrupts since we do not these interrupts to take place ever again.

To handle this: restore the masking of interrupts which we have
already recorded in the system as ones we cannot handle.

Fixes: 2100b595b7 ("bus: omap_l3_noc: ignore masked out unclearable targets")
Acked-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 1 changed file with 55 additions and 0 deletions Inline Diff

drivers/bus/omap_l3_noc.c
1 /* 1 /*
2 * OMAP L3 Interconnect error handling driver 2 * OMAP L3 Interconnect error handling driver
3 * 3 *
4 * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/ 4 * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/
5 * Santosh Shilimkar <santosh.shilimkar@ti.com> 5 * Santosh Shilimkar <santosh.shilimkar@ti.com>
6 * Sricharan <r.sricharan@ti.com> 6 * Sricharan <r.sricharan@ti.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 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 9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11 * 11 *
12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
13 * kind, whether express or implied; without even the implied warranty 13 * kind, whether express or implied; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details. 15 * GNU General Public License for more details.
16 */ 16 */
17 #include <linux/init.h> 17 #include <linux/init.h>
18 #include <linux/interrupt.h> 18 #include <linux/interrupt.h>
19 #include <linux/io.h> 19 #include <linux/io.h>
20 #include <linux/kernel.h> 20 #include <linux/kernel.h>
21 #include <linux/module.h> 21 #include <linux/module.h>
22 #include <linux/of_device.h> 22 #include <linux/of_device.h>
23 #include <linux/of.h> 23 #include <linux/of.h>
24 #include <linux/platform_device.h> 24 #include <linux/platform_device.h>
25 #include <linux/slab.h> 25 #include <linux/slab.h>
26 26
27 #include "omap_l3_noc.h" 27 #include "omap_l3_noc.h"
28 28
29 /** 29 /**
30 * l3_handle_target() - Handle Target specific parse and reporting 30 * l3_handle_target() - Handle Target specific parse and reporting
31 * @l3: pointer to l3 struct 31 * @l3: pointer to l3 struct
32 * @base: base address of clkdm 32 * @base: base address of clkdm
33 * @flag_mux: flagmux corresponding to the event 33 * @flag_mux: flagmux corresponding to the event
34 * @err_src: error source index of the slave (target) 34 * @err_src: error source index of the slave (target)
35 * 35 *
36 * This does the second part of the error interrupt handling: 36 * This does the second part of the error interrupt handling:
37 * 3) Parse in the slave information 37 * 3) Parse in the slave information
38 * 4) Print the logged information. 38 * 4) Print the logged information.
39 * 5) Add dump stack to provide kernel trace. 39 * 5) Add dump stack to provide kernel trace.
40 * 6) Clear the source if known. 40 * 6) Clear the source if known.
41 * 41 *
42 * This handles two types of errors: 42 * This handles two types of errors:
43 * 1) Custom errors in L3 : 43 * 1) Custom errors in L3 :
44 * Target like DMM/FW/EMIF generates SRESP=ERR error 44 * Target like DMM/FW/EMIF generates SRESP=ERR error
45 * 2) Standard L3 error: 45 * 2) Standard L3 error:
46 * - Unsupported CMD. 46 * - Unsupported CMD.
47 * L3 tries to access target while it is idle 47 * L3 tries to access target while it is idle
48 * - OCP disconnect. 48 * - OCP disconnect.
49 * - Address hole error: 49 * - Address hole error:
50 * If DSS/ISS/FDIF/USBHOSTFS access a target where they 50 * If DSS/ISS/FDIF/USBHOSTFS access a target where they
51 * do not have connectivity, the error is logged in 51 * do not have connectivity, the error is logged in
52 * their default target which is DMM2. 52 * their default target which is DMM2.
53 * 53 *
54 * On High Secure devices, firewall errors are possible and those 54 * On High Secure devices, firewall errors are possible and those
55 * can be trapped as well. But the trapping is implemented as part 55 * can be trapped as well. But the trapping is implemented as part
56 * secure software and hence need not be implemented here. 56 * secure software and hence need not be implemented here.
57 */ 57 */
58 static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, 58 static int l3_handle_target(struct omap_l3 *l3, void __iomem *base,
59 struct l3_flagmux_data *flag_mux, int err_src) 59 struct l3_flagmux_data *flag_mux, int err_src)
60 { 60 {
61 int k; 61 int k;
62 u32 std_err_main, clear, masterid; 62 u32 std_err_main, clear, masterid;
63 u8 op_code, m_req_info; 63 u8 op_code, m_req_info;
64 void __iomem *l3_targ_base; 64 void __iomem *l3_targ_base;
65 void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; 65 void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr;
66 void __iomem *l3_targ_hdr, *l3_targ_info; 66 void __iomem *l3_targ_hdr, *l3_targ_info;
67 struct l3_target_data *l3_targ_inst; 67 struct l3_target_data *l3_targ_inst;
68 struct l3_masters_data *master; 68 struct l3_masters_data *master;
69 char *target_name, *master_name = "UN IDENTIFIED"; 69 char *target_name, *master_name = "UN IDENTIFIED";
70 char *err_description; 70 char *err_description;
71 char err_string[30] = { 0 }; 71 char err_string[30] = { 0 };
72 char info_string[60] = { 0 }; 72 char info_string[60] = { 0 };
73 73
74 /* We DONOT expect err_src to go out of bounds */ 74 /* We DONOT expect err_src to go out of bounds */
75 BUG_ON(err_src > MAX_CLKDM_TARGETS); 75 BUG_ON(err_src > MAX_CLKDM_TARGETS);
76 76
77 if (err_src < flag_mux->num_targ_data) { 77 if (err_src < flag_mux->num_targ_data) {
78 l3_targ_inst = &flag_mux->l3_targ[err_src]; 78 l3_targ_inst = &flag_mux->l3_targ[err_src];
79 target_name = l3_targ_inst->name; 79 target_name = l3_targ_inst->name;
80 l3_targ_base = base + l3_targ_inst->offset; 80 l3_targ_base = base + l3_targ_inst->offset;
81 } else { 81 } else {
82 target_name = L3_TARGET_NOT_SUPPORTED; 82 target_name = L3_TARGET_NOT_SUPPORTED;
83 } 83 }
84 84
85 if (target_name == L3_TARGET_NOT_SUPPORTED) 85 if (target_name == L3_TARGET_NOT_SUPPORTED)
86 return -ENODEV; 86 return -ENODEV;
87 87
88 /* Read the stderrlog_main_source from clk domain */ 88 /* Read the stderrlog_main_source from clk domain */
89 l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; 89 l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN;
90 l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB; 90 l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB;
91 91
92 std_err_main = readl_relaxed(l3_targ_stderr); 92 std_err_main = readl_relaxed(l3_targ_stderr);
93 93
94 switch (std_err_main & CUSTOM_ERROR) { 94 switch (std_err_main & CUSTOM_ERROR) {
95 case STANDARD_ERROR: 95 case STANDARD_ERROR:
96 err_description = "Standard"; 96 err_description = "Standard";
97 snprintf(err_string, sizeof(err_string), 97 snprintf(err_string, sizeof(err_string),
98 ": At Address: 0x%08X ", 98 ": At Address: 0x%08X ",
99 readl_relaxed(l3_targ_slvofslsb)); 99 readl_relaxed(l3_targ_slvofslsb));
100 100
101 l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_MSTADDR; 101 l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_MSTADDR;
102 l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_HDR; 102 l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_HDR;
103 l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_INFO; 103 l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_INFO;
104 break; 104 break;
105 105
106 case CUSTOM_ERROR: 106 case CUSTOM_ERROR:
107 err_description = "Custom"; 107 err_description = "Custom";
108 108
109 l3_targ_mstaddr = l3_targ_base + 109 l3_targ_mstaddr = l3_targ_base +
110 L3_TARG_STDERRLOG_CINFO_MSTADDR; 110 L3_TARG_STDERRLOG_CINFO_MSTADDR;
111 l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_CINFO_OPCODE; 111 l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_CINFO_OPCODE;
112 l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_CINFO_INFO; 112 l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_CINFO_INFO;
113 break; 113 break;
114 114
115 default: 115 default:
116 /* Nothing to be handled here as of now */ 116 /* Nothing to be handled here as of now */
117 return 0; 117 return 0;
118 } 118 }
119 119
120 /* STDERRLOG_MSTADDR Stores the NTTP master address. */ 120 /* STDERRLOG_MSTADDR Stores the NTTP master address. */
121 masterid = (readl_relaxed(l3_targ_mstaddr) & 121 masterid = (readl_relaxed(l3_targ_mstaddr) &
122 l3->mst_addr_mask) >> __ffs(l3->mst_addr_mask); 122 l3->mst_addr_mask) >> __ffs(l3->mst_addr_mask);
123 123
124 for (k = 0, master = l3->l3_masters; k < l3->num_masters; 124 for (k = 0, master = l3->l3_masters; k < l3->num_masters;
125 k++, master++) { 125 k++, master++) {
126 if (masterid == master->id) { 126 if (masterid == master->id) {
127 master_name = master->name; 127 master_name = master->name;
128 break; 128 break;
129 } 129 }
130 } 130 }
131 131
132 op_code = readl_relaxed(l3_targ_hdr) & 0x7; 132 op_code = readl_relaxed(l3_targ_hdr) & 0x7;
133 133
134 m_req_info = readl_relaxed(l3_targ_info) & 0xF; 134 m_req_info = readl_relaxed(l3_targ_info) & 0xF;
135 snprintf(info_string, sizeof(info_string), 135 snprintf(info_string, sizeof(info_string),
136 ": %s in %s mode during %s access", 136 ": %s in %s mode during %s access",
137 (m_req_info & BIT(0)) ? "Opcode Fetch" : "Data Access", 137 (m_req_info & BIT(0)) ? "Opcode Fetch" : "Data Access",
138 (m_req_info & BIT(1)) ? "Supervisor" : "User", 138 (m_req_info & BIT(1)) ? "Supervisor" : "User",
139 (m_req_info & BIT(3)) ? "Debug" : "Functional"); 139 (m_req_info & BIT(3)) ? "Debug" : "Functional");
140 140
141 WARN(true, 141 WARN(true,
142 "%s:L3 %s Error: MASTER %s TARGET %s (%s)%s%s\n", 142 "%s:L3 %s Error: MASTER %s TARGET %s (%s)%s%s\n",
143 dev_name(l3->dev), 143 dev_name(l3->dev),
144 err_description, 144 err_description,
145 master_name, target_name, 145 master_name, target_name,
146 l3_transaction_type[op_code], 146 l3_transaction_type[op_code],
147 err_string, info_string); 147 err_string, info_string);
148 148
149 /* clear the std error log*/ 149 /* clear the std error log*/
150 clear = std_err_main | CLEAR_STDERR_LOG; 150 clear = std_err_main | CLEAR_STDERR_LOG;
151 writel_relaxed(clear, l3_targ_stderr); 151 writel_relaxed(clear, l3_targ_stderr);
152 152
153 return 0; 153 return 0;
154 } 154 }
155 155
156 /** 156 /**
157 * l3_interrupt_handler() - interrupt handler for l3 events 157 * l3_interrupt_handler() - interrupt handler for l3 events
158 * @irq: irq number 158 * @irq: irq number
159 * @_l3: pointer to l3 structure 159 * @_l3: pointer to l3 structure
160 * 160 *
161 * Interrupt Handler for L3 error detection. 161 * Interrupt Handler for L3 error detection.
162 * 1) Identify the L3 clockdomain partition to which the error belongs to. 162 * 1) Identify the L3 clockdomain partition to which the error belongs to.
163 * 2) Identify the slave where the error information is logged 163 * 2) Identify the slave where the error information is logged
164 * ... handle the slave event.. 164 * ... handle the slave event..
165 * 7) if the slave is unknown, mask out the slave. 165 * 7) if the slave is unknown, mask out the slave.
166 */ 166 */
167 static irqreturn_t l3_interrupt_handler(int irq, void *_l3) 167 static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
168 { 168 {
169 struct omap_l3 *l3 = _l3; 169 struct omap_l3 *l3 = _l3;
170 int inttype, i, ret; 170 int inttype, i, ret;
171 int err_src = 0; 171 int err_src = 0;
172 u32 err_reg, mask_val; 172 u32 err_reg, mask_val;
173 void __iomem *base, *mask_reg; 173 void __iomem *base, *mask_reg;
174 struct l3_flagmux_data *flag_mux; 174 struct l3_flagmux_data *flag_mux;
175 175
176 /* Get the Type of interrupt */ 176 /* Get the Type of interrupt */
177 inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; 177 inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
178 178
179 for (i = 0; i < l3->num_modules; i++) { 179 for (i = 0; i < l3->num_modules; i++) {
180 /* 180 /*
181 * Read the regerr register of the clock domain 181 * Read the regerr register of the clock domain
182 * to determine the source 182 * to determine the source
183 */ 183 */
184 base = l3->l3_base[i]; 184 base = l3->l3_base[i];
185 flag_mux = l3->l3_flagmux[i]; 185 flag_mux = l3->l3_flagmux[i];
186 err_reg = readl_relaxed(base + flag_mux->offset + 186 err_reg = readl_relaxed(base + flag_mux->offset +
187 L3_FLAGMUX_REGERR0 + (inttype << 3)); 187 L3_FLAGMUX_REGERR0 + (inttype << 3));
188 188
189 err_reg &= ~(inttype ? flag_mux->mask_app_bits : 189 err_reg &= ~(inttype ? flag_mux->mask_app_bits :
190 flag_mux->mask_dbg_bits); 190 flag_mux->mask_dbg_bits);
191 191
192 /* Get the corresponding error and analyse */ 192 /* Get the corresponding error and analyse */
193 if (err_reg) { 193 if (err_reg) {
194 /* Identify the source from control status register */ 194 /* Identify the source from control status register */
195 err_src = __ffs(err_reg); 195 err_src = __ffs(err_reg);
196 196
197 ret = l3_handle_target(l3, base, flag_mux, err_src); 197 ret = l3_handle_target(l3, base, flag_mux, err_src);
198 198
199 /* 199 /*
200 * Certain plaforms may have "undocumented" status 200 * Certain plaforms may have "undocumented" status
201 * pending on boot. So dont generate a severe warning 201 * pending on boot. So dont generate a severe warning
202 * here. Just mask it off to prevent the error from 202 * here. Just mask it off to prevent the error from
203 * reoccuring and locking up the system. 203 * reoccuring and locking up the system.
204 */ 204 */
205 if (ret) { 205 if (ret) {
206 dev_err(l3->dev, 206 dev_err(l3->dev,
207 "L3 %s error: target %d mod:%d %s\n", 207 "L3 %s error: target %d mod:%d %s\n",
208 inttype ? "debug" : "application", 208 inttype ? "debug" : "application",
209 err_src, i, "(unclearable)"); 209 err_src, i, "(unclearable)");
210 210
211 mask_reg = base + flag_mux->offset + 211 mask_reg = base + flag_mux->offset +
212 L3_FLAGMUX_MASK0 + (inttype << 3); 212 L3_FLAGMUX_MASK0 + (inttype << 3);
213 mask_val = readl_relaxed(mask_reg); 213 mask_val = readl_relaxed(mask_reg);
214 mask_val &= ~(1 << err_src); 214 mask_val &= ~(1 << err_src);
215 writel_relaxed(mask_val, mask_reg); 215 writel_relaxed(mask_val, mask_reg);
216 216
217 /* Mark these bits as to be ignored */ 217 /* Mark these bits as to be ignored */
218 if (inttype) 218 if (inttype)
219 flag_mux->mask_app_bits |= 1 << err_src; 219 flag_mux->mask_app_bits |= 1 << err_src;
220 else 220 else
221 flag_mux->mask_dbg_bits |= 1 << err_src; 221 flag_mux->mask_dbg_bits |= 1 << err_src;
222 } 222 }
223 223
224 /* Error found so break the for loop */ 224 /* Error found so break the for loop */
225 break; 225 break;
226 } 226 }
227 } 227 }
228 return IRQ_HANDLED; 228 return IRQ_HANDLED;
229 } 229 }
230 230
231 static const struct of_device_id l3_noc_match[] = { 231 static const struct of_device_id l3_noc_match[] = {
232 {.compatible = "ti,omap4-l3-noc", .data = &omap_l3_data}, 232 {.compatible = "ti,omap4-l3-noc", .data = &omap_l3_data},
233 {.compatible = "ti,dra7-l3-noc", .data = &dra_l3_data}, 233 {.compatible = "ti,dra7-l3-noc", .data = &dra_l3_data},
234 {.compatible = "ti,am4372-l3-noc", .data = &am4372_l3_data}, 234 {.compatible = "ti,am4372-l3-noc", .data = &am4372_l3_data},
235 {}, 235 {},
236 }; 236 };
237 MODULE_DEVICE_TABLE(of, l3_noc_match); 237 MODULE_DEVICE_TABLE(of, l3_noc_match);
238 238
239 static int omap_l3_probe(struct platform_device *pdev) 239 static int omap_l3_probe(struct platform_device *pdev)
240 { 240 {
241 const struct of_device_id *of_id; 241 const struct of_device_id *of_id;
242 static struct omap_l3 *l3; 242 static struct omap_l3 *l3;
243 int ret, i, res_idx; 243 int ret, i, res_idx;
244 244
245 of_id = of_match_device(l3_noc_match, &pdev->dev); 245 of_id = of_match_device(l3_noc_match, &pdev->dev);
246 if (!of_id) { 246 if (!of_id) {
247 dev_err(&pdev->dev, "OF data missing\n"); 247 dev_err(&pdev->dev, "OF data missing\n");
248 return -EINVAL; 248 return -EINVAL;
249 } 249 }
250 250
251 l3 = devm_kzalloc(&pdev->dev, sizeof(*l3), GFP_KERNEL); 251 l3 = devm_kzalloc(&pdev->dev, sizeof(*l3), GFP_KERNEL);
252 if (!l3) 252 if (!l3)
253 return -ENOMEM; 253 return -ENOMEM;
254 254
255 memcpy(l3, of_id->data, sizeof(*l3)); 255 memcpy(l3, of_id->data, sizeof(*l3));
256 l3->dev = &pdev->dev; 256 l3->dev = &pdev->dev;
257 platform_set_drvdata(pdev, l3); 257 platform_set_drvdata(pdev, l3);
258 258
259 /* Get mem resources */ 259 /* Get mem resources */
260 for (i = 0, res_idx = 0; i < l3->num_modules; i++) { 260 for (i = 0, res_idx = 0; i < l3->num_modules; i++) {
261 struct resource *res; 261 struct resource *res;
262 262
263 if (l3->l3_base[i] == L3_BASE_IS_SUBMODULE) { 263 if (l3->l3_base[i] == L3_BASE_IS_SUBMODULE) {
264 /* First entry cannot be submodule */ 264 /* First entry cannot be submodule */
265 BUG_ON(i == 0); 265 BUG_ON(i == 0);
266 l3->l3_base[i] = l3->l3_base[i - 1]; 266 l3->l3_base[i] = l3->l3_base[i - 1];
267 continue; 267 continue;
268 } 268 }
269 res = platform_get_resource(pdev, IORESOURCE_MEM, res_idx); 269 res = platform_get_resource(pdev, IORESOURCE_MEM, res_idx);
270 l3->l3_base[i] = devm_ioremap_resource(&pdev->dev, res); 270 l3->l3_base[i] = devm_ioremap_resource(&pdev->dev, res);
271 if (IS_ERR(l3->l3_base[i])) { 271 if (IS_ERR(l3->l3_base[i])) {
272 dev_err(l3->dev, "ioremap %d failed\n", i); 272 dev_err(l3->dev, "ioremap %d failed\n", i);
273 return PTR_ERR(l3->l3_base[i]); 273 return PTR_ERR(l3->l3_base[i]);
274 } 274 }
275 res_idx++; 275 res_idx++;
276 } 276 }
277 277
278 /* 278 /*
279 * Setup interrupt Handlers 279 * Setup interrupt Handlers
280 */ 280 */
281 l3->debug_irq = platform_get_irq(pdev, 0); 281 l3->debug_irq = platform_get_irq(pdev, 0);
282 ret = devm_request_irq(l3->dev, l3->debug_irq, l3_interrupt_handler, 282 ret = devm_request_irq(l3->dev, l3->debug_irq, l3_interrupt_handler,
283 IRQF_DISABLED, "l3-dbg-irq", l3); 283 IRQF_DISABLED, "l3-dbg-irq", l3);
284 if (ret) { 284 if (ret) {
285 dev_err(l3->dev, "request_irq failed for %d\n", 285 dev_err(l3->dev, "request_irq failed for %d\n",
286 l3->debug_irq); 286 l3->debug_irq);
287 return ret; 287 return ret;
288 } 288 }
289 289
290 l3->app_irq = platform_get_irq(pdev, 1); 290 l3->app_irq = platform_get_irq(pdev, 1);
291 ret = devm_request_irq(l3->dev, l3->app_irq, l3_interrupt_handler, 291 ret = devm_request_irq(l3->dev, l3->app_irq, l3_interrupt_handler,
292 IRQF_DISABLED, "l3-app-irq", l3); 292 IRQF_DISABLED, "l3-app-irq", l3);
293 if (ret) 293 if (ret)
294 dev_err(l3->dev, "request_irq failed for %d\n", l3->app_irq); 294 dev_err(l3->dev, "request_irq failed for %d\n", l3->app_irq);
295 295
296 return ret; 296 return ret;
297 } 297 }
298 298
299 #ifdef CONFIG_PM
300
301 /**
302 * l3_resume_noirq() - resume function for l3_noc
303 * @dev: pointer to l3_noc device structure
304 *
305 * We only have the resume handler only since we
306 * have already maintained the delta register
307 * configuration as part of configuring the system
308 */
309 static int l3_resume_noirq(struct device *dev)
310 {
311 struct omap_l3 *l3 = dev_get_drvdata(dev);
312 int i;
313 struct l3_flagmux_data *flag_mux;
314 void __iomem *base, *mask_regx = NULL;
315 u32 mask_val;
316
317 for (i = 0; i < l3->num_modules; i++) {
318 base = l3->l3_base[i];
319 flag_mux = l3->l3_flagmux[i];
320 if (!flag_mux->mask_app_bits && !flag_mux->mask_dbg_bits)
321 continue;
322
323 mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
324 (L3_APPLICATION_ERROR << 3);
325 mask_val = readl_relaxed(mask_regx);
326 mask_val &= ~(flag_mux->mask_app_bits);
327
328 writel_relaxed(mask_val, mask_regx);
329 mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
330 (L3_DEBUG_ERROR << 3);
331 mask_val = readl_relaxed(mask_regx);
332 mask_val &= ~(flag_mux->mask_dbg_bits);
333
334 writel_relaxed(mask_val, mask_regx);
335 }
336
337 /* Dummy read to force OCP barrier */
338 if (mask_regx)
339 (void)readl(mask_regx);
340
341 return 0;
342 }
343
344 static const struct dev_pm_ops l3_dev_pm_ops = {
345 .resume_noirq = l3_resume_noirq,
346 };
347
348 #define L3_DEV_PM_OPS (&l3_dev_pm_ops)
349 #else
350 #define L3_DEV_PM_OPS NULL
351 #endif
352
299 static struct platform_driver omap_l3_driver = { 353 static struct platform_driver omap_l3_driver = {
300 .probe = omap_l3_probe, 354 .probe = omap_l3_probe,
301 .driver = { 355 .driver = {
302 .name = "omap_l3_noc", 356 .name = "omap_l3_noc",
303 .owner = THIS_MODULE, 357 .owner = THIS_MODULE,
358 .pm = L3_DEV_PM_OPS,
304 .of_match_table = of_match_ptr(l3_noc_match), 359 .of_match_table = of_match_ptr(l3_noc_match),
305 }, 360 },
306 }; 361 };
307 362
308 static int __init omap_l3_init(void) 363 static int __init omap_l3_init(void)
309 { 364 {
310 return platform_driver_register(&omap_l3_driver); 365 return platform_driver_register(&omap_l3_driver);
311 } 366 }
312 postcore_initcall_sync(omap_l3_init); 367 postcore_initcall_sync(omap_l3_init);
313 368
314 static void __exit omap_l3_exit(void) 369 static void __exit omap_l3_exit(void)
315 { 370 {
316 platform_driver_unregister(&omap_l3_driver); 371 platform_driver_unregister(&omap_l3_driver);
317 } 372 }
318 module_exit(omap_l3_exit); 373 module_exit(omap_l3_exit);
319 374