From: Sherry Sun <[email protected]>
This patchset add edac driver support for i.MX8MP, since i.MX8MP use the same
synopsys memory controller with ZynqMP, so the driver is based on synopsys_edac
driver.
Considering that i.MX8MP dts file is still in kernel/git/shawnguo/linux.git and
isn't in mainline now, I will add EDAC node in i.MX8MP dts after this file is
pushed to mainline.
And the edac driver for i.MX8MP has been tested in kernel/git/shawnguo/linux.git
where i.MX8MP is supported, it turns out that this driver works well to detect
corrected and uncorrected errors for LPDDR4 in i.MX8MP.
Sherry Sun (3):
dt-bindings: memory-controllers: Add i.MX8MP DDRC binding doc
EDAC: Add synopsys edac driver support for i.MX8MP
EDAC: synopsys: Add edac driver support for i.MX8MP
.../bindings/memory-controllers/synopsys.txt | 8 +-
drivers/edac/Kconfig | 2 +-
drivers/edac/synopsys_edac.c | 77 ++++++++++++++++++-
3 files changed, 83 insertions(+), 4 deletions(-)
--
2.17.1
From: Sherry Sun <[email protected]>
Add documentation for i.MX8MP DDRC binding based on synopsys_edac doc,
which use the same memory-controller IP.
Signed-off-by: Sherry Sun <[email protected]>
---
.../devicetree/bindings/memory-controllers/synopsys.txt | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
index 9d32762c47e1..5c03959a451f 100644
--- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
@@ -6,16 +6,20 @@ bus width configurations.
The Zynq DDR ECC controller has an optional ECC support in half-bus width
(16-bit) configuration.
-These both ECC controllers correct single bit ECC errors and detect double bit
+The i.MX8MP DDR ECC controller has an ECC support in 64-bit bus width
+configurations.
+
+These all ECC controllers correct single bit ECC errors and detect double bit
ECC errors.
Required properties:
- compatible: One of:
- 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller
- 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller
+ - 'fsl,imx8mp-ddrc' : i.MX8MP DDR ECC controller
- reg: Should contain DDR controller registers location and length.
-Required properties for "xlnx,zynqmp-ddrc-2.40a":
+Required properties for "xlnx,zynqmp-ddrc-2.40a" and "fsl,imx8mp-ddrc":
- interrupts: Property with a value describing the interrupt number.
Example:
--
2.17.1
From: Sherry Sun <[email protected]>
The i.MX8MP has a memory controller supported by this driver. So here
add edac driver for i.MX8MP based on synopsys edac driver.
Signed-off-by: Sherry Sun <[email protected]>
---
drivers/edac/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index fe2eb892a1bd..58a2d67d5513 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -475,7 +475,7 @@ config EDAC_ARMADA_XP
config EDAC_SYNOPSYS
tristate "Synopsys DDR Memory Controller"
- depends on ARCH_ZYNQ || ARCH_ZYNQMP
+ depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_MXC
help
Support for error detection and correction on the Synopsys DDR
memory controller.
--
2.17.1
From: Sherry Sun <[email protected]>
Since i.MX8MP use synopsys ddr controller IP, so add edac support
for i.MX8MP based on synopsys edac driver. i.MX8MP use LPDDR4 and
support interrupts for corrected and uncorrected errors. The main
difference between ZynqMP and i.MX8MP ddr controller is the interrupt
registers. So add another interrupt handler function, enable/disable
interrupt function to distinguish with ZynqMP.
Signed-off-by: Sherry Sun <[email protected]>
---
drivers/edac/synopsys_edac.c | 77 +++++++++++++++++++++++++++++++++++-
1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
index 2d263382d797..66c801502212 100644
--- a/drivers/edac/synopsys_edac.c
+++ b/drivers/edac/synopsys_edac.c
@@ -101,6 +101,7 @@
/* DDR ECC Quirks */
#define DDR_ECC_INTR_SUPPORT BIT(0)
#define DDR_ECC_DATA_POISON_SUPPORT BIT(1)
+#define DDR_ECC_IMX8MP BIT(2)
/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */
/* ECC Configuration Registers */
@@ -266,6 +267,11 @@
#define RANK_B0_BASE 6
+/* ECCCTL UE/CE Interrupt enable/disable for IMX8MP*/
+#define DDR_CE_INTR_EN_MASK 0x100
+#define DDR_UE_INTR_EN_MASK 0x200
+#define ECC_INTR_MASK 0x10100
+
/**
* struct ecc_error_info - ECC error log information.
* @row: Row number.
@@ -524,6 +530,54 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
memset(p, 0, sizeof(*p));
}
+static void enable_intr_imx8mp(struct synps_edac_priv *priv)
+{
+ int regval;
+
+ regval = readl(priv->baseaddr + ECC_CLR_OFST);
+ regval |= (DDR_CE_INTR_EN_MASK | DDR_UE_INTR_EN_MASK);
+ writel(regval, priv->baseaddr + ECC_CLR_OFST);
+}
+
+static void disable_intr_imx8mp(struct synps_edac_priv *priv)
+{
+ int regval;
+
+ regval = readl(priv->baseaddr + ECC_CLR_OFST);
+ regval &= ~(DDR_CE_INTR_EN_MASK | DDR_UE_INTR_EN_MASK);
+ writel(regval, priv->baseaddr + ECC_CLR_OFST);
+}
+
+/* Interrupt Handler for ECC interrupts on imx8mp platform. */
+static irqreturn_t intr_handler_imx8mp(int irq, void *dev_id)
+{
+ const struct synps_platform_data *p_data;
+ struct mem_ctl_info *mci = dev_id;
+ struct synps_edac_priv *priv;
+ int status, regval;
+
+ priv = mci->pvt_info;
+ p_data = priv->p_data;
+
+ regval = readl(priv->baseaddr + ECC_STAT_OFST);
+ if (!(regval & ECC_INTR_MASK))
+ return IRQ_NONE;
+
+ status = p_data->get_error_info(priv);
+ if (status)
+ return IRQ_NONE;
+
+ priv->ce_cnt += priv->stat.ce_cnt;
+ priv->ue_cnt += priv->stat.ue_cnt;
+ handle_error(mci, &priv->stat);
+
+ edac_dbg(3, "Total error count CE %d UE %d\n",
+ priv->ce_cnt, priv->ue_cnt);
+ enable_intr_imx8mp(priv);
+
+ return IRQ_HANDLED;
+}
+
/**
* intr_handler - Interrupt Handler for ECC interrupts.
* @irq: IRQ number.
@@ -541,6 +595,9 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
priv = mci->pvt_info;
p_data = priv->p_data;
+ if (p_data->quirks & DDR_ECC_IMX8MP)
+ return intr_handler_imx8mp(irq, dev_id);
+
regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK);
if (!(regval & ECC_CE_UE_INTR_MASK))
@@ -817,7 +874,7 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
platform_set_drvdata(pdev, mci);
/* Initialize controller capabilities and configuration */
- mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
+ mci->mtype_cap = MEM_FLAG_LRDDR4 | MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
mci->scrub_cap = SCRUB_HW_SRC;
mci->scrub_mode = SCRUB_NONE;
@@ -842,6 +899,9 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
static void enable_intr(struct synps_edac_priv *priv)
{
/* Enable UE/CE Interrupts */
+ if (priv->p_data->quirks & DDR_ECC_IMX8MP)
+ return enable_intr_imx8mp(priv);
+
writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
priv->baseaddr + DDR_QOS_IRQ_EN_OFST);
}
@@ -849,6 +909,9 @@ static void enable_intr(struct synps_edac_priv *priv)
static void disable_intr(struct synps_edac_priv *priv)
{
/* Disable UE/CE Interrupts */
+ if (priv->p_data->quirks & DDR_ECC_IMX8MP)
+ return disable_intr_imx8mp(priv);
+
writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK,
priv->baseaddr + DDR_QOS_IRQ_DB_OFST);
}
@@ -898,6 +961,14 @@ static const struct synps_platform_data zynqmp_edac_def = {
),
};
+static const struct synps_platform_data imx8mp_edac_def = {
+ .get_error_info = zynqmp_get_error_info,
+ .get_mtype = zynqmp_get_mtype,
+ .get_dtype = zynqmp_get_dtype,
+ .get_ecc_state = zynqmp_get_ecc_state,
+ .quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_IMX8MP),
+};
+
static const struct of_device_id synps_edac_match[] = {
{
.compatible = "xlnx,zynq-ddrc-a05",
@@ -907,6 +978,10 @@ static const struct of_device_id synps_edac_match[] = {
.compatible = "xlnx,zynqmp-ddrc-2.40a",
.data = (void *)&zynqmp_edac_def
},
+ {
+ .compatible = "fsl,imx8mp-ddrc",
+ .data = (void *)&imx8mp_edac_def
+ },
{
/* end of table */
}
--
2.17.1
Hi Sherry,
On 21/02/2020 06:39, sherry sun wrote:
> From: Sherry Sun <[email protected]>
>
> Since i.MX8MP use synopsys ddr controller IP, so add edac support
> for i.MX8MP based on synopsys edac driver. i.MX8MP use LPDDR4 and
> support interrupts for corrected and uncorrected errors.
> The main
> difference between ZynqMP and i.MX8MP ddr controller is the interrupt
> registers. So add another interrupt handler function, enable/disable
> interrupt function to distinguish with ZynqMP.
Same, but different! Is there any more information on how this difference comes about?
It looks like the existing users of this driver all used DDR_QOS_IRQ, but yours uses
DDR_CE_INTR and DDR_UE_INTR. I note you didn't add a new register offset, so this must be
a feature of the IP that i.MX8MP uses, but others don't.
Is it possible to describe the feature in the DT instead of quirking based on the compatible?
Ideally someone else with the same configuration in a different SoC should be able to use
the new parts of this driver without changing the code to quirk their platform too.
> diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
> index 2d263382d797..66c801502212 100644
> --- a/drivers/edac/synopsys_edac.c
> +++ b/drivers/edac/synopsys_edac.c
> @@ -524,6 +530,54 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
> +static void enable_intr_imx8mp(struct synps_edac_priv *priv)
> +{
> + int regval;
> +
> + regval = readl(priv->baseaddr + ECC_CLR_OFST);
> + regval |= (DDR_CE_INTR_EN_MASK | DDR_UE_INTR_EN_MASK);
> + writel(regval, priv->baseaddr + ECC_CLR_OFST);
> +}
I assume these two interrupts are combined as one line. i.e. this driver can't race with
itself.
Was this an integration choice? Could someone else use wire the DDR_CE_INTR and
DDR_UE_INTR interrupts separately so that two CPUs take them in parallel?
ECC_CLR_OFST looks mighty like one of these write-only 'clear pending irqs' register. I'm
surprised you read it, then write to it to enable interrupts... but I don't have the
documentation!
> +/* Interrupt Handler for ECC interrupts on imx8mp platform. */
> +static irqreturn_t intr_handler_imx8mp(int irq, void *dev_id)
> +{
> + const struct synps_platform_data *p_data;
> + struct mem_ctl_info *mci = dev_id;
> + struct synps_edac_priv *priv;
> + int status, regval;
> +
> + priv = mci->pvt_info;
> + p_data = priv->p_data;
> + regval = readl(priv->baseaddr + ECC_STAT_OFST);
> + if (!(regval & ECC_INTR_MASK))
> + return IRQ_NONE;
zynqmp_get_error_info(), which you call via p_data->get_error_info() does this too, so
this is redundant.
> + status = p_data->get_error_info(priv);
> + if (status)
> + return IRQ_NONE;
> +
> + priv->ce_cnt += priv->stat.ce_cnt;
> + priv->ue_cnt += priv->stat.ue_cnt;
> + handle_error(mci, &priv->stat);
> +
> + edac_dbg(3, "Total error count CE %d UE %d\n",
> + priv->ce_cnt, priv->ue_cnt);
This is the same as the existing intr_handler()...
> + enable_intr_imx8mp(priv);
Is this because zynqmp_get_error_info() wrote 0 to ECC_CLR_OFST, so now you have to
re-enable the interrrupts?
It looks like you are hacking round the problem!
> +
> + return IRQ_HANDLED;
> +}
> @@ -541,6 +595,9 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
> priv = mci->pvt_info;
> p_data = priv->p_data;
>
> + if (p_data->quirks & DDR_ECC_IMX8MP)
> + return intr_handler_imx8mp(irq, dev_id);
> +
> regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
> regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK);
> if (!(regval & ECC_CE_UE_INTR_MASK))
As this driver has struct synps_platform_data for some function calls (that are all the
same today), you could add this as one that differs. This would let you pass the right one
to devm_request_irq() at setup_irq() time. If there is a third type of intr_handler, it
avoids chaining these quirk/features in the intr_handler().
> @@ -817,7 +874,7 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
> platform_set_drvdata(pdev, mci);
>
> /* Initialize controller capabilities and configuration */
> - mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
> + mci->mtype_cap = MEM_FLAG_LRDDR4 | MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
> mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
> mci->scrub_cap = SCRUB_HW_SRC;
> mci->scrub_mode = SCRUB_NONE;
You haven't updated zynq_get_mtype(), is it possible to use the new memory type?
I think this would be cleaner if you moved the existing parts of the driver that aren't
needed when using DDR_CE_INTR and DDR_UE_INTR to the platform data as a preparatory patch.
You can then add support for these interrupts by adding the bits that are different.
This should avoid things like trying to undo what zynq_get_error_info() did. Things like
this are a maintenance headache.
As it is, you're hooking in the differences, then working round some of the things you
didn't want to happen. (e.g. ECC_CLR_OFST being written as zero)
Thanks,
James
On Fri, Feb 21, 2020 at 02:39:14PM +0800, sherry sun wrote:
> From: Sherry Sun <[email protected]>
>
> Add documentation for i.MX8MP DDRC binding based on synopsys_edac doc,
> which use the same memory-controller IP.
>
> Signed-off-by: Sherry Sun <[email protected]>
> ---
> .../devicetree/bindings/memory-controllers/synopsys.txt | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
> index 9d32762c47e1..5c03959a451f 100644
> --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
> +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
> @@ -6,16 +6,20 @@ bus width configurations.
> The Zynq DDR ECC controller has an optional ECC support in half-bus width
> (16-bit) configuration.
>
> -These both ECC controllers correct single bit ECC errors and detect double bit
> +The i.MX8MP DDR ECC controller has an ECC support in 64-bit bus width
> +configurations.
> +
> +These all ECC controllers correct single bit ECC errors and detect double bit
All the ECC...
With that,
Reviewed-by: Rob Herring <[email protected]>
> ECC errors.
>
> Required properties:
> - compatible: One of:
> - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller
> - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller
> + - 'fsl,imx8mp-ddrc' : i.MX8MP DDR ECC controller
> - reg: Should contain DDR controller registers location and length.
>
> -Required properties for "xlnx,zynqmp-ddrc-2.40a":
> +Required properties for "xlnx,zynqmp-ddrc-2.40a" and "fsl,imx8mp-ddrc":
> - interrupts: Property with a value describing the interrupt number.
>
> Example:
> --
> 2.17.1
>
Hi James,
> -----Original Message-----
> From: James Morse <[email protected]>
> Sent: 2020年2月27日 1:13
> To: Sherry Sun <[email protected]>
> Cc: [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected]; dl-linux-imx
> <[email protected]>; Frank Li <[email protected]>
> Subject: Re: [PATCH 3/3] EDAC: synopsys: Add edac driver support for
> i.MX8MP
>
> Hi Sherry,
>
> On 21/02/2020 06:39, sherry sun wrote:
> > From: Sherry Sun <[email protected]>
> >
> > Since i.MX8MP use synopsys ddr controller IP, so add edac support for
> > i.MX8MP based on synopsys edac driver. i.MX8MP use LPDDR4 and support
> > interrupts for corrected and uncorrected errors.
>
> > The main
> > difference between ZynqMP and i.MX8MP ddr controller is the interrupt
> > registers. So add another interrupt handler function, enable/disable
> > interrupt function to distinguish with ZynqMP.
>
> Same, but different! Is there any more information on how this difference
> comes about?
First of all, thanks for your comments.
The only difference between ZynqMP and i.MX8MP is the interrupt register, because I didn't find DDR QOS Interrupt registers as ZynqMP used in synopsys DDRC Databook, instead, it use ECC Clear Register to enable or disable the ce/ue interrupts. (In synopsys ddrc databook, the name of this register is ECCCTL, maybe it is better to rename the register in this driver form ECCCLR to ECCCTL to avoid misunderstanding, but the description of this register in databook is ECC Clear Register. I'm also confused.)
Actually I have no idea about DDR_QOS_IRQ since I can't find it in synopsys DDRC Databook, I guess it maybe the private register of ZynqMP?
Or ZynqMP and i.MX8MP use different version of synopsys DDRC Databook? But expect the interrupt register, all the other registers are the same.
>
> It looks like the existing users of this driver all used DDR_QOS_IRQ, but yours
> uses DDR_CE_INTR and DDR_UE_INTR. I note you didn't add a new register
> offset, so this must be a feature of the IP that i.MX8MP uses, but others don't.
>
> Is it possible to describe the feature in the DT instead of quirking based on
> the compatible?
>
> Ideally someone else with the same configuration in a different SoC should
> be able to use the new parts of this driver without changing the code to quirk
> their platform too.
As talked above, I think i.MX8MP uses the general interrupt feature of the IP since it use the common register ECCCTL. And the DDR_QOS_IRQ maybe the feature of the IP or ZynqMP. But I'm not very sure. So should I still describe it in the DT?
>
>
> > diff --git a/drivers/edac/synopsys_edac.c
> > b/drivers/edac/synopsys_edac.c index 2d263382d797..66c801502212
> 100644
> > --- a/drivers/edac/synopsys_edac.c
> > +++ b/drivers/edac/synopsys_edac.c
>
> > @@ -524,6 +530,54 @@ static void handle_error(struct mem_ctl_info
> > *mci, struct synps_ecc_status *p)
>
> > +static void enable_intr_imx8mp(struct synps_edac_priv *priv) {
> > + int regval;
> > +
> > + regval = readl(priv->baseaddr + ECC_CLR_OFST);
> > + regval |= (DDR_CE_INTR_EN_MASK | DDR_UE_INTR_EN_MASK);
> > + writel(regval, priv->baseaddr + ECC_CLR_OFST); }
>
> I assume these two interrupts are combined as one line. i.e. this driver can't
> race with itself.
>
> Was this an integration choice? Could someone else use wire the
> DDR_CE_INTR and DDR_UE_INTR interrupts separately so that two CPUs take
> them in parallel?
>
Actually I enable or disable CE/UE interrupts in one function because I followed the way ZynqMP do.
If it needed, I can separate CE/UE interrupts into different enable or disable functions.
>
> ECC_CLR_OFST looks mighty like one of these write-only 'clear pending irqs'
> register. I'm surprised you read it, then write to it to enable interrupts... but I
> don't have the documentation!
>
As explained above, the name of the register is actually ECCCTL, but the description is ECC Clear Register in databook, and it can enable/disable interrupts.
>
> > +/* Interrupt Handler for ECC interrupts on imx8mp platform. */ static
> > +irqreturn_t intr_handler_imx8mp(int irq, void *dev_id) {
> > + const struct synps_platform_data *p_data;
> > + struct mem_ctl_info *mci = dev_id;
> > + struct synps_edac_priv *priv;
> > + int status, regval;
> > +
> > + priv = mci->pvt_info;
> > + p_data = priv->p_data;
>
>
> > + regval = readl(priv->baseaddr + ECC_STAT_OFST);
> > + if (!(regval & ECC_INTR_MASK))
> > + return IRQ_NONE;
>
> zynqmp_get_error_info(), which you call via p_data->get_error_info() does
> this too, so this is redundant.
>
In intr_handler(), when it calls intr_handler_imx8mp(), it uses return intr_handler_imx8mp(), so p_data->get_error_info() will only be executed once.
>
> > + status = p_data->get_error_info(priv);
> > + if (status)
> > + return IRQ_NONE;
> > +
> > + priv->ce_cnt += priv->stat.ce_cnt;
> > + priv->ue_cnt += priv->stat.ue_cnt;
> > + handle_error(mci, &priv->stat);
> > +
> > + edac_dbg(3, "Total error count CE %d UE %d\n",
> > + priv->ce_cnt, priv->ue_cnt);
>
> This is the same as the existing intr_handler()...
Same as above, this will be called only once.
>
>
> > + enable_intr_imx8mp(priv);
>
> Is this because zynqmp_get_error_info() wrote 0 to ECC_CLR_OFST, so now
> you have to re-enable the interrrupts?
>
> It looks like you are hacking round the problem!
Yes, you are right. Because Zynqmp only use ECC_CLR_OFST register to clear CE/UE error flags and counts, so it has no effect on Zynqmp interrupts when it write 0 to this register. But for i.MX8MP, wirte 0 to ECC_CLR_OFST will disable i.MX8MP CE/UE interrupt, so here need re-enable the interrupts.
>
>
> > +
> > + return IRQ_HANDLED;
> > +}
>
> > @@ -541,6 +595,9 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
> > priv = mci->pvt_info;
> > p_data = priv->p_data;
> >
> > + if (p_data->quirks & DDR_ECC_IMX8MP)
> > + return intr_handler_imx8mp(irq, dev_id);
> > +
> > regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST);
> > regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK);
> > if (!(regval & ECC_CE_UE_INTR_MASK))
>
> As this driver has struct synps_platform_data for some function calls (that
> are all the same today), you could add this as one that differs. This would let
> you pass the right one to devm_request_irq() at setup_irq() time. If there is a
> third type of intr_handler, it avoids chaining these quirk/features in the
> intr_handler().
Do you mean I should add a interrupt handler function in synps_platform_data, then use p_data->intr_handler in devm_request_irq() to pass on different interrupt handlers for ZynqMP and i.MX8MP?
>
>
> > @@ -817,7 +874,7 @@ static void mc_init(struct mem_ctl_info *mci, struct
> platform_device *pdev)
> > platform_set_drvdata(pdev, mci);
> >
> > /* Initialize controller capabilities and configuration */
> > - mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
> > + mci->mtype_cap = MEM_FLAG_LRDDR4 | MEM_FLAG_DDR3 |
> MEM_FLAG_DDR2;
> > mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
> > mci->scrub_cap = SCRUB_HW_SRC;
> > mci->scrub_mode = SCRUB_NONE;
>
> You haven't updated zynq_get_mtype(), is it possible to use the new memory
> type?
I'm not sure if Zynq platform support LPDDR4.
And I don't think it's needed for all the three platform(Zynq/ZynqMP/i.MX8MP) to support the new memory type, mci->mtype_cap only represent the synopsys_edac driver can support this new type(for i.MX8MP part). What do you think?
>
>
> I think this would be cleaner if you moved the existing parts of the driver that
> aren't needed when using DDR_CE_INTR and DDR_UE_INTR to the platform
> data as a preparatory patch.
> You can then add support for these interrupts by adding the bits that are
> different.
> This should avoid things like trying to undo what zynq_get_error_info() did.
> Things like this are a maintenance headache.
>
> As it is, you're hooking in the differences, then working round some of the
> things you didn't want to happen. (e.g. ECC_CLR_OFST being written as zero)
>
The most part of zynqmp_get_error_info() and intr_handler() functions are same useful for i.MX8MP, so do you mean I should add new functions through platform data instead change the ZynqMP functions?
Best regards
Sherry Sun
>
>
> Thanks,
>
> James
Hi Rob,
> -----Original Message-----
> From: [email protected] <linux-kernel-
> [email protected]> On Behalf Of Rob Herring
> Sent: 2020??2??27?? 1:25
> To: Sherry Sun <[email protected]>
> Cc: [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected]; dl-linux-imx
> <[email protected]>; Frank Li <[email protected]>
> Subject: Re: [PATCH 1/3] dt-bindings: memory-controllers: Add i.MX8MP
> DDRC binding doc
>
> On Fri, Feb 21, 2020 at 02:39:14PM +0800, sherry sun wrote:
> > From: Sherry Sun <[email protected]>
> >
> > Add documentation for i.MX8MP DDRC binding based on synopsys_edac
> doc,
> > which use the same memory-controller IP.
> >
> > Signed-off-by: Sherry Sun <[email protected]>
> > ---
> > .../devicetree/bindings/memory-controllers/synopsys.txt | 8 ++++++--
> > 1 file changed, 6 insertions(+), 2 deletions(-)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
> > b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
> > index 9d32762c47e1..5c03959a451f 100644
> > ---
> > a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt
> > +++ b/Documentation/devicetree/bindings/memory-
> controllers/synopsys.tx
> > +++ t
> > @@ -6,16 +6,20 @@ bus width configurations.
> > The Zynq DDR ECC controller has an optional ECC support in half-bus
> > width
> > (16-bit) configuration.
> >
> > -These both ECC controllers correct single bit ECC errors and detect
> > double bit
> > +The i.MX8MP DDR ECC controller has an ECC support in 64-bit bus width
> > +configurations.
> > +
> > +These all ECC controllers correct single bit ECC errors and detect
> > +double bit
>
> All the ECC...
>
> With that,
>
> Reviewed-by: Rob Herring <[email protected]>
Thanks, I will correct it.
Best regards
Sherry Sun
>
> > ECC errors.
> >
> > Required properties:
> > - compatible: One of:
> > - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller
> > - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller
> > + - 'fsl,imx8mp-ddrc' : i.MX8MP DDR ECC controller
> > - reg: Should contain DDR controller registers location and length.
> >
> > -Required properties for "xlnx,zynqmp-ddrc-2.40a":
> > +Required properties for "xlnx,zynqmp-ddrc-2.40a" and "fsl,imx8mp-ddrc":
> > - interrupts: Property with a value describing the interrupt number.
> >
> > Example:
> > --
> > 2.17.1
> >