Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.16-rc4 327 lines 8.3 kB view raw
1/* 2 * Copyright (C) STMicroelectronics SA 2017 3 * Author: Fabien Dessenne <fabien.dessenne@st.com> 4 * License terms: GNU General Public License (GPL), version 2 5 */ 6 7#include <linux/bitrev.h> 8#include <linux/clk.h> 9#include <linux/module.h> 10#include <linux/platform_device.h> 11 12#include <crypto/internal/hash.h> 13 14#include <asm/unaligned.h> 15 16#define DRIVER_NAME "stm32-crc32" 17#define CHKSUM_DIGEST_SIZE 4 18#define CHKSUM_BLOCK_SIZE 1 19 20/* Registers */ 21#define CRC_DR 0x00000000 22#define CRC_CR 0x00000008 23#define CRC_INIT 0x00000010 24#define CRC_POL 0x00000014 25 26/* Registers values */ 27#define CRC_CR_RESET BIT(0) 28#define CRC_CR_REVERSE (BIT(7) | BIT(6) | BIT(5)) 29#define CRC_INIT_DEFAULT 0xFFFFFFFF 30 31/* Polynomial reversed */ 32#define POLY_CRC32 0xEDB88320 33#define POLY_CRC32C 0x82F63B78 34 35struct stm32_crc { 36 struct list_head list; 37 struct device *dev; 38 void __iomem *regs; 39 struct clk *clk; 40 u8 pending_data[sizeof(u32)]; 41 size_t nb_pending_bytes; 42}; 43 44struct stm32_crc_list { 45 struct list_head dev_list; 46 spinlock_t lock; /* protect dev_list */ 47}; 48 49static struct stm32_crc_list crc_list = { 50 .dev_list = LIST_HEAD_INIT(crc_list.dev_list), 51 .lock = __SPIN_LOCK_UNLOCKED(crc_list.lock), 52}; 53 54struct stm32_crc_ctx { 55 u32 key; 56 u32 poly; 57}; 58 59struct stm32_crc_desc_ctx { 60 u32 partial; /* crc32c: partial in first 4 bytes of that struct */ 61 struct stm32_crc *crc; 62}; 63 64static int stm32_crc32_cra_init(struct crypto_tfm *tfm) 65{ 66 struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); 67 68 mctx->key = CRC_INIT_DEFAULT; 69 mctx->poly = POLY_CRC32; 70 return 0; 71} 72 73static int stm32_crc32c_cra_init(struct crypto_tfm *tfm) 74{ 75 struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); 76 77 mctx->key = CRC_INIT_DEFAULT; 78 mctx->poly = POLY_CRC32C; 79 return 0; 80} 81 82static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key, 83 unsigned int keylen) 84{ 85 struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm); 86 87 if (keylen != sizeof(u32)) { 88 crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); 89 return -EINVAL; 90 } 91 92 mctx->key = get_unaligned_le32(key); 93 return 0; 94} 95 96static int stm32_crc_init(struct shash_desc *desc) 97{ 98 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); 99 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); 100 struct stm32_crc *crc; 101 102 spin_lock_bh(&crc_list.lock); 103 list_for_each_entry(crc, &crc_list.dev_list, list) { 104 ctx->crc = crc; 105 break; 106 } 107 spin_unlock_bh(&crc_list.lock); 108 109 /* Reset, set key, poly and configure in bit reverse mode */ 110 writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT); 111 writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL); 112 writel_relaxed(CRC_CR_RESET | CRC_CR_REVERSE, ctx->crc->regs + CRC_CR); 113 114 /* Store partial result */ 115 ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR); 116 ctx->crc->nb_pending_bytes = 0; 117 118 return 0; 119} 120 121static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, 122 unsigned int length) 123{ 124 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); 125 struct stm32_crc *crc = ctx->crc; 126 u32 *d32; 127 unsigned int i; 128 129 if (unlikely(crc->nb_pending_bytes)) { 130 while (crc->nb_pending_bytes != sizeof(u32) && length) { 131 /* Fill in pending data */ 132 crc->pending_data[crc->nb_pending_bytes++] = *(d8++); 133 length--; 134 } 135 136 if (crc->nb_pending_bytes == sizeof(u32)) { 137 /* Process completed pending data */ 138 writel_relaxed(*(u32 *)crc->pending_data, 139 crc->regs + CRC_DR); 140 crc->nb_pending_bytes = 0; 141 } 142 } 143 144 d32 = (u32 *)d8; 145 for (i = 0; i < length >> 2; i++) 146 /* Process 32 bits data */ 147 writel_relaxed(*(d32++), crc->regs + CRC_DR); 148 149 /* Store partial result */ 150 ctx->partial = readl_relaxed(crc->regs + CRC_DR); 151 152 /* Check for pending data (non 32 bits) */ 153 length &= 3; 154 if (likely(!length)) 155 return 0; 156 157 if ((crc->nb_pending_bytes + length) >= sizeof(u32)) { 158 /* Shall not happen */ 159 dev_err(crc->dev, "Pending data overflow\n"); 160 return -EINVAL; 161 } 162 163 d8 = (const u8 *)d32; 164 for (i = 0; i < length; i++) 165 /* Store pending data */ 166 crc->pending_data[crc->nb_pending_bytes++] = *(d8++); 167 168 return 0; 169} 170 171static int stm32_crc_final(struct shash_desc *desc, u8 *out) 172{ 173 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); 174 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); 175 176 /* Send computed CRC */ 177 put_unaligned_le32(mctx->poly == POLY_CRC32C ? 178 ~ctx->partial : ctx->partial, out); 179 180 return 0; 181} 182 183static int stm32_crc_finup(struct shash_desc *desc, const u8 *data, 184 unsigned int length, u8 *out) 185{ 186 return stm32_crc_update(desc, data, length) ?: 187 stm32_crc_final(desc, out); 188} 189 190static int stm32_crc_digest(struct shash_desc *desc, const u8 *data, 191 unsigned int length, u8 *out) 192{ 193 return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out); 194} 195 196static struct shash_alg algs[] = { 197 /* CRC-32 */ 198 { 199 .setkey = stm32_crc_setkey, 200 .init = stm32_crc_init, 201 .update = stm32_crc_update, 202 .final = stm32_crc_final, 203 .finup = stm32_crc_finup, 204 .digest = stm32_crc_digest, 205 .descsize = sizeof(struct stm32_crc_desc_ctx), 206 .digestsize = CHKSUM_DIGEST_SIZE, 207 .base = { 208 .cra_name = "crc32", 209 .cra_driver_name = DRIVER_NAME, 210 .cra_priority = 200, 211 .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 212 .cra_blocksize = CHKSUM_BLOCK_SIZE, 213 .cra_alignmask = 3, 214 .cra_ctxsize = sizeof(struct stm32_crc_ctx), 215 .cra_module = THIS_MODULE, 216 .cra_init = stm32_crc32_cra_init, 217 } 218 }, 219 /* CRC-32Castagnoli */ 220 { 221 .setkey = stm32_crc_setkey, 222 .init = stm32_crc_init, 223 .update = stm32_crc_update, 224 .final = stm32_crc_final, 225 .finup = stm32_crc_finup, 226 .digest = stm32_crc_digest, 227 .descsize = sizeof(struct stm32_crc_desc_ctx), 228 .digestsize = CHKSUM_DIGEST_SIZE, 229 .base = { 230 .cra_name = "crc32c", 231 .cra_driver_name = DRIVER_NAME, 232 .cra_priority = 200, 233 .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 234 .cra_blocksize = CHKSUM_BLOCK_SIZE, 235 .cra_alignmask = 3, 236 .cra_ctxsize = sizeof(struct stm32_crc_ctx), 237 .cra_module = THIS_MODULE, 238 .cra_init = stm32_crc32c_cra_init, 239 } 240 } 241}; 242 243static int stm32_crc_probe(struct platform_device *pdev) 244{ 245 struct device *dev = &pdev->dev; 246 struct stm32_crc *crc; 247 struct resource *res; 248 int ret; 249 250 crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL); 251 if (!crc) 252 return -ENOMEM; 253 254 crc->dev = dev; 255 256 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 257 crc->regs = devm_ioremap_resource(dev, res); 258 if (IS_ERR(crc->regs)) { 259 dev_err(dev, "Cannot map CRC IO\n"); 260 return PTR_ERR(crc->regs); 261 } 262 263 crc->clk = devm_clk_get(dev, NULL); 264 if (IS_ERR(crc->clk)) { 265 dev_err(dev, "Could not get clock\n"); 266 return PTR_ERR(crc->clk); 267 } 268 269 ret = clk_prepare_enable(crc->clk); 270 if (ret) { 271 dev_err(crc->dev, "Failed to enable clock\n"); 272 return ret; 273 } 274 275 platform_set_drvdata(pdev, crc); 276 277 spin_lock(&crc_list.lock); 278 list_add(&crc->list, &crc_list.dev_list); 279 spin_unlock(&crc_list.lock); 280 281 ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); 282 if (ret) { 283 dev_err(dev, "Failed to register\n"); 284 clk_disable_unprepare(crc->clk); 285 return ret; 286 } 287 288 dev_info(dev, "Initialized\n"); 289 290 return 0; 291} 292 293static int stm32_crc_remove(struct platform_device *pdev) 294{ 295 struct stm32_crc *crc = platform_get_drvdata(pdev); 296 297 spin_lock(&crc_list.lock); 298 list_del(&crc->list); 299 spin_unlock(&crc_list.lock); 300 301 crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); 302 303 clk_disable_unprepare(crc->clk); 304 305 return 0; 306} 307 308static const struct of_device_id stm32_dt_ids[] = { 309 { .compatible = "st,stm32f7-crc", }, 310 {}, 311}; 312MODULE_DEVICE_TABLE(of, stm32_dt_ids); 313 314static struct platform_driver stm32_crc_driver = { 315 .probe = stm32_crc_probe, 316 .remove = stm32_crc_remove, 317 .driver = { 318 .name = DRIVER_NAME, 319 .of_match_table = stm32_dt_ids, 320 }, 321}; 322 323module_platform_driver(stm32_crc_driver); 324 325MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>"); 326MODULE_DESCRIPTION("STMicrolectronics STM32 CRC32 hardware driver"); 327MODULE_LICENSE("GPL");