1618b5dc4SHoria Geantă // SPDX-License-Identifier: GPL-2.0+
28e8ec596SKim Phillips /*
38e8ec596SKim Phillips * CAAM/SEC 4.x transport/backend driver
48e8ec596SKim Phillips * JobR backend functionality
58e8ec596SKim Phillips *
64bba1e9fSKim Phillips * Copyright 2008-2012 Freescale Semiconductor, Inc.
706e39357SHoria Geanta * Copyright 2019, 2023 NXP
88e8ec596SKim Phillips */
98e8ec596SKim Phillips
105af50730SRob Herring #include <linux/of_irq.h>
116c5dc7f8SMichael Neuling #include <linux/of_address.h>
12*b0cc7491SRob Herring #include <linux/platform_device.h>
135af50730SRob Herring
148e8ec596SKim Phillips #include "compat.h"
15297b9cebSHoria Geantă #include "ctrl.h"
168e8ec596SKim Phillips #include "regs.h"
178e8ec596SKim Phillips #include "jr.h"
188e8ec596SKim Phillips #include "desc.h"
198e8ec596SKim Phillips #include "intern.h"
208e8ec596SKim Phillips
21313ea293SRuchika Gupta struct jr_driver_data {
22313ea293SRuchika Gupta /* List of Physical JobR's with the Driver */
23313ea293SRuchika Gupta struct list_head jr_list;
24313ea293SRuchika Gupta spinlock_t jr_alloc_lock; /* jr_list lock */
25313ea293SRuchika Gupta } ____cacheline_aligned;
26313ea293SRuchika Gupta
27313ea293SRuchika Gupta static struct jr_driver_data driver_data;
281b46c90cSHoria Geantă static DEFINE_MUTEX(algs_lock);
291b46c90cSHoria Geantă static unsigned int active_devs;
301b46c90cSHoria Geantă
register_algs(struct caam_drv_private_jr * jrpriv,struct device * dev)311517f63cSAndrey Smirnov static void register_algs(struct caam_drv_private_jr *jrpriv,
321517f63cSAndrey Smirnov struct device *dev)
331b46c90cSHoria Geantă {
341b46c90cSHoria Geantă mutex_lock(&algs_lock);
351b46c90cSHoria Geantă
361b46c90cSHoria Geantă if (++active_devs != 1)
371b46c90cSHoria Geantă goto algs_unlock;
381b46c90cSHoria Geantă
391b46c90cSHoria Geantă caam_algapi_init(dev);
401b46c90cSHoria Geantă caam_algapi_hash_init(dev);
411b46c90cSHoria Geantă caam_pkc_init(dev);
421517f63cSAndrey Smirnov jrpriv->hwrng = !caam_rng_init(dev);
430aa6ac77SMeenakshi Aggarwal caam_prng_register(dev);
441b46c90cSHoria Geantă caam_qi_algapi_init(dev);
451b46c90cSHoria Geantă
461b46c90cSHoria Geantă algs_unlock:
471b46c90cSHoria Geantă mutex_unlock(&algs_lock);
481b46c90cSHoria Geantă }
491b46c90cSHoria Geantă
unregister_algs(void)501b46c90cSHoria Geantă static void unregister_algs(void)
511b46c90cSHoria Geantă {
521b46c90cSHoria Geantă mutex_lock(&algs_lock);
531b46c90cSHoria Geantă
541b46c90cSHoria Geantă if (--active_devs != 0)
551b46c90cSHoria Geantă goto algs_unlock;
561b46c90cSHoria Geantă
571b46c90cSHoria Geantă caam_qi_algapi_exit();
580aa6ac77SMeenakshi Aggarwal caam_prng_unregister(NULL);
591b46c90cSHoria Geantă caam_pkc_exit();
601b46c90cSHoria Geantă caam_algapi_hash_exit();
611b46c90cSHoria Geantă caam_algapi_exit();
621b46c90cSHoria Geantă
631b46c90cSHoria Geantă algs_unlock:
641b46c90cSHoria Geantă mutex_unlock(&algs_lock);
651b46c90cSHoria Geantă }
66313ea293SRuchika Gupta
caam_jr_crypto_engine_exit(void * data)67ee38767fSIuliana Prodan static void caam_jr_crypto_engine_exit(void *data)
68ee38767fSIuliana Prodan {
69ee38767fSIuliana Prodan struct device *jrdev = data;
70ee38767fSIuliana Prodan struct caam_drv_private_jr *jrpriv = dev_get_drvdata(jrdev);
71ee38767fSIuliana Prodan
72ee38767fSIuliana Prodan /* Free the resources of crypto-engine */
73ee38767fSIuliana Prodan crypto_engine_exit(jrpriv->engine);
74ee38767fSIuliana Prodan }
75ee38767fSIuliana Prodan
7606e39357SHoria Geanta /*
7706e39357SHoria Geanta * Put the CAAM in quiesce, ie stop
7806e39357SHoria Geanta *
7906e39357SHoria Geanta * Must be called with itr disabled
8006e39357SHoria Geanta */
caam_jr_stop_processing(struct device * dev,u32 jrcr_bits)8106e39357SHoria Geanta static int caam_jr_stop_processing(struct device *dev, u32 jrcr_bits)
82313ea293SRuchika Gupta {
83313ea293SRuchika Gupta struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
84313ea293SRuchika Gupta unsigned int timeout = 100000;
85313ea293SRuchika Gupta
8606e39357SHoria Geanta /* Check the current status */
8706e39357SHoria Geanta if (rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_INPROGRESS)
8806e39357SHoria Geanta goto wait_quiesce_completion;
89313ea293SRuchika Gupta
9006e39357SHoria Geanta /* Reset the field */
9106e39357SHoria Geanta clrsetbits_32(&jrp->rregs->jrintstatus, JRINT_ERR_HALT_MASK, 0);
9206e39357SHoria Geanta
9306e39357SHoria Geanta /* initiate flush / park (required prior to reset) */
9406e39357SHoria Geanta wr_reg32(&jrp->rregs->jrcommand, jrcr_bits);
9506e39357SHoria Geanta
9606e39357SHoria Geanta wait_quiesce_completion:
97313ea293SRuchika Gupta while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
98313ea293SRuchika Gupta JRINT_ERR_HALT_INPROGRESS) && --timeout)
99313ea293SRuchika Gupta cpu_relax();
100313ea293SRuchika Gupta
101313ea293SRuchika Gupta if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) !=
102313ea293SRuchika Gupta JRINT_ERR_HALT_COMPLETE || timeout == 0) {
103313ea293SRuchika Gupta dev_err(dev, "failed to flush job ring %d\n", jrp->ridx);
104313ea293SRuchika Gupta return -EIO;
105313ea293SRuchika Gupta }
106313ea293SRuchika Gupta
10706e39357SHoria Geanta return 0;
10806e39357SHoria Geanta }
10906e39357SHoria Geanta
11006e39357SHoria Geanta /*
11106e39357SHoria Geanta * Flush the job ring, so the jobs running will be stopped, jobs queued will be
11206e39357SHoria Geanta * invalidated and the CAAM will no longer fetch fron input ring.
11306e39357SHoria Geanta *
11406e39357SHoria Geanta * Must be called with itr disabled
11506e39357SHoria Geanta */
caam_jr_flush(struct device * dev)11606e39357SHoria Geanta static int caam_jr_flush(struct device *dev)
11706e39357SHoria Geanta {
11806e39357SHoria Geanta return caam_jr_stop_processing(dev, JRCR_RESET);
11906e39357SHoria Geanta }
12006e39357SHoria Geanta
121322d7475SHoria Geanta /* The resume can be used after a park or a flush if CAAM has not been reset */
caam_jr_restart_processing(struct device * dev)122322d7475SHoria Geanta static int caam_jr_restart_processing(struct device *dev)
123322d7475SHoria Geanta {
124322d7475SHoria Geanta struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
125322d7475SHoria Geanta u32 halt_status = rd_reg32(&jrp->rregs->jrintstatus) &
126322d7475SHoria Geanta JRINT_ERR_HALT_MASK;
127322d7475SHoria Geanta
128322d7475SHoria Geanta /* Check that the flush/park is completed */
129322d7475SHoria Geanta if (halt_status != JRINT_ERR_HALT_COMPLETE)
130322d7475SHoria Geanta return -1;
131322d7475SHoria Geanta
132322d7475SHoria Geanta /* Resume processing of jobs */
133322d7475SHoria Geanta clrsetbits_32(&jrp->rregs->jrintstatus, 0, JRINT_ERR_HALT_COMPLETE);
134322d7475SHoria Geanta
135322d7475SHoria Geanta return 0;
136322d7475SHoria Geanta }
137322d7475SHoria Geanta
caam_reset_hw_jr(struct device * dev)13806e39357SHoria Geanta static int caam_reset_hw_jr(struct device *dev)
13906e39357SHoria Geanta {
14006e39357SHoria Geanta struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
14106e39357SHoria Geanta unsigned int timeout = 100000;
14206e39357SHoria Geanta int err;
14306e39357SHoria Geanta /*
14406e39357SHoria Geanta * mask interrupts since we are going to poll
14506e39357SHoria Geanta * for reset completion status
14606e39357SHoria Geanta */
14706e39357SHoria Geanta clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
14806e39357SHoria Geanta err = caam_jr_flush(dev);
14906e39357SHoria Geanta if (err)
15006e39357SHoria Geanta return err;
15106e39357SHoria Geanta
152313ea293SRuchika Gupta /* initiate reset */
153313ea293SRuchika Gupta wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
154313ea293SRuchika Gupta while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout)
155313ea293SRuchika Gupta cpu_relax();
156313ea293SRuchika Gupta
157313ea293SRuchika Gupta if (timeout == 0) {
158313ea293SRuchika Gupta dev_err(dev, "failed to reset job ring %d\n", jrp->ridx);
159313ea293SRuchika Gupta return -EIO;
160313ea293SRuchika Gupta }
161313ea293SRuchika Gupta
162313ea293SRuchika Gupta /* unmask interrupts */
163261ea058SHoria Geantă clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
164313ea293SRuchika Gupta
165313ea293SRuchika Gupta return 0;
166313ea293SRuchika Gupta }
167313ea293SRuchika Gupta
168313ea293SRuchika Gupta /*
169313ea293SRuchika Gupta * Shutdown JobR independent of platform property code
170313ea293SRuchika Gupta */
caam_jr_shutdown(struct device * dev)171029c053cSFabio Estevam static int caam_jr_shutdown(struct device *dev)
172313ea293SRuchika Gupta {
173313ea293SRuchika Gupta struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
174313ea293SRuchika Gupta int ret;
175313ea293SRuchika Gupta
176313ea293SRuchika Gupta ret = caam_reset_hw_jr(dev);
177313ea293SRuchika Gupta
1782b163b5bSHoria Geantă tasklet_kill(&jrp->irqtask);
1792b163b5bSHoria Geantă
180313ea293SRuchika Gupta return ret;
181313ea293SRuchika Gupta }
182313ea293SRuchika Gupta
caam_jr_remove(struct platform_device * pdev)183313ea293SRuchika Gupta static int caam_jr_remove(struct platform_device *pdev)
184313ea293SRuchika Gupta {
185313ea293SRuchika Gupta int ret;
186313ea293SRuchika Gupta struct device *jrdev;
187313ea293SRuchika Gupta struct caam_drv_private_jr *jrpriv;
188313ea293SRuchika Gupta
189313ea293SRuchika Gupta jrdev = &pdev->dev;
190313ea293SRuchika Gupta jrpriv = dev_get_drvdata(jrdev);
191313ea293SRuchika Gupta
1921517f63cSAndrey Smirnov if (jrpriv->hwrng)
1931517f63cSAndrey Smirnov caam_rng_exit(jrdev->parent);
1941517f63cSAndrey Smirnov
195313ea293SRuchika Gupta /*
19607defbfbSRuchika Gupta * Return EBUSY if job ring already allocated.
197313ea293SRuchika Gupta */
19807defbfbSRuchika Gupta if (atomic_read(&jrpriv->tfm_count)) {
199313ea293SRuchika Gupta dev_err(jrdev, "Device is busy\n");
200313ea293SRuchika Gupta return -EBUSY;
201313ea293SRuchika Gupta }
202313ea293SRuchika Gupta
2031b46c90cSHoria Geantă /* Unregister JR-based RNG & crypto algorithms */
2041b46c90cSHoria Geantă unregister_algs();
2051b46c90cSHoria Geantă
206313ea293SRuchika Gupta /* Remove the node from Physical JobR list maintained by driver */
207313ea293SRuchika Gupta spin_lock(&driver_data.jr_alloc_lock);
208313ea293SRuchika Gupta list_del(&jrpriv->list_node);
209313ea293SRuchika Gupta spin_unlock(&driver_data.jr_alloc_lock);
210313ea293SRuchika Gupta
211313ea293SRuchika Gupta /* Release ring */
212313ea293SRuchika Gupta ret = caam_jr_shutdown(jrdev);
213313ea293SRuchika Gupta if (ret)
214313ea293SRuchika Gupta dev_err(jrdev, "Failed to shut down job ring\n");
215313ea293SRuchika Gupta
216313ea293SRuchika Gupta return ret;
217313ea293SRuchika Gupta }
218313ea293SRuchika Gupta
caam_jr_platform_shutdown(struct platform_device * pdev)219c007e720SGaurav Jain static void caam_jr_platform_shutdown(struct platform_device *pdev)
220c007e720SGaurav Jain {
221c007e720SGaurav Jain caam_jr_remove(pdev);
222c007e720SGaurav Jain }
223c007e720SGaurav Jain
2248e8ec596SKim Phillips /* Main per-ring interrupt handler */
caam_jr_interrupt(int irq,void * st_dev)2258e8ec596SKim Phillips static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
2268e8ec596SKim Phillips {
2278e8ec596SKim Phillips struct device *dev = st_dev;
2288e8ec596SKim Phillips struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
2298e8ec596SKim Phillips u32 irqstate;
2308e8ec596SKim Phillips
2318e8ec596SKim Phillips /*
2328e8ec596SKim Phillips * Check the output ring for ready responses, kick
2332b163b5bSHoria Geantă * tasklet if jobs done.
2348e8ec596SKim Phillips */
2358e8ec596SKim Phillips irqstate = rd_reg32(&jrp->rregs->jrintstatus);
23623d422a4SHoria Geantă if (!(irqstate & JRINT_JR_INT))
2378e8ec596SKim Phillips return IRQ_NONE;
2388e8ec596SKim Phillips
2398e8ec596SKim Phillips /*
2408e8ec596SKim Phillips * If JobR error, we got more development work to do
2418e8ec596SKim Phillips * Flag a bug now, but we really need to shut down and
2428e8ec596SKim Phillips * restart the queue (and fix code).
2438e8ec596SKim Phillips */
2448e8ec596SKim Phillips if (irqstate & JRINT_JR_ERROR) {
2458e8ec596SKim Phillips dev_err(dev, "job ring error: irqstate: %08x\n", irqstate);
2468e8ec596SKim Phillips BUG();
2478e8ec596SKim Phillips }
2488e8ec596SKim Phillips
2498e8ec596SKim Phillips /* mask valid interrupts */
250261ea058SHoria Geantă clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
2518e8ec596SKim Phillips
2528e8ec596SKim Phillips /* Have valid interrupt at this point, just ACK and trigger */
2538e8ec596SKim Phillips wr_reg32(&jrp->rregs->jrintstatus, irqstate);
2548e8ec596SKim Phillips
2552b163b5bSHoria Geantă preempt_disable();
2562b163b5bSHoria Geantă tasklet_schedule(&jrp->irqtask);
2572b163b5bSHoria Geantă preempt_enable();
2582b163b5bSHoria Geantă
2592b163b5bSHoria Geantă return IRQ_HANDLED;
2608e8ec596SKim Phillips }
2618e8ec596SKim Phillips
2622b163b5bSHoria Geantă /* Deferred service handler, run as interrupt-fired tasklet */
caam_jr_dequeue(unsigned long devarg)2632b163b5bSHoria Geantă static void caam_jr_dequeue(unsigned long devarg)
2648e8ec596SKim Phillips {
2658e8ec596SKim Phillips int hw_idx, sw_idx, i, head, tail;
266322d7475SHoria Geanta struct caam_jr_dequeue_params *params = (void *)devarg;
267322d7475SHoria Geanta struct device *dev = params->dev;
2688e8ec596SKim Phillips struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
2698e8ec596SKim Phillips void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
2708e8ec596SKim Phillips u32 *userdesc, userstatus;
2718e8ec596SKim Phillips void *userarg;
27216c4dd83SVakul Garg u32 outring_used = 0;
2738e8ec596SKim Phillips
27416c4dd83SVakul Garg while (outring_used ||
27516c4dd83SVakul Garg (outring_used = rd_reg32(&jrp->rregs->outring_used))) {
2768e8ec596SKim Phillips
2776aa7de05SMark Rutland head = READ_ONCE(jrp->head);
278a8ea07c2SKim Phillips
2798e8ec596SKim Phillips sw_idx = tail = jrp->tail;
2808e8ec596SKim Phillips hw_idx = jrp->out_ring_read_index;
281a8ea07c2SKim Phillips
2828e8ec596SKim Phillips for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
2838e8ec596SKim Phillips sw_idx = (tail + i) & (JOBR_DEPTH - 1);
2848e8ec596SKim Phillips
2856c5f898fSAndrey Smirnov if (jr_outentry_desc(jrp->outring, hw_idx) ==
286261ea058SHoria Geantă caam_dma_to_cpu(jrp->entinfo[sw_idx].desc_addr_dma))
2878e8ec596SKim Phillips break; /* found */
2888e8ec596SKim Phillips }
2898e8ec596SKim Phillips /* we should never fail to find a matching descriptor */
2908e8ec596SKim Phillips BUG_ON(CIRC_CNT(head, tail + i, JOBR_DEPTH) <= 0);
2918e8ec596SKim Phillips
2928e8ec596SKim Phillips /* Unmap just-run descriptor so we can post-process */
293cc98963dSHoria Geantă dma_unmap_single(dev,
2946c5f898fSAndrey Smirnov caam_dma_to_cpu(jr_outentry_desc(jrp->outring,
2956c5f898fSAndrey Smirnov hw_idx)),
2968e8ec596SKim Phillips jrp->entinfo[sw_idx].desc_size,
2978e8ec596SKim Phillips DMA_TO_DEVICE);
2988e8ec596SKim Phillips
2998e8ec596SKim Phillips /* mark completed, avoid matching on a recycled desc addr */
3008e8ec596SKim Phillips jrp->entinfo[sw_idx].desc_addr_dma = 0;
3018e8ec596SKim Phillips
302a118dfa0SVakul Garg /* Stash callback params */
3038e8ec596SKim Phillips usercall = jrp->entinfo[sw_idx].callbk;
3048e8ec596SKim Phillips userarg = jrp->entinfo[sw_idx].cbkarg;
3058e8ec596SKim Phillips userdesc = jrp->entinfo[sw_idx].desc_addr_virt;
3066c5f898fSAndrey Smirnov userstatus = caam32_to_cpu(jr_outentry_jrstatus(jrp->outring,
3076c5f898fSAndrey Smirnov hw_idx));
3088e8ec596SKim Phillips
309e7472422SVictoria Milhoan /*
310e7472422SVictoria Milhoan * Make sure all information from the job has been obtained
311e7472422SVictoria Milhoan * before telling CAAM that the job has been removed from the
312e7472422SVictoria Milhoan * output ring.
313e7472422SVictoria Milhoan */
314e7472422SVictoria Milhoan mb();
315e7472422SVictoria Milhoan
31614a8e29cSKim Phillips /* set done */
317cbc22b06SHerbert Xu wr_reg32(&jrp->rregs->outring_rmvd, 1);
3188e8ec596SKim Phillips
3198e8ec596SKim Phillips jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) &
3208e8ec596SKim Phillips (JOBR_DEPTH - 1);
3218e8ec596SKim Phillips
3228e8ec596SKim Phillips /*
3238e8ec596SKim Phillips * if this job completed out-of-order, do not increment
3248e8ec596SKim Phillips * the tail. Otherwise, increment tail by 1 plus the
3258e8ec596SKim Phillips * number of subsequent jobs already completed out-of-order
3268e8ec596SKim Phillips */
3278e8ec596SKim Phillips if (sw_idx == tail) {
3288e8ec596SKim Phillips do {
3298e8ec596SKim Phillips tail = (tail + 1) & (JOBR_DEPTH - 1);
3308e8ec596SKim Phillips } while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 &&
3318e8ec596SKim Phillips jrp->entinfo[tail].desc_addr_dma == 0);
3328e8ec596SKim Phillips
3338e8ec596SKim Phillips jrp->tail = tail;
3348e8ec596SKim Phillips }
3358e8ec596SKim Phillips
3368e8ec596SKim Phillips /* Finally, execute user's callback */
3378e8ec596SKim Phillips usercall(dev, userdesc, userstatus, userarg);
33816c4dd83SVakul Garg outring_used--;
3398e8ec596SKim Phillips }
3408e8ec596SKim Phillips
341322d7475SHoria Geanta if (params->enable_itr)
3428e8ec596SKim Phillips /* reenable / unmask IRQs */
343261ea058SHoria Geantă clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
3448e8ec596SKim Phillips }
3458e8ec596SKim Phillips
3468e8ec596SKim Phillips /**
34707defbfbSRuchika Gupta * caam_jr_alloc() - Alloc a job ring for someone to use as needed.
34807defbfbSRuchika Gupta *
34907defbfbSRuchika Gupta * returns : pointer to the newly allocated physical
35007defbfbSRuchika Gupta * JobR dev can be written to if successful.
35107defbfbSRuchika Gupta **/
caam_jr_alloc(void)35207defbfbSRuchika Gupta struct device *caam_jr_alloc(void)
35307defbfbSRuchika Gupta {
35407defbfbSRuchika Gupta struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL;
355e930c765SCatalin Vasile struct device *dev = ERR_PTR(-ENODEV);
35607defbfbSRuchika Gupta int min_tfm_cnt = INT_MAX;
35707defbfbSRuchika Gupta int tfm_cnt;
35807defbfbSRuchika Gupta
35907defbfbSRuchika Gupta spin_lock(&driver_data.jr_alloc_lock);
36007defbfbSRuchika Gupta
36107defbfbSRuchika Gupta if (list_empty(&driver_data.jr_list)) {
36207defbfbSRuchika Gupta spin_unlock(&driver_data.jr_alloc_lock);
36307defbfbSRuchika Gupta return ERR_PTR(-ENODEV);
36407defbfbSRuchika Gupta }
36507defbfbSRuchika Gupta
36607defbfbSRuchika Gupta list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) {
36707defbfbSRuchika Gupta tfm_cnt = atomic_read(&jrpriv->tfm_count);
36807defbfbSRuchika Gupta if (tfm_cnt < min_tfm_cnt) {
36907defbfbSRuchika Gupta min_tfm_cnt = tfm_cnt;
37007defbfbSRuchika Gupta min_jrpriv = jrpriv;
37107defbfbSRuchika Gupta }
37207defbfbSRuchika Gupta if (!min_tfm_cnt)
37307defbfbSRuchika Gupta break;
37407defbfbSRuchika Gupta }
37507defbfbSRuchika Gupta
37607defbfbSRuchika Gupta if (min_jrpriv) {
37707defbfbSRuchika Gupta atomic_inc(&min_jrpriv->tfm_count);
37807defbfbSRuchika Gupta dev = min_jrpriv->dev;
37907defbfbSRuchika Gupta }
38007defbfbSRuchika Gupta spin_unlock(&driver_data.jr_alloc_lock);
38107defbfbSRuchika Gupta
38207defbfbSRuchika Gupta return dev;
38307defbfbSRuchika Gupta }
38407defbfbSRuchika Gupta EXPORT_SYMBOL(caam_jr_alloc);
38507defbfbSRuchika Gupta
38607defbfbSRuchika Gupta /**
38707defbfbSRuchika Gupta * caam_jr_free() - Free the Job Ring
388319936bfSKrzysztof Kozlowski * @rdev: points to the dev that identifies the Job ring to
38907defbfbSRuchika Gupta * be released.
39007defbfbSRuchika Gupta **/
caam_jr_free(struct device * rdev)39107defbfbSRuchika Gupta void caam_jr_free(struct device *rdev)
39207defbfbSRuchika Gupta {
39307defbfbSRuchika Gupta struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev);
39407defbfbSRuchika Gupta
39507defbfbSRuchika Gupta atomic_dec(&jrpriv->tfm_count);
39607defbfbSRuchika Gupta }
39707defbfbSRuchika Gupta EXPORT_SYMBOL(caam_jr_free);
39807defbfbSRuchika Gupta
39907defbfbSRuchika Gupta /**
4004d370a10SIuliana Prodan * caam_jr_enqueue() - Enqueue a job descriptor head. Returns -EINPROGRESS
4014d370a10SIuliana Prodan * if OK, -ENOSPC if the queue is full, -EIO if it cannot map the caller's
4028e8ec596SKim Phillips * descriptor.
40326c4a51fSDan Douglass * @dev: struct device of the job ring to be used
4048e8ec596SKim Phillips * @desc: points to a job descriptor that execute our request. All
4058e8ec596SKim Phillips * descriptors (and all referenced data) must be in a DMAable
4068e8ec596SKim Phillips * region, and all data references must be physical addresses
4078e8ec596SKim Phillips * accessible to CAAM (i.e. within a PAMU window granted
4088e8ec596SKim Phillips * to it).
4098e8ec596SKim Phillips * @cbk: pointer to a callback function to be invoked upon completion
4108e8ec596SKim Phillips * of this request. This has the form:
4118e8ec596SKim Phillips * callback(struct device *dev, u32 *desc, u32 stat, void *arg)
4128e8ec596SKim Phillips * where:
413319936bfSKrzysztof Kozlowski * dev: contains the job ring device that processed this
4148e8ec596SKim Phillips * response.
415319936bfSKrzysztof Kozlowski * desc: descriptor that initiated the request, same as
4168e8ec596SKim Phillips * "desc" being argued to caam_jr_enqueue().
417319936bfSKrzysztof Kozlowski * status: untranslated status received from CAAM. See the
4188e8ec596SKim Phillips * reference manual for a detailed description of
4198e8ec596SKim Phillips * error meaning, or see the JRSTA definitions in the
4208e8ec596SKim Phillips * register header file
421319936bfSKrzysztof Kozlowski * areq: optional pointer to an argument passed with the
4228e8ec596SKim Phillips * original request
4238e8ec596SKim Phillips * @areq: optional pointer to a user argument for use at callback
4248e8ec596SKim Phillips * time.
4258e8ec596SKim Phillips **/
caam_jr_enqueue(struct device * dev,u32 * desc,void (* cbk)(struct device * dev,u32 * desc,u32 status,void * areq),void * areq)4268e8ec596SKim Phillips int caam_jr_enqueue(struct device *dev, u32 *desc,
4278e8ec596SKim Phillips void (*cbk)(struct device *dev, u32 *desc,
4288e8ec596SKim Phillips u32 status, void *areq),
4298e8ec596SKim Phillips void *areq)
4308e8ec596SKim Phillips {
4318e8ec596SKim Phillips struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
4328e8ec596SKim Phillips struct caam_jrentry_info *head_entry;
4338e8ec596SKim Phillips int head, tail, desc_size;
4348e8ec596SKim Phillips dma_addr_t desc_dma;
4358e8ec596SKim Phillips
436261ea058SHoria Geantă desc_size = (caam32_to_cpu(*desc) & HDR_JD_LENGTH_MASK) * sizeof(u32);
4378e8ec596SKim Phillips desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE);
4388e8ec596SKim Phillips if (dma_mapping_error(dev, desc_dma)) {
4398e8ec596SKim Phillips dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n");
4408e8ec596SKim Phillips return -EIO;
4418e8ec596SKim Phillips }
4428e8ec596SKim Phillips
443ce026cb9SKim Phillips spin_lock_bh(&jrp->inplock);
4448e8ec596SKim Phillips
4458e8ec596SKim Phillips head = jrp->head;
4466aa7de05SMark Rutland tail = READ_ONCE(jrp->tail);
4478e8ec596SKim Phillips
44816c4dd83SVakul Garg if (!jrp->inpring_avail ||
4498e8ec596SKim Phillips CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
450ce026cb9SKim Phillips spin_unlock_bh(&jrp->inplock);
4518e8ec596SKim Phillips dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
4524d370a10SIuliana Prodan return -ENOSPC;
4538e8ec596SKim Phillips }
4548e8ec596SKim Phillips
4558e8ec596SKim Phillips head_entry = &jrp->entinfo[head];
4568e8ec596SKim Phillips head_entry->desc_addr_virt = desc;
4578e8ec596SKim Phillips head_entry->desc_size = desc_size;
4588e8ec596SKim Phillips head_entry->callbk = (void *)cbk;
4598e8ec596SKim Phillips head_entry->cbkarg = areq;
4608e8ec596SKim Phillips head_entry->desc_addr_dma = desc_dma;
4618e8ec596SKim Phillips
462dff36801SAndrey Smirnov jr_inpentry_set(jrp->inpring, head, cpu_to_caam_dma(desc_dma));
4638e8ec596SKim Phillips
464e7472422SVictoria Milhoan /*
465e7472422SVictoria Milhoan * Guarantee that the descriptor's DMA address has been written to
466e7472422SVictoria Milhoan * the next slot in the ring before the write index is updated, since
467e7472422SVictoria Milhoan * other cores may update this index independently.
468e47e6d2aSIuliana Prodan *
469e47e6d2aSIuliana Prodan * Under heavy DDR load, smp_wmb() or dma_wmb() fail to make the input
470e47e6d2aSIuliana Prodan * ring be updated before the CAAM starts reading it. So, CAAM will
471e47e6d2aSIuliana Prodan * process, again, an old descriptor address and will put it in the
472e47e6d2aSIuliana Prodan * output ring. This will make caam_jr_dequeue() to fail, since this
473e47e6d2aSIuliana Prodan * old descriptor is not in the software ring.
474e47e6d2aSIuliana Prodan * To fix this, use wmb() which works on the full system instead of
475e47e6d2aSIuliana Prodan * inner/outer shareable domains.
476e7472422SVictoria Milhoan */
477e47e6d2aSIuliana Prodan wmb();
4788e8ec596SKim Phillips
4798e8ec596SKim Phillips jrp->head = (head + 1) & (JOBR_DEPTH - 1);
4808e8ec596SKim Phillips
481e7472422SVictoria Milhoan /*
482e7472422SVictoria Milhoan * Ensure that all job information has been written before
483c23116e4SVakul Garg * notifying CAAM that a new job was added to the input ring
484c23116e4SVakul Garg * using a memory barrier. The wr_reg32() uses api iowrite32()
485c23116e4SVakul Garg * to do the register write. iowrite32() issues a memory barrier
486c23116e4SVakul Garg * before the write operation.
487e7472422SVictoria Milhoan */
488e7472422SVictoria Milhoan
4898e8ec596SKim Phillips wr_reg32(&jrp->rregs->inpring_jobadd, 1);
4908e8ec596SKim Phillips
49116c4dd83SVakul Garg jrp->inpring_avail--;
49216c4dd83SVakul Garg if (!jrp->inpring_avail)
49316c4dd83SVakul Garg jrp->inpring_avail = rd_reg32(&jrp->rregs->inpring_avail);
49416c4dd83SVakul Garg
495ce026cb9SKim Phillips spin_unlock_bh(&jrp->inplock);
4968e8ec596SKim Phillips
4974d370a10SIuliana Prodan return -EINPROGRESS;
4988e8ec596SKim Phillips }
4998e8ec596SKim Phillips EXPORT_SYMBOL(caam_jr_enqueue);
5008e8ec596SKim Phillips
caam_jr_init_hw(struct device * dev,dma_addr_t inpbusaddr,dma_addr_t outbusaddr)501322d7475SHoria Geanta static void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr,
502322d7475SHoria Geanta dma_addr_t outbusaddr)
503322d7475SHoria Geanta {
504322d7475SHoria Geanta struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
505322d7475SHoria Geanta
506322d7475SHoria Geanta wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
507322d7475SHoria Geanta wr_reg64(&jrp->rregs->outring_base, outbusaddr);
508322d7475SHoria Geanta wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
509322d7475SHoria Geanta wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
510322d7475SHoria Geanta
511322d7475SHoria Geanta /* Select interrupt coalescing parameters */
512322d7475SHoria Geanta clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
513322d7475SHoria Geanta (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
514322d7475SHoria Geanta (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
515322d7475SHoria Geanta }
516322d7475SHoria Geanta
caam_jr_reset_index(struct caam_drv_private_jr * jrp)517322d7475SHoria Geanta static void caam_jr_reset_index(struct caam_drv_private_jr *jrp)
518322d7475SHoria Geanta {
519322d7475SHoria Geanta jrp->out_ring_read_index = 0;
520322d7475SHoria Geanta jrp->head = 0;
521322d7475SHoria Geanta jrp->tail = 0;
522322d7475SHoria Geanta }
523322d7475SHoria Geanta
5248e8ec596SKim Phillips /*
5258e8ec596SKim Phillips * Init JobR independent of platform property detection
5268e8ec596SKim Phillips */
caam_jr_init(struct device * dev)5278e8ec596SKim Phillips static int caam_jr_init(struct device *dev)
5288e8ec596SKim Phillips {
5298e8ec596SKim Phillips struct caam_drv_private_jr *jrp;
5308e8ec596SKim Phillips dma_addr_t inpbusaddr, outbusaddr;
5318e8ec596SKim Phillips int i, error;
5328e8ec596SKim Phillips
5338e8ec596SKim Phillips jrp = dev_get_drvdata(dev);
5348e8ec596SKim Phillips
5358e8ec596SKim Phillips error = caam_reset_hw_jr(dev);
5368e8ec596SKim Phillips if (error)
537d488dfd9SAndrey Smirnov return error;
5388e8ec596SKim Phillips
539dff36801SAndrey Smirnov jrp->inpring = dmam_alloc_coherent(dev, SIZEOF_JR_INPENTRY *
540a6c4194eSAndrey Smirnov JOBR_DEPTH, &inpbusaddr,
541a6c4194eSAndrey Smirnov GFP_KERNEL);
542cbceeefdSCristian Stoica if (!jrp->inpring)
543d488dfd9SAndrey Smirnov return -ENOMEM;
5441af8ea86SBharat Bhushan
5456c5f898fSAndrey Smirnov jrp->outring = dmam_alloc_coherent(dev, SIZEOF_JR_OUTENTRY *
546a6c4194eSAndrey Smirnov JOBR_DEPTH, &outbusaddr,
547a6c4194eSAndrey Smirnov GFP_KERNEL);
548cbceeefdSCristian Stoica if (!jrp->outring)
549d488dfd9SAndrey Smirnov return -ENOMEM;
5508e8ec596SKim Phillips
551a6c4194eSAndrey Smirnov jrp->entinfo = devm_kcalloc(dev, JOBR_DEPTH, sizeof(*jrp->entinfo),
552a6c4194eSAndrey Smirnov GFP_KERNEL);
553cbceeefdSCristian Stoica if (!jrp->entinfo)
554d488dfd9SAndrey Smirnov return -ENOMEM;
5558e8ec596SKim Phillips
5568e8ec596SKim Phillips for (i = 0; i < JOBR_DEPTH; i++)
5578e8ec596SKim Phillips jrp->entinfo[i].desc_addr_dma = !0;
5588e8ec596SKim Phillips
5598e8ec596SKim Phillips /* Setup rings */
560322d7475SHoria Geanta caam_jr_reset_index(jrp);
56116c4dd83SVakul Garg jrp->inpring_avail = JOBR_DEPTH;
562322d7475SHoria Geanta caam_jr_init_hw(dev, inpbusaddr, outbusaddr);
5638e8ec596SKim Phillips
5648e8ec596SKim Phillips spin_lock_init(&jrp->inplock);
5658e8ec596SKim Phillips
566322d7475SHoria Geanta jrp->tasklet_params.dev = dev;
567322d7475SHoria Geanta jrp->tasklet_params.enable_itr = 1;
568322d7475SHoria Geanta tasklet_init(&jrp->irqtask, caam_jr_dequeue,
569322d7475SHoria Geanta (unsigned long)&jrp->tasklet_params);
570d488dfd9SAndrey Smirnov
571d488dfd9SAndrey Smirnov /* Connect job ring interrupt handler. */
572d488dfd9SAndrey Smirnov error = devm_request_irq(dev, jrp->irq, caam_jr_interrupt, IRQF_SHARED,
573d488dfd9SAndrey Smirnov dev_name(dev), dev);
574d488dfd9SAndrey Smirnov if (error) {
575d488dfd9SAndrey Smirnov dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
576d488dfd9SAndrey Smirnov jrp->ridx, jrp->irq);
5772b163b5bSHoria Geantă tasklet_kill(&jrp->irqtask);
578d488dfd9SAndrey Smirnov }
579d488dfd9SAndrey Smirnov
580cbceeefdSCristian Stoica return error;
5818e8ec596SKim Phillips }
5828e8ec596SKim Phillips
caam_jr_irq_dispose_mapping(void * data)583f2ef9602SAndrey Smirnov static void caam_jr_irq_dispose_mapping(void *data)
584f2ef9602SAndrey Smirnov {
5859575d1a5SHerbert Xu irq_dispose_mapping((unsigned long)data);
586f2ef9602SAndrey Smirnov }
5878e8ec596SKim Phillips
5888e8ec596SKim Phillips /*
589313ea293SRuchika Gupta * Probe routine for each detected JobR subsystem.
5908e8ec596SKim Phillips */
caam_jr_probe(struct platform_device * pdev)591313ea293SRuchika Gupta static int caam_jr_probe(struct platform_device *pdev)
5928e8ec596SKim Phillips {
593313ea293SRuchika Gupta struct device *jrdev;
594313ea293SRuchika Gupta struct device_node *nprop;
595313ea293SRuchika Gupta struct caam_job_ring __iomem *ctrl;
5968e8ec596SKim Phillips struct caam_drv_private_jr *jrpriv;
597313ea293SRuchika Gupta static int total_jobrs;
59805d2a754SAndrey Smirnov struct resource *r;
5998e8ec596SKim Phillips int error;
6008e8ec596SKim Phillips
601313ea293SRuchika Gupta jrdev = &pdev->dev;
6021517f63cSAndrey Smirnov jrpriv = devm_kzalloc(jrdev, sizeof(*jrpriv), GFP_KERNEL);
603313ea293SRuchika Gupta if (!jrpriv)
604313ea293SRuchika Gupta return -ENOMEM;
605313ea293SRuchika Gupta
606313ea293SRuchika Gupta dev_set_drvdata(jrdev, jrpriv);
607313ea293SRuchika Gupta
608313ea293SRuchika Gupta /* save ring identity relative to detection */
609313ea293SRuchika Gupta jrpriv->ridx = total_jobrs++;
610313ea293SRuchika Gupta
611313ea293SRuchika Gupta nprop = pdev->dev.of_node;
612313ea293SRuchika Gupta /* Get configuration properties from device tree */
613313ea293SRuchika Gupta /* First, get register page */
61405d2a754SAndrey Smirnov r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
61505d2a754SAndrey Smirnov if (!r) {
61605d2a754SAndrey Smirnov dev_err(jrdev, "platform_get_resource() failed\n");
61705d2a754SAndrey Smirnov return -ENOMEM;
61805d2a754SAndrey Smirnov }
61905d2a754SAndrey Smirnov
62005d2a754SAndrey Smirnov ctrl = devm_ioremap(jrdev, r->start, resource_size(r));
621313ea293SRuchika Gupta if (!ctrl) {
62205d2a754SAndrey Smirnov dev_err(jrdev, "devm_ioremap() failed\n");
6238e8ec596SKim Phillips return -ENOMEM;
6248e8ec596SKim Phillips }
6258e8ec596SKim Phillips
6268439e94fSHoria Geantă jrpriv->rregs = (struct caam_job_ring __iomem __force *)ctrl;
6278e8ec596SKim Phillips
62870c0cda2SAndrey Smirnov error = dma_set_mask_and_coherent(jrdev, caam_get_dma_mask(jrdev));
629b3b5fce7SHoria Geantă if (error) {
630b3b5fce7SHoria Geantă dev_err(jrdev, "dma_set_mask_and_coherent failed (%d)\n",
631b3b5fce7SHoria Geantă error);
632b3b5fce7SHoria Geantă return error;
633b3b5fce7SHoria Geantă }
634e13af18aSKim Phillips
635ee38767fSIuliana Prodan /* Initialize crypto engine */
6362d653936SIuliana Prodan jrpriv->engine = crypto_engine_alloc_init_and_set(jrdev, true, NULL,
6372d653936SIuliana Prodan false,
6382d653936SIuliana Prodan CRYPTO_ENGINE_MAX_QLEN);
639ee38767fSIuliana Prodan if (!jrpriv->engine) {
640ee38767fSIuliana Prodan dev_err(jrdev, "Could not init crypto-engine\n");
641ee38767fSIuliana Prodan return -ENOMEM;
642ee38767fSIuliana Prodan }
643ee38767fSIuliana Prodan
644ee38767fSIuliana Prodan error = devm_add_action_or_reset(jrdev, caam_jr_crypto_engine_exit,
645ee38767fSIuliana Prodan jrdev);
646ee38767fSIuliana Prodan if (error)
647ee38767fSIuliana Prodan return error;
648ee38767fSIuliana Prodan
649ee38767fSIuliana Prodan /* Start crypto engine */
650ee38767fSIuliana Prodan error = crypto_engine_start(jrpriv->engine);
651ee38767fSIuliana Prodan if (error) {
652ee38767fSIuliana Prodan dev_err(jrdev, "Could not start crypto-engine\n");
653ee38767fSIuliana Prodan return error;
654ee38767fSIuliana Prodan }
655ee38767fSIuliana Prodan
6568e8ec596SKim Phillips /* Identify the interrupt */
65726b265cdSLinus Torvalds jrpriv->irq = irq_of_parse_and_map(nprop, 0);
658549077d7SAndrey Smirnov if (!jrpriv->irq) {
659549077d7SAndrey Smirnov dev_err(jrdev, "irq_of_parse_and_map failed\n");
660549077d7SAndrey Smirnov return -EINVAL;
661549077d7SAndrey Smirnov }
6628e8ec596SKim Phillips
663f2ef9602SAndrey Smirnov error = devm_add_action_or_reset(jrdev, caam_jr_irq_dispose_mapping,
6649575d1a5SHerbert Xu (void *)(unsigned long)jrpriv->irq);
665f2ef9602SAndrey Smirnov if (error)
666f2ef9602SAndrey Smirnov return error;
667f2ef9602SAndrey Smirnov
6688e8ec596SKim Phillips /* Now do the platform independent part */
6698e8ec596SKim Phillips error = caam_jr_init(jrdev); /* now turn on hardware */
670f2ef9602SAndrey Smirnov if (error)
6718e8ec596SKim Phillips return error;
6728e8ec596SKim Phillips
673313ea293SRuchika Gupta jrpriv->dev = jrdev;
674313ea293SRuchika Gupta spin_lock(&driver_data.jr_alloc_lock);
675313ea293SRuchika Gupta list_add_tail(&jrpriv->list_node, &driver_data.jr_list);
676313ea293SRuchika Gupta spin_unlock(&driver_data.jr_alloc_lock);
677313ea293SRuchika Gupta
67807defbfbSRuchika Gupta atomic_set(&jrpriv->tfm_count, 0);
67907defbfbSRuchika Gupta
680322d7475SHoria Geanta device_init_wakeup(&pdev->dev, 1);
681322d7475SHoria Geanta device_set_wakeup_enable(&pdev->dev, false);
682322d7475SHoria Geanta
6831517f63cSAndrey Smirnov register_algs(jrpriv, jrdev->parent);
6841b46c90cSHoria Geantă
685313ea293SRuchika Gupta return 0;
6868e8ec596SKim Phillips }
687313ea293SRuchika Gupta
caam_jr_get_hw_state(struct device * dev)688322d7475SHoria Geanta static void caam_jr_get_hw_state(struct device *dev)
689322d7475SHoria Geanta {
690322d7475SHoria Geanta struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
691322d7475SHoria Geanta
692322d7475SHoria Geanta jrp->state.inpbusaddr = rd_reg64(&jrp->rregs->inpring_base);
693322d7475SHoria Geanta jrp->state.outbusaddr = rd_reg64(&jrp->rregs->outring_base);
694322d7475SHoria Geanta }
695322d7475SHoria Geanta
caam_jr_suspend(struct device * dev)696322d7475SHoria Geanta static int caam_jr_suspend(struct device *dev)
697322d7475SHoria Geanta {
698322d7475SHoria Geanta struct platform_device *pdev = to_platform_device(dev);
699322d7475SHoria Geanta struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
700322d7475SHoria Geanta struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
701322d7475SHoria Geanta struct caam_jr_dequeue_params suspend_params = {
702322d7475SHoria Geanta .dev = dev,
703322d7475SHoria Geanta .enable_itr = 0,
704322d7475SHoria Geanta };
705322d7475SHoria Geanta
706322d7475SHoria Geanta /* Remove the node from Physical JobR list maintained by driver */
707322d7475SHoria Geanta spin_lock(&driver_data.jr_alloc_lock);
708322d7475SHoria Geanta list_del(&jrpriv->list_node);
709322d7475SHoria Geanta spin_unlock(&driver_data.jr_alloc_lock);
710322d7475SHoria Geanta
711322d7475SHoria Geanta if (jrpriv->hwrng)
712322d7475SHoria Geanta caam_rng_exit(dev->parent);
713322d7475SHoria Geanta
714322d7475SHoria Geanta if (ctrlpriv->caam_off_during_pm) {
715322d7475SHoria Geanta int err;
716322d7475SHoria Geanta
717322d7475SHoria Geanta tasklet_disable(&jrpriv->irqtask);
718322d7475SHoria Geanta
719322d7475SHoria Geanta /* mask itr to call flush */
720322d7475SHoria Geanta clrsetbits_32(&jrpriv->rregs->rconfig_lo, 0, JRCFG_IMSK);
721322d7475SHoria Geanta
722322d7475SHoria Geanta /* Invalid job in process */
723322d7475SHoria Geanta err = caam_jr_flush(dev);
724322d7475SHoria Geanta if (err) {
725322d7475SHoria Geanta dev_err(dev, "Failed to flush\n");
726322d7475SHoria Geanta return err;
727322d7475SHoria Geanta }
728322d7475SHoria Geanta
729322d7475SHoria Geanta /* Dequeing jobs flushed */
730322d7475SHoria Geanta caam_jr_dequeue((unsigned long)&suspend_params);
731322d7475SHoria Geanta
732322d7475SHoria Geanta /* Save state */
733322d7475SHoria Geanta caam_jr_get_hw_state(dev);
734322d7475SHoria Geanta } else if (device_may_wakeup(&pdev->dev)) {
735322d7475SHoria Geanta enable_irq_wake(jrpriv->irq);
736322d7475SHoria Geanta }
737322d7475SHoria Geanta
738322d7475SHoria Geanta return 0;
739322d7475SHoria Geanta }
740322d7475SHoria Geanta
caam_jr_resume(struct device * dev)741322d7475SHoria Geanta static int caam_jr_resume(struct device *dev)
742322d7475SHoria Geanta {
743322d7475SHoria Geanta struct platform_device *pdev = to_platform_device(dev);
744322d7475SHoria Geanta struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
745322d7475SHoria Geanta struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
746322d7475SHoria Geanta
747322d7475SHoria Geanta if (ctrlpriv->caam_off_during_pm) {
748322d7475SHoria Geanta u64 inp_addr;
749322d7475SHoria Geanta int err;
750322d7475SHoria Geanta
751322d7475SHoria Geanta /*
752322d7475SHoria Geanta * Check if the CAAM has been resetted checking the address of
753322d7475SHoria Geanta * the input ring
754322d7475SHoria Geanta */
755322d7475SHoria Geanta inp_addr = rd_reg64(&jrpriv->rregs->inpring_base);
756322d7475SHoria Geanta if (inp_addr != 0) {
757322d7475SHoria Geanta /* JR still has some configuration */
758322d7475SHoria Geanta if (inp_addr == jrpriv->state.inpbusaddr) {
759322d7475SHoria Geanta /* JR has not been resetted */
760322d7475SHoria Geanta err = caam_jr_restart_processing(dev);
761322d7475SHoria Geanta if (err) {
762322d7475SHoria Geanta dev_err(dev,
763322d7475SHoria Geanta "Restart processing failed\n");
764322d7475SHoria Geanta return err;
765322d7475SHoria Geanta }
766322d7475SHoria Geanta
767322d7475SHoria Geanta tasklet_enable(&jrpriv->irqtask);
768322d7475SHoria Geanta
769322d7475SHoria Geanta clrsetbits_32(&jrpriv->rregs->rconfig_lo,
770322d7475SHoria Geanta JRCFG_IMSK, 0);
771322d7475SHoria Geanta
772322d7475SHoria Geanta goto add_jr;
773322d7475SHoria Geanta } else if (ctrlpriv->optee_en) {
774322d7475SHoria Geanta /* JR has been used by OPTEE, reset it */
775322d7475SHoria Geanta err = caam_reset_hw_jr(dev);
776322d7475SHoria Geanta if (err) {
777322d7475SHoria Geanta dev_err(dev, "Failed to reset JR\n");
778322d7475SHoria Geanta return err;
779322d7475SHoria Geanta }
780322d7475SHoria Geanta } else {
781322d7475SHoria Geanta /* No explanation, return error */
782322d7475SHoria Geanta return -EIO;
783322d7475SHoria Geanta }
784322d7475SHoria Geanta }
785322d7475SHoria Geanta
786322d7475SHoria Geanta caam_jr_reset_index(jrpriv);
787322d7475SHoria Geanta caam_jr_init_hw(dev, jrpriv->state.inpbusaddr,
788322d7475SHoria Geanta jrpriv->state.outbusaddr);
789322d7475SHoria Geanta
790322d7475SHoria Geanta tasklet_enable(&jrpriv->irqtask);
791322d7475SHoria Geanta } else if (device_may_wakeup(&pdev->dev)) {
792322d7475SHoria Geanta disable_irq_wake(jrpriv->irq);
793322d7475SHoria Geanta }
794322d7475SHoria Geanta
795322d7475SHoria Geanta add_jr:
796322d7475SHoria Geanta spin_lock(&driver_data.jr_alloc_lock);
797322d7475SHoria Geanta list_add_tail(&jrpriv->list_node, &driver_data.jr_list);
798322d7475SHoria Geanta spin_unlock(&driver_data.jr_alloc_lock);
799322d7475SHoria Geanta
800322d7475SHoria Geanta if (jrpriv->hwrng)
801322d7475SHoria Geanta jrpriv->hwrng = !caam_rng_init(dev->parent);
802322d7475SHoria Geanta
803322d7475SHoria Geanta return 0;
804322d7475SHoria Geanta }
805322d7475SHoria Geanta
806b52c8c72SArnd Bergmann static DEFINE_SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, caam_jr_resume);
807322d7475SHoria Geanta
80852a33d99SArvind Yadav static const struct of_device_id caam_jr_match[] = {
809313ea293SRuchika Gupta {
810313ea293SRuchika Gupta .compatible = "fsl,sec-v4.0-job-ring",
811313ea293SRuchika Gupta },
812313ea293SRuchika Gupta {
813313ea293SRuchika Gupta .compatible = "fsl,sec4.0-job-ring",
814313ea293SRuchika Gupta },
815313ea293SRuchika Gupta {},
816313ea293SRuchika Gupta };
817313ea293SRuchika Gupta MODULE_DEVICE_TABLE(of, caam_jr_match);
818313ea293SRuchika Gupta
819313ea293SRuchika Gupta static struct platform_driver caam_jr_driver = {
820313ea293SRuchika Gupta .driver = {
821313ea293SRuchika Gupta .name = "caam_jr",
822313ea293SRuchika Gupta .of_match_table = caam_jr_match,
823b52c8c72SArnd Bergmann .pm = pm_ptr(&caam_jr_pm_ops),
824313ea293SRuchika Gupta },
825313ea293SRuchika Gupta .probe = caam_jr_probe,
826313ea293SRuchika Gupta .remove = caam_jr_remove,
827c007e720SGaurav Jain .shutdown = caam_jr_platform_shutdown,
828313ea293SRuchika Gupta };
829313ea293SRuchika Gupta
jr_driver_init(void)830313ea293SRuchika Gupta static int __init jr_driver_init(void)
831313ea293SRuchika Gupta {
832313ea293SRuchika Gupta spin_lock_init(&driver_data.jr_alloc_lock);
833313ea293SRuchika Gupta INIT_LIST_HEAD(&driver_data.jr_list);
834313ea293SRuchika Gupta return platform_driver_register(&caam_jr_driver);
835313ea293SRuchika Gupta }
836313ea293SRuchika Gupta
jr_driver_exit(void)837313ea293SRuchika Gupta static void __exit jr_driver_exit(void)
838313ea293SRuchika Gupta {
839313ea293SRuchika Gupta platform_driver_unregister(&caam_jr_driver);
840313ea293SRuchika Gupta }
841313ea293SRuchika Gupta
842313ea293SRuchika Gupta module_init(jr_driver_init);
843313ea293SRuchika Gupta module_exit(jr_driver_exit);
844313ea293SRuchika Gupta
845313ea293SRuchika Gupta MODULE_LICENSE("GPL");
846313ea293SRuchika Gupta MODULE_DESCRIPTION("FSL CAAM JR request backend");
847313ea293SRuchika Gupta MODULE_AUTHOR("Freescale Semiconductor - NMG/STC");
848