Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices
0004  *
0005  *  Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
0006  */
0007 
0008 /*
0009  * This driver manages a bridge between an FPGA and the SDRAM used by the ARM
0010  * host processor system (HPS).
0011  *
0012  * The bridge contains 4 read ports, 4 write ports, and 6 command ports.
0013  * Reconfiguring these ports requires that no SDRAM transactions occur during
0014  * reconfiguration.  The code reconfiguring the ports cannot run out of SDRAM
0015  * nor can the FPGA access the SDRAM during reconfiguration.  This driver does
0016  * not support reconfiguring the ports.  The ports are configured by code
0017  * running out of on chip ram before Linux is started and the configuration
0018  * is passed in a handoff register in the system manager.
0019  *
0020  * This driver supports enabling and disabling of the configured ports, which
0021  * allows for safe reprogramming of the FPGA, assuming that the new FPGA image
0022  * uses the same port configuration.  Bridges must be disabled before
0023  * reprogramming the FPGA and re-enabled after the FPGA has been programmed.
0024  */
0025 
0026 #include <linux/fpga/fpga-bridge.h>
0027 #include <linux/kernel.h>
0028 #include <linux/mfd/syscon.h>
0029 #include <linux/module.h>
0030 #include <linux/of_platform.h>
0031 #include <linux/regmap.h>
0032 
0033 #define ALT_SDR_CTL_FPGAPORTRST_OFST        0x80
0034 #define ALT_SDR_CTL_FPGAPORTRST_PORTRSTN_MSK    0x00003fff
0035 #define ALT_SDR_CTL_FPGAPORTRST_RD_SHIFT    0
0036 #define ALT_SDR_CTL_FPGAPORTRST_WR_SHIFT    4
0037 #define ALT_SDR_CTL_FPGAPORTRST_CTRL_SHIFT  8
0038 
0039 /*
0040  * From the Cyclone V HPS Memory Map document:
0041  *   These registers are used to store handoff information between the
0042  *   preloader and the OS. These 8 registers can be used to store any
0043  *   information. The contents of these registers have no impact on
0044  *   the state of the HPS hardware.
0045  */
0046 #define SYSMGR_ISWGRP_HANDOFF3          (0x8C)
0047 
0048 #define F2S_BRIDGE_NAME "fpga2sdram"
0049 
0050 struct alt_fpga2sdram_data {
0051     struct device *dev;
0052     struct regmap *sdrctl;
0053     int mask;
0054 };
0055 
0056 static int alt_fpga2sdram_enable_show(struct fpga_bridge *bridge)
0057 {
0058     struct alt_fpga2sdram_data *priv = bridge->priv;
0059     int value;
0060 
0061     regmap_read(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST, &value);
0062 
0063     return (value & priv->mask) == priv->mask;
0064 }
0065 
0066 static inline int _alt_fpga2sdram_enable_set(struct alt_fpga2sdram_data *priv,
0067                          bool enable)
0068 {
0069     return regmap_update_bits(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST,
0070                   priv->mask, enable ? priv->mask : 0);
0071 }
0072 
0073 static int alt_fpga2sdram_enable_set(struct fpga_bridge *bridge, bool enable)
0074 {
0075     return _alt_fpga2sdram_enable_set(bridge->priv, enable);
0076 }
0077 
0078 struct prop_map {
0079     char *prop_name;
0080     u32 *prop_value;
0081     u32 prop_max;
0082 };
0083 
0084 static const struct fpga_bridge_ops altera_fpga2sdram_br_ops = {
0085     .enable_set = alt_fpga2sdram_enable_set,
0086     .enable_show = alt_fpga2sdram_enable_show,
0087 };
0088 
0089 static const struct of_device_id altera_fpga_of_match[] = {
0090     { .compatible = "altr,socfpga-fpga2sdram-bridge" },
0091     {},
0092 };
0093 
0094 static int alt_fpga_bridge_probe(struct platform_device *pdev)
0095 {
0096     struct device *dev = &pdev->dev;
0097     struct alt_fpga2sdram_data *priv;
0098     struct fpga_bridge *br;
0099     u32 enable;
0100     struct regmap *sysmgr;
0101     int ret = 0;
0102 
0103     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0104     if (!priv)
0105         return -ENOMEM;
0106 
0107     priv->dev = dev;
0108 
0109     priv->sdrctl = syscon_regmap_lookup_by_compatible("altr,sdr-ctl");
0110     if (IS_ERR(priv->sdrctl)) {
0111         dev_err(dev, "regmap for altr,sdr-ctl lookup failed.\n");
0112         return PTR_ERR(priv->sdrctl);
0113     }
0114 
0115     sysmgr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
0116     if (IS_ERR(sysmgr)) {
0117         dev_err(dev, "regmap for altr,sys-mgr lookup failed.\n");
0118         return PTR_ERR(sysmgr);
0119     }
0120 
0121     /* Get f2s bridge configuration saved in handoff register */
0122     regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask);
0123 
0124     br = fpga_bridge_register(dev, F2S_BRIDGE_NAME,
0125                   &altera_fpga2sdram_br_ops, priv);
0126     if (IS_ERR(br))
0127         return PTR_ERR(br);
0128 
0129     platform_set_drvdata(pdev, br);
0130 
0131     dev_info(dev, "driver initialized with handoff %08x\n", priv->mask);
0132 
0133     if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) {
0134         if (enable > 1) {
0135             dev_warn(dev, "invalid bridge-enable %u > 1\n", enable);
0136         } else {
0137             dev_info(dev, "%s bridge\n",
0138                  (enable ? "enabling" : "disabling"));
0139             ret = _alt_fpga2sdram_enable_set(priv, enable);
0140             if (ret) {
0141                 fpga_bridge_unregister(br);
0142                 return ret;
0143             }
0144         }
0145     }
0146 
0147     return ret;
0148 }
0149 
0150 static int alt_fpga_bridge_remove(struct platform_device *pdev)
0151 {
0152     struct fpga_bridge *br = platform_get_drvdata(pdev);
0153 
0154     fpga_bridge_unregister(br);
0155 
0156     return 0;
0157 }
0158 
0159 MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
0160 
0161 static struct platform_driver altera_fpga_driver = {
0162     .probe = alt_fpga_bridge_probe,
0163     .remove = alt_fpga_bridge_remove,
0164     .driver = {
0165         .name   = "altera_fpga2sdram_bridge",
0166         .of_match_table = of_match_ptr(altera_fpga_of_match),
0167     },
0168 };
0169 
0170 module_platform_driver(altera_fpga_driver);
0171 
0172 MODULE_DESCRIPTION("Altera SoCFPGA FPGA to SDRAM Bridge");
0173 MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
0174 MODULE_LICENSE("GPL v2");