Skip to content

Commit

Permalink
EDAC, synopsys: Add platform specific structures for the DDR Controller
Browse files Browse the repository at this point in the history
Add platform specific structures so that different IP support can be
added later using quirks.

 [ bp: fix function names. ]

Signed-off-by: Manish Narani <manish.narani@xilinx.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
CC: Mauro Carvalho Chehab <mchehab@kernel.org>
CC: Michal Simek <michal.simek@xilinx.com>
CC: amit.kucheria@linaro.org
CC: devicetree@vger.kernel.org
CC: leoyang.li@nxp.com
CC: linux-arm-kernel@lists.infradead.org
CC: linux-edac <linux-edac@vger.kernel.org>
CC: mark.rutland@arm.com
CC: robh+dt@kernel.org
CC: sudeep.holla@arm.com
Link: http://lkml.kernel.org/r/1538667328-9465-6-git-send-email-manish.narani@xilinx.com
  • Loading branch information
Manish Narani authored and Borislav Petkov committed Nov 5, 2018
1 parent fa9f6b9 commit 3d02a89
Showing 1 changed file with 63 additions and 23 deletions.
86 changes: 63 additions & 23 deletions drivers/edac/synopsys_edac.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <linux/edac.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>

#include "edac_module.h"

Expand Down Expand Up @@ -130,27 +132,49 @@ 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.
*/
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;
};

/**
* get_error_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.
* @get_error_info: Get EDAC error info.
* @get_mtype: Get mtype.
* @get_dtype: Get dtype.
* @get_ecc_state: Get ECC state.
* @quirks: To differentiate IPs.
*/
struct synps_platform_data {
int (*get_error_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_ecc_state)(void __iomem *base);
int quirks;
};

/**
* zynq_get_error_info - Get the current ECC error info.
* @priv: DDR memory controller private instance data.
*
* Return: one if there is no error otherwise zero.
* Return: one if there is no error, otherwise zero.
*/
static int get_error_info(void __iomem *base, struct synps_ecc_status *p)
static int zynq_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 + STAT_OFST);
if (!regval)
Expand Down Expand Up @@ -236,9 +260,10 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
static void check_errors(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 = get_error_info(priv->baseaddr, &priv->stat);
status = p_data->get_error_info(priv);
if (status)
return;

Expand All @@ -251,15 +276,15 @@ static void check_errors(struct mem_ctl_info *mci)
}

/**
* 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
* configuration.
*
* Return: a device type width enumeration.
*/
static enum dev_type get_dtype(const void __iomem *base)
static enum dev_type zynq_get_dtype(const void __iomem *base)
{
enum dev_type dt;
u32 width;
Expand All @@ -282,20 +307,20 @@ static enum dev_type get_dtype(const void __iomem *base)
}

/**
* get_ecc_state - Return the controller ECC enable/disable status.
* zynq_get_ecc_state - Return the controller ECC enable/disable status.
* @base: DDR memory controller base address.
*
* Get the ECC enable/disable status of the controller.
*
* Return: true if enabled, otherwise false.
*/
static bool get_ecc_state(void __iomem *base)
static bool zynq_get_ecc_state(void __iomem *base)
{
bool state = false;
enum dev_type dt;
u32 ecctype;

dt = get_dtype(base);
dt = zynq_get_dtype(base);
if (dt == DEV_UNKNOWN)
return state;

Expand All @@ -321,15 +346,15 @@ static u32 get_memsize(void)
}

/**
* get_mtype - Return the controller memory type.
* zynq_get_mtype - Return the controller memory type.
* @base: Synopsys ECC status structure.
*
* Get the EDAC memory type appropriate for the current controller
* configuration.
*
* Return: a memory type enumeration.
*/
static enum mem_type get_mtype(const void __iomem *base)
static enum mem_type zynq_get_mtype(const void __iomem *base)
{
enum mem_type mt;
u32 memtype;
Expand All @@ -354,22 +379,25 @@ static enum mem_type get_mtype(const void __iomem *base)
static void init_csrows(struct mem_ctl_info *mci)
{
struct synps_edac_priv *priv = mci->pvt_info;
const struct synps_platform_data *p_data;
struct csrow_info *csi;
struct dimm_info *dimm;
u32 size, row;
int j;

p_data = priv->p_data;

for (row = 0; row < mci->nr_csrows; row++) {
csi = mci->csrows[row];
size = get_memsize();

for (j = 0; j < csi->nr_channels; j++) {
dimm = csi->channels[j]->dimm;
dimm->edac_mode = EDAC_FLAG_SECDED;
dimm->mtype = get_mtype(priv->baseaddr);
dimm->mtype = p_data->get_mtype(priv->baseaddr);
dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels;
dimm->grain = SYNPS_EDAC_ERR_GRAIN;
dimm->dtype = get_dtype(priv->baseaddr);
dimm->dtype = p_data->get_dtype(priv->baseaddr);
}
}
}
Expand Down Expand Up @@ -409,6 +437,21 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
init_csrows(mci);
}

static const struct synps_platform_data zynq_edac_def = {
.get_error_info = zynq_get_error_info,
.get_mtype = zynq_get_mtype,
.get_dtype = zynq_get_dtype,
.get_ecc_state = zynq_get_ecc_state,
.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);

/**
* mc_probe - Check controller and bind driver.
* @pdev: platform device.
Expand All @@ -420,6 +463,7 @@ static void mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
*/
static int mc_probe(struct platform_device *pdev)
{
const struct synps_platform_data *p_data;
struct edac_mc_layer layers[2];
struct synps_edac_priv *priv;
struct mem_ctl_info *mci;
Expand All @@ -432,7 +476,8 @@ static int mc_probe(struct platform_device *pdev)
if (IS_ERR(baseaddr))
return PTR_ERR(baseaddr);

if (!get_ecc_state(baseaddr)) {
p_data = of_device_get_match_data(&pdev->dev);
if (!p_data->get_ecc_state(baseaddr)) {
edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
return -ENXIO;
}
Expand All @@ -454,6 +499,8 @@ static int mc_probe(struct platform_device *pdev)

priv = mci->pvt_info;
priv->baseaddr = baseaddr;
priv->p_data = p_data;

mc_init(mci, pdev);

rc = edac_mc_add_mc(mci);
Expand Down Expand Up @@ -492,13 +539,6 @@ static int mc_remove(struct platform_device *pdev)
return 0;
}

static const struct of_device_id synps_edac_match[] = {
{ .compatible = "xlnx,zynq-ddrc-a05", },
{ /* end of table */ }
};

MODULE_DEVICE_TABLE(of, synps_edac_match);

static struct platform_driver synps_edac_mc_driver = {
.driver = {
.name = "synopsys-edac",
Expand Down

0 comments on commit 3d02a89

Please sign in to comment.