[PATCH v20 09/10] fpga: add altera freeze bridge support

2016-10-17 Thread Alan Tull
Add a low level driver for Altera Freeze Bridges to the FPGA Bridge
framework.  A freeze bridge is a bridge that exists in the FPGA
fabric to isolate one region of the FPGA from the busses while that
one region is being reprogrammed.

Signed-off-by: Alan Tull 
Signed-off-by: Matthew Gerlach 
---
v19: added in v19 of patchset as it needs for fpga info struct
v20: No change for this patch in v20 of patchset
---
 drivers/fpga/Kconfig|   9 ++
 drivers/fpga/Makefile   |   1 +
 drivers/fpga/altera-freeze-bridge.c | 273 
 3 files changed, 283 insertions(+)
 create mode 100644 drivers/fpga/altera-freeze-bridge.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 5605ad6..8fe6a84 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -47,6 +47,15 @@ config SOCFPGA_FPGA_BRIDGE
  Say Y to enable drivers for FPGA bridges for Altera SOCFPGA
  devices.
 
+config ALTERA_FREEZE_BRIDGE
+   tristate "Altera FPGA Freeze Bridge"
+   depends on ARCH_SOCFPGA && FPGA_BRIDGE
+   help
+ Say Y to enable drivers for Altera FPGA Freeze bridges.  A
+ freeze bridge is a bridge that exists in the FPGA fabric to
+ isolate one region of the FPGA from the busses while that
+ region is being reprogrammed.
+
 endif # FPGA
 
 endmenu
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index e658436..a6f874d 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)  += zynq-fpga.o
 # FPGA Bridge Drivers
 obj-$(CONFIG_FPGA_BRIDGE)  += fpga-bridge.o
 obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)  += altera-hps2fpga.o altera-fpga2sdram.o
+obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o
 
 # High Level Interfaces
 obj-$(CONFIG_FPGA_REGION)  += fpga-region.o
diff --git a/drivers/fpga/altera-freeze-bridge.c 
b/drivers/fpga/altera-freeze-bridge.c
new file mode 100644
index 000..8dcd9fb
--- /dev/null
+++ b/drivers/fpga/altera-freeze-bridge.c
@@ -0,0 +1,273 @@
+/*
+ * FPGA Freeze Bridge Controller
+ *
+ *  Copyright (C) 2016 Altera Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see .
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define FREEZE_CSR_STATUS_OFFSET   0
+#define FREEZE_CSR_CTRL_OFFSET 4
+#define FREEZE_CSR_ILLEGAL_REQ_OFFSET  8
+#define FREEZE_CSR_REG_VERSION 12
+
+#define FREEZE_CSR_SUPPORTED_VERSION   2
+
+#define FREEZE_CSR_STATUS_FREEZE_REQ_DONE  BIT(0)
+#define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONEBIT(1)
+
+#define FREEZE_CSR_CTRL_FREEZE_REQ BIT(0)
+#define FREEZE_CSR_CTRL_RESET_REQ  BIT(1)
+#define FREEZE_CSR_CTRL_UNFREEZE_REQ   BIT(2)
+
+#define FREEZE_BRIDGE_NAME "freeze"
+
+struct altera_freeze_br_data {
+   struct device *dev;
+   void __iomem *base_addr;
+   bool enable;
+};
+
+/*
+ * Poll status until status bit is set or we have a timeout.
+ */
+static int altera_freeze_br_req_ack(struct altera_freeze_br_data *priv,
+   u32 timeout, u32 req_ack)
+{
+   struct device *dev = priv->dev;
+   void __iomem *csr_illegal_req_addr = priv->base_addr +
+FREEZE_CSR_ILLEGAL_REQ_OFFSET;
+   u32 status, illegal, ctrl;
+   int ret = -ETIMEDOUT;
+
+   do {
+   illegal = readl(csr_illegal_req_addr);
+   if (illegal) {
+   dev_err(dev, "illegal request detected 0x%x", illegal);
+
+   writel(1, csr_illegal_req_addr);
+
+   illegal = readl(csr_illegal_req_addr);
+   if (illegal)
+   dev_err(dev, "illegal request not cleared 0x%x",
+   illegal);
+
+   ret = -EINVAL;
+   break;
+   }
+
+   status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET);
+   dev_dbg(dev, "%s %x %x\n", __func__, status, req_ack);
+   status &= req_ack;
+   if (status) {
+   ctrl = readl(priv->base_addr + FREEZE_CSR_CTRL_OFFSET);
+   

[PATCH v20 09/10] fpga: add altera freeze bridge support

2016-10-17 Thread Alan Tull
Add a low level driver for Altera Freeze Bridges to the FPGA Bridge
framework.  A freeze bridge is a bridge that exists in the FPGA
fabric to isolate one region of the FPGA from the busses while that
one region is being reprogrammed.

Signed-off-by: Alan Tull 
Signed-off-by: Matthew Gerlach 
---
v19: added in v19 of patchset as it needs for fpga info struct
v20: No change for this patch in v20 of patchset
---
 drivers/fpga/Kconfig|   9 ++
 drivers/fpga/Makefile   |   1 +
 drivers/fpga/altera-freeze-bridge.c | 273 
 3 files changed, 283 insertions(+)
 create mode 100644 drivers/fpga/altera-freeze-bridge.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 5605ad6..8fe6a84 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -47,6 +47,15 @@ config SOCFPGA_FPGA_BRIDGE
  Say Y to enable drivers for FPGA bridges for Altera SOCFPGA
  devices.
 
+config ALTERA_FREEZE_BRIDGE
+   tristate "Altera FPGA Freeze Bridge"
+   depends on ARCH_SOCFPGA && FPGA_BRIDGE
+   help
+ Say Y to enable drivers for Altera FPGA Freeze bridges.  A
+ freeze bridge is a bridge that exists in the FPGA fabric to
+ isolate one region of the FPGA from the busses while that
+ region is being reprogrammed.
+
 endif # FPGA
 
 endmenu
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index e658436..a6f874d 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)  += zynq-fpga.o
 # FPGA Bridge Drivers
 obj-$(CONFIG_FPGA_BRIDGE)  += fpga-bridge.o
 obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE)  += altera-hps2fpga.o altera-fpga2sdram.o
+obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o
 
 # High Level Interfaces
 obj-$(CONFIG_FPGA_REGION)  += fpga-region.o
diff --git a/drivers/fpga/altera-freeze-bridge.c 
b/drivers/fpga/altera-freeze-bridge.c
new file mode 100644
index 000..8dcd9fb
--- /dev/null
+++ b/drivers/fpga/altera-freeze-bridge.c
@@ -0,0 +1,273 @@
+/*
+ * FPGA Freeze Bridge Controller
+ *
+ *  Copyright (C) 2016 Altera Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see .
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define FREEZE_CSR_STATUS_OFFSET   0
+#define FREEZE_CSR_CTRL_OFFSET 4
+#define FREEZE_CSR_ILLEGAL_REQ_OFFSET  8
+#define FREEZE_CSR_REG_VERSION 12
+
+#define FREEZE_CSR_SUPPORTED_VERSION   2
+
+#define FREEZE_CSR_STATUS_FREEZE_REQ_DONE  BIT(0)
+#define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONEBIT(1)
+
+#define FREEZE_CSR_CTRL_FREEZE_REQ BIT(0)
+#define FREEZE_CSR_CTRL_RESET_REQ  BIT(1)
+#define FREEZE_CSR_CTRL_UNFREEZE_REQ   BIT(2)
+
+#define FREEZE_BRIDGE_NAME "freeze"
+
+struct altera_freeze_br_data {
+   struct device *dev;
+   void __iomem *base_addr;
+   bool enable;
+};
+
+/*
+ * Poll status until status bit is set or we have a timeout.
+ */
+static int altera_freeze_br_req_ack(struct altera_freeze_br_data *priv,
+   u32 timeout, u32 req_ack)
+{
+   struct device *dev = priv->dev;
+   void __iomem *csr_illegal_req_addr = priv->base_addr +
+FREEZE_CSR_ILLEGAL_REQ_OFFSET;
+   u32 status, illegal, ctrl;
+   int ret = -ETIMEDOUT;
+
+   do {
+   illegal = readl(csr_illegal_req_addr);
+   if (illegal) {
+   dev_err(dev, "illegal request detected 0x%x", illegal);
+
+   writel(1, csr_illegal_req_addr);
+
+   illegal = readl(csr_illegal_req_addr);
+   if (illegal)
+   dev_err(dev, "illegal request not cleared 0x%x",
+   illegal);
+
+   ret = -EINVAL;
+   break;
+   }
+
+   status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET);
+   dev_dbg(dev, "%s %x %x\n", __func__, status, req_ack);
+   status &= req_ack;
+   if (status) {
+   ctrl = readl(priv->base_addr + FREEZE_CSR_CTRL_OFFSET);
+   dev_dbg(dev, "%s request %x acknowledged %x %x\n",
+