| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #include <linux/types.h> |
| #include <linux/device.h> |
| #include <linux/slab.h> |
| #include <linux/platform_device.h> |
| #include <linux/err.h> |
| #include <linux/of.h> |
| #include "unifykey.h" |
| |
| #undef pr_fmt |
| #define pr_fmt(fmt) "unifykey: " fmt |
| |
| static int uk_item_parse_dt(struct aml_uk_dev *ukdev, struct device_node *node, |
| int id) |
| { |
| int count; |
| int ret; |
| const char *propname; |
| struct key_item_t *tmp_item = NULL; |
| |
| tmp_item = kzalloc(sizeof(*tmp_item), GFP_KERNEL); |
| if (!tmp_item) |
| return -ENOMEM; |
| |
| propname = NULL; |
| ret = of_property_read_string(node, "key-name", &propname); |
| if (ret < 0) { |
| pr_err("%s:%d,get key-name fail\n", __func__, __LINE__); |
| ret = -EINVAL; |
| goto exit; |
| } |
| if (propname) { |
| count = strlen(propname); |
| if (count >= KEY_UNIFY_NAME_LEN) |
| count = KEY_UNIFY_NAME_LEN - 1; |
| memcpy(tmp_item->name, propname, count); |
| } |
| |
| propname = NULL; |
| ret = of_property_read_string(node, "key-device", &propname); |
| if (ret < 0) { |
| pr_err("%s:%d,get key-device fail\n", __func__, __LINE__); |
| ret = -EINVAL; |
| goto exit; |
| } |
| if (propname) { |
| if (strcmp(propname, "efuse") == 0) |
| tmp_item->dev = KEY_EFUSE; |
| else if (strcmp(propname, "normal") == 0) |
| tmp_item->dev = KEY_NORMAL; |
| else if (strcmp(propname, "secure") == 0) |
| tmp_item->dev = KEY_SECURE; |
| else |
| tmp_item->dev = KEY_UNKNOWN_DEV; |
| } |
| |
| tmp_item->perm = 0; |
| if (of_property_match_string(node, "key-permit", "read") >= 0) |
| tmp_item->perm |= KEY_PERM_READ; |
| if (of_property_match_string(node, "key-permit", "write") >= 0) |
| tmp_item->perm |= KEY_PERM_WRITE; |
| tmp_item->id = id; |
| |
| tmp_item->attr = 0; |
| if (of_property_read_bool(node, "key-encrypt")) |
| tmp_item->attr = KEY_ATTR_ENCRYPT; |
| |
| list_add(&tmp_item->node, &ukdev->uk_hdr); |
| return 0; |
| exit: |
| kfree(tmp_item); |
| return ret; |
| } |
| |
| static int uk_item_create(struct platform_device *pdev, int *num) |
| { |
| int ret = -1; |
| int index; |
| struct device_node *child; |
| struct device_node *np = pdev->dev.of_node; |
| struct aml_uk_dev *ukdev = platform_get_drvdata(pdev); |
| |
| of_node_get(np); |
| index = 0; |
| for_each_child_of_node(np, child) { |
| ret = uk_item_parse_dt(ukdev, child, index); |
| if (!ret) |
| index++; |
| } |
| *num = index; |
| pr_info("unifykey num is %d\n", *num); |
| |
| return 0; |
| } |
| |
| int uk_dt_create(struct platform_device *pdev) |
| { |
| int key_num, ret; |
| struct aml_uk_dev *ukdev = platform_get_drvdata(pdev); |
| |
| ukdev->uk_info.encrypt_type = -1; |
| /* do not care whether unifykey-encrypt really exists*/ |
| ret = of_property_read_u32(pdev->dev.of_node, "unifykey-encrypt", |
| &ukdev->uk_info.encrypt_type); |
| if (ret < 0) |
| pr_info("no unifykey-encrypt property\n"); |
| |
| if (!(ukdev->uk_info.key_flag)) { |
| uk_item_create(pdev, &key_num); |
| ukdev->uk_info.key_num = key_num; |
| ukdev->uk_info.key_flag = 1; |
| } |
| |
| return 0; |
| } |
| |
| int uk_dt_release(struct platform_device *pdev) |
| { |
| struct aml_uk_dev *ukdev = platform_get_drvdata(pdev); |
| struct key_item_t *item; |
| struct key_item_t *tmp; |
| |
| if (pdev->dev.of_node) |
| of_node_put(pdev->dev.of_node); |
| |
| list_for_each_entry_safe(item, tmp, &ukdev->uk_hdr, node) { |
| list_del(&item->node); |
| kfree(item); |
| } |
| ukdev->uk_info.key_flag = 0; |
| return 0; |
| } |