Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: caam - add power management support

Add support for suspend and resume operation for PM in CAAM driver.

When the CAAM goes in suspend, the hardware is considered to do nothing.

On some platforms, the power of the CAAM is not turned off so it keeps
its configuration.
On other platforms, it doesn't so it is necessary to save the state of
the CAAM:
- JRs MID
- Address of input and output rings

Signed-off-by: Horia Geanta <horia.geanta@nxp.com>
Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
Signed-off-by: Dan Douglass <dan.douglass@nxp.com>
Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
Signed-off-by: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
Reviewed-by: Gaurav Jain <gaurav.jain@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Horia Geanta and committed by
Herbert Xu
322d7475 9a6913fe

+306 -21
+106
drivers/crypto/caam/ctrl.c
··· 740 740 return 0; 741 741 } 742 742 743 + /* Indicate if the internal state of the CAAM is lost during PM */ 744 + static int caam_off_during_pm(void) 745 + { 746 + bool not_off_during_pm = of_machine_is_compatible("fsl,imx6q") || 747 + of_machine_is_compatible("fsl,imx6qp") || 748 + of_machine_is_compatible("fsl,imx6dl"); 749 + 750 + return not_off_during_pm ? 0 : 1; 751 + } 752 + 753 + static void caam_state_save(struct device *dev) 754 + { 755 + struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 756 + struct caam_ctl_state *state = &ctrlpriv->state; 757 + struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; 758 + u32 deco_inst, jr_inst; 759 + int i; 760 + 761 + state->mcr = rd_reg32(&ctrl->mcr); 762 + state->scfgr = rd_reg32(&ctrl->scfgr); 763 + 764 + deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 765 + CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT; 766 + for (i = 0; i < deco_inst; i++) { 767 + state->deco_mid[i].liodn_ms = 768 + rd_reg32(&ctrl->deco_mid[i].liodn_ms); 769 + state->deco_mid[i].liodn_ls = 770 + rd_reg32(&ctrl->deco_mid[i].liodn_ls); 771 + } 772 + 773 + jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 774 + CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT; 775 + for (i = 0; i < jr_inst; i++) { 776 + state->jr_mid[i].liodn_ms = 777 + rd_reg32(&ctrl->jr_mid[i].liodn_ms); 778 + state->jr_mid[i].liodn_ls = 779 + rd_reg32(&ctrl->jr_mid[i].liodn_ls); 780 + } 781 + } 782 + 783 + static void caam_state_restore(const struct device *dev) 784 + { 785 + const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 786 + const struct caam_ctl_state *state = &ctrlpriv->state; 787 + struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl; 788 + u32 deco_inst, jr_inst; 789 + int i; 790 + 791 + wr_reg32(&ctrl->mcr, state->mcr); 792 + wr_reg32(&ctrl->scfgr, state->scfgr); 793 + 794 + deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 795 + CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT; 796 + for (i = 0; i < deco_inst; i++) { 797 + wr_reg32(&ctrl->deco_mid[i].liodn_ms, 798 + state->deco_mid[i].liodn_ms); 799 + wr_reg32(&ctrl->deco_mid[i].liodn_ls, 800 + state->deco_mid[i].liodn_ls); 801 + } 802 + 803 + jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) & 804 + CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT; 805 + for (i = 0; i < jr_inst; i++) { 806 + wr_reg32(&ctrl->jr_mid[i].liodn_ms, 807 + state->jr_mid[i].liodn_ms); 808 + wr_reg32(&ctrl->jr_mid[i].liodn_ls, 809 + state->jr_mid[i].liodn_ls); 810 + } 811 + 812 + if (ctrlpriv->virt_en == 1) 813 + clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START | 814 + JRSTART_JR1_START | JRSTART_JR2_START | 815 + JRSTART_JR3_START); 816 + } 817 + 818 + static int caam_ctrl_suspend(struct device *dev) 819 + { 820 + const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 821 + 822 + if (ctrlpriv->caam_off_during_pm && !ctrlpriv->optee_en) 823 + caam_state_save(dev); 824 + 825 + return 0; 826 + } 827 + 828 + static int caam_ctrl_resume(struct device *dev) 829 + { 830 + struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev); 831 + int ret = 0; 832 + 833 + if (ctrlpriv->caam_off_during_pm && !ctrlpriv->optee_en) { 834 + caam_state_restore(dev); 835 + 836 + /* HW and rng will be reset so deinstantiation can be removed */ 837 + devm_remove_action(dev, devm_deinstantiate_rng, dev); 838 + ret = caam_ctrl_rng_init(dev); 839 + } 840 + 841 + return ret; 842 + } 843 + 844 + static SIMPLE_DEV_PM_OPS(caam_ctrl_pm_ops, caam_ctrl_suspend, caam_ctrl_resume); 845 + 743 846 /* Probe routine for CAAM top (controller) level */ 744 847 static int caam_probe(struct platform_device *pdev) 745 848 { ··· 873 770 return -EPROBE_DEFER; 874 771 875 772 caam_imx = (bool)imx_soc_match; 773 + 774 + ctrlpriv->caam_off_during_pm = caam_imx && caam_off_during_pm(); 876 775 877 776 if (imx_soc_match) { 878 777 /* ··· 1138 1033 .driver = { 1139 1034 .name = "caam", 1140 1035 .of_match_table = caam_match, 1036 + .pm = &caam_ctrl_pm_ops, 1141 1037 }, 1142 1038 .probe = caam_probe, 1143 1039 };
+24 -1
drivers/crypto/caam/intern.h
··· 4 4 * Private/internal definitions between modules 5 5 * 6 6 * Copyright 2008-2011 Freescale Semiconductor, Inc. 7 - * Copyright 2019 NXP 7 + * Copyright 2019, 2023 NXP 8 8 */ 9 9 10 10 #ifndef INTERN_H ··· 47 47 u32 desc_size; /* Stored size for postprocessing, header derived */ 48 48 }; 49 49 50 + struct caam_jr_state { 51 + dma_addr_t inpbusaddr; 52 + dma_addr_t outbusaddr; 53 + }; 54 + 55 + struct caam_jr_dequeue_params { 56 + struct device *dev; 57 + int enable_itr; 58 + }; 59 + 50 60 /* Private sub-storage for a single JobR */ 51 61 struct caam_drv_private_jr { 52 62 struct list_head list_node; /* Job Ring device list */ ··· 64 54 int ridx; 65 55 struct caam_job_ring __iomem *rregs; /* JobR's register space */ 66 56 struct tasklet_struct irqtask; 57 + struct caam_jr_dequeue_params tasklet_params; 67 58 int irq; /* One per queue */ 68 59 bool hwrng; 69 60 ··· 82 71 int tail; /* entinfo (s/w ring) tail index */ 83 72 void *outring; /* Base of output ring, DMA-safe */ 84 73 struct crypto_engine *engine; 74 + 75 + struct caam_jr_state state; /* State of the JR during PM */ 76 + }; 77 + 78 + struct caam_ctl_state { 79 + struct masterid deco_mid[16]; 80 + struct masterid jr_mid[4]; 81 + u32 mcr; 82 + u32 scfgr; 85 83 }; 86 84 87 85 /* ··· 136 116 struct dentry *ctl; /* controller dir */ 137 117 struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap; 138 118 #endif 119 + 120 + int caam_off_during_pm; /* If the CAAM is reset after suspend */ 121 + struct caam_ctl_state state; /* State of the CTL during PM */ 139 122 }; 140 123 141 124 #ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+175 -18
drivers/crypto/caam/jr.c
··· 117 117 return caam_jr_stop_processing(dev, JRCR_RESET); 118 118 } 119 119 120 + /* The resume can be used after a park or a flush if CAAM has not been reset */ 121 + static int caam_jr_restart_processing(struct device *dev) 122 + { 123 + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); 124 + u32 halt_status = rd_reg32(&jrp->rregs->jrintstatus) & 125 + JRINT_ERR_HALT_MASK; 126 + 127 + /* Check that the flush/park is completed */ 128 + if (halt_status != JRINT_ERR_HALT_COMPLETE) 129 + return -1; 130 + 131 + /* Resume processing of jobs */ 132 + clrsetbits_32(&jrp->rregs->jrintstatus, 0, JRINT_ERR_HALT_COMPLETE); 133 + 134 + return 0; 135 + } 136 + 120 137 static int caam_reset_hw_jr(struct device *dev) 121 138 { 122 139 struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); ··· 262 245 static void caam_jr_dequeue(unsigned long devarg) 263 246 { 264 247 int hw_idx, sw_idx, i, head, tail; 265 - struct device *dev = (struct device *)devarg; 248 + struct caam_jr_dequeue_params *params = (void *)devarg; 249 + struct device *dev = params->dev; 266 250 struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); 267 251 void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); 268 252 u32 *userdesc, userstatus; ··· 337 319 outring_used--; 338 320 } 339 321 340 - /* reenable / unmask IRQs */ 341 - clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0); 322 + if (params->enable_itr) 323 + /* reenable / unmask IRQs */ 324 + clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0); 342 325 } 343 326 344 327 /** ··· 489 470 } 490 471 EXPORT_SYMBOL(caam_jr_enqueue); 491 472 473 + static void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr, 474 + dma_addr_t outbusaddr) 475 + { 476 + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); 477 + 478 + wr_reg64(&jrp->rregs->inpring_base, inpbusaddr); 479 + wr_reg64(&jrp->rregs->outring_base, outbusaddr); 480 + wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH); 481 + wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH); 482 + 483 + /* Select interrupt coalescing parameters */ 484 + clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC | 485 + (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) | 486 + (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT)); 487 + } 488 + 489 + static void caam_jr_reset_index(struct caam_drv_private_jr *jrp) 490 + { 491 + jrp->out_ring_read_index = 0; 492 + jrp->head = 0; 493 + jrp->tail = 0; 494 + } 495 + 492 496 /* 493 497 * Init JobR independent of platform property detection 494 498 */ ··· 548 506 jrp->entinfo[i].desc_addr_dma = !0; 549 507 550 508 /* Setup rings */ 551 - jrp->out_ring_read_index = 0; 552 - jrp->head = 0; 553 - jrp->tail = 0; 554 - 555 - wr_reg64(&jrp->rregs->inpring_base, inpbusaddr); 556 - wr_reg64(&jrp->rregs->outring_base, outbusaddr); 557 - wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH); 558 - wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH); 559 - 509 + caam_jr_reset_index(jrp); 560 510 jrp->inpring_avail = JOBR_DEPTH; 511 + caam_jr_init_hw(dev, inpbusaddr, outbusaddr); 561 512 562 513 spin_lock_init(&jrp->inplock); 563 514 564 - /* Select interrupt coalescing parameters */ 565 - clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC | 566 - (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) | 567 - (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT)); 568 - 569 - tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev); 515 + jrp->tasklet_params.dev = dev; 516 + jrp->tasklet_params.enable_itr = 1; 517 + tasklet_init(&jrp->irqtask, caam_jr_dequeue, 518 + (unsigned long)&jrp->tasklet_params); 570 519 571 520 /* Connect job ring interrupt handler. */ 572 521 error = devm_request_irq(dev, jrp->irq, caam_jr_interrupt, IRQF_SHARED, ··· 668 635 669 636 atomic_set(&jrpriv->tfm_count, 0); 670 637 638 + device_init_wakeup(&pdev->dev, 1); 639 + device_set_wakeup_enable(&pdev->dev, false); 640 + 671 641 register_algs(jrpriv, jrdev->parent); 672 642 673 643 return 0; 674 644 } 645 + 646 + static void caam_jr_get_hw_state(struct device *dev) 647 + { 648 + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); 649 + 650 + jrp->state.inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); 651 + jrp->state.outbusaddr = rd_reg64(&jrp->rregs->outring_base); 652 + } 653 + 654 + static int caam_jr_suspend(struct device *dev) 655 + { 656 + struct platform_device *pdev = to_platform_device(dev); 657 + struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev); 658 + struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent); 659 + struct caam_jr_dequeue_params suspend_params = { 660 + .dev = dev, 661 + .enable_itr = 0, 662 + }; 663 + 664 + /* Remove the node from Physical JobR list maintained by driver */ 665 + spin_lock(&driver_data.jr_alloc_lock); 666 + list_del(&jrpriv->list_node); 667 + spin_unlock(&driver_data.jr_alloc_lock); 668 + 669 + if (jrpriv->hwrng) 670 + caam_rng_exit(dev->parent); 671 + 672 + if (ctrlpriv->caam_off_during_pm) { 673 + int err; 674 + 675 + tasklet_disable(&jrpriv->irqtask); 676 + 677 + /* mask itr to call flush */ 678 + clrsetbits_32(&jrpriv->rregs->rconfig_lo, 0, JRCFG_IMSK); 679 + 680 + /* Invalid job in process */ 681 + err = caam_jr_flush(dev); 682 + if (err) { 683 + dev_err(dev, "Failed to flush\n"); 684 + return err; 685 + } 686 + 687 + /* Dequeing jobs flushed */ 688 + caam_jr_dequeue((unsigned long)&suspend_params); 689 + 690 + /* Save state */ 691 + caam_jr_get_hw_state(dev); 692 + } else if (device_may_wakeup(&pdev->dev)) { 693 + enable_irq_wake(jrpriv->irq); 694 + } 695 + 696 + return 0; 697 + } 698 + 699 + static int caam_jr_resume(struct device *dev) 700 + { 701 + struct platform_device *pdev = to_platform_device(dev); 702 + struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev); 703 + struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent); 704 + 705 + if (ctrlpriv->caam_off_during_pm) { 706 + u64 inp_addr; 707 + int err; 708 + 709 + /* 710 + * Check if the CAAM has been resetted checking the address of 711 + * the input ring 712 + */ 713 + inp_addr = rd_reg64(&jrpriv->rregs->inpring_base); 714 + if (inp_addr != 0) { 715 + /* JR still has some configuration */ 716 + if (inp_addr == jrpriv->state.inpbusaddr) { 717 + /* JR has not been resetted */ 718 + err = caam_jr_restart_processing(dev); 719 + if (err) { 720 + dev_err(dev, 721 + "Restart processing failed\n"); 722 + return err; 723 + } 724 + 725 + tasklet_enable(&jrpriv->irqtask); 726 + 727 + clrsetbits_32(&jrpriv->rregs->rconfig_lo, 728 + JRCFG_IMSK, 0); 729 + 730 + goto add_jr; 731 + } else if (ctrlpriv->optee_en) { 732 + /* JR has been used by OPTEE, reset it */ 733 + err = caam_reset_hw_jr(dev); 734 + if (err) { 735 + dev_err(dev, "Failed to reset JR\n"); 736 + return err; 737 + } 738 + } else { 739 + /* No explanation, return error */ 740 + return -EIO; 741 + } 742 + } 743 + 744 + caam_jr_reset_index(jrpriv); 745 + caam_jr_init_hw(dev, jrpriv->state.inpbusaddr, 746 + jrpriv->state.outbusaddr); 747 + 748 + tasklet_enable(&jrpriv->irqtask); 749 + } else if (device_may_wakeup(&pdev->dev)) { 750 + disable_irq_wake(jrpriv->irq); 751 + } 752 + 753 + add_jr: 754 + spin_lock(&driver_data.jr_alloc_lock); 755 + list_add_tail(&jrpriv->list_node, &driver_data.jr_list); 756 + spin_unlock(&driver_data.jr_alloc_lock); 757 + 758 + if (jrpriv->hwrng) 759 + jrpriv->hwrng = !caam_rng_init(dev->parent); 760 + 761 + return 0; 762 + } 763 + 764 + static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, caam_jr_resume); 675 765 676 766 static const struct of_device_id caam_jr_match[] = { 677 767 { ··· 811 655 .driver = { 812 656 .name = "caam_jr", 813 657 .of_match_table = caam_jr_match, 658 + .pm = &caam_jr_pm_ops, 814 659 }, 815 660 .probe = caam_jr_probe, 816 661 .remove = caam_jr_remove,
+1 -2
drivers/crypto/caam/regs.h
··· 584 584 u32 deco_rsr; /* DECORSR - Deco Request Source */ 585 585 u32 rsvd11; 586 586 u32 deco_rq; /* DECORR - DECO Request */ 587 - struct masterid deco_mid[5]; /* DECOxLIODNR - 1 per DECO */ 588 - u32 rsvd5[22]; 587 + struct masterid deco_mid[16]; /* DECOxLIODNR - 1 per DECO */ 589 588 590 589 /* DECO Availability/Reset Section 120-3ff */ 591 590 u32 deco_avail; /* DAR - DECO availability */