xref: /openbmc/linux/drivers/crypto/caam/jr.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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