xref: /linux/drivers/crypto/hisilicon/zip/dae_main.c (revision 454cb97726fe62a04b187a0d631ec0a69f6b713a)
109463346SWeili Qian // SPDX-License-Identifier: GPL-2.0
209463346SWeili Qian /* Copyright (c) 2024 HiSilicon Limited. */
309463346SWeili Qian 
409463346SWeili Qian #include <linux/bitops.h>
509463346SWeili Qian #include <linux/io.h>
609463346SWeili Qian #include <linux/uacce.h>
709463346SWeili Qian #include "zip.h"
809463346SWeili Qian 
909463346SWeili Qian /* memory */
1009463346SWeili Qian #define DAE_MEM_START_OFFSET		0x331040
1109463346SWeili Qian #define DAE_MEM_DONE_OFFSET		0x331044
1209463346SWeili Qian #define DAE_MEM_START_MASK		0x1
1309463346SWeili Qian #define DAE_MEM_DONE_MASK		0x1
1409463346SWeili Qian #define DAE_REG_RD_INTVRL_US		10
1509463346SWeili Qian #define DAE_REG_RD_TMOUT_US		USEC_PER_SEC
1609463346SWeili Qian 
1709463346SWeili Qian #define DAE_ALG_NAME			"hashagg"
1809463346SWeili Qian 
19*771ba5c9SWeili Qian /* error */
20*771ba5c9SWeili Qian #define DAE_AXI_CFG_OFFSET		0x331000
21*771ba5c9SWeili Qian #define DAE_AXI_SHUTDOWN_MASK		(BIT(0) | BIT(5))
22*771ba5c9SWeili Qian #define DAE_ERR_SOURCE_OFFSET		0x331C84
23*771ba5c9SWeili Qian #define DAE_ERR_STATUS_OFFSET		0x331C88
24*771ba5c9SWeili Qian #define DAE_ERR_CE_OFFSET		0x331CA0
25*771ba5c9SWeili Qian #define DAE_ERR_CE_MASK			BIT(3)
26*771ba5c9SWeili Qian #define DAE_ERR_NFE_OFFSET		0x331CA4
27*771ba5c9SWeili Qian #define DAE_ERR_NFE_MASK		0x17
28*771ba5c9SWeili Qian #define DAE_ERR_FE_OFFSET		0x331CA8
29*771ba5c9SWeili Qian #define DAE_ERR_FE_MASK			0
30*771ba5c9SWeili Qian #define DAE_ECC_MBIT_MASK		BIT(2)
31*771ba5c9SWeili Qian #define DAE_ECC_INFO_OFFSET		0x33400C
32*771ba5c9SWeili Qian #define DAE_ERR_SHUTDOWN_OFFSET		0x331CAC
33*771ba5c9SWeili Qian #define DAE_ERR_SHUTDOWN_MASK		0x17
34*771ba5c9SWeili Qian #define DAE_ERR_ENABLE_OFFSET		0x331C80
35*771ba5c9SWeili Qian #define DAE_ERR_ENABLE_MASK		(DAE_ERR_FE_MASK | DAE_ERR_NFE_MASK | DAE_ERR_CE_MASK)
36*771ba5c9SWeili Qian #define DAE_AM_CTRL_GLOBAL_OFFSET	0x330000
37*771ba5c9SWeili Qian #define DAE_AM_RETURN_OFFSET		0x330150
38*771ba5c9SWeili Qian #define DAE_AM_RETURN_MASK		0x3
39*771ba5c9SWeili Qian #define DAE_AXI_CFG_OFFSET		0x331000
40*771ba5c9SWeili Qian #define DAE_AXI_SHUTDOWN_EN_MASK	(BIT(0) | BIT(5))
41*771ba5c9SWeili Qian 
42*771ba5c9SWeili Qian struct hisi_dae_hw_error {
43*771ba5c9SWeili Qian 	u32 int_msk;
44*771ba5c9SWeili Qian 	const char *msg;
45*771ba5c9SWeili Qian };
46*771ba5c9SWeili Qian 
47*771ba5c9SWeili Qian static const struct hisi_dae_hw_error dae_hw_error[] = {
48*771ba5c9SWeili Qian 	{ .int_msk = BIT(0), .msg = "dae_axi_bus_err" },
49*771ba5c9SWeili Qian 	{ .int_msk = BIT(1), .msg = "dae_axi_poison_err" },
50*771ba5c9SWeili Qian 	{ .int_msk = BIT(2), .msg = "dae_ecc_2bit_err" },
51*771ba5c9SWeili Qian 	{ .int_msk = BIT(3), .msg = "dae_ecc_1bit_err" },
52*771ba5c9SWeili Qian 	{ .int_msk = BIT(4), .msg = "dae_fsm_hbeat_err" },
53*771ba5c9SWeili Qian };
54*771ba5c9SWeili Qian 
5509463346SWeili Qian static inline bool dae_is_support(struct hisi_qm *qm)
5609463346SWeili Qian {
5709463346SWeili Qian 	if (test_bit(QM_SUPPORT_DAE, &qm->caps))
5809463346SWeili Qian 		return true;
5909463346SWeili Qian 
6009463346SWeili Qian 	return false;
6109463346SWeili Qian }
6209463346SWeili Qian 
6309463346SWeili Qian int hisi_dae_set_user_domain(struct hisi_qm *qm)
6409463346SWeili Qian {
6509463346SWeili Qian 	u32 val;
6609463346SWeili Qian 	int ret;
6709463346SWeili Qian 
6809463346SWeili Qian 	if (!dae_is_support(qm))
6909463346SWeili Qian 		return 0;
7009463346SWeili Qian 
7109463346SWeili Qian 	val = readl(qm->io_base + DAE_MEM_START_OFFSET);
7209463346SWeili Qian 	val |= DAE_MEM_START_MASK;
7309463346SWeili Qian 	writel(val, qm->io_base + DAE_MEM_START_OFFSET);
7409463346SWeili Qian 	ret = readl_relaxed_poll_timeout(qm->io_base + DAE_MEM_DONE_OFFSET, val,
7509463346SWeili Qian 					 val & DAE_MEM_DONE_MASK,
7609463346SWeili Qian 					 DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);
7709463346SWeili Qian 	if (ret)
7809463346SWeili Qian 		pci_err(qm->pdev, "failed to init dae memory!\n");
7909463346SWeili Qian 
8009463346SWeili Qian 	return ret;
8109463346SWeili Qian }
8209463346SWeili Qian 
8309463346SWeili Qian int hisi_dae_set_alg(struct hisi_qm *qm)
8409463346SWeili Qian {
8509463346SWeili Qian 	size_t len;
8609463346SWeili Qian 
8709463346SWeili Qian 	if (!dae_is_support(qm))
8809463346SWeili Qian 		return 0;
8909463346SWeili Qian 
9009463346SWeili Qian 	if (!qm->uacce)
9109463346SWeili Qian 		return 0;
9209463346SWeili Qian 
9309463346SWeili Qian 	len = strlen(qm->uacce->algs);
9409463346SWeili Qian 	/* A line break may be required */
9509463346SWeili Qian 	if (len + strlen(DAE_ALG_NAME) + 1 >= QM_DEV_ALG_MAX_LEN) {
9609463346SWeili Qian 		pci_err(qm->pdev, "algorithm name is too long!\n");
9709463346SWeili Qian 		return -EINVAL;
9809463346SWeili Qian 	}
9909463346SWeili Qian 
10009463346SWeili Qian 	if (len)
10109463346SWeili Qian 		strcat((char *)qm->uacce->algs, "\n");
10209463346SWeili Qian 
10309463346SWeili Qian 	strcat((char *)qm->uacce->algs, DAE_ALG_NAME);
10409463346SWeili Qian 
10509463346SWeili Qian 	return 0;
10609463346SWeili Qian }
107*771ba5c9SWeili Qian 
108*771ba5c9SWeili Qian static void hisi_dae_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
109*771ba5c9SWeili Qian {
110*771ba5c9SWeili Qian 	u32 axi_val, err_val;
111*771ba5c9SWeili Qian 
112*771ba5c9SWeili Qian 	axi_val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);
113*771ba5c9SWeili Qian 	if (enable) {
114*771ba5c9SWeili Qian 		axi_val |= DAE_AXI_SHUTDOWN_MASK;
115*771ba5c9SWeili Qian 		err_val = DAE_ERR_SHUTDOWN_MASK;
116*771ba5c9SWeili Qian 	} else {
117*771ba5c9SWeili Qian 		axi_val &= ~DAE_AXI_SHUTDOWN_MASK;
118*771ba5c9SWeili Qian 		err_val = 0;
119*771ba5c9SWeili Qian 	}
120*771ba5c9SWeili Qian 
121*771ba5c9SWeili Qian 	writel(axi_val, qm->io_base + DAE_AXI_CFG_OFFSET);
122*771ba5c9SWeili Qian 	writel(err_val, qm->io_base + DAE_ERR_SHUTDOWN_OFFSET);
123*771ba5c9SWeili Qian }
124*771ba5c9SWeili Qian 
125*771ba5c9SWeili Qian void hisi_dae_hw_error_enable(struct hisi_qm *qm)
126*771ba5c9SWeili Qian {
127*771ba5c9SWeili Qian 	if (!dae_is_support(qm))
128*771ba5c9SWeili Qian 		return;
129*771ba5c9SWeili Qian 
130*771ba5c9SWeili Qian 	/* clear dae hw error source if having */
131*771ba5c9SWeili Qian 	writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_SOURCE_OFFSET);
132*771ba5c9SWeili Qian 
133*771ba5c9SWeili Qian 	/* configure error type */
134*771ba5c9SWeili Qian 	writel(DAE_ERR_CE_MASK, qm->io_base + DAE_ERR_CE_OFFSET);
135*771ba5c9SWeili Qian 	writel(DAE_ERR_NFE_MASK, qm->io_base + DAE_ERR_NFE_OFFSET);
136*771ba5c9SWeili Qian 	writel(DAE_ERR_FE_MASK, qm->io_base + DAE_ERR_FE_OFFSET);
137*771ba5c9SWeili Qian 
138*771ba5c9SWeili Qian 	hisi_dae_master_ooo_ctrl(qm, true);
139*771ba5c9SWeili Qian 
140*771ba5c9SWeili Qian 	/* enable dae hw error interrupts */
141*771ba5c9SWeili Qian 	writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_ENABLE_OFFSET);
142*771ba5c9SWeili Qian }
143*771ba5c9SWeili Qian 
144*771ba5c9SWeili Qian void hisi_dae_hw_error_disable(struct hisi_qm *qm)
145*771ba5c9SWeili Qian {
146*771ba5c9SWeili Qian 	if (!dae_is_support(qm))
147*771ba5c9SWeili Qian 		return;
148*771ba5c9SWeili Qian 
149*771ba5c9SWeili Qian 	writel(0, qm->io_base + DAE_ERR_ENABLE_OFFSET);
150*771ba5c9SWeili Qian 	hisi_dae_master_ooo_ctrl(qm, false);
151*771ba5c9SWeili Qian }
152*771ba5c9SWeili Qian 
153*771ba5c9SWeili Qian static u32 hisi_dae_get_hw_err_status(struct hisi_qm *qm)
154*771ba5c9SWeili Qian {
155*771ba5c9SWeili Qian 	return readl(qm->io_base + DAE_ERR_STATUS_OFFSET);
156*771ba5c9SWeili Qian }
157*771ba5c9SWeili Qian 
158*771ba5c9SWeili Qian static void hisi_dae_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts)
159*771ba5c9SWeili Qian {
160*771ba5c9SWeili Qian 	if (!dae_is_support(qm))
161*771ba5c9SWeili Qian 		return;
162*771ba5c9SWeili Qian 
163*771ba5c9SWeili Qian 	writel(err_sts, qm->io_base + DAE_ERR_SOURCE_OFFSET);
164*771ba5c9SWeili Qian }
165*771ba5c9SWeili Qian 
166*771ba5c9SWeili Qian static void hisi_dae_disable_error_report(struct hisi_qm *qm, u32 err_type)
167*771ba5c9SWeili Qian {
168*771ba5c9SWeili Qian 	writel(DAE_ERR_NFE_MASK & (~err_type), qm->io_base + DAE_ERR_NFE_OFFSET);
169*771ba5c9SWeili Qian }
170*771ba5c9SWeili Qian 
171*771ba5c9SWeili Qian static void hisi_dae_log_hw_error(struct hisi_qm *qm, u32 err_type)
172*771ba5c9SWeili Qian {
173*771ba5c9SWeili Qian 	const struct hisi_dae_hw_error *err = dae_hw_error;
174*771ba5c9SWeili Qian 	struct device *dev = &qm->pdev->dev;
175*771ba5c9SWeili Qian 	u32 ecc_info;
176*771ba5c9SWeili Qian 	size_t i;
177*771ba5c9SWeili Qian 
178*771ba5c9SWeili Qian 	for (i = 0; i < ARRAY_SIZE(dae_hw_error); i++) {
179*771ba5c9SWeili Qian 		err = &dae_hw_error[i];
180*771ba5c9SWeili Qian 		if (!(err->int_msk & err_type))
181*771ba5c9SWeili Qian 			continue;
182*771ba5c9SWeili Qian 
183*771ba5c9SWeili Qian 		dev_err(dev, "%s [error status=0x%x] found\n",
184*771ba5c9SWeili Qian 			err->msg, err->int_msk);
185*771ba5c9SWeili Qian 
186*771ba5c9SWeili Qian 		if (err->int_msk & DAE_ECC_MBIT_MASK) {
187*771ba5c9SWeili Qian 			ecc_info = readl(qm->io_base + DAE_ECC_INFO_OFFSET);
188*771ba5c9SWeili Qian 			dev_err(dev, "dae multi ecc sram info 0x%x\n", ecc_info);
189*771ba5c9SWeili Qian 		}
190*771ba5c9SWeili Qian 	}
191*771ba5c9SWeili Qian }
192*771ba5c9SWeili Qian 
193*771ba5c9SWeili Qian enum acc_err_result hisi_dae_get_err_result(struct hisi_qm *qm)
194*771ba5c9SWeili Qian {
195*771ba5c9SWeili Qian 	u32 err_status;
196*771ba5c9SWeili Qian 
197*771ba5c9SWeili Qian 	if (!dae_is_support(qm))
198*771ba5c9SWeili Qian 		return ACC_ERR_NONE;
199*771ba5c9SWeili Qian 
200*771ba5c9SWeili Qian 	err_status = hisi_dae_get_hw_err_status(qm);
201*771ba5c9SWeili Qian 	if (!err_status)
202*771ba5c9SWeili Qian 		return ACC_ERR_NONE;
203*771ba5c9SWeili Qian 
204*771ba5c9SWeili Qian 	hisi_dae_log_hw_error(qm, err_status);
205*771ba5c9SWeili Qian 
206*771ba5c9SWeili Qian 	if (err_status & DAE_ERR_NFE_MASK) {
207*771ba5c9SWeili Qian 		/* Disable the same error reporting until device is recovered. */
208*771ba5c9SWeili Qian 		hisi_dae_disable_error_report(qm, err_status);
209*771ba5c9SWeili Qian 		return ACC_ERR_NEED_RESET;
210*771ba5c9SWeili Qian 	}
211*771ba5c9SWeili Qian 	hisi_dae_clear_hw_err_status(qm, err_status);
212*771ba5c9SWeili Qian 
213*771ba5c9SWeili Qian 	return ACC_ERR_RECOVERED;
214*771ba5c9SWeili Qian }
215*771ba5c9SWeili Qian 
216*771ba5c9SWeili Qian bool hisi_dae_dev_is_abnormal(struct hisi_qm *qm)
217*771ba5c9SWeili Qian {
218*771ba5c9SWeili Qian 	u32 err_status;
219*771ba5c9SWeili Qian 
220*771ba5c9SWeili Qian 	if (!dae_is_support(qm))
221*771ba5c9SWeili Qian 		return false;
222*771ba5c9SWeili Qian 
223*771ba5c9SWeili Qian 	err_status = hisi_dae_get_hw_err_status(qm);
224*771ba5c9SWeili Qian 	if (err_status & DAE_ERR_NFE_MASK)
225*771ba5c9SWeili Qian 		return true;
226*771ba5c9SWeili Qian 
227*771ba5c9SWeili Qian 	return false;
228*771ba5c9SWeili Qian }
229*771ba5c9SWeili Qian 
230*771ba5c9SWeili Qian int hisi_dae_close_axi_master_ooo(struct hisi_qm *qm)
231*771ba5c9SWeili Qian {
232*771ba5c9SWeili Qian 	u32 val;
233*771ba5c9SWeili Qian 	int ret;
234*771ba5c9SWeili Qian 
235*771ba5c9SWeili Qian 	if (!dae_is_support(qm))
236*771ba5c9SWeili Qian 		return 0;
237*771ba5c9SWeili Qian 
238*771ba5c9SWeili Qian 	val = readl(qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);
239*771ba5c9SWeili Qian 	val |= BIT(0);
240*771ba5c9SWeili Qian 	writel(val, qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);
241*771ba5c9SWeili Qian 
242*771ba5c9SWeili Qian 	ret = readl_relaxed_poll_timeout(qm->io_base + DAE_AM_RETURN_OFFSET,
243*771ba5c9SWeili Qian 					 val, (val == DAE_AM_RETURN_MASK),
244*771ba5c9SWeili Qian 					 DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);
245*771ba5c9SWeili Qian 	if (ret)
246*771ba5c9SWeili Qian 		dev_err(&qm->pdev->dev, "failed to close dae axi ooo!\n");
247*771ba5c9SWeili Qian 
248*771ba5c9SWeili Qian 	return ret;
249*771ba5c9SWeili Qian }
250*771ba5c9SWeili Qian 
251*771ba5c9SWeili Qian void hisi_dae_open_axi_master_ooo(struct hisi_qm *qm)
252*771ba5c9SWeili Qian {
253*771ba5c9SWeili Qian 	u32 val;
254*771ba5c9SWeili Qian 
255*771ba5c9SWeili Qian 	if (!dae_is_support(qm))
256*771ba5c9SWeili Qian 		return;
257*771ba5c9SWeili Qian 
258*771ba5c9SWeili Qian 	val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);
259*771ba5c9SWeili Qian 
260*771ba5c9SWeili Qian 	writel(val & ~DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);
261*771ba5c9SWeili Qian 	writel(val | DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);
262*771ba5c9SWeili Qian }
263