Skip to content

Commit ddb8a8a

Browse files
Ye Libp3tk0v
authored andcommitted
EDAC/fsl_ddr: Add support for i.MX9 DDR controller
Add support for the i.MX9 DDR controller, which has different register offsets and some function changes compared to the existing fsl_ddr controller. The ECC and error injection functions are almost the same, so update and reuse the driver for i.MX9. Add a special type 'TYPE_IMX9' specifically for the i.MX9 controller to distinguish the differences. Signed-off-by: Ye Li <[email protected]> Signed-off-by: Frank Li <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Peng Fan <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b01a731 commit ddb8a8a

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

drivers/edac/fsl_ddr_edac.c

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,28 @@
3131

3232
static int edac_mc_idx;
3333

34+
static inline void __iomem *ddr_reg_addr(struct fsl_mc_pdata *pdata, unsigned int off)
35+
{
36+
if (pdata->flag == TYPE_IMX9 && off >= FSL_MC_DATA_ERR_INJECT_HI && off <= FSL_MC_ERR_SBE)
37+
return pdata->inject_vbase + off - FSL_MC_DATA_ERR_INJECT_HI
38+
+ IMX9_MC_DATA_ERR_INJECT_OFF;
39+
40+
if (pdata->flag == TYPE_IMX9 && off >= IMX9_MC_ERR_EN)
41+
return pdata->inject_vbase + off - IMX9_MC_ERR_EN;
42+
43+
return pdata->mc_vbase + off;
44+
}
45+
3446
static inline u32 ddr_in32(struct fsl_mc_pdata *pdata, unsigned int off)
3547
{
36-
void __iomem *addr = pdata->mc_vbase + off;
48+
void __iomem *addr = ddr_reg_addr(pdata, off);
3749

3850
return pdata->little_endian ? ioread32(addr) : ioread32be(addr);
3951
}
4052

4153
static inline void ddr_out32(struct fsl_mc_pdata *pdata, unsigned int off, u32 value)
4254
{
43-
void __iomem *addr = pdata->mc_vbase + off;
55+
void __iomem *addr = ddr_reg_addr(pdata, off);
4456

4557
if (pdata->little_endian)
4658
iowrite32(value, addr);
@@ -435,6 +447,9 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci)
435447
case 0x05000000:
436448
mtype = MEM_DDR4;
437449
break;
450+
case 0x04000000:
451+
mtype = MEM_LPDDR4;
452+
break;
438453
default:
439454
mtype = MEM_UNKNOWN;
440455
break;
@@ -468,7 +483,9 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci)
468483
dimm->grain = 8;
469484
dimm->mtype = mtype;
470485
dimm->dtype = DEV_UNKNOWN;
471-
if (sdram_ctl & DSC_X32_EN)
486+
if (pdata->flag == TYPE_IMX9)
487+
dimm->dtype = DEV_X16;
488+
else if (sdram_ctl & DSC_X32_EN)
472489
dimm->dtype = DEV_X32;
473490
dimm->edac_mode = EDAC_SECDED;
474491
}
@@ -480,6 +497,7 @@ int fsl_mc_err_probe(struct platform_device *op)
480497
struct edac_mc_layer layers[2];
481498
struct fsl_mc_pdata *pdata;
482499
struct resource r;
500+
u32 ecc_en_mask;
483501
u32 sdram_ctl;
484502
int res;
485503

@@ -507,6 +525,8 @@ int fsl_mc_err_probe(struct platform_device *op)
507525
mci->ctl_name = pdata->name;
508526
mci->dev_name = pdata->name;
509527

528+
pdata->flag = (unsigned long)device_get_match_data(&op->dev);
529+
510530
/*
511531
* Get the endianness of DDR controller registers.
512532
* Default is big endian.
@@ -535,8 +555,23 @@ int fsl_mc_err_probe(struct platform_device *op)
535555
goto err;
536556
}
537557

538-
sdram_ctl = ddr_in32(pdata, FSL_MC_DDR_SDRAM_CFG);
539-
if (!(sdram_ctl & DSC_ECC_EN)) {
558+
if (pdata->flag == TYPE_IMX9) {
559+
pdata->inject_vbase = devm_platform_ioremap_resource_byname(op, "inject");
560+
if (IS_ERR(pdata->inject_vbase)) {
561+
res = -ENOMEM;
562+
goto err;
563+
}
564+
}
565+
566+
if (pdata->flag == TYPE_IMX9) {
567+
sdram_ctl = ddr_in32(pdata, IMX9_MC_ERR_EN);
568+
ecc_en_mask = ERR_ECC_EN | ERR_INLINE_ECC;
569+
} else {
570+
sdram_ctl = ddr_in32(pdata, FSL_MC_DDR_SDRAM_CFG);
571+
ecc_en_mask = DSC_ECC_EN;
572+
}
573+
574+
if ((sdram_ctl & ecc_en_mask) != ecc_en_mask) {
540575
/* no ECC */
541576
pr_warn("%s: No ECC DIMMs discovered\n", __func__);
542577
res = -ENODEV;
@@ -547,7 +582,8 @@ int fsl_mc_err_probe(struct platform_device *op)
547582
mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR |
548583
MEM_FLAG_DDR2 | MEM_FLAG_RDDR2 |
549584
MEM_FLAG_DDR3 | MEM_FLAG_RDDR3 |
550-
MEM_FLAG_DDR4 | MEM_FLAG_RDDR4;
585+
MEM_FLAG_DDR4 | MEM_FLAG_RDDR4 |
586+
MEM_FLAG_LPDDR4;
551587
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
552588
mci->edac_cap = EDAC_FLAG_SECDED;
553589
mci->mod_name = EDAC_MOD_STR;

drivers/edac/fsl_ddr_edac.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,19 @@
3939
#define FSL_MC_CAPTURE_EXT_ADDRESS 0x0e54
4040
#define FSL_MC_ERR_SBE 0x0e58
4141

42+
#define IMX9_MC_ERR_EN 0x1000
43+
#define IMX9_MC_DATA_ERR_INJECT_OFF 0x100
44+
4245
#define DSC_MEM_EN 0x80000000
4346
#define DSC_ECC_EN 0x20000000
4447
#define DSC_RD_EN 0x10000000
4548
#define DSC_DBW_MASK 0x00180000
4649
#define DSC_DBW_32 0x00080000
4750
#define DSC_DBW_64 0x00000000
4851

52+
#define ERR_ECC_EN 0x80000000
53+
#define ERR_INLINE_ECC 0x40000000
54+
4955
#define DSC_SDTYPE_MASK 0x07000000
5056
#define DSC_X32_EN 0x00000020
5157

@@ -65,14 +71,18 @@
6571
#define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */
6672
#define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */
6773

74+
#define TYPE_IMX9 0x1 /* MC used by iMX9 having registers changed */
75+
6876
struct fsl_mc_pdata {
6977
char *name;
7078
int edac_idx;
7179
void __iomem *mc_vbase;
80+
void __iomem *inject_vbase;
7281
int irq;
7382
u32 orig_ddr_err_disable;
7483
u32 orig_ddr_err_sbe;
7584
bool little_endian;
85+
unsigned long flag;
7686
};
7787
int fsl_mc_err_probe(struct platform_device *op);
7888
void fsl_mc_err_remove(struct platform_device *op);

drivers/edac/layerscape_edac.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
static const struct of_device_id fsl_ddr_mc_err_of_match[] = {
2323
{ .compatible = "fsl,qoriq-memory-controller", },
24+
{ .compatible = "nxp,imx9-memory-controller", .data = (void *)TYPE_IMX9, },
2425
{},
2526
};
2627
MODULE_DEVICE_TABLE(of, fsl_ddr_mc_err_of_match);

0 commit comments

Comments
 (0)