19b6221aeSleisen // SPDX-License-Identifier: BSD-2-Clause
29b6221aeSleisen /*
39b6221aeSleisen * Copyright 2022-2024 HiSilicon Limited.
49b6221aeSleisen * Kunpeng hardware accelerator SEC module init.
59b6221aeSleisen */
69b6221aeSleisen
79b6221aeSleisen #include <initcall.h>
89b6221aeSleisen #include <io.h>
99b6221aeSleisen #include <malloc.h>
109b6221aeSleisen #include <sys/queue.h>
119b6221aeSleisen #include <trace.h>
129b6221aeSleisen #include <util.h>
139b6221aeSleisen
14*b6a44cc5Sleisen #include "sec_main.h"
15*b6a44cc5Sleisen
169b6221aeSleisen #define AM_CFG_SINGLE_PORT_MAX_TRANS 0x300014
179b6221aeSleisen #define SEC_CORE_INT_MASK 0x301000
189b6221aeSleisen #define SEC_CORE_INT_SOURCE 0x301010
199b6221aeSleisen #define SEC_RAS_CE_ENABLE 0x301050
209b6221aeSleisen #define SEC_RAS_FE_ENABLE 0x301054
219b6221aeSleisen #define SEC_RAS_NFE_ENABLE 0x301058
229b6221aeSleisen #define SEC_MEM_START_INIT 0x301100
239b6221aeSleisen #define SEC_MEM_INIT_DONE 0x301104
249b6221aeSleisen #define SEC_CONTROL_REG 0x301200
259b6221aeSleisen #define SEC_INTERFACE_USER_CTRL0 0x301220
269b6221aeSleisen #define SEC_INTERFACE_USER_CTRL1 0x301224
279b6221aeSleisen #define SEC_SAA_EN 0x301270
289b6221aeSleisen #define SEC_BD_ERR_CHK_EN0 0x301380
299b6221aeSleisen #define SEC_BD_ERR_CHK_EN1 0x301384
309b6221aeSleisen #define SEC_BD_ERR_CHK_EN2 0x301388
319b6221aeSleisen #define SEC_BD_ERR_CHK_EN3 0x30138c
329b6221aeSleisen #define SEC_DYNAMIC_GATE_V3 0x30121c
339b6221aeSleisen #define SEC_BD_ERR_CHK_EN2_V3 0x301508
349b6221aeSleisen #define SEC_CORE_AUTO_GATE_V3 0x30212c
359b6221aeSleisen #define SEC_INTERFACE_USER_CTRL0_V3 0x302220
369b6221aeSleisen #define SEC_INTERFACE_USER_CTRL1_V3 0x302224
379b6221aeSleisen #define SEC_SINGLE_PORT_MAX_TRANS 0x2060
389b6221aeSleisen #define SEC_ABNML_INT_DISABLE 0x0
399b6221aeSleisen #define SEC_RAS_CE_ENB_MASK 0x88
409b6221aeSleisen #define SEC_RAS_FE_ENB 0x0
419b6221aeSleisen #define SEC_RAS_NFE_ENB_MASK 0x177
429b6221aeSleisen #define SEC_CLK_GATE_ENABLE BIT(3)
439b6221aeSleisen #define SEC_DYNAMIC_GATE_EN 0x7bff
449b6221aeSleisen #define SEC_CORE_AUTO_GATE_EN GENMASK_32(3, 0)
459b6221aeSleisen #define SEC_TRNG_EN_MASK BIT(8)
469b6221aeSleisen #define SEC_SAA_ENABLE 0x17f
479b6221aeSleisen #define SEC_SAA_ENABLE_V3 0xf
489b6221aeSleisen #define SEC_BD_ERR_CHK0 0xefffffff
499b6221aeSleisen #define SEC_BD_ERR_CHK1 0x7ffff7fd
509b6221aeSleisen #define SEC_BD_ERR_CHK2 0xffff7fff
519b6221aeSleisen #define SEC_BD_ERR_CHK3 0xffffbfff
529b6221aeSleisen #define SEC_USER0_CFG 0x20200
539b6221aeSleisen #define SEC_USER0_SMMU_NORMAL (BIT(23) | BIT(15))
549b6221aeSleisen #define SEC_USER1_CFG 0x12141214
559b6221aeSleisen #define SEC_USER1_SMMU_NORMAL (BIT(31) | BIT(23) | BIT(15) | BIT(7))
569b6221aeSleisen #define SEC_USER0_CFG_V3 0x20200
579b6221aeSleisen #define SEC_USER1_CFG_V3 0x8c494
589b6221aeSleisen
599b6221aeSleisen static SLIST_HEAD(, acc_device) sec_list = SLIST_HEAD_INITIALIZER(sec_list);
609b6221aeSleisen
sec_create_qp(uint8_t sq_type)619b6221aeSleisen struct hisi_qp *sec_create_qp(uint8_t sq_type)
629b6221aeSleisen {
639b6221aeSleisen struct acc_device *sec_dev = NULL;
649b6221aeSleisen struct acc_device *cur_dev = NULL;
659b6221aeSleisen uint32_t free_qp_num = 0;
669b6221aeSleisen uint32_t max_qp_num = 0;
679b6221aeSleisen
689b6221aeSleisen /* Find the SEC device with the most remaining qp numbers */
699b6221aeSleisen SLIST_FOREACH(cur_dev, &sec_list, link) {
709b6221aeSleisen if (cur_dev->qm.fun_type == HISI_QM_HW_PF)
719b6221aeSleisen free_qp_num = HISI_QM_PF_Q_NUM - cur_dev->qm.qp_in_used;
729b6221aeSleisen else
739b6221aeSleisen free_qp_num = HISI_QM_VF_Q_NUM - cur_dev->qm.qp_in_used;
749b6221aeSleisen if (free_qp_num > max_qp_num) {
759b6221aeSleisen max_qp_num = free_qp_num;
769b6221aeSleisen sec_dev = cur_dev;
779b6221aeSleisen }
789b6221aeSleisen }
799b6221aeSleisen
809b6221aeSleisen if (!sec_dev) {
819b6221aeSleisen EMSG("No available sec device");
829b6221aeSleisen return NULL;
839b6221aeSleisen }
849b6221aeSleisen
859b6221aeSleisen return hisi_qm_create_qp(&sec_dev->qm, sq_type);
869b6221aeSleisen }
879b6221aeSleisen
sec_enable_clock_gate(struct hisi_qm * qm)889b6221aeSleisen static void sec_enable_clock_gate(struct hisi_qm *qm)
899b6221aeSleisen {
909b6221aeSleisen if (qm->version == HISI_QM_HW_V2)
919b6221aeSleisen return;
929b6221aeSleisen
939b6221aeSleisen io_setbits32(qm->io_base + SEC_CONTROL_REG, SEC_CLK_GATE_ENABLE);
949b6221aeSleisen io_write32(qm->io_base + SEC_DYNAMIC_GATE_V3, SEC_DYNAMIC_GATE_EN);
959b6221aeSleisen io_write32(qm->io_base + SEC_CORE_AUTO_GATE_V3, SEC_CORE_AUTO_GATE_EN);
969b6221aeSleisen }
979b6221aeSleisen
sec_engine_init(struct acc_device * sec_dev)989b6221aeSleisen static enum hisi_drv_status sec_engine_init(struct acc_device *sec_dev)
999b6221aeSleisen {
1009b6221aeSleisen struct hisi_qm *qm = &sec_dev->qm;
1019b6221aeSleisen uint32_t val = 0;
1029b6221aeSleisen
1039b6221aeSleisen if (qm->fun_type == HISI_QM_HW_VF)
1049b6221aeSleisen return HISI_QM_DRVCRYPT_NO_ERR;
1059b6221aeSleisen
1069b6221aeSleisen /* QM_HW_V2 version need to close clock gating */
1079b6221aeSleisen io_clrbits32(qm->io_base + SEC_CONTROL_REG, SEC_CLK_GATE_ENABLE);
1089b6221aeSleisen
1099b6221aeSleisen hisi_qm_dev_init(qm);
1109b6221aeSleisen
1119b6221aeSleisen io_write32(qm->io_base + SEC_MEM_START_INIT, 0x1);
1129b6221aeSleisen if (IO_READ32_POLL_TIMEOUT(qm->io_base + SEC_MEM_INIT_DONE, val,
1139b6221aeSleisen val & 0x1, POLL_PERIOD, POLL_TIMEOUT)) {
1149b6221aeSleisen EMSG("Fail to init sec mem");
1159b6221aeSleisen return HISI_QM_DRVCRYPT_ETMOUT;
1169b6221aeSleisen }
1179b6221aeSleisen
1189b6221aeSleisen io_setbits32(qm->io_base + SEC_CONTROL_REG, sec_dev->endian);
1199b6221aeSleisen
1209b6221aeSleisen if (qm->version == HISI_QM_HW_V2) {
1219b6221aeSleisen /* SMMU bypass */
1229b6221aeSleisen io_write32(qm->io_base + SEC_INTERFACE_USER_CTRL0,
1239b6221aeSleisen SEC_USER0_CFG);
1249b6221aeSleisen io_write32(qm->io_base + SEC_INTERFACE_USER_CTRL1,
1259b6221aeSleisen SEC_USER1_CFG);
1269b6221aeSleisen io_write32(qm->io_base + AM_CFG_SINGLE_PORT_MAX_TRANS,
1279b6221aeSleisen SEC_SINGLE_PORT_MAX_TRANS);
1289b6221aeSleisen io_write32(qm->io_base + SEC_SAA_EN, SEC_SAA_ENABLE);
1299b6221aeSleisen /* HW V2 enable SM4 extra mode, as CTR/ECB */
1309b6221aeSleisen io_write32(qm->io_base + SEC_BD_ERR_CHK_EN0, SEC_BD_ERR_CHK0);
1319b6221aeSleisen /* Enable SM4 xts mode multiple iv */
1329b6221aeSleisen io_write32(qm->io_base + SEC_BD_ERR_CHK_EN1, SEC_BD_ERR_CHK1);
1339b6221aeSleisen /* disable PBKDF2 len check */
1349b6221aeSleisen io_write32(qm->io_base + SEC_BD_ERR_CHK_EN2, SEC_BD_ERR_CHK2);
1359b6221aeSleisen io_write32(qm->io_base + SEC_BD_ERR_CHK_EN3, SEC_BD_ERR_CHK3);
1369b6221aeSleisen } else {
1379b6221aeSleisen /* cmd_type is controlled by HAC subctrl, default normal */
1389b6221aeSleisen io_write32(qm->io_base + SEC_INTERFACE_USER_CTRL0_V3,
1399b6221aeSleisen SEC_USER0_CFG_V3);
1409b6221aeSleisen io_write32(qm->io_base + SEC_INTERFACE_USER_CTRL1_V3,
1419b6221aeSleisen SEC_USER1_CFG_V3);
1429b6221aeSleisen io_write32(qm->io_base + SEC_SAA_EN, SEC_SAA_ENABLE_V3);
1439b6221aeSleisen /* disable PBKDF2 salt len check */
1449b6221aeSleisen io_write32(qm->io_base + SEC_BD_ERR_CHK_EN2_V3,
1459b6221aeSleisen SEC_BD_ERR_CHK2);
1469b6221aeSleisen }
1479b6221aeSleisen io_write32(qm->io_base + SEC_RAS_CE_ENABLE, SEC_RAS_CE_ENB_MASK);
1489b6221aeSleisen io_write32(qm->io_base + SEC_RAS_FE_ENABLE, SEC_RAS_FE_ENB);
1499b6221aeSleisen io_write32(qm->io_base + SEC_RAS_NFE_ENABLE, SEC_RAS_NFE_ENB_MASK);
1509b6221aeSleisen io_write32(qm->io_base + SEC_CORE_INT_MASK, SEC_ABNML_INT_DISABLE);
1519b6221aeSleisen
1529b6221aeSleisen sec_enable_clock_gate(qm);
1539b6221aeSleisen
1549b6221aeSleisen return HISI_QM_DRVCRYPT_NO_ERR;
1559b6221aeSleisen }
1569b6221aeSleisen
sec_dev_status_check(struct hisi_qm * qm)1579b6221aeSleisen static enum hisi_drv_status sec_dev_status_check(struct hisi_qm *qm)
1589b6221aeSleisen {
1599b6221aeSleisen uint32_t val = 0;
1609b6221aeSleisen
1619b6221aeSleisen val = io_read32(qm->io_base + SEC_CORE_INT_SOURCE);
1629b6221aeSleisen if (val & SEC_RAS_NFE_ENB_MASK) {
1639b6221aeSleisen EMSG("SEC NFE RAS happened, need to reset");
1649b6221aeSleisen return HISI_QM_DRVCRYPT_HW_EACCESS;
1659b6221aeSleisen }
1669b6221aeSleisen
1679b6221aeSleisen val = io_read32(qm->io_base + HISI_QM_ABNML_INT_SRC);
1689b6221aeSleisen if (val) {
1699b6221aeSleisen if (val & HISI_QM_SEC_NFE_INT_MASK)
1709b6221aeSleisen EMSG("QM NFE RAS happened, need to reset");
1719b6221aeSleisen
1729b6221aeSleisen if (val & HISI_QM_INVALID_DB) {
1739b6221aeSleisen EMSG("QM invalid db happened, please check");
1749b6221aeSleisen io_write32(qm->io_base + HISI_QM_ABNML_INT_SRC,
1759b6221aeSleisen HISI_QM_INVALID_DB);
1769b6221aeSleisen }
1779b6221aeSleisen
1789b6221aeSleisen return HISI_QM_DRVCRYPT_HW_EACCESS;
1799b6221aeSleisen }
1809b6221aeSleisen
1819b6221aeSleisen return HISI_QM_DRVCRYPT_NO_ERR;
1829b6221aeSleisen }
1839b6221aeSleisen
sec_qm_init(struct acc_device * sec_dev)1849b6221aeSleisen static enum hisi_drv_status sec_qm_init(struct acc_device *sec_dev)
1859b6221aeSleisen {
1869b6221aeSleisen struct hisi_qm *qm = &sec_dev->qm;
1879b6221aeSleisen
1889b6221aeSleisen qm->io_base = (vaddr_t)phys_to_virt_io(sec_dev->io_base,
1899b6221aeSleisen sec_dev->io_size);
1909b6221aeSleisen if (!qm->io_base) {
1919b6221aeSleisen EMSG("Fail to get qm io_base");
1929b6221aeSleisen return HISI_QM_DRVCRYPT_EFAULT;
1939b6221aeSleisen }
1949b6221aeSleisen
1959b6221aeSleisen qm->fun_type = sec_dev->fun_type;
1969b6221aeSleisen qm->vfs_num = sec_dev->vfs_num;
1979b6221aeSleisen qm->sqe_size = SEC_SQE_SIZE;
1989b6221aeSleisen qm->sqe_log2_size = SEC_SQE_LOG2_SIZE;
1999b6221aeSleisen if (qm->fun_type == HISI_QM_HW_PF) {
2009b6221aeSleisen hisi_qm_get_version(qm);
2019b6221aeSleisen DMSG("SEC hardware version is %#"PRIx32, qm->version);
2029b6221aeSleisen qm->qp_base = HISI_QM_PF_Q_BASE;
2039b6221aeSleisen qm->qp_num = HISI_QM_PF_Q_NUM;
2049b6221aeSleisen qm->dev_status_check = sec_dev_status_check;
2059b6221aeSleisen }
2069b6221aeSleisen
2079b6221aeSleisen return hisi_qm_init(qm);
2089b6221aeSleisen }
2099b6221aeSleisen
sec_alloc(void)2109b6221aeSleisen static struct acc_device *sec_alloc(void)
2119b6221aeSleisen {
2129b6221aeSleisen struct acc_device *sec_dev = NULL;
2139b6221aeSleisen
2149b6221aeSleisen sec_dev = calloc(1, sizeof(*sec_dev));
2159b6221aeSleisen if (!sec_dev) {
2169b6221aeSleisen EMSG("Fail to alloc sec_dev");
2179b6221aeSleisen return NULL;
2189b6221aeSleisen }
2199b6221aeSleisen
2209b6221aeSleisen sec_dev->io_base = SEC_BAR;
2219b6221aeSleisen sec_dev->io_size = SEC_SIZE;
2229b6221aeSleisen sec_dev->fun_type = HISI_QM_HW_PF;
2239b6221aeSleisen SLIST_INSERT_HEAD(&sec_list, sec_dev, link);
2249b6221aeSleisen
2259b6221aeSleisen return sec_dev;
2269b6221aeSleisen }
2279b6221aeSleisen
sec_free(struct acc_device * sec_dev)2289b6221aeSleisen static void sec_free(struct acc_device *sec_dev)
2299b6221aeSleisen {
2309b6221aeSleisen SLIST_REMOVE_HEAD(&sec_list, link);
2319b6221aeSleisen free(sec_dev);
2329b6221aeSleisen }
2339b6221aeSleisen
sec_probe(void)2349b6221aeSleisen static TEE_Result sec_probe(void)
2359b6221aeSleisen {
2369b6221aeSleisen enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
2379b6221aeSleisen struct acc_device *sec_dev = NULL;
2389b6221aeSleisen struct hisi_qm *qm = NULL;
2399b6221aeSleisen
2409b6221aeSleisen DMSG("SEC driver init start");
2419b6221aeSleisen sec_dev = sec_alloc();
2429b6221aeSleisen if (!sec_dev)
2439b6221aeSleisen return TEE_ERROR_OUT_OF_MEMORY;
2449b6221aeSleisen
2459b6221aeSleisen qm = &sec_dev->qm;
2469b6221aeSleisen ret = sec_qm_init(sec_dev);
2479b6221aeSleisen if (ret) {
2489b6221aeSleisen EMSG("Fail to init sec qm, ret=%d", ret);
2499b6221aeSleisen goto err_with_pre_init;
2509b6221aeSleisen }
2519b6221aeSleisen
2529b6221aeSleisen ret = sec_engine_init(sec_dev);
2539b6221aeSleisen if (ret) {
2549b6221aeSleisen EMSG("fail to init engine, ret=%d", ret);
2559b6221aeSleisen goto err_with_qm_init;
2569b6221aeSleisen }
2579b6221aeSleisen
2589b6221aeSleisen ret = hisi_qm_start(qm);
2599b6221aeSleisen if (ret) {
2609b6221aeSleisen EMSG("Fail to start qm, ret=%d", ret);
2619b6221aeSleisen goto err_with_qm_init;
2629b6221aeSleisen }
2639b6221aeSleisen
2649b6221aeSleisen DMSG("SEC driver init done");
2659b6221aeSleisen return TEE_SUCCESS;
2669b6221aeSleisen
2679b6221aeSleisen err_with_qm_init:
2689b6221aeSleisen hisi_qm_uninit(qm);
2699b6221aeSleisen err_with_pre_init:
2709b6221aeSleisen sec_free(sec_dev);
2719b6221aeSleisen
2729b6221aeSleisen return TEE_ERROR_BAD_STATE;
2739b6221aeSleisen }
2749b6221aeSleisen
2759b6221aeSleisen driver_init(sec_probe);
276