Lines Matching +full:versal +full:- +full:8
1 // SPDX-License-Identifier: GPL-2.0
3 * Xilinx Versal memory controller driver
15 #include <linux/firmware/xlnx-zynqmp.h>
16 #include <linux/firmware/xlnx-event-manager.h>
38 #define XDDR_REG_CONFIG0_SIZE_MASK GENMASK(10, 8)
111 #define XDDR_NOC_MATCH_EN_MASK BIT(8)
133 * https://docs.xilinx.com/r/en-US/am012-versal-register-reference/PCSR_LOCK-XRAM_SLCR-Register
149 * struct ecc_error_info - ECC error log information.
195 * struct ecc_status - ECC status information to report.
209 * struct edac_priv - DDR memory controller private instance data.
255 ddrmc_base = priv->ddrmc_baseaddr; in get_ce_error_info()
256 p = &priv->stat; in get_ce_error_info()
258 p->error_type = XDDR_ERR_TYPE_CE; in get_ce_error_info()
261 p->ceinfo[0].i = regval | reghi << 32; in get_ce_error_info()
271 p->ceinfo[1].i = regval | reghi << 32; in get_ce_error_info()
287 ddrmc_base = priv->ddrmc_baseaddr; in get_ue_error_info()
288 p = &priv->stat; in get_ue_error_info()
290 p->error_type = XDDR_ERR_TYPE_UE; in get_ue_error_info()
294 p->ueinfo[0].i = regval | reghi << 32; in get_ue_error_info()
304 p->ueinfo[1].i = regval | reghi << 32; in get_ue_error_info()
318 ddrmc_base = priv->ddrmc_baseaddr; in get_error_info()
319 p = &priv->stat; in get_error_info()
329 p->channel = 1; in get_error_info()
331 p->channel = 0; in get_error_info()
338 p->channel = 1; in get_error_info()
340 p->channel = 0; in get_error_info()
359 * convert_to_physical - Convert to physical address.
373 err_addr |= (row & BIT(0)) << priv->row_bit[index]; in convert_to_physical()
378 err_addr |= (pinf.col & BIT(0)) << priv->col_bit[index]; in convert_to_physical()
383 err_addr |= (pinf.bank & BIT(0)) << priv->bank_bit[index]; in convert_to_physical()
388 err_addr |= (pinf.group & BIT(0)) << priv->grp_bit[index]; in convert_to_physical()
393 err_addr |= (pinf.rank & BIT(0)) << priv->rank_bit[index]; in convert_to_physical()
398 err_addr |= (pinf.lrank & BIT(0)) << priv->lrank_bit[index]; in convert_to_physical()
402 err_addr |= (priv->stat.channel & BIT(0)) << priv->ch_bit; in convert_to_physical()
408 * handle_error - Handle Correctable and Uncorrectable errors.
416 struct edac_priv *priv = mci->pvt_info; in handle_error()
419 if (stat->error_type == XDDR_ERR_TYPE_CE) { in handle_error()
420 priv->ce_cnt++; in handle_error()
421 pinf = stat->ceinfo[stat->channel]; in handle_error()
422 snprintf(priv->message, XDDR_EDAC_MSG_SIZE, in handle_error()
424 "CE", priv->mc_id, in handle_error()
428 1, 0, 0, 0, 0, 0, -1, in handle_error()
429 priv->message, ""); in handle_error()
432 if (stat->error_type == XDDR_ERR_TYPE_UE) { in handle_error()
433 priv->ue_cnt++; in handle_error()
434 pinf = stat->ueinfo[stat->channel]; in handle_error()
435 snprintf(priv->message, XDDR_EDAC_MSG_SIZE, in handle_error()
437 "UE", priv->mc_id, in handle_error()
441 1, 0, 0, 0, 0, 0, -1, in handle_error()
442 priv->message, ""); in handle_error()
449 * err_callback - Handle Correctable and Uncorrectable errors.
462 priv = mci->pvt_info; in err_callback()
463 p = &priv->stat; in err_callback()
465 regval = readl(priv->ddrmc_baseaddr + XDDR_ISR_OFFSET); in err_callback()
468 p->error_type = XDDR_ERR_TYPE_CE; in err_callback()
470 p->error_type = XDDR_ERR_TYPE_UE; in err_callback()
475 handle_error(mci, &priv->stat); in err_callback()
478 writel(PCSR_UNLOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in err_callback()
481 writel(regval, priv->ddrmc_baseaddr + XDDR_ISR_OFFSET); in err_callback()
484 writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in err_callback()
486 priv->ce_cnt, priv->ue_cnt); in err_callback()
490 * get_dwidth - Return the controller memory width.
525 * get_ecc_state - Return the controller ECC enable/disable status.
530 * Return: a ECC status boolean i.e true/false - enabled/disabled.
548 * get_memsize - Get the size of the attached memory device.
558 regval = readl(priv->ddrmc_baseaddr + XDDR_REG_CONFIG0_OFFSET); in get_memsize()
567 size = 8U; break; in get_memsize()
584 * init_csrows - Initialize the csrow data.
592 struct edac_priv *priv = mci->pvt_info; in init_csrows()
600 for (row = 0; row < mci->nr_csrows; row++) { in init_csrows()
601 csi = mci->csrows[row]; in init_csrows()
602 for (ch = 0; ch < csi->nr_channels; ch++) { in init_csrows()
603 dimm = csi->channels[ch]->dimm; in init_csrows()
604 dimm->edac_mode = EDAC_SECDED; in init_csrows()
605 dimm->mtype = MEM_DDR4; in init_csrows()
606 dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; in init_csrows()
607 dimm->grain = XDDR_EDAC_ERR_GRAIN; in init_csrows()
608 dimm->dtype = get_dwidth(priv->ddrmc_baseaddr); in init_csrows()
614 * mc_init - Initialize one driver instance.
619 * related driver-private data associated with the memory controller the
624 mci->pdev = &pdev->dev; in mc_init()
628 mci->mtype_cap = MEM_FLAG_DDR4; in mc_init()
629 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; in mc_init()
630 mci->scrub_cap = SCRUB_HW_SRC; in mc_init()
631 mci->scrub_mode = SCRUB_NONE; in mc_init()
633 mci->edac_cap = EDAC_FLAG_SECDED; in mc_init()
634 mci->ctl_name = "xlnx_ddr_controller"; in mc_init()
635 mci->dev_name = dev_name(&pdev->dev); in mc_init()
636 mci->mod_name = "xlnx_edac"; in mc_init()
646 writel(PCSR_UNLOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in enable_intr()
650 priv->ddrmc_baseaddr + XDDR_IRQ_EN_OFFSET); in enable_intr()
653 priv->ddrmc_baseaddr + XDDR_IRQ1_EN_OFFSET); in enable_intr()
655 writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in enable_intr()
661 writel(PCSR_UNLOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in disable_intr()
665 priv->ddrmc_baseaddr + XDDR_IRQ_DIS_OFFSET); in disable_intr()
668 writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in disable_intr()
675 * poison_setup - Update poison registers.
688 row |= (((priv->err_inject_addr >> priv->row_bit[index]) & in poison_setup()
693 col |= (((priv->err_inject_addr >> priv->col_bit[index]) & in poison_setup()
698 bank |= (((priv->err_inject_addr >> priv->bank_bit[index]) & in poison_setup()
703 grp |= (((priv->err_inject_addr >> priv->grp_bit[index]) & in poison_setup()
708 rank |= (((priv->err_inject_addr >> priv->rank_bit[index]) & in poison_setup()
713 lrank |= (((priv->err_inject_addr >> priv->lrank_bit[index]) & in poison_setup()
717 ch = (priv->err_inject_addr >> priv->ch_bit) & BIT(0); in poison_setup()
719 writel(0xFF, priv->ddrmc_baseaddr + ECCW1_FLIP_CTRL); in poison_setup()
721 writel(0xFF, priv->ddrmc_baseaddr + ECCW0_FLIP_CTRL); in poison_setup()
723 writel(0, priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC12_OFFSET); in poison_setup()
724 writel(0, priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC13_OFFSET); in poison_setup()
730 writel(regval, priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC14_OFFSET); in poison_setup()
736 writel(regval, priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC15_OFFSET); in poison_setup()
742 struct edac_priv *priv = mci->pvt_info; in xddr_inject_data_ce_store()
750 ce_bitpos = ce_bitpos - ECCW0_FLIP0_BITS; in xddr_inject_data_ce_store()
757 writel(ecc0_flip0, priv->ddrmc_baseaddr + ECCW0_FLIP0_OFFSET); in xddr_inject_data_ce_store()
758 writel(ecc1_flip0, priv->ddrmc_baseaddr + ECCW1_FLIP0_OFFSET); in xddr_inject_data_ce_store()
759 writel(ecc0_flip1, priv->ddrmc_baseaddr + ECCW0_FLIP1_OFFSET); in xddr_inject_data_ce_store()
760 writel(ecc1_flip1, priv->ddrmc_baseaddr + ECCW1_FLIP1_OFFSET); in xddr_inject_data_ce_store()
766 * - Write the correctable error bit position value:
787 struct device *dev = file->private_data; in inject_data_ce_store()
789 struct edac_priv *priv = mci->pvt_info; in inject_data_ce_store()
798 writel(PCSR_UNLOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ce_store()
799 writel(PCSR_UNLOCK_VAL, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ce_store()
807 writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ce_store()
808 writel(PCSR_LOCK_VAL, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ce_store()
821 struct edac_priv *priv = mci->pvt_info; in xddr_inject_data_ue_store()
823 writel(val0, priv->ddrmc_baseaddr + ECCW0_FLIP0_OFFSET); in xddr_inject_data_ue_store()
824 writel(val0, priv->ddrmc_baseaddr + ECCW0_FLIP1_OFFSET); in xddr_inject_data_ue_store()
825 writel(val1, priv->ddrmc_baseaddr + ECCW1_FLIP1_OFFSET); in xddr_inject_data_ue_store()
826 writel(val1, priv->ddrmc_baseaddr + ECCW1_FLIP1_OFFSET); in xddr_inject_data_ue_store()
851 struct device *dev = file->private_data; in inject_data_ue_store()
853 struct edac_priv *priv = mci->pvt_info; in inject_data_ue_store()
861 return -EFAULT; in inject_data_ue_store()
869 return -EFAULT; in inject_data_ue_store()
882 ue0 = ue0 - ECCW0_FLIP0_BITS; in inject_data_ue_store()
889 ue1 = ue1 - ECCW0_FLIP0_BITS; in inject_data_ue_store()
894 writel(PCSR_UNLOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ue_store()
895 writel(PCSR_UNLOCK_VAL, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ue_store()
902 writel(PCSR_LOCK_VAL, priv->ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ue_store()
903 writel(PCSR_LOCK_VAL, priv->ddrmc_baseaddr + XDDR_PCSR_OFFSET); in inject_data_ue_store()
915 struct edac_priv *priv = mci->pvt_info; in create_debugfs_attributes()
917 priv->debugfs = edac_debugfs_create_dir(mci->dev_name); in create_debugfs_attributes()
918 if (!priv->debugfs) in create_debugfs_attributes()
921 if (!edac_debugfs_create_file("inject_ce", 0200, priv->debugfs, in create_debugfs_attributes()
922 &mci->dev, &xddr_inject_ce_fops)) { in create_debugfs_attributes()
923 debugfs_remove_recursive(priv->debugfs); in create_debugfs_attributes()
927 if (!edac_debugfs_create_file("inject_ue", 0200, priv->debugfs, in create_debugfs_attributes()
928 &mci->dev, &xddr_inject_ue_fops)) { in create_debugfs_attributes()
929 debugfs_remove_recursive(priv->debugfs); in create_debugfs_attributes()
932 debugfs_create_x64("address", 0600, priv->debugfs, in create_debugfs_attributes()
933 &priv->err_inject_addr); in create_debugfs_attributes()
934 mci->debugfs = priv->debugfs; in create_debugfs_attributes()
942 priv->row_bit[start] = rows.row0; in process_bit()
943 priv->row_bit[start + 1] = rows.row1; in process_bit()
944 priv->row_bit[start + 2] = rows.row2; in process_bit()
945 priv->row_bit[start + 3] = rows.row3; in process_bit()
946 priv->row_bit[start + 4] = rows.row4; in process_bit()
954 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC5_OFFSET); in setup_row_address_map()
957 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC6_OFFSET); in setup_row_address_map()
960 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC7_OFFSET); in setup_row_address_map()
963 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC8_OFFSET); in setup_row_address_map()
966 priv->row_bit[15] = rows.row0; in setup_row_address_map()
967 priv->row_bit[16] = rows.row1; in setup_row_address_map()
968 priv->row_bit[17] = rows.row2; in setup_row_address_map()
976 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC8_OFFSET); in setup_column_address_map()
977 priv->col_bit[0] = FIELD_GET(MASK_24, regval); in setup_column_address_map()
979 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC9_OFFSET); in setup_column_address_map()
981 priv->col_bit[1] = cols.col1; in setup_column_address_map()
982 priv->col_bit[2] = cols.col2; in setup_column_address_map()
983 priv->col_bit[3] = cols.col3; in setup_column_address_map()
984 priv->col_bit[4] = cols.col4; in setup_column_address_map()
985 priv->col_bit[5] = cols.col5; in setup_column_address_map()
987 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC10_OFFSET); in setup_column_address_map()
989 priv->col_bit[6] = cols.col1; in setup_column_address_map()
990 priv->col_bit[7] = cols.col2; in setup_column_address_map()
991 priv->col_bit[8] = cols.col3; in setup_column_address_map()
992 priv->col_bit[9] = cols.col4; in setup_column_address_map()
999 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC10_OFFSET); in setup_bank_grp_ch_address_map()
1000 priv->bank_bit[0] = FIELD_GET(MASK_24, regval); in setup_bank_grp_ch_address_map()
1002 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC11_OFFSET); in setup_bank_grp_ch_address_map()
1003 priv->bank_bit[1] = (regval & MASK_0); in setup_bank_grp_ch_address_map()
1004 priv->grp_bit[0] = FIELD_GET(GRP_0_MASK, regval); in setup_bank_grp_ch_address_map()
1005 priv->grp_bit[1] = FIELD_GET(GRP_1_MASK, regval); in setup_bank_grp_ch_address_map()
1006 priv->ch_bit = FIELD_GET(CH_0_MASK, regval); in setup_bank_grp_ch_address_map()
1013 regval = readl(priv->ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC4_OFFSET); in setup_rank_lrank_address_map()
1014 priv->rank_bit[0] = (regval & MASK_0); in setup_rank_lrank_address_map()
1015 priv->rank_bit[1] = FIELD_GET(RANK_1_MASK, regval); in setup_rank_lrank_address_map()
1016 priv->lrank_bit[0] = FIELD_GET(LRANK_0_MASK, regval); in setup_rank_lrank_address_map()
1017 priv->lrank_bit[1] = FIELD_GET(LRANK_1_MASK, regval); in setup_rank_lrank_address_map()
1018 priv->lrank_bit[2] = FIELD_GET(MASK_24, regval); in setup_rank_lrank_address_map()
1022 * setup_address_map - Set Address Map by querying ADDRMAP registers.
1042 { .compatible = "xlnx,versal-ddrmc", },
1095 return -ENXIO; in mc_probe()
1098 edac_mc_id = emif_get_id(pdev->dev.of_node); in mc_probe()
1121 return -ENOMEM; in mc_probe()
1124 priv = mci->pvt_info; in mc_probe()
1125 priv->ddrmc_baseaddr = ddrmc_baseaddr; in mc_probe()
1126 priv->ddrmc_noc_baseaddr = ddrmc_noc_baseaddr; in mc_probe()
1127 priv->ce_cnt = 0; in mc_probe()
1128 priv->ue_cnt = 0; in mc_probe()
1129 priv->mc_id = edac_mc_id; in mc_probe()
1144 if (rc == -EACCES) in mc_probe()
1145 rc = -EPROBE_DEFER; in mc_probe()
1158 edac_mc_del_mc(&pdev->dev); in mc_probe()
1168 struct edac_priv *priv = mci->pvt_info; in mc_remove()
1173 debugfs_remove_recursive(priv->debugfs); in mc_remove()
1179 edac_mc_del_mc(&pdev->dev); in mc_remove()
1185 .name = "xilinx-ddrmc-edac",