Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/fpga/altera-fpga2sdram.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices
4
*
5
* Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
6
*/
7
8
/*
9
* This driver manages a bridge between an FPGA and the SDRAM used by the ARM
10
* host processor system (HPS).
11
*
12
* The bridge contains 4 read ports, 4 write ports, and 6 command ports.
13
* Reconfiguring these ports requires that no SDRAM transactions occur during
14
* reconfiguration. The code reconfiguring the ports cannot run out of SDRAM
15
* nor can the FPGA access the SDRAM during reconfiguration. This driver does
16
* not support reconfiguring the ports. The ports are configured by code
17
* running out of on chip ram before Linux is started and the configuration
18
* is passed in a handoff register in the system manager.
19
*
20
* This driver supports enabling and disabling of the configured ports, which
21
* allows for safe reprogramming of the FPGA, assuming that the new FPGA image
22
* uses the same port configuration. Bridges must be disabled before
23
* reprogramming the FPGA and re-enabled after the FPGA has been programmed.
24
*/
25
26
#include <linux/fpga/fpga-bridge.h>
27
#include <linux/kernel.h>
28
#include <linux/mfd/syscon.h>
29
#include <linux/module.h>
30
#include <linux/of.h>
31
#include <linux/regmap.h>
32
33
#define ALT_SDR_CTL_FPGAPORTRST_OFST 0x80
34
#define ALT_SDR_CTL_FPGAPORTRST_PORTRSTN_MSK 0x00003fff
35
#define ALT_SDR_CTL_FPGAPORTRST_RD_SHIFT 0
36
#define ALT_SDR_CTL_FPGAPORTRST_WR_SHIFT 4
37
#define ALT_SDR_CTL_FPGAPORTRST_CTRL_SHIFT 8
38
39
/*
40
* From the Cyclone V HPS Memory Map document:
41
* These registers are used to store handoff information between the
42
* preloader and the OS. These 8 registers can be used to store any
43
* information. The contents of these registers have no impact on
44
* the state of the HPS hardware.
45
*/
46
#define SYSMGR_ISWGRP_HANDOFF3 (0x8C)
47
48
#define F2S_BRIDGE_NAME "fpga2sdram"
49
50
struct alt_fpga2sdram_data {
51
struct device *dev;
52
struct regmap *sdrctl;
53
int mask;
54
};
55
56
static int alt_fpga2sdram_enable_show(struct fpga_bridge *bridge)
57
{
58
struct alt_fpga2sdram_data *priv = bridge->priv;
59
int value;
60
61
regmap_read(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST, &value);
62
63
return (value & priv->mask) == priv->mask;
64
}
65
66
static inline int _alt_fpga2sdram_enable_set(struct alt_fpga2sdram_data *priv,
67
bool enable)
68
{
69
return regmap_update_bits(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST,
70
priv->mask, enable ? priv->mask : 0);
71
}
72
73
static int alt_fpga2sdram_enable_set(struct fpga_bridge *bridge, bool enable)
74
{
75
return _alt_fpga2sdram_enable_set(bridge->priv, enable);
76
}
77
78
static const struct fpga_bridge_ops altera_fpga2sdram_br_ops = {
79
.enable_set = alt_fpga2sdram_enable_set,
80
.enable_show = alt_fpga2sdram_enable_show,
81
};
82
83
static const struct of_device_id altera_fpga_of_match[] = {
84
{ .compatible = "altr,socfpga-fpga2sdram-bridge" },
85
{},
86
};
87
88
static int alt_fpga_bridge_probe(struct platform_device *pdev)
89
{
90
struct device *dev = &pdev->dev;
91
struct alt_fpga2sdram_data *priv;
92
struct fpga_bridge *br;
93
u32 enable;
94
struct regmap *sysmgr;
95
int ret = 0;
96
97
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
98
if (!priv)
99
return -ENOMEM;
100
101
priv->dev = dev;
102
103
priv->sdrctl = syscon_regmap_lookup_by_compatible("altr,sdr-ctl");
104
if (IS_ERR(priv->sdrctl)) {
105
dev_err(dev, "regmap for altr,sdr-ctl lookup failed.\n");
106
return PTR_ERR(priv->sdrctl);
107
}
108
109
sysmgr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
110
if (IS_ERR(sysmgr)) {
111
dev_err(dev, "regmap for altr,sys-mgr lookup failed.\n");
112
return PTR_ERR(sysmgr);
113
}
114
115
/* Get f2s bridge configuration saved in handoff register */
116
regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask);
117
118
br = fpga_bridge_register(dev, F2S_BRIDGE_NAME,
119
&altera_fpga2sdram_br_ops, priv);
120
if (IS_ERR(br))
121
return PTR_ERR(br);
122
123
platform_set_drvdata(pdev, br);
124
125
dev_info(dev, "driver initialized with handoff %08x\n", priv->mask);
126
127
if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) {
128
if (enable > 1) {
129
dev_warn(dev, "invalid bridge-enable %u > 1\n", enable);
130
} else {
131
dev_info(dev, "%s bridge\n",
132
(enable ? "enabling" : "disabling"));
133
ret = _alt_fpga2sdram_enable_set(priv, enable);
134
if (ret) {
135
fpga_bridge_unregister(br);
136
return ret;
137
}
138
}
139
}
140
141
return ret;
142
}
143
144
static void alt_fpga_bridge_remove(struct platform_device *pdev)
145
{
146
struct fpga_bridge *br = platform_get_drvdata(pdev);
147
148
fpga_bridge_unregister(br);
149
}
150
151
MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
152
153
static struct platform_driver altera_fpga_driver = {
154
.probe = alt_fpga_bridge_probe,
155
.remove = alt_fpga_bridge_remove,
156
.driver = {
157
.name = "altera_fpga2sdram_bridge",
158
.of_match_table = of_match_ptr(altera_fpga_of_match),
159
},
160
};
161
162
module_platform_driver(altera_fpga_driver);
163
164
MODULE_DESCRIPTION("Altera SoCFPGA FPGA to SDRAM Bridge");
165
MODULE_AUTHOR("Alan Tull <[email protected]>");
166
MODULE_LICENSE("GPL v2");
167
168