162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * CAAM/SEC 4.x transport/backend driver
462306a36Sopenharmony_ci * JobR backend functionality
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2008-2012 Freescale Semiconductor, Inc.
762306a36Sopenharmony_ci * Copyright 2019, 2023 NXP
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/of_irq.h>
1162306a36Sopenharmony_ci#include <linux/of_address.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "compat.h"
1562306a36Sopenharmony_ci#include "ctrl.h"
1662306a36Sopenharmony_ci#include "regs.h"
1762306a36Sopenharmony_ci#include "jr.h"
1862306a36Sopenharmony_ci#include "desc.h"
1962306a36Sopenharmony_ci#include "intern.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct jr_driver_data {
2262306a36Sopenharmony_ci	/* List of Physical JobR's with the Driver */
2362306a36Sopenharmony_ci	struct list_head	jr_list;
2462306a36Sopenharmony_ci	spinlock_t		jr_alloc_lock;	/* jr_list lock */
2562306a36Sopenharmony_ci} ____cacheline_aligned;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic struct jr_driver_data driver_data;
2862306a36Sopenharmony_cistatic DEFINE_MUTEX(algs_lock);
2962306a36Sopenharmony_cistatic unsigned int active_devs;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void register_algs(struct caam_drv_private_jr *jrpriv,
3262306a36Sopenharmony_ci			  struct device *dev)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	mutex_lock(&algs_lock);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (++active_devs != 1)
3762306a36Sopenharmony_ci		goto algs_unlock;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	caam_algapi_init(dev);
4062306a36Sopenharmony_ci	caam_algapi_hash_init(dev);
4162306a36Sopenharmony_ci	caam_pkc_init(dev);
4262306a36Sopenharmony_ci	jrpriv->hwrng = !caam_rng_init(dev);
4362306a36Sopenharmony_ci	caam_prng_register(dev);
4462306a36Sopenharmony_ci	caam_qi_algapi_init(dev);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cialgs_unlock:
4762306a36Sopenharmony_ci	mutex_unlock(&algs_lock);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void unregister_algs(void)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	mutex_lock(&algs_lock);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (--active_devs != 0)
5562306a36Sopenharmony_ci		goto algs_unlock;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	caam_qi_algapi_exit();
5862306a36Sopenharmony_ci	caam_prng_unregister(NULL);
5962306a36Sopenharmony_ci	caam_pkc_exit();
6062306a36Sopenharmony_ci	caam_algapi_hash_exit();
6162306a36Sopenharmony_ci	caam_algapi_exit();
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cialgs_unlock:
6462306a36Sopenharmony_ci	mutex_unlock(&algs_lock);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void caam_jr_crypto_engine_exit(void *data)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct device *jrdev = data;
7062306a36Sopenharmony_ci	struct caam_drv_private_jr *jrpriv = dev_get_drvdata(jrdev);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Free the resources of crypto-engine */
7362306a36Sopenharmony_ci	crypto_engine_exit(jrpriv->engine);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/*
7762306a36Sopenharmony_ci * Put the CAAM in quiesce, ie stop
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * Must be called with itr disabled
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistatic int caam_jr_stop_processing(struct device *dev, u32 jrcr_bits)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
8462306a36Sopenharmony_ci	unsigned int timeout = 100000;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Check the current status */
8762306a36Sopenharmony_ci	if (rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_INPROGRESS)
8862306a36Sopenharmony_ci		goto wait_quiesce_completion;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Reset the field */
9162306a36Sopenharmony_ci	clrsetbits_32(&jrp->rregs->jrintstatus, JRINT_ERR_HALT_MASK, 0);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* initiate flush / park (required prior to reset) */
9462306a36Sopenharmony_ci	wr_reg32(&jrp->rregs->jrcommand, jrcr_bits);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciwait_quiesce_completion:
9762306a36Sopenharmony_ci	while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
9862306a36Sopenharmony_ci		JRINT_ERR_HALT_INPROGRESS) && --timeout)
9962306a36Sopenharmony_ci		cpu_relax();
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) !=
10262306a36Sopenharmony_ci	    JRINT_ERR_HALT_COMPLETE || timeout == 0) {
10362306a36Sopenharmony_ci		dev_err(dev, "failed to flush job ring %d\n", jrp->ridx);
10462306a36Sopenharmony_ci		return -EIO;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return 0;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci * Flush the job ring, so the jobs running will be stopped, jobs queued will be
11262306a36Sopenharmony_ci * invalidated and the CAAM will no longer fetch fron input ring.
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * Must be called with itr disabled
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_cistatic int caam_jr_flush(struct device *dev)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return caam_jr_stop_processing(dev, JRCR_RESET);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/* The resume can be used after a park or a flush if CAAM has not been reset */
12262306a36Sopenharmony_cistatic int caam_jr_restart_processing(struct device *dev)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
12562306a36Sopenharmony_ci	u32 halt_status = rd_reg32(&jrp->rregs->jrintstatus) &
12662306a36Sopenharmony_ci			  JRINT_ERR_HALT_MASK;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* Check that the flush/park is completed */
12962306a36Sopenharmony_ci	if (halt_status != JRINT_ERR_HALT_COMPLETE)
13062306a36Sopenharmony_ci		return -1;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Resume processing of jobs */
13362306a36Sopenharmony_ci	clrsetbits_32(&jrp->rregs->jrintstatus, 0, JRINT_ERR_HALT_COMPLETE);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int caam_reset_hw_jr(struct device *dev)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
14162306a36Sopenharmony_ci	unsigned int timeout = 100000;
14262306a36Sopenharmony_ci	int err;
14362306a36Sopenharmony_ci	/*
14462306a36Sopenharmony_ci	 * mask interrupts since we are going to poll
14562306a36Sopenharmony_ci	 * for reset completion status
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
14862306a36Sopenharmony_ci	err = caam_jr_flush(dev);
14962306a36Sopenharmony_ci	if (err)
15062306a36Sopenharmony_ci		return err;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* initiate reset */
15362306a36Sopenharmony_ci	wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
15462306a36Sopenharmony_ci	while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout)
15562306a36Sopenharmony_ci		cpu_relax();
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (timeout == 0) {
15862306a36Sopenharmony_ci		dev_err(dev, "failed to reset job ring %d\n", jrp->ridx);
15962306a36Sopenharmony_ci		return -EIO;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* unmask interrupts */
16362306a36Sopenharmony_ci	clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/*
16962306a36Sopenharmony_ci * Shutdown JobR independent of platform property code
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_cistatic int caam_jr_shutdown(struct device *dev)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
17462306a36Sopenharmony_ci	int ret;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	ret = caam_reset_hw_jr(dev);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	tasklet_kill(&jrp->irqtask);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return ret;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int caam_jr_remove(struct platform_device *pdev)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	int ret;
18662306a36Sopenharmony_ci	struct device *jrdev;
18762306a36Sopenharmony_ci	struct caam_drv_private_jr *jrpriv;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	jrdev = &pdev->dev;
19062306a36Sopenharmony_ci	jrpriv = dev_get_drvdata(jrdev);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (jrpriv->hwrng)
19362306a36Sopenharmony_ci		caam_rng_exit(jrdev->parent);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/*
19662306a36Sopenharmony_ci	 * Return EBUSY if job ring already allocated.
19762306a36Sopenharmony_ci	 */
19862306a36Sopenharmony_ci	if (atomic_read(&jrpriv->tfm_count)) {
19962306a36Sopenharmony_ci		dev_err(jrdev, "Device is busy\n");
20062306a36Sopenharmony_ci		return -EBUSY;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* Unregister JR-based RNG & crypto algorithms */
20462306a36Sopenharmony_ci	unregister_algs();
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Remove the node from Physical JobR list maintained by driver */
20762306a36Sopenharmony_ci	spin_lock(&driver_data.jr_alloc_lock);
20862306a36Sopenharmony_ci	list_del(&jrpriv->list_node);
20962306a36Sopenharmony_ci	spin_unlock(&driver_data.jr_alloc_lock);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* Release ring */
21262306a36Sopenharmony_ci	ret = caam_jr_shutdown(jrdev);
21362306a36Sopenharmony_ci	if (ret)
21462306a36Sopenharmony_ci		dev_err(jrdev, "Failed to shut down job ring\n");
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return ret;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic void caam_jr_platform_shutdown(struct platform_device *pdev)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	caam_jr_remove(pdev);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/* Main per-ring interrupt handler */
22562306a36Sopenharmony_cistatic irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct device *dev = st_dev;
22862306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
22962306a36Sopenharmony_ci	u32 irqstate;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/*
23262306a36Sopenharmony_ci	 * Check the output ring for ready responses, kick
23362306a36Sopenharmony_ci	 * tasklet if jobs done.
23462306a36Sopenharmony_ci	 */
23562306a36Sopenharmony_ci	irqstate = rd_reg32(&jrp->rregs->jrintstatus);
23662306a36Sopenharmony_ci	if (!(irqstate & JRINT_JR_INT))
23762306a36Sopenharmony_ci		return IRQ_NONE;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/*
24062306a36Sopenharmony_ci	 * If JobR error, we got more development work to do
24162306a36Sopenharmony_ci	 * Flag a bug now, but we really need to shut down and
24262306a36Sopenharmony_ci	 * restart the queue (and fix code).
24362306a36Sopenharmony_ci	 */
24462306a36Sopenharmony_ci	if (irqstate & JRINT_JR_ERROR) {
24562306a36Sopenharmony_ci		dev_err(dev, "job ring error: irqstate: %08x\n", irqstate);
24662306a36Sopenharmony_ci		BUG();
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* mask valid interrupts */
25062306a36Sopenharmony_ci	clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/* Have valid interrupt at this point, just ACK and trigger */
25362306a36Sopenharmony_ci	wr_reg32(&jrp->rregs->jrintstatus, irqstate);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	preempt_disable();
25662306a36Sopenharmony_ci	tasklet_schedule(&jrp->irqtask);
25762306a36Sopenharmony_ci	preempt_enable();
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return IRQ_HANDLED;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/* Deferred service handler, run as interrupt-fired tasklet */
26362306a36Sopenharmony_cistatic void caam_jr_dequeue(unsigned long devarg)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	int hw_idx, sw_idx, i, head, tail;
26662306a36Sopenharmony_ci	struct caam_jr_dequeue_params *params = (void *)devarg;
26762306a36Sopenharmony_ci	struct device *dev = params->dev;
26862306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
26962306a36Sopenharmony_ci	void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
27062306a36Sopenharmony_ci	u32 *userdesc, userstatus;
27162306a36Sopenharmony_ci	void *userarg;
27262306a36Sopenharmony_ci	u32 outring_used = 0;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	while (outring_used ||
27562306a36Sopenharmony_ci	       (outring_used = rd_reg32(&jrp->rregs->outring_used))) {
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci		head = READ_ONCE(jrp->head);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		sw_idx = tail = jrp->tail;
28062306a36Sopenharmony_ci		hw_idx = jrp->out_ring_read_index;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
28362306a36Sopenharmony_ci			sw_idx = (tail + i) & (JOBR_DEPTH - 1);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci			if (jr_outentry_desc(jrp->outring, hw_idx) ==
28662306a36Sopenharmony_ci			    caam_dma_to_cpu(jrp->entinfo[sw_idx].desc_addr_dma))
28762306a36Sopenharmony_ci				break; /* found */
28862306a36Sopenharmony_ci		}
28962306a36Sopenharmony_ci		/* we should never fail to find a matching descriptor */
29062306a36Sopenharmony_ci		BUG_ON(CIRC_CNT(head, tail + i, JOBR_DEPTH) <= 0);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		/* Unmap just-run descriptor so we can post-process */
29362306a36Sopenharmony_ci		dma_unmap_single(dev,
29462306a36Sopenharmony_ci				 caam_dma_to_cpu(jr_outentry_desc(jrp->outring,
29562306a36Sopenharmony_ci								  hw_idx)),
29662306a36Sopenharmony_ci				 jrp->entinfo[sw_idx].desc_size,
29762306a36Sopenharmony_ci				 DMA_TO_DEVICE);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		/* mark completed, avoid matching on a recycled desc addr */
30062306a36Sopenharmony_ci		jrp->entinfo[sw_idx].desc_addr_dma = 0;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		/* Stash callback params */
30362306a36Sopenharmony_ci		usercall = jrp->entinfo[sw_idx].callbk;
30462306a36Sopenharmony_ci		userarg = jrp->entinfo[sw_idx].cbkarg;
30562306a36Sopenharmony_ci		userdesc = jrp->entinfo[sw_idx].desc_addr_virt;
30662306a36Sopenharmony_ci		userstatus = caam32_to_cpu(jr_outentry_jrstatus(jrp->outring,
30762306a36Sopenharmony_ci								hw_idx));
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		/*
31062306a36Sopenharmony_ci		 * Make sure all information from the job has been obtained
31162306a36Sopenharmony_ci		 * before telling CAAM that the job has been removed from the
31262306a36Sopenharmony_ci		 * output ring.
31362306a36Sopenharmony_ci		 */
31462306a36Sopenharmony_ci		mb();
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		/* set done */
31762306a36Sopenharmony_ci		wr_reg32(&jrp->rregs->outring_rmvd, 1);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) &
32062306a36Sopenharmony_ci					   (JOBR_DEPTH - 1);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		/*
32362306a36Sopenharmony_ci		 * if this job completed out-of-order, do not increment
32462306a36Sopenharmony_ci		 * the tail.  Otherwise, increment tail by 1 plus the
32562306a36Sopenharmony_ci		 * number of subsequent jobs already completed out-of-order
32662306a36Sopenharmony_ci		 */
32762306a36Sopenharmony_ci		if (sw_idx == tail) {
32862306a36Sopenharmony_ci			do {
32962306a36Sopenharmony_ci				tail = (tail + 1) & (JOBR_DEPTH - 1);
33062306a36Sopenharmony_ci			} while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 &&
33162306a36Sopenharmony_ci				 jrp->entinfo[tail].desc_addr_dma == 0);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci			jrp->tail = tail;
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		/* Finally, execute user's callback */
33762306a36Sopenharmony_ci		usercall(dev, userdesc, userstatus, userarg);
33862306a36Sopenharmony_ci		outring_used--;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (params->enable_itr)
34262306a36Sopenharmony_ci		/* reenable / unmask IRQs */
34362306a36Sopenharmony_ci		clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/**
34762306a36Sopenharmony_ci * caam_jr_alloc() - Alloc a job ring for someone to use as needed.
34862306a36Sopenharmony_ci *
34962306a36Sopenharmony_ci * returns :  pointer to the newly allocated physical
35062306a36Sopenharmony_ci *	      JobR dev can be written to if successful.
35162306a36Sopenharmony_ci **/
35262306a36Sopenharmony_cistruct device *caam_jr_alloc(void)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL;
35562306a36Sopenharmony_ci	struct device *dev = ERR_PTR(-ENODEV);
35662306a36Sopenharmony_ci	int min_tfm_cnt	= INT_MAX;
35762306a36Sopenharmony_ci	int tfm_cnt;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	spin_lock(&driver_data.jr_alloc_lock);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (list_empty(&driver_data.jr_list)) {
36262306a36Sopenharmony_ci		spin_unlock(&driver_data.jr_alloc_lock);
36362306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) {
36762306a36Sopenharmony_ci		tfm_cnt = atomic_read(&jrpriv->tfm_count);
36862306a36Sopenharmony_ci		if (tfm_cnt < min_tfm_cnt) {
36962306a36Sopenharmony_ci			min_tfm_cnt = tfm_cnt;
37062306a36Sopenharmony_ci			min_jrpriv = jrpriv;
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci		if (!min_tfm_cnt)
37362306a36Sopenharmony_ci			break;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (min_jrpriv) {
37762306a36Sopenharmony_ci		atomic_inc(&min_jrpriv->tfm_count);
37862306a36Sopenharmony_ci		dev = min_jrpriv->dev;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	spin_unlock(&driver_data.jr_alloc_lock);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return dev;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ciEXPORT_SYMBOL(caam_jr_alloc);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * caam_jr_free() - Free the Job Ring
38862306a36Sopenharmony_ci * @rdev:      points to the dev that identifies the Job ring to
38962306a36Sopenharmony_ci *             be released.
39062306a36Sopenharmony_ci **/
39162306a36Sopenharmony_civoid caam_jr_free(struct device *rdev)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	atomic_dec(&jrpriv->tfm_count);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ciEXPORT_SYMBOL(caam_jr_free);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/**
40062306a36Sopenharmony_ci * caam_jr_enqueue() - Enqueue a job descriptor head. Returns -EINPROGRESS
40162306a36Sopenharmony_ci * if OK, -ENOSPC if the queue is full, -EIO if it cannot map the caller's
40262306a36Sopenharmony_ci * descriptor.
40362306a36Sopenharmony_ci * @dev:  struct device of the job ring to be used
40462306a36Sopenharmony_ci * @desc: points to a job descriptor that execute our request. All
40562306a36Sopenharmony_ci *        descriptors (and all referenced data) must be in a DMAable
40662306a36Sopenharmony_ci *        region, and all data references must be physical addresses
40762306a36Sopenharmony_ci *        accessible to CAAM (i.e. within a PAMU window granted
40862306a36Sopenharmony_ci *        to it).
40962306a36Sopenharmony_ci * @cbk:  pointer to a callback function to be invoked upon completion
41062306a36Sopenharmony_ci *        of this request. This has the form:
41162306a36Sopenharmony_ci *        callback(struct device *dev, u32 *desc, u32 stat, void *arg)
41262306a36Sopenharmony_ci *        where:
41362306a36Sopenharmony_ci *        dev:     contains the job ring device that processed this
41462306a36Sopenharmony_ci *                 response.
41562306a36Sopenharmony_ci *        desc:    descriptor that initiated the request, same as
41662306a36Sopenharmony_ci *                 "desc" being argued to caam_jr_enqueue().
41762306a36Sopenharmony_ci *        status:  untranslated status received from CAAM. See the
41862306a36Sopenharmony_ci *                 reference manual for a detailed description of
41962306a36Sopenharmony_ci *                 error meaning, or see the JRSTA definitions in the
42062306a36Sopenharmony_ci *                 register header file
42162306a36Sopenharmony_ci *        areq:    optional pointer to an argument passed with the
42262306a36Sopenharmony_ci *                 original request
42362306a36Sopenharmony_ci * @areq: optional pointer to a user argument for use at callback
42462306a36Sopenharmony_ci *        time.
42562306a36Sopenharmony_ci **/
42662306a36Sopenharmony_ciint caam_jr_enqueue(struct device *dev, u32 *desc,
42762306a36Sopenharmony_ci		    void (*cbk)(struct device *dev, u32 *desc,
42862306a36Sopenharmony_ci				u32 status, void *areq),
42962306a36Sopenharmony_ci		    void *areq)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
43262306a36Sopenharmony_ci	struct caam_jrentry_info *head_entry;
43362306a36Sopenharmony_ci	int head, tail, desc_size;
43462306a36Sopenharmony_ci	dma_addr_t desc_dma;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	desc_size = (caam32_to_cpu(*desc) & HDR_JD_LENGTH_MASK) * sizeof(u32);
43762306a36Sopenharmony_ci	desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE);
43862306a36Sopenharmony_ci	if (dma_mapping_error(dev, desc_dma)) {
43962306a36Sopenharmony_ci		dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n");
44062306a36Sopenharmony_ci		return -EIO;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	spin_lock_bh(&jrp->inplock);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	head = jrp->head;
44662306a36Sopenharmony_ci	tail = READ_ONCE(jrp->tail);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (!jrp->inpring_avail ||
44962306a36Sopenharmony_ci	    CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
45062306a36Sopenharmony_ci		spin_unlock_bh(&jrp->inplock);
45162306a36Sopenharmony_ci		dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
45262306a36Sopenharmony_ci		return -ENOSPC;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	head_entry = &jrp->entinfo[head];
45662306a36Sopenharmony_ci	head_entry->desc_addr_virt = desc;
45762306a36Sopenharmony_ci	head_entry->desc_size = desc_size;
45862306a36Sopenharmony_ci	head_entry->callbk = (void *)cbk;
45962306a36Sopenharmony_ci	head_entry->cbkarg = areq;
46062306a36Sopenharmony_ci	head_entry->desc_addr_dma = desc_dma;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	jr_inpentry_set(jrp->inpring, head, cpu_to_caam_dma(desc_dma));
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/*
46562306a36Sopenharmony_ci	 * Guarantee that the descriptor's DMA address has been written to
46662306a36Sopenharmony_ci	 * the next slot in the ring before the write index is updated, since
46762306a36Sopenharmony_ci	 * other cores may update this index independently.
46862306a36Sopenharmony_ci	 *
46962306a36Sopenharmony_ci	 * Under heavy DDR load, smp_wmb() or dma_wmb() fail to make the input
47062306a36Sopenharmony_ci	 * ring be updated before the CAAM starts reading it. So, CAAM will
47162306a36Sopenharmony_ci	 * process, again, an old descriptor address and will put it in the
47262306a36Sopenharmony_ci	 * output ring. This will make caam_jr_dequeue() to fail, since this
47362306a36Sopenharmony_ci	 * old descriptor is not in the software ring.
47462306a36Sopenharmony_ci	 * To fix this, use wmb() which works on the full system instead of
47562306a36Sopenharmony_ci	 * inner/outer shareable domains.
47662306a36Sopenharmony_ci	 */
47762306a36Sopenharmony_ci	wmb();
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	jrp->head = (head + 1) & (JOBR_DEPTH - 1);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/*
48262306a36Sopenharmony_ci	 * Ensure that all job information has been written before
48362306a36Sopenharmony_ci	 * notifying CAAM that a new job was added to the input ring
48462306a36Sopenharmony_ci	 * using a memory barrier. The wr_reg32() uses api iowrite32()
48562306a36Sopenharmony_ci	 * to do the register write. iowrite32() issues a memory barrier
48662306a36Sopenharmony_ci	 * before the write operation.
48762306a36Sopenharmony_ci	 */
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	wr_reg32(&jrp->rregs->inpring_jobadd, 1);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	jrp->inpring_avail--;
49262306a36Sopenharmony_ci	if (!jrp->inpring_avail)
49362306a36Sopenharmony_ci		jrp->inpring_avail = rd_reg32(&jrp->rregs->inpring_avail);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	spin_unlock_bh(&jrp->inplock);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return -EINPROGRESS;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ciEXPORT_SYMBOL(caam_jr_enqueue);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr,
50262306a36Sopenharmony_ci			    dma_addr_t outbusaddr)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
50762306a36Sopenharmony_ci	wr_reg64(&jrp->rregs->outring_base, outbusaddr);
50862306a36Sopenharmony_ci	wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
50962306a36Sopenharmony_ci	wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Select interrupt coalescing parameters */
51262306a36Sopenharmony_ci	clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
51362306a36Sopenharmony_ci		      (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
51462306a36Sopenharmony_ci		      (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic void caam_jr_reset_index(struct caam_drv_private_jr *jrp)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	jrp->out_ring_read_index = 0;
52062306a36Sopenharmony_ci	jrp->head = 0;
52162306a36Sopenharmony_ci	jrp->tail = 0;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/*
52562306a36Sopenharmony_ci * Init JobR independent of platform property detection
52662306a36Sopenharmony_ci */
52762306a36Sopenharmony_cistatic int caam_jr_init(struct device *dev)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp;
53062306a36Sopenharmony_ci	dma_addr_t inpbusaddr, outbusaddr;
53162306a36Sopenharmony_ci	int i, error;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	jrp = dev_get_drvdata(dev);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	error = caam_reset_hw_jr(dev);
53662306a36Sopenharmony_ci	if (error)
53762306a36Sopenharmony_ci		return error;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	jrp->inpring = dmam_alloc_coherent(dev, SIZEOF_JR_INPENTRY *
54062306a36Sopenharmony_ci					   JOBR_DEPTH, &inpbusaddr,
54162306a36Sopenharmony_ci					   GFP_KERNEL);
54262306a36Sopenharmony_ci	if (!jrp->inpring)
54362306a36Sopenharmony_ci		return -ENOMEM;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	jrp->outring = dmam_alloc_coherent(dev, SIZEOF_JR_OUTENTRY *
54662306a36Sopenharmony_ci					   JOBR_DEPTH, &outbusaddr,
54762306a36Sopenharmony_ci					   GFP_KERNEL);
54862306a36Sopenharmony_ci	if (!jrp->outring)
54962306a36Sopenharmony_ci		return -ENOMEM;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	jrp->entinfo = devm_kcalloc(dev, JOBR_DEPTH, sizeof(*jrp->entinfo),
55262306a36Sopenharmony_ci				    GFP_KERNEL);
55362306a36Sopenharmony_ci	if (!jrp->entinfo)
55462306a36Sopenharmony_ci		return -ENOMEM;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	for (i = 0; i < JOBR_DEPTH; i++)
55762306a36Sopenharmony_ci		jrp->entinfo[i].desc_addr_dma = !0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* Setup rings */
56062306a36Sopenharmony_ci	caam_jr_reset_index(jrp);
56162306a36Sopenharmony_ci	jrp->inpring_avail = JOBR_DEPTH;
56262306a36Sopenharmony_ci	caam_jr_init_hw(dev, inpbusaddr, outbusaddr);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	spin_lock_init(&jrp->inplock);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	jrp->tasklet_params.dev = dev;
56762306a36Sopenharmony_ci	jrp->tasklet_params.enable_itr = 1;
56862306a36Sopenharmony_ci	tasklet_init(&jrp->irqtask, caam_jr_dequeue,
56962306a36Sopenharmony_ci		     (unsigned long)&jrp->tasklet_params);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/* Connect job ring interrupt handler. */
57262306a36Sopenharmony_ci	error = devm_request_irq(dev, jrp->irq, caam_jr_interrupt, IRQF_SHARED,
57362306a36Sopenharmony_ci				 dev_name(dev), dev);
57462306a36Sopenharmony_ci	if (error) {
57562306a36Sopenharmony_ci		dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
57662306a36Sopenharmony_ci			jrp->ridx, jrp->irq);
57762306a36Sopenharmony_ci		tasklet_kill(&jrp->irqtask);
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return error;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic void caam_jr_irq_dispose_mapping(void *data)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	irq_dispose_mapping((unsigned long)data);
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci/*
58962306a36Sopenharmony_ci * Probe routine for each detected JobR subsystem.
59062306a36Sopenharmony_ci */
59162306a36Sopenharmony_cistatic int caam_jr_probe(struct platform_device *pdev)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct device *jrdev;
59462306a36Sopenharmony_ci	struct device_node *nprop;
59562306a36Sopenharmony_ci	struct caam_job_ring __iomem *ctrl;
59662306a36Sopenharmony_ci	struct caam_drv_private_jr *jrpriv;
59762306a36Sopenharmony_ci	static int total_jobrs;
59862306a36Sopenharmony_ci	struct resource *r;
59962306a36Sopenharmony_ci	int error;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	jrdev = &pdev->dev;
60262306a36Sopenharmony_ci	jrpriv = devm_kzalloc(jrdev, sizeof(*jrpriv), GFP_KERNEL);
60362306a36Sopenharmony_ci	if (!jrpriv)
60462306a36Sopenharmony_ci		return -ENOMEM;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	dev_set_drvdata(jrdev, jrpriv);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* save ring identity relative to detection */
60962306a36Sopenharmony_ci	jrpriv->ridx = total_jobrs++;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	nprop = pdev->dev.of_node;
61262306a36Sopenharmony_ci	/* Get configuration properties from device tree */
61362306a36Sopenharmony_ci	/* First, get register page */
61462306a36Sopenharmony_ci	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
61562306a36Sopenharmony_ci	if (!r) {
61662306a36Sopenharmony_ci		dev_err(jrdev, "platform_get_resource() failed\n");
61762306a36Sopenharmony_ci		return -ENOMEM;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	ctrl = devm_ioremap(jrdev, r->start, resource_size(r));
62162306a36Sopenharmony_ci	if (!ctrl) {
62262306a36Sopenharmony_ci		dev_err(jrdev, "devm_ioremap() failed\n");
62362306a36Sopenharmony_ci		return -ENOMEM;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	jrpriv->rregs = (struct caam_job_ring __iomem __force *)ctrl;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	error = dma_set_mask_and_coherent(jrdev, caam_get_dma_mask(jrdev));
62962306a36Sopenharmony_ci	if (error) {
63062306a36Sopenharmony_ci		dev_err(jrdev, "dma_set_mask_and_coherent failed (%d)\n",
63162306a36Sopenharmony_ci			error);
63262306a36Sopenharmony_ci		return error;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/* Initialize crypto engine */
63662306a36Sopenharmony_ci	jrpriv->engine = crypto_engine_alloc_init_and_set(jrdev, true, NULL,
63762306a36Sopenharmony_ci							  false,
63862306a36Sopenharmony_ci							  CRYPTO_ENGINE_MAX_QLEN);
63962306a36Sopenharmony_ci	if (!jrpriv->engine) {
64062306a36Sopenharmony_ci		dev_err(jrdev, "Could not init crypto-engine\n");
64162306a36Sopenharmony_ci		return -ENOMEM;
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	error = devm_add_action_or_reset(jrdev, caam_jr_crypto_engine_exit,
64562306a36Sopenharmony_ci					 jrdev);
64662306a36Sopenharmony_ci	if (error)
64762306a36Sopenharmony_ci		return error;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/* Start crypto engine */
65062306a36Sopenharmony_ci	error = crypto_engine_start(jrpriv->engine);
65162306a36Sopenharmony_ci	if (error) {
65262306a36Sopenharmony_ci		dev_err(jrdev, "Could not start crypto-engine\n");
65362306a36Sopenharmony_ci		return error;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/* Identify the interrupt */
65762306a36Sopenharmony_ci	jrpriv->irq = irq_of_parse_and_map(nprop, 0);
65862306a36Sopenharmony_ci	if (!jrpriv->irq) {
65962306a36Sopenharmony_ci		dev_err(jrdev, "irq_of_parse_and_map failed\n");
66062306a36Sopenharmony_ci		return -EINVAL;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	error = devm_add_action_or_reset(jrdev, caam_jr_irq_dispose_mapping,
66462306a36Sopenharmony_ci					 (void *)(unsigned long)jrpriv->irq);
66562306a36Sopenharmony_ci	if (error)
66662306a36Sopenharmony_ci		return error;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Now do the platform independent part */
66962306a36Sopenharmony_ci	error = caam_jr_init(jrdev); /* now turn on hardware */
67062306a36Sopenharmony_ci	if (error)
67162306a36Sopenharmony_ci		return error;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	jrpriv->dev = jrdev;
67462306a36Sopenharmony_ci	spin_lock(&driver_data.jr_alloc_lock);
67562306a36Sopenharmony_ci	list_add_tail(&jrpriv->list_node, &driver_data.jr_list);
67662306a36Sopenharmony_ci	spin_unlock(&driver_data.jr_alloc_lock);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	atomic_set(&jrpriv->tfm_count, 0);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	device_init_wakeup(&pdev->dev, 1);
68162306a36Sopenharmony_ci	device_set_wakeup_enable(&pdev->dev, false);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	register_algs(jrpriv, jrdev->parent);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	return 0;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic void caam_jr_get_hw_state(struct device *dev)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	jrp->state.inpbusaddr = rd_reg64(&jrp->rregs->inpring_base);
69362306a36Sopenharmony_ci	jrp->state.outbusaddr = rd_reg64(&jrp->rregs->outring_base);
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic int caam_jr_suspend(struct device *dev)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
69962306a36Sopenharmony_ci	struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
70062306a36Sopenharmony_ci	struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
70162306a36Sopenharmony_ci	struct caam_jr_dequeue_params suspend_params = {
70262306a36Sopenharmony_ci		.dev = dev,
70362306a36Sopenharmony_ci		.enable_itr = 0,
70462306a36Sopenharmony_ci	};
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Remove the node from Physical JobR list maintained by driver */
70762306a36Sopenharmony_ci	spin_lock(&driver_data.jr_alloc_lock);
70862306a36Sopenharmony_ci	list_del(&jrpriv->list_node);
70962306a36Sopenharmony_ci	spin_unlock(&driver_data.jr_alloc_lock);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (jrpriv->hwrng)
71262306a36Sopenharmony_ci		caam_rng_exit(dev->parent);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (ctrlpriv->caam_off_during_pm) {
71562306a36Sopenharmony_ci		int err;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		tasklet_disable(&jrpriv->irqtask);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci		/* mask itr to call flush */
72062306a36Sopenharmony_ci		clrsetbits_32(&jrpriv->rregs->rconfig_lo, 0, JRCFG_IMSK);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		/* Invalid job in process */
72362306a36Sopenharmony_ci		err = caam_jr_flush(dev);
72462306a36Sopenharmony_ci		if (err) {
72562306a36Sopenharmony_ci			dev_err(dev, "Failed to flush\n");
72662306a36Sopenharmony_ci			return err;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		/* Dequeing jobs flushed */
73062306a36Sopenharmony_ci		caam_jr_dequeue((unsigned long)&suspend_params);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		/* Save state */
73362306a36Sopenharmony_ci		caam_jr_get_hw_state(dev);
73462306a36Sopenharmony_ci	} else if (device_may_wakeup(&pdev->dev)) {
73562306a36Sopenharmony_ci		enable_irq_wake(jrpriv->irq);
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return 0;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic int caam_jr_resume(struct device *dev)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
74462306a36Sopenharmony_ci	struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
74562306a36Sopenharmony_ci	struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (ctrlpriv->caam_off_during_pm) {
74862306a36Sopenharmony_ci		u64 inp_addr;
74962306a36Sopenharmony_ci		int err;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		/*
75262306a36Sopenharmony_ci		 * Check if the CAAM has been resetted checking the address of
75362306a36Sopenharmony_ci		 * the input ring
75462306a36Sopenharmony_ci		 */
75562306a36Sopenharmony_ci		inp_addr = rd_reg64(&jrpriv->rregs->inpring_base);
75662306a36Sopenharmony_ci		if (inp_addr != 0) {
75762306a36Sopenharmony_ci			/* JR still has some configuration */
75862306a36Sopenharmony_ci			if (inp_addr == jrpriv->state.inpbusaddr) {
75962306a36Sopenharmony_ci				/* JR has not been resetted */
76062306a36Sopenharmony_ci				err = caam_jr_restart_processing(dev);
76162306a36Sopenharmony_ci				if (err) {
76262306a36Sopenharmony_ci					dev_err(dev,
76362306a36Sopenharmony_ci						"Restart processing failed\n");
76462306a36Sopenharmony_ci					return err;
76562306a36Sopenharmony_ci				}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci				tasklet_enable(&jrpriv->irqtask);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci				clrsetbits_32(&jrpriv->rregs->rconfig_lo,
77062306a36Sopenharmony_ci					      JRCFG_IMSK, 0);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci				goto add_jr;
77362306a36Sopenharmony_ci			} else if (ctrlpriv->optee_en) {
77462306a36Sopenharmony_ci				/* JR has been used by OPTEE, reset it */
77562306a36Sopenharmony_ci				err = caam_reset_hw_jr(dev);
77662306a36Sopenharmony_ci				if (err) {
77762306a36Sopenharmony_ci					dev_err(dev, "Failed to reset JR\n");
77862306a36Sopenharmony_ci					return err;
77962306a36Sopenharmony_ci				}
78062306a36Sopenharmony_ci			} else {
78162306a36Sopenharmony_ci				/* No explanation, return error */
78262306a36Sopenharmony_ci				return -EIO;
78362306a36Sopenharmony_ci			}
78462306a36Sopenharmony_ci		}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		caam_jr_reset_index(jrpriv);
78762306a36Sopenharmony_ci		caam_jr_init_hw(dev, jrpriv->state.inpbusaddr,
78862306a36Sopenharmony_ci				jrpriv->state.outbusaddr);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		tasklet_enable(&jrpriv->irqtask);
79162306a36Sopenharmony_ci	} else if (device_may_wakeup(&pdev->dev)) {
79262306a36Sopenharmony_ci		disable_irq_wake(jrpriv->irq);
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ciadd_jr:
79662306a36Sopenharmony_ci	spin_lock(&driver_data.jr_alloc_lock);
79762306a36Sopenharmony_ci	list_add_tail(&jrpriv->list_node, &driver_data.jr_list);
79862306a36Sopenharmony_ci	spin_unlock(&driver_data.jr_alloc_lock);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if (jrpriv->hwrng)
80162306a36Sopenharmony_ci		jrpriv->hwrng = !caam_rng_init(dev->parent);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	return 0;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, caam_jr_resume);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic const struct of_device_id caam_jr_match[] = {
80962306a36Sopenharmony_ci	{
81062306a36Sopenharmony_ci		.compatible = "fsl,sec-v4.0-job-ring",
81162306a36Sopenharmony_ci	},
81262306a36Sopenharmony_ci	{
81362306a36Sopenharmony_ci		.compatible = "fsl,sec4.0-job-ring",
81462306a36Sopenharmony_ci	},
81562306a36Sopenharmony_ci	{},
81662306a36Sopenharmony_ci};
81762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, caam_jr_match);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic struct platform_driver caam_jr_driver = {
82062306a36Sopenharmony_ci	.driver = {
82162306a36Sopenharmony_ci		.name = "caam_jr",
82262306a36Sopenharmony_ci		.of_match_table = caam_jr_match,
82362306a36Sopenharmony_ci		.pm = pm_ptr(&caam_jr_pm_ops),
82462306a36Sopenharmony_ci	},
82562306a36Sopenharmony_ci	.probe       = caam_jr_probe,
82662306a36Sopenharmony_ci	.remove      = caam_jr_remove,
82762306a36Sopenharmony_ci	.shutdown    = caam_jr_platform_shutdown,
82862306a36Sopenharmony_ci};
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic int __init jr_driver_init(void)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	spin_lock_init(&driver_data.jr_alloc_lock);
83362306a36Sopenharmony_ci	INIT_LIST_HEAD(&driver_data.jr_list);
83462306a36Sopenharmony_ci	return platform_driver_register(&caam_jr_driver);
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic void __exit jr_driver_exit(void)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	platform_driver_unregister(&caam_jr_driver);
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cimodule_init(jr_driver_init);
84362306a36Sopenharmony_cimodule_exit(jr_driver_exit);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
84662306a36Sopenharmony_ciMODULE_DESCRIPTION("FSL CAAM JR request backend");
84762306a36Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor - NMG/STC");
848