aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/fpga/altera-fpga2sdram.c
diff options
context:
space:
mode:
authorAlan Tull <atull@opensource.altera.com>2016-11-01 15:14:30 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-11-10 11:03:36 -0500
commite5f8efa5c8bf86c1fa698551d54db8f6aee221fd (patch)
tree8be983f965df4d7f28d05285b8d8ee57041a8dee /drivers/fpga/altera-fpga2sdram.c
parent0fa20cdfcc1f68847cdfc47824476301eedc8297 (diff)
ARM: socfpga: fpga bridge driver support
Supports Altera SOCFPGA bridges: * fpga2sdram * fpga2hps * hps2fpga * lwhps2fpga Allows enabling/disabling the bridges through the FPGA Bridge Framework API functions. The fpga2sdram driver only supports enabling and disabling of the ports that been configured early on. This is due to a hardware limitation where the read, write, and command ports on the fpga2sdram bridge can only be reconfigured while there are no transactions to the sdram, i.e. when running out of OCRAM before the kernel boots. Device tree property 'init-val' configures the driver to enable or disable the bridge during probe. If the property does not exist, the driver will leave the bridge in its current state. Signed-off-by: Alan Tull <atull@opensource.altera.com> Signed-off-by: Matthew Gerlach <mgerlach@altera.com> Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/fpga/altera-fpga2sdram.c')
-rw-r--r--drivers/fpga/altera-fpga2sdram.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c
new file mode 100644
index 000000000000..7ab358ed6c76
--- /dev/null
+++ b/drivers/fpga/altera-fpga2sdram.c
@@ -0,0 +1,180 @@
1/*
2 * FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices
3 *
4 * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * This driver manages a bridge between an FPGA and the SDRAM used by the ARM
21 * host processor system (HPS).
22 *
23 * The bridge contains 4 read ports, 4 write ports, and 6 command ports.
24 * Reconfiguring these ports requires that no SDRAM transactions occur during
25 * reconfiguration. The code reconfiguring the ports cannot run out of SDRAM
26 * nor can the FPGA access the SDRAM during reconfiguration. This driver does
27 * not support reconfiguring the ports. The ports are configured by code
28 * running out of on chip ram before Linux is started and the configuration
29 * is passed in a handoff register in the system manager.
30 *
31 * This driver supports enabling and disabling of the configured ports, which
32 * allows for safe reprogramming of the FPGA, assuming that the new FPGA image
33 * uses the same port configuration. Bridges must be disabled before
34 * reprogramming the FPGA and re-enabled after the FPGA has been programmed.
35 */
36
37#include <linux/fpga/fpga-bridge.h>
38#include <linux/kernel.h>
39#include <linux/mfd/syscon.h>
40#include <linux/module.h>
41#include <linux/of_platform.h>
42#include <linux/regmap.h>
43
44#define ALT_SDR_CTL_FPGAPORTRST_OFST 0x80
45#define ALT_SDR_CTL_FPGAPORTRST_PORTRSTN_MSK 0x00003fff
46#define ALT_SDR_CTL_FPGAPORTRST_RD_SHIFT 0
47#define ALT_SDR_CTL_FPGAPORTRST_WR_SHIFT 4
48#define ALT_SDR_CTL_FPGAPORTRST_CTRL_SHIFT 8
49
50/*
51 * From the Cyclone V HPS Memory Map document:
52 * These registers are used to store handoff information between the
53 * preloader and the OS. These 8 registers can be used to store any
54 * information. The contents of these registers have no impact on
55 * the state of the HPS hardware.
56 */
57#define SYSMGR_ISWGRP_HANDOFF3 (0x8C)
58
59#define F2S_BRIDGE_NAME "fpga2sdram"
60
61struct alt_fpga2sdram_data {
62 struct device *dev;
63 struct regmap *sdrctl;
64 int mask;
65};
66
67static int alt_fpga2sdram_enable_show(struct fpga_bridge *bridge)
68{
69 struct alt_fpga2sdram_data *priv = bridge->priv;
70 int value;
71
72 regmap_read(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST, &value);
73
74 return (value & priv->mask) == priv->mask;
75}
76
77static inline int _alt_fpga2sdram_enable_set(struct alt_fpga2sdram_data *priv,
78 bool enable)
79{
80 return regmap_update_bits(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST,
81 priv->mask, enable ? priv->mask : 0);
82}
83
84static int alt_fpga2sdram_enable_set(struct fpga_bridge *bridge, bool enable)
85{
86 return _alt_fpga2sdram_enable_set(bridge->priv, enable);
87}
88
89struct prop_map {
90 char *prop_name;
91 u32 *prop_value;
92 u32 prop_max;
93};
94
95static const struct fpga_bridge_ops altera_fpga2sdram_br_ops = {
96 .enable_set = alt_fpga2sdram_enable_set,
97 .enable_show = alt_fpga2sdram_enable_show,
98};
99
100static const struct of_device_id altera_fpga_of_match[] = {
101 { .compatible = "altr,socfpga-fpga2sdram-bridge" },
102 {},
103};
104
105static int alt_fpga_bridge_probe(struct platform_device *pdev)
106{
107 struct device *dev = &pdev->dev;
108 struct alt_fpga2sdram_data *priv;
109 u32 enable;
110 struct regmap *sysmgr;
111 int ret = 0;
112
113 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
114 if (!priv)
115 return -ENOMEM;
116
117 priv->dev = dev;
118
119 priv->sdrctl = syscon_regmap_lookup_by_compatible("altr,sdr-ctl");
120 if (IS_ERR(priv->sdrctl)) {
121 dev_err(dev, "regmap for altr,sdr-ctl lookup failed.\n");
122 return PTR_ERR(priv->sdrctl);
123 }
124
125 sysmgr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
126 if (IS_ERR(priv->sdrctl)) {
127 dev_err(dev, "regmap for altr,sys-mgr lookup failed.\n");
128 return PTR_ERR(sysmgr);
129 }
130
131 /* Get f2s bridge configuration saved in handoff register */
132 regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask);
133
134 ret = fpga_bridge_register(dev, F2S_BRIDGE_NAME,
135 &altera_fpga2sdram_br_ops, priv);
136 if (ret)
137 return ret;
138
139 dev_info(dev, "driver initialized with handoff %08x\n", priv->mask);
140
141 if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) {
142 if (enable > 1) {
143 dev_warn(dev, "invalid bridge-enable %u > 1\n", enable);
144 } else {
145 dev_info(dev, "%s bridge\n",
146 (enable ? "enabling" : "disabling"));
147 ret = _alt_fpga2sdram_enable_set(priv, enable);
148 if (ret) {
149 fpga_bridge_unregister(&pdev->dev);
150 return ret;
151 }
152 }
153 }
154
155 return ret;
156}
157
158static int alt_fpga_bridge_remove(struct platform_device *pdev)
159{
160 fpga_bridge_unregister(&pdev->dev);
161
162 return 0;
163}
164
165MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
166
167static struct platform_driver altera_fpga_driver = {
168 .probe = alt_fpga_bridge_probe,
169 .remove = alt_fpga_bridge_remove,
170 .driver = {
171 .name = "altera_fpga2sdram_bridge",
172 .of_match_table = of_match_ptr(altera_fpga_of_match),
173 },
174};
175
176module_platform_driver(altera_fpga_driver);
177
178MODULE_DESCRIPTION("Altera SoCFPGA FPGA to SDRAM Bridge");
179MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
180MODULE_LICENSE("GPL v2");