| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include <linux/err.h> |
| #include <linux/clk-provider.h> |
| #include <linux/clk.h> |
| #include <linux/io.h> |
| #include <linux/hw_random.h> |
| #include <linux/platform_device.h> |
| #include <linux/device.h> |
| #include <linux/init.h> |
| #include <linux/errno.h> |
| #include <linux/interrupt.h> |
| #include <linux/irq.h> |
| #include <linux/scatterlist.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/of_device.h> |
| #include <linux/delay.h> |
| #include <linux/crypto.h> |
| #include <crypto/scatterwalk.h> |
| #include <crypto/algapi.h> |
| #include <linux/tee_drv.h> |
| |
| #include "asr-bcm-optee.h" |
| |
| static void asrbcm_uuid_to_octets(uint8_t d[TEE_IOCTL_UUID_LEN], struct teec_uuid *s) |
| { |
| d[0] = s->timeLow >> 24; |
| d[1] = s->timeLow >> 16; |
| d[2] = s->timeLow >> 8; |
| d[3] = s->timeLow; |
| d[4] = s->timeMid >> 8; |
| d[5] = s->timeMid; |
| d[6] = s->timeHiAndVersion >> 8; |
| d[7] = s->timeHiAndVersion; |
| memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode)); |
| } |
| |
| static int asrbcm_tee_match_cb(struct tee_ioctl_version_data *ver, const void *data) |
| { |
| return 1; |
| } |
| |
| int asrbcm_optee_open_ta(struct asrbcm_tee_context *ctx, struct teec_uuid *uuid) |
| { |
| struct tee_ioctl_open_session_arg open_session_arg; |
| int ret; |
| |
| if (ctx == NULL) |
| return -EINVAL; |
| |
| ctx->session = 0; |
| ctx->tee_ctx = tee_client_open_context(NULL, asrbcm_tee_match_cb, NULL, NULL); |
| if (IS_ERR(ctx->tee_ctx)) { |
| ret = PTR_ERR(ctx->tee_ctx); |
| ctx->tee_ctx = NULL; |
| return ret; |
| } |
| |
| memset(&open_session_arg, 0x0, sizeof(struct tee_ioctl_open_session_arg)); |
| asrbcm_uuid_to_octets(open_session_arg.uuid, uuid); |
| open_session_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; |
| open_session_arg.num_params = 0; |
| ret = tee_client_open_session(ctx->tee_ctx, &open_session_arg, NULL); |
| if (ret != 0) { |
| goto err_exit; |
| } else if (open_session_arg.ret != 0) { |
| ret = -EIO; |
| goto err_exit; |
| } |
| |
| ctx->session = open_session_arg.session; |
| |
| return ret; |
| err_exit: |
| tee_client_close_context(ctx->tee_ctx); |
| ctx->tee_ctx = NULL; |
| return ret; |
| } |
| |
| int asrbcm_optee_close_ta(struct asrbcm_tee_context *ctx) |
| { |
| int ret; |
| |
| if (ctx == NULL) |
| return -EINVAL; |
| |
| ret = tee_client_close_session(ctx->tee_ctx, ctx->session); |
| |
| tee_client_close_context(ctx->tee_ctx); |
| |
| return ret; |
| } |
| |
| #if defined(CONFIG_OF) |
| static const struct of_device_id asr_bcm_dt_ids[] = { |
| { .compatible = "asr,asr-bcm" }, |
| { /* sentinel */ } |
| }; |
| MODULE_DEVICE_TABLE(of, asr_bcm_dt_ids); |
| #endif |
| |
| static int asr_bcm_probe(struct platform_device *pdev) |
| { |
| struct asr_bcm_dev *bcm_dd; |
| struct device *dev = &pdev->dev; |
| struct device_node *np = NULL; |
| int err = 0, devnum = 0; |
| |
| bcm_dd = devm_kzalloc(&pdev->dev, sizeof(*bcm_dd), GFP_KERNEL); |
| if (bcm_dd == NULL) { |
| err = -ENOMEM; |
| goto no_mem_err; |
| } |
| |
| np = dev->of_node; |
| bcm_dd->dev = dev; |
| |
| platform_set_drvdata(pdev, bcm_dd); |
| |
| #ifdef CONFIG_ASR_BCM_CIPHER |
| if (of_get_property(np, "asr,asr-cipher", NULL)) { |
| err = asr_bcm_cipher_register(bcm_dd); |
| if (err) |
| goto res_err; |
| dev_info(dev, "CIPHER engine is initialized\n"); |
| devnum ++; |
| } |
| #endif |
| |
| #ifdef CONFIG_ASR_BCM_SHA |
| if (of_get_property(np, "asr,asr-sha", NULL)) { |
| err = asr_bcm_sha_register(bcm_dd); |
| if (err) |
| goto sha_err; |
| dev_info(dev, "SHA engine is initialized\n"); |
| devnum ++; |
| } |
| #endif |
| |
| if (!devnum) { |
| dev_err(dev, "No BCM device enabled\n"); |
| err = -ENODEV; |
| goto res_err; |
| } |
| |
| return 0; |
| |
| #ifdef CONFIG_ASR_BCM_SHA |
| sha_err: |
| #ifdef CONFIG_ASR_BCM_CIPHER |
| asr_bcm_cipher_unregister(bcm_dd); |
| #endif |
| #endif |
| |
| res_err: |
| devm_kfree(dev, bcm_dd); |
| no_mem_err: |
| dev_err(dev, "initialization failed.\n"); |
| |
| return err; |
| } |
| |
| static int asr_bcm_remove(struct platform_device *pdev) |
| { |
| struct asr_bcm_dev *bcm_dd; |
| |
| bcm_dd = platform_get_drvdata(pdev); |
| if (!bcm_dd) |
| return -ENODEV; |
| |
| #ifdef CONFIG_ASR_BCM_CIPHER |
| asr_bcm_cipher_unregister(bcm_dd); |
| #endif |
| |
| #ifdef CONFIG_ASR_BCM_SHA |
| asr_bcm_sha_unregister(bcm_dd); |
| #endif |
| |
| devm_kfree(bcm_dd->dev, bcm_dd); |
| |
| return 0; |
| } |
| |
| static struct platform_driver asr_bcm_driver = { |
| .probe = asr_bcm_probe, |
| .remove = asr_bcm_remove, |
| .driver = { |
| .name = "asr_bcm", |
| .of_match_table = of_match_ptr(asr_bcm_dt_ids), |
| }, |
| }; |
| |
| static int __init asr_bcm_init(void) |
| { |
| int ret; |
| |
| ret = platform_driver_register(&asr_bcm_driver); |
| |
| return ret; |
| } |
| |
| device_initcall_sync(asr_bcm_init); |
| |
| MODULE_DESCRIPTION("BCM: ASR Trust Engine support."); |
| MODULE_LICENSE("GPL v2"); |
| MODULE_AUTHOR("Yonggan Wang"); |