481 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) STMicroelectronics SA 20174 * Author: Fabien Dessenne <fabien.dessenne@st.com>5 */6 7#include <linux/bitrev.h>8#include <linux/clk.h>9#include <linux/crc32.h>10#include <linux/crc32poly.h>11#include <linux/io.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/mod_devicetable.h>15#include <linux/platform_device.h>16#include <linux/pm_runtime.h>17 18#include <crypto/internal/hash.h>19 20#include <linux/unaligned.h>21 22#define DRIVER_NAME "stm32-crc32"23#define CHKSUM_DIGEST_SIZE 424#define CHKSUM_BLOCK_SIZE 125 26/* Registers */27#define CRC_DR 0x0000000028#define CRC_CR 0x0000000829#define CRC_INIT 0x0000001030#define CRC_POL 0x0000001431 32/* Registers values */33#define CRC_CR_RESET BIT(0)34#define CRC_CR_REV_IN_WORD (BIT(6) | BIT(5))35#define CRC_CR_REV_IN_BYTE BIT(5)36#define CRC_CR_REV_OUT BIT(7)37#define CRC32C_INIT_DEFAULT 0xFFFFFFFF38 39#define CRC_AUTOSUSPEND_DELAY 5040 41static unsigned int burst_size;42module_param(burst_size, uint, 0644);43MODULE_PARM_DESC(burst_size, "Select burst byte size (0 unlimited)");44 45struct stm32_crc {46 struct list_head list;47 struct device *dev;48 void __iomem *regs;49 struct clk *clk;50 spinlock_t lock;51};52 53struct stm32_crc_list {54 struct list_head dev_list;55 spinlock_t lock; /* protect dev_list */56};57 58static struct stm32_crc_list crc_list = {59 .dev_list = LIST_HEAD_INIT(crc_list.dev_list),60 .lock = __SPIN_LOCK_UNLOCKED(crc_list.lock),61};62 63struct stm32_crc_ctx {64 u32 key;65 u32 poly;66};67 68struct stm32_crc_desc_ctx {69 u32 partial; /* crc32c: partial in first 4 bytes of that struct */70};71 72static int stm32_crc32_cra_init(struct crypto_tfm *tfm)73{74 struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm);75 76 mctx->key = 0;77 mctx->poly = CRC32_POLY_LE;78 return 0;79}80 81static int stm32_crc32c_cra_init(struct crypto_tfm *tfm)82{83 struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm);84 85 mctx->key = CRC32C_INIT_DEFAULT;86 mctx->poly = CRC32C_POLY_LE;87 return 0;88}89 90static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key,91 unsigned int keylen)92{93 struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm);94 95 if (keylen != sizeof(u32))96 return -EINVAL;97 98 mctx->key = get_unaligned_le32(key);99 return 0;100}101 102static struct stm32_crc *stm32_crc_get_next_crc(void)103{104 struct stm32_crc *crc;105 106 spin_lock_bh(&crc_list.lock);107 crc = list_first_entry_or_null(&crc_list.dev_list, struct stm32_crc, list);108 if (crc)109 list_move_tail(&crc->list, &crc_list.dev_list);110 spin_unlock_bh(&crc_list.lock);111 112 return crc;113}114 115static int stm32_crc_init(struct shash_desc *desc)116{117 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);118 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);119 struct stm32_crc *crc;120 unsigned long flags;121 122 crc = stm32_crc_get_next_crc();123 if (!crc)124 return -ENODEV;125 126 pm_runtime_get_sync(crc->dev);127 128 spin_lock_irqsave(&crc->lock, flags);129 130 /* Reset, set key, poly and configure in bit reverse mode */131 writel_relaxed(bitrev32(mctx->key), crc->regs + CRC_INIT);132 writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL);133 writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT,134 crc->regs + CRC_CR);135 136 /* Store partial result */137 ctx->partial = readl_relaxed(crc->regs + CRC_DR);138 139 spin_unlock_irqrestore(&crc->lock, flags);140 141 pm_runtime_mark_last_busy(crc->dev);142 pm_runtime_put_autosuspend(crc->dev);143 144 return 0;145}146 147static int burst_update(struct shash_desc *desc, const u8 *d8,148 size_t length)149{150 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);151 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);152 struct stm32_crc *crc;153 154 crc = stm32_crc_get_next_crc();155 if (!crc)156 return -ENODEV;157 158 pm_runtime_get_sync(crc->dev);159 160 if (!spin_trylock(&crc->lock)) {161 /* Hardware is busy, calculate crc32 by software */162 if (mctx->poly == CRC32_POLY_LE)163 ctx->partial = crc32_le(ctx->partial, d8, length);164 else165 ctx->partial = __crc32c_le(ctx->partial, d8, length);166 167 goto pm_out;168 }169 170 /*171 * Restore previously calculated CRC for this context as init value172 * Restore polynomial configuration173 * Configure in register for word input data,174 * Configure out register in reversed bit mode data.175 */176 writel_relaxed(bitrev32(ctx->partial), crc->regs + CRC_INIT);177 writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL);178 writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT,179 crc->regs + CRC_CR);180 181 if (d8 != PTR_ALIGN(d8, sizeof(u32))) {182 /* Configure for byte data */183 writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT,184 crc->regs + CRC_CR);185 while (d8 != PTR_ALIGN(d8, sizeof(u32)) && length) {186 writeb_relaxed(*d8++, crc->regs + CRC_DR);187 length--;188 }189 /* Configure for word data */190 writel_relaxed(CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT,191 crc->regs + CRC_CR);192 }193 194 for (; length >= sizeof(u32); d8 += sizeof(u32), length -= sizeof(u32))195 writel_relaxed(*((u32 *)d8), crc->regs + CRC_DR);196 197 if (length) {198 /* Configure for byte data */199 writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT,200 crc->regs + CRC_CR);201 while (length--)202 writeb_relaxed(*d8++, crc->regs + CRC_DR);203 }204 205 /* Store partial result */206 ctx->partial = readl_relaxed(crc->regs + CRC_DR);207 208 spin_unlock(&crc->lock);209 210pm_out:211 pm_runtime_mark_last_busy(crc->dev);212 pm_runtime_put_autosuspend(crc->dev);213 214 return 0;215}216 217static int stm32_crc_update(struct shash_desc *desc, const u8 *d8,218 unsigned int length)219{220 const unsigned int burst_sz = burst_size;221 unsigned int rem_sz;222 const u8 *cur;223 size_t size;224 int ret;225 226 if (!burst_sz)227 return burst_update(desc, d8, length);228 229 /* Digest first bytes not 32bit aligned at first pass in the loop */230 size = min_t(size_t, length, burst_sz + (size_t)d8 -231 ALIGN_DOWN((size_t)d8, sizeof(u32)));232 for (rem_sz = length, cur = d8; rem_sz;233 rem_sz -= size, cur += size, size = min(rem_sz, burst_sz)) {234 ret = burst_update(desc, cur, size);235 if (ret)236 return ret;237 }238 239 return 0;240}241 242static int stm32_crc_final(struct shash_desc *desc, u8 *out)243{244 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc);245 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm);246 247 /* Send computed CRC */248 put_unaligned_le32(mctx->poly == CRC32C_POLY_LE ?249 ~ctx->partial : ctx->partial, out);250 251 return 0;252}253 254static int stm32_crc_finup(struct shash_desc *desc, const u8 *data,255 unsigned int length, u8 *out)256{257 return stm32_crc_update(desc, data, length) ?:258 stm32_crc_final(desc, out);259}260 261static int stm32_crc_digest(struct shash_desc *desc, const u8 *data,262 unsigned int length, u8 *out)263{264 return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out);265}266 267static unsigned int refcnt;268static DEFINE_MUTEX(refcnt_lock);269static struct shash_alg algs[] = {270 /* CRC-32 */271 {272 .setkey = stm32_crc_setkey,273 .init = stm32_crc_init,274 .update = stm32_crc_update,275 .final = stm32_crc_final,276 .finup = stm32_crc_finup,277 .digest = stm32_crc_digest,278 .descsize = sizeof(struct stm32_crc_desc_ctx),279 .digestsize = CHKSUM_DIGEST_SIZE,280 .base = {281 .cra_name = "crc32",282 .cra_driver_name = "stm32-crc32-crc32",283 .cra_priority = 200,284 .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,285 .cra_blocksize = CHKSUM_BLOCK_SIZE,286 .cra_ctxsize = sizeof(struct stm32_crc_ctx),287 .cra_module = THIS_MODULE,288 .cra_init = stm32_crc32_cra_init,289 }290 },291 /* CRC-32Castagnoli */292 {293 .setkey = stm32_crc_setkey,294 .init = stm32_crc_init,295 .update = stm32_crc_update,296 .final = stm32_crc_final,297 .finup = stm32_crc_finup,298 .digest = stm32_crc_digest,299 .descsize = sizeof(struct stm32_crc_desc_ctx),300 .digestsize = CHKSUM_DIGEST_SIZE,301 .base = {302 .cra_name = "crc32c",303 .cra_driver_name = "stm32-crc32-crc32c",304 .cra_priority = 200,305 .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,306 .cra_blocksize = CHKSUM_BLOCK_SIZE,307 .cra_ctxsize = sizeof(struct stm32_crc_ctx),308 .cra_module = THIS_MODULE,309 .cra_init = stm32_crc32c_cra_init,310 }311 }312};313 314static int stm32_crc_probe(struct platform_device *pdev)315{316 struct device *dev = &pdev->dev;317 struct stm32_crc *crc;318 int ret;319 320 crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL);321 if (!crc)322 return -ENOMEM;323 324 crc->dev = dev;325 326 crc->regs = devm_platform_ioremap_resource(pdev, 0);327 if (IS_ERR(crc->regs)) {328 dev_err(dev, "Cannot map CRC IO\n");329 return PTR_ERR(crc->regs);330 }331 332 crc->clk = devm_clk_get(dev, NULL);333 if (IS_ERR(crc->clk)) {334 dev_err(dev, "Could not get clock\n");335 return PTR_ERR(crc->clk);336 }337 338 ret = clk_prepare_enable(crc->clk);339 if (ret) {340 dev_err(crc->dev, "Failed to enable clock\n");341 return ret;342 }343 344 pm_runtime_set_autosuspend_delay(dev, CRC_AUTOSUSPEND_DELAY);345 pm_runtime_use_autosuspend(dev);346 347 pm_runtime_get_noresume(dev);348 pm_runtime_set_active(dev);349 pm_runtime_irq_safe(dev);350 pm_runtime_enable(dev);351 352 spin_lock_init(&crc->lock);353 354 platform_set_drvdata(pdev, crc);355 356 spin_lock(&crc_list.lock);357 list_add(&crc->list, &crc_list.dev_list);358 spin_unlock(&crc_list.lock);359 360 mutex_lock(&refcnt_lock);361 if (!refcnt) {362 ret = crypto_register_shashes(algs, ARRAY_SIZE(algs));363 if (ret) {364 mutex_unlock(&refcnt_lock);365 dev_err(dev, "Failed to register\n");366 clk_disable_unprepare(crc->clk);367 return ret;368 }369 }370 refcnt++;371 mutex_unlock(&refcnt_lock);372 373 dev_info(dev, "Initialized\n");374 375 pm_runtime_put_sync(dev);376 377 return 0;378}379 380static void stm32_crc_remove(struct platform_device *pdev)381{382 struct stm32_crc *crc = platform_get_drvdata(pdev);383 int ret = pm_runtime_get_sync(crc->dev);384 385 spin_lock(&crc_list.lock);386 list_del(&crc->list);387 spin_unlock(&crc_list.lock);388 389 mutex_lock(&refcnt_lock);390 if (!--refcnt)391 crypto_unregister_shashes(algs, ARRAY_SIZE(algs));392 mutex_unlock(&refcnt_lock);393 394 pm_runtime_disable(crc->dev);395 pm_runtime_put_noidle(crc->dev);396 397 if (ret >= 0)398 clk_disable(crc->clk);399 clk_unprepare(crc->clk);400}401 402static int __maybe_unused stm32_crc_suspend(struct device *dev)403{404 struct stm32_crc *crc = dev_get_drvdata(dev);405 int ret;406 407 ret = pm_runtime_force_suspend(dev);408 if (ret)409 return ret;410 411 clk_unprepare(crc->clk);412 413 return 0;414}415 416static int __maybe_unused stm32_crc_resume(struct device *dev)417{418 struct stm32_crc *crc = dev_get_drvdata(dev);419 int ret;420 421 ret = clk_prepare(crc->clk);422 if (ret) {423 dev_err(crc->dev, "Failed to prepare clock\n");424 return ret;425 }426 427 return pm_runtime_force_resume(dev);428}429 430static int __maybe_unused stm32_crc_runtime_suspend(struct device *dev)431{432 struct stm32_crc *crc = dev_get_drvdata(dev);433 434 clk_disable(crc->clk);435 436 return 0;437}438 439static int __maybe_unused stm32_crc_runtime_resume(struct device *dev)440{441 struct stm32_crc *crc = dev_get_drvdata(dev);442 int ret;443 444 ret = clk_enable(crc->clk);445 if (ret) {446 dev_err(crc->dev, "Failed to enable clock\n");447 return ret;448 }449 450 return 0;451}452 453static const struct dev_pm_ops stm32_crc_pm_ops = {454 SET_SYSTEM_SLEEP_PM_OPS(stm32_crc_suspend,455 stm32_crc_resume)456 SET_RUNTIME_PM_OPS(stm32_crc_runtime_suspend,457 stm32_crc_runtime_resume, NULL)458};459 460static const struct of_device_id stm32_dt_ids[] = {461 { .compatible = "st,stm32f7-crc", },462 {},463};464MODULE_DEVICE_TABLE(of, stm32_dt_ids);465 466static struct platform_driver stm32_crc_driver = {467 .probe = stm32_crc_probe,468 .remove_new = stm32_crc_remove,469 .driver = {470 .name = DRIVER_NAME,471 .pm = &stm32_crc_pm_ops,472 .of_match_table = stm32_dt_ids,473 },474};475 476module_platform_driver(stm32_crc_driver);477 478MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");479MODULE_DESCRIPTION("STMicrolectronics STM32 CRC32 hardware driver");480MODULE_LICENSE("GPL");481