aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorJuergen Borleis <jbe@pengutronix.de>2015-04-27 09:59:49 -0400
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2015-06-19 14:03:21 -0400
commitc7e9bbe022c7bee57d9e14b42a7c3732da8db558 (patch)
tree7b81b55261e6ef1212646f6657262d2e762f7596 /drivers/rtc
parent3ba3fab765beecd599d8e8e00dc2ed4306518dfd (diff)
rtc: imxdi: add the unit recovery code
This code is required to recover the unit from a security violation. Hopefully this code can recover the unit from a hardware related invalid state as well. Signed-off-by: Juergen Borleis <jbe@pengutronix.de> Signed-off-by: Robert Schwebel <rsc@pengutronix.de> [rsc: got NDA clearance from Freescale] Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/rtc-imxdi.c317
1 files changed, 279 insertions, 38 deletions
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 63ca52b2029b..3d7f0390170e 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -173,6 +173,281 @@ struct imxdi_dev {
173 */ 173 */
174 174
175/* 175/*
176 * Do a write into the unit without interrupt support.
177 * We do not need to check the WEF here, because the only reason this kind of
178 * write error can happen is if we write to the unit twice within the 122 us
179 * interval. This cannot happen, since we are using this function only while
180 * setting up the unit.
181 */
182static void di_write_busy_wait(const struct imxdi_dev *imxdi, u32 val,
183 unsigned reg)
184{
185 /* do the register write */
186 writel(val, imxdi->ioaddr + reg);
187
188 /*
189 * now it takes four 32,768 kHz clock cycles to take
190 * the change into effect = 122 us
191 */
192 usleep_range(130, 200);
193}
194
195static void di_report_tamper_info(struct imxdi_dev *imxdi, u32 dsr)
196{
197 u32 dtcr;
198
199 dtcr = readl(imxdi->ioaddr + DTCR);
200
201 dev_emerg(&imxdi->pdev->dev, "DryIce tamper event detected\n");
202 /* the following flags force a transition into the "FAILURE STATE" */
203 if (dsr & DSR_VTD)
204 dev_emerg(&imxdi->pdev->dev, "%sVoltage Tamper Event\n",
205 dtcr & DTCR_VTE ? "" : "Spurious ");
206
207 if (dsr & DSR_CTD)
208 dev_emerg(&imxdi->pdev->dev, "%s32768 Hz Clock Tamper Event\n",
209 dtcr & DTCR_CTE ? "" : "Spurious ");
210
211 if (dsr & DSR_TTD)
212 dev_emerg(&imxdi->pdev->dev, "%sTemperature Tamper Event\n",
213 dtcr & DTCR_TTE ? "" : "Spurious ");
214
215 if (dsr & DSR_SAD)
216 dev_emerg(&imxdi->pdev->dev,
217 "%sSecure Controller Alarm Event\n",
218 dtcr & DTCR_SAIE ? "" : "Spurious ");
219
220 if (dsr & DSR_EBD)
221 dev_emerg(&imxdi->pdev->dev, "%sExternal Boot Tamper Event\n",
222 dtcr & DTCR_EBE ? "" : "Spurious ");
223
224 if (dsr & DSR_ETAD)
225 dev_emerg(&imxdi->pdev->dev, "%sExternal Tamper A Event\n",
226 dtcr & DTCR_ETAE ? "" : "Spurious ");
227
228 if (dsr & DSR_ETBD)
229 dev_emerg(&imxdi->pdev->dev, "%sExternal Tamper B Event\n",
230 dtcr & DTCR_ETBE ? "" : "Spurious ");
231
232 if (dsr & DSR_WTD)
233 dev_emerg(&imxdi->pdev->dev, "%sWire-mesh Tamper Event\n",
234 dtcr & DTCR_WTE ? "" : "Spurious ");
235
236 if (dsr & DSR_MCO)
237 dev_emerg(&imxdi->pdev->dev,
238 "%sMonotonic-counter Overflow Event\n",
239 dtcr & DTCR_MOE ? "" : "Spurious ");
240
241 if (dsr & DSR_TCO)
242 dev_emerg(&imxdi->pdev->dev, "%sTimer-counter Overflow Event\n",
243 dtcr & DTCR_TOE ? "" : "Spurious ");
244}
245
246static void di_what_is_to_be_done(struct imxdi_dev *imxdi,
247 const char *power_supply)
248{
249 dev_emerg(&imxdi->pdev->dev, "Please cycle the %s power supply in order to get the DryIce/RTC unit working again\n",
250 power_supply);
251}
252
253static int di_handle_failure_state(struct imxdi_dev *imxdi, u32 dsr)
254{
255 u32 dcr;
256
257 dev_dbg(&imxdi->pdev->dev, "DSR register reports: %08X\n", dsr);
258
259 /* report the cause */
260 di_report_tamper_info(imxdi, dsr);
261
262 dcr = readl(imxdi->ioaddr + DCR);
263
264 if (dcr & DCR_FSHL) {
265 /* we are out of luck */
266 di_what_is_to_be_done(imxdi, "battery");
267 return -ENODEV;
268 }
269 /*
270 * with the next SYSTEM POR we will transit from the "FAILURE STATE"
271 * into the "NON-VALID STATE" + "FAILURE STATE"
272 */
273 di_what_is_to_be_done(imxdi, "main");
274
275 return -ENODEV;
276}
277
278static int di_handle_valid_state(struct imxdi_dev *imxdi, u32 dsr)
279{
280 /* initialize alarm */
281 di_write_busy_wait(imxdi, DCAMR_UNSET, DCAMR);
282 di_write_busy_wait(imxdi, 0, DCALR);
283
284 /* clear alarm flag */
285 if (dsr & DSR_CAF)
286 di_write_busy_wait(imxdi, DSR_CAF, DSR);
287
288 return 0;
289}
290
291static int di_handle_invalid_state(struct imxdi_dev *imxdi, u32 dsr)
292{
293 u32 dcr, sec;
294
295 /*
296 * lets disable all sources which can force the DryIce unit into
297 * the "FAILURE STATE" for now
298 */
299 di_write_busy_wait(imxdi, 0x00000000, DTCR);
300 /* and lets protect them at runtime from any change */
301 di_write_busy_wait(imxdi, DCR_TDCSL, DCR);
302
303 sec = readl(imxdi->ioaddr + DTCMR);
304 if (sec != 0)
305 dev_warn(&imxdi->pdev->dev,
306 "The security violation has happend at %u seconds\n",
307 sec);
308 /*
309 * the timer cannot be set/modified if
310 * - the TCHL or TCSL bit is set in DCR
311 */
312 dcr = readl(imxdi->ioaddr + DCR);
313 if (!(dcr & DCR_TCE)) {
314 if (dcr & DCR_TCHL) {
315 /* we are out of luck */
316 di_what_is_to_be_done(imxdi, "battery");
317 return -ENODEV;
318 }
319 if (dcr & DCR_TCSL) {
320 di_what_is_to_be_done(imxdi, "main");
321 return -ENODEV;
322 }
323 }
324 /*
325 * - the timer counter stops/is stopped if
326 * - its overflow flag is set (TCO in DSR)
327 * -> clear overflow bit to make it count again
328 * - NVF is set in DSR
329 * -> clear non-valid bit to make it count again
330 * - its TCE (DCR) is cleared
331 * -> set TCE to make it count
332 * - it was never set before
333 * -> write a time into it (required again if the NVF was set)
334 */
335 /* state handled */
336 di_write_busy_wait(imxdi, DSR_NVF, DSR);
337 /* clear overflow flag */
338 di_write_busy_wait(imxdi, DSR_TCO, DSR);
339 /* enable the counter */
340 di_write_busy_wait(imxdi, dcr | DCR_TCE, DCR);
341 /* set and trigger it to make it count */
342 di_write_busy_wait(imxdi, sec, DTCMR);
343
344 /* now prepare for the valid state */
345 return di_handle_valid_state(imxdi, __raw_readl(imxdi->ioaddr + DSR));
346}
347
348static int di_handle_invalid_and_failure_state(struct imxdi_dev *imxdi, u32 dsr)
349{
350 u32 dcr;
351
352 /*
353 * now we must first remove the tamper sources in order to get the
354 * device out of the "FAILURE STATE"
355 * To disable any of the following sources we need to modify the DTCR
356 */
357 if (dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD | DSR_EBD | DSR_SAD |
358 DSR_TTD | DSR_CTD | DSR_VTD | DSR_MCO | DSR_TCO)) {
359 dcr = __raw_readl(imxdi->ioaddr + DCR);
360 if (dcr & DCR_TDCHL) {
361 /*
362 * the tamper register is locked. We cannot disable the
363 * tamper detection. The TDCHL can only be reset by a
364 * DRYICE POR, but we cannot force a DRYICE POR in
365 * softwere because we are still in "FAILURE STATE".
366 * We need a DRYICE POR via battery power cycling....
367 */
368 /*
369 * out of luck!
370 * we cannot disable them without a DRYICE POR
371 */
372 di_what_is_to_be_done(imxdi, "battery");
373 return -ENODEV;
374 }
375 if (dcr & DCR_TDCSL) {
376 /* a soft lock can be removed by a SYSTEM POR */
377 di_what_is_to_be_done(imxdi, "main");
378 return -ENODEV;
379 }
380 }
381
382 /* disable all sources */
383 di_write_busy_wait(imxdi, 0x00000000, DTCR);
384
385 /* clear the status bits now */
386 di_write_busy_wait(imxdi, dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD |
387 DSR_EBD | DSR_SAD | DSR_TTD | DSR_CTD | DSR_VTD |
388 DSR_MCO | DSR_TCO), DSR);
389
390 dsr = readl(imxdi->ioaddr + DSR);
391 if ((dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF |
392 DSR_WCF | DSR_WEF)) != 0)
393 dev_warn(&imxdi->pdev->dev,
394 "There are still some sources of pain in DSR: %08x!\n",
395 dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF |
396 DSR_WCF | DSR_WEF));
397
398 /*
399 * now we are trying to clear the "Security-violation flag" to
400 * get the DryIce out of this state
401 */
402 di_write_busy_wait(imxdi, DSR_SVF, DSR);
403
404 /* success? */
405 dsr = readl(imxdi->ioaddr + DSR);
406 if (dsr & DSR_SVF) {
407 dev_crit(&imxdi->pdev->dev,
408 "Cannot clear the security violation flag. We are ending up in an endless loop!\n");
409 /* last resort */
410 di_what_is_to_be_done(imxdi, "battery");
411 return -ENODEV;
412 }
413
414 /*
415 * now we have left the "FAILURE STATE" and ending up in the
416 * "NON-VALID STATE" time to recover everything
417 */
418 return di_handle_invalid_state(imxdi, dsr);
419}
420
421static int di_handle_state(struct imxdi_dev *imxdi)
422{
423 int rc;
424 u32 dsr;
425
426 dsr = readl(imxdi->ioaddr + DSR);
427
428 switch (dsr & (DSR_NVF | DSR_SVF)) {
429 case DSR_NVF:
430 dev_warn(&imxdi->pdev->dev, "Invalid stated unit detected\n");
431 rc = di_handle_invalid_state(imxdi, dsr);
432 break;
433 case DSR_SVF:
434 dev_warn(&imxdi->pdev->dev, "Failure stated unit detected\n");
435 rc = di_handle_failure_state(imxdi, dsr);
436 break;
437 case DSR_NVF | DSR_SVF:
438 dev_warn(&imxdi->pdev->dev,
439 "Failure+Invalid stated unit detected\n");
440 rc = di_handle_invalid_and_failure_state(imxdi, dsr);
441 break;
442 default:
443 dev_notice(&imxdi->pdev->dev, "Unlocked unit detected\n");
444 rc = di_handle_valid_state(imxdi, dsr);
445 }
446
447 return rc;
448}
449
450/*
176 * enable a dryice interrupt 451 * enable a dryice interrupt
177 */ 452 */
178static void di_int_enable(struct imxdi_dev *imxdi, u32 intr) 453static void di_int_enable(struct imxdi_dev *imxdi, u32 intr)
@@ -491,6 +766,10 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
491 /* mask all interrupts */ 766 /* mask all interrupts */
492 writel(0, imxdi->ioaddr + DIER); 767 writel(0, imxdi->ioaddr + DIER);
493 768
769 rc = di_handle_state(imxdi);
770 if (rc != 0)
771 goto err;
772
494 rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq, 773 rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq,
495 IRQF_SHARED, pdev->name, imxdi); 774 IRQF_SHARED, pdev->name, imxdi);
496 if (rc) { 775 if (rc) {
@@ -498,44 +777,6 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
498 goto err; 777 goto err;
499 } 778 }
500 779
501 /* put dryice into valid state */
502 if (readl(imxdi->ioaddr + DSR) & DSR_NVF) {
503 rc = di_write_wait(imxdi, DSR_NVF | DSR_SVF, DSR);
504 if (rc)
505 goto err;
506 }
507
508 /* initialize alarm */
509 rc = di_write_wait(imxdi, DCAMR_UNSET, DCAMR);
510 if (rc)
511 goto err;
512 rc = di_write_wait(imxdi, 0, DCALR);
513 if (rc)
514 goto err;
515
516 /* clear alarm flag */
517 if (readl(imxdi->ioaddr + DSR) & DSR_CAF) {
518 rc = di_write_wait(imxdi, DSR_CAF, DSR);
519 if (rc)
520 goto err;
521 }
522
523 /* the timer won't count if it has never been written to */
524 if (readl(imxdi->ioaddr + DTCMR) == 0) {
525 rc = di_write_wait(imxdi, 0, DTCMR);
526 if (rc)
527 goto err;
528 }
529
530 /* start keeping time */
531 if (!(readl(imxdi->ioaddr + DCR) & DCR_TCE)) {
532 rc = di_write_wait(imxdi,
533 readl(imxdi->ioaddr + DCR) | DCR_TCE,
534 DCR);
535 if (rc)
536 goto err;
537 }
538
539 platform_set_drvdata(pdev, imxdi); 780 platform_set_drvdata(pdev, imxdi);
540 imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, 781 imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
541 &dryice_rtc_ops, THIS_MODULE); 782 &dryice_rtc_ops, THIS_MODULE);