RE: [PATCH v3 1/4] edac: synps: Add platform specific structures for ddrc controller
Hi Boris, > -Original Message- > From: Borislav Petkov [mailto:b...@alien8.de] > Sent: Saturday, August 4, 2018 10:49 AM > Subject: Re: [PATCH v3 1/4] edac: synps: Add platform specific structures for > ddrc controller > > On Thu, Aug 02, 2018 at 06:21:19PM +0530, Manish Narani wrote: > > This patch adds platform specific structures, so that we can add > > "This patch" in a commit message is tautologically redundant. Okay. I will update this in v4. > > > different IP support later using quirks. > > > > Signed-off-by: Manish Narani > > --- > > drivers/edac/synopsys_edac.c | 64 > > > > 1 file changed, 53 insertions(+), 11 deletions(-) > > > > diff --git a/drivers/edac/synopsys_edac.c > > b/drivers/edac/synopsys_edac.c index 0c9c59e..d4798e8 100644 > > --- a/drivers/edac/synopsys_edac.c > > +++ b/drivers/edac/synopsys_edac.c > > @@ -22,6 +22,7 @@ > > #include > > #include > > #include > > +#include > > > > #include "edac_module.h" > > > > @@ -130,6 +131,7 @@ struct synps_ecc_status { > > * @baseaddr: Base address of the DDR controller > > * @message: Buffer for framing the event specific info > > * @stat: ECC status information > > + * @p_data:Pointer to platform data > > * @ce_cnt:Correctable Error count > > * @ue_cnt:Uncorrectable Error count > > */ > > @@ -137,11 +139,29 @@ struct synps_edac_priv { > > void __iomem *baseaddr; > > char message[SYNPS_EDAC_MSG_SIZE]; > > struct synps_ecc_status stat; > > + const struct synps_platform_data *p_data; > > u32 ce_cnt; > > u32 ue_cnt; > > }; > > > > /** > > + * struct synps_platform_data - synps platform data structure > > + * @synps_edac_geterror_info: function pointer to synps edac error > info > > + * @synps_edac_get_mtype: function pointer to synps edac mtype > > + * @synps_edac_get_dtype: function pointer to synps edac dtype > > + * @synps_edac_get_eccstate: function pointer to synps edac eccstate > > + * @quirks:to differentiate IPs > > + */ > > +struct synps_platform_data { > > + int (*synps_edac_geterror_info)(void __iomem *base, > > + struct synps_ecc_status *p); > > + enum mem_type (*synps_edac_get_mtype)(const void __iomem > *base); > > + enum dev_type (*synps_edac_get_dtype)(const void __iomem *base); > > + bool (*synps_edac_get_eccstate)(void __iomem *base); > > + int quirks; > > +}; > > + > > +/** > > * synps_edac_geterror_info - Get the current ecc error info > > * @base: Pointer to the base address of the ddr memory controller > > * @p: Pointer to the synopsys ecc status structure > > @@ -242,7 +262,8 @@ static void synps_edac_check(struct mem_ctl_info > *mci) > > struct synps_edac_priv *priv = mci->pvt_info; > > int status; > > > > - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); > > + status = priv->p_data->synps_edac_geterror_info(priv->baseaddr, > > + &priv->stat); > > Unnecessarily long line - shortening by renaming might help. Fair One. I will look to change the name. Also, May be I could use only 'priv' as argument and extract/use 'baseaddr' and 'stat' in the function definition itself. > > > @@ -372,10 +393,12 @@ static int synps_edac_init_csrows(struct > mem_ctl_info *mci) > > for (j = 0; j < csi->nr_channels; j++) { > > dimm= csi->channels[j]->dimm; > > dimm->edac_mode = EDAC_FLAG_SECDED; > > - dimm->mtype = synps_edac_get_mtype(priv- > >baseaddr); > > + dimm->mtype = priv->p_data- > >synps_edac_get_mtype( > > + priv->baseaddr); > > Ditto - that trailing opening brace at the end is just yucky. Shorten it and > let is > stick out even if it longer than 80 cols. Okay. Will modify it. > > > > > +static const struct synps_platform_data zynq_edac_def = { > > + .synps_edac_geterror_info = synps_edac_geterror_info, > > + .synps_edac_get_mtype = synps_edac_get_mtype, > > + .synps_edac_get_dtype = synps_edac_get_dtype, > > + .synps_edac_get_eccstate= synps_edac_get_eccstate, > > + .quirks = 0, > > Drop the "synps_" prefix from the function pointer names and leave them in > the actual function names so that when one looks at the code, knows what is > what. Okay. I will correct it in v4. Thanks, Manish Narani
[PATCH v4 1/4] edac: synps: Add platform specific structures for ddrc controller
Add platform specific structures, so that we can add different IP support later using quirks. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 83 ++-- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0c9c59e..b3c54e7 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "edac_module.h" @@ -130,6 +131,7 @@ struct synps_ecc_status { * @baseaddr: Base address of the DDR controller * @message: Buffer for framing the event specific info * @stat: ECC status information + * @p_data:Pointer to platform data * @ce_cnt:Correctable Error count * @ue_cnt:Uncorrectable Error count */ @@ -137,24 +139,47 @@ struct synps_edac_priv { void __iomem *baseaddr; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; + const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; }; /** + * struct synps_platform_data - synps platform data structure + * @edac_geterror_info:function pointer to synps edac error info + * @edac_get_mtype:function pointer to synps edac mtype + * @edac_get_dtype:function pointer to synps edac dtype + * @edac_get_eccstate: function pointer to synps edac eccstate + * @quirks:to differentiate IPs + */ +struct synps_platform_data { + int (*edac_geterror_info)(struct synps_edac_priv *priv); + enum mem_type (*edac_get_mtype)(const void __iomem *base); + enum dev_type (*edac_get_dtype)(const void __iomem *base); + bool (*edac_get_eccstate)(void __iomem *base); + int quirks; +}; + +/** * synps_edac_geterror_info - Get the current ecc error info - * @base: Pointer to the base address of the ddr memory controller - * @p: Pointer to the synopsys ecc status structure + * @priv: Pointer to DDR memory controller private instance data * * Determines there is any ecc error or not * * Return: one if there is no error otherwise returns zero */ -static int synps_edac_geterror_info(void __iomem *base, - struct synps_ecc_status *p) +static int synps_edac_geterror_info(struct synps_edac_priv *priv) { + void __iomem *base; + struct synps_ecc_status *p; u32 regval, clearval = 0; + if (!priv) + return 1; + + base = priv->baseaddr; + p = &priv->stat; + regval = readl(base + STAT_OFST); if (!regval) return 1; @@ -240,9 +265,10 @@ static void synps_edac_handle_error(struct mem_ctl_info *mci, static void synps_edac_check(struct mem_ctl_info *mci) { struct synps_edac_priv *priv = mci->pvt_info; + const struct synps_platform_data *p_data = priv->p_data; int status; - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); + status = p_data->edac_geterror_info(priv); if (status) return; @@ -362,6 +388,7 @@ static int synps_edac_init_csrows(struct mem_ctl_info *mci) struct csrow_info *csi; struct dimm_info *dimm; struct synps_edac_priv *priv = mci->pvt_info; + const struct synps_platform_data *p_data = priv->p_data; u32 size; int row, j; @@ -370,12 +397,13 @@ static int synps_edac_init_csrows(struct mem_ctl_info *mci) size = synps_edac_get_memsize(); for (j = 0; j < csi->nr_channels; j++) { - dimm= csi->channels[j]->dimm; + dimm = csi->channels[j]->dimm; dimm->edac_mode = EDAC_FLAG_SECDED; - dimm->mtype = synps_edac_get_mtype(priv->baseaddr); - dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; - dimm->grain = SYNPS_EDAC_ERR_GRAIN; - dimm->dtype = synps_edac_get_dtype(priv->baseaddr); + dimm->mtype = p_data->edac_get_mtype(priv->baseaddr); + dimm->nr_pages = (size >> PAGE_SHIFT) / + csi->nr_channels; + dimm->grain = SYNPS_EDAC_ERR_GRAIN; + dimm->dtype = p_data->edac_get_dtype(priv->baseaddr); } } @@ -423,6 +451,21 @@ static int synps_edac_mc_init(struct mem_ctl_info *mci, return status; } +static const struct synps_platform_data zynq_edac_def = { + .edac_geterror_info = synps_edac_geterror_info, + .edac_get_mtype = synps_edac_get_mtype, + .edac_get_dtype = synps_edac_get_dtype, + .edac_get_eccstate = synps_edac_get_eccst
[PATCH v4 2/4] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
This patch adds information of ZynqMP DDRC which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v4 3/4] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
Add EDAC ECC support for ZynqMP DDRC IP. Also add support for ECC Error Injection in ZynqMP. The corrected and uncorrected error interrupts support is added. The Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 864 ++- 2 files changed, 848 insertions(+), 18 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..b1fc7a16 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index b3c54e7..82f276b 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "edac_module.h" @@ -96,6 +97,170 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) + +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORT BIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST 0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON1_BANKGRP_SHIFT 28 +#define ECC_POISON1_BANKNR_SHIFT 24 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_DEV_CONFIG_MASK 0xC000 +#define DDRC_MSTR_DEV_CONFIG_SHIFT 30 +#define DDRC_MSTR_DEV_CONFIG_X4_MASK 0x0 +#define DDRC_MSTR_DEV_CONFIG_X8_MASK 0x1 +#define DDRC_MSTR_DEV_CONFIG_X16_MASK 0x2 +#define DDRC_MSTR_DEV_CONFIG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#define ROW_MAX_VAL_MASK 0xF +#define COL_MAX_VAL_MASK 0xF +#define BAN
[PATCH v4 4/4] arm64: zynqmp: Add DDRC node
This patch adds ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at fd090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index a091e6f..7d6a3cf 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH v4 0/4] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms.This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Changes in v3: - The commit message in (2/4) is modified (Synopsys EDAC Driver --> ZynqMP DDRC) Changes in v4: - Updated the commit message in (1/4) - Renamed function pointer names removing 'synps_' in (1/4) - Shortened unnecessary long lines as per the review comment on (1/4) Manish Narani (4): edac: synps: Add platform specific structures for ddrc controller dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node .../bindings/memory-controllers/synopsys.txt | 27 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 945 - 4 files changed, 941 insertions(+), 40 deletions(-) -- 2.1.1
RE: [PATCH v4 0/4] EDAC: Enhancements to Synopsys EDAC driver
Hi Boris, > -Original Message- > From: Borislav Petkov [mailto:b...@alien8.de] > Sent: Saturday, August 4, 2018 10:03 PM > Subject: Re: [PATCH v4 0/4] EDAC: Enhancements to Synopsys EDAC driver > > On Sat, Aug 04, 2018 at 02:55:31PM +0530, Manish Narani wrote: > > This patch series enhances the current EDAC driver to support > > different > > This one, your 2/4 and 4/4 still says "this patch". Hurried too much? > How about slowing down and looking at them with a critical eye? > > Also, how about waiting for a week before resending your patches so that you > give people chance to review them too? > > While you wait, please read Documentation/process/submitting-patches.rst > - it'll help you with the submission modalities. Yes, I missed it. Sorry for that. I will surely wait for around a week for others to review. Thanks for the guidance. Thanks, Manish Narani
RE: [RFC PATCH 2/3] dt: bindings: Add SD tap value properties details
Hi Mark, > -Original Message- > From: Mark Rutland [mailto:mark.rutl...@arm.com] > Sent: Thursday, June 7, 2018 6:18 PM > To: Manish Narani > Cc: robh...@kernel.org; catalin.mari...@arm.com; will.dea...@arm.com; > m...@kernel.org; stefan.krsmano...@aggios.com; linux-arm- > ker...@lists.infradead.org; linux-kernel@vger.kernel.org; linux- > m...@vger.kernel.org; devicet...@vger.kernel.org; adrian.hun...@intel.com; > michal.si...@xilinx.com; ulf.hans...@linaro.org > Subject: Re: [RFC PATCH 2/3] dt: bindings: Add SD tap value properties details > > On Thu, Jun 07, 2018 at 05:41:39PM +0530, Manish Narani wrote: > > This patch adds details of SD tap value properties in device tree. > > > > Signed-off-by: Manish Narani > > --- > > .../devicetree/bindings/mmc/arasan,sdhci.txt | 26 > ++ > > 1 file changed, 26 insertions(+) > > > > diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt > > b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt > > index 60481bf..0e08877 100644 > > --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt > > +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt > > @@ -15,6 +15,8 @@ Required Properties: > > - "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY > > - "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY > >For this device it is strongly suggested to include > > arasan,soc-ctl-syscon. > > +- "xlnx,zynqmp-8.9a": Xilinx ZynqMP Arasan SDHCI 8.9a PHY > > + For this device it is strongly suggested to include > > arasan,soc-ctl-syscon. > >- reg: From mmc bindings: Register location and length. > >- clocks: From clock bindings: Handles to clock inputs. > >- clock-names: From clock bindings: Tuple including "clk_xin" and > > "clk_ahb" > > @@ -26,6 +28,30 @@ Required Properties for "arasan,sdhci-5.1": > >- phys: From PHY bindings: Phandle for the Generic PHY for arasan. > >- phy-names: MUST be "phy_arasan". > > > > +Required Properties for "xlnx,zynqmp-8.9a": > > + - xlnx,mio_bank: The value will be 0/1/2 depending on MIO bank selection. > > For all of these properties, please s/_/-/, folowing the usual property name > conventions. I will correct this in the next version. > > It's not clear to me why you need this property. The code in patch 3 only > seems > to use this to determine which properties to read, choosing between _b0 > or _b2. I don't see why you dont have the base alone... The property 'xlnx,mio_bank' will be different for various ZynqMP varients. So different ZynqMP dts files may have different values for 'xlnx,mio_bank'. That's why I am maintaining _b0 and _b2 as different values > > Is this a HW detail, or configuration that you prefer? These are SD tap values which are generally used for configuring taps in SD. Keeping it in device tree makes it User Configurable without changing the driver code. > > > + - xlnx,device_id: Unique Id of the device, value will be 0/1. > > What's this used for? This used to identify the controller ID between two SD controllers present on ZynqMP. > > > + - xlnx,itap_delay_sd_hsd: Input Tap Delay for SD HS. > > What unit at hese delays in? The tap values don't have specific units. They are generally a fraction of the clock cycle. For the SD frequency of - 200 MHz: 30 Input taps are available 100 MHz: 60 Input taps are available 50 MHz: 120 Input taps are available 200 MHz: 8 Output taps are available 100 MHz: 15 Output taps are available 50 MHz: 30 Output taps are available Thanks, Manish > > Please follow the conventions in > Documentation/devicetree/bindings/property-units.txt. > > > + - xlnx,itap_delay_sdr25: Input Tap Delay for SDR25. > > + - xlnx,itap_delay_sdr50: Input Tap Delay for SDR50. > > + - xlnx,itap_delay_sdr104_b0: Input Tap Delay for SDR104. > > + - xlnx,itap_delay_sdr104_b2: Input Tap Delay for SDR104. > > As above, Given you have to specify the bank, I don't see why you need > multiple > properties. > > Thanks, > Mark. > > > + - xlnx,itap_delay_sd_ddr50: Input Tap Delay for SD DDR50. > > + - xlnx,itap_delay_mmc_hsd: Input Tap Delay for MMC HS. > > + - xlnx,itap_delay_mmc_ddr50: Input Tap Delay for MMC DDR50. > > + - xlnx,itap_delay_mmc_hs200_b0: Input Tap Delay for MMC HS200. > > + - xlnx,itap_delay_mmc_hs200_b2: Input Tap Delay for MMC HS200. > > + - xlnx,otap_delay_sd_hsd: Output Tap Delay for SD HS. > > + - xlnx,otap_delay_sdr25: Output Tap
RE: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay values from DT
Hi Adrian, > -Original Message- > From: Adrian Hunter [mailto:adrian.hun...@intel.com] > Sent: Tuesday, June 19, 2018 5:08 PM > To: Manish Narani ; robh...@kernel.org; > catalin.mari...@arm.com; will.dea...@arm.com; m...@kernel.org; > stefan.krsmano...@aggios.com; linux-arm-ker...@lists.infradead.org; linux- > ker...@vger.kernel.org; linux-...@vger.kernel.org; > devicet...@vger.kernel.org; Michal Simek ; > ulf.hans...@linaro.org > Cc: Srinivas Goud ; Anirudha Sarangi > > Subject: Re: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay > values from DT > > On 14/06/18 08:38, Manish Narani wrote: > > Ping for RFC > > What is eemi? Why aren't there patches for that? Eemi(Extensible Energy Management Interface) is a power management interface for ZynqMP core. The patches for the same are already in process of mainlining. https://lkml.org/lkml/2018/6/20/823 Thanks, Manish > > > > >> -Original Message- > >> From: Manish Narani [mailto:manish.nar...@xilinx.com] > >> Sent: Thursday, June 7, 2018 5:42 PM > >> To: robh...@kernel.org; mark.rutl...@arm.com; > >> catalin.mari...@arm.com; will.dea...@arm.com; m...@kernel.org; > >> stefan.krsmano...@aggios.com; linux-arm-ker...@lists.infradead.org; > >> linux-kernel@vger.kernel.org; linux- m...@vger.kernel.org; > >> devicet...@vger.kernel.org; adrian.hun...@intel.com; > >> michal.si...@xilinx.com; ulf.hans...@linaro.org > >> Cc: Manish Narani > >> Subject: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay > >> values from DT > >> > >> This patch adds support for reading Tap Delay values from Device Tree > >> and write them via eemi calls. The macros containing these tap delay > >> values are removed from the driver. > >> > >> Signed-off-by: Manish Narani > >> --- > >> drivers/mmc/host/sdhci-of-arasan.c | 131 > >> + > >> 1 file changed, 131 insertions(+) > >> > >> diff --git a/drivers/mmc/host/sdhci-of-arasan.c > >> b/drivers/mmc/host/sdhci- of-arasan.c index e3332a5..fc0fd01 100644 > >> --- a/drivers/mmc/host/sdhci-of-arasan.c > >> +++ b/drivers/mmc/host/sdhci-of-arasan.c > >> @@ -36,6 +36,8 @@ > >> > >> #define PHY_CLK_TOO_SLOW_HZ 40 > >> > >> +#define MMC_BANK2 0x2 > >> + > >> /* > >> * On some SoCs the syscon area has a feature where the upper 16-bits of > >> * each 32-bit register act as a write mask for the lower 16-bits. > >> This allows @@ -90,6 +92,10 @@ struct sdhci_arasan_data { > >>struct sdhci_host *host; > >>struct clk *clk_ahb; > >>struct phy *phy; > >> + u32 mio_bank; > >> + u32 device_id; > >> + u32 itapdly[MMC_TIMING_MMC_HS400 + 1]; > >> + u32 otapdly[MMC_TIMING_MMC_HS400 + 1]; > >>boolis_phy_on; > >> > >>boolhas_cqe; > >> @@ -160,11 +166,36 @@ static int sdhci_arasan_syscon_write(struct > >> sdhci_host *host, > >>return ret; > >> } > >> > >> +/** > >> + * arasan_zynqmp_set_tap_delay - Program the tap delays. > >> + * @deviceid: Unique Id of device > >> + * @itap_delay: Input Tap Delay > >> + * @oitap_delay: Output Tap Delay > >> + */ > >> +static void arasan_zynqmp_set_tap_delay(u8 deviceid, u8 itap_delay, > >> +u8 > >> +otap_delay) { > >> + const struct zynqmp_eemi_ops *eemi_ops = > >> zynqmp_pm_get_eemi_ops(); > >> + u32 node_id = (deviceid == 0) ? NODE_SD_0 : NODE_SD_1; > >> + > >> + if (!eemi_ops || !eemi_ops->ioctl) > >> + return; > >> + > >> + if (itap_delay) > >> + eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, > >> + PM_TAPDELAY_INPUT, itap_delay, NULL); > >> + > >> + if (otap_delay) > >> + eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, > >> + PM_TAPDELAY_OUTPUT, otap_delay, NULL); > >> } > >> + > >> static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned > >> int > >> clock) { > >>struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > >>struct sdhci_arasan_data *sdhci_arasan = > >> sdhci_pltfm_priv(pltfm_host); > >>bool ctrl_phy = false; > >> + u8 itap_delay; > >> + u8 otap_delay; > >>
[PATCH 0/3] Add Xilinx AMS Driver
Add Xilinx AMS driver which is used for Xilinx's ZynqMP AMS controller. This AMS driver is used to report various interface voltages and temperatures across the system. This driver handles AMS module including PS-Sysmon & PL-Sysmon. The binding documentation is added for understanding of AMS, PS, PL Sysmon Channels. Manish Narani (3): dt-bindings: iio: adc: Add Xilinx AMS binding documentation iio: adc: Add Xilinx AMS driver arm64: zynqmp: DT: Add Xilinx AMS node .../devicetree/bindings/iio/adc/xilinx-ams.txt | 159 +++ arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 26 + drivers/iio/adc/Kconfig| 10 + drivers/iio/adc/Makefile |1 + drivers/iio/adc/xilinx-ams.c | 1081 drivers/iio/adc/xilinx-ams.h | 281 + 6 files changed, 1558 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/xilinx-ams.txt create mode 100644 drivers/iio/adc/xilinx-ams.c create mode 100644 drivers/iio/adc/xilinx-ams.h -- 2.1.1
[PATCH 3/3] arm64: zynqmp: DT: Add Xilinx AMS node
The Xilinx AMS includes an ADC as well as on-chip sensors that can be used to sample external and monitor on-die operating conditions, such as temperature and supply voltage levels. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 26 ++ 1 file changed, 26 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 29ce234..6e42ca2 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -617,5 +617,31 @@ reg = <0x0 0xfd4d 0x0 0x1000>; timeout-sec = <10>; }; + + xilinx_ams: ams@ffa5 { + compatible = "xlnx,zynqmp-ams"; + status = "disabled"; + interrupt-parent = <&gic>; + interrupts = <0 56 4>; + interrupt-names = "ams-irq"; + reg = <0x0 0xffa5 0x0 0x800>; + reg-names = "ams-base"; + #address-cells = <2>; + #size-cells = <2>; + #io-channel-cells = <1>; + ranges; + + ams_ps: ams_ps@ffa50800 { + compatible = "xlnx,zynqmp-ams-ps"; + status = "disabled"; + reg = <0x0 0xffa50800 0x0 0x400>; + }; + + ams_pl: ams_pl@ffa50c00 { + compatible = "xlnx,zynqmp-ams-pl"; + status = "disabled"; + reg = <0x0 0xffa50c00 0x0 0x400>; + }; + }; }; }; -- 2.1.1
[PATCH 2/3] iio: adc: Add Xilinx AMS driver
The AMS includes an ADC as well as on-chip sensors that can be used to sample external voltages and monitor on-die operating conditions, such as temperature and supply voltage levels. The AMS has two SYSMON blocks. PL-SYSMON block is capable of monitoring off chip voltage and temperature. PL-SYSMON block has DRP, JTAG and I2C interface to enable monitoring from external master. Out of these interface currently only DRP is supported. Other block PS-SYSMON is memory mapped to PS. The AMS can use internal channels to monitor voltage and temperature as well as one primary and up to 16 auxiliary channels for measuring external voltages. The voltage and temperature monitoring channels also have event capability which allows to generate an interrupt when their value falls below or raises above a set threshold. Signed-off-by: Manish Narani --- drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile |1 + drivers/iio/adc/xilinx-ams.c | 1081 ++ drivers/iio/adc/xilinx-ams.h | 281 +++ 4 files changed, 1373 insertions(+) create mode 100644 drivers/iio/adc/xilinx-ams.c create mode 100644 drivers/iio/adc/xilinx-ams.h diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 4a75492..405ea00 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -941,4 +941,14 @@ config XILINX_XADC The driver can also be build as a module. If so, the module will be called xilinx-xadc. +config XILINX_AMS + tristate "Xilinx AMS driver" + depends on ARCH_ZYNQMP || COMPILE_TEST + depends on HAS_IOMEM + help + Say yes here to have support for the Xilinx AMS. + + The driver can also be build as a module. If so, the module will be called + xilinx-ams. + endmenu diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 03db7b5..fbfcc45 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -85,4 +85,5 @@ obj-$(CONFIG_VF610_ADC) += vf610_adc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o +obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c new file mode 100644 index 000..10bcc52 --- /dev/null +++ b/drivers/iio/adc/xilinx-ams.c @@ -0,0 +1,1081 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx AMS driver + * + * Copyright (C) 2017-2018 Xilinx, Inc. + * + * Manish Narani + * Rajnikant Bhojani + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xilinx-ams.h" + +static const unsigned int AMS_UNMASK_TIMEOUT_MS = 500; + +static inline void ams_ps_update_reg(struct ams *ams, unsigned int offset, +u32 mask, u32 data) +{ + u32 val; + + val = readl(ams->ps_base + offset); + writel((val & ~mask) | (data & mask), ams->ps_base + offset); +} + +static inline void ams_pl_write_reg(struct ams *ams, unsigned int offset, + u32 data) +{ + writel(data, ams->pl_base + offset); +} + +static inline void ams_pl_update_reg(struct ams *ams, unsigned int offset, +u32 mask, u32 data) +{ + u32 val; + + val = readl(ams->pl_base + offset); + writel((val & ~mask) | (data & mask), ams->pl_base + offset); +} + +static void ams_update_intrmask(struct ams *ams, u64 mask, u64 val) +{ + ams->intr_mask &= ~mask; + ams->intr_mask |= (val & mask); + + writel(~(ams->intr_mask | ams->masked_alarm), ams->base + AMS_IER_0); + writel(~(ams->intr_mask >> AMS_ISR1_INTR_MASK_SHIFT), + ams->base + AMS_IER_1); + writel(ams->intr_mask | ams->masked_alarm, ams->base + AMS_IDR_0); + writel(ams->intr_mask >> AMS_ISR1_INTR_MASK_SHIFT, + ams->base + AMS_IDR_1); +} + +static void ams_disable_all_alarms(struct ams *ams) +{ + /* disable PS module alarm */ + if (ams->ps_base) { + ams_ps_update_reg(ams, AMS_REG_CONFIG1, AMS_REGCFG1_ALARM_MASK, + AMS_REGCFG1_ALARM_MASK); + ams_ps_update_reg(ams, AMS_REG_CONFIG3, AMS_REGCFG3_ALARM_MASK, + AMS_REGCFG3_ALARM_MASK); + } + + /* disable PL module alarm */ + if (ams->pl_base) { + ams_pl_update_reg(ams, AMS_REG_CONFIG1, + AMS_REGCFG1_ALARM_MASK, + AMS_REGCFG1_ALARM_MASK); + ams_pl_update_reg(ams, AMS_REG_CONFIG3, + AMS_REGCFG3_ALARM_MA
[PATCH 1/3] dt-bindings: iio: adc: Add Xilinx AMS binding documentation
Xilinx AMS have several ADC channels that can be used for measurement of different voltages and temperatures. Document the same in the bindings. Signed-off-by: Manish Narani --- .../devicetree/bindings/iio/adc/xilinx-ams.txt | 159 + 1 file changed, 159 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/xilinx-ams.txt diff --git a/Documentation/devicetree/bindings/iio/adc/xilinx-ams.txt b/Documentation/devicetree/bindings/iio/adc/xilinx-ams.txt new file mode 100644 index 000..8cc96f0 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/xilinx-ams.txt @@ -0,0 +1,159 @@ +Xilinx AMS controller + +The AMS includes an ADC as well as on-chip sensors that can be used to +sample external voltages and monitor on-die operating conditions, such as +temperature and supply voltage levels. The AMS has two SYSMON blocks. +PL-SYSMON block is capable of monitoring off chip voltage and temperature. +PL-SYSMON block has DRP, JTAG and I2C interface to enable monitoring from +external master. Out of this interface currently only DRP is supported. +Other block PS-SYSMON is memory mapped to PS. Both of block has built-in +alarm generation logic that is used to interrupt the processor based on +condition set. + +All designs should have AMS registers, but PS and PL are optional. The +AMS controller can work with only PS, only PL and both PS and PL +configurations. Please specify registers according to your design. Devicetree +should always have AMS module property. Providing PS & PL module is optional. + +Required properties: + - compatible: Should be "xlnx,zynqmp-ams" + - reg: Should specify AMS register space + - interrupts: Interrupt number for the AMS control interface + - interrupt-names: Interrupt name, must be "ams-irq" + - clocks: Should contain a clock specifier for the device + - ranges: keep the property empty to map child address space + (for PS and/or PL) nodes 1:1 onto the parent address + space + +AMS device tree subnode: + - compatible: Should be "xlnx,zynqmp-ams-ps" or "xlnx,zynqmp-ams-pl" + - reg: Register space for PS or PL + +Optional properties: + +Following optional property only valid for PL. + - xlnx,ext-channels: List of external channels that are connected to the +AMS PL module. + + The child nodes of this node represent the external channels which are + connected to the AMS Module. If the property is not present + no external channels will be assumed to be connected. + + Each child node represents one channel and has the following + properties: + Required properties: + * reg: Pair of pins the channel is connected to. + 0: VP/VN + 1: VUSER0 + 2: VUSER1 + 3: VUSER3 + 4: VUSER4 + 5: VAUXP[0]/VAUXN[0] + 6: VAUXP[1]/VAUXN[1] + ... + 20: VAUXP[15]/VAUXN[15] + Note each channel number should only be used at most + once. + Optional properties: + * xlnx,bipolar: If set the channel is used in bipolar + mode. + + +Example: + xilinx_ams: ams@ffa5 { + compatible = "xlnx,zynqmp-ams"; + interrupt-parent = <&gic>; + interrupts = <0 56 4>; + interrupt-names = "ams-irq"; + clocks = <&clkc 70>; + reg = <0x0 0xffa5 0x0 0x800>; + reg-names = "ams-base"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ams_ps: ams_ps@ffa50800 { + compatible = "xlnx,zynqmp-ams-ps"; + reg = <0x0 0xffa50800 0x0 0x400>; + }; + + ams_pl: ams_pl@ffa50c00 { + compatible = "xlnx,zynqmp-ams-pl"; + reg = <0x0 0xffa50c00 0x0 0x400>; + xlnx,ext-channels { + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + xlnx,bipolar; + }; + channel@1 { + reg = <1>; + }; + channel@8 { +
RE: [PATCH v4 1/4] edac: synps: Add platform specific structures for ddrc controller
Hi Boris, Thank you so much for the review. > -Original Message- > From: Borislav Petkov [mailto:b...@alien8.de] > Sent: Tuesday, August 21, 2018 6:37 PM > To: Manish Narani > Cc: robh...@kernel.org; mark.rutl...@arm.com; catalin.mari...@arm.com; > will.dea...@arm.com; Michal Simek ; > mche...@kernel.org; m...@kernel.org; Edgar Iglesias ; > Shubhrajyoti Datta ; Naga Sureshkumar Relli > ; Bharat Kumar Gogada ; > stefan.krsmano...@aggios.com; Srinivas Goud ; Anirudha > Sarangi ; linux-kernel@vger.kernel.org; > devicet...@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux- > e...@vger.kernel.org > Subject: Re: [PATCH v4 1/4] edac: synps: Add platform specific structures for > ddrc controller > > On Sat, Aug 04, 2018 at 02:55:32PM +0530, Manish Narani wrote: > > Add platform specific structures, so that we can add different IP > > support later using quirks. > > > > Signed-off-by: Manish Narani > > --- > > drivers/edac/synopsys_edac.c | 83 > > ++-- > > 1 file changed, 65 insertions(+), 18 deletions(-) > > > > diff --git a/drivers/edac/synopsys_edac.c > > b/drivers/edac/synopsys_edac.c index 0c9c59e..b3c54e7 100644 > > --- a/drivers/edac/synopsys_edac.c > > +++ b/drivers/edac/synopsys_edac.c > > @@ -22,6 +22,7 @@ > > #include > > #include > > #include > > +#include > > > > #include "edac_module.h" > > > > @@ -130,6 +131,7 @@ struct synps_ecc_status { > > * @baseaddr: Base address of the DDR controller > > * @message: Buffer for framing the event specific info > > * @stat: ECC status information > > + * @p_data:Pointer to platform data > > * @ce_cnt:Correctable Error count > > * @ue_cnt:Uncorrectable Error count > > */ > > @@ -137,24 +139,47 @@ struct synps_edac_priv { > > void __iomem *baseaddr; > > char message[SYNPS_EDAC_MSG_SIZE]; > > struct synps_ecc_status stat; > > + const struct synps_platform_data *p_data; > > u32 ce_cnt; > > u32 ue_cnt; > > }; > > > > /** > > + * struct synps_platform_data - synps platform data structure > > + * @edac_geterror_info:function pointer to synps edac error info > > + * @edac_get_mtype:function pointer to synps edac mtype > > + * @edac_get_dtype:function pointer to synps edac dtype > > + * @edac_get_eccstate: function pointer to synps edac eccstate > > + * @quirks:to differentiate IPs > > + */ > > +struct synps_platform_data { > > + int (*edac_geterror_info)(struct synps_edac_priv *priv); > > + enum mem_type (*edac_get_mtype)(const void __iomem *base); > > + enum dev_type (*edac_get_dtype)(const void __iomem *base); > > + bool (*edac_get_eccstate)(void __iomem *base); > > + int quirks; > > +}; > > + > > +/** > > * synps_edac_geterror_info - Get the current ecc error info > > - * @base: Pointer to the base address of the ddr memory controller > > - * @p: Pointer to the synopsys ecc status structure > > + * @priv: Pointer to DDR memory controller private instance data > > * > > * Determines there is any ecc error or not > > * > > * Return: one if there is no error otherwise returns zero > > */ > > -static int synps_edac_geterror_info(void __iomem *base, > > - struct synps_ecc_status *p) > > +static int synps_edac_geterror_info(struct synps_edac_priv *priv) > > { > > + void __iomem *base; > > + struct synps_ecc_status *p; > > u32 regval, clearval = 0; > > > > + if (!priv) > > + return 1; > > + > > + base = priv->baseaddr; > > + p = &priv->stat; > > + > > regval = readl(base + STAT_OFST); > > if (!regval) > > return 1; > > @@ -240,9 +265,10 @@ static void synps_edac_handle_error(struct > > mem_ctl_info *mci, static void synps_edac_check(struct mem_ctl_info > > *mci) { > > struct synps_edac_priv *priv = mci->pvt_info; > > + const struct synps_platform_data *p_data = priv->p_data; > > int status; > > > > - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); > > + status = p_data->edac_geterror_info(priv); > > if (status) > > return; > > > > @@ -362,6 +388,7 @@ static int synps_edac_init_csrows(struct > mem_ctl_info *mci) > > struct csrow_info *csi; > > struct dimm_info *dimm; &
RE: [PATCH v4 3/4] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
Hi Boris, Thanks a lot for the review. > -Original Message- > From: Borislav Petkov [mailto:b...@alien8.de] > Sent: Tuesday, August 21, 2018 6:40 PM > To: Manish Narani > Cc: robh...@kernel.org; mark.rutl...@arm.com; catalin.mari...@arm.com; > will.dea...@arm.com; Michal Simek ; > mche...@kernel.org; m...@kernel.org; Edgar Iglesias ; > Shubhrajyoti Datta ; Naga Sureshkumar Relli > ; Bharat Kumar Gogada ; > stefan.krsmano...@aggios.com; Srinivas Goud ; Anirudha > Sarangi ; linux-kernel@vger.kernel.org; > devicet...@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux- > e...@vger.kernel.org > Subject: Re: [PATCH v4 3/4] edac: synopsys: Add EDAC ECC support for ZynqMP > DDRC > > On Sat, Aug 04, 2018 at 02:55:34PM +0530, Manish Narani wrote: > > Add EDAC ECC support for ZynqMP DDRC IP. Also add support for ECC > > Error Injection in ZynqMP. The corrected and uncorrected error > > interrupts support is added. The Row, Column, Bank, Bank Group and > > Rank bits positions are determined via Address Map registers of Synopsys > DDRC. > > > > Signed-off-by: Manish Narani > > --- > > drivers/edac/Kconfig | 2 +- > > drivers/edac/synopsys_edac.c | 864 > > ++- > > 2 files changed, 848 insertions(+), 18 deletions(-) > > > > diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index > > 57304b2..b1fc7a16 100644 > > --- a/drivers/edac/Kconfig > > +++ b/drivers/edac/Kconfig > > @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC > > > > config EDAC_SYNOPSYS > > tristate "Synopsys DDR Memory Controller" > > - depends on ARCH_ZYNQ > > + depends on ARCH_ZYNQ || ARM64 > > help > > Support for error detection and correction on the Synopsys DDR > > memory controller. > > diff --git a/drivers/edac/synopsys_edac.c > > b/drivers/edac/synopsys_edac.c index b3c54e7..82f276b 100644 > > --- a/drivers/edac/synopsys_edac.c > > +++ b/drivers/edac/synopsys_edac.c > > @@ -22,6 +22,7 @@ > > #include > > #include > > #include > > +#include > > #include > > > > #include "edac_module.h" > > @@ -96,6 +97,170 @@ > > #define SCRUB_MODE_MASK0x7 > > #define SCRUB_MODE_SECDED 0x4 > > > > +/* DDR ECC Quirks */ > > +#define DDR_ECC_INTR_SUPPORT BIT(0) > > + > > +/* DDR ECC Quirks */ > > +#define DDR_ECC_INTR_SUPPORT BIT(0) > > This is repeated. I missed that. I will update the same in v5. > > > +#define DDR_ECC_DATA_POISON_SUPPORT BIT(1) > > + > > +/* ZynqMP Enhanced DDR memory controller registers that are relevant > > +to ECC */ > > +/* ECC Configuration Registers */ > > +#define ECC_CFG0_OFST 0x70 > > +#define ECC_CFG1_OFST 0x74 > > + > > +/* ECC Status Register */ > > +#define ECC_STAT_OFST 0x78 > > + > > +/* ECC Clear Register */ > > +#define ECC_CLR_OFST 0x7C > > + > > +/* ECC Error count Register */ > > +#define ECC_ERRCNT_OFST0x80 > > Do you not see how the rest of the defines' values are aligned vertically in > this > file? Will work in this and update the same. > > > + > > +/* ECC Corrected Error Address Register */ > > +#define ECC_CEADDR0_OFST 0x84 > > +#define ECC_CEADDR1_OFST 0x88 > > + > > +/* ECC Syndrome Registers */ > > +#define ECC_CSYND0_OFST0x8C > > +#define ECC_CSYND1_OFST0x90 > > +#define ECC_CSYND2_OFST0x94 > > + > > +/* ECC Bit Mask0 Address Register */ > > +#define ECC_BITMASK0_OFST 0x98 > > +#define ECC_BITMASK1_OFST 0x9C > > +#define ECC_BITMASK2_OFST 0xA0 > > + > > +/* ECC UnCorrected Error Address Register */ > > +#define ECC_UEADDR0_OFST 0xA4 > > +#define ECC_UEADDR1_OFST 0xA8 > > + > > +/* ECC Syndrome Registers */ > > +#define ECC_UESYND0_OFST 0xAC > > +#define ECC_UESYND1_OFST 0xB0 > > +#define ECC_UESYND2_OFST 0xB4 > > + > > +/* ECC Poison Address Reg */ > > +#define ECC_POISON0_OFST 0xB8 > > +#define ECC_POISON1_OFST 0xBC > > + > > +#define ECC_ADDRMAP0_OFFSET0x200 > > + > > +/* Control register bitfield definitions */ > > +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 > > +#define ECC_CTRL_BUSWIDTH_SHIFT12 > > +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) > > +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) > > + > > +/* DDR Control Register width definitions */ > > +#define DDRCTL_EWDTH_162 > > +#define DDRCTL
RE: [PATCH v2 2/4] iio: adc: xilinx: limit pcap clock frequency value
Hi Jonathan, > -Original Message- > From: Jonathan Cameron [mailto:ji...@kernel.org] > Sent: Sunday, July 29, 2018 5:21 PM > To: Manish Narani > Cc: Sai Krishna Potthuri ; Michal Simek > ; pme...@pmeerw.net; l...@metafoo.de; > knaac...@gmx.de; Anirudha Sarangi ; Srinivas Goud > ; linux-kernel@vger.kernel.org; linux-arm- > ker...@lists.infradead.org; linux-...@vger.kernel.org > Subject: Re: [PATCH v2 2/4] iio: adc: xilinx: limit pcap clock frequency value > > On Mon, 23 Jul 2018 20:32:01 +0530 > Manish Narani wrote: > > > This patch limits the xadc pcap clock frequency value to be less than > > 200MHz. This fixes the issue when zynq is booted at higher frequency > > values, pcap crosses the maximum limit of 200MHz(Fmax) as it is > > derived from IOPLL. > > If this limit is crossed it is required to alter the WEDGE and REDGE > > bits of XADC_CFG register to make timings better in the interface. So > > to avoid alteration of these bits every time, the pcap value should > > not cross the Fmax limit. > > > > Signed-off-by: Manish Narani > > Applied, to the togreg branch of iio.git. If you want this backported to > stable, > then request it once this patch is upstream. It may be sometime given we've > probably just missed the coming merge window. > > If you do need it faster then let me know and I'll look at moving it over to > the > branch of fixes during the RC phases. Thanks for getting this applied. There is no concern for this to be in the stable ASAP. I can wait. Thanks & Regards, Manish Narani
[PATCH 2/4] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
This patch documents Synopsys EDAC driver which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani --- .../bindings/memory-controllers/synopsys.txt | 25 ++ 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..5d20b76 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects +Synopsys EDAC driver, it does reports the DDR ECC single bit errors +that are corrected and double bit ecc errors that are detected by the DDR +ECC controller. + +The Zynq DDR ECC controller has an optional ECC support in half-bus width +(16-bit) configuration. The ECC controller corrects one bit error and detects two bit errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupt-parent: Should be core interrupt controller. + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH 1/4] edac: synps: Add platform specific structures for ddrc controller
This patch adds platform specific structures, so that we can add different IP support later using quirks. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 70 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0c9c59e..447396e 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "edac_module.h" @@ -95,6 +96,9 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) + /** * struct ecc_error_info - ECC error log information * @row: Row number @@ -130,6 +134,7 @@ struct synps_ecc_status { * @baseaddr: Base address of the DDR controller * @message: Buffer for framing the event specific info * @stat: ECC status information + * @p_data:Pointer to platform data * @ce_cnt:Correctable Error count * @ue_cnt:Uncorrectable Error count */ @@ -137,11 +142,29 @@ struct synps_edac_priv { void __iomem *baseaddr; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; + const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; }; /** + * struct synps_platform_data - synps platform data structure + * @synps_edac_geterror_info: function pointer to synps edac error info + * @synps_edac_get_mtype: function pointer to synps edac mtype + * @synps_edac_get_dtype: function pointer to synps edac dtype + * @synps_edac_get_eccstate: function pointer to synps edac eccstate + * @quirks:to differentiate IPs + */ +struct synps_platform_data { + int (*synps_edac_geterror_info)(void __iomem *base, + struct synps_ecc_status *p); + enum mem_type (*synps_edac_get_mtype)(const void __iomem *base); + enum dev_type (*synps_edac_get_dtype)(const void __iomem *base); + bool (*synps_edac_get_eccstate)(void __iomem *base); + int quirks; +}; + +/** * synps_edac_geterror_info - Get the current ecc error info * @base: Pointer to the base address of the ddr memory controller * @p: Pointer to the synopsys ecc status structure @@ -242,7 +265,8 @@ static void synps_edac_check(struct mem_ctl_info *mci) struct synps_edac_priv *priv = mci->pvt_info; int status; - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); + status = priv->p_data->synps_edac_geterror_info(priv->baseaddr, + &priv->stat); if (status) return; @@ -372,10 +396,12 @@ static int synps_edac_init_csrows(struct mem_ctl_info *mci) for (j = 0; j < csi->nr_channels; j++) { dimm= csi->channels[j]->dimm; dimm->edac_mode = EDAC_FLAG_SECDED; - dimm->mtype = synps_edac_get_mtype(priv->baseaddr); + dimm->mtype = priv->p_data->synps_edac_get_mtype( + priv->baseaddr); dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; dimm->grain = SYNPS_EDAC_ERR_GRAIN; - dimm->dtype = synps_edac_get_dtype(priv->baseaddr); + dimm->dtype = priv->p_data->synps_edac_get_dtype( + priv->baseaddr); } } @@ -423,6 +449,21 @@ static int synps_edac_mc_init(struct mem_ctl_info *mci, return status; } +static const struct synps_platform_data zynq_edac_def = { + .synps_edac_geterror_info = synps_edac_geterror_info, + .synps_edac_get_mtype = synps_edac_get_mtype, + .synps_edac_get_dtype = synps_edac_get_dtype, + .synps_edac_get_eccstate= synps_edac_get_eccstate, + .quirks = 0, +}; + +static const struct of_device_id synps_edac_match[] = { + { .compatible = "xlnx,zynq-ddrc-a05", .data = (void *)&zynq_edac_def }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, synps_edac_match); + /** * synps_edac_mc_probe - Check controller and bind driver * @pdev: Pointer to the platform_device struct @@ -440,13 +481,22 @@ static int synps_edac_mc_probe(struct platform_device *pdev) int rc; struct resource *res; void __iomem *baseaddr; + const struct of_device_id *match; + const struct synps_platform_data *p_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); baseaddr = devm_ioremap_resource(&pdev->dev,
[PATCH 3/4] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
This patch adds EDAC ECC support for ZynqMP DDRC IP. The patch also adds support for ECC Error Injection in ZynqMP. The corrected and uncorrected error interrupts support is added in this patch. The Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 848 ++- 2 files changed, 833 insertions(+), 17 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..b1fc7a16 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 447396e..4380eb9 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "edac_module.h" @@ -98,6 +99,164 @@ /* DDR ECC Quirks */ #define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORT BIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST 0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON1_BANKGRP_SHIFT 28 +#define ECC_POISON1_BANKNR_SHIFT 24 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_DEV_CONFIG_MASK 0xC000 +#define DDRC_MSTR_DEV_CONFIG_SHIFT 30 +#define DDRC_MSTR_DEV_CONFIG_X4_MASK 0x0 +#define DDRC_MSTR_DEV_CONFIG_X8_MASK 0x1 +#define DDRC_MSTR_DEV_CONFIG_X16_MASK 0x2 +#define DDRC_MSTR_DEV_CONFIG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#define ROW_MAX_VAL_MASK 0xF +#define COL_MAX_VAL_MASK 0xF +#define BANK_MAX_VAL_MASK 0x1F +#define BANKGRP_MAX_VAL_MASK 0x1F +#define RANK_MAX_VAL_MASK 0x1
[PATCH 4/4] arm64: zynqmp: Add DDRC node
This patch adds ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at fd090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index a091e6f..7d6a3cf 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH 0/4] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms.This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Manish Narani (4): edac: synps: Add platform specific structures for ddrc controller dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node .../bindings/memory-controllers/synopsys.txt | 25 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 916 - 4 files changed, 918 insertions(+), 32 deletions(-) -- 2.1.1
RE: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay values from DT
Hi Uffe, > -Original Message- > From: Ulf Hansson [mailto:ulf.hans...@linaro.org] > Sent: Tuesday, July 10, 2018 2:02 PM > To: Manish Narani > Cc: Rob Herring ; Mark Rutland > ; Catalin Marinas ; Will > Deacon ; Moritz Fischer ; > stefan.krsmano...@aggios.com; Linux ARM ker...@lists.infradead.org>; Linux Kernel Mailing List ker...@vger.kernel.org>; linux-...@vger.kernel.org; > devicet...@vger.kernel.org; Adrian Hunter ; > Michal Simek > Subject: Re: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay > values from DT > > On 7 June 2018 at 14:11, Manish Narani wrote: > > This patch adds support for reading Tap Delay values from Device Tree > > and write them via eemi calls. The macros containing these tap delay > > values are removed from the driver. > > > > Signed-off-by: Manish Narani > > --- > > drivers/mmc/host/sdhci-of-arasan.c | 131 > > + > > 1 file changed, 131 insertions(+) > > > > diff --git a/drivers/mmc/host/sdhci-of-arasan.c > > b/drivers/mmc/host/sdhci-of-arasan.c > > index e3332a5..fc0fd01 100644 > > --- a/drivers/mmc/host/sdhci-of-arasan.c > > +++ b/drivers/mmc/host/sdhci-of-arasan.c > > @@ -36,6 +36,8 @@ > > > > #define PHY_CLK_TOO_SLOW_HZ40 > > > > +#define MMC_BANK2 0x2 > > + > > /* > > * On some SoCs the syscon area has a feature where the upper 16-bits of > > * each 32-bit register act as a write mask for the lower 16-bits. > > This allows @@ -90,6 +92,10 @@ struct sdhci_arasan_data { > > struct sdhci_host *host; > > struct clk *clk_ahb; > > struct phy *phy; > > + u32 mio_bank; > > + u32 device_id; > > + u32 itapdly[MMC_TIMING_MMC_HS400 + 1]; > > + u32 otapdly[MMC_TIMING_MMC_HS400 + 1]; > > boolis_phy_on; > > > > boolhas_cqe; > > @@ -160,11 +166,36 @@ static int sdhci_arasan_syscon_write(struct > sdhci_host *host, > > return ret; > > } > > > > +/** > > + * arasan_zynqmp_set_tap_delay - Program the tap delays. > > + * @deviceid: Unique Id of device > > + * @itap_delay:Input Tap Delay > > + * @oitap_delay: Output Tap Delay > > + */ > > +static void arasan_zynqmp_set_tap_delay(u8 deviceid, u8 itap_delay, > > +u8 otap_delay) { > > + const struct zynqmp_eemi_ops *eemi_ops = > > +zynqmp_pm_get_eemi_ops(); > > No thanks! > > Isn't there a more generic framework we can use to change the tap values, > rather than calling SoC specific functions from the driver? Yes, Thanks for your suggestion. I will work on the generic framework which will be used to change tap values Via SoC drivers. > > BTW, what is a tap value, more exactly? > What does changing a tap value mean and where does the property belong, > really? Tap Value is the delay of clock phase which is used to adjust phase to the working value. The auto tuning process generally sets tap values internally in controller in SD UHS modes. But for other modes where auto tuning is applicable, we are determining tap values via trial & error method for specific SoC. > > > Of course this doesn't even compile, as you have a dependency to another > series. Next time, please clarify that in a cover-letter (maybe you did, but I > can't find it). > > > + u32 node_id = (deviceid == 0) ? NODE_SD_0 : NODE_SD_1; > > + > > + if (!eemi_ops || !eemi_ops->ioctl) > > + return; > > + > > + if (itap_delay) > > + eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, > > + PM_TAPDELAY_INPUT, itap_delay, NULL); > > + > > + if (otap_delay) > > + eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, > > + PM_TAPDELAY_OUTPUT, otap_delay, NULL); > > +} > > Another overall comment for the series. > > I would recommend to change the order of the patches in the series. > Let the DT doc change come first, next the driver change and finally the > change > to the DTS file(s). This makes it easier to follow and review. Sure, I will do that. Thanks & Regards, Manish > > [...] > > Kind regards > Uffe
RE: [PATCH 4/4] iio: adc: xilinx: Use devm_ functions while requesting irq
Hi Lars, > -Original Message- > From: Lars-Peter Clausen [mailto:l...@metafoo.de] > Sent: Thursday, July 19, 2018 10:08 PM > To: Manish Narani ; ji...@kernel.org; > knaac...@gmx.de; pme...@pmeerw.net; Michal Simek > ; linux-...@vger.kernel.org; linux-arm- > ker...@lists.infradead.org; linux-kernel@vger.kernel.org > Cc: Anirudha Sarangi ; Srinivas Goud > > Subject: Re: [PATCH 4/4] iio: adc: xilinx: Use devm_ functions while > requesting > irq > > > @@ -1310,7 +1308,6 @@ static int xadc_remove(struct platform_device > > *pdev) { > > struct iio_dev *indio_dev = platform_get_drvdata(pdev); > > struct xadc *xadc = iio_priv(indio_dev); > > - int irq = platform_get_irq(pdev, 0); > > > > iio_device_unregister(indio_dev); > > if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { @@ -1318,7 +1315,6 > @@ > > static int xadc_remove(struct platform_device *pdev) > > iio_trigger_free(xadc->convst_trigger); > > iio_triggered_buffer_cleanup(indio_dev); > > } > > - free_irq(irq, indio_dev); > > This opens up a race condition. The IRQ needs to be freed before any of these > other things below the free_irq() are executed. Will look into it and send with taking care of the same. > > > clk_disable_unprepare(xadc->clk); > > cancel_delayed_work(&xadc->zynq_unmask_work); > > kfree(xadc->data); > > Thanks, Manish
RE: [PATCH 3/4] iio: adc: xilinx: Check for return values in clk related functions
Hi Jonathan, Thanks for your comments. > -Original Message- > From: Jonathan Cameron [mailto:ji...@kernel.org] > Sent: Saturday, July 21, 2018 9:54 PM > To: Lars-Peter Clausen > Cc: Manish Narani ; knaac...@gmx.de; > pme...@pmeerw.net; Michal Simek ; linux- > i...@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux- > ker...@vger.kernel.org; Anirudha Sarangi ; Srinivas > Goud > Subject: Re: [PATCH 3/4] iio: adc: xilinx: Check for return values in clk > related > functions > > On Thu, 19 Jul 2018 18:40:26 +0200 > Lars-Peter Clausen wrote: > > > On 07/18/2018 01:12 PM, Manish Narani wrote: > > > This patch adds check for return values from clock related functions. > > > This was reported by static code analysis tool. > > > > This patch seems to do something else. > Indeed, definitely doing two things only one of which is mentioned. > Please break it up and resend. I will break it up and resend. > > Jonathan > > > > > > > > > Signed-off-by: Manish Narani > > > --- > > > drivers/iio/adc/xilinx-xadc-core.c | 24 ++-- > > > 1 file changed, 22 insertions(+), 2 deletions(-) > > > > > > diff --git a/drivers/iio/adc/xilinx-xadc-core.c > > > b/drivers/iio/adc/xilinx-xadc-core.c > > > index 248cffa..47eb364 100644 > > > --- a/drivers/iio/adc/xilinx-xadc-core.c > > > +++ b/drivers/iio/adc/xilinx-xadc-core.c > > > @@ -322,6 +322,7 @@ static irqreturn_t > > > xadc_zynq_interrupt_handler(int irq, void *devid) > > > > > > #define XADC_ZYNQ_TCK_RATE_MAX 5000 #define > > > XADC_ZYNQ_IGAP_DEFAULT 20 > > > +#define XADC_ZYNQ_PCAP_RATE_MAX 2 > > > > > > static int xadc_zynq_setup(struct platform_device *pdev, > > > struct iio_dev *indio_dev, int irq) @@ -332,6 +333,7 @@ static int > > > xadc_zynq_setup(struct platform_device *pdev, > > > unsigned int div; > > > unsigned int igap; > > > unsigned int tck_rate; > > > + int ret; > > > > > > /* TODO: Figure out how to make igap and tck_rate configurable */ > > > igap = XADC_ZYNQ_IGAP_DEFAULT; > > > @@ -341,6 +343,13 @@ static int xadc_zynq_setup(struct > > > platform_device *pdev, > > > > > > pcap_rate = clk_get_rate(xadc->clk); > > > > > > + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { > > > + ret = clk_set_rate(xadc->clk, > > > +(unsigned > long)XADC_ZYNQ_PCAP_RATE_MAX); > > > + if (ret) > > > + return ret; > > > + } > > > + > > > if (tck_rate > pcap_rate / 2) { > > > div = 2; > > > } else { > > > @@ -366,6 +375,12 @@ static int xadc_zynq_setup(struct platform_device > *pdev, > > > XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE > | > > > tck_div | XADC_ZYNQ_CFG_IGAP(igap)); > > > > > > + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { > > > + ret = clk_set_rate(xadc->clk, pcap_rate); > > > + if (ret) > > > + return ret; > > > + } > > > + > > > return 0; > > > } > > > > > > @@ -887,6 +902,9 @@ static int xadc_write_raw(struct iio_dev *indio_dev, > > > unsigned long clk_rate = xadc_get_dclk_rate(xadc); > > > unsigned int div; > > > > > > + if (!clk_rate) > > > + return -EINVAL; > > > + > > > if (info != IIO_CHAN_INFO_SAMP_FREQ) > > > return -EINVAL; > > > > > > @@ -1239,8 +1257,10 @@ static int xadc_probe(struct platform_device > *pdev) > > > goto err_free_irq; > > > > > > /* Disable all alarms */ > > > - xadc_update_adc_reg(xadc, XADC_REG_CONF1, > XADC_CONF1_ALARM_MASK, > > > - XADC_CONF1_ALARM_MASK); > > > + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, > XADC_CONF1_ALARM_MASK, > > > + XADC_CONF1_ALARM_MASK); > > > + if (ret) > > > + goto err_free_irq; > > > > > > /* Set thresholds to min/max */ > > > for (i = 0; i < 16; i++) { > > > > > Thanks, Manish Narani
[PATCH v2 4/4] arm64: zynqmp: Add DDRC node
This patch adds ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at fd090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index a091e6f..7d6a3cf 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH v2 0/4] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms.This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Manish Narani (4): edac: synps: Add platform specific structures for ddrc controller dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node .../bindings/memory-controllers/synopsys.txt | 27 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 919 - 4 files changed, 922 insertions(+), 33 deletions(-) -- 2.1.1
[PATCH v2 2/4] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
This patch documents Synopsys EDAC driver which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v2 1/4] edac: synps: Add platform specific structures for ddrc controller
This patch adds platform specific structures, so that we can add different IP support later using quirks. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 64 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0c9c59e..d4798e8 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "edac_module.h" @@ -130,6 +131,7 @@ struct synps_ecc_status { * @baseaddr: Base address of the DDR controller * @message: Buffer for framing the event specific info * @stat: ECC status information + * @p_data:Pointer to platform data * @ce_cnt:Correctable Error count * @ue_cnt:Uncorrectable Error count */ @@ -137,11 +139,29 @@ struct synps_edac_priv { void __iomem *baseaddr; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; + const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; }; /** + * struct synps_platform_data - synps platform data structure + * @synps_edac_geterror_info: function pointer to synps edac error info + * @synps_edac_get_mtype: function pointer to synps edac mtype + * @synps_edac_get_dtype: function pointer to synps edac dtype + * @synps_edac_get_eccstate: function pointer to synps edac eccstate + * @quirks:to differentiate IPs + */ +struct synps_platform_data { + int (*synps_edac_geterror_info)(void __iomem *base, + struct synps_ecc_status *p); + enum mem_type (*synps_edac_get_mtype)(const void __iomem *base); + enum dev_type (*synps_edac_get_dtype)(const void __iomem *base); + bool (*synps_edac_get_eccstate)(void __iomem *base); + int quirks; +}; + +/** * synps_edac_geterror_info - Get the current ecc error info * @base: Pointer to the base address of the ddr memory controller * @p: Pointer to the synopsys ecc status structure @@ -242,7 +262,8 @@ static void synps_edac_check(struct mem_ctl_info *mci) struct synps_edac_priv *priv = mci->pvt_info; int status; - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); + status = priv->p_data->synps_edac_geterror_info(priv->baseaddr, + &priv->stat); if (status) return; @@ -372,10 +393,12 @@ static int synps_edac_init_csrows(struct mem_ctl_info *mci) for (j = 0; j < csi->nr_channels; j++) { dimm= csi->channels[j]->dimm; dimm->edac_mode = EDAC_FLAG_SECDED; - dimm->mtype = synps_edac_get_mtype(priv->baseaddr); + dimm->mtype = priv->p_data->synps_edac_get_mtype( + priv->baseaddr); dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; dimm->grain = SYNPS_EDAC_ERR_GRAIN; - dimm->dtype = synps_edac_get_dtype(priv->baseaddr); + dimm->dtype = priv->p_data->synps_edac_get_dtype( + priv->baseaddr); } } @@ -423,6 +446,21 @@ static int synps_edac_mc_init(struct mem_ctl_info *mci, return status; } +static const struct synps_platform_data zynq_edac_def = { + .synps_edac_geterror_info = synps_edac_geterror_info, + .synps_edac_get_mtype = synps_edac_get_mtype, + .synps_edac_get_dtype = synps_edac_get_dtype, + .synps_edac_get_eccstate= synps_edac_get_eccstate, + .quirks = 0, +}; + +static const struct of_device_id synps_edac_match[] = { + { .compatible = "xlnx,zynq-ddrc-a05", .data = (void *)&zynq_edac_def }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, synps_edac_match); + /** * synps_edac_mc_probe - Check controller and bind driver * @pdev: Pointer to the platform_device struct @@ -440,13 +478,22 @@ static int synps_edac_mc_probe(struct platform_device *pdev) int rc; struct resource *res; void __iomem *baseaddr; + const struct of_device_id *match; + const struct synps_platform_data *p_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); baseaddr = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(baseaddr)) return PTR_ERR(baseaddr); - if (!synps_edac_get_eccstate(baseaddr)) { + match = of_match_node(synps_edac_match, pdev->dev.of_node); + if (!match && !match->data) { +
[PATCH v2 3/4] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
This patch adds EDAC ECC support for ZynqMP DDRC IP. The patch also adds support for ECC Error Injection in ZynqMP. The corrected and uncorrected error interrupts support is added in this patch. The Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 857 ++- 2 files changed, 841 insertions(+), 18 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..b1fc7a16 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index d4798e8..8a1c327 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "edac_module.h" @@ -96,6 +97,170 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) + +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORT BIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST 0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON1_BANKGRP_SHIFT 28 +#define ECC_POISON1_BANKNR_SHIFT 24 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_DEV_CONFIG_MASK 0xC000 +#define DDRC_MSTR_DEV_CONFIG_SHIFT 30 +#define DDRC_MSTR_DEV_CONFIG_X4_MASK 0x0 +#define DDRC_MSTR_DEV_CONFIG_X8_MASK 0x1 +#define DDRC_MSTR_DEV_CONFIG_X16_MASK 0x2 +#define DDRC_MSTR_DEV_CONFIG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#define ROW_MAX_VAL_MASK 0xF +#define CO
[PATCH v3 1/4] edac: synps: Add platform specific structures for ddrc controller
This patch adds platform specific structures, so that we can add different IP support later using quirks. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 64 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0c9c59e..d4798e8 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "edac_module.h" @@ -130,6 +131,7 @@ struct synps_ecc_status { * @baseaddr: Base address of the DDR controller * @message: Buffer for framing the event specific info * @stat: ECC status information + * @p_data:Pointer to platform data * @ce_cnt:Correctable Error count * @ue_cnt:Uncorrectable Error count */ @@ -137,11 +139,29 @@ struct synps_edac_priv { void __iomem *baseaddr; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; + const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; }; /** + * struct synps_platform_data - synps platform data structure + * @synps_edac_geterror_info: function pointer to synps edac error info + * @synps_edac_get_mtype: function pointer to synps edac mtype + * @synps_edac_get_dtype: function pointer to synps edac dtype + * @synps_edac_get_eccstate: function pointer to synps edac eccstate + * @quirks:to differentiate IPs + */ +struct synps_platform_data { + int (*synps_edac_geterror_info)(void __iomem *base, + struct synps_ecc_status *p); + enum mem_type (*synps_edac_get_mtype)(const void __iomem *base); + enum dev_type (*synps_edac_get_dtype)(const void __iomem *base); + bool (*synps_edac_get_eccstate)(void __iomem *base); + int quirks; +}; + +/** * synps_edac_geterror_info - Get the current ecc error info * @base: Pointer to the base address of the ddr memory controller * @p: Pointer to the synopsys ecc status structure @@ -242,7 +262,8 @@ static void synps_edac_check(struct mem_ctl_info *mci) struct synps_edac_priv *priv = mci->pvt_info; int status; - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); + status = priv->p_data->synps_edac_geterror_info(priv->baseaddr, + &priv->stat); if (status) return; @@ -372,10 +393,12 @@ static int synps_edac_init_csrows(struct mem_ctl_info *mci) for (j = 0; j < csi->nr_channels; j++) { dimm= csi->channels[j]->dimm; dimm->edac_mode = EDAC_FLAG_SECDED; - dimm->mtype = synps_edac_get_mtype(priv->baseaddr); + dimm->mtype = priv->p_data->synps_edac_get_mtype( + priv->baseaddr); dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; dimm->grain = SYNPS_EDAC_ERR_GRAIN; - dimm->dtype = synps_edac_get_dtype(priv->baseaddr); + dimm->dtype = priv->p_data->synps_edac_get_dtype( + priv->baseaddr); } } @@ -423,6 +446,21 @@ static int synps_edac_mc_init(struct mem_ctl_info *mci, return status; } +static const struct synps_platform_data zynq_edac_def = { + .synps_edac_geterror_info = synps_edac_geterror_info, + .synps_edac_get_mtype = synps_edac_get_mtype, + .synps_edac_get_dtype = synps_edac_get_dtype, + .synps_edac_get_eccstate= synps_edac_get_eccstate, + .quirks = 0, +}; + +static const struct of_device_id synps_edac_match[] = { + { .compatible = "xlnx,zynq-ddrc-a05", .data = (void *)&zynq_edac_def }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, synps_edac_match); + /** * synps_edac_mc_probe - Check controller and bind driver * @pdev: Pointer to the platform_device struct @@ -440,13 +478,22 @@ static int synps_edac_mc_probe(struct platform_device *pdev) int rc; struct resource *res; void __iomem *baseaddr; + const struct of_device_id *match; + const struct synps_platform_data *p_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); baseaddr = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(baseaddr)) return PTR_ERR(baseaddr); - if (!synps_edac_get_eccstate(baseaddr)) { + match = of_match_node(synps_edac_match, pdev->dev.of_node); + if (!match && !match->data) { +
[PATCH v3 0/4] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms.This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Changes in v3: - The commit message in (2/4) is modified (Synopsys EDAC Driver --> ZynqMP DDRC) Manish Narani (4): edac: synps: Add platform specific structures for ddrc controller dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node .../bindings/memory-controllers/synopsys.txt | 27 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 919 - 4 files changed, 922 insertions(+), 33 deletions(-) -- 2.1.1
[PATCH v3 4/4] arm64: zynqmp: Add DDRC node
This patch adds ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at fd090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index a091e6f..7d6a3cf 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH v3 3/4] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
This patch adds EDAC ECC support for ZynqMP DDRC IP. The patch also adds support for ECC Error Injection in ZynqMP. The corrected and uncorrected error interrupts support is added in this patch. The Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 857 ++- 2 files changed, 841 insertions(+), 18 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..b1fc7a16 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index d4798e8..8a1c327 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "edac_module.h" @@ -96,6 +97,170 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) + +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORT BIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST 0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON1_BANKGRP_SHIFT 28 +#define ECC_POISON1_BANKNR_SHIFT 24 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_DEV_CONFIG_MASK 0xC000 +#define DDRC_MSTR_DEV_CONFIG_SHIFT 30 +#define DDRC_MSTR_DEV_CONFIG_X4_MASK 0x0 +#define DDRC_MSTR_DEV_CONFIG_X8_MASK 0x1 +#define DDRC_MSTR_DEV_CONFIG_X16_MASK 0x2 +#define DDRC_MSTR_DEV_CONFIG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#define ROW_MAX_VAL_MASK 0xF +#define CO
[PATCH v3 2/4] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
This patch adds information of ZynqMP DDRC which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v2 2/4] iio: adc: xilinx: limit pcap clock frequency value
This patch limits the xadc pcap clock frequency value to be less than 200MHz. This fixes the issue when zynq is booted at higher frequency values, pcap crosses the maximum limit of 200MHz(Fmax) as it is derived from IOPLL. If this limit is crossed it is required to alter the WEDGE and REDGE bits of XADC_CFG register to make timings better in the interface. So to avoid alteration of these bits every time, the pcap value should not cross the Fmax limit. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 15 +++ 1 file changed, 15 insertions(+) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 23395fc..0dd306d 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -322,6 +322,7 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) #define XADC_ZYNQ_TCK_RATE_MAX 5000 #define XADC_ZYNQ_IGAP_DEFAULT 20 +#define XADC_ZYNQ_PCAP_RATE_MAX 2 static int xadc_zynq_setup(struct platform_device *pdev, struct iio_dev *indio_dev, int irq) @@ -332,6 +333,7 @@ static int xadc_zynq_setup(struct platform_device *pdev, unsigned int div; unsigned int igap; unsigned int tck_rate; + int ret; /* TODO: Figure out how to make igap and tck_rate configurable */ igap = XADC_ZYNQ_IGAP_DEFAULT; @@ -343,6 +345,13 @@ static int xadc_zynq_setup(struct platform_device *pdev, if (!pcap_rate) return -EINVAL; + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, + (unsigned long)XADC_ZYNQ_PCAP_RATE_MAX); + if (ret) + return ret; + } + if (tck_rate > pcap_rate / 2) { div = 2; } else { @@ -368,6 +377,12 @@ static int xadc_zynq_setup(struct platform_device *pdev, XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | tck_div | XADC_ZYNQ_CFG_IGAP(igap)); + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, pcap_rate); + if (ret) + return ret; + } + return 0; } -- 2.1.1
[PATCH v2 1/4] iio: adc: xilinx: Check for return values in clk related functions
This patch adds check for return values from clock related functions. This was reported by static code analysis tool. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 0127e85..23395fc 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -340,6 +340,8 @@ static int xadc_zynq_setup(struct platform_device *pdev, xadc->zynq_intmask = ~0; pcap_rate = clk_get_rate(xadc->clk); + if (!pcap_rate) + return -EINVAL; if (tck_rate > pcap_rate / 2) { div = 2; @@ -887,6 +889,9 @@ static int xadc_write_raw(struct iio_dev *indio_dev, unsigned long clk_rate = xadc_get_dclk_rate(xadc); unsigned int div; + if (!clk_rate) + return -EINVAL; + if (info != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL; @@ -1237,8 +1242,10 @@ static int xadc_probe(struct platform_device *pdev) goto err_free_irq; /* Disable all alarms */ - xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, - XADC_CONF1_ALARM_MASK); + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, + XADC_CONF1_ALARM_MASK); + if (ret) + goto err_free_irq; /* Set thresholds to min/max */ for (i = 0; i < 16; i++) { -- 2.1.1
[PATCH v2 3/4] iio: adc: xilinx: Remove platform_get_irq from xadc_remove function
This patch avoids getting irq number in xadc_remove function. Instead store 'irq' in xadc struct and use xadc->irq wherever needed. This patch also resolves a warning reported by coverity where it asks to check return value of platform_get_irq() for any errors in xadc_remove. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 10 +- drivers/iio/adc/xilinx-xadc.h | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 0dd306d..44a2519 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1175,6 +1175,7 @@ static int xadc_probe(struct platform_device *pdev) xadc = iio_priv(indio_dev); xadc->ops = id->data; + xadc->irq = irq; init_completion(&xadc->completion); mutex_init(&xadc->mutex); spin_lock_init(&xadc->lock); @@ -1225,11 +1226,11 @@ static int xadc_probe(struct platform_device *pdev) if (ret) goto err_free_samplerate_trigger; - ret = xadc->ops->setup(pdev, indio_dev, irq); + ret = xadc->ops->setup(pdev, indio_dev, xadc->irq); if (ret) goto err_clk_disable_unprepare; - ret = request_irq(irq, xadc->ops->interrupt_handler, 0, + ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0, dev_name(&pdev->dev), indio_dev); if (ret) goto err_clk_disable_unprepare; @@ -1288,7 +1289,7 @@ static int xadc_probe(struct platform_device *pdev) return 0; err_free_irq: - free_irq(irq, indio_dev); + free_irq(xadc->irq, indio_dev); err_clk_disable_unprepare: clk_disable_unprepare(xadc->clk); err_free_samplerate_trigger: @@ -1310,7 +1311,6 @@ static int xadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct xadc *xadc = iio_priv(indio_dev); - int irq = platform_get_irq(pdev, 0); iio_device_unregister(indio_dev); if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { @@ -1318,7 +1318,7 @@ static int xadc_remove(struct platform_device *pdev) iio_trigger_free(xadc->convst_trigger); iio_triggered_buffer_cleanup(indio_dev); } - free_irq(irq, indio_dev); + free_irq(xadc->irq, indio_dev); clk_disable_unprepare(xadc->clk); cancel_delayed_work(&xadc->zynq_unmask_work); kfree(xadc->data); diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index 62edbda..8c00095 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -68,6 +68,7 @@ struct xadc { spinlock_t lock; struct completion completion; + int irq; }; struct xadc_ops { -- 2.1.1
[PATCH v2 0/4] iio: adc: xilinx: XADC driver Enhancements and bug fixes
This patch series resolves code style problems as reported by code analysis tools. Changes in v2: - From the first version of patches, 2 patches are dropped in this series. - In the v1 patch set, 1/4 was not required as the issue is in checkpatch.pl script and not in the code. - In the v1 patch set 2/4 was applied on togreg branch of iio.git - for 3/4 patch in v1 patch set, the patch is broken up in 2 patches in this series as per review comments. They are now 1/4 and 2/4 in this series. - 4/4 patch in the v1 patch set was basically to resolve coverity warning for platform_get_irq() in xadc_remove function, but that was causing potential race condition. Fixed that in this series (3/4). - A new patch is added in this series for moving request_irq() before enabling interrupts. Manish Narani (4): iio: adc: xilinx: Check for return values in clk related functions iio: adc: xilinx: limit pcap clock frequency value iio: adc: xilinx: Remove platform_get_irq from xadc_remove function iio: adc: xilinx: Move request_irq before enabling interrupts drivers/iio/adc/xilinx-xadc-core.c | 40 +- drivers/iio/adc/xilinx-xadc.h | 1 + 2 files changed, 32 insertions(+), 9 deletions(-) -- 2.1.1
[PATCH v2 4/4] iio: adc: xilinx: Move request_irq before enabling interrupts
Enabling the Interrupts before registering the irq handler is a bad idea. This patch corrects the same for XADC driver. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 44a2519..3f6be5a 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1226,15 +1226,15 @@ static int xadc_probe(struct platform_device *pdev) if (ret) goto err_free_samplerate_trigger; - ret = xadc->ops->setup(pdev, indio_dev, xadc->irq); - if (ret) - goto err_clk_disable_unprepare; - ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0, dev_name(&pdev->dev), indio_dev); if (ret) goto err_clk_disable_unprepare; + ret = xadc->ops->setup(pdev, indio_dev, xadc->irq); + if (ret) + goto err_free_irq; + for (i = 0; i < 16; i++) xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), &xadc->threshold[i]); -- 2.1.1
[RFC PATCH] mmc: sdhci-of-arasan: Add auto tuning support for ZynqMP Platform
This patch adds support of SD auto tuning for ZynqMP platform. Auto tuning sequence sends tuning block to card when operating in UHS-1 modes. This resets the DLL and sends CMD19/CMD21 as a part of the auto tuning process. Once the auto tuning process gets completed, reset the DLL to load the newly obtained SDHC tuned tap value. Signed-off-by: Manish Narani --- .../devicetree/bindings/mmc/arasan,sdhci.txt | 1 + drivers/mmc/host/sdhci-of-arasan.c | 219 - 2 files changed, 219 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt index 60481bf..7d29751 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -14,6 +14,7 @@ Required Properties: - "arasan,sdhci-4.9a": generic Arasan SDHCI 4.9a PHY - "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY - "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY +- "xlnx,zynqmp-8.9a": Xilinx ZynqMP 8.9a PHY For this device it is strongly suggested to include arasan,soc-ctl-syscon. - reg: From mmc bindings: Register location and length. - clocks: From clock bindings: Handles to clock inputs. diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 0720ea7..7673db4 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -24,15 +24,18 @@ #include #include #include +#include #include #include "sdhci-pltfm.h" #include +#include #define SDHCI_ARASAN_VENDOR_REGISTER 0x78 #define VENDOR_ENHANCED_STROBE BIT(0) #define PHY_CLK_TOO_SLOW_HZ40 +#define MAX_TUNING_LOOP40 /* * On some SoCs the syscon area has a feature where the upper 16-bits of @@ -88,6 +91,7 @@ struct sdhci_arasan_data { struct sdhci_host *host; struct clk *clk_ahb; struct phy *phy; + u32 device_id; boolis_phy_on; struct clk_hw sdcardclk_hw; @@ -157,6 +161,213 @@ static int sdhci_arasan_syscon_write(struct sdhci_host *host, return ret; } +/** + * arasan_zynqmp_dll_reset - Issue the DLL reset. + * @deviceid: Unique Id of device + */ +void zynqmp_dll_reset(u8 deviceid) +{ + const struct zynqmp_eemi_ops *eemi_ops = get_eemi_ops(); + + if (!eemi_ops || !eemi_ops->ioctl) + return; + + /* Issue DLL Reset */ + if (deviceid == 0) + eemi_ops->ioctl(NODE_SD_0, IOCTL_SD_DLL_RESET, + PM_DLL_RESET_PULSE, 0, NULL); + else + eemi_ops->ioctl(NODE_SD_1, IOCTL_SD_DLL_RESET, + PM_DLL_RESET_PULSE, 0, NULL); +} + +static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) +{ + u16 clk; + unsigned long timeout; + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + /* Issue DLL Reset */ + zynqmp_dll_reset(deviceid); + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + /* Wait max 20 ms */ + timeout = 20; + while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + dev_err(mmc_dev(host->mmc), + ": Internal clock never stabilised.\n"); + return; + } + timeout--; + mdelay(1); + } + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); +} + +static int arasan_zynqmp_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + struct mmc_host *mmc = host->mmc; + u16 ctrl; + int tuning_loop_counter = MAX_TUNING_LOOP; + int err = 0; + unsigned long flags; + unsigned int tuning_count = 0; + + spin_lock_irqsave(&host->lock, flags); + + if (host->tuning_mode == SDHCI_TUNING_MODE_1) + tuning_count = host->tuning_count; + + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl |= SDHCI_CTRL_EXEC_TUNING; + if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND) + ctrl |= SDHCI_CTRL_TUNED_CLK; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + + mdelay(1); + + arasan_zynqmp_dll_reset(host, sdhci_arasan->device_id); + + /* +* As
RE: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay values from DT
Ping > -Original Message- > From: Manish Narani > Sent: Thursday, June 21, 2018 6:25 PM > To: Adrian Hunter ; robh...@kernel.org; > catalin.mari...@arm.com; will.dea...@arm.com; m...@kernel.org; > stefan.krsmano...@aggios.com; linux-arm-ker...@lists.infradead.org; linux- > ker...@vger.kernel.org; linux-...@vger.kernel.org; > devicet...@vger.kernel.org; Michal Simek ; > ulf.hans...@linaro.org > Cc: Srinivas Goud ; Anirudha Sarangi > > Subject: RE: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay > values from DT > > Hi Adrian, > > > -Original Message- > > From: Adrian Hunter [mailto:adrian.hun...@intel.com] > > Sent: Tuesday, June 19, 2018 5:08 PM > > To: Manish Narani ; robh...@kernel.org; > > catalin.mari...@arm.com; will.dea...@arm.com; m...@kernel.org; > > stefan.krsmano...@aggios.com; linux-arm-ker...@lists.infradead.org; > > linux- ker...@vger.kernel.org; linux-...@vger.kernel.org; > > devicet...@vger.kernel.org; Michal Simek ; > > ulf.hans...@linaro.org > > Cc: Srinivas Goud ; Anirudha Sarangi > > > > Subject: Re: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap > > Delay values from DT > > > > On 14/06/18 08:38, Manish Narani wrote: > > > Ping for RFC > > > > What is eemi? Why aren't there patches for that? > Eemi(Extensible Energy Management Interface) is a power management > interface for ZynqMP core. The patches for the same are already in process of > mainlining. > https://lkml.org/lkml/2018/6/20/823 > > Thanks, > Manish > > > > > > > >> -Original Message- > > >> From: Manish Narani [mailto:manish.nar...@xilinx.com] > > >> Sent: Thursday, June 7, 2018 5:42 PM > > >> To: robh...@kernel.org; mark.rutl...@arm.com; > > >> catalin.mari...@arm.com; will.dea...@arm.com; m...@kernel.org; > > >> stefan.krsmano...@aggios.com; linux-arm-ker...@lists.infradead.org; > > >> linux-kernel@vger.kernel.org; linux- m...@vger.kernel.org; > > >> devicet...@vger.kernel.org; adrian.hun...@intel.com; > > >> michal.si...@xilinx.com; ulf.hans...@linaro.org > > >> Cc: Manish Narani > > >> Subject: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap > > >> Delay values from DT > > >> > > >> This patch adds support for reading Tap Delay values from Device > > >> Tree and write them via eemi calls. The macros containing these tap > > >> delay values are removed from the driver. > > >> > > >> Signed-off-by: Manish Narani > > >> --- > > >> drivers/mmc/host/sdhci-of-arasan.c | 131 > > >> + > > >> 1 file changed, 131 insertions(+) > > >> > > >> diff --git a/drivers/mmc/host/sdhci-of-arasan.c > > >> b/drivers/mmc/host/sdhci- of-arasan.c index e3332a5..fc0fd01 100644 > > >> --- a/drivers/mmc/host/sdhci-of-arasan.c > > >> +++ b/drivers/mmc/host/sdhci-of-arasan.c > > >> @@ -36,6 +36,8 @@ > > >> > > >> #define PHY_CLK_TOO_SLOW_HZ 40 > > >> > > >> +#define MMC_BANK2 0x2 > > >> + > > >> /* > > >> * On some SoCs the syscon area has a feature where the upper 16-bits of > > >> * each 32-bit register act as a write mask for the lower 16-bits. > > >> This allows @@ -90,6 +92,10 @@ struct sdhci_arasan_data { > > >> struct sdhci_host *host; > > >> struct clk *clk_ahb; > > >> struct phy *phy; > > >> +u32 mio_bank; > > >> +u32 device_id; > > >> +u32 itapdly[MMC_TIMING_MMC_HS400 + 1]; > > >> +u32 otapdly[MMC_TIMING_MMC_HS400 + 1]; > > >> boolis_phy_on; > > >> > > >> boolhas_cqe; > > >> @@ -160,11 +166,36 @@ static int sdhci_arasan_syscon_write(struct > > >> sdhci_host *host, > > >> return ret; > > >> } > > >> > > >> +/** > > >> + * arasan_zynqmp_set_tap_delay - Program the tap delays. > > >> + * @deviceid: Unique Id of device > > >> + * @itap_delay: Input Tap Delay > > >> + * @oitap_delay:Output Tap Delay > > >> + */ > > >> +static void arasan_zynqmp_set_tap_delay(u8 deviceid, u8 > > >> +itap_delay, > > >> +u8 > > >> +otap_delay) { > >
RE: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay values from DT
Ping for RFC > -Original Message- > From: Manish Narani [mailto:manish.nar...@xilinx.com] > Sent: Thursday, June 7, 2018 5:42 PM > To: robh...@kernel.org; mark.rutl...@arm.com; catalin.mari...@arm.com; > will.dea...@arm.com; m...@kernel.org; stefan.krsmano...@aggios.com; > linux-arm-ker...@lists.infradead.org; linux-kernel@vger.kernel.org; linux- > m...@vger.kernel.org; devicet...@vger.kernel.org; > adrian.hun...@intel.com; michal.si...@xilinx.com; ulf.hans...@linaro.org > Cc: Manish Narani > Subject: [RFC PATCH 3/3] sdhci: arasan: Add support to read Tap Delay values > from DT > > This patch adds support for reading Tap Delay values from Device Tree and > write them via eemi calls. The macros containing these tap delay values are > removed from the driver. > > Signed-off-by: Manish Narani > --- > drivers/mmc/host/sdhci-of-arasan.c | 131 > + > 1 file changed, 131 insertions(+) > > diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci- > of-arasan.c > index e3332a5..fc0fd01 100644 > --- a/drivers/mmc/host/sdhci-of-arasan.c > +++ b/drivers/mmc/host/sdhci-of-arasan.c > @@ -36,6 +36,8 @@ > > #define PHY_CLK_TOO_SLOW_HZ 40 > > +#define MMC_BANK20x2 > + > /* > * On some SoCs the syscon area has a feature where the upper 16-bits of > * each 32-bit register act as a write mask for the lower 16-bits. This > allows > @@ -90,6 +92,10 @@ struct sdhci_arasan_data { > struct sdhci_host *host; > struct clk *clk_ahb; > struct phy *phy; > + u32 mio_bank; > + u32 device_id; > + u32 itapdly[MMC_TIMING_MMC_HS400 + 1]; > + u32 otapdly[MMC_TIMING_MMC_HS400 + 1]; > boolis_phy_on; > > boolhas_cqe; > @@ -160,11 +166,36 @@ static int sdhci_arasan_syscon_write(struct > sdhci_host *host, > return ret; > } > > +/** > + * arasan_zynqmp_set_tap_delay - Program the tap delays. > + * @deviceid:Unique Id of device > + * @itap_delay: Input Tap Delay > + * @oitap_delay: Output Tap Delay > + */ > +static void arasan_zynqmp_set_tap_delay(u8 deviceid, u8 itap_delay, u8 > +otap_delay) { > + const struct zynqmp_eemi_ops *eemi_ops = > zynqmp_pm_get_eemi_ops(); > + u32 node_id = (deviceid == 0) ? NODE_SD_0 : NODE_SD_1; > + > + if (!eemi_ops || !eemi_ops->ioctl) > + return; > + > + if (itap_delay) > + eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, > + PM_TAPDELAY_INPUT, itap_delay, NULL); > + > + if (otap_delay) > + eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, > + PM_TAPDELAY_OUTPUT, otap_delay, NULL); > } > + > static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int > clock) { > struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > struct sdhci_arasan_data *sdhci_arasan = > sdhci_pltfm_priv(pltfm_host); > bool ctrl_phy = false; > + u8 itap_delay; > + u8 otap_delay; > > if (!IS_ERR(sdhci_arasan->phy)) { > if (!sdhci_arasan->is_phy_on && clock <= > PHY_CLK_TOO_SLOW_HZ) { @@ -200,6 +231,16 @@ static void > sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) > } > } > > + if (host->version >= SDHCI_SPEC_300) { > + if ((host->timing != MMC_TIMING_LEGACY) && > + (host->timing != MMC_TIMING_UHS_SDR12)) { > + itap_delay = sdhci_arasan->itapdly[host->timing]; > + otap_delay = sdhci_arasan->otapdly[host->timing]; > + arasan_zynqmp_set_tap_delay(sdhci_arasan- > >device_id, > + itap_delay, otap_delay); > + } > + } > + > if (ctrl_phy && sdhci_arasan->is_phy_on) { > phy_power_off(sdhci_arasan->phy); > sdhci_arasan->is_phy_on = false; > @@ -456,6 +497,7 @@ static const struct of_device_id > sdhci_arasan_of_match[] = { > { .compatible = "arasan,sdhci-8.9a" }, > { .compatible = "arasan,sdhci-5.1" }, > { .compatible = "arasan,sdhci-4.9a" }, > + { .compatible = "xlnx,zynqmp-8.9a" }, > > { /* sentinel */ } > }; > @@ -641,6 +683,74 @@ static void sdhci_arasan_unregister_sdclk(struct > device *dev) > of_clk_del_provider(dev->of_node); > } > > +/** > + * arasan_zynqmp_dt_parse_tap_delays - Read Tap Delay val
RE: [PATCH v4 1/4] edac: synps: Add platform specific structures for ddrc controller
Ping. > -Original Message- > From: Manish Narani [mailto:manish.nar...@xilinx.com] > Sent: Saturday, August 4, 2018 2:56 PM > To: robh...@kernel.org; mark.rutl...@arm.com; catalin.mari...@arm.com; > will.dea...@arm.com; Michal Simek ; b...@alien8.de; > mche...@kernel.org; m...@kernel.org; Edgar Iglesias ; > Shubhrajyoti Datta ; Naga Sureshkumar Relli > ; Bharat Kumar Gogada ; > stefan.krsmano...@aggios.com > Cc: Srinivas Goud ; Anirudha Sarangi > ; linux-kernel@vger.kernel.org; > devicet...@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux- > e...@vger.kernel.org; Manish Narani > Subject: [PATCH v4 1/4] edac: synps: Add platform specific structures for ddrc > controller > > Add platform specific structures, so that we can add different IP support > later > using quirks. > > Signed-off-by: Manish Narani > --- > drivers/edac/synopsys_edac.c | 83 ++-- > > 1 file changed, 65 insertions(+), 18 deletions(-) > > diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index > 0c9c59e..b3c54e7 100644 > --- a/drivers/edac/synopsys_edac.c > +++ b/drivers/edac/synopsys_edac.c > @@ -22,6 +22,7 @@ > #include > #include > #include > +#include > > #include "edac_module.h" > > @@ -130,6 +131,7 @@ struct synps_ecc_status { > * @baseaddr:Base address of the DDR controller > * @message: Buffer for framing the event specific info > * @stat:ECC status information > + * @p_data: Pointer to platform data > * @ce_cnt: Correctable Error count > * @ue_cnt: Uncorrectable Error count > */ > @@ -137,24 +139,47 @@ struct synps_edac_priv { > void __iomem *baseaddr; > char message[SYNPS_EDAC_MSG_SIZE]; > struct synps_ecc_status stat; > + const struct synps_platform_data *p_data; > u32 ce_cnt; > u32 ue_cnt; > }; > > /** > + * struct synps_platform_data - synps platform data structure > + * @edac_geterror_info: function pointer to synps edac error info > + * @edac_get_mtype: function pointer to synps edac mtype > + * @edac_get_dtype: function pointer to synps edac dtype > + * @edac_get_eccstate: function pointer to synps edac eccstate > + * @quirks: to differentiate IPs > + */ > +struct synps_platform_data { > + int (*edac_geterror_info)(struct synps_edac_priv *priv); > + enum mem_type (*edac_get_mtype)(const void __iomem *base); > + enum dev_type (*edac_get_dtype)(const void __iomem *base); > + bool (*edac_get_eccstate)(void __iomem *base); > + int quirks; > +}; > + > +/** > * synps_edac_geterror_info - Get the current ecc error info > - * @base:Pointer to the base address of the ddr memory controller > - * @p: Pointer to the synopsys ecc status structure > + * @priv:Pointer to DDR memory controller private instance data > * > * Determines there is any ecc error or not > * > * Return: one if there is no error otherwise returns zero > */ > -static int synps_edac_geterror_info(void __iomem *base, > - struct synps_ecc_status *p) > +static int synps_edac_geterror_info(struct synps_edac_priv *priv) > { > + void __iomem *base; > + struct synps_ecc_status *p; > u32 regval, clearval = 0; > > + if (!priv) > + return 1; > + > + base = priv->baseaddr; > + p = &priv->stat; > + > regval = readl(base + STAT_OFST); > if (!regval) > return 1; > @@ -240,9 +265,10 @@ static void synps_edac_handle_error(struct > mem_ctl_info *mci, static void synps_edac_check(struct mem_ctl_info *mci) { > struct synps_edac_priv *priv = mci->pvt_info; > + const struct synps_platform_data *p_data = priv->p_data; > int status; > > - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); > + status = p_data->edac_geterror_info(priv); > if (status) > return; > > @@ -362,6 +388,7 @@ static int synps_edac_init_csrows(struct mem_ctl_info > *mci) > struct csrow_info *csi; > struct dimm_info *dimm; > struct synps_edac_priv *priv = mci->pvt_info; > + const struct synps_platform_data *p_data = priv->p_data; > u32 size; > int row, j; > > @@ -370,12 +397,13 @@ static int synps_edac_init_csrows(struct > mem_ctl_info *mci) > size = synps_edac_get_memsize(); > > for (j = 0; j < csi->nr_channels; j++) { > - dimm= csi->channels[j]->dimm; > + dimm = csi->chan
RE: [PATCH v4 4/4] arm64: zynqmp: Add DDRC node
Ping. > -Original Message- > From: Manish Narani [mailto:manish.nar...@xilinx.com] > Sent: Saturday, August 4, 2018 2:56 PM > To: robh...@kernel.org; mark.rutl...@arm.com; catalin.mari...@arm.com; > will.dea...@arm.com; Michal Simek ; b...@alien8.de; > mche...@kernel.org; m...@kernel.org; Edgar Iglesias ; > Shubhrajyoti Datta ; Naga Sureshkumar Relli > ; Bharat Kumar Gogada ; > stefan.krsmano...@aggios.com > Cc: Srinivas Goud ; Anirudha Sarangi > ; linux-kernel@vger.kernel.org; > devicet...@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux- > e...@vger.kernel.org; Manish Narani > Subject: [PATCH v4 4/4] arm64: zynqmp: Add DDRC node > > This patch adds ddrc memory controller node in dts. The size mentioned in dts > is 0x3, because we need to access DDR_QOS INTR registers located at > fd090208 from this driver. > > Signed-off-by: Manish Narani > --- > arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ > 1 file changed, 7 insertions(+) > > diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi > b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi > index a091e6f..7d6a3cf 100644 > --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi > +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi > @@ -355,6 +355,13 @@ > xlnx,bus-width = <64>; > }; > > + mc: memory-controller@fd07 { > + compatible = "xlnx,zynqmp-ddrc-2.40a"; > + reg = <0x0 0xfd07 0x0 0x3>; > + interrupt-parent = <&gic>; > + interrupts = <0 112 4>; > + }; > + > gem0: ethernet@ff0b { > compatible = "cdns,zynqmp-gem", "cdns,gem"; > status = "disabled"; > -- > 2.1.1
RE: [PATCH v10 0/6] EDAC: Enhancements to Synopsys EDAC driver
Hi Boris, > -Original Message- > From: Borislav Petkov [mailto:b...@alien8.de] > Sent: Tuesday, November 6, 2018 3:34 PM > To: Manish Narani > Cc: robh...@kernel.org; mark.rutl...@arm.com; Michal Simek > ; mche...@kernel.org; amit.kuche...@linaro.org; > sudeep.ho...@arm.com; leoyang...@nxp.com; devicet...@vger.kernel.org; > linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux- > e...@vger.kernel.org > Subject: Re: [PATCH v10 0/6] EDAC: Enhancements to Synopsys EDAC driver > > On Thu, Oct 25, 2018 at 11:36:55AM +0530, Manish Narani wrote: > > Change in v10: > > - Moved the checking for ce_cnt and ue_cnt before the readl() call > > - Aligned arguments on the opening brace in setup_irq() > > > > Manish Narani (6): > > edac: synopsys: Add error handling for NULL in probe() > > dt: bindings: Document ZynqMP DDRC in Synopsys documentation > > edac: synopsys: Add macro defines for ZynqMP DDRC > > edac: synopsys: Add EDAC ECC support for ZynqMP DDRC > > arm64: zynqmp: Add DDRC node > > edac: synopsys: Add Error Injection support for ZynqMP DDRC > > > > .../bindings/memory-controllers/synopsys.txt | 27 +- > > arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + > > drivers/edac/Kconfig | 2 +- > > drivers/edac/synopsys_edac.c | 911 > > - > > 4 files changed, 918 insertions(+), 29 deletions(-) > > Ok, patches pushed here: > > (minus https://lkml.kernel.org/r/1540447621-22870-6-git-send-email- > manish.nar...@xilinx.com) > > https://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git/log/?h=edac-for-4.21- > synps > Thanks a lot for your support. > Please run this on the hw before I queue it for linux-next. I have tested this and verified as working fine on hardware. You can go ahead and queue it for linux-next. Thanks, Manish
[PATCH v9 3/6] edac: synopsys: Add macro defines for ZynqMP DDRC
Add macro defines for ZynqMP DDR controller. These macros will be used for ZynqMP ECC operations. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 168 +++ 1 file changed, 168 insertions(+) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0005ef3..d1999e0 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -97,6 +97,174 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORTBIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON0_RANK_MASK BIT(24) +#define ECC_POISON0_COLUMN_SHIFT 0 +#define ECC_POISON0_COLUMN_MASK0xFFF +#define ECC_POISON1_BG_SHIFT 28 +#define ECC_POISON1_BG_MASK0x3000 +#define ECC_POISON1_BANKNR_SHIFT 24 +#define ECC_POISON1_BANKNR_MASK0x700 +#define ECC_POISON1_ROW_SHIFT 0 +#define ECC_POISON1_ROW_MASK 0x3 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_CFG_MASK 0xC000 +#define DDRC_MSTR_CFG_SHIFT30 +#define DDRC_MSTR_CFG_X4_MASK 0x0 +#define DDRC_MSTR_CFG_X8_MASK 0x1 +#define DDRC_MSTR_CFG_X16_MASK 0x2 +#define DDRC_MSTR_CFG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#de
[PATCH v9 0/6] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms. This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Changes in v3: - The commit message in (2/4) is modified (Synopsys EDAC Driver --> ZynqMP DDRC) Changes in v4: - Updated the commit message in (1/4) - Renamed function pointer names removing 'synps_' in (1/4) - Shortened unnecessary long lines as per the review comment on (1/4) Changes in v5: - Updated the commit message in (2/4) and (4/4). - Removed the unnecessary check for match data in probe() in (1/4) - Some Indentation changes for better readability in (1/4) and (3/4) - Removed repeated code in (3/4) - Used 'zynq' and 'zynqmp' instead of 'synps_enh_edac' in function names Changes in v6: - Splitted the patches according to functionalities - Addressed code style comments from v5 review - Moved the Error Injection to CONFIG_EDAC_DEBUG mode Changes in v7: - Included DTS patch (6/7) which was missed in v6 patch set Changes in v8: - patch (1/7) from v7 is split in to 3 different logically different patches 1. functional changes like code cleanup 2. functions renaming 3. comments cleanup - Added a separate patch (4) for making always successful functions as void - Corrected 'Too many parentheses' review comment in patch (5) - Corrected comments as per the v7 review feedback - Made dedicated functions for IRQ setup, IRQ enable and IRQ disable in patch (8) - Addressed review comments in patch (10) Changes in v9: - Added check for return value of of_device_get_match_data() function in (1/6). - From v8 the first 5 patches are removed in this series as they are applied on: https://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git/?h=edac-for-4.20-synps - Updated Kconfig to check for ARCH_ZYNQMP instead of ARM64 Manish Narani (6): edac: synopsys: Add error handling for NULL in probe() dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add macro defines for ZynqMP DDRC edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node edac: synopsys: Add Error Injection support for ZynqMP DDRC .../bindings/memory-controllers/synopsys.txt | 27 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 913 - 4 files changed, 920 insertions(+), 29 deletions(-) -- 2.1.1
[PATCH v9 4/6] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
Add EDAC ECC support for ZynqMP DDRC IP. The IP supports interrupts for corrected and uncorrected errors. Add interrupt handlers for the same. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 324 --- 2 files changed, 308 insertions(+), 18 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..7c40eb2 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARCH_ZYNQMP help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index d1999e0..603c4bd 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,8 @@ * @bank: Bank number. * @bitpos:Bit position. * @data: Data causing the error. + * @bankgrpnr: Bank group number. + * @blknr: Block number. */ struct ecc_error_info { u32 row; @@ -279,6 +282,8 @@ struct ecc_error_info { u32 bank; u32 bitpos; u32 data; + u32 bankgrpnr; + u32 blknr; }; /** @@ -385,6 +390,66 @@ static int zynq_get_error_info(struct synps_edac_priv *priv) } /** + * zynqmp_get_error_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. + * + * Return: one if there is no error otherwise returns zero. + */ +static int zynqmp_get_error_info(struct synps_edac_priv *priv) +{ + struct synps_ecc_status *p; + u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; + + regval = readl(base + ECC_STAT_OFST); + if (!regval) + return 1; + + p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT; + p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT; + p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK); + + regval = readl(base + ECC_CEADDR0_OFST); + if (!p->ce_cnt) + goto ue_err; + + p->ceinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_CEADDR1_OFST); + p->ceinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ceinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ceinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ceinfo.data = readl(base + ECC_CSYND0_OFST); + edac_dbg(2, "ECCCSYN0: 0x%08X ECCCSYN1: 0x%08X ECCCSYN2: 0x%08X\n", +readl(base + ECC_CSYND0_OFST), readl(base + ECC_CSYND1_OFST), +readl(base + ECC_CSYND2_OFST)); +ue_err: + regval = readl(base + ECC_UEADDR0_OFST); + if (!p->ue_cnt) + goto out; + + p->ueinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_UEADDR1_OFST); + p->ueinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ueinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ueinfo.data = readl(base + ECC_UESYND0_OFST); +out: + clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; + clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + writel(clearval, base + ECC_CLR_OFST); + writel(0x0, base + ECC_CLR_OFST); + + return 0; +} + +/** * handle_error - Handle Correctable and Uncorrectable errors. * @mci: EDAC memory controller instance. * @p: Synopsys ECC status structure. @@ -398,9 +463,25 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) if (p->ce_cnt) { pinf = &p->ceinfo; - snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, -"DDR ECC error type :%s Row %d Bank %d Col %d ", -"CE", pinf->row, pinf->bank, pinf->col); + if (!priv->p_data->quirks) { + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, +"DDR ECC error type:%s Row %d Bank %d Col %d ", + "CE", pinf->row, pinf->bank, pinf->col); + snprintf(priv->message, SYN
[PATCH v9 5/6] arm64: zynqmp: Add DDRC node
Add ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at 0xFD090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 29ce234..a81d3b16 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH v9 6/6] edac: synopsys: Add Error Injection support for ZynqMP DDRC
Add support for Error Injection for ZynqMP DDRC IP. For injecting errors, the Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 420 ++- 1 file changed, 413 insertions(+), 7 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 603c4bd..1f86d5e 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -302,12 +302,18 @@ struct synps_ecc_status { /** * struct synps_edac_priv - DDR memory controller private instance data. - * @baseaddr: Base address of the DDR controller. - * @message: Buffer for framing the event specific info. - * @stat: ECC status information. - * @p_data:Platform data. - * @ce_cnt:Correctable Error count. - * @ue_cnt:Uncorrectable Error count. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @p_data:Platform data. + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. + * @poison_addr: Data poison address. + * @row_shift: Bit shifts for row bit. + * @col_shift: Bit shifts for column bit. + * @bank_shift:Bit shifts for bank bit. + * @bankgrp_shift: Bit shifts for bank group bit. + * @rank_shift:Bit shifts for rank bit. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -316,6 +322,14 @@ struct synps_edac_priv { const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; +#ifdef CONFIG_EDAC_DEBUG + ulong poison_addr; + u32 row_shift[18]; + u32 col_shift[14]; + u32 bank_shift[3]; + u32 bankgrp_shift[2]; + u32 rank_shift[1]; +#endif }; /** @@ -877,7 +891,11 @@ static const struct synps_platform_data zynqmp_edac_def = { .get_mtype = zynqmp_get_mtype, .get_dtype = zynqmp_get_dtype, .get_ecc_state = zynqmp_get_ecc_state, - .quirks = DDR_ECC_INTR_SUPPORT, + .quirks = (DDR_ECC_INTR_SUPPORT +#ifdef CONFIG_EDAC_DEBUG + | DDR_ECC_DATA_POISON_SUPPORT +#endif + ), }; static const struct of_device_id synps_edac_match[] = { @@ -896,6 +914,375 @@ static const struct of_device_id synps_edac_match[] = { MODULE_DEVICE_TABLE(of, synps_edac_match); +#ifdef CONFIG_EDAC_DEBUG +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +/** + * ddr_poison_setup - Update poison registers. + * @priv: DDR memory controller private instance data. + * + * Update poison registers as per DDR mapping. + * Return: none. + */ +static void ddr_poison_setup(struct synps_edac_priv *priv) +{ + int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval; + int index; + ulong hif_addr = 0; + + hif_addr = priv->poison_addr >> 3; + + for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) { + if (priv->row_shift[index]) + row |= (((hif_addr >> priv->row_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_COL_SHIFT; index++) { + if (priv->col_shift[index] || index < 3) + col |= (((hif_addr >> priv->col_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANK_SHIFT; index++) { + if (priv->bank_shift[index]) + bank |= (((hif_addr >> priv->bank_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANKGRP_SHIFT; index++) { + if (priv->bankgrp_shift[index]) + bankgrp |= (((hif_addr >> priv->bankgrp_shift[index]) + & BIT(0)) << index); + else + break; + } + + if (priv->rank_shift[0]) + rank = (hif_addr >> priv->rank_shift[0]) & BIT(0); + + regval = (rank << ECC_POISON0_RANK_SHIFT) & ECC_POISON0_RANK_MASK; + regval |= (col << ECC_POISON0_COLUMN_SHIFT) & ECC_POISON0_COLUMN_MASK; + writel(regval, priv->baseaddr + ECC_POISON0_OFST); + + regval = (bankgrp << ECC_POISON1_BG_SHIFT) & ECC_POISON1_BG_MASK; + regval |= (bank << ECC_POISON1_BANKNR_SHIFT) & ECC_PO
[PATCH v9 1/6] edac: synopsys: Add error handling for NULL in probe()
The function of_device_get_match_data() can return NULL in case of error. Add error handling for the same in probe(). Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 1c3795d..0005ef3 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -477,6 +477,9 @@ static int mc_probe(struct platform_device *pdev) return PTR_ERR(baseaddr); p_data = of_device_get_match_data(&pdev->dev); + if (!p_data) + return -ENODEV; + if (!p_data->get_ecc_state(baseaddr)) { edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); return -ENXIO; -- 2.1.1
[PATCH v9 2/6] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
Add information of ZynqMP DDRC which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani Reviewed-by: Rob Herring --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v8 01/10] edac: synopsys: Update the driver code for better readability
Modify the driver with some changes for code clean up. Update the debug messages for EDAC errors reported. Increase the indentation of the macros for better readability. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 104 +-- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0c9c59e..1936c73 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -26,74 +26,74 @@ #include "edac_module.h" /* Number of cs_rows needed per memory controller */ -#define SYNPS_EDAC_NR_CSROWS 1 +#define SYNPS_EDAC_NR_CSROWS 1 /* Number of channels per memory controller */ -#define SYNPS_EDAC_NR_CHANS1 +#define SYNPS_EDAC_NR_CHANS1 /* Granularity of reported error in bytes */ -#define SYNPS_EDAC_ERR_GRAIN 1 +#define SYNPS_EDAC_ERR_GRAIN 1 -#define SYNPS_EDAC_MSG_SIZE256 +#define SYNPS_EDAC_MSG_SIZE256 -#define SYNPS_EDAC_MOD_STRING "synps_edac" -#define SYNPS_EDAC_MOD_VER "1" +#define SYNPS_EDAC_MOD_STRING "synps_edac" +#define SYNPS_EDAC_MOD_VER "1" /* Synopsys DDR memory controller registers that are relevant to ECC */ -#define CTRL_OFST 0x0 -#define T_ZQ_OFST 0xA4 +#define CTRL_OFST 0x0 +#define T_ZQ_OFST 0xA4 /* ECC control register */ -#define ECC_CTRL_OFST 0xC4 +#define ECC_CTRL_OFST 0xC4 /* ECC log register */ -#define CE_LOG_OFST0xC8 +#define CE_LOG_OFST0xC8 /* ECC address register */ -#define CE_ADDR_OFST 0xCC +#define CE_ADDR_OFST 0xCC /* ECC data[31:0] register */ -#define CE_DATA_31_0_OFST 0xD0 +#define CE_DATA_31_0_OFST 0xD0 /* Uncorrectable error info registers */ -#define UE_LOG_OFST0xDC -#define UE_ADDR_OFST 0xE0 -#define UE_DATA_31_0_OFST 0xE4 +#define UE_LOG_OFST0xDC +#define UE_ADDR_OFST 0xE0 +#define UE_DATA_31_0_OFST 0xE4 -#define STAT_OFST 0xF0 -#define SCRUB_OFST 0xF4 +#define STAT_OFST 0xF0 +#define SCRUB_OFST 0xF4 /* Control register bit field definitions */ -#define CTRL_BW_MASK 0xC -#define CTRL_BW_SHIFT 2 +#define CTRL_BW_MASK 0xC +#define CTRL_BW_SHIFT 2 -#define DDRCTL_WDTH_16 1 -#define DDRCTL_WDTH_32 0 +#define DDRCTL_WDTH_16 1 +#define DDRCTL_WDTH_32 0 /* ZQ register bit field definitions */ -#define T_ZQ_DDRMODE_MASK 0x2 +#define T_ZQ_DDRMODE_MASK 0x2 /* ECC control register bit field definitions */ -#define ECC_CTRL_CLR_CE_ERR0x2 -#define ECC_CTRL_CLR_UE_ERR0x1 +#define ECC_CTRL_CLR_CE_ERR0x2 +#define ECC_CTRL_CLR_UE_ERR0x1 /* ECC correctable/uncorrectable error log register definitions */ -#define LOG_VALID 0x1 -#define CE_LOG_BITPOS_MASK 0xFE -#define CE_LOG_BITPOS_SHIFT1 +#define LOG_VALID 0x1 +#define CE_LOG_BITPOS_MASK 0xFE +#define CE_LOG_BITPOS_SHIFT1 /* ECC correctable/uncorrectable error address register definitions */ -#define ADDR_COL_MASK 0xFFF -#define ADDR_ROW_MASK 0x000 -#define ADDR_ROW_SHIFT 12 -#define ADDR_BANK_MASK 0x7000 -#define ADDR_BANK_SHIFT28 +#define ADDR_COL_MASK 0xFFF +#define ADDR_ROW_MASK 0x000 +#define ADDR_ROW_SHIFT 12 +#define ADDR_BANK_MASK 0x7000 +#define ADDR_BANK_SHIFT28 /* ECC statistic register definitions */ -#define STAT_UECNT_MASK0xFF -#define STAT_CECNT_MASK0xFF00 -#define STAT_CECNT_SHIFT 8 +#define STAT_UECNT_MASK0xFF +#define STAT_CECNT_MASK0xFF00 +#define STAT_CECNT_SHIFT 8 /* ECC scrub register definitions */ -#define SCRUB_MODE_MASK0x7 -#define SCRUB_MODE_SECDED 0x4 +#define SCRUB_MODE_MASK0x7 +#define SCRUB_MODE_SECDED 0x4 /** * struct ecc_error_info - ECC error log information @@ -172,7 +172,7 @@ static int synps_edac_geterror_info(void __iomem *base, p->ceinfo.col = regval & ADDR_COL_MASK; p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; p->ceinfo.data = readl(base + CE_DATA_31_0_OFST); - edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos, + edac_dbg(3, "CE bit position: %d data: %d\n", p->ceinfo.bitpos, p->ceinfo.data); clear
[PATCH v8 04/10] edac: synopsys: Make return type void for functions always returning 0
The current driver has functions which are always returning 0. Those functions can be modified to void. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 22 -- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 7db5928..675155f 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -352,10 +352,8 @@ static enum mem_type edac_get_mtype(const void __iomem *base) * * Initializes the chip select rows associated with the EDAC memory * controller instance. - * - * Return: Unconditionally 0. */ -static int edac_init_csrows(struct mem_ctl_info *mci) +static void edac_init_csrows(struct mem_ctl_info *mci) { struct synps_edac_priv *priv = mci->pvt_info; struct csrow_info *csi; @@ -376,8 +374,6 @@ static int edac_init_csrows(struct mem_ctl_info *mci) dimm->dtype = edac_get_dtype(priv->baseaddr); } } - - return 0; } /** @@ -388,13 +384,10 @@ static int edac_init_csrows(struct mem_ctl_info *mci) * Performs initialization of the EDAC memory controller instance and * related driver-private data associated with the memory controller the * instance is bound to. - * - * Return: Always zero. */ -static int edac_mc_init(struct mem_ctl_info *mci, +static void edac_mc_init(struct mem_ctl_info *mci, struct platform_device *pdev) { - int status; struct synps_edac_priv *priv; mci->pdev = &pdev->dev; @@ -416,9 +409,7 @@ static int edac_mc_init(struct mem_ctl_info *mci, mci->edac_check = edac_check; mci->ctl_page_to_phys = NULL; - status = edac_init_csrows(mci); - - return status; + edac_init_csrows(mci); } /** @@ -466,12 +457,7 @@ static int synps_edac_mc_probe(struct platform_device *pdev) priv = mci->pvt_info; priv->baseaddr = baseaddr; - rc = edac_mc_init(mci, pdev); - if (rc) { - edac_printk(KERN_ERR, EDAC_MC, - "Failed to initialize instance\n"); - goto free_edac_mc; - } + edac_mc_init(mci, pdev); rc = edac_mc_add_mc(mci); if (rc) { -- 2.1.1
[PATCH v8 05/10] edac: synps: Add platform specific structures for ddrc controller
Add platform specific structures, so that we can add different IP support later using quirks. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 91 +++- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 675155f..f0f4704 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "edac_module.h" @@ -130,6 +132,7 @@ struct synps_ecc_status { * @baseaddr: Base address of the DDR controller. * @message: Buffer for framing the event specific info. * @stat: ECC status information. + * @p_data:Platform data. * @ce_cnt:Correctable Error count. * @ue_cnt:Uncorrectable Error count. */ @@ -137,21 +140,41 @@ struct synps_edac_priv { void __iomem *baseaddr; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; + const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; }; /** - * edac_geterror_info - Get the current ECC error info. - * @base: Base address of the DDR memory controller. - * @p: Synopsys ECC status structure. + * struct synps_platform_data - synps platform data structure. + * @geterror_info: EDAC error info. + * @get_mtype: Get mtype. + * @get_dtype: Get dtype. + * @get_eccstate: Get ECC state. + * @quirks:To differentiate IPs. + */ +struct synps_platform_data { + int (*geterror_info)(struct synps_edac_priv *priv); + enum mem_type (*get_mtype)(const void __iomem *base); + enum dev_type (*get_dtype)(const void __iomem *base); + bool (*get_eccstate)(void __iomem *base); + int quirks; +}; + +/** + * zynq_geterror_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. * * Return: one if there is no error otherwise returns zero. */ -static int edac_geterror_info(void __iomem *base, - struct synps_ecc_status *p) +static int zynq_geterror_info(struct synps_edac_priv *priv) { + struct synps_ecc_status *p; u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; regval = readl(base + STAT_OFST); if (!regval) @@ -230,17 +253,18 @@ static void edac_handle_error(struct mem_ctl_info *mci, } /** - * edac_check - Check controller for ECC errors. + * edac_error_check - Check controller for ECC errors. * @mci: EDAC memory controller instance. * * Used to check and post ECC errors. Called by the polling thread. */ -static void edac_check(struct mem_ctl_info *mci) +static void edac_error_check(struct mem_ctl_info *mci) { struct synps_edac_priv *priv = mci->pvt_info; + const struct synps_platform_data *p_data = priv->p_data; int status; - status = edac_geterror_info(priv->baseaddr, &priv->stat); + status = p_data->geterror_info(priv); if (status) return; @@ -253,7 +277,7 @@ static void edac_check(struct mem_ctl_info *mci) } /** - * edac_get_dtype - Return the controller memory width. + * zynq_get_dtype - Return the controller memory width. * @base: DDR memory controller base address. * * Get the EDAC device type width appropriate for the current controller @@ -261,7 +285,7 @@ static void edac_check(struct mem_ctl_info *mci) * * Return: a device type width enumeration. */ -static enum dev_type edac_get_dtype(const void __iomem *base) +static enum dev_type zynq_get_dtype(const void __iomem *base) { enum dev_type dt; u32 width; @@ -284,20 +308,20 @@ static enum dev_type edac_get_dtype(const void __iomem *base) } /** - * edac_get_eccstate - Return the controller ECC enable/disable status. + * zynq_get_eccstate - Return the controller ECC enable/disable status. * @base: DDR memory controller base address. * * Get the ECC enable/disable status for the controller. * * Return: a ECC status boolean i.e true/false - enabled/disabled. */ -static bool edac_get_eccstate(void __iomem *base) +static bool zynq_get_eccstate(void __iomem *base) { bool state = false; enum dev_type dt; u32 ecctype; - dt = edac_get_dtype(base); + dt = zynq_get_dtype(base); if (dt == DEV_UNKNOWN) return state; @@ -323,7 +347,7 @@ static u32 edac_get_memsize(void) } /** - * edac_get_mtype - Returns controller memory type. + * zynq_get_mtype - Returns controller memory type. * @base: Synopsys ECC status structure. * * Get the EDAC memory type appropriate for the current controller @@ -331,7 +355,7 @@ static u32 edac_get_memsize(void) * * Return: a memory type enumeration. */ -static enum mem_type edac_get_mtype
[PATCH v8 09/10] arm64: zynqmp: Add DDRC node
Add ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at 0xFD090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 29ce234..a81d3b16 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH v8 02/10] edac: synopsys: Rename the static functions to a shorter name
Rename the static functions to a shorter name. Since this is Synopsys EDAC driver, better to remove unnecessary 'synps_' prefix in function names. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 56 ++-- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 1936c73..abb5de8 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -142,7 +142,7 @@ struct synps_edac_priv { }; /** - * synps_edac_geterror_info - Get the current ecc error info + * edac_geterror_info - Get the current ecc error info * @base: Pointer to the base address of the ddr memory controller * @p: Pointer to the synopsys ecc status structure * @@ -150,7 +150,7 @@ struct synps_edac_priv { * * Return: one if there is no error otherwise returns zero */ -static int synps_edac_geterror_info(void __iomem *base, +static int edac_geterror_info(void __iomem *base, struct synps_ecc_status *p) { u32 regval, clearval = 0; @@ -196,13 +196,13 @@ static int synps_edac_geterror_info(void __iomem *base, } /** - * synps_edac_handle_error - Handle controller error types CE and UE + * edac_handle_error - Handle controller error types CE and UE * @mci: Pointer to the edac memory controller instance * @p: Pointer to the synopsys ecc status structure * * Handles the controller ECC correctable and un correctable error. */ -static void synps_edac_handle_error(struct mem_ctl_info *mci, +static void edac_handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) { struct synps_edac_priv *priv = mci->pvt_info; @@ -232,30 +232,30 @@ static void synps_edac_handle_error(struct mem_ctl_info *mci, } /** - * synps_edac_check - Check controller for ECC errors + * edac_check - Check controller for ECC errors * @mci: Pointer to the edac memory controller instance * * Used to check and post ECC errors. Called by the polling thread */ -static void synps_edac_check(struct mem_ctl_info *mci) +static void edac_check(struct mem_ctl_info *mci) { struct synps_edac_priv *priv = mci->pvt_info; int status; - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); + status = edac_geterror_info(priv->baseaddr, &priv->stat); if (status) return; priv->ce_cnt += priv->stat.ce_cnt; priv->ue_cnt += priv->stat.ue_cnt; - synps_edac_handle_error(mci, &priv->stat); + edac_handle_error(mci, &priv->stat); edac_dbg(3, "Total error count CE %d UE %d\n", priv->ce_cnt, priv->ue_cnt); } /** - * synps_edac_get_dtype - Return the controller memory width + * edac_get_dtype - Return the controller memory width * @base: Pointer to the ddr memory controller base address * * Get the EDAC device type width appropriate for the current controller @@ -263,7 +263,7 @@ static void synps_edac_check(struct mem_ctl_info *mci) * * Return: a device type width enumeration. */ -static enum dev_type synps_edac_get_dtype(const void __iomem *base) +static enum dev_type edac_get_dtype(const void __iomem *base) { enum dev_type dt; u32 width; @@ -286,20 +286,20 @@ static enum dev_type synps_edac_get_dtype(const void __iomem *base) } /** - * synps_edac_get_eccstate - Return the controller ecc enable/disable status + * edac_get_eccstate - Return the controller ecc enable/disable status * @base: Pointer to the ddr memory controller base address * * Get the ECC enable/disable status for the controller * * Return: a ecc status boolean i.e true/false - enabled/disabled. */ -static bool synps_edac_get_eccstate(void __iomem *base) +static bool edac_get_eccstate(void __iomem *base) { bool state = false; enum dev_type dt; u32 ecctype; - dt = synps_edac_get_dtype(base); + dt = edac_get_dtype(base); if (dt == DEV_UNKNOWN) return state; @@ -311,11 +311,11 @@ static bool synps_edac_get_eccstate(void __iomem *base) } /** - * synps_edac_get_memsize - reads the size of the attached memory device + * edac_get_memsize - reads the size of the attached memory device * * Return: the memory size in bytes */ -static u32 synps_edac_get_memsize(void) +static u32 edac_get_memsize(void) { struct sysinfo inf; @@ -325,7 +325,7 @@ static u32 synps_edac_get_memsize(void) } /** - * synps_edac_get_mtype - Returns controller memory type + * edac_get_mtype - Returns controller memory type * @base: pointer to the synopsys ecc status structure * * Get the EDAC memory type appropriate for the current controller @@ -333,7 +333,7 @@ static u32 synps_edac_get_memsize(void) * * Return: a
[PATCH v8 10/10] edac: synopsys: Add Error Injection support for ZynqMP DDRC
Add support for Error Injection for ZynqMP DDRC IP. For injecting errors, the Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 421 ++- 1 file changed, 414 insertions(+), 7 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index adfa3bb..b64de4a 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -302,12 +302,18 @@ struct synps_ecc_status { /** * struct synps_edac_priv - DDR memory controller private instance data. - * @baseaddr: Base address of the DDR controller. - * @message: Buffer for framing the event specific info. - * @stat: ECC status information. - * @p_data:Platform data. - * @ce_cnt:Correctable Error count. - * @ue_cnt:Uncorrectable Error count. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @p_data:Platform data. + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. + * @poison_addr: Data poison address. + * @row_shift: Bit shifts for row bit. + * @col_shift: Bit shifts for column bit. + * @bank_shift:Bit shifts for bank bit. + * @bankgrp_shift: Bit shifts for bank group bit. + * @rank_shift:Bit shifts for rank bit. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -316,6 +322,14 @@ struct synps_edac_priv { const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; +#ifdef CONFIG_EDAC_DEBUG + ulong poison_addr; + u32 row_shift[18]; + u32 col_shift[14]; + u32 bank_shift[3]; + u32 bankgrp_shift[2]; + u32 rank_shift[1]; +#endif }; /** @@ -882,7 +896,11 @@ static const struct synps_platform_data zynqmp_edac_def = { .get_mtype = zynqmp_get_mtype, .get_dtype = zynqmp_get_dtype, .get_eccstate = zynqmp_get_eccstate, - .quirks = DDR_ECC_INTR_SUPPORT, + .quirks = (DDR_ECC_INTR_SUPPORT +#ifdef CONFIG_EDAC_DEBUG + | DDR_ECC_DATA_POISON_SUPPORT +#endif + ), }; static const struct of_device_id synps_edac_match[] = { @@ -901,6 +919,375 @@ static const struct of_device_id synps_edac_match[] = { MODULE_DEVICE_TABLE(of, synps_edac_match); +#ifdef CONFIG_EDAC_DEBUG +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +/** + * ddr_poison_setup - Update poison registers. + * @priv: DDR memory controller private instance data. + * + * Update poison registers as per DDR mapping. + * Return: none. + */ +static void ddr_poison_setup(struct synps_edac_priv *priv) +{ + int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval; + int index; + ulong hif_addr = 0; + + hif_addr = priv->poison_addr >> 3; + + for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) { + if (priv->row_shift[index]) + row |= (((hif_addr >> priv->row_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_COL_SHIFT; index++) { + if (priv->col_shift[index] || index < 3) + col |= (((hif_addr >> priv->col_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANK_SHIFT; index++) { + if (priv->bank_shift[index]) + bank |= (((hif_addr >> priv->bank_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANKGRP_SHIFT; index++) { + if (priv->bankgrp_shift[index]) + bankgrp |= (((hif_addr >> priv->bankgrp_shift[index]) + & BIT(0)) << index); + else + break; + } + + if (priv->rank_shift[0]) + rank = (hif_addr >> priv->rank_shift[0]) & BIT(0); + + regval = (rank << ECC_POISON0_RANK_SHIFT) & ECC_POISON0_RANK_MASK; + regval |= (col << ECC_POISON0_COLUMN_SHIFT) & ECC_POISON0_COLUMN_MASK; + writel(regval, priv->baseaddr + ECC_POISON0_OFST); + + regval = (bankgrp << ECC_POISON1_BG_SHIFT) & ECC_POISON1_BG_MASK; + regval |= (bank << ECC_POISON1_BANKNR_SHIFT) & ECC_PO
[PATCH v8 08/10] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
Add EDAC ECC support for ZynqMP DDRC IP. The IP supports interrupts for corrected and uncorrected errors. Add interrupt handlers for the same. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 328 --- 2 files changed, 311 insertions(+), 19 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..b1fc7a16 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 94d1398..adfa3bb 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,8 @@ * @bank: Bank number. * @bitpos:Bit position. * @data: Data causing the error. + * @bankgrpnr: Bank group number. + * @blknr: Block number. */ struct ecc_error_info { u32 row; @@ -279,6 +282,8 @@ struct ecc_error_info { u32 bank; u32 bitpos; u32 data; + u32 bankgrpnr; + u32 blknr; }; /** @@ -385,6 +390,68 @@ static int zynq_geterror_info(struct synps_edac_priv *priv) } /** + * zynqmp_geterror_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. + * + * Return: one if there is no error otherwise returns zero. + */ +static int zynqmp_geterror_info(struct synps_edac_priv *priv) +{ + struct synps_ecc_status *p; + u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; + + regval = readl(base + ECC_STAT_OFST); + if (!regval) + return 1; + + p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT; + p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT; + p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK); + + regval = readl(base + ECC_CEADDR0_OFST); + if (!p->ce_cnt) + goto ue_err; + + p->ceinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_CEADDR1_OFST); + p->ceinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ceinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ceinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ceinfo.data = readl(base + ECC_CSYND0_OFST); + edac_dbg(2, "ECCCSYN0: 0x%08X ECCCSYN1: 0x%08X ECCCSYN2: 0x%08X\n", +readl(base + ECC_CSYND0_OFST), readl(base + ECC_CSYND1_OFST), +readl(base + ECC_CSYND2_OFST)); + + +ue_err: + regval = readl(base + ECC_UEADDR0_OFST); + if (!p->ue_cnt) + goto out; + + p->ueinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_UEADDR1_OFST); + p->ueinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ueinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ueinfo.data = readl(base + ECC_UESYND0_OFST); +out: + clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; + clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + writel(clearval, base + ECC_CLR_OFST); + writel(0x0, base + ECC_CLR_OFST); + + return 0; +} + +/** * edac_handle_error - Handle controller error types CE and UE. * @mci: EDAC memory controller instance. * @p: Synopsys ECC status structure. @@ -399,9 +466,25 @@ static void edac_handle_error(struct mem_ctl_info *mci, if (p->ce_cnt) { pinf = &p->ceinfo; - snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, -"DDR ECC error type :%s Row %d Bank %d Col %d ", -"CE", pinf->row, pinf->bank, pinf->col); + if (!priv->p_data->quirks) { + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, +"DDR ECC error type:%s Row %d Bank %d Col %d ", + "CE", pinf->row, pinf->bank, pinf->col); + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, +
[PATCH v8 06/10] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
Add information of ZynqMP DDRC which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani Reviewed-by: Rob Herring --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v8 00/10] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms. This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Changes in v3: - The commit message in (2/4) is modified (Synopsys EDAC Driver --> ZynqMP DDRC) Changes in v4: - Updated the commit message in (1/4) - Renamed function pointer names removing 'synps_' in (1/4) - Shortened unnecessary long lines as per the review comment on (1/4) Changes in v5: - Updated the commit message in (2/4) and (4/4). - Removed the unnecessary check for match data in probe() in (1/4) - Some Indentation changes for better readability in (1/4) and (3/4) - Removed repeated code in (3/4) - Used 'zynq' and 'zynqmp' instead of 'synps_enh_edac' in function names Changes in v6: - Splitted the patches according to functionalities - Addressed code style comments from v5 review - Moved the Error Injection to CONFIG_EDAC_DEBUG mode Changes in v7: - Included DTS patch (6/7) which was missed in v6 patch set Changes in v8: - patch (1/7) from v7 is split in to 3 different logically different patches 1. functional changes like code cleanup 2. functions renaming 3. comments cleanup - Added a separate patch (4) for making always successful functions as void - Corrected 'Too many parentheses' review comment in patch (5) - Corrected comments as per the v7 review feedback - Made dedicated functions for IRQ setup, IRQ enable and IRQ disable in patch (8) - Addressed review comments in patch (10) Manish Narani (10): edac: synopsys: Update the driver code for better readability edac: synopsys: Rename the static functions to a shorter name edac: synopsys: Modify the comments in the driver edac: synopsys: Make return type void for functions always returning 0 edac: synps: Add platform specific structures for ddrc controller dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add macro defines for ZynqMP DDRC edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node edac: synopsys: Add Error Injection support for ZynqMP DDRC .../bindings/memory-controllers/synopsys.txt | 27 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi |7 + drivers/edac/Kconfig |2 +- drivers/edac/synopsys_edac.c | 1194 +--- 4 files changed, 1072 insertions(+), 158 deletions(-) -- 2.1.1
[PATCH v8 07/10] edac: synopsys: Add macro defines for ZynqMP DDRC
Add macro defines for ZynqMP DDR controller. These macros will be used for ZynqMP ECC operations. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 168 +++ 1 file changed, 168 insertions(+) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index f0f4704..94d1398 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -97,6 +97,174 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORTBIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON0_RANK_MASK BIT(24) +#define ECC_POISON0_COLUMN_SHIFT 0 +#define ECC_POISON0_COLUMN_MASK0xFFF +#define ECC_POISON1_BG_SHIFT 28 +#define ECC_POISON1_BG_MASK0x3000 +#define ECC_POISON1_BANKNR_SHIFT 24 +#define ECC_POISON1_BANKNR_MASK0x700 +#define ECC_POISON1_ROW_SHIFT 0 +#define ECC_POISON1_ROW_MASK 0x3 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_CFG_MASK 0xC000 +#define DDRC_MSTR_CFG_SHIFT30 +#define DDRC_MSTR_CFG_X4_MASK 0x0 +#define DDRC_MSTR_CFG_X8_MASK 0x1 +#define DDRC_MSTR_CFG_X16_MASK 0x2 +#define DDRC_MSTR_CFG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#de
[PATCH v8 03/10] edac: synopsys: Modify the comments in the driver
There are some comments which can be updated for better readability of the driver. Update abbreviations to capital letters in the comments. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 98 ++-- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index abb5de8..7db5928 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -96,12 +96,12 @@ #define SCRUB_MODE_SECDED 0x4 /** - * struct ecc_error_info - ECC error log information - * @row: Row number - * @col: Column number - * @bank: Bank number - * @bitpos:Bit position - * @data: Data causing the error + * struct ecc_error_info - ECC error log information. + * @row: Row number. + * @col: Column number. + * @bank: Bank number. + * @bitpos:Bit position. + * @data: Data causing the error. */ struct ecc_error_info { u32 row; @@ -112,11 +112,11 @@ struct ecc_error_info { }; /** - * struct synps_ecc_status - ECC status information to report - * @ce_cnt:Correctable error count - * @ue_cnt:Uncorrectable error count - * @ceinfo:Correctable error log information - * @ueinfo:Uncorrectable error log information + * struct synps_ecc_status - ECC status information to report. + * @ce_cnt:Correctable error count. + * @ue_cnt:Uncorrectable error count. + * @ceinfo:Correctable error log information. + * @ueinfo:Uncorrectable error log information. */ struct synps_ecc_status { u32 ce_cnt; @@ -126,12 +126,12 @@ struct synps_ecc_status { }; /** - * struct synps_edac_priv - DDR memory controller private instance data - * @baseaddr: Base address of the DDR controller - * @message: Buffer for framing the event specific info - * @stat: ECC status information - * @ce_cnt:Correctable Error count - * @ue_cnt:Uncorrectable Error count + * struct synps_edac_priv - DDR memory controller private instance data. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -142,13 +142,11 @@ struct synps_edac_priv { }; /** - * edac_geterror_info - Get the current ecc error info - * @base: Pointer to the base address of the ddr memory controller - * @p: Pointer to the synopsys ecc status structure + * edac_geterror_info - Get the current ECC error info. + * @base: Base address of the DDR memory controller. + * @p: Synopsys ECC status structure. * - * Determines there is any ecc error or not - * - * Return: one if there is no error otherwise returns zero + * Return: one if there is no error otherwise returns zero. */ static int edac_geterror_info(void __iomem *base, struct synps_ecc_status *p) @@ -196,11 +194,11 @@ static int edac_geterror_info(void __iomem *base, } /** - * edac_handle_error - Handle controller error types CE and UE - * @mci: Pointer to the edac memory controller instance - * @p: Pointer to the synopsys ecc status structure + * edac_handle_error - Handle controller error types CE and UE. + * @mci: EDAC memory controller instance. + * @p: Synopsys ECC status structure. * - * Handles the controller ECC correctable and un correctable error. + * Handles the controller ECC correctable and un-correctable error. */ static void edac_handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) @@ -232,10 +230,10 @@ static void edac_handle_error(struct mem_ctl_info *mci, } /** - * edac_check - Check controller for ECC errors - * @mci: Pointer to the edac memory controller instance + * edac_check - Check controller for ECC errors. + * @mci: EDAC memory controller instance. * - * Used to check and post ECC errors. Called by the polling thread + * Used to check and post ECC errors. Called by the polling thread. */ static void edac_check(struct mem_ctl_info *mci) { @@ -255,8 +253,8 @@ static void edac_check(struct mem_ctl_info *mci) } /** - * edac_get_dtype - Return the controller memory width - * @base: Pointer to the ddr memory controller base address + * edac_get_dtype - Return the controller memory width. + * @base: DDR memory controller base address. * * Get the EDAC device type width appropriate for the current controller * configuration. @@ -286,12 +284,12 @@ static enum dev_type edac_get_dtype(const void __iomem *base) } /** - * edac_get_eccstate - Return the controller ecc enable/disable status - * @base: Pointer to the ddr memory controller base address + * edac_get_eccstate - Return the controller ECC enable/disable status. + * @base: DDR
RE: [PATCH v8 02/10] edac: synopsys: Rename the static functions to a shorter name
Hi Boris, Thanks a lot for the review. > -Original Message- > From: Borislav Petkov [mailto:b...@alien8.de] > Sent: Friday, October 5, 2018 2:06 AM > Subject: Re: [PATCH v8 02/10] edac: synopsys: Rename the static functions to a > shorter name > > On Thu, Oct 04, 2018 at 09:05:20PM +0530, Manish Narani wrote: > > Rename the static functions to a shorter name. Since this is Synopsys > > EDAC driver, better to remove unnecessary 'synps_' prefix in function > > names. > > > > Signed-off-by: Manish Narani > > --- > > drivers/edac/synopsys_edac.c | 56 ++--- > --- > > 1 file changed, 28 insertions(+), 28 deletions(-) > > Ok, let's flip the roles - now you get to review what I've committed: Okay. Few minor nits below. :) > > --- > From: Manish Narani > Date: Thu, 4 Oct 2018 21:05:20 +0530 > Subject: [PATCH 1/2] EDAC, synopsys: Shorten static function names > > Shorten static function names, remove the unnecessary 'synps_' prefix in > function names. > > [ bp: Drop the "edac_" prefix too as that prefix is reserved for >EDAC core functions. ] > > Signed-off-by: Manish Narani > Signed-off-by: Borislav Petkov > CC: Mauro Carvalho Chehab > CC: Michal Simek > CC: amit.kuche...@linaro.org > CC: devicet...@vger.kernel.org > CC: leoyang...@nxp.com > CC: linux-arm-ker...@lists.infradead.org > CC: linux-edac > CC: mark.rutl...@arm.com > CC: robh...@kernel.org > CC: sudeep.ho...@arm.com > Link: http://lkml.kernel.org/r/1538667328-9465-3-git-send-email- > manish.nar...@xilinx.com > --- > drivers/edac/synopsys_edac.c | 79 +--- > 1 file changed, 38 insertions(+), 41 deletions(-) > > diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c > index 1936c73f1d15..fbaf33540ce3 100644 > --- a/drivers/edac/synopsys_edac.c > +++ b/drivers/edac/synopsys_edac.c > @@ -142,7 +142,7 @@ struct synps_edac_priv { > }; > > /** > - * synps_edac_geterror_info - Get the current ecc error info > + * get_error_info - Get the current ecc error info > * @base:Pointer to the base address of the ddr memory controller > * @p: Pointer to the synopsys ecc status structure > * > @@ -150,8 +150,7 @@ struct synps_edac_priv { > * > * Return: one if there is no error otherwise returns zero > */ > -static int synps_edac_geterror_info(void __iomem *base, > - struct synps_ecc_status *p) > +static int get_error_info(void __iomem *base, struct synps_ecc_status *p) > { > u32 regval, clearval = 0; > > @@ -196,14 +195,13 @@ static int synps_edac_geterror_info(void __iomem > *base, > } > > /** > - * synps_edac_handle_error - Handle controller error types CE and UE > + * handle_error - Handle controller error types CE and UE > * @mci: Pointer to the edac memory controller instance > * @p: Pointer to the synopsys ecc status structure > * > - * Handles the controller ECC correctable and un correctable error. > + * Handles the controller ECC correctable and uncorrectable error. Nit: This can be moved to Comments Correction patch > */ > -static void synps_edac_handle_error(struct mem_ctl_info *mci, > - struct synps_ecc_status *p) > +static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status > *p) > { > struct synps_edac_priv *priv = mci->pvt_info; > struct ecc_error_info *pinf; > @@ -232,30 +230,30 @@ static void synps_edac_handle_error(struct > mem_ctl_info *mci, > } > > /** > - * synps_edac_check - Check controller for ECC errors > + * check_errors - Check controller for ECC errors > * @mci: Pointer to the edac memory controller instance > * > * Used to check and post ECC errors. Called by the polling thread > */ > -static void synps_edac_check(struct mem_ctl_info *mci) > +static void check_errors(struct mem_ctl_info *mci) > { > struct synps_edac_priv *priv = mci->pvt_info; > int status; > > - status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); > + status = get_error_info(priv->baseaddr, &priv->stat); > if (status) > return; > > priv->ce_cnt += priv->stat.ce_cnt; > priv->ue_cnt += priv->stat.ue_cnt; > - synps_edac_handle_error(mci, &priv->stat); > + handle_error(mci, &priv->stat); > > edac_dbg(3, "Total error count CE %d UE %d\n", >priv->ce_cnt, priv->ue_cnt); > } > > /** > - * synp
RE: [PATCH v10 0/6] EDAC: Enhancements to Synopsys EDAC driver
Ping! > -Original Message- > From: Manish Narani [mailto:manish.nar...@xilinx.com] > Sent: Thursday, October 25, 2018 11:37 AM > To: robh...@kernel.org; mark.rutl...@arm.com; Michal Simek > ; b...@alien8.de; mche...@kernel.org; Manish Narani > ; amit.kuche...@linaro.org; sudeep.ho...@arm.com; > leoyang...@nxp.com > Cc: devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm- > ker...@lists.infradead.org; linux-e...@vger.kernel.org > Subject: [PATCH v10 0/6] EDAC: Enhancements to Synopsys EDAC driver > > This patch series enhances the current EDAC driver to support different > platforms. This series adds support for ZynqMP DDRC controller in synopsys > EDAC driver. This series also adds Device tree properties and relevant binding > documentation. > > Changes in v2: > - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it > is > a feature of ZynqMP DDRC > - The Binding Documentation in (2/4) is modified as per the review > comments > > Changes in v3: > - The commit message in (2/4) is modified (Synopsys EDAC Driver --> > ZynqMP DDRC) > > Changes in v4: > - Updated the commit message in (1/4) > - Renamed function pointer names removing 'synps_' in (1/4) > - Shortened unnecessary long lines as per the review comment on (1/4) > > Changes in v5: > - Updated the commit message in (2/4) and (4/4). > - Removed the unnecessary check for match data in probe() in (1/4) > - Some Indentation changes for better readability in (1/4) and (3/4) > - Removed repeated code in (3/4) > - Used 'zynq' and 'zynqmp' instead of 'synps_enh_edac' in function > names > > Changes in v6: > - Splitted the patches according to functionalities > - Addressed code style comments from v5 review > - Moved the Error Injection to CONFIG_EDAC_DEBUG mode > > Changes in v7: > - Included DTS patch (6/7) which was missed in v6 patch set > > Changes in v8: > - patch (1/7) from v7 is split in to 3 different logically different > patches > 1. functional changes like code cleanup > 2. functions renaming > 3. comments cleanup > - Added a separate patch (4) for making always successful functions as > void > - Corrected 'Too many parentheses' review comment in patch (5) > - Corrected comments as per the v7 review feedback > - Made dedicated functions for IRQ setup, IRQ enable and IRQ disable > in patch (8) > - Addressed review comments in patch (10) > > Changes in v9: > - Added check for return value of of_device_get_match_data() function > in (1/6). > - From v8 the first 5 patches are removed in this series as they are > applied on: > > https://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git/?h=edac-for- > 4.20-synps > - Updated Kconfig to check for ARCH_ZYNQMP instead of ARM64 > > Change in v10: > - Moved the checking for ce_cnt and ue_cnt before the readl() call > - Aligned arguments on the opening brace in setup_irq() > > Manish Narani (6): > edac: synopsys: Add error handling for NULL in probe() > dt: bindings: Document ZynqMP DDRC in Synopsys documentation > edac: synopsys: Add macro defines for ZynqMP DDRC > edac: synopsys: Add EDAC ECC support for ZynqMP DDRC > arm64: zynqmp: Add DDRC node > edac: synopsys: Add Error Injection support for ZynqMP DDRC > > .../bindings/memory-controllers/synopsys.txt | 27 +- > arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + > drivers/edac/Kconfig | 2 +- > drivers/edac/synopsys_edac.c | 911 > - > 4 files changed, 918 insertions(+), 29 deletions(-) > > -- > 2.1.1
[PATCH v10 4/6] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
Add EDAC ECC support for ZynqMP DDRC IP. The IP supports interrupts for corrected and uncorrected errors. Add interrupt handlers for the same. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 322 --- 2 files changed, 306 insertions(+), 18 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..7c40eb2 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARCH_ZYNQMP help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index d1999e0..e81f18a 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,8 @@ * @bank: Bank number. * @bitpos:Bit position. * @data: Data causing the error. + * @bankgrpnr: Bank group number. + * @blknr: Block number. */ struct ecc_error_info { u32 row; @@ -279,6 +282,8 @@ struct ecc_error_info { u32 bank; u32 bitpos; u32 data; + u32 bankgrpnr; + u32 blknr; }; /** @@ -385,6 +390,66 @@ static int zynq_get_error_info(struct synps_edac_priv *priv) } /** + * zynqmp_get_error_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. + * + * Return: one if there is no error otherwise returns zero. + */ +static int zynqmp_get_error_info(struct synps_edac_priv *priv) +{ + struct synps_ecc_status *p; + u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; + + regval = readl(base + ECC_STAT_OFST); + if (!regval) + return 1; + + p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT; + p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT; + if (!p->ce_cnt) + goto ue_err; + + p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK); + + regval = readl(base + ECC_CEADDR0_OFST); + p->ceinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_CEADDR1_OFST); + p->ceinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ceinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ceinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ceinfo.data = readl(base + ECC_CSYND0_OFST); + edac_dbg(2, "ECCCSYN0: 0x%08X ECCCSYN1: 0x%08X ECCCSYN2: 0x%08X\n", +readl(base + ECC_CSYND0_OFST), readl(base + ECC_CSYND1_OFST), +readl(base + ECC_CSYND2_OFST)); +ue_err: + if (!p->ue_cnt) + goto out; + + regval = readl(base + ECC_UEADDR0_OFST); + p->ueinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_UEADDR1_OFST); + p->ueinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ueinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ueinfo.data = readl(base + ECC_UESYND0_OFST); +out: + clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; + clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + writel(clearval, base + ECC_CLR_OFST); + writel(0x0, base + ECC_CLR_OFST); + + return 0; +} + +/** * handle_error - Handle Correctable and Uncorrectable errors. * @mci: EDAC memory controller instance. * @p: Synopsys ECC status structure. @@ -398,9 +463,25 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) if (p->ce_cnt) { pinf = &p->ceinfo; - snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, -"DDR ECC error type :%s Row %d Bank %d Col %d ", -"CE", pinf->row, pinf->bank, pinf->col); + if (!priv->p_data->quirks) { + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, +"DDR ECC error type:%s Row %d Bank %d Col %d ", + "CE", pinf->row, pinf->bank, pinf->col); + snprintf(priv->message, SYN
[PATCH v10 2/6] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
Add information of ZynqMP DDRC which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani Reviewed-by: Rob Herring --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v10 0/6] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms. This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Changes in v3: - The commit message in (2/4) is modified (Synopsys EDAC Driver --> ZynqMP DDRC) Changes in v4: - Updated the commit message in (1/4) - Renamed function pointer names removing 'synps_' in (1/4) - Shortened unnecessary long lines as per the review comment on (1/4) Changes in v5: - Updated the commit message in (2/4) and (4/4). - Removed the unnecessary check for match data in probe() in (1/4) - Some Indentation changes for better readability in (1/4) and (3/4) - Removed repeated code in (3/4) - Used 'zynq' and 'zynqmp' instead of 'synps_enh_edac' in function names Changes in v6: - Splitted the patches according to functionalities - Addressed code style comments from v5 review - Moved the Error Injection to CONFIG_EDAC_DEBUG mode Changes in v7: - Included DTS patch (6/7) which was missed in v6 patch set Changes in v8: - patch (1/7) from v7 is split in to 3 different logically different patches 1. functional changes like code cleanup 2. functions renaming 3. comments cleanup - Added a separate patch (4) for making always successful functions as void - Corrected 'Too many parentheses' review comment in patch (5) - Corrected comments as per the v7 review feedback - Made dedicated functions for IRQ setup, IRQ enable and IRQ disable in patch (8) - Addressed review comments in patch (10) Changes in v9: - Added check for return value of of_device_get_match_data() function in (1/6). - From v8 the first 5 patches are removed in this series as they are applied on: https://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git/?h=edac-for-4.20-synps - Updated Kconfig to check for ARCH_ZYNQMP instead of ARM64 Change in v10: - Moved the checking for ce_cnt and ue_cnt before the readl() call - Aligned arguments on the opening brace in setup_irq() Manish Narani (6): edac: synopsys: Add error handling for NULL in probe() dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add macro defines for ZynqMP DDRC edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node edac: synopsys: Add Error Injection support for ZynqMP DDRC .../bindings/memory-controllers/synopsys.txt | 27 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 + drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 911 - 4 files changed, 918 insertions(+), 29 deletions(-) -- 2.1.1
[PATCH v10 1/6] edac: synopsys: Add error handling for NULL in probe()
The function of_device_get_match_data() can return NULL in case of error. Add error handling for the same in probe(). Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 1c3795d..0005ef3 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -477,6 +477,9 @@ static int mc_probe(struct platform_device *pdev) return PTR_ERR(baseaddr); p_data = of_device_get_match_data(&pdev->dev); + if (!p_data) + return -ENODEV; + if (!p_data->get_ecc_state(baseaddr)) { edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); return -ENXIO; -- 2.1.1
[PATCH v10 6/6] edac: synopsys: Add Error Injection support for ZynqMP DDRC
Add support for Error Injection for ZynqMP DDRC IP. For injecting errors, the Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 420 ++- 1 file changed, 413 insertions(+), 7 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index e81f18a..2d26338 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -302,12 +302,18 @@ struct synps_ecc_status { /** * struct synps_edac_priv - DDR memory controller private instance data. - * @baseaddr: Base address of the DDR controller. - * @message: Buffer for framing the event specific info. - * @stat: ECC status information. - * @p_data:Platform data. - * @ce_cnt:Correctable Error count. - * @ue_cnt:Uncorrectable Error count. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @p_data:Platform data. + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. + * @poison_addr: Data poison address. + * @row_shift: Bit shifts for row bit. + * @col_shift: Bit shifts for column bit. + * @bank_shift:Bit shifts for bank bit. + * @bankgrp_shift: Bit shifts for bank group bit. + * @rank_shift:Bit shifts for rank bit. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -316,6 +322,14 @@ struct synps_edac_priv { const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; +#ifdef CONFIG_EDAC_DEBUG + ulong poison_addr; + u32 row_shift[18]; + u32 col_shift[14]; + u32 bank_shift[3]; + u32 bankgrp_shift[2]; + u32 rank_shift[1]; +#endif }; /** @@ -877,7 +891,11 @@ static const struct synps_platform_data zynqmp_edac_def = { .get_mtype = zynqmp_get_mtype, .get_dtype = zynqmp_get_dtype, .get_ecc_state = zynqmp_get_ecc_state, - .quirks = DDR_ECC_INTR_SUPPORT, + .quirks = (DDR_ECC_INTR_SUPPORT +#ifdef CONFIG_EDAC_DEBUG + | DDR_ECC_DATA_POISON_SUPPORT +#endif + ), }; static const struct of_device_id synps_edac_match[] = { @@ -896,6 +914,375 @@ static const struct of_device_id synps_edac_match[] = { MODULE_DEVICE_TABLE(of, synps_edac_match); +#ifdef CONFIG_EDAC_DEBUG +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +/** + * ddr_poison_setup - Update poison registers. + * @priv: DDR memory controller private instance data. + * + * Update poison registers as per DDR mapping. + * Return: none. + */ +static void ddr_poison_setup(struct synps_edac_priv *priv) +{ + int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval; + int index; + ulong hif_addr = 0; + + hif_addr = priv->poison_addr >> 3; + + for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) { + if (priv->row_shift[index]) + row |= (((hif_addr >> priv->row_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_COL_SHIFT; index++) { + if (priv->col_shift[index] || index < 3) + col |= (((hif_addr >> priv->col_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANK_SHIFT; index++) { + if (priv->bank_shift[index]) + bank |= (((hif_addr >> priv->bank_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANKGRP_SHIFT; index++) { + if (priv->bankgrp_shift[index]) + bankgrp |= (((hif_addr >> priv->bankgrp_shift[index]) + & BIT(0)) << index); + else + break; + } + + if (priv->rank_shift[0]) + rank = (hif_addr >> priv->rank_shift[0]) & BIT(0); + + regval = (rank << ECC_POISON0_RANK_SHIFT) & ECC_POISON0_RANK_MASK; + regval |= (col << ECC_POISON0_COLUMN_SHIFT) & ECC_POISON0_COLUMN_MASK; + writel(regval, priv->baseaddr + ECC_POISON0_OFST); + + regval = (bankgrp << ECC_POISON1_BG_SHIFT) & ECC_POISON1_BG_MASK; + regval |= (bank << ECC_POISON1_BANKNR_SHIFT) & ECC_PO
[PATCH v10 3/6] edac: synopsys: Add macro defines for ZynqMP DDRC
Add macro defines for ZynqMP DDR controller. These macros will be used for ZynqMP ECC operations. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 168 +++ 1 file changed, 168 insertions(+) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0005ef3..d1999e0 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -97,6 +97,174 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORTBIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON0_RANK_MASK BIT(24) +#define ECC_POISON0_COLUMN_SHIFT 0 +#define ECC_POISON0_COLUMN_MASK0xFFF +#define ECC_POISON1_BG_SHIFT 28 +#define ECC_POISON1_BG_MASK0x3000 +#define ECC_POISON1_BANKNR_SHIFT 24 +#define ECC_POISON1_BANKNR_MASK0x700 +#define ECC_POISON1_ROW_SHIFT 0 +#define ECC_POISON1_ROW_MASK 0x3 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_CFG_MASK 0xC000 +#define DDRC_MSTR_CFG_SHIFT30 +#define DDRC_MSTR_CFG_X4_MASK 0x0 +#define DDRC_MSTR_CFG_X8_MASK 0x1 +#define DDRC_MSTR_CFG_X16_MASK 0x2 +#define DDRC_MSTR_CFG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#de
[PATCH v10 5/6] arm64: zynqmp: Add DDRC node
Add ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at 0xFD090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 29ce234..a81d3b16 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH v6 0/6] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms. This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Changes in v3: - The commit message in (2/4) is modified (Synopsys EDAC Driver --> ZynqMP DDRC) Changes in v4: - Updated the commit message in (1/4) - Renamed function pointer names removing 'synps_' in (1/4) - Shortened unnecessary long lines as per the review comment on (1/4) Changes in v5: - Updated the commit message in (2/4) and (4/4). - Removed the unnecessary check for match data in probe() in (1/4) - Some Indentation changes for better readability in (1/4) and (3/4) - Removed repeated code in (3/4) - Used 'zynq' and 'zynqmp' instead of 'synps_enh_edac' in function names Changes in v6: - Splitted the patches according to functionalities - Addressed code style comments from v5 review - Moved the Error Injection to CONFIG_EDAC_DEBUG mode Manish Narani (6): edac: synopsys: Fix code comments and naming convention edac: synps: Add platform specific structures for ddrc controller dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add macro defines for ZynqMP DDRC edac: synopsys: Add EDAC ECC support for ZynqMP DDRC edac: synopsys: Add Error Injection support for ZynqMP DDRC .../bindings/memory-controllers/synopsys.txt | 27 +- drivers/edac/Kconfig |2 +- drivers/edac/synopsys_edac.c | 1098 ++-- 3 files changed, 1007 insertions(+), 120 deletions(-) -- 2.1.1
[PATCH v6 1/6] edac: synopsys: Fix code comments and naming convention
Update the comments in the Synopsys EDAC driver. Minor changes to function names and return types are also included. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 176 --- 1 file changed, 80 insertions(+), 96 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0c9c59e..4963930 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -96,12 +96,12 @@ #define SCRUB_MODE_SECDED 0x4 /** - * struct ecc_error_info - ECC error log information - * @row: Row number - * @col: Column number - * @bank: Bank number - * @bitpos:Bit position - * @data: Data causing the error + * struct ecc_error_info - ECC error log information. + * @row: Row number. + * @col: Column number. + * @bank: Bank number. + * @bitpos:Bit position. + * @data: Data causing the error. */ struct ecc_error_info { u32 row; @@ -112,11 +112,11 @@ struct ecc_error_info { }; /** - * struct synps_ecc_status - ECC status information to report - * @ce_cnt:Correctable error count - * @ue_cnt:Uncorrectable error count - * @ceinfo:Correctable error log information - * @ueinfo:Uncorrectable error log information + * struct synps_ecc_status - ECC status information to report. + * @ce_cnt:Correctable error count. + * @ue_cnt:Uncorrectable error count. + * @ceinfo:Correctable error log information. + * @ueinfo:Uncorrectable error log information. */ struct synps_ecc_status { u32 ce_cnt; @@ -126,12 +126,12 @@ struct synps_ecc_status { }; /** - * struct synps_edac_priv - DDR memory controller private instance data - * @baseaddr: Base address of the DDR controller - * @message: Buffer for framing the event specific info - * @stat: ECC status information - * @ce_cnt:Correctable Error count - * @ue_cnt:Uncorrectable Error count + * struct synps_edac_priv - DDR memory controller private instance data. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -142,15 +142,13 @@ struct synps_edac_priv { }; /** - * synps_edac_geterror_info - Get the current ecc error info - * @base: Pointer to the base address of the ddr memory controller - * @p: Pointer to the synopsys ecc status structure + * edac_geterror_info - Get the current ECC error info. + * @base: Base address of the DDR memory controller. + * @p: Synopsys ECC status structure. * - * Determines there is any ecc error or not - * - * Return: one if there is no error otherwise returns zero + * Return: one if there is no error otherwise returns zero. */ -static int synps_edac_geterror_info(void __iomem *base, +static int edac_geterror_info(void __iomem *base, struct synps_ecc_status *p) { u32 regval, clearval = 0; @@ -172,7 +170,7 @@ static int synps_edac_geterror_info(void __iomem *base, p->ceinfo.col = regval & ADDR_COL_MASK; p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; p->ceinfo.data = readl(base + CE_DATA_31_0_OFST); - edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos, + edac_dbg(3, "CE bit position: %d data: %d\n", p->ceinfo.bitpos, p->ceinfo.data); clearval = ECC_CTRL_CLR_CE_ERR; @@ -196,13 +194,13 @@ static int synps_edac_geterror_info(void __iomem *base, } /** - * synps_edac_handle_error - Handle controller error types CE and UE - * @mci: Pointer to the edac memory controller instance - * @p: Pointer to the synopsys ecc status structure + * edac_handle_error - Handle controller error types CE and UE. + * @mci: EDAC memory controller instance. + * @p: Synopsys ECC status structure. * - * Handles the controller ECC correctable and un correctable error. + * Handles the controller ECC correctable and un-correctable error. */ -static void synps_edac_handle_error(struct mem_ctl_info *mci, +static void edac_handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) { struct synps_edac_priv *priv = mci->pvt_info; @@ -232,38 +230,38 @@ static void synps_edac_handle_error(struct mem_ctl_info *mci, } /** - * synps_edac_check - Check controller for ECC errors - * @mci: Pointer to the edac memory controller instance + * edac_check - Check controller for ECC errors. + * @mci: EDAC memory controller instance. * - * Used to check and post ECC errors. Called by the polling thread + * Used to check and post ECC errors. Called by the polling thread. */ -static void synps_edac_check(struct mem_ctl
[PATCH v6 6/6] edac: synopsys: Add Error Injection support for ZynqMP DDRC
Add support for Error Injection for ZynqMP DDRC IP. For injecting errors, the Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 423 ++- 1 file changed, 417 insertions(+), 6 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 7ab5b9a..177b5c3 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -302,12 +302,18 @@ struct synps_ecc_status { /** * struct synps_edac_priv - DDR memory controller private instance data. - * @baseaddr: Base address of the DDR controller. - * @message: Buffer for framing the event specific info. - * @stat: ECC status information. - * @p_data:Platform data - * @ce_cnt:Correctable Error count. - * @ue_cnt:Uncorrectable Error count. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @p_data:Platform data + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. + * @poison_addr: Data poison address. + * @row_shift: Bit shifts for row bit. + * @col_shift: Bit shifts for column bit. + * @bank_shift:Bit shifts for bank bit. + * @bankgrp_shift: Bit shifts for bank group bit. + * @rank_shift:Bit shifts for rank bit. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -316,6 +322,14 @@ struct synps_edac_priv { const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; +#ifdef CONFIG_EDAC_DEBUG + ulong poison_addr; + u32 row_shift[18]; + u32 col_shift[14]; + u32 bank_shift[3]; + u32 bankgrp_shift[2]; + u32 rank_shift[1]; +#endif }; /** @@ -842,7 +856,12 @@ static const struct synps_platform_data zynqmp_edac_def = { .get_mtype = zynqmp_get_mtype, .get_dtype = zynqmp_get_dtype, .get_eccstate = zynqmp_get_eccstate, +#ifdef CONFIG_EDAC_DEBUG + .quirks = (DDR_ECC_INTR_SUPPORT | + DDR_ECC_DATA_POISON_SUPPORT), +#else .quirks = DDR_ECC_INTR_SUPPORT, +#endif }; static const struct of_device_id synps_edac_match[] = { @@ -861,6 +880,380 @@ static const struct of_device_id synps_edac_match[] = { MODULE_DEVICE_TABLE(of, synps_edac_match); +#ifdef CONFIG_EDAC_DEBUG +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +/** + * ddr_poison_setup - Update poison registers. + * @priv: DDR memory controller private instance data. + * + * Update poison registers as per DDR mapping. + * Return: none. + */ +static void ddr_poison_setup(struct synps_edac_priv *priv) +{ + int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval; + int index; + ulong hif_addr = 0; + + hif_addr = priv->poison_addr >> 3; + + for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) { + if (priv->row_shift[index]) + row |= (((hif_addr >> priv->row_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_COL_SHIFT; index++) { + if (priv->col_shift[index] || index < 3) + col |= (((hif_addr >> priv->col_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANK_SHIFT; index++) { + if (priv->bank_shift[index]) + bank |= (((hif_addr >> priv->bank_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANKGRP_SHIFT; index++) { + if (priv->bankgrp_shift[index]) + bankgrp |= (((hif_addr >> priv->bankgrp_shift[index]) + & BIT(0)) << index); + else + break; + } + + if (priv->rank_shift[0]) + rank = (hif_addr >> priv->rank_shift[0]) & BIT(0); + + regval = (rank << ECC_POISON0_RANK_SHIFT) & ECC_POISON0_RANK_MASK; + regval |= (col << ECC_POISON0_COLUMN_SHIFT) & ECC_POISON0_COLUMN_MASK; + writel(regval, priv->baseaddr + ECC_POISON0_OFST); + + regval = (bankgrp << ECC_POISON1_BG_SHIFT) & ECC_POISON1_BG_MASK; + regval |= (bank << ECC_POISON1_BANKNR_SHIFT) & ECC_POISON1_BANKNR_MASK; +
[PATCH v6 3/6] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
Add information of ZynqMP DDRC which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani Reviewed-by: Rob Herring --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v6 5/6] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
Add EDAC ECC support for ZynqMP DDRC IP. The IP supports interrupts for corrected and uncorrected errors. Add interrupt handlers for the same. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 304 --- 2 files changed, 287 insertions(+), 19 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..b1fc7a16 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 6bf7959..7ab5b9a 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,8 @@ * @bank: Bank number. * @bitpos:Bit position. * @data: Data causing the error. + * @bankgrpnr: Bank group number. + * @blknr: Block number. */ struct ecc_error_info { u32 row; @@ -279,6 +282,8 @@ struct ecc_error_info { u32 bank; u32 bitpos; u32 data; + u32 bankgrpnr; + u32 blknr; }; /** @@ -385,6 +390,68 @@ static int zynq_geterror_info(struct synps_edac_priv *priv) } /** + * zynqmp_geterror_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. + * + * Return: one if there is no error otherwise returns zero. + */ +static int zynqmp_geterror_info(struct synps_edac_priv *priv) +{ + struct synps_ecc_status *p; + u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; + + regval = readl(base + ECC_STAT_OFST); + if (!regval) + return 1; + + p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT; + p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT; + p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK); + + regval = readl(base + ECC_CEADDR0_OFST); + if (!(p->ce_cnt)) + goto ue_err; + + p->ceinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_CEADDR1_OFST); + p->ceinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ceinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ceinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ceinfo.data = readl(base + ECC_CSYND0_OFST); + edac_dbg(2, "ECCCSYN0: 0x%08X ECCCSYN1: 0x%08X ECCCSYN2: 0x%08X\n", +readl(base + ECC_CSYND0_OFST), readl(base + ECC_CSYND1_OFST), +readl(base + ECC_CSYND2_OFST)); + + +ue_err: + regval = readl(base + ECC_UEADDR0_OFST); + if (!(p->ue_cnt)) + goto out; + + p->ueinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_UEADDR1_OFST); + p->ueinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ueinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ueinfo.data = readl(base + ECC_UESYND0_OFST); +out: + clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; + clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + writel(clearval, base + ECC_CLR_OFST); + writel(0x0, base + ECC_CLR_OFST); + + return 0; +} + +/** * edac_handle_error - Handle controller error types CE and UE. * @mci: EDAC memory controller instance. * @p: Synopsys ECC status structure. @@ -399,9 +466,25 @@ static void edac_handle_error(struct mem_ctl_info *mci, if (p->ce_cnt) { pinf = &p->ceinfo; - snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, -"DDR ECC error type :%s Row %d Bank %d Col %d ", -"CE", pinf->row, pinf->bank, pinf->col); + if (!priv->p_data->quirks) { + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, +"DDR ECC error type:%s Row %d Bank %d Col %d ", + "CE", pinf->row, pinf->bank, pinf->col); + snprintf(priv->message, SYN
[PATCH v6 2/6] edac: synps: Add platform specific structures for ddrc controller
Add platform specific structures, so that we can add different IP support later using quirks. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 91 +++- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 4963930..eb458e5 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "edac_module.h" @@ -130,6 +132,7 @@ struct synps_ecc_status { * @baseaddr: Base address of the DDR controller. * @message: Buffer for framing the event specific info. * @stat: ECC status information. + * @p_data:Platform data * @ce_cnt:Correctable Error count. * @ue_cnt:Uncorrectable Error count. */ @@ -137,21 +140,41 @@ struct synps_edac_priv { void __iomem *baseaddr; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; + const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; }; /** - * edac_geterror_info - Get the current ECC error info. - * @base: Base address of the DDR memory controller. - * @p: Synopsys ECC status structure. + * struct synps_platform_data - synps platform data structure. + * @geterror_info: Get error info. + * @get_mtype: Get mtype. + * @get_dtype: Get dtype. + * @get_eccstate: Get eccstate. + * @quirks:To differentiate IPs. + */ +struct synps_platform_data { + int (*geterror_info)(struct synps_edac_priv *priv); + enum mem_type (*get_mtype)(const void __iomem *base); + enum dev_type (*get_dtype)(const void __iomem *base); + bool (*get_eccstate)(void __iomem *base); + int quirks; +}; + +/** + * zynq_geterror_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. * * Return: one if there is no error otherwise returns zero. */ -static int edac_geterror_info(void __iomem *base, - struct synps_ecc_status *p) +static int zynq_geterror_info(struct synps_edac_priv *priv) { + struct synps_ecc_status *p; u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; regval = readl(base + STAT_OFST); if (!regval) @@ -230,17 +253,18 @@ static void edac_handle_error(struct mem_ctl_info *mci, } /** - * edac_check - Check controller for ECC errors. + * edac_error_check - Check controller for ECC errors. * @mci: EDAC memory controller instance. * * Used to check and post ECC errors. Called by the polling thread. */ -static void edac_check(struct mem_ctl_info *mci) +static void edac_error_check(struct mem_ctl_info *mci) { struct synps_edac_priv *priv = mci->pvt_info; + const struct synps_platform_data *p_data = priv->p_data; int status; - status = edac_geterror_info(priv->baseaddr, &priv->stat); + status = p_data->geterror_info(priv); if (status) return; @@ -253,7 +277,7 @@ static void edac_check(struct mem_ctl_info *mci) } /** - * edac_get_dtype - Return the controller memory width. + * zynq_get_dtype - Return the controller memory width. * @base: DDR memory controller base address. * * Get the EDAC device type width appropriate for the current controller @@ -261,7 +285,7 @@ static void edac_check(struct mem_ctl_info *mci) * * Return: a device type width enumeration. */ -static enum dev_type edac_get_dtype(const void __iomem *base) +static enum dev_type zynq_get_dtype(const void __iomem *base) { enum dev_type dt; u32 width; @@ -284,20 +308,20 @@ static enum dev_type edac_get_dtype(const void __iomem *base) } /** - * edac_get_eccstate - Return the controller ECC enable/disable status. + * zynq_get_eccstate - Return the controller ECC enable/disable status. * @base: DDR memory controller base address. * * Get the ECC enable/disable status for the controller. * * Return: a ECC status boolean i.e true/false - enabled/disabled. */ -static bool edac_get_eccstate(void __iomem *base) +static bool zynq_get_eccstate(void __iomem *base) { bool state = false; enum dev_type dt; u32 ecctype; - dt = edac_get_dtype(base); + dt = zynq_get_dtype(base); if (dt == DEV_UNKNOWN) return state; @@ -323,7 +347,7 @@ static u32 edac_get_memsize(void) } /** - * edac_get_mtype - Returns controller memory type. + * zynq_get_mtype - Returns controller memory type. * @base: Synopsys ECC status structure. * * Get the EDAC memory type appropriate for the current controller @@ -331,7 +355,7 @@ static u32 edac_get_memsize(void) * * Return: a memory type enumeration. */ -static enum mem_type edac_get_mtype(const vo
[PATCH v6 4/6] edac: synopsys: Add macro defines for ZynqMP DDRC
Add macro defines for ZynqMP DDR controller. These macros will be used for ZyqnMP ECC operations. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 168 +++ 1 file changed, 168 insertions(+) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index eb458e5..6bf7959 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -97,6 +97,174 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORTBIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON0_RANK_MASK BIT(24) +#define ECC_POISON0_COLUMN_SHIFT 0 +#define ECC_POISON0_COLUMN_MASK0xFFF +#define ECC_POISON1_BG_SHIFT 28 +#define ECC_POISON1_BG_MASK0x3000 +#define ECC_POISON1_BANKNR_SHIFT 24 +#define ECC_POISON1_BANKNR_MASK0x700 +#define ECC_POISON1_ROW_SHIFT 0 +#define ECC_POISON1_ROW_MASK 0x3 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_CFG_MASK 0xC000 +#define DDRC_MSTR_CFG_SHIFT30 +#define DDRC_MSTR_CFG_X4_MASK 0x0 +#define DDRC_MSTR_CFG_X8_MASK 0x1 +#define DDRC_MSTR_CFG_X16_MASK 0x2 +#define DDRC_MSTR_CFG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#define ROW_MAX_VAL_
[PATCH v7 0/7] EDAC: Enhancements to Synopsys EDAC driver
This patch series enhances the current EDAC driver to support different platforms. This series adds support for ZynqMP DDRC controller in synopsys EDAC driver. This series also adds Device tree properties and relevant binding documentation. Changes in v2: - Moved checking of DDR_ECC_INTR_SUPPORT from (1/4) to (3/4) as it is a feature of ZynqMP DDRC - The Binding Documentation in (2/4) is modified as per the review comments Changes in v3: - The commit message in (2/4) is modified (Synopsys EDAC Driver --> ZynqMP DDRC) Changes in v4: - Updated the commit message in (1/4) - Renamed function pointer names removing 'synps_' in (1/4) - Shortened unnecessary long lines as per the review comment on (1/4) Changes in v5: - Updated the commit message in (2/4) and (4/4). - Removed the unnecessary check for match data in probe() in (1/4) - Some Indentation changes for better readability in (1/4) and (3/4) - Removed repeated code in (3/4) - Used 'zynq' and 'zynqmp' instead of 'synps_enh_edac' in function names Changes in v6: - Splitted the patches according to functionalities - Addressed code style comments from v5 review - Moved the Error Injection to CONFIG_EDAC_DEBUG mode Changes in v7: - Included DTS patch (6/7) which was missed in v6 patch set Manish Narani (7): edac: synopsys: Fix code comments and naming convention edac: synps: Add platform specific structures for ddrc controller dt: bindings: Document ZynqMP DDRC in Synopsys documentation edac: synopsys: Add macro defines for ZynqMP DDRC edac: synopsys: Add EDAC ECC support for ZynqMP DDRC arm64: zynqmp: Add DDRC node edac: synopsys: Add Error Injection support for ZynqMP DDRC .../bindings/memory-controllers/synopsys.txt | 27 +- arch/arm64/boot/dts/xilinx/zynqmp.dtsi |7 + drivers/edac/Kconfig |2 +- drivers/edac/synopsys_edac.c | 1098 ++-- 4 files changed, 1014 insertions(+), 120 deletions(-) -- 2.1.1
[PATCH v7 1/7] edac: synopsys: Fix code comments and naming convention
Update the comments in the Synopsys EDAC driver. Minor changes to function names and return types are also included. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 176 --- 1 file changed, 80 insertions(+), 96 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 0c9c59e..4963930 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -96,12 +96,12 @@ #define SCRUB_MODE_SECDED 0x4 /** - * struct ecc_error_info - ECC error log information - * @row: Row number - * @col: Column number - * @bank: Bank number - * @bitpos:Bit position - * @data: Data causing the error + * struct ecc_error_info - ECC error log information. + * @row: Row number. + * @col: Column number. + * @bank: Bank number. + * @bitpos:Bit position. + * @data: Data causing the error. */ struct ecc_error_info { u32 row; @@ -112,11 +112,11 @@ struct ecc_error_info { }; /** - * struct synps_ecc_status - ECC status information to report - * @ce_cnt:Correctable error count - * @ue_cnt:Uncorrectable error count - * @ceinfo:Correctable error log information - * @ueinfo:Uncorrectable error log information + * struct synps_ecc_status - ECC status information to report. + * @ce_cnt:Correctable error count. + * @ue_cnt:Uncorrectable error count. + * @ceinfo:Correctable error log information. + * @ueinfo:Uncorrectable error log information. */ struct synps_ecc_status { u32 ce_cnt; @@ -126,12 +126,12 @@ struct synps_ecc_status { }; /** - * struct synps_edac_priv - DDR memory controller private instance data - * @baseaddr: Base address of the DDR controller - * @message: Buffer for framing the event specific info - * @stat: ECC status information - * @ce_cnt:Correctable Error count - * @ue_cnt:Uncorrectable Error count + * struct synps_edac_priv - DDR memory controller private instance data. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -142,15 +142,13 @@ struct synps_edac_priv { }; /** - * synps_edac_geterror_info - Get the current ecc error info - * @base: Pointer to the base address of the ddr memory controller - * @p: Pointer to the synopsys ecc status structure + * edac_geterror_info - Get the current ECC error info. + * @base: Base address of the DDR memory controller. + * @p: Synopsys ECC status structure. * - * Determines there is any ecc error or not - * - * Return: one if there is no error otherwise returns zero + * Return: one if there is no error otherwise returns zero. */ -static int synps_edac_geterror_info(void __iomem *base, +static int edac_geterror_info(void __iomem *base, struct synps_ecc_status *p) { u32 regval, clearval = 0; @@ -172,7 +170,7 @@ static int synps_edac_geterror_info(void __iomem *base, p->ceinfo.col = regval & ADDR_COL_MASK; p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; p->ceinfo.data = readl(base + CE_DATA_31_0_OFST); - edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos, + edac_dbg(3, "CE bit position: %d data: %d\n", p->ceinfo.bitpos, p->ceinfo.data); clearval = ECC_CTRL_CLR_CE_ERR; @@ -196,13 +194,13 @@ static int synps_edac_geterror_info(void __iomem *base, } /** - * synps_edac_handle_error - Handle controller error types CE and UE - * @mci: Pointer to the edac memory controller instance - * @p: Pointer to the synopsys ecc status structure + * edac_handle_error - Handle controller error types CE and UE. + * @mci: EDAC memory controller instance. + * @p: Synopsys ECC status structure. * - * Handles the controller ECC correctable and un correctable error. + * Handles the controller ECC correctable and un-correctable error. */ -static void synps_edac_handle_error(struct mem_ctl_info *mci, +static void edac_handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) { struct synps_edac_priv *priv = mci->pvt_info; @@ -232,38 +230,38 @@ static void synps_edac_handle_error(struct mem_ctl_info *mci, } /** - * synps_edac_check - Check controller for ECC errors - * @mci: Pointer to the edac memory controller instance + * edac_check - Check controller for ECC errors. + * @mci: EDAC memory controller instance. * - * Used to check and post ECC errors. Called by the polling thread + * Used to check and post ECC errors. Called by the polling thread. */ -static void synps_edac_check(struct mem_ctl
[PATCH v7 2/7] edac: synps: Add platform specific structures for ddrc controller
Add platform specific structures, so that we can add different IP support later using quirks. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 91 +++- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 4963930..eb458e5 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "edac_module.h" @@ -130,6 +132,7 @@ struct synps_ecc_status { * @baseaddr: Base address of the DDR controller. * @message: Buffer for framing the event specific info. * @stat: ECC status information. + * @p_data:Platform data * @ce_cnt:Correctable Error count. * @ue_cnt:Uncorrectable Error count. */ @@ -137,21 +140,41 @@ struct synps_edac_priv { void __iomem *baseaddr; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; + const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; }; /** - * edac_geterror_info - Get the current ECC error info. - * @base: Base address of the DDR memory controller. - * @p: Synopsys ECC status structure. + * struct synps_platform_data - synps platform data structure. + * @geterror_info: Get error info. + * @get_mtype: Get mtype. + * @get_dtype: Get dtype. + * @get_eccstate: Get eccstate. + * @quirks:To differentiate IPs. + */ +struct synps_platform_data { + int (*geterror_info)(struct synps_edac_priv *priv); + enum mem_type (*get_mtype)(const void __iomem *base); + enum dev_type (*get_dtype)(const void __iomem *base); + bool (*get_eccstate)(void __iomem *base); + int quirks; +}; + +/** + * zynq_geterror_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. * * Return: one if there is no error otherwise returns zero. */ -static int edac_geterror_info(void __iomem *base, - struct synps_ecc_status *p) +static int zynq_geterror_info(struct synps_edac_priv *priv) { + struct synps_ecc_status *p; u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; regval = readl(base + STAT_OFST); if (!regval) @@ -230,17 +253,18 @@ static void edac_handle_error(struct mem_ctl_info *mci, } /** - * edac_check - Check controller for ECC errors. + * edac_error_check - Check controller for ECC errors. * @mci: EDAC memory controller instance. * * Used to check and post ECC errors. Called by the polling thread. */ -static void edac_check(struct mem_ctl_info *mci) +static void edac_error_check(struct mem_ctl_info *mci) { struct synps_edac_priv *priv = mci->pvt_info; + const struct synps_platform_data *p_data = priv->p_data; int status; - status = edac_geterror_info(priv->baseaddr, &priv->stat); + status = p_data->geterror_info(priv); if (status) return; @@ -253,7 +277,7 @@ static void edac_check(struct mem_ctl_info *mci) } /** - * edac_get_dtype - Return the controller memory width. + * zynq_get_dtype - Return the controller memory width. * @base: DDR memory controller base address. * * Get the EDAC device type width appropriate for the current controller @@ -261,7 +285,7 @@ static void edac_check(struct mem_ctl_info *mci) * * Return: a device type width enumeration. */ -static enum dev_type edac_get_dtype(const void __iomem *base) +static enum dev_type zynq_get_dtype(const void __iomem *base) { enum dev_type dt; u32 width; @@ -284,20 +308,20 @@ static enum dev_type edac_get_dtype(const void __iomem *base) } /** - * edac_get_eccstate - Return the controller ECC enable/disable status. + * zynq_get_eccstate - Return the controller ECC enable/disable status. * @base: DDR memory controller base address. * * Get the ECC enable/disable status for the controller. * * Return: a ECC status boolean i.e true/false - enabled/disabled. */ -static bool edac_get_eccstate(void __iomem *base) +static bool zynq_get_eccstate(void __iomem *base) { bool state = false; enum dev_type dt; u32 ecctype; - dt = edac_get_dtype(base); + dt = zynq_get_dtype(base); if (dt == DEV_UNKNOWN) return state; @@ -323,7 +347,7 @@ static u32 edac_get_memsize(void) } /** - * edac_get_mtype - Returns controller memory type. + * zynq_get_mtype - Returns controller memory type. * @base: Synopsys ECC status structure. * * Get the EDAC memory type appropriate for the current controller @@ -331,7 +355,7 @@ static u32 edac_get_memsize(void) * * Return: a memory type enumeration. */ -static enum mem_type edac_get_mtype(const vo
[PATCH v7 5/7] edac: synopsys: Add EDAC ECC support for ZynqMP DDRC
Add EDAC ECC support for ZynqMP DDRC IP. The IP supports interrupts for corrected and uncorrected errors. Add interrupt handlers for the same. Signed-off-by: Manish Narani --- drivers/edac/Kconfig | 2 +- drivers/edac/synopsys_edac.c | 304 --- 2 files changed, 287 insertions(+), 19 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2..b1fc7a16 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -441,7 +441,7 @@ config EDAC_ALTERA_SDMMC config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Support for error detection and correction on the Synopsys DDR memory controller. diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 6bf7959..7ab5b9a 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,8 @@ * @bank: Bank number. * @bitpos:Bit position. * @data: Data causing the error. + * @bankgrpnr: Bank group number. + * @blknr: Block number. */ struct ecc_error_info { u32 row; @@ -279,6 +282,8 @@ struct ecc_error_info { u32 bank; u32 bitpos; u32 data; + u32 bankgrpnr; + u32 blknr; }; /** @@ -385,6 +390,68 @@ static int zynq_geterror_info(struct synps_edac_priv *priv) } /** + * zynqmp_geterror_info - Get the current ECC error info. + * @priv: DDR memory controller private instance data. + * + * Return: one if there is no error otherwise returns zero. + */ +static int zynqmp_geterror_info(struct synps_edac_priv *priv) +{ + struct synps_ecc_status *p; + u32 regval, clearval = 0; + void __iomem *base; + + base = priv->baseaddr; + p = &priv->stat; + + regval = readl(base + ECC_STAT_OFST); + if (!regval) + return 1; + + p->ce_cnt = (regval & ECC_STAT_CECNT_MASK) >> ECC_STAT_CECNT_SHIFT; + p->ue_cnt = (regval & ECC_STAT_UECNT_MASK) >> ECC_STAT_UECNT_SHIFT; + p->ceinfo.bitpos = (regval & ECC_STAT_BITNUM_MASK); + + regval = readl(base + ECC_CEADDR0_OFST); + if (!(p->ce_cnt)) + goto ue_err; + + p->ceinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_CEADDR1_OFST); + p->ceinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ceinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ceinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ceinfo.data = readl(base + ECC_CSYND0_OFST); + edac_dbg(2, "ECCCSYN0: 0x%08X ECCCSYN1: 0x%08X ECCCSYN2: 0x%08X\n", +readl(base + ECC_CSYND0_OFST), readl(base + ECC_CSYND1_OFST), +readl(base + ECC_CSYND2_OFST)); + + +ue_err: + regval = readl(base + ECC_UEADDR0_OFST); + if (!(p->ue_cnt)) + goto out; + + p->ueinfo.row = (regval & ECC_CEADDR0_RW_MASK); + regval = readl(base + ECC_UEADDR1_OFST); + p->ueinfo.bankgrpnr = (regval & ECC_CEADDR1_BNKGRP_MASK) >> + ECC_CEADDR1_BNKGRP_SHIFT; + p->ueinfo.bank = (regval & ECC_CEADDR1_BNKNR_MASK) >> + ECC_CEADDR1_BNKNR_SHIFT; + p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); + p->ueinfo.data = readl(base + ECC_UESYND0_OFST); +out: + clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; + clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + writel(clearval, base + ECC_CLR_OFST); + writel(0x0, base + ECC_CLR_OFST); + + return 0; +} + +/** * edac_handle_error - Handle controller error types CE and UE. * @mci: EDAC memory controller instance. * @p: Synopsys ECC status structure. @@ -399,9 +466,25 @@ static void edac_handle_error(struct mem_ctl_info *mci, if (p->ce_cnt) { pinf = &p->ceinfo; - snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, -"DDR ECC error type :%s Row %d Bank %d Col %d ", -"CE", pinf->row, pinf->bank, pinf->col); + if (!priv->p_data->quirks) { + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, +"DDR ECC error type:%s Row %d Bank %d Col %d ", + "CE", pinf->row, pinf->bank, pinf->col); + snprintf(priv->message, SYN
[PATCH v7 6/7] arm64: zynqmp: Add DDRC node
Add ddrc memory controller node in dts. The size mentioned in dts is 0x3, because we need to access DDR_QOS INTR registers located at 0xFD090208 from this driver. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 29ce234..a81d3b16 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -355,6 +355,13 @@ xlnx,bus-width = <64>; }; + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; + gem0: ethernet@ff0b { compatible = "cdns,zynqmp-gem", "cdns,gem"; status = "disabled"; -- 2.1.1
[PATCH v7 7/7] edac: synopsys: Add Error Injection support for ZynqMP DDRC
Add support for Error Injection for ZynqMP DDRC IP. For injecting errors, the Row, Column, Bank, Bank Group and Rank bits positions are determined via Address Map registers of Synopsys DDRC. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 423 ++- 1 file changed, 417 insertions(+), 6 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 7ab5b9a..177b5c3 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -302,12 +302,18 @@ struct synps_ecc_status { /** * struct synps_edac_priv - DDR memory controller private instance data. - * @baseaddr: Base address of the DDR controller. - * @message: Buffer for framing the event specific info. - * @stat: ECC status information. - * @p_data:Platform data - * @ce_cnt:Correctable Error count. - * @ue_cnt:Uncorrectable Error count. + * @baseaddr: Base address of the DDR controller. + * @message: Buffer for framing the event specific info. + * @stat: ECC status information. + * @p_data:Platform data + * @ce_cnt:Correctable Error count. + * @ue_cnt:Uncorrectable Error count. + * @poison_addr: Data poison address. + * @row_shift: Bit shifts for row bit. + * @col_shift: Bit shifts for column bit. + * @bank_shift:Bit shifts for bank bit. + * @bankgrp_shift: Bit shifts for bank group bit. + * @rank_shift:Bit shifts for rank bit. */ struct synps_edac_priv { void __iomem *baseaddr; @@ -316,6 +322,14 @@ struct synps_edac_priv { const struct synps_platform_data *p_data; u32 ce_cnt; u32 ue_cnt; +#ifdef CONFIG_EDAC_DEBUG + ulong poison_addr; + u32 row_shift[18]; + u32 col_shift[14]; + u32 bank_shift[3]; + u32 bankgrp_shift[2]; + u32 rank_shift[1]; +#endif }; /** @@ -842,7 +856,12 @@ static const struct synps_platform_data zynqmp_edac_def = { .get_mtype = zynqmp_get_mtype, .get_dtype = zynqmp_get_dtype, .get_eccstate = zynqmp_get_eccstate, +#ifdef CONFIG_EDAC_DEBUG + .quirks = (DDR_ECC_INTR_SUPPORT | + DDR_ECC_DATA_POISON_SUPPORT), +#else .quirks = DDR_ECC_INTR_SUPPORT, +#endif }; static const struct of_device_id synps_edac_match[] = { @@ -861,6 +880,380 @@ static const struct of_device_id synps_edac_match[] = { MODULE_DEVICE_TABLE(of, synps_edac_match); +#ifdef CONFIG_EDAC_DEBUG +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +/** + * ddr_poison_setup - Update poison registers. + * @priv: DDR memory controller private instance data. + * + * Update poison registers as per DDR mapping. + * Return: none. + */ +static void ddr_poison_setup(struct synps_edac_priv *priv) +{ + int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval; + int index; + ulong hif_addr = 0; + + hif_addr = priv->poison_addr >> 3; + + for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) { + if (priv->row_shift[index]) + row |= (((hif_addr >> priv->row_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_COL_SHIFT; index++) { + if (priv->col_shift[index] || index < 3) + col |= (((hif_addr >> priv->col_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANK_SHIFT; index++) { + if (priv->bank_shift[index]) + bank |= (((hif_addr >> priv->bank_shift[index]) & + BIT(0)) << index); + else + break; + } + + for (index = 0; index < DDR_MAX_BANKGRP_SHIFT; index++) { + if (priv->bankgrp_shift[index]) + bankgrp |= (((hif_addr >> priv->bankgrp_shift[index]) + & BIT(0)) << index); + else + break; + } + + if (priv->rank_shift[0]) + rank = (hif_addr >> priv->rank_shift[0]) & BIT(0); + + regval = (rank << ECC_POISON0_RANK_SHIFT) & ECC_POISON0_RANK_MASK; + regval |= (col << ECC_POISON0_COLUMN_SHIFT) & ECC_POISON0_COLUMN_MASK; + writel(regval, priv->baseaddr + ECC_POISON0_OFST); + + regval = (bankgrp << ECC_POISON1_BG_SHIFT) & ECC_POISON1_BG_MASK; + regval |= (bank << ECC_POISON1_BANKNR_SHIFT) & ECC_POISON1_BANKNR_MASK; +
[PATCH v7 3/7] dt: bindings: Document ZynqMP DDRC in Synopsys documentation
Add information of ZynqMP DDRC which reports the single bit errors that are corrected and the double bit errors that are detected. Signed-off-by: Manish Narani Reviewed-by: Rob Herring --- .../bindings/memory-controllers/synopsys.txt | 27 ++ 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt index a43d26d..9d32762 100644 --- a/Documentation/devicetree/bindings/memory-controllers/synopsys.txt +++ b/Documentation/devicetree/bindings/memory-controllers/synopsys.txt @@ -1,15 +1,32 @@ Binding for Synopsys IntelliDDR Multi Protocol Memory Controller -This controller has an optional ECC support in half-bus width (16-bit) -configuration. The ECC controller corrects one bit error and detects -two bit errors. +The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit +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 +ECC errors. Required properties: - - compatible: Should be 'xlnx,zynq-ddrc-a05' - - reg: Base address and size of the controllers memory area + - compatible: One of: + - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller + - 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller + - reg: Should contain DDR controller registers location and length. + +Required properties for "xlnx,zynqmp-ddrc-2.40a": + - interrupts: Property with a value describing the interrupt number. Example: memory-controller@f8006000 { compatible = "xlnx,zynq-ddrc-a05"; reg = <0xf8006000 0x1000>; }; + + mc: memory-controller@fd07 { + compatible = "xlnx,zynqmp-ddrc-2.40a"; + reg = <0x0 0xfd07 0x0 0x3>; + interrupt-parent = <&gic>; + interrupts = <0 112 4>; + }; -- 2.1.1
[PATCH v7 4/7] edac: synopsys: Add macro defines for ZynqMP DDRC
Add macro defines for ZynqMP DDR controller. These macros will be used for ZyqnMP ECC operations. Signed-off-by: Manish Narani --- drivers/edac/synopsys_edac.c | 168 +++ 1 file changed, 168 insertions(+) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index eb458e5..6bf7959 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -97,6 +97,174 @@ #define SCRUB_MODE_MASK0x7 #define SCRUB_MODE_SECDED 0x4 +/* DDR ECC Quirks */ +#define DDR_ECC_INTR_SUPPORT BIT(0) +#define DDR_ECC_DATA_POISON_SUPPORTBIT(1) + +/* ZynqMP Enhanced DDR memory controller registers that are relevant to ECC */ +/* ECC Configuration Registers */ +#define ECC_CFG0_OFST 0x70 +#define ECC_CFG1_OFST 0x74 + +/* ECC Status Register */ +#define ECC_STAT_OFST 0x78 + +/* ECC Clear Register */ +#define ECC_CLR_OFST 0x7C + +/* ECC Error count Register */ +#define ECC_ERRCNT_OFST0x80 + +/* ECC Corrected Error Address Register */ +#define ECC_CEADDR0_OFST 0x84 +#define ECC_CEADDR1_OFST 0x88 + +/* ECC Syndrome Registers */ +#define ECC_CSYND0_OFST0x8C +#define ECC_CSYND1_OFST0x90 +#define ECC_CSYND2_OFST0x94 + +/* ECC Bit Mask0 Address Register */ +#define ECC_BITMASK0_OFST 0x98 +#define ECC_BITMASK1_OFST 0x9C +#define ECC_BITMASK2_OFST 0xA0 + +/* ECC UnCorrected Error Address Register */ +#define ECC_UEADDR0_OFST 0xA4 +#define ECC_UEADDR1_OFST 0xA8 + +/* ECC Syndrome Registers */ +#define ECC_UESYND0_OFST 0xAC +#define ECC_UESYND1_OFST 0xB0 +#define ECC_UESYND2_OFST 0xB4 + +/* ECC Poison Address Reg */ +#define ECC_POISON0_OFST 0xB8 +#define ECC_POISON1_OFST 0xBC + +#define ECC_ADDRMAP0_OFFSET0x200 + +/* Control register bitfield definitions */ +#define ECC_CTRL_BUSWIDTH_MASK 0x3000 +#define ECC_CTRL_BUSWIDTH_SHIFT12 +#define ECC_CTRL_CLR_CE_ERRCNT BIT(2) +#define ECC_CTRL_CLR_UE_ERRCNT BIT(3) + +/* DDR Control Register width definitions */ +#define DDRCTL_EWDTH_162 +#define DDRCTL_EWDTH_321 +#define DDRCTL_EWDTH_640 + +/* ECC status register definitions */ +#define ECC_STAT_UECNT_MASK0xF +#define ECC_STAT_UECNT_SHIFT 16 +#define ECC_STAT_CECNT_MASK0xF00 +#define ECC_STAT_CECNT_SHIFT 8 +#define ECC_STAT_BITNUM_MASK 0x7F + +/* DDR QOS Interrupt register definitions */ +#define DDR_QOS_IRQ_STAT_OFST 0x20200 +#define DDR_QOSUE_MASK 0x4 +#defineDDR_QOSCE_MASK 0x2 +#defineECC_CE_UE_INTR_MASK 0x6 +#define DDR_QOS_IRQ_EN_OFST0x20208 +#define DDR_QOS_IRQ_DB_OFST0x2020C + +/* ECC Corrected Error Register Mask and Shifts*/ +#define ECC_CEADDR0_RW_MASK0x3 +#define ECC_CEADDR0_RNK_MASK BIT(24) +#define ECC_CEADDR1_BNKGRP_MASK0x300 +#define ECC_CEADDR1_BNKNR_MASK 0x7 +#define ECC_CEADDR1_BLKNR_MASK 0xFFF +#define ECC_CEADDR1_BNKGRP_SHIFT 24 +#define ECC_CEADDR1_BNKNR_SHIFT16 + +/* ECC Poison register shifts */ +#define ECC_POISON0_RANK_SHIFT 24 +#define ECC_POISON0_RANK_MASK BIT(24) +#define ECC_POISON0_COLUMN_SHIFT 0 +#define ECC_POISON0_COLUMN_MASK0xFFF +#define ECC_POISON1_BG_SHIFT 28 +#define ECC_POISON1_BG_MASK0x3000 +#define ECC_POISON1_BANKNR_SHIFT 24 +#define ECC_POISON1_BANKNR_MASK0x700 +#define ECC_POISON1_ROW_SHIFT 0 +#define ECC_POISON1_ROW_MASK 0x3 + +/* DDR Memory type defines */ +#define MEM_TYPE_DDR3 0x1 +#define MEM_TYPE_LPDDR30x8 +#define MEM_TYPE_DDR2 0x4 +#define MEM_TYPE_DDR4 0x10 +#define MEM_TYPE_LPDDR40x20 + +/* DDRC Software control register */ +#define DDRC_SWCTL 0x320 + +/* DDRC ECC CE & UE poison mask */ +#define ECC_CEPOISON_MASK 0x3 +#define ECC_UEPOISON_MASK 0x1 + +/* DDRC Device config masks */ +#define DDRC_MSTR_CFG_MASK 0xC000 +#define DDRC_MSTR_CFG_SHIFT30 +#define DDRC_MSTR_CFG_X4_MASK 0x0 +#define DDRC_MSTR_CFG_X8_MASK 0x1 +#define DDRC_MSTR_CFG_X16_MASK 0x2 +#define DDRC_MSTR_CFG_X32_MASK 0x3 + +#define DDR_MAX_ROW_SHIFT 18 +#define DDR_MAX_COL_SHIFT 14 +#define DDR_MAX_BANK_SHIFT 3 +#define DDR_MAX_BANKGRP_SHIFT 2 + +#define ROW_MAX_VAL_
[RFC PATCH 0/4] Add auto tuning support for ZynqMP SDHCI controller
This series of patches are created On top of the below series of patches. https://lkml.org/lkml/2018/8/3/687 Manish Narani (4): firmware: xilinx: Add SD Node and DLL Reset Data APIs dt-bindings: mmc: arasan: Document 'xlnx,zynqmp-8.9a' controller mmc: sdhci-of-arasan: Add auto tuning support for ZynqMP platform arm64: zynqmp: Add new SDHCI compatible string .../devicetree/bindings/mmc/arasan,sdhci.txt | 14 arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 6 +- drivers/mmc/host/sdhci-of-arasan.c | 83 ++ include/linux/firmware/xlnx-zynqmp.h | 12 4 files changed, 113 insertions(+), 2 deletions(-) -- 2.1.1
[RFC PATCH 3/4] mmc: sdhci-of-arasan: Add auto tuning support for ZynqMP platform
Add support of SD auto tuning for ZynqMP platform. Before tuning execution, reset the DLL and after the auto tuning process gets completed, reset the DLL to load the newly obtained SDHC tuned tap value. Signed-off-by: Manish Narani --- drivers/mmc/host/sdhci-of-arasan.c | 83 ++ 1 file changed, 83 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index a40bcc2..1a8bbd2 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "cqhci.h" #include "sdhci-pltfm.h" @@ -98,6 +99,7 @@ struct sdhci_arasan_data { struct regmap *soc_ctl_base; const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; + unsigned intdevice_id; unsigned intquirks; /* Arasan deviations from spec */ /* Controller does not have CD wired and will not function normally without */ @@ -163,6 +165,72 @@ static int sdhci_arasan_syscon_write(struct sdhci_host *host, return ret; } +static void zynqmp_dll_reset(u8 deviceid) +{ + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); + + if (!eemi_ops || !eemi_ops->ioctl) + return; + + /* Issue DLL Reset */ + if (deviceid == 0) + eemi_ops->ioctl(NODE_SD_0, IOCTL_SD_DLL_RESET, + PM_DLL_RESET_PULSE, 0, NULL); + else + eemi_ops->ioctl(NODE_SD_1, IOCTL_SD_DLL_RESET, + PM_DLL_RESET_PULSE, 0, NULL); +} + +static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) +{ + u16 clk; + unsigned long timeout; + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + /* Issue DLL Reset */ + zynqmp_dll_reset(deviceid); + + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + /* Wait max 20 ms */ + timeout = 20; + while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + dev_err(mmc_dev(host->mmc), + ": Internal clock never stabilised.\n"); + return; + } + timeout--; + mdelay(1); + } + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); +} + +static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode) { + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + int err; + + arasan_zynqmp_dll_reset(host, sdhci_arasan->device_id); + + err = sdhci_execute_tuning(mmc, opcode); + if (err) + return err; + + arasan_zynqmp_dll_reset(host, sdhci_arasan->device_id); + + return 0; +} + static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -469,6 +537,7 @@ static const struct of_device_id sdhci_arasan_of_match[] = { { .compatible = "arasan,sdhci-8.9a" }, { .compatible = "arasan,sdhci-5.1" }, { .compatible = "arasan,sdhci-4.9a" }, + { .compatible = "xlnx,zynqmp-8.9a" }, { /* sentinel */ } }; @@ -792,6 +861,20 @@ static int sdhci_arasan_probe(struct platform_device *pdev) goto unreg_clk; } + if (of_device_is_compatible(pdev->dev.of_node, "xlnx,zynqmp-8.9a")) { + ret = of_property_read_u32(pdev->dev.of_node, + "xlnx,device_id", + &sdhci_arasan->device_id); + if (ret < 0) { + dev_err(&pdev->dev, + "\"xlnx,device_id \" property is missing.\n"); + goto unreg_clk; + } + + host->mmc_host_ops.execute_tuning = + arasan_zynqmp_execute_tuning; + } + sdhci_arasan->phy = ERR_PTR(-ENODEV); if (of_device_is_compatible(pdev->dev.of_node, "arasan,sdhci-5.1")) { -- 2.1.1
[RFC PATCH 1/4] firmware: xilinx: Add SD Node and DLL Reset Data APIs
Add ZynqMP firmware SD Node data API to be used in call from SDHCI driver. Also add DLL Reset data API to used for DLL reset calls from any drivers. Signed-off-by: Manish Narani --- include/linux/firmware/xlnx-zynqmp.h | 12 1 file changed, 12 insertions(+) diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 58a7478..743687b 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -58,13 +58,25 @@ enum pm_ret_status { XST_PM_ABORT_SUSPEND, }; +enum pm_node_id { + NODE_SD_0 = 39, + NODE_SD_1, +}; + enum pm_ioctl_id { + IOCTL_SD_DLL_RESET = 6, IOCTL_SET_PLL_FRAC_MODE = 8, IOCTL_GET_PLL_FRAC_MODE, IOCTL_SET_PLL_FRAC_DATA, IOCTL_GET_PLL_FRAC_DATA, }; +enum dll_reset_type { + PM_DLL_RESET_ASSERT, + PM_DLL_RESET_RELEASE, + PM_DLL_RESET_PULSE, +}; + enum pm_query_id { PM_QID_INVALID, PM_QID_CLOCK_GET_NAME, -- 2.1.1
[RFC PATCH 4/4] arm64: zynqmp: Add new SDHCI compatible string
Mainline kernel has arasan compatible string now. Append this new compatible string for ZynqMP SDHCI controller. Also add a required property indicating ZynqMP SDHCI controller device ID. Signed-off-by: Manish Narani --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 29ce234..1def7e1 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -485,21 +485,23 @@ }; sdhci0: sdhci@ff16 { - compatible = "arasan,sdhci-8.9a"; + compatible = "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a"; status = "disabled"; interrupt-parent = <&gic>; interrupts = <0 48 4>; reg = <0x0 0xff16 0x0 0x1000>; clock-names = "clk_xin", "clk_ahb"; + xlnx,device_id = <0>; }; sdhci1: sdhci@ff17 { - compatible = "arasan,sdhci-8.9a"; + compatible = "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a"; status = "disabled"; interrupt-parent = <&gic>; interrupts = <0 49 4>; reg = <0x0 0xff17 0x0 0x1000>; clock-names = "clk_xin", "clk_ahb"; + xlnx,device_id = <1>; }; smmu: smmu@fd80 { -- 2.1.1
[RFC PATCH 2/4] dt-bindings: mmc: arasan: Document 'xlnx,zynqmp-8.9a' controller
Add documentation for 'xlnx,zynqmp-8.9a' SDHCI controller and required properties followed by example. Signed-off-by: Manish Narani --- Documentation/devicetree/bindings/mmc/arasan,sdhci.txt | 14 ++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt index f6ddba3..72769e0 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -15,6 +15,7 @@ Required Properties: - "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY - "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY For this device it is strongly suggested to include arasan,soc-ctl-syscon. +- "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a": Xilinx ZynqMP Arasan SDHCI 8.9a PHY - reg: From mmc bindings: Register location and length. - clocks: From clock bindings: Handles to clock inputs. - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb" @@ -24,6 +25,9 @@ Required Properties for "arasan,sdhci-5.1": - phys: From PHY bindings: Phandle for the Generic PHY for arasan. - phy-names: MUST be "phy_arasan". +Required Properties for "xlnx,zynqmp-8.9a": + - xlnx,device_id: SD controller device ID. Must be either <0> or <1>. + Optional Properties: - arasan,soc-ctl-syscon: A phandle to a syscon device (see ../mfd/syscon.txt) used to access core corecfg registers. Offsets of registers in this @@ -75,3 +79,13 @@ Example: phy-names = "phy_arasan"; #clock-cells = <0>; }; + + sdhci: sdhci@ff16 { + compatible = "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a"; + reg = <0x0 0xff16 0x0 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 48 4>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clk 54>, <&clk 31>; + xlnx,device_id = <0>; + }; -- 2.1.1
[PATCH] sdhci: arasan: Add runtime PM support
Add runtime PM support in Arasan SDHCI driver. Signed-off-by: Manish Narani --- drivers/mmc/host/sdhci-of-arasan.c | 80 +- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index a40bcc2..370ada5 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include "cqhci.h" #include "sdhci-pltfm.h" +#define SDHCI_ARASAN_AUTOSUSPEND_DELAY 2000 /* ms */ #define SDHCI_ARASAN_VENDOR_REGISTER 0x78 #define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 #define VENDOR_ENHANCED_STROBE BIT(0) @@ -363,6 +365,70 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; +#ifdef CONFIG_PM +static int sdhci_arasan_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + int ret; + + if (sdhci_arasan->has_cqe) { + ret = cqhci_suspend(host->mmc); + if (ret) + return ret; + } + + ret = sdhci_runtime_suspend_host(host); + if (ret) + return ret; + + if (host->tuning_mode != SDHCI_TUNING_MODE_3) + mmc_retune_needed(host->mmc); + + clk_disable(pltfm_host->clk); + clk_disable(sdhci_arasan->clk_ahb); + + return 0; +} + +static int sdhci_arasan_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + int ret; + + ret = clk_enable(sdhci_arasan->clk_ahb); + if (ret) { + dev_err(dev, "Cannot enable AHB clock.\n"); + return ret; + } + + ret = clk_enable(pltfm_host->clk); + if (ret) { + dev_err(dev, "Cannot enable SD clock.\n"); + return ret; + } + + ret = sdhci_runtime_resume_host(host); + if (ret) + goto out; + + if (sdhci_arasan->has_cqe) + return cqhci_resume(host->mmc); + + return 0; +out: + clk_disable(pltfm_host->clk); + clk_disable(sdhci_arasan->clk_ahb); + + return ret; +} +#endif /* ! CONFIG_PM */ + #ifdef CONFIG_PM_SLEEP /** * sdhci_arasan_suspend - Suspend method for the driver @@ -455,8 +521,10 @@ static int sdhci_arasan_resume(struct device *dev) } #endif /* ! CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, -sdhci_arasan_resume); +static const struct dev_pm_ops sdhci_arasan_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sdhci_arasan_suspend, sdhci_arasan_resume) + SET_RUNTIME_PM_OPS(sdhci_arasan_runtime_suspend, + sdhci_arasan_runtime_resume, NULL) }; static const struct of_device_id sdhci_arasan_of_match[] = { /* SoC-specific compatible strings w/ soc_ctl_map */ @@ -821,6 +889,14 @@ static int sdhci_arasan_probe(struct platform_device *pdev) if (ret) goto err_add_host; + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, +SDHCI_ARASAN_AUTOSUSPEND_DELAY); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_forbid(&pdev->dev); + return 0; err_add_host: -- 2.1.1
[PATCH 4/4] iio: adc: xilinx: Use devm_ functions while requesting irq
This patch adds support for using devm_ functions for requesting irq. This will let the core free irq itself whenever the error condition happens in probe or when xadc_remove is called. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 18 +++--- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 47eb364..7cadcc77 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1229,8 +1229,8 @@ static int xadc_probe(struct platform_device *pdev) if (ret) goto err_clk_disable_unprepare; - ret = request_irq(irq, xadc->ops->interrupt_handler, 0, - dev_name(&pdev->dev), indio_dev); + ret = devm_request_irq(&pdev->dev, irq, xadc->ops->interrupt_handler, 0, + dev_name(&pdev->dev), indio_dev); if (ret) goto err_clk_disable_unprepare; @@ -1240,7 +1240,7 @@ static int xadc_probe(struct platform_device *pdev) ret = xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0); if (ret) - goto err_free_irq; + goto err_clk_disable_unprepare; bipolar_mask = 0; for (i = 0; i < indio_dev->num_channels; i++) { @@ -1250,17 +1250,17 @@ static int xadc_probe(struct platform_device *pdev) ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask); if (ret) - goto err_free_irq; + goto err_clk_disable_unprepare; ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1), bipolar_mask >> 16); if (ret) - goto err_free_irq; + goto err_clk_disable_unprepare; /* Disable all alarms */ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, XADC_CONF1_ALARM_MASK); if (ret) - goto err_free_irq; + goto err_clk_disable_unprepare; /* Set thresholds to min/max */ for (i = 0; i < 16; i++) { @@ -1281,14 +1281,12 @@ static int xadc_probe(struct platform_device *pdev) ret = iio_device_register(indio_dev); if (ret) - goto err_free_irq; + goto err_clk_disable_unprepare; platform_set_drvdata(pdev, indio_dev); return 0; -err_free_irq: - free_irq(irq, indio_dev); err_clk_disable_unprepare: clk_disable_unprepare(xadc->clk); err_free_samplerate_trigger: @@ -1310,7 +1308,6 @@ static int xadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct xadc *xadc = iio_priv(indio_dev); - int irq = platform_get_irq(pdev, 0); iio_device_unregister(indio_dev); if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { @@ -1318,7 +1315,6 @@ static int xadc_remove(struct platform_device *pdev) iio_trigger_free(xadc->convst_trigger); iio_triggered_buffer_cleanup(indio_dev); } - free_irq(irq, indio_dev); clk_disable_unprepare(xadc->clk); cancel_delayed_work(&xadc->zynq_unmask_work); kfree(xadc->data); -- 2.1.1
[PATCH 2/4] iio: adc: xilinx: Remove dead code from xadc_zynq_setup
This patch removes dead code from xadc_zynq_setup. The condition "if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX)" cannot be true at any point of time. There is also an incompatible parameter used in the code. This patch fixes the same reported by coverity. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 27b45df..248cffa 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -341,8 +341,6 @@ static int xadc_zynq_setup(struct platform_device *pdev, pcap_rate = clk_get_rate(xadc->clk); - if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX) - tck_rate = XADC_ZYNQ_TCK_RATE_MAX; if (tck_rate > pcap_rate / 2) { div = 2; } else { @@ -1045,7 +1043,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, unsigned int num_channels; const char *external_mux; u32 ext_mux_chan; - int reg; + u32 reg; int ret; *conf = 0; -- 2.1.1
[PATCH 3/4] iio: adc: xilinx: Check for return values in clk related functions
This patch adds check for return values from clock related functions. This was reported by static code analysis tool. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 24 ++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 248cffa..47eb364 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -322,6 +322,7 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) #define XADC_ZYNQ_TCK_RATE_MAX 5000 #define XADC_ZYNQ_IGAP_DEFAULT 20 +#define XADC_ZYNQ_PCAP_RATE_MAX 2 static int xadc_zynq_setup(struct platform_device *pdev, struct iio_dev *indio_dev, int irq) @@ -332,6 +333,7 @@ static int xadc_zynq_setup(struct platform_device *pdev, unsigned int div; unsigned int igap; unsigned int tck_rate; + int ret; /* TODO: Figure out how to make igap and tck_rate configurable */ igap = XADC_ZYNQ_IGAP_DEFAULT; @@ -341,6 +343,13 @@ static int xadc_zynq_setup(struct platform_device *pdev, pcap_rate = clk_get_rate(xadc->clk); + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, + (unsigned long)XADC_ZYNQ_PCAP_RATE_MAX); + if (ret) + return ret; + } + if (tck_rate > pcap_rate / 2) { div = 2; } else { @@ -366,6 +375,12 @@ static int xadc_zynq_setup(struct platform_device *pdev, XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | tck_div | XADC_ZYNQ_CFG_IGAP(igap)); + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret = clk_set_rate(xadc->clk, pcap_rate); + if (ret) + return ret; + } + return 0; } @@ -887,6 +902,9 @@ static int xadc_write_raw(struct iio_dev *indio_dev, unsigned long clk_rate = xadc_get_dclk_rate(xadc); unsigned int div; + if (!clk_rate) + return -EINVAL; + if (info != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL; @@ -1239,8 +1257,10 @@ static int xadc_probe(struct platform_device *pdev) goto err_free_irq; /* Disable all alarms */ - xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, - XADC_CONF1_ALARM_MASK); + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, + XADC_CONF1_ALARM_MASK); + if (ret) + goto err_free_irq; /* Set thresholds to min/max */ for (i = 0; i < 16; i++) { -- 2.1.1
[PATCH 0/4] iio: adc: xilinx: XADC driver enhancements and bug fixes
This patch series resolves code style problems as reported by code analysis tools. Manish Narani (4): iio: adc: xilinx: Rename 'channels' variable name to 'iio_xadc_channels' iio: adc: xilinx: Remove dead code from xadc_zynq_setup iio: adc: xilinx: Check for return values in clk related functions iio: adc: xilinx: Use devm_ functions while requesting irq drivers/iio/adc/xilinx-xadc-core.c | 60 -- 1 file changed, 38 insertions(+), 22 deletions(-) -- 2.1.1
[PATCH 1/4] iio: adc: xilinx: Rename 'channels' variable name to 'iio_xadc_channels'
This patch fix the following checkpatch warning in xadc driver. - Reusing the krealloc arg is almost always a bug. Renamed the 'channels' variable as 'iio_xadc_channels' to fix the above warning. Signed-off-by: Manish Narani --- drivers/iio/adc/xilinx-xadc-core.c | 16 +--- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index d4f21d1..27b45df 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1040,7 +1040,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, unsigned int *conf) { struct xadc *xadc = iio_priv(indio_dev); - struct iio_chan_spec *channels, *chan; + struct iio_chan_spec *iio_xadc_channels, *chan; struct device_node *chan_node, *child; unsigned int num_channels; const char *external_mux; @@ -1083,12 +1083,13 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, *conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan); } - channels = kmemdup(xadc_channels, sizeof(xadc_channels), GFP_KERNEL); - if (!channels) + iio_xadc_channels = kmemdup(xadc_channels, sizeof(xadc_channels), + GFP_KERNEL); + if (!iio_xadc_channels) return -ENOMEM; num_channels = 9; - chan = &channels[9]; + chan = &iio_xadc_channels[9]; chan_node = of_get_child_by_name(np, "xlnx,channels"); if (chan_node) { @@ -1119,11 +1120,12 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, of_node_put(chan_node); indio_dev->num_channels = num_channels; - indio_dev->channels = krealloc(channels, sizeof(*channels) * - num_channels, GFP_KERNEL); + indio_dev->channels = krealloc(iio_xadc_channels, + sizeof(*iio_xadc_channels) * + num_channels, GFP_KERNEL); /* If we can't resize the channels array, just use the original */ if (!indio_dev->channels) - indio_dev->channels = channels; + indio_dev->channels = iio_xadc_channels; return 0; } -- 2.1.1
RE: [PATCH 1/4] iio: adc: xilinx: Rename 'channels' variable name to 'iio_xadc_channels'
Hi Lars, > -Original Message- > From: Lars-Peter Clausen [mailto:l...@metafoo.de] > Sent: Wednesday, July 18, 2018 4:49 PM > To: Manish Narani ; ji...@kernel.org; > knaac...@gmx.de; pme...@pmeerw.net; Michal Simek > ; linux-...@vger.kernel.org; linux-arm- > ker...@lists.infradead.org; linux-kernel@vger.kernel.org > Cc: Anirudha Sarangi ; Srinivas Goud > ; Joe Perches > Subject: Re: [PATCH 1/4] iio: adc: xilinx: Rename 'channels' variable name to > 'iio_xadc_channels' > > On 07/18/2018 01:12 PM, Manish Narani wrote: > > This patch fix the following checkpatch warning in xadc driver. > > - Reusing the krealloc arg is almost always a bug. > > > > Renamed the 'channels' variable as 'iio_xadc_channels' to fix the > > above warning. > > > > This is a bug in checkpatch and should be fixed in checkpatch. The code is not > actually re-using the parameter. channels and xadc_channels are independent > variables, just checkpatch somehow does not realize this. I agree with you on this. Initially I presumed the checkpatch to be giving genuine warning but now I am sure that this is certainly the checkpatch script issue. In that case should we keep this code change? Please suggest. Thanks, Manish > > > Signed-off-by: Manish Narani > > --- > > drivers/iio/adc/xilinx-xadc-core.c | 16 +--- > > 1 file changed, 9 insertions(+), 7 deletions(-) > > > > diff --git a/drivers/iio/adc/xilinx-xadc-core.c > > b/drivers/iio/adc/xilinx-xadc-core.c > > index d4f21d1..27b45df 100644 > > --- a/drivers/iio/adc/xilinx-xadc-core.c > > +++ b/drivers/iio/adc/xilinx-xadc-core.c > > @@ -1040,7 +1040,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, > struct device_node *np, > > unsigned int *conf) > > { > > struct xadc *xadc = iio_priv(indio_dev); > > - struct iio_chan_spec *channels, *chan; > > + struct iio_chan_spec *iio_xadc_channels, *chan; > > struct device_node *chan_node, *child; > > unsigned int num_channels; > > const char *external_mux; > > @@ -1083,12 +1083,13 @@ static int xadc_parse_dt(struct iio_dev > *indio_dev, struct device_node *np, > > *conf |= XADC_CONF0_MUX | > XADC_CONF0_CHAN(ext_mux_chan); > > } > > > > - channels = kmemdup(xadc_channels, sizeof(xadc_channels), > GFP_KERNEL); > > - if (!channels) > > + iio_xadc_channels = kmemdup(xadc_channels, sizeof(xadc_channels), > > + GFP_KERNEL); > > + if (!iio_xadc_channels) > > return -ENOMEM; > > > > num_channels = 9; > > - chan = &channels[9]; > > + chan = &iio_xadc_channels[9]; > > > > chan_node = of_get_child_by_name(np, "xlnx,channels"); > > if (chan_node) { > > @@ -1119,11 +1120,12 @@ static int xadc_parse_dt(struct iio_dev > *indio_dev, struct device_node *np, > > of_node_put(chan_node); > > > > indio_dev->num_channels = num_channels; > > - indio_dev->channels = krealloc(channels, sizeof(*channels) * > > - num_channels, GFP_KERNEL); > > + indio_dev->channels = krealloc(iio_xadc_channels, > > + sizeof(*iio_xadc_channels) * > > + num_channels, GFP_KERNEL); > > /* If we can't resize the channels array, just use the original */ > > if (!indio_dev->channels) > > - indio_dev->channels = channels; > > + indio_dev->channels = iio_xadc_channels; > > > > return 0; > > } > >
[PATCH] checkpatch: Resolve improper warning for krealloc arg reuse
Correct the check for reuse of krealloc. It gives false warning when a structure member variable name and krealloc argument name is same. For Example: { ... abc.def_var = krealloc(def_var, sizeof(*def_var), GFP_KERNEL); ... } $ ./scripts/checkpatch.pl -f file.c WARNING: Reusing the krealloc arg is almost always a bug + abc.def_var = krealloc(def_var, sizeof(*def_var), This patch resolves the above false warning. Signed-off-by: Manish Narani --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 447857f..db9b666 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -6119,7 +6119,7 @@ sub process { # check for krealloc arg reuse if ($^V && $^V ge 5.10.0 && - $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) { + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/ && $line !~ m/[\.|\-\>].*\s*\=\s*.*/) { WARN("KREALLOC_ARG_REUSE", "Reusing the krealloc arg is almost always a bug\n" . $herecurr); } -- 2.1.1