162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for the HiSilicon SEC units found on Hip06 Hip07 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2016-2017 HiSilicon Limited. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/acpi.h> 862306a36Sopenharmony_ci#include <linux/atomic.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/dma-direction.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/dmapool.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/iommu.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/irq.h> 1762306a36Sopenharmony_ci#include <linux/irqreturn.h> 1862306a36Sopenharmony_ci#include <linux/mm.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/of.h> 2162306a36Sopenharmony_ci#include <linux/platform_device.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "sec_drv.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define SEC_QUEUE_AR_FROCE_ALLOC 0 2762306a36Sopenharmony_ci#define SEC_QUEUE_AR_FROCE_NOALLOC 1 2862306a36Sopenharmony_ci#define SEC_QUEUE_AR_FROCE_DIS 2 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define SEC_QUEUE_AW_FROCE_ALLOC 0 3162306a36Sopenharmony_ci#define SEC_QUEUE_AW_FROCE_NOALLOC 1 3262306a36Sopenharmony_ci#define SEC_QUEUE_AW_FROCE_DIS 2 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* SEC_ALGSUB registers */ 3562306a36Sopenharmony_ci#define SEC_ALGSUB_CLK_EN_REG 0x03b8 3662306a36Sopenharmony_ci#define SEC_ALGSUB_CLK_DIS_REG 0x03bc 3762306a36Sopenharmony_ci#define SEC_ALGSUB_CLK_ST_REG 0x535c 3862306a36Sopenharmony_ci#define SEC_ALGSUB_RST_REQ_REG 0x0aa8 3962306a36Sopenharmony_ci#define SEC_ALGSUB_RST_DREQ_REG 0x0aac 4062306a36Sopenharmony_ci#define SEC_ALGSUB_RST_ST_REG 0x5a54 4162306a36Sopenharmony_ci#define SEC_ALGSUB_RST_ST_IS_RST BIT(0) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define SEC_ALGSUB_BUILD_RST_REQ_REG 0x0ab8 4462306a36Sopenharmony_ci#define SEC_ALGSUB_BUILD_RST_DREQ_REG 0x0abc 4562306a36Sopenharmony_ci#define SEC_ALGSUB_BUILD_RST_ST_REG 0x5a5c 4662306a36Sopenharmony_ci#define SEC_ALGSUB_BUILD_RST_ST_IS_RST BIT(0) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define SEC_SAA_BASE 0x00001000UL 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* SEC_SAA registers */ 5162306a36Sopenharmony_ci#define SEC_SAA_CTRL_REG(x) ((x) * SEC_SAA_ADDR_SIZE) 5262306a36Sopenharmony_ci#define SEC_SAA_CTRL_GET_QM_EN BIT(0) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define SEC_ST_INTMSK1_REG 0x0200 5562306a36Sopenharmony_ci#define SEC_ST_RINT1_REG 0x0400 5662306a36Sopenharmony_ci#define SEC_ST_INTSTS1_REG 0x0600 5762306a36Sopenharmony_ci#define SEC_BD_MNG_STAT_REG 0x0800 5862306a36Sopenharmony_ci#define SEC_PARSING_STAT_REG 0x0804 5962306a36Sopenharmony_ci#define SEC_LOAD_TIME_OUT_CNT_REG 0x0808 6062306a36Sopenharmony_ci#define SEC_CORE_WORK_TIME_OUT_CNT_REG 0x080c 6162306a36Sopenharmony_ci#define SEC_BACK_TIME_OUT_CNT_REG 0x0810 6262306a36Sopenharmony_ci#define SEC_BD1_PARSING_RD_TIME_OUT_CNT_REG 0x0814 6362306a36Sopenharmony_ci#define SEC_BD1_PARSING_WR_TIME_OUT_CNT_REG 0x0818 6462306a36Sopenharmony_ci#define SEC_BD2_PARSING_RD_TIME_OUT_CNT_REG 0x081c 6562306a36Sopenharmony_ci#define SEC_BD2_PARSING_WR_TIME_OUT_CNT_REG 0x0820 6662306a36Sopenharmony_ci#define SEC_SAA_ACC_REG 0x083c 6762306a36Sopenharmony_ci#define SEC_BD_NUM_CNT_IN_SEC_REG 0x0858 6862306a36Sopenharmony_ci#define SEC_LOAD_WORK_TIME_CNT_REG 0x0860 6962306a36Sopenharmony_ci#define SEC_CORE_WORK_WORK_TIME_CNT_REG 0x0864 7062306a36Sopenharmony_ci#define SEC_BACK_WORK_TIME_CNT_REG 0x0868 7162306a36Sopenharmony_ci#define SEC_SAA_IDLE_TIME_CNT_REG 0x086c 7262306a36Sopenharmony_ci#define SEC_SAA_CLK_CNT_REG 0x0870 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* SEC_COMMON registers */ 7562306a36Sopenharmony_ci#define SEC_CLK_EN_REG 0x0000 7662306a36Sopenharmony_ci#define SEC_CTRL_REG 0x0004 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define SEC_COMMON_CNT_CLR_CE_REG 0x0008 7962306a36Sopenharmony_ci#define SEC_COMMON_CNT_CLR_CE_CLEAR BIT(0) 8062306a36Sopenharmony_ci#define SEC_COMMON_CNT_CLR_CE_SNAP_EN BIT(1) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define SEC_SECURE_CTRL_REG 0x000c 8362306a36Sopenharmony_ci#define SEC_AXI_CACHE_CFG_REG 0x0010 8462306a36Sopenharmony_ci#define SEC_AXI_QOS_CFG_REG 0x0014 8562306a36Sopenharmony_ci#define SEC_IPV4_MASK_TABLE_REG 0x0020 8662306a36Sopenharmony_ci#define SEC_IPV6_MASK_TABLE_X_REG(x) (0x0024 + (x) * 4) 8762306a36Sopenharmony_ci#define SEC_FSM_MAX_CNT_REG 0x0064 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define SEC_CTRL2_REG 0x0068 9062306a36Sopenharmony_ci#define SEC_CTRL2_DATA_AXI_RD_OTSD_CFG_M GENMASK(3, 0) 9162306a36Sopenharmony_ci#define SEC_CTRL2_DATA_AXI_RD_OTSD_CFG_S 0 9262306a36Sopenharmony_ci#define SEC_CTRL2_DATA_AXI_WR_OTSD_CFG_M GENMASK(6, 4) 9362306a36Sopenharmony_ci#define SEC_CTRL2_DATA_AXI_WR_OTSD_CFG_S 4 9462306a36Sopenharmony_ci#define SEC_CTRL2_CLK_GATE_EN BIT(7) 9562306a36Sopenharmony_ci#define SEC_CTRL2_ENDIAN_BD BIT(8) 9662306a36Sopenharmony_ci#define SEC_CTRL2_ENDIAN_BD_TYPE BIT(9) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define SEC_CNT_PRECISION_CFG_REG 0x006c 9962306a36Sopenharmony_ci#define SEC_DEBUG_BD_CFG_REG 0x0070 10062306a36Sopenharmony_ci#define SEC_DEBUG_BD_CFG_WB_NORMAL BIT(0) 10162306a36Sopenharmony_ci#define SEC_DEBUG_BD_CFG_WB_EN BIT(1) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define SEC_Q_SIGHT_SEL 0x0074 10462306a36Sopenharmony_ci#define SEC_Q_SIGHT_HIS_CLR 0x0078 10562306a36Sopenharmony_ci#define SEC_Q_VMID_CFG_REG(q) (0x0100 + (q) * 4) 10662306a36Sopenharmony_ci#define SEC_Q_WEIGHT_CFG_REG(q) (0x200 + (q) * 4) 10762306a36Sopenharmony_ci#define SEC_STAT_CLR_REG 0x0a00 10862306a36Sopenharmony_ci#define SEC_SAA_IDLE_CNT_CLR_REG 0x0a04 10962306a36Sopenharmony_ci#define SEC_QM_CPL_Q_IDBUF_DFX_CFG_REG 0x0b00 11062306a36Sopenharmony_ci#define SEC_QM_CPL_Q_IDBUF_DFX_RESULT_REG 0x0b04 11162306a36Sopenharmony_ci#define SEC_QM_BD_DFX_CFG_REG 0x0b08 11262306a36Sopenharmony_ci#define SEC_QM_BD_DFX_RESULT_REG 0x0b0c 11362306a36Sopenharmony_ci#define SEC_QM_BDID_DFX_RESULT_REG 0x0b10 11462306a36Sopenharmony_ci#define SEC_QM_BD_DFIFO_STATUS_REG 0x0b14 11562306a36Sopenharmony_ci#define SEC_QM_BD_DFX_CFG2_REG 0x0b1c 11662306a36Sopenharmony_ci#define SEC_QM_BD_DFX_RESULT2_REG 0x0b20 11762306a36Sopenharmony_ci#define SEC_QM_BD_IDFIFO_STATUS_REG 0x0b18 11862306a36Sopenharmony_ci#define SEC_QM_BD_DFIFO_STATUS2_REG 0x0b28 11962306a36Sopenharmony_ci#define SEC_QM_BD_IDFIFO_STATUS2_REG 0x0b2c 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define SEC_HASH_IPV4_MASK 0xfff00000 12262306a36Sopenharmony_ci#define SEC_MAX_SAA_NUM 0xa 12362306a36Sopenharmony_ci#define SEC_SAA_ADDR_SIZE 0x1000 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define SEC_Q_INIT_REG 0x0 12662306a36Sopenharmony_ci#define SEC_Q_INIT_WO_STAT_CLEAR 0x2 12762306a36Sopenharmony_ci#define SEC_Q_INIT_AND_STAT_CLEAR 0x3 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define SEC_Q_CFG_REG 0x8 13062306a36Sopenharmony_ci#define SEC_Q_CFG_REORDER BIT(0) 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define SEC_Q_PROC_NUM_CFG_REG 0x10 13362306a36Sopenharmony_ci#define SEC_QUEUE_ENB_REG 0x18 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define SEC_Q_DEPTH_CFG_REG 0x50 13662306a36Sopenharmony_ci#define SEC_Q_DEPTH_CFG_DEPTH_M GENMASK(11, 0) 13762306a36Sopenharmony_ci#define SEC_Q_DEPTH_CFG_DEPTH_S 0 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define SEC_Q_BASE_HADDR_REG 0x54 14062306a36Sopenharmony_ci#define SEC_Q_BASE_LADDR_REG 0x58 14162306a36Sopenharmony_ci#define SEC_Q_WR_PTR_REG 0x5c 14262306a36Sopenharmony_ci#define SEC_Q_OUTORDER_BASE_HADDR_REG 0x60 14362306a36Sopenharmony_ci#define SEC_Q_OUTORDER_BASE_LADDR_REG 0x64 14462306a36Sopenharmony_ci#define SEC_Q_OUTORDER_RD_PTR_REG 0x68 14562306a36Sopenharmony_ci#define SEC_Q_OT_TH_REG 0x6c 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define SEC_Q_ARUSER_CFG_REG 0x70 14862306a36Sopenharmony_ci#define SEC_Q_ARUSER_CFG_FA BIT(0) 14962306a36Sopenharmony_ci#define SEC_Q_ARUSER_CFG_FNA BIT(1) 15062306a36Sopenharmony_ci#define SEC_Q_ARUSER_CFG_RINVLD BIT(2) 15162306a36Sopenharmony_ci#define SEC_Q_ARUSER_CFG_PKG BIT(3) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define SEC_Q_AWUSER_CFG_REG 0x74 15462306a36Sopenharmony_ci#define SEC_Q_AWUSER_CFG_FA BIT(0) 15562306a36Sopenharmony_ci#define SEC_Q_AWUSER_CFG_FNA BIT(1) 15662306a36Sopenharmony_ci#define SEC_Q_AWUSER_CFG_PKG BIT(2) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define SEC_Q_ERR_BASE_HADDR_REG 0x7c 15962306a36Sopenharmony_ci#define SEC_Q_ERR_BASE_LADDR_REG 0x80 16062306a36Sopenharmony_ci#define SEC_Q_CFG_VF_NUM_REG 0x84 16162306a36Sopenharmony_ci#define SEC_Q_SOFT_PROC_PTR_REG 0x88 16262306a36Sopenharmony_ci#define SEC_Q_FAIL_INT_MSK_REG 0x300 16362306a36Sopenharmony_ci#define SEC_Q_FLOW_INT_MKS_REG 0x304 16462306a36Sopenharmony_ci#define SEC_Q_FAIL_RINT_REG 0x400 16562306a36Sopenharmony_ci#define SEC_Q_FLOW_RINT_REG 0x404 16662306a36Sopenharmony_ci#define SEC_Q_FAIL_INT_STATUS_REG 0x500 16762306a36Sopenharmony_ci#define SEC_Q_FLOW_INT_STATUS_REG 0x504 16862306a36Sopenharmony_ci#define SEC_Q_STATUS_REG 0x600 16962306a36Sopenharmony_ci#define SEC_Q_RD_PTR_REG 0x604 17062306a36Sopenharmony_ci#define SEC_Q_PRO_PTR_REG 0x608 17162306a36Sopenharmony_ci#define SEC_Q_OUTORDER_WR_PTR_REG 0x60c 17262306a36Sopenharmony_ci#define SEC_Q_OT_CNT_STATUS_REG 0x610 17362306a36Sopenharmony_ci#define SEC_Q_INORDER_BD_NUM_ST_REG 0x650 17462306a36Sopenharmony_ci#define SEC_Q_INORDER_GET_FLAG_ST_REG 0x654 17562306a36Sopenharmony_ci#define SEC_Q_INORDER_ADD_FLAG_ST_REG 0x658 17662306a36Sopenharmony_ci#define SEC_Q_INORDER_TASK_INT_NUM_LEFT_ST_REG 0x65c 17762306a36Sopenharmony_ci#define SEC_Q_RD_DONE_PTR_REG 0x660 17862306a36Sopenharmony_ci#define SEC_Q_CPL_Q_BD_NUM_ST_REG 0x700 17962306a36Sopenharmony_ci#define SEC_Q_CPL_Q_PTR_ST_REG 0x704 18062306a36Sopenharmony_ci#define SEC_Q_CPL_Q_H_ADDR_ST_REG 0x708 18162306a36Sopenharmony_ci#define SEC_Q_CPL_Q_L_ADDR_ST_REG 0x70c 18262306a36Sopenharmony_ci#define SEC_Q_CPL_TASK_INT_NUM_LEFT_ST_REG 0x710 18362306a36Sopenharmony_ci#define SEC_Q_WRR_ID_CHECK_REG 0x714 18462306a36Sopenharmony_ci#define SEC_Q_CPLQ_FULL_CHECK_REG 0x718 18562306a36Sopenharmony_ci#define SEC_Q_SUCCESS_BD_CNT_REG 0x800 18662306a36Sopenharmony_ci#define SEC_Q_FAIL_BD_CNT_REG 0x804 18762306a36Sopenharmony_ci#define SEC_Q_GET_BD_CNT_REG 0x808 18862306a36Sopenharmony_ci#define SEC_Q_IVLD_CNT_REG 0x80c 18962306a36Sopenharmony_ci#define SEC_Q_BD_PROC_GET_CNT_REG 0x810 19062306a36Sopenharmony_ci#define SEC_Q_BD_PROC_DONE_CNT_REG 0x814 19162306a36Sopenharmony_ci#define SEC_Q_LAT_CLR_REG 0x850 19262306a36Sopenharmony_ci#define SEC_Q_PKT_LAT_MAX_REG 0x854 19362306a36Sopenharmony_ci#define SEC_Q_PKT_LAT_AVG_REG 0x858 19462306a36Sopenharmony_ci#define SEC_Q_PKT_LAT_MIN_REG 0x85c 19562306a36Sopenharmony_ci#define SEC_Q_ID_CLR_CFG_REG 0x900 19662306a36Sopenharmony_ci#define SEC_Q_1ST_BD_ERR_ID_REG 0x904 19762306a36Sopenharmony_ci#define SEC_Q_1ST_AUTH_FAIL_ID_REG 0x908 19862306a36Sopenharmony_ci#define SEC_Q_1ST_RD_ERR_ID_REG 0x90c 19962306a36Sopenharmony_ci#define SEC_Q_1ST_ECC2_ERR_ID_REG 0x910 20062306a36Sopenharmony_ci#define SEC_Q_1ST_IVLD_ID_REG 0x914 20162306a36Sopenharmony_ci#define SEC_Q_1ST_BD_WR_ERR_ID_REG 0x918 20262306a36Sopenharmony_ci#define SEC_Q_1ST_ERR_BD_WR_ERR_ID_REG 0x91c 20362306a36Sopenharmony_ci#define SEC_Q_1ST_BD_MAC_WR_ERR_ID_REG 0x920 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistruct sec_debug_bd_info { 20662306a36Sopenharmony_ci#define SEC_DEBUG_BD_INFO_SOFT_ERR_CHECK_M GENMASK(22, 0) 20762306a36Sopenharmony_ci u32 soft_err_check; 20862306a36Sopenharmony_ci#define SEC_DEBUG_BD_INFO_HARD_ERR_CHECK_M GENMASK(9, 0) 20962306a36Sopenharmony_ci u32 hard_err_check; 21062306a36Sopenharmony_ci u32 icv_mac1st_word; 21162306a36Sopenharmony_ci#define SEC_DEBUG_BD_INFO_GET_ID_M GENMASK(19, 0) 21262306a36Sopenharmony_ci u32 sec_get_id; 21362306a36Sopenharmony_ci /* W4---W15 */ 21462306a36Sopenharmony_ci u32 reserv_left[12]; 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistruct sec_out_bd_info { 21862306a36Sopenharmony_ci#define SEC_OUT_BD_INFO_Q_ID_M GENMASK(11, 0) 21962306a36Sopenharmony_ci#define SEC_OUT_BD_INFO_ECC_2BIT_ERR BIT(14) 22062306a36Sopenharmony_ci u16 data; 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define SEC_MAX_DEVICES 8 22462306a36Sopenharmony_cistatic struct sec_dev_info *sec_devices[SEC_MAX_DEVICES]; 22562306a36Sopenharmony_cistatic DEFINE_MUTEX(sec_id_lock); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int sec_queue_map_io(struct sec_queue *queue) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct device *dev = queue->dev_info->dev; 23062306a36Sopenharmony_ci struct resource *res; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci res = platform_get_resource(to_platform_device(dev), 23362306a36Sopenharmony_ci IORESOURCE_MEM, 23462306a36Sopenharmony_ci 2 + queue->queue_id); 23562306a36Sopenharmony_ci if (!res) { 23662306a36Sopenharmony_ci dev_err(dev, "Failed to get queue %u memory resource\n", 23762306a36Sopenharmony_ci queue->queue_id); 23862306a36Sopenharmony_ci return -ENOMEM; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci queue->regs = ioremap(res->start, resource_size(res)); 24162306a36Sopenharmony_ci if (!queue->regs) 24262306a36Sopenharmony_ci return -ENOMEM; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void sec_queue_unmap_io(struct sec_queue *queue) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci iounmap(queue->regs); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int sec_queue_ar_pkgattr(struct sec_queue *queue, u32 ar_pkg) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci void __iomem *addr = queue->regs + SEC_Q_ARUSER_CFG_REG; 25562306a36Sopenharmony_ci u32 regval; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci regval = readl_relaxed(addr); 25862306a36Sopenharmony_ci if (ar_pkg) 25962306a36Sopenharmony_ci regval |= SEC_Q_ARUSER_CFG_PKG; 26062306a36Sopenharmony_ci else 26162306a36Sopenharmony_ci regval &= ~SEC_Q_ARUSER_CFG_PKG; 26262306a36Sopenharmony_ci writel_relaxed(regval, addr); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int sec_queue_aw_pkgattr(struct sec_queue *queue, u32 aw_pkg) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci void __iomem *addr = queue->regs + SEC_Q_AWUSER_CFG_REG; 27062306a36Sopenharmony_ci u32 regval; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci regval = readl_relaxed(addr); 27362306a36Sopenharmony_ci regval |= SEC_Q_AWUSER_CFG_PKG; 27462306a36Sopenharmony_ci writel_relaxed(regval, addr); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int sec_clk_en(struct sec_dev_info *info) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci void __iomem *base = info->regs[SEC_COMMON]; 28262306a36Sopenharmony_ci u32 i = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci writel_relaxed(0x7, base + SEC_ALGSUB_CLK_EN_REG); 28562306a36Sopenharmony_ci do { 28662306a36Sopenharmony_ci usleep_range(1000, 10000); 28762306a36Sopenharmony_ci if ((readl_relaxed(base + SEC_ALGSUB_CLK_ST_REG) & 0x7) == 0x7) 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci i++; 29062306a36Sopenharmony_ci } while (i < 10); 29162306a36Sopenharmony_ci dev_err(info->dev, "sec clock enable fail!\n"); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return -EIO; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int sec_clk_dis(struct sec_dev_info *info) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci void __iomem *base = info->regs[SEC_COMMON]; 29962306a36Sopenharmony_ci u32 i = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci writel_relaxed(0x7, base + SEC_ALGSUB_CLK_DIS_REG); 30262306a36Sopenharmony_ci do { 30362306a36Sopenharmony_ci usleep_range(1000, 10000); 30462306a36Sopenharmony_ci if ((readl_relaxed(base + SEC_ALGSUB_CLK_ST_REG) & 0x7) == 0) 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci i++; 30762306a36Sopenharmony_ci } while (i < 10); 30862306a36Sopenharmony_ci dev_err(info->dev, "sec clock disable fail!\n"); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return -EIO; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int sec_reset_whole_module(struct sec_dev_info *info) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci void __iomem *base = info->regs[SEC_COMMON]; 31662306a36Sopenharmony_ci bool is_reset, b_is_reset; 31762306a36Sopenharmony_ci u32 i = 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci writel_relaxed(1, base + SEC_ALGSUB_RST_REQ_REG); 32062306a36Sopenharmony_ci writel_relaxed(1, base + SEC_ALGSUB_BUILD_RST_REQ_REG); 32162306a36Sopenharmony_ci while (1) { 32262306a36Sopenharmony_ci usleep_range(1000, 10000); 32362306a36Sopenharmony_ci is_reset = readl_relaxed(base + SEC_ALGSUB_RST_ST_REG) & 32462306a36Sopenharmony_ci SEC_ALGSUB_RST_ST_IS_RST; 32562306a36Sopenharmony_ci b_is_reset = readl_relaxed(base + SEC_ALGSUB_BUILD_RST_ST_REG) & 32662306a36Sopenharmony_ci SEC_ALGSUB_BUILD_RST_ST_IS_RST; 32762306a36Sopenharmony_ci if (is_reset && b_is_reset) 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci i++; 33062306a36Sopenharmony_ci if (i > 10) { 33162306a36Sopenharmony_ci dev_err(info->dev, "Reset req failed\n"); 33262306a36Sopenharmony_ci return -EIO; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci i = 0; 33762306a36Sopenharmony_ci writel_relaxed(1, base + SEC_ALGSUB_RST_DREQ_REG); 33862306a36Sopenharmony_ci writel_relaxed(1, base + SEC_ALGSUB_BUILD_RST_DREQ_REG); 33962306a36Sopenharmony_ci while (1) { 34062306a36Sopenharmony_ci usleep_range(1000, 10000); 34162306a36Sopenharmony_ci is_reset = readl_relaxed(base + SEC_ALGSUB_RST_ST_REG) & 34262306a36Sopenharmony_ci SEC_ALGSUB_RST_ST_IS_RST; 34362306a36Sopenharmony_ci b_is_reset = readl_relaxed(base + SEC_ALGSUB_BUILD_RST_ST_REG) & 34462306a36Sopenharmony_ci SEC_ALGSUB_BUILD_RST_ST_IS_RST; 34562306a36Sopenharmony_ci if (!is_reset && !b_is_reset) 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci i++; 34962306a36Sopenharmony_ci if (i > 10) { 35062306a36Sopenharmony_ci dev_err(info->dev, "Reset dreq failed\n"); 35162306a36Sopenharmony_ci return -EIO; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void sec_bd_endian_little(struct sec_dev_info *info) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_CTRL2_REG; 36162306a36Sopenharmony_ci u32 regval; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci regval = readl_relaxed(addr); 36462306a36Sopenharmony_ci regval &= ~(SEC_CTRL2_ENDIAN_BD | SEC_CTRL2_ENDIAN_BD_TYPE); 36562306a36Sopenharmony_ci writel_relaxed(regval, addr); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/* 36962306a36Sopenharmony_ci * sec_cache_config - configure optimum cache placement 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_cistatic void sec_cache_config(struct sec_dev_info *info) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct iommu_domain *domain; 37462306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_CTRL_REG; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci domain = iommu_get_domain_for_dev(info->dev); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* Check that translation is occurring */ 37962306a36Sopenharmony_ci if (domain && (domain->type & __IOMMU_DOMAIN_PAGING)) 38062306a36Sopenharmony_ci writel_relaxed(0x44cf9e, addr); 38162306a36Sopenharmony_ci else 38262306a36Sopenharmony_ci writel_relaxed(0x4cfd9, addr); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic void sec_data_axiwr_otsd_cfg(struct sec_dev_info *info, u32 cfg) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_CTRL2_REG; 38862306a36Sopenharmony_ci u32 regval; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci regval = readl_relaxed(addr); 39162306a36Sopenharmony_ci regval &= ~SEC_CTRL2_DATA_AXI_WR_OTSD_CFG_M; 39262306a36Sopenharmony_ci regval |= (cfg << SEC_CTRL2_DATA_AXI_WR_OTSD_CFG_S) & 39362306a36Sopenharmony_ci SEC_CTRL2_DATA_AXI_WR_OTSD_CFG_M; 39462306a36Sopenharmony_ci writel_relaxed(regval, addr); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic void sec_data_axird_otsd_cfg(struct sec_dev_info *info, u32 cfg) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_CTRL2_REG; 40062306a36Sopenharmony_ci u32 regval; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci regval = readl_relaxed(addr); 40362306a36Sopenharmony_ci regval &= ~SEC_CTRL2_DATA_AXI_RD_OTSD_CFG_M; 40462306a36Sopenharmony_ci regval |= (cfg << SEC_CTRL2_DATA_AXI_RD_OTSD_CFG_S) & 40562306a36Sopenharmony_ci SEC_CTRL2_DATA_AXI_RD_OTSD_CFG_M; 40662306a36Sopenharmony_ci writel_relaxed(regval, addr); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void sec_clk_gate_en(struct sec_dev_info *info, bool clkgate) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_CTRL2_REG; 41262306a36Sopenharmony_ci u32 regval; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci regval = readl_relaxed(addr); 41562306a36Sopenharmony_ci if (clkgate) 41662306a36Sopenharmony_ci regval |= SEC_CTRL2_CLK_GATE_EN; 41762306a36Sopenharmony_ci else 41862306a36Sopenharmony_ci regval &= ~SEC_CTRL2_CLK_GATE_EN; 41962306a36Sopenharmony_ci writel_relaxed(regval, addr); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic void sec_comm_cnt_cfg(struct sec_dev_info *info, bool clr_ce) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_COMMON_CNT_CLR_CE_REG; 42562306a36Sopenharmony_ci u32 regval; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci regval = readl_relaxed(addr); 42862306a36Sopenharmony_ci if (clr_ce) 42962306a36Sopenharmony_ci regval |= SEC_COMMON_CNT_CLR_CE_CLEAR; 43062306a36Sopenharmony_ci else 43162306a36Sopenharmony_ci regval &= ~SEC_COMMON_CNT_CLR_CE_CLEAR; 43262306a36Sopenharmony_ci writel_relaxed(regval, addr); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic void sec_commsnap_en(struct sec_dev_info *info, bool snap_en) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_COMMON_CNT_CLR_CE_REG; 43862306a36Sopenharmony_ci u32 regval; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci regval = readl_relaxed(addr); 44162306a36Sopenharmony_ci if (snap_en) 44262306a36Sopenharmony_ci regval |= SEC_COMMON_CNT_CLR_CE_SNAP_EN; 44362306a36Sopenharmony_ci else 44462306a36Sopenharmony_ci regval &= ~SEC_COMMON_CNT_CLR_CE_SNAP_EN; 44562306a36Sopenharmony_ci writel_relaxed(regval, addr); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void sec_ipv6_hashmask(struct sec_dev_info *info, u32 hash_mask[]) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci void __iomem *base = info->regs[SEC_SAA]; 45162306a36Sopenharmony_ci int i; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci for (i = 0; i < 10; i++) 45462306a36Sopenharmony_ci writel_relaxed(hash_mask[0], 45562306a36Sopenharmony_ci base + SEC_IPV6_MASK_TABLE_X_REG(i)); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int sec_ipv4_hashmask(struct sec_dev_info *info, u32 hash_mask) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci if (hash_mask & SEC_HASH_IPV4_MASK) { 46162306a36Sopenharmony_ci dev_err(info->dev, "Sec Ipv4 Hash Mask Input Error!\n "); 46262306a36Sopenharmony_ci return -EINVAL; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci writel_relaxed(hash_mask, 46662306a36Sopenharmony_ci info->regs[SEC_SAA] + SEC_IPV4_MASK_TABLE_REG); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic void sec_set_dbg_bd_cfg(struct sec_dev_info *info, u32 cfg) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_DEBUG_BD_CFG_REG; 47462306a36Sopenharmony_ci u32 regval; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci regval = readl_relaxed(addr); 47762306a36Sopenharmony_ci /* Always disable write back of normal bd */ 47862306a36Sopenharmony_ci regval &= ~SEC_DEBUG_BD_CFG_WB_NORMAL; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (cfg) 48162306a36Sopenharmony_ci regval &= ~SEC_DEBUG_BD_CFG_WB_EN; 48262306a36Sopenharmony_ci else 48362306a36Sopenharmony_ci regval |= SEC_DEBUG_BD_CFG_WB_EN; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci writel_relaxed(regval, addr); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic void sec_saa_getqm_en(struct sec_dev_info *info, u32 saa_indx, u32 en) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci void __iomem *addr = info->regs[SEC_SAA] + SEC_SAA_BASE + 49162306a36Sopenharmony_ci SEC_SAA_CTRL_REG(saa_indx); 49262306a36Sopenharmony_ci u32 regval; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci regval = readl_relaxed(addr); 49562306a36Sopenharmony_ci if (en) 49662306a36Sopenharmony_ci regval |= SEC_SAA_CTRL_GET_QM_EN; 49762306a36Sopenharmony_ci else 49862306a36Sopenharmony_ci regval &= ~SEC_SAA_CTRL_GET_QM_EN; 49962306a36Sopenharmony_ci writel_relaxed(regval, addr); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void sec_saa_int_mask(struct sec_dev_info *info, u32 saa_indx, 50362306a36Sopenharmony_ci u32 saa_int_mask) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci writel_relaxed(saa_int_mask, 50662306a36Sopenharmony_ci info->regs[SEC_SAA] + SEC_SAA_BASE + SEC_ST_INTMSK1_REG + 50762306a36Sopenharmony_ci saa_indx * SEC_SAA_ADDR_SIZE); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void sec_streamid(struct sec_dev_info *info, int i) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci #define SEC_SID 0x600 51362306a36Sopenharmony_ci #define SEC_VMID 0 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci writel_relaxed((SEC_VMID | ((SEC_SID & 0xffff) << 8)), 51662306a36Sopenharmony_ci info->regs[SEC_SAA] + SEC_Q_VMID_CFG_REG(i)); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic void sec_queue_ar_alloc(struct sec_queue *queue, u32 alloc) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci void __iomem *addr = queue->regs + SEC_Q_ARUSER_CFG_REG; 52262306a36Sopenharmony_ci u32 regval; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci regval = readl_relaxed(addr); 52562306a36Sopenharmony_ci if (alloc == SEC_QUEUE_AR_FROCE_ALLOC) { 52662306a36Sopenharmony_ci regval |= SEC_Q_ARUSER_CFG_FA; 52762306a36Sopenharmony_ci regval &= ~SEC_Q_ARUSER_CFG_FNA; 52862306a36Sopenharmony_ci } else { 52962306a36Sopenharmony_ci regval &= ~SEC_Q_ARUSER_CFG_FA; 53062306a36Sopenharmony_ci regval |= SEC_Q_ARUSER_CFG_FNA; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci writel_relaxed(regval, addr); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic void sec_queue_aw_alloc(struct sec_queue *queue, u32 alloc) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci void __iomem *addr = queue->regs + SEC_Q_AWUSER_CFG_REG; 53962306a36Sopenharmony_ci u32 regval; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci regval = readl_relaxed(addr); 54262306a36Sopenharmony_ci if (alloc == SEC_QUEUE_AW_FROCE_ALLOC) { 54362306a36Sopenharmony_ci regval |= SEC_Q_AWUSER_CFG_FA; 54462306a36Sopenharmony_ci regval &= ~SEC_Q_AWUSER_CFG_FNA; 54562306a36Sopenharmony_ci } else { 54662306a36Sopenharmony_ci regval &= ~SEC_Q_AWUSER_CFG_FA; 54762306a36Sopenharmony_ci regval |= SEC_Q_AWUSER_CFG_FNA; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci writel_relaxed(regval, addr); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic void sec_queue_reorder(struct sec_queue *queue, bool reorder) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci void __iomem *base = queue->regs; 55662306a36Sopenharmony_ci u32 regval; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci regval = readl_relaxed(base + SEC_Q_CFG_REG); 55962306a36Sopenharmony_ci if (reorder) 56062306a36Sopenharmony_ci regval |= SEC_Q_CFG_REORDER; 56162306a36Sopenharmony_ci else 56262306a36Sopenharmony_ci regval &= ~SEC_Q_CFG_REORDER; 56362306a36Sopenharmony_ci writel_relaxed(regval, base + SEC_Q_CFG_REG); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void sec_queue_depth(struct sec_queue *queue, u32 depth) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci void __iomem *addr = queue->regs + SEC_Q_DEPTH_CFG_REG; 56962306a36Sopenharmony_ci u32 regval; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci regval = readl_relaxed(addr); 57262306a36Sopenharmony_ci regval &= ~SEC_Q_DEPTH_CFG_DEPTH_M; 57362306a36Sopenharmony_ci regval |= (depth << SEC_Q_DEPTH_CFG_DEPTH_S) & SEC_Q_DEPTH_CFG_DEPTH_M; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci writel_relaxed(regval, addr); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic void sec_queue_cmdbase_addr(struct sec_queue *queue, u64 addr) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci writel_relaxed(upper_32_bits(addr), queue->regs + SEC_Q_BASE_HADDR_REG); 58162306a36Sopenharmony_ci writel_relaxed(lower_32_bits(addr), queue->regs + SEC_Q_BASE_LADDR_REG); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic void sec_queue_outorder_addr(struct sec_queue *queue, u64 addr) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci writel_relaxed(upper_32_bits(addr), 58762306a36Sopenharmony_ci queue->regs + SEC_Q_OUTORDER_BASE_HADDR_REG); 58862306a36Sopenharmony_ci writel_relaxed(lower_32_bits(addr), 58962306a36Sopenharmony_ci queue->regs + SEC_Q_OUTORDER_BASE_LADDR_REG); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic void sec_queue_errbase_addr(struct sec_queue *queue, u64 addr) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci writel_relaxed(upper_32_bits(addr), 59562306a36Sopenharmony_ci queue->regs + SEC_Q_ERR_BASE_HADDR_REG); 59662306a36Sopenharmony_ci writel_relaxed(lower_32_bits(addr), 59762306a36Sopenharmony_ci queue->regs + SEC_Q_ERR_BASE_LADDR_REG); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic void sec_queue_irq_disable(struct sec_queue *queue) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci writel_relaxed((u32)~0, queue->regs + SEC_Q_FLOW_INT_MKS_REG); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void sec_queue_irq_enable(struct sec_queue *queue) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci writel_relaxed(0, queue->regs + SEC_Q_FLOW_INT_MKS_REG); 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void sec_queue_abn_irq_disable(struct sec_queue *queue) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci writel_relaxed((u32)~0, queue->regs + SEC_Q_FAIL_INT_MSK_REG); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic void sec_queue_stop(struct sec_queue *queue) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci disable_irq(queue->task_irq); 61862306a36Sopenharmony_ci sec_queue_irq_disable(queue); 61962306a36Sopenharmony_ci writel_relaxed(0x0, queue->regs + SEC_QUEUE_ENB_REG); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic void sec_queue_start(struct sec_queue *queue) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci sec_queue_irq_enable(queue); 62562306a36Sopenharmony_ci enable_irq(queue->task_irq); 62662306a36Sopenharmony_ci queue->expected = 0; 62762306a36Sopenharmony_ci writel_relaxed(SEC_Q_INIT_AND_STAT_CLEAR, queue->regs + SEC_Q_INIT_REG); 62862306a36Sopenharmony_ci writel_relaxed(0x1, queue->regs + SEC_QUEUE_ENB_REG); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic struct sec_queue *sec_alloc_queue(struct sec_dev_info *info) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci int i; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci mutex_lock(&info->dev_lock); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Get the first idle queue in SEC device */ 63862306a36Sopenharmony_ci for (i = 0; i < SEC_Q_NUM; i++) 63962306a36Sopenharmony_ci if (!info->queues[i].in_use) { 64062306a36Sopenharmony_ci info->queues[i].in_use = true; 64162306a36Sopenharmony_ci info->queues_in_use++; 64262306a36Sopenharmony_ci mutex_unlock(&info->dev_lock); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return &info->queues[i]; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci mutex_unlock(&info->dev_lock); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int sec_queue_free(struct sec_queue *queue) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct sec_dev_info *info = queue->dev_info; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (queue->queue_id >= SEC_Q_NUM) { 65662306a36Sopenharmony_ci dev_err(info->dev, "No queue %u\n", queue->queue_id); 65762306a36Sopenharmony_ci return -ENODEV; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (!queue->in_use) { 66162306a36Sopenharmony_ci dev_err(info->dev, "Queue %u is idle\n", queue->queue_id); 66262306a36Sopenharmony_ci return -ENODEV; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci mutex_lock(&info->dev_lock); 66662306a36Sopenharmony_ci queue->in_use = false; 66762306a36Sopenharmony_ci info->queues_in_use--; 66862306a36Sopenharmony_ci mutex_unlock(&info->dev_lock); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic irqreturn_t sec_isr_handle_th(int irq, void *q) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci sec_queue_irq_disable(q); 67662306a36Sopenharmony_ci return IRQ_WAKE_THREAD; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic irqreturn_t sec_isr_handle(int irq, void *q) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct sec_queue *queue = q; 68262306a36Sopenharmony_ci struct sec_queue_ring_cmd *msg_ring = &queue->ring_cmd; 68362306a36Sopenharmony_ci struct sec_queue_ring_cq *cq_ring = &queue->ring_cq; 68462306a36Sopenharmony_ci struct sec_out_bd_info *outorder_msg; 68562306a36Sopenharmony_ci struct sec_bd_info *msg; 68662306a36Sopenharmony_ci u32 ooo_read, ooo_write; 68762306a36Sopenharmony_ci void __iomem *base = queue->regs; 68862306a36Sopenharmony_ci int q_id; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ooo_read = readl(base + SEC_Q_OUTORDER_RD_PTR_REG); 69162306a36Sopenharmony_ci ooo_write = readl(base + SEC_Q_OUTORDER_WR_PTR_REG); 69262306a36Sopenharmony_ci outorder_msg = cq_ring->vaddr + ooo_read; 69362306a36Sopenharmony_ci q_id = outorder_msg->data & SEC_OUT_BD_INFO_Q_ID_M; 69462306a36Sopenharmony_ci msg = msg_ring->vaddr + q_id; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci while ((ooo_write != ooo_read) && msg->w0 & SEC_BD_W0_DONE) { 69762306a36Sopenharmony_ci /* 69862306a36Sopenharmony_ci * Must be before callback otherwise blocks adding other chained 69962306a36Sopenharmony_ci * elements 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ci set_bit(q_id, queue->unprocessed); 70262306a36Sopenharmony_ci if (q_id == queue->expected) 70362306a36Sopenharmony_ci while (test_bit(queue->expected, queue->unprocessed)) { 70462306a36Sopenharmony_ci clear_bit(queue->expected, queue->unprocessed); 70562306a36Sopenharmony_ci msg = msg_ring->vaddr + queue->expected; 70662306a36Sopenharmony_ci msg->w0 &= ~SEC_BD_W0_DONE; 70762306a36Sopenharmony_ci msg_ring->callback(msg, 70862306a36Sopenharmony_ci queue->shadow[queue->expected]); 70962306a36Sopenharmony_ci queue->shadow[queue->expected] = NULL; 71062306a36Sopenharmony_ci queue->expected = (queue->expected + 1) % 71162306a36Sopenharmony_ci SEC_QUEUE_LEN; 71262306a36Sopenharmony_ci atomic_dec(&msg_ring->used); 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci ooo_read = (ooo_read + 1) % SEC_QUEUE_LEN; 71662306a36Sopenharmony_ci writel(ooo_read, base + SEC_Q_OUTORDER_RD_PTR_REG); 71762306a36Sopenharmony_ci ooo_write = readl(base + SEC_Q_OUTORDER_WR_PTR_REG); 71862306a36Sopenharmony_ci outorder_msg = cq_ring->vaddr + ooo_read; 71962306a36Sopenharmony_ci q_id = outorder_msg->data & SEC_OUT_BD_INFO_Q_ID_M; 72062306a36Sopenharmony_ci msg = msg_ring->vaddr + q_id; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci sec_queue_irq_enable(queue); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return IRQ_HANDLED; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int sec_queue_irq_init(struct sec_queue *queue) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct sec_dev_info *info = queue->dev_info; 73162306a36Sopenharmony_ci int irq = queue->task_irq; 73262306a36Sopenharmony_ci int ret; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci ret = request_threaded_irq(irq, sec_isr_handle_th, sec_isr_handle, 73562306a36Sopenharmony_ci IRQF_TRIGGER_RISING, queue->name, queue); 73662306a36Sopenharmony_ci if (ret) { 73762306a36Sopenharmony_ci dev_err(info->dev, "request irq(%d) failed %d\n", irq, ret); 73862306a36Sopenharmony_ci return ret; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci disable_irq(irq); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int sec_queue_irq_uninit(struct sec_queue *queue) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci free_irq(queue->task_irq, queue); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return 0; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic struct sec_dev_info *sec_device_get(void) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct sec_dev_info *sec_dev = NULL; 75562306a36Sopenharmony_ci struct sec_dev_info *this_sec_dev; 75662306a36Sopenharmony_ci int least_busy_n = SEC_Q_NUM + 1; 75762306a36Sopenharmony_ci int i; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* Find which one is least busy and use that first */ 76062306a36Sopenharmony_ci for (i = 0; i < SEC_MAX_DEVICES; i++) { 76162306a36Sopenharmony_ci this_sec_dev = sec_devices[i]; 76262306a36Sopenharmony_ci if (this_sec_dev && 76362306a36Sopenharmony_ci this_sec_dev->queues_in_use < least_busy_n) { 76462306a36Sopenharmony_ci least_busy_n = this_sec_dev->queues_in_use; 76562306a36Sopenharmony_ci sec_dev = this_sec_dev; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci return sec_dev; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic struct sec_queue *sec_queue_alloc_start(struct sec_dev_info *info) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct sec_queue *queue; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci queue = sec_alloc_queue(info); 77762306a36Sopenharmony_ci if (IS_ERR(queue)) { 77862306a36Sopenharmony_ci dev_err(info->dev, "alloc sec queue failed! %ld\n", 77962306a36Sopenharmony_ci PTR_ERR(queue)); 78062306a36Sopenharmony_ci return queue; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci sec_queue_start(queue); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return queue; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci/** 78962306a36Sopenharmony_ci * sec_queue_alloc_start_safe - get a hw queue from appropriate instance 79062306a36Sopenharmony_ci * 79162306a36Sopenharmony_ci * This function does extremely simplistic load balancing. It does not take into 79262306a36Sopenharmony_ci * account NUMA locality of the accelerator, or which cpu has requested the 79362306a36Sopenharmony_ci * queue. Future work may focus on optimizing this in order to improve full 79462306a36Sopenharmony_ci * machine throughput. 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_cistruct sec_queue *sec_queue_alloc_start_safe(void) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct sec_dev_info *info; 79962306a36Sopenharmony_ci struct sec_queue *queue = ERR_PTR(-ENODEV); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci mutex_lock(&sec_id_lock); 80262306a36Sopenharmony_ci info = sec_device_get(); 80362306a36Sopenharmony_ci if (!info) 80462306a36Sopenharmony_ci goto unlock; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci queue = sec_queue_alloc_start(info); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ciunlock: 80962306a36Sopenharmony_ci mutex_unlock(&sec_id_lock); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return queue; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci/** 81562306a36Sopenharmony_ci * sec_queue_stop_release() - free up a hw queue for reuse 81662306a36Sopenharmony_ci * @queue: The queue we are done with. 81762306a36Sopenharmony_ci * 81862306a36Sopenharmony_ci * This will stop the current queue, terminanting any transactions 81962306a36Sopenharmony_ci * that are inflight an return it to the pool of available hw queuess 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_ciint sec_queue_stop_release(struct sec_queue *queue) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct device *dev = queue->dev_info->dev; 82462306a36Sopenharmony_ci int ret; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci sec_queue_stop(queue); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci ret = sec_queue_free(queue); 82962306a36Sopenharmony_ci if (ret) 83062306a36Sopenharmony_ci dev_err(dev, "Releasing queue failed %d\n", ret); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci return ret; 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci/** 83662306a36Sopenharmony_ci * sec_queue_empty() - Is this hardware queue currently empty. 83762306a36Sopenharmony_ci * @queue: The queue to test 83862306a36Sopenharmony_ci * 83962306a36Sopenharmony_ci * We need to know if we have an empty queue for some of the chaining modes 84062306a36Sopenharmony_ci * as if it is not empty we may need to hold the message in a software queue 84162306a36Sopenharmony_ci * until the hw queue is drained. 84262306a36Sopenharmony_ci */ 84362306a36Sopenharmony_cibool sec_queue_empty(struct sec_queue *queue) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci struct sec_queue_ring_cmd *msg_ring = &queue->ring_cmd; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return !atomic_read(&msg_ring->used); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/** 85162306a36Sopenharmony_ci * sec_queue_send() - queue up a single operation in the hw queue 85262306a36Sopenharmony_ci * @queue: The queue in which to put the message 85362306a36Sopenharmony_ci * @msg: The message 85462306a36Sopenharmony_ci * @ctx: Context to be put in the shadow array and passed back to cb on result. 85562306a36Sopenharmony_ci * 85662306a36Sopenharmony_ci * This function will return -EAGAIN if the queue is currently full. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_ciint sec_queue_send(struct sec_queue *queue, struct sec_bd_info *msg, void *ctx) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct sec_queue_ring_cmd *msg_ring = &queue->ring_cmd; 86162306a36Sopenharmony_ci void __iomem *base = queue->regs; 86262306a36Sopenharmony_ci u32 write, read; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci mutex_lock(&msg_ring->lock); 86562306a36Sopenharmony_ci read = readl(base + SEC_Q_RD_PTR_REG); 86662306a36Sopenharmony_ci write = readl(base + SEC_Q_WR_PTR_REG); 86762306a36Sopenharmony_ci if (write == read && atomic_read(&msg_ring->used) == SEC_QUEUE_LEN) { 86862306a36Sopenharmony_ci mutex_unlock(&msg_ring->lock); 86962306a36Sopenharmony_ci return -EAGAIN; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci memcpy(msg_ring->vaddr + write, msg, sizeof(*msg)); 87262306a36Sopenharmony_ci queue->shadow[write] = ctx; 87362306a36Sopenharmony_ci write = (write + 1) % SEC_QUEUE_LEN; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Ensure content updated before queue advance */ 87662306a36Sopenharmony_ci wmb(); 87762306a36Sopenharmony_ci writel(write, base + SEC_Q_WR_PTR_REG); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci atomic_inc(&msg_ring->used); 88062306a36Sopenharmony_ci mutex_unlock(&msg_ring->lock); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cibool sec_queue_can_enqueue(struct sec_queue *queue, int num) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct sec_queue_ring_cmd *msg_ring = &queue->ring_cmd; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return SEC_QUEUE_LEN - atomic_read(&msg_ring->used) >= num; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic void sec_queue_hw_init(struct sec_queue *queue) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci sec_queue_ar_alloc(queue, SEC_QUEUE_AR_FROCE_NOALLOC); 89562306a36Sopenharmony_ci sec_queue_aw_alloc(queue, SEC_QUEUE_AW_FROCE_NOALLOC); 89662306a36Sopenharmony_ci sec_queue_ar_pkgattr(queue, 1); 89762306a36Sopenharmony_ci sec_queue_aw_pkgattr(queue, 1); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci /* Enable out of order queue */ 90062306a36Sopenharmony_ci sec_queue_reorder(queue, true); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* Interrupt after a single complete element */ 90362306a36Sopenharmony_ci writel_relaxed(1, queue->regs + SEC_Q_PROC_NUM_CFG_REG); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci sec_queue_depth(queue, SEC_QUEUE_LEN - 1); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci sec_queue_cmdbase_addr(queue, queue->ring_cmd.paddr); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci sec_queue_outorder_addr(queue, queue->ring_cq.paddr); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci sec_queue_errbase_addr(queue, queue->ring_db.paddr); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci writel_relaxed(0x100, queue->regs + SEC_Q_OT_TH_REG); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci sec_queue_abn_irq_disable(queue); 91662306a36Sopenharmony_ci sec_queue_irq_disable(queue); 91762306a36Sopenharmony_ci writel_relaxed(SEC_Q_INIT_AND_STAT_CLEAR, queue->regs + SEC_Q_INIT_REG); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic int sec_hw_init(struct sec_dev_info *info) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci struct iommu_domain *domain; 92362306a36Sopenharmony_ci u32 sec_ipv4_mask = 0; 92462306a36Sopenharmony_ci u32 sec_ipv6_mask[10] = {}; 92562306a36Sopenharmony_ci u32 i, ret; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci domain = iommu_get_domain_for_dev(info->dev); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* 93062306a36Sopenharmony_ci * Enable all available processing unit clocks. 93162306a36Sopenharmony_ci * Only the first cluster is usable with translations. 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_ci if (domain && (domain->type & __IOMMU_DOMAIN_PAGING)) 93462306a36Sopenharmony_ci info->num_saas = 5; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci else 93762306a36Sopenharmony_ci info->num_saas = 10; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci writel_relaxed(GENMASK(info->num_saas - 1, 0), 94062306a36Sopenharmony_ci info->regs[SEC_SAA] + SEC_CLK_EN_REG); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* 32 bit little endian */ 94362306a36Sopenharmony_ci sec_bd_endian_little(info); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci sec_cache_config(info); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* Data axi port write and read outstanding config as per datasheet */ 94862306a36Sopenharmony_ci sec_data_axiwr_otsd_cfg(info, 0x7); 94962306a36Sopenharmony_ci sec_data_axird_otsd_cfg(info, 0x7); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* Enable clock gating */ 95262306a36Sopenharmony_ci sec_clk_gate_en(info, true); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* Set CNT_CYC register not read clear */ 95562306a36Sopenharmony_ci sec_comm_cnt_cfg(info, false); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci /* Enable CNT_CYC */ 95862306a36Sopenharmony_ci sec_commsnap_en(info, false); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci writel_relaxed((u32)~0, info->regs[SEC_SAA] + SEC_FSM_MAX_CNT_REG); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ret = sec_ipv4_hashmask(info, sec_ipv4_mask); 96362306a36Sopenharmony_ci if (ret) { 96462306a36Sopenharmony_ci dev_err(info->dev, "Failed to set ipv4 hashmask %d\n", ret); 96562306a36Sopenharmony_ci return -EIO; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci sec_ipv6_hashmask(info, sec_ipv6_mask); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* do not use debug bd */ 97162306a36Sopenharmony_ci sec_set_dbg_bd_cfg(info, 0); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (domain && (domain->type & __IOMMU_DOMAIN_PAGING)) { 97462306a36Sopenharmony_ci for (i = 0; i < SEC_Q_NUM; i++) { 97562306a36Sopenharmony_ci sec_streamid(info, i); 97662306a36Sopenharmony_ci /* Same QoS for all queues */ 97762306a36Sopenharmony_ci writel_relaxed(0x3f, 97862306a36Sopenharmony_ci info->regs[SEC_SAA] + 97962306a36Sopenharmony_ci SEC_Q_WEIGHT_CFG_REG(i)); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci for (i = 0; i < info->num_saas; i++) { 98462306a36Sopenharmony_ci sec_saa_getqm_en(info, i, 1); 98562306a36Sopenharmony_ci sec_saa_int_mask(info, i, 0); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return 0; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void sec_hw_exit(struct sec_dev_info *info) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci int i; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci for (i = 0; i < SEC_MAX_SAA_NUM; i++) { 99662306a36Sopenharmony_ci sec_saa_int_mask(info, i, (u32)~0); 99762306a36Sopenharmony_ci sec_saa_getqm_en(info, i, 0); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic void sec_queue_base_init(struct sec_dev_info *info, 100262306a36Sopenharmony_ci struct sec_queue *queue, int queue_id) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci queue->dev_info = info; 100562306a36Sopenharmony_ci queue->queue_id = queue_id; 100662306a36Sopenharmony_ci snprintf(queue->name, sizeof(queue->name), 100762306a36Sopenharmony_ci "%s_%d", dev_name(info->dev), queue->queue_id); 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic int sec_map_io(struct sec_dev_info *info, struct platform_device *pdev) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci struct resource *res; 101362306a36Sopenharmony_ci int i; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci for (i = 0; i < SEC_NUM_ADDR_REGIONS; i++) { 101662306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, i); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (!res) { 101962306a36Sopenharmony_ci dev_err(info->dev, "Memory resource %d not found\n", i); 102062306a36Sopenharmony_ci return -EINVAL; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci info->regs[i] = devm_ioremap(info->dev, res->start, 102462306a36Sopenharmony_ci resource_size(res)); 102562306a36Sopenharmony_ci if (!info->regs[i]) { 102662306a36Sopenharmony_ci dev_err(info->dev, 102762306a36Sopenharmony_ci "Memory resource %d could not be remapped\n", 102862306a36Sopenharmony_ci i); 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci return 0; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic int sec_base_init(struct sec_dev_info *info, 103762306a36Sopenharmony_ci struct platform_device *pdev) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci int ret; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci ret = sec_map_io(info, pdev); 104262306a36Sopenharmony_ci if (ret) 104362306a36Sopenharmony_ci return ret; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci ret = sec_clk_en(info); 104662306a36Sopenharmony_ci if (ret) 104762306a36Sopenharmony_ci return ret; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci ret = sec_reset_whole_module(info); 105062306a36Sopenharmony_ci if (ret) 105162306a36Sopenharmony_ci goto sec_clk_disable; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci ret = sec_hw_init(info); 105462306a36Sopenharmony_ci if (ret) 105562306a36Sopenharmony_ci goto sec_clk_disable; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci return 0; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cisec_clk_disable: 106062306a36Sopenharmony_ci sec_clk_dis(info); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci return ret; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic void sec_base_exit(struct sec_dev_info *info) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci sec_hw_exit(info); 106862306a36Sopenharmony_ci sec_clk_dis(info); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci#define SEC_Q_CMD_SIZE \ 107262306a36Sopenharmony_ci round_up(SEC_QUEUE_LEN * sizeof(struct sec_bd_info), PAGE_SIZE) 107362306a36Sopenharmony_ci#define SEC_Q_CQ_SIZE \ 107462306a36Sopenharmony_ci round_up(SEC_QUEUE_LEN * sizeof(struct sec_out_bd_info), PAGE_SIZE) 107562306a36Sopenharmony_ci#define SEC_Q_DB_SIZE \ 107662306a36Sopenharmony_ci round_up(SEC_QUEUE_LEN * sizeof(struct sec_debug_bd_info), PAGE_SIZE) 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic int sec_queue_res_cfg(struct sec_queue *queue) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci struct device *dev = queue->dev_info->dev; 108162306a36Sopenharmony_ci struct sec_queue_ring_cmd *ring_cmd = &queue->ring_cmd; 108262306a36Sopenharmony_ci struct sec_queue_ring_cq *ring_cq = &queue->ring_cq; 108362306a36Sopenharmony_ci struct sec_queue_ring_db *ring_db = &queue->ring_db; 108462306a36Sopenharmony_ci int ret; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci ring_cmd->vaddr = dma_alloc_coherent(dev, SEC_Q_CMD_SIZE, 108762306a36Sopenharmony_ci &ring_cmd->paddr, GFP_KERNEL); 108862306a36Sopenharmony_ci if (!ring_cmd->vaddr) 108962306a36Sopenharmony_ci return -ENOMEM; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci atomic_set(&ring_cmd->used, 0); 109262306a36Sopenharmony_ci mutex_init(&ring_cmd->lock); 109362306a36Sopenharmony_ci ring_cmd->callback = sec_alg_callback; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci ring_cq->vaddr = dma_alloc_coherent(dev, SEC_Q_CQ_SIZE, 109662306a36Sopenharmony_ci &ring_cq->paddr, GFP_KERNEL); 109762306a36Sopenharmony_ci if (!ring_cq->vaddr) { 109862306a36Sopenharmony_ci ret = -ENOMEM; 109962306a36Sopenharmony_ci goto err_free_ring_cmd; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci ring_db->vaddr = dma_alloc_coherent(dev, SEC_Q_DB_SIZE, 110362306a36Sopenharmony_ci &ring_db->paddr, GFP_KERNEL); 110462306a36Sopenharmony_ci if (!ring_db->vaddr) { 110562306a36Sopenharmony_ci ret = -ENOMEM; 110662306a36Sopenharmony_ci goto err_free_ring_cq; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci queue->task_irq = platform_get_irq(to_platform_device(dev), 110962306a36Sopenharmony_ci queue->queue_id * 2 + 1); 111062306a36Sopenharmony_ci if (queue->task_irq < 0) { 111162306a36Sopenharmony_ci ret = queue->task_irq; 111262306a36Sopenharmony_ci goto err_free_ring_db; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cierr_free_ring_db: 111862306a36Sopenharmony_ci dma_free_coherent(dev, SEC_Q_DB_SIZE, queue->ring_db.vaddr, 111962306a36Sopenharmony_ci queue->ring_db.paddr); 112062306a36Sopenharmony_cierr_free_ring_cq: 112162306a36Sopenharmony_ci dma_free_coherent(dev, SEC_Q_CQ_SIZE, queue->ring_cq.vaddr, 112262306a36Sopenharmony_ci queue->ring_cq.paddr); 112362306a36Sopenharmony_cierr_free_ring_cmd: 112462306a36Sopenharmony_ci dma_free_coherent(dev, SEC_Q_CMD_SIZE, queue->ring_cmd.vaddr, 112562306a36Sopenharmony_ci queue->ring_cmd.paddr); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci return ret; 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic void sec_queue_free_ring_pages(struct sec_queue *queue) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci struct device *dev = queue->dev_info->dev; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci dma_free_coherent(dev, SEC_Q_DB_SIZE, queue->ring_db.vaddr, 113562306a36Sopenharmony_ci queue->ring_db.paddr); 113662306a36Sopenharmony_ci dma_free_coherent(dev, SEC_Q_CQ_SIZE, queue->ring_cq.vaddr, 113762306a36Sopenharmony_ci queue->ring_cq.paddr); 113862306a36Sopenharmony_ci dma_free_coherent(dev, SEC_Q_CMD_SIZE, queue->ring_cmd.vaddr, 113962306a36Sopenharmony_ci queue->ring_cmd.paddr); 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_cistatic int sec_queue_config(struct sec_dev_info *info, struct sec_queue *queue, 114362306a36Sopenharmony_ci int queue_id) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci int ret; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci sec_queue_base_init(info, queue, queue_id); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci ret = sec_queue_res_cfg(queue); 115062306a36Sopenharmony_ci if (ret) 115162306a36Sopenharmony_ci return ret; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci ret = sec_queue_map_io(queue); 115462306a36Sopenharmony_ci if (ret) { 115562306a36Sopenharmony_ci dev_err(info->dev, "Queue map failed %d\n", ret); 115662306a36Sopenharmony_ci sec_queue_free_ring_pages(queue); 115762306a36Sopenharmony_ci return ret; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci sec_queue_hw_init(queue); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci return 0; 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic void sec_queue_unconfig(struct sec_dev_info *info, 116662306a36Sopenharmony_ci struct sec_queue *queue) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci sec_queue_unmap_io(queue); 116962306a36Sopenharmony_ci sec_queue_free_ring_pages(queue); 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic int sec_id_alloc(struct sec_dev_info *info) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci int ret = 0; 117562306a36Sopenharmony_ci int i; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci mutex_lock(&sec_id_lock); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci for (i = 0; i < SEC_MAX_DEVICES; i++) 118062306a36Sopenharmony_ci if (!sec_devices[i]) 118162306a36Sopenharmony_ci break; 118262306a36Sopenharmony_ci if (i == SEC_MAX_DEVICES) { 118362306a36Sopenharmony_ci ret = -ENOMEM; 118462306a36Sopenharmony_ci goto unlock; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci info->sec_id = i; 118762306a36Sopenharmony_ci sec_devices[info->sec_id] = info; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ciunlock: 119062306a36Sopenharmony_ci mutex_unlock(&sec_id_lock); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci return ret; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic void sec_id_free(struct sec_dev_info *info) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci mutex_lock(&sec_id_lock); 119862306a36Sopenharmony_ci sec_devices[info->sec_id] = NULL; 119962306a36Sopenharmony_ci mutex_unlock(&sec_id_lock); 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_cistatic int sec_probe(struct platform_device *pdev) 120362306a36Sopenharmony_ci{ 120462306a36Sopenharmony_ci struct sec_dev_info *info; 120562306a36Sopenharmony_ci struct device *dev = &pdev->dev; 120662306a36Sopenharmony_ci int i, j; 120762306a36Sopenharmony_ci int ret; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 121062306a36Sopenharmony_ci if (ret) { 121162306a36Sopenharmony_ci dev_err(dev, "Failed to set 64 bit dma mask %d", ret); 121262306a36Sopenharmony_ci return -ENODEV; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci info = devm_kzalloc(dev, (sizeof(*info)), GFP_KERNEL); 121662306a36Sopenharmony_ci if (!info) 121762306a36Sopenharmony_ci return -ENOMEM; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci info->dev = dev; 122062306a36Sopenharmony_ci mutex_init(&info->dev_lock); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci info->hw_sgl_pool = dmam_pool_create("sgl", dev, 122362306a36Sopenharmony_ci sizeof(struct sec_hw_sgl), 64, 0); 122462306a36Sopenharmony_ci if (!info->hw_sgl_pool) { 122562306a36Sopenharmony_ci dev_err(dev, "Failed to create sec sgl dma pool\n"); 122662306a36Sopenharmony_ci return -ENOMEM; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci ret = sec_base_init(info, pdev); 123062306a36Sopenharmony_ci if (ret) { 123162306a36Sopenharmony_ci dev_err(dev, "Base initialization fail! %d\n", ret); 123262306a36Sopenharmony_ci return ret; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci for (i = 0; i < SEC_Q_NUM; i++) { 123662306a36Sopenharmony_ci ret = sec_queue_config(info, &info->queues[i], i); 123762306a36Sopenharmony_ci if (ret) 123862306a36Sopenharmony_ci goto queues_unconfig; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci ret = sec_queue_irq_init(&info->queues[i]); 124162306a36Sopenharmony_ci if (ret) { 124262306a36Sopenharmony_ci sec_queue_unconfig(info, &info->queues[i]); 124362306a36Sopenharmony_ci goto queues_unconfig; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci ret = sec_algs_register(); 124862306a36Sopenharmony_ci if (ret) { 124962306a36Sopenharmony_ci dev_err(dev, "Failed to register algorithms with crypto %d\n", 125062306a36Sopenharmony_ci ret); 125162306a36Sopenharmony_ci goto queues_unconfig; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci platform_set_drvdata(pdev, info); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci ret = sec_id_alloc(info); 125762306a36Sopenharmony_ci if (ret) 125862306a36Sopenharmony_ci goto algs_unregister; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci return 0; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cialgs_unregister: 126362306a36Sopenharmony_ci sec_algs_unregister(); 126462306a36Sopenharmony_ciqueues_unconfig: 126562306a36Sopenharmony_ci for (j = i - 1; j >= 0; j--) { 126662306a36Sopenharmony_ci sec_queue_irq_uninit(&info->queues[j]); 126762306a36Sopenharmony_ci sec_queue_unconfig(info, &info->queues[j]); 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci sec_base_exit(info); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci return ret; 127262306a36Sopenharmony_ci} 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic int sec_remove(struct platform_device *pdev) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct sec_dev_info *info = platform_get_drvdata(pdev); 127762306a36Sopenharmony_ci int i; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* Unexpose as soon as possible, reuse during remove is fine */ 128062306a36Sopenharmony_ci sec_id_free(info); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci sec_algs_unregister(); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci for (i = 0; i < SEC_Q_NUM; i++) { 128562306a36Sopenharmony_ci sec_queue_irq_uninit(&info->queues[i]); 128662306a36Sopenharmony_ci sec_queue_unconfig(info, &info->queues[i]); 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci sec_base_exit(info); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci return 0; 129262306a36Sopenharmony_ci} 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic const __maybe_unused struct of_device_id sec_match[] = { 129562306a36Sopenharmony_ci { .compatible = "hisilicon,hip06-sec" }, 129662306a36Sopenharmony_ci { .compatible = "hisilicon,hip07-sec" }, 129762306a36Sopenharmony_ci {} 129862306a36Sopenharmony_ci}; 129962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sec_match); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic const __maybe_unused struct acpi_device_id sec_acpi_match[] = { 130262306a36Sopenharmony_ci { "HISI02C1", 0 }, 130362306a36Sopenharmony_ci { } 130462306a36Sopenharmony_ci}; 130562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, sec_acpi_match); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic struct platform_driver sec_driver = { 130862306a36Sopenharmony_ci .probe = sec_probe, 130962306a36Sopenharmony_ci .remove = sec_remove, 131062306a36Sopenharmony_ci .driver = { 131162306a36Sopenharmony_ci .name = "hisi_sec_platform_driver", 131262306a36Sopenharmony_ci .of_match_table = sec_match, 131362306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(sec_acpi_match), 131462306a36Sopenharmony_ci }, 131562306a36Sopenharmony_ci}; 131662306a36Sopenharmony_cimodule_platform_driver(sec_driver); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 131962306a36Sopenharmony_ciMODULE_DESCRIPTION("HiSilicon Security Accelerators"); 132062306a36Sopenharmony_ciMODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com"); 132162306a36Sopenharmony_ciMODULE_AUTHOR("Jonathan Cameron <jonathan.cameron@huawei.com>"); 1322