Lines Matching +full:write +full:- +full:enable
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
8 * This driver uses the 47-bit 32 kHz counter in the Freescale DryIce block
10 * Since the RTC framework performs API locking via rtc->ops_lock the
15 * the WCF (Write Complete Flag). All DryIce writes are synchronized to the
17 * DIER (DryIce Interrupt Enable Register) are the only exception. These
41 #define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */
44 #define DCR_TDCHL (1 << 30) /* Tamper-detect configuration hard lock */
45 #define DCR_TDCSL (1 << 29) /* Tamper-detect configuration soft lock */
46 #define DCR_KSSL (1 << 27) /* Key-select soft lock */
47 #define DCR_MCHL (1 << 20) /* Monotonic-counter hard lock */
48 #define DCR_MCSL (1 << 19) /* Monotonic-counter soft lock */
49 #define DCR_TCHL (1 << 18) /* Timer-counter hard lock */
50 #define DCR_TCSL (1 << 17) /* Timer-counter soft lock */
52 #define DCR_TCE (1 << 3) /* Time Counter Enable */
53 #define DCR_MCE (1 << 2) /* Monotonic Counter Enable */
56 #define DSR_WTD (1 << 23) /* Wire-mesh tamper detected */
64 #define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */
65 #define DSR_WNF (1 << 9) /* Write Next Flag (synchronous) */
66 #define DSR_WCF (1 << 8) /* Write Complete Flag (synchronous)*/
67 #define DSR_WEF (1 << 7) /* Write Error Flag */
71 #define DSR_NVF (1 << 1) /* Non-Valid Flag */
74 #define DIER 0x18 /* Interrupt Enable Reg (synchronous) */
75 #define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */
76 #define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */
77 #define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */
78 #define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */
79 #define DIER_SVIE (1 << 0) /* Security-violation Interrupt Enable */
86 #define DTCR_WTE (1 << 7) /* wire-mesh tamper enabled */
98 * struct imxdi_dev - private imxdi rtc data
104 * @irq_lock: interrupt enable register (DIER) lock
105 * @write_wait: registers write complete queue
106 * @write_mutex: serialize registers write
129 * - "NON-VALID STATE"
131 * - "FAILURE STATE"
133 * - "VALID STATE"
142 * - wire-mesh-tamper detect
143 * - external tamper B detect
144 * - external tamper A detect
145 * - temperature tamper detect
146 * - clock tamper detect
147 * - voltage tamper detect
148 * - RTC counter overflow
149 * - monotonic counter overflow
150 * - external boot
155 * "NON-VALID STATE" + "FAILURE STATE" where a recovery is possible.
159 * In the "NON-VALID STATE" + "FAILURE STATE" we can clear the "FAILURE STATE"
160 * and recover the DryIce unit. By clearing the "NON-VALID STATE" as the last
165 * Do a write into the unit without interrupt support.
167 * write error can happen is if we write to the unit twice within the 122 us
174 /* do the register write */ in di_write_busy_wait()
175 writel(val, imxdi->ioaddr + reg); in di_write_busy_wait()
188 dtcr = readl(imxdi->ioaddr + DTCR); in di_report_tamper_info()
190 dev_emerg(&imxdi->pdev->dev, "DryIce tamper event detected\n"); in di_report_tamper_info()
193 dev_emerg(&imxdi->pdev->dev, "%sVoltage Tamper Event\n", in di_report_tamper_info()
197 dev_emerg(&imxdi->pdev->dev, "%s32768 Hz Clock Tamper Event\n", in di_report_tamper_info()
201 dev_emerg(&imxdi->pdev->dev, "%sTemperature Tamper Event\n", in di_report_tamper_info()
205 dev_emerg(&imxdi->pdev->dev, in di_report_tamper_info()
210 dev_emerg(&imxdi->pdev->dev, "%sExternal Boot Tamper Event\n", in di_report_tamper_info()
214 dev_emerg(&imxdi->pdev->dev, "%sExternal Tamper A Event\n", in di_report_tamper_info()
218 dev_emerg(&imxdi->pdev->dev, "%sExternal Tamper B Event\n", in di_report_tamper_info()
222 dev_emerg(&imxdi->pdev->dev, "%sWire-mesh Tamper Event\n", in di_report_tamper_info()
226 dev_emerg(&imxdi->pdev->dev, in di_report_tamper_info()
227 "%sMonotonic-counter Overflow Event\n", in di_report_tamper_info()
231 dev_emerg(&imxdi->pdev->dev, "%sTimer-counter Overflow Event\n", in di_report_tamper_info()
238 …dev_emerg(&imxdi->pdev->dev, "Please cycle the %s power supply in order to get the DryIce/RTC unit… in di_what_is_to_be_done()
246 dev_dbg(&imxdi->pdev->dev, "DSR register reports: %08X\n", dsr); in di_handle_failure_state()
251 dcr = readl(imxdi->ioaddr + DCR); in di_handle_failure_state()
256 return -ENODEV; in di_handle_failure_state()
260 * into the "NON-VALID STATE" + "FAILURE STATE" in di_handle_failure_state()
264 return -ENODEV; in di_handle_failure_state()
292 sec = readl(imxdi->ioaddr + DTCMR); in di_handle_invalid_state()
294 dev_warn(&imxdi->pdev->dev, in di_handle_invalid_state()
299 * - the TCHL or TCSL bit is set in DCR in di_handle_invalid_state()
301 dcr = readl(imxdi->ioaddr + DCR); in di_handle_invalid_state()
306 return -ENODEV; in di_handle_invalid_state()
310 return -ENODEV; in di_handle_invalid_state()
314 * - the timer counter stops/is stopped if in di_handle_invalid_state()
315 * - its overflow flag is set (TCO in DSR) in di_handle_invalid_state()
316 * -> clear overflow bit to make it count again in di_handle_invalid_state()
317 * - NVF is set in DSR in di_handle_invalid_state()
318 * -> clear non-valid bit to make it count again in di_handle_invalid_state()
319 * - its TCE (DCR) is cleared in di_handle_invalid_state()
320 * -> set TCE to make it count in di_handle_invalid_state()
321 * - it was never set before in di_handle_invalid_state()
322 * -> write a time into it (required again if the NVF was set) in di_handle_invalid_state()
328 /* enable the counter */ in di_handle_invalid_state()
334 return di_handle_valid_state(imxdi, __raw_readl(imxdi->ioaddr + DSR)); in di_handle_invalid_state()
348 dcr = __raw_readl(imxdi->ioaddr + DCR); in di_handle_invalid_and_failure_state()
362 return -ENODEV; in di_handle_invalid_and_failure_state()
367 return -ENODEV; in di_handle_invalid_and_failure_state()
379 dsr = readl(imxdi->ioaddr + DSR); in di_handle_invalid_and_failure_state()
382 dev_warn(&imxdi->pdev->dev, in di_handle_invalid_and_failure_state()
388 * now we are trying to clear the "Security-violation flag" to in di_handle_invalid_and_failure_state()
394 dsr = readl(imxdi->ioaddr + DSR); in di_handle_invalid_and_failure_state()
396 dev_crit(&imxdi->pdev->dev, in di_handle_invalid_and_failure_state()
400 return -ENODEV; in di_handle_invalid_and_failure_state()
405 * "NON-VALID STATE" time to recover everything in di_handle_invalid_and_failure_state()
415 dsr = readl(imxdi->ioaddr + DSR); in di_handle_state()
419 dev_warn(&imxdi->pdev->dev, "Invalid stated unit detected\n"); in di_handle_state()
423 dev_warn(&imxdi->pdev->dev, "Failure stated unit detected\n"); in di_handle_state()
427 dev_warn(&imxdi->pdev->dev, in di_handle_state()
432 dev_notice(&imxdi->pdev->dev, "Unlocked unit detected\n"); in di_handle_state()
440 * enable a dryice interrupt
446 spin_lock_irqsave(&imxdi->irq_lock, flags); in di_int_enable()
447 writel(readl(imxdi->ioaddr + DIER) | intr, in di_int_enable()
448 imxdi->ioaddr + DIER); in di_int_enable()
449 spin_unlock_irqrestore(&imxdi->irq_lock, flags); in di_int_enable()
459 spin_lock_irqsave(&imxdi->irq_lock, flags); in di_int_disable()
460 writel(readl(imxdi->ioaddr + DIER) & ~intr, in di_int_disable()
461 imxdi->ioaddr + DIER); in di_int_disable()
462 spin_unlock_irqrestore(&imxdi->irq_lock, flags); in di_int_disable()
466 * This function attempts to clear the dryice write-error flag.
468 * A dryice write error is similar to a bus fault and should not occur in
469 * normal operation. Clearing the flag requires another write, so the root
476 dev_warn(&imxdi->pdev->dev, "WARNING: Register write error!\n"); in clear_write_error()
478 /* clear the write error flag */ in clear_write_error()
479 writel(DSR_WEF, imxdi->ioaddr + DSR); in clear_write_error()
483 if ((readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0) in clear_write_error()
487 dev_err(&imxdi->pdev->dev, in clear_write_error()
488 "ERROR: Cannot clear write-error flag!\n"); in clear_write_error()
492 * Write a dryice register and wait until it completes.
495 * write has completed.
503 mutex_lock(&imxdi->write_mutex); in di_write_wait()
505 /* enable the write-complete interrupt */ in di_write_wait()
508 imxdi->dsr = 0; in di_write_wait()
510 /* do the register write */ in di_write_wait()
511 writel(val, imxdi->ioaddr + reg); in di_write_wait()
513 /* wait for the write to finish */ in di_write_wait()
514 ret = wait_event_interruptible_timeout(imxdi->write_wait, in di_write_wait()
515 imxdi->dsr & (DSR_WCF | DSR_WEF), msecs_to_jiffies(1)); in di_write_wait()
520 dev_warn(&imxdi->pdev->dev, in di_write_wait()
521 "Write-wait timeout " in di_write_wait()
525 /* check for write error */ in di_write_wait()
526 if (imxdi->dsr & DSR_WEF) { in di_write_wait()
528 rc = -EIO; in di_write_wait()
532 mutex_unlock(&imxdi->write_mutex); in di_write_wait()
545 now = readl(imxdi->ioaddr + DTCMR); in dryice_rtc_read_time()
561 dcr = readl(imxdi->ioaddr + DCR); in dryice_rtc_set_time()
562 dsr = readl(imxdi->ioaddr + DSR); in dryice_rtc_set_time()
568 return -EPERM; in dryice_rtc_set_time()
573 return -EPERM; in dryice_rtc_set_time()
586 return di_write_wait(imxdi, readl(imxdi->ioaddr + DCR) | DCR_TCE, DCR); in dryice_rtc_set_time()
611 dcamr = readl(imxdi->ioaddr + DCAMR); in dryice_rtc_read_alarm()
612 rtc_time64_to_tm(dcamr, &alarm->time); in dryice_rtc_read_alarm()
615 alarm->enabled = (readl(imxdi->ioaddr + DIER) & DIER_CAIE) != 0; in dryice_rtc_read_alarm()
618 mutex_lock(&imxdi->write_mutex); in dryice_rtc_read_alarm()
621 alarm->pending = (readl(imxdi->ioaddr + DSR) & DSR_CAF) != 0; in dryice_rtc_read_alarm()
623 mutex_unlock(&imxdi->write_mutex); in dryice_rtc_read_alarm()
636 /* write the new alarm time */ in dryice_rtc_set_alarm()
637 rc = di_write_wait(imxdi, rtc_tm_to_time64(&alarm->time), DCAMR); in dryice_rtc_set_alarm()
641 if (alarm->enabled) in dryice_rtc_set_alarm()
642 di_int_enable(imxdi, DIER_CAIE); /* enable alarm intr */ in dryice_rtc_set_alarm()
666 dier = readl(imxdi->ioaddr + DIER); in dryice_irq()
667 dsr = readl(imxdi->ioaddr + DSR); in dryice_irq()
687 /* handle write complete and write error cases */ in dryice_irq()
689 /*If the write wait queue is empty then there is no pending in dryice_irq()
690 operations. It means the interrupt is for DryIce -Security. in dryice_irq()
692 if (list_empty_careful(&imxdi->write_wait.head)) in dryice_irq()
701 imxdi->dsr |= dsr; in dryice_irq()
703 wake_up_interruptible(&imxdi->write_wait); in dryice_irq()
716 schedule_work(&imxdi->work); in dryice_irq()
725 * on the write completion.
736 rtc_update_irq(imxdi->rtc, 1, RTC_AF | RTC_IRQF); in dryice_work()
748 imxdi = devm_kzalloc(&pdev->dev, sizeof(*imxdi), GFP_KERNEL); in dryice_rtc_probe()
750 return -ENOMEM; in dryice_rtc_probe()
752 imxdi->pdev = pdev; in dryice_rtc_probe()
754 imxdi->ioaddr = devm_platform_ioremap_resource(pdev, 0); in dryice_rtc_probe()
755 if (IS_ERR(imxdi->ioaddr)) in dryice_rtc_probe()
756 return PTR_ERR(imxdi->ioaddr); in dryice_rtc_probe()
758 spin_lock_init(&imxdi->irq_lock); in dryice_rtc_probe()
771 init_waitqueue_head(&imxdi->write_wait); in dryice_rtc_probe()
773 INIT_WORK(&imxdi->work, dryice_work); in dryice_rtc_probe()
775 mutex_init(&imxdi->write_mutex); in dryice_rtc_probe()
777 imxdi->rtc = devm_rtc_allocate_device(&pdev->dev); in dryice_rtc_probe()
778 if (IS_ERR(imxdi->rtc)) in dryice_rtc_probe()
779 return PTR_ERR(imxdi->rtc); in dryice_rtc_probe()
781 imxdi->clk = devm_clk_get(&pdev->dev, NULL); in dryice_rtc_probe()
782 if (IS_ERR(imxdi->clk)) in dryice_rtc_probe()
783 return PTR_ERR(imxdi->clk); in dryice_rtc_probe()
784 rc = clk_prepare_enable(imxdi->clk); in dryice_rtc_probe()
793 writel(0, imxdi->ioaddr + DIER); in dryice_rtc_probe()
799 rc = devm_request_irq(&pdev->dev, norm_irq, dryice_irq, in dryice_rtc_probe()
800 IRQF_SHARED, pdev->name, imxdi); in dryice_rtc_probe()
802 dev_warn(&pdev->dev, "interrupt not available.\n"); in dryice_rtc_probe()
806 rc = devm_request_irq(&pdev->dev, sec_irq, dryice_irq, in dryice_rtc_probe()
807 IRQF_SHARED, pdev->name, imxdi); in dryice_rtc_probe()
809 dev_warn(&pdev->dev, "security violation interrupt not available.\n"); in dryice_rtc_probe()
815 device_init_wakeup(&pdev->dev, true); in dryice_rtc_probe()
816 dev_pm_set_wake_irq(&pdev->dev, norm_irq); in dryice_rtc_probe()
818 imxdi->rtc->ops = &dryice_rtc_ops; in dryice_rtc_probe()
819 imxdi->rtc->range_max = U32_MAX; in dryice_rtc_probe()
821 rc = devm_rtc_register_device(imxdi->rtc); in dryice_rtc_probe()
828 clk_disable_unprepare(imxdi->clk); in dryice_rtc_probe()
837 flush_work(&imxdi->work); in dryice_rtc_remove()
840 writel(0, imxdi->ioaddr + DIER); in dryice_rtc_remove()
842 clk_disable_unprepare(imxdi->clk); in dryice_rtc_remove()
846 { .compatible = "fsl,imx25-rtc" },