Commit 554c42b4 authored by Corentin Labbe's avatar Corentin Labbe Committed by Herbert Xu
Browse files

crypto: sun4i-ss - enable pm_runtime



This patch enables power management on the Security System.
sun4i-ss now depends on PM because it simplify code and prevent some ifdef.
But this is not a problem since arch maintainer want ARCH_SUNXI to
depend on PM in the future.

Signed-off-by: default avatarCorentin Labbe <clabbe.montjoie@gmail.com>
Acked-by: default avatarMaxime Ripard <mripard@kernel.org>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 70dd444a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -660,6 +660,7 @@ config CRYPTO_DEV_IMGTEC_HASH
config CRYPTO_DEV_SUN4I_SS
	tristate "Support for Allwinner Security System cryptographic accelerator"
	depends on ARCH_SUNXI && !64BIT
	depends on PM
	select CRYPTO_MD5
	select CRYPTO_SHA1
	select CRYPTO_AES
+10 −0
Original line number Diff line number Diff line
@@ -480,6 +480,7 @@ int sun4i_ss_cipher_init(struct crypto_tfm *tfm)
	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
	struct sun4i_ss_alg_template *algt;
	const char *name = crypto_tfm_alg_name(tfm);
	int err;

	memset(op, 0, sizeof(struct sun4i_tfm_ctx));

@@ -497,13 +498,22 @@ int sun4i_ss_cipher_init(struct crypto_tfm *tfm)
		return PTR_ERR(op->fallback_tfm);
	}

	err = pm_runtime_get_sync(op->ss->dev);
	if (err < 0)
		goto error_pm;

	return 0;
error_pm:
	crypto_free_sync_skcipher(op->fallback_tfm);
	return err;
}

void sun4i_ss_cipher_exit(struct crypto_tfm *tfm)
{
	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);

	crypto_free_sync_skcipher(op->fallback_tfm);
	pm_runtime_put(op->ss->dev);
}

/* check and set the AES key, prepare the mode to be used */
+64 −18
Original line number Diff line number Diff line
@@ -44,7 +44,8 @@ static struct sun4i_ss_alg_template ss_algs[] = {
				.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
				.cra_ctxsize = sizeof(struct sun4i_req_ctx),
				.cra_module = THIS_MODULE,
				.cra_init = sun4i_hash_crainit
				.cra_init = sun4i_hash_crainit,
				.cra_exit = sun4i_hash_craexit,
			}
		}
	}
@@ -70,7 +71,8 @@ static struct sun4i_ss_alg_template ss_algs[] = {
				.cra_blocksize = SHA1_BLOCK_SIZE,
				.cra_ctxsize = sizeof(struct sun4i_req_ctx),
				.cra_module = THIS_MODULE,
				.cra_init = sun4i_hash_crainit
				.cra_init = sun4i_hash_crainit,
				.cra_exit = sun4i_hash_craexit,
			}
		}
	}
@@ -223,17 +225,26 @@ static struct sun4i_ss_alg_template ss_algs[] = {
#endif
};

static void sun4i_ss_disable(struct sun4i_ss_ctx *ss)
/*
 * Power management strategy: The device is suspended unless a TFM exists for
 * one of the algorithms proposed by this driver.
 */
static int sun4i_ss_pm_suspend(struct device *dev)
{
	struct sun4i_ss_ctx *ss = dev_get_drvdata(dev);

	if (ss->reset)
		reset_control_assert(ss->reset);

	clk_disable_unprepare(ss->ssclk);
	clk_disable_unprepare(ss->busclk);
	return 0;
}

static int sun4i_ss_enable(struct sun4i_ss_ctx *ss)
static int sun4i_ss_pm_resume(struct device *dev)
{
	struct sun4i_ss_ctx *ss = dev_get_drvdata(dev);

	int err;

	err = clk_prepare_enable(ss->busclk);
@@ -258,10 +269,38 @@ static int sun4i_ss_enable(struct sun4i_ss_ctx *ss)

	return err;
err_enable:
	sun4i_ss_disable(ss);
	sun4i_ss_pm_suspend(dev);
	return err;
}

const struct dev_pm_ops sun4i_ss_pm_ops = {
	SET_RUNTIME_PM_OPS(sun4i_ss_pm_suspend, sun4i_ss_pm_resume, NULL)
};

/*
 * When power management is enabled, this function enables the PM and set the
 * device as suspended
 * When power management is disabled, this function just enables the device
 */
static int sun4i_ss_pm_init(struct sun4i_ss_ctx *ss)
{
	int err;

	pm_runtime_use_autosuspend(ss->dev);
	pm_runtime_set_autosuspend_delay(ss->dev, 2000);

	err = pm_runtime_set_suspended(ss->dev);
	if (err)
		return err;
	pm_runtime_enable(ss->dev);
	return err;
}

static void sun4i_ss_pm_exit(struct sun4i_ss_ctx *ss)
{
	pm_runtime_disable(ss->dev);
}

static int sun4i_ss_probe(struct platform_device *pdev)
{
	u32 v;
@@ -308,10 +347,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
		ss->reset = NULL;
	}

	err = sun4i_ss_enable(ss);
	if (err)
		goto error_enable;

	/*
	 * Check that clock have the correct rates given in the datasheet
	 * Try to set the clock to the maximum allowed
@@ -319,7 +354,7 @@ static int sun4i_ss_probe(struct platform_device *pdev)
	err = clk_set_rate(ss->ssclk, cr_mod);
	if (err) {
		dev_err(&pdev->dev, "Cannot set clock rate to ssclk\n");
		goto error_enable;
		return err;
	}

	/*
@@ -347,12 +382,26 @@ static int sun4i_ss_probe(struct platform_device *pdev)
		dev_warn(&pdev->dev, "Clock ss is at %lu (%lu MHz) (must be <= %lu)\n",
			 cr, cr / 1000000, cr_mod);

	ss->dev = &pdev->dev;
	platform_set_drvdata(pdev, ss);

	spin_lock_init(&ss->slock);

	err = sun4i_ss_pm_init(ss);
	if (err)
		return err;

	/*
	 * Datasheet named it "Die Bonding ID"
	 * I expect to be a sort of Security System Revision number.
	 * Since the A80 seems to have an other version of SS
	 * this info could be useful
	 */

	err = pm_runtime_get_sync(ss->dev);
	if (err < 0)
		goto error_pm;

	writel(SS_ENABLED, ss->base + SS_CTL);
	v = readl(ss->base + SS_CTL);
	v >>= 16;
@@ -360,9 +409,7 @@ static int sun4i_ss_probe(struct platform_device *pdev)
	dev_info(&pdev->dev, "Die ID %d\n", v);
	writel(0, ss->base + SS_CTL);

	ss->dev = &pdev->dev;

	spin_lock_init(&ss->slock);
	pm_runtime_put_sync(ss->dev);

	for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
		ss_algs[i].ss = ss;
@@ -392,7 +439,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
			break;
		}
	}
	platform_set_drvdata(pdev, ss);
	return 0;
error_alg:
	i--;
@@ -409,8 +455,8 @@ error_alg:
			break;
		}
	}
error_enable:
	sun4i_ss_disable(ss);
error_pm:
	sun4i_ss_pm_exit(ss);
	return err;
}

@@ -433,8 +479,7 @@ static int sun4i_ss_remove(struct platform_device *pdev)
		}
	}

	writel(0, ss->base + SS_CTL);
	sun4i_ss_disable(ss);
	sun4i_ss_pm_exit(ss);
	return 0;
}

@@ -449,6 +494,7 @@ static struct platform_driver sun4i_ss_driver = {
	.remove         = sun4i_ss_remove,
	.driver         = {
		.name           = "sun4i-ss",
		.pm		= &sun4i_ss_pm_ops,
		.of_match_table	= a20ss_crypto_of_match_table,
	},
};
+12 −0
Original line number Diff line number Diff line
@@ -19,17 +19,29 @@ int sun4i_hash_crainit(struct crypto_tfm *tfm)
	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
	struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
	struct sun4i_ss_alg_template *algt;
	int err;

	memset(op, 0, sizeof(struct sun4i_tfm_ctx));

	algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash);
	op->ss = algt->ss;

	err = pm_runtime_get_sync(op->ss->dev);
	if (err < 0)
		return err;

	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
				 sizeof(struct sun4i_req_ctx));
	return 0;
}

void sun4i_hash_craexit(struct crypto_tfm *tfm)
{
	struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);

	pm_runtime_put(op->ss->dev);
}

/* sun4i_hash_init: initialize request context */
int sun4i_hash_init(struct ahash_request *areq)
{
+8 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
{
	struct sun4i_ss_alg_template *algt;
	struct rng_alg *alg = crypto_rng_alg(tfm);
	int i;
	int i, err;
	u32 v;
	u32 *data = (u32 *)dst;
	const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
@@ -28,6 +28,10 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
	algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
	ss = algt->ss;

	err = pm_runtime_get_sync(ss->dev);
	if (err < 0)
		return err;

	spin_lock_bh(&ss->slock);

	writel(mode, ss->base + SS_CTL);
@@ -52,5 +56,8 @@ int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,

	writel(0, ss->base + SS_CTL);
	spin_unlock_bh(&ss->slock);

	pm_runtime_put(ss->dev);

	return 0;
}
Loading