lkml.org 
[lkml]   [2021]   [May]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V7 XRT Alveo 18/20] fpga: xrt: DDR calibration driver
    Date
    Add DDR calibration driver. DDR calibration is a hardware function
    discovered by walking firmware metadata. A xrt device node will
    be created for it. Hardware provides DDR calibration status through
    this function.

    Signed-off-by: Sonal Santan <sonal.santan@xilinx.com>
    Signed-off-by: Max Zhen <max.zhen@xilinx.com>
    Signed-off-by: Lizhi Hou <lizhi.hou@xilinx.com>
    Reviewed-by: Tom Rix <trix@redhat.com>
    ---
    .../fpga/xrt/include/xleaf/ddr_calibration.h | 28 +++
    drivers/fpga/xrt/lib/xleaf/ddr_calibration.c | 210 ++++++++++++++++++
    2 files changed, 238 insertions(+)
    create mode 100644 drivers/fpga/xrt/include/xleaf/ddr_calibration.h
    create mode 100644 drivers/fpga/xrt/lib/xleaf/ddr_calibration.c

    diff --git a/drivers/fpga/xrt/include/xleaf/ddr_calibration.h b/drivers/fpga/xrt/include/xleaf/ddr_calibration.h
    new file mode 100644
    index 000000000000..878740c26ca2
    --- /dev/null
    +++ b/drivers/fpga/xrt/include/xleaf/ddr_calibration.h
    @@ -0,0 +1,28 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2020-2021 Xilinx, Inc.
    + *
    + * Authors:
    + * Cheng Zhen <maxz@xilinx.com>
    + */
    +
    +#ifndef _XRT_DDR_CALIBRATION_H_
    +#define _XRT_DDR_CALIBRATION_H_
    +
    +#include "xleaf.h"
    +#include <linux/xrt/xclbin.h>
    +
    +/*
    + * Memory calibration driver leaf calls.
    + */
    +enum xrt_calib_results {
    + XRT_CALIB_UNKNOWN = 0,
    + XRT_CALIB_SUCCEEDED,
    + XRT_CALIB_FAILED,
    +};
    +
    +enum xrt_calib_leaf_cmd {
    + XRT_CALIB_RESULT = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */
    +};
    +
    +#endif /* _XRT_DDR_CALIBRATION_H_ */
    diff --git a/drivers/fpga/xrt/lib/xleaf/ddr_calibration.c b/drivers/fpga/xrt/lib/xleaf/ddr_calibration.c
    new file mode 100644
    index 000000000000..36a0937c9195
    --- /dev/null
    +++ b/drivers/fpga/xrt/lib/xleaf/ddr_calibration.c
    @@ -0,0 +1,210 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Xilinx Alveo FPGA memory calibration driver
    + *
    + * Copyright (C) 2020-2021 Xilinx, Inc.
    + *
    + * memory calibration
    + *
    + * Authors:
    + * Lizhi Hou<Lizhi.Hou@xilinx.com>
    + */
    +#include <linux/delay.h>
    +#include <linux/regmap.h>
    +#include "xclbin-helper.h"
    +#include "metadata.h"
    +#include "xleaf/ddr_calibration.h"
    +
    +#define XRT_CALIB "xrt_calib"
    +
    +#define XRT_CALIB_STATUS_REG 0
    +#define XRT_CALIB_READ_RETRIES 20
    +#define XRT_CALIB_READ_INTERVAL 500 /* ms */
    +
    +XRT_DEFINE_REGMAP_CONFIG(calib_regmap_config);
    +
    +struct calib_cache {
    + struct list_head link;
    + const char *ep_name;
    + char *data;
    + u32 data_size;
    +};
    +
    +struct calib {
    + struct xrt_device *xdev;
    + struct regmap *regmap;
    + struct mutex lock; /* calibration dev lock */
    + struct list_head cache_list;
    + u32 cache_num;
    + enum xrt_calib_results result;
    +};
    +
    +static void __calib_cache_clean_nolock(struct calib *calib)
    +{
    + struct calib_cache *cache, *temp;
    +
    + list_for_each_entry_safe(cache, temp, &calib->cache_list, link) {
    + vfree(cache->data);
    + list_del(&cache->link);
    + vfree(cache);
    + }
    + calib->cache_num = 0;
    +}
    +
    +static void calib_cache_clean(struct calib *calib)
    +{
    + mutex_lock(&calib->lock);
    + __calib_cache_clean_nolock(calib);
    + mutex_unlock(&calib->lock);
    +}
    +
    +static int calib_calibration(struct calib *calib)
    +{
    + u32 times = XRT_CALIB_READ_RETRIES;
    + u32 status;
    + int ret;
    +
    + while (times != 0) {
    + ret = regmap_read(calib->regmap, XRT_CALIB_STATUS_REG, &status);
    + if (ret) {
    + xrt_err(calib->xdev, "failed to read status reg %d", ret);
    + return ret;
    + }
    +
    + if (status & BIT(0))
    + break;
    + msleep(XRT_CALIB_READ_INTERVAL);
    + times--;
    + }
    +
    + if (!times) {
    + xrt_err(calib->xdev,
    + "MIG calibration timeout after bitstream download");
    + return -ETIMEDOUT;
    + }
    +
    + xrt_info(calib->xdev, "took %dms", (XRT_CALIB_READ_RETRIES - times) *
    + XRT_CALIB_READ_INTERVAL);
    + return 0;
    +}
    +
    +static void xrt_calib_event_cb(struct xrt_device *xdev, void *arg)
    +{
    + struct calib *calib = xrt_get_drvdata(xdev);
    + struct xrt_event *evt = (struct xrt_event *)arg;
    + enum xrt_events e = evt->xe_evt;
    + enum xrt_subdev_id id;
    + int ret;
    +
    + id = evt->xe_subdev.xevt_subdev_id;
    +
    + switch (e) {
    + case XRT_EVENT_POST_CREATION:
    + if (id == XRT_SUBDEV_UCS) {
    + ret = calib_calibration(calib);
    + if (ret)
    + calib->result = XRT_CALIB_FAILED;
    + else
    + calib->result = XRT_CALIB_SUCCEEDED;
    + }
    + break;
    + default:
    + xrt_dbg(xdev, "ignored event %d", e);
    + break;
    + }
    +}
    +
    +static void xrt_calib_remove(struct xrt_device *xdev)
    +{
    + struct calib *calib = xrt_get_drvdata(xdev);
    +
    + calib_cache_clean(calib);
    +}
    +
    +static int xrt_calib_probe(struct xrt_device *xdev)
    +{
    + void __iomem *base = NULL;
    + struct resource *res;
    + struct calib *calib;
    + int err = 0;
    +
    + calib = devm_kzalloc(&xdev->dev, sizeof(*calib), GFP_KERNEL);
    + if (!calib)
    + return -ENOMEM;
    +
    + calib->xdev = xdev;
    + xrt_set_drvdata(xdev, calib);
    +
    + res = xrt_get_resource(xdev, IORESOURCE_MEM, 0);
    + if (!res) {
    + err = -EINVAL;
    + goto failed;
    + }
    +
    + base = devm_ioremap_resource(&xdev->dev, res);
    + if (IS_ERR(base)) {
    + err = PTR_ERR(base);
    + goto failed;
    + }
    +
    + calib->regmap = devm_regmap_init_mmio(&xdev->dev, base, &calib_regmap_config);
    + if (IS_ERR(calib->regmap)) {
    + xrt_err(xdev, "Map iomem failed");
    + err = PTR_ERR(calib->regmap);
    + goto failed;
    + }
    +
    + mutex_init(&calib->lock);
    + INIT_LIST_HEAD(&calib->cache_list);
    +
    + return 0;
    +
    +failed:
    + return err;
    +}
    +
    +static int
    +xrt_calib_leaf_call(struct xrt_device *xdev, u32 cmd, void *arg)
    +{
    + struct calib *calib = xrt_get_drvdata(xdev);
    + int ret = 0;
    +
    + switch (cmd) {
    + case XRT_XLEAF_EVENT:
    + xrt_calib_event_cb(xdev, arg);
    + break;
    + case XRT_CALIB_RESULT: {
    + enum xrt_calib_results *r = (enum xrt_calib_results *)arg;
    + *r = calib->result;
    + break;
    + }
    + default:
    + xrt_err(xdev, "unsupported cmd %d", cmd);
    + ret = -EINVAL;
    + }
    + return ret;
    +}
    +
    +static struct xrt_dev_endpoints xrt_calib_endpoints[] = {
    + {
    + .xse_names = (struct xrt_dev_ep_names[]) {
    + { .ep_name = XRT_MD_NODE_DDR_CALIB },
    + { NULL },
    + },
    + .xse_min_ep = 1,
    + },
    + { 0 },
    +};
    +
    +static struct xrt_driver xrt_calib_driver = {
    + .driver = {
    + .name = XRT_CALIB,
    + },
    + .subdev_id = XRT_SUBDEV_CALIB,
    + .endpoints = xrt_calib_endpoints,
    + .probe = xrt_calib_probe,
    + .remove = xrt_calib_remove,
    + .leaf_call = xrt_calib_leaf_call,
    +};
    +
    +XRT_LEAF_INIT_FINI_FUNC(calib);
    --
    2.27.0
    \
     
     \ /
      Last update: 2021-05-28 02:55    [W:4.130 / U:0.248 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site