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