aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-11-27 17:38:56 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-11-27 17:38:56 -0800
commitab2fa693c905f2dd6ad435082fa8c175a1ddbd23 (patch)
treea93c56e1049d6817f42429e34b6cc1377f8092a4
parent7dcbe3014ffc969629a250b4c614a43856a585ea (diff)
downloadltsi-kernel-ab2fa693c905f2dd6ad435082fa8c175a1ddbd23.tar.gz
Altera fpga patches
-rw-r--r--patches.altera/0001-usage-documentation-for-FPGA-manager-core.patch196
-rw-r--r--patches.altera/0002-fpga-manager-add-sysfs-interface-document.patch63
-rw-r--r--patches.altera/0003-add-FPGA-manager-core.patch627
-rw-r--r--patches.altera/0004-fpga-manager-add-driver-for-socfpga-fpga-manager.patch674
-rw-r--r--patches.altera/0005-MAINTAINERS-add-fpga-manager-framework.patch32
-rw-r--r--patches.altera/0006-ARM-socfpga_defconfig-enable-fpga-manager.patch33
-rw-r--r--patches.altera/0007-ARM-socfpga-dts-add-fpga-manager.patch32
-rw-r--r--series9
8 files changed, 1666 insertions, 0 deletions
diff --git a/patches.altera/0001-usage-documentation-for-FPGA-manager-core.patch b/patches.altera/0001-usage-documentation-for-FPGA-manager-core.patch
new file mode 100644
index 00000000000000..08b4c2fcd955ca
--- /dev/null
+++ b/patches.altera/0001-usage-documentation-for-FPGA-manager-core.patch
@@ -0,0 +1,196 @@
+From 0cf026d06a9d7f22f2d29de5ac43edd10c676fe1 Mon Sep 17 00:00:00 2001
+From: Alan Tull <atull@opensource.altera.com>
+Date: Wed, 7 Oct 2015 16:36:26 +0100
+Subject: [PATCH 1/7] usage documentation for FPGA manager core
+
+Add a document on the new FPGA manager core.
+
+Signed-off-by: Alan Tull <atull@opensource.altera.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+(cherry picked from commit e8f5fda1ad477f02bf82a50284acbd0f7f1364e3)
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+---
+ Documentation/fpga/fpga-mgr.txt | 171 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 171 insertions(+)
+ create mode 100644 Documentation/fpga/fpga-mgr.txt
+
+diff --git a/Documentation/fpga/fpga-mgr.txt b/Documentation/fpga/fpga-mgr.txt
+new file mode 100644
+index 000000000000..ce3e84fa9023
+--- /dev/null
++++ b/Documentation/fpga/fpga-mgr.txt
+@@ -0,0 +1,171 @@
++FPGA Manager Core
++
++Alan Tull 2015
++
++Overview
++========
++
++The FPGA manager core exports a set of functions for programming an FPGA with
++an image. The API is manufacturer agnostic. All manufacturer specifics are
++hidden away in a low level driver which registers a set of ops with the core.
++The FPGA image data itself is very manufacturer specific, but for our purposes
++it's just binary data. The FPGA manager core won't parse it.
++
++
++API Functions:
++==============
++
++To program the FPGA from a file or from a buffer:
++-------------------------------------------------
++
++ int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags,
++ const char *buf, size_t count);
++
++Load the FPGA from an image which exists as a buffer in memory.
++
++ int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
++ const char *image_name);
++
++Load the FPGA from an image which exists as a file. The image file must be on
++the firmware search path (see the firmware class documentation).
++
++For both these functions, flags == 0 for normal full reconfiguration or
++FPGA_MGR_PARTIAL_RECONFIG for partial reconfiguration. If successful, the FPGA
++ends up in operating mode. Return 0 on success or a negative error code.
++
++
++To get/put a reference to a FPGA manager:
++-----------------------------------------
++
++ struct fpga_manager *of_fpga_mgr_get(struct device_node *node);
++
++ void fpga_mgr_put(struct fpga_manager *mgr);
++
++Given a DT node, get an exclusive reference to a FPGA manager or release
++the reference.
++
++
++To register or unregister the low level FPGA-specific driver:
++-------------------------------------------------------------
++
++ int fpga_mgr_register(struct device *dev, const char *name,
++ const struct fpga_manager_ops *mops,
++ void *priv);
++
++ void fpga_mgr_unregister(struct device *dev);
++
++Use of these two functions is described below in "How To Support a new FPGA
++device."
++
++
++How to write an image buffer to a supported FPGA
++================================================
++/* Include to get the API */
++#include <linux/fpga/fpga-mgr.h>
++
++/* device node that specifies the FPGA manager to use */
++struct device_node *mgr_node = ...
++
++/* FPGA image is in this buffer. count is size of the buffer. */
++char *buf = ...
++int count = ...
++
++/* flags indicates whether to do full or partial reconfiguration */
++int flags = 0;
++
++int ret;
++
++/* Get exclusive control of FPGA manager */
++struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node);
++
++/* Load the buffer to the FPGA */
++ret = fpga_mgr_buf_load(mgr, flags, buf, count);
++
++/* Release the FPGA manager */
++fpga_mgr_put(mgr);
++
++
++How to write an image file to a supported FPGA
++==============================================
++/* Include to get the API */
++#include <linux/fpga/fpga-mgr.h>
++
++/* device node that specifies the FPGA manager to use */
++struct device_node *mgr_node = ...
++
++/* FPGA image is in this file which is in the firmware search path */
++const char *path = "fpga-image-9.rbf"
++
++/* flags indicates whether to do full or partial reconfiguration */
++int flags = 0;
++
++int ret;
++
++/* Get exclusive control of FPGA manager */
++struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node);
++
++/* Get the firmware image (path) and load it to the FPGA */
++ret = fpga_mgr_firmware_load(mgr, flags, path);
++
++/* Release the FPGA manager */
++fpga_mgr_put(mgr);
++
++
++How to support a new FPGA device
++================================
++To add another FPGA manager, write a driver that implements a set of ops. The
++probe function calls fpga_mgr_register(), such as:
++
++static const struct fpga_manager_ops socfpga_fpga_ops = {
++ .write_init = socfpga_fpga_ops_configure_init,
++ .write = socfpga_fpga_ops_configure_write,
++ .write_complete = socfpga_fpga_ops_configure_complete,
++ .state = socfpga_fpga_ops_state,
++};
++
++static int socfpga_fpga_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct socfpga_fpga_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ /* ... do ioremaps, get interrupts, etc. and save
++ them in priv... */
++
++ return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
++ &socfpga_fpga_ops, priv);
++}
++
++static int socfpga_fpga_remove(struct platform_device *pdev)
++{
++ fpga_mgr_unregister(&pdev->dev);
++
++ return 0;
++}
++
++
++The ops will implement whatever device specific register writes are needed to
++do the programming sequence for this particular FPGA. These ops return 0 for
++success or negative error codes otherwise.
++
++The programming sequence is:
++ 1. .write_init
++ 2. .write (may be called once or multiple times)
++ 3. .write_complete
++
++The .write_init function will prepare the FPGA to receive the image data.
++
++The .write function writes a buffer to the FPGA. The buffer may be contain the
++whole FPGA image or may be a smaller chunk of an FPGA image. In the latter
++case, this function is called multiple times for successive chunks.
++
++The .write_complete function is called after all the image has been written
++to put the FPGA into operating mode.
++
++The ops include a .state function which will read the hardware FPGA manager and
++return a code of type enum fpga_mgr_states. It doesn't result in a change in
++hardware state.
+--
+2.6.2
+
diff --git a/patches.altera/0002-fpga-manager-add-sysfs-interface-document.patch b/patches.altera/0002-fpga-manager-add-sysfs-interface-document.patch
new file mode 100644
index 00000000000000..82137d40ba74ae
--- /dev/null
+++ b/patches.altera/0002-fpga-manager-add-sysfs-interface-document.patch
@@ -0,0 +1,63 @@
+From f92ef90a1c0b6517bef416ab08ed805058fab46e Mon Sep 17 00:00:00 2001
+From: Alan Tull <atull@opensource.altera.com>
+Date: Wed, 7 Oct 2015 16:36:27 +0100
+Subject: [PATCH 2/7] fpga manager: add sysfs interface document
+
+Add documentation under drivers/staging for new fpga manager's
+sysfs interface.
+
+Signed-off-by: Alan Tull <atull@opensource.altera.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+(cherry picked from commit afb79e993a949d02895b912eacc86ab0e416b6fd)
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+---
+ Documentation/ABI/testing/sysfs-class-fpga-manager | 37 ++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+ create mode 100644 Documentation/ABI/testing/sysfs-class-fpga-manager
+
+diff --git a/Documentation/ABI/testing/sysfs-class-fpga-manager b/Documentation/ABI/testing/sysfs-class-fpga-manager
+new file mode 100644
+index 000000000000..23056c532fdd
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-class-fpga-manager
+@@ -0,0 +1,37 @@
++What: /sys/class/fpga_manager/<fpga>/name
++Date: August 2015
++KernelVersion: 4.3
++Contact: Alan Tull <atull@opensource.altera.com>
++Description: Name of low level fpga manager driver.
++
++What: /sys/class/fpga_manager/<fpga>/state
++Date: August 2015
++KernelVersion: 4.3
++Contact: Alan Tull <atull@opensource.altera.com>
++Description: Read fpga manager state as a string.
++ The intent is to provide enough detail that if something goes
++ wrong during FPGA programming (something that the driver can't
++ fix) then userspace can know, i.e. if the firmware request
++ fails, that could be due to not being able to find the firmware
++ file.
++
++ This is a superset of FPGA states and fpga manager driver
++ states. The fpga manager driver is walking through these steps
++ to get the FPGA into a known operating state. It's a sequence,
++ though some steps may get skipped. Valid FPGA states will vary
++ by manufacturer; this is a superset.
++
++ * unknown = can't determine state
++ * power off = FPGA power is off
++ * power up = FPGA reports power is up
++ * reset = FPGA held in reset state
++ * firmware request = firmware class request in progress
++ * firmware request error = firmware request failed
++ * write init = preparing FPGA for programming
++ * write init error = Error while preparing FPGA for
++ programming
++ * write = FPGA ready to receive image data
++ * write error = Error while programming
++ * write complete = Doing post programming steps
++ * write complete error = Error while doing post programming
++ * operating = FPGA is programmed and operating
+--
+2.6.2
+
diff --git a/patches.altera/0003-add-FPGA-manager-core.patch b/patches.altera/0003-add-FPGA-manager-core.patch
new file mode 100644
index 00000000000000..de36673b7b13e8
--- /dev/null
+++ b/patches.altera/0003-add-FPGA-manager-core.patch
@@ -0,0 +1,627 @@
+From e821d320b23b7fa202632ed65adc8718b01b9193 Mon Sep 17 00:00:00 2001
+From: Alan Tull <atull@opensource.altera.com>
+Date: Wed, 7 Oct 2015 16:36:28 +0100
+Subject: [PATCH 3/7] add FPGA manager core
+
+API to support programming FPGA's.
+
+The following functions are exported as GPL:
+* fpga_mgr_buf_load
+ Load fpga from image in buffer
+
+* fpga_mgr_firmware_load
+ Request firmware and load it to the FPGA.
+
+* fpga_mgr_register
+* fpga_mgr_unregister
+ FPGA device drivers can be added by calling
+ fpga_mgr_register() to register a set of
+ fpga_manager_ops to do device specific stuff.
+
+* of_fpga_mgr_get
+* fpga_mgr_put
+ Get/put a reference to a fpga manager.
+
+The following sysfs files are created:
+* /sys/class/fpga_manager/<fpga>/name
+ Name of low level driver.
+
+* /sys/class/fpga_manager/<fpga>/state
+ State of fpga manager
+
+Signed-off-by: Alan Tull <atull@opensource.altera.com>
+Acked-by: Michal Simek <michal.simek@xilinx.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+(cherry picked from commit 6a8c3be7ec8eb3c1197766f9245e0d65a4e5aff8)
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+---
+ drivers/Kconfig | 2 +
+ drivers/Makefile | 1 +
+ drivers/fpga/Kconfig | 14 ++
+ drivers/fpga/Makefile | 8 +
+ drivers/fpga/fpga-mgr.c | 382 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/fpga/fpga-mgr.h | 127 ++++++++++++++
+ 6 files changed, 534 insertions(+)
+ create mode 100644 drivers/fpga/Kconfig
+ create mode 100644 drivers/fpga/Makefile
+ create mode 100644 drivers/fpga/fpga-mgr.c
+ create mode 100644 include/linux/fpga/fpga-mgr.h
+
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index c0cc96bab9e7..9df7978b5b40 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -182,4 +182,6 @@ source "drivers/thunderbolt/Kconfig"
+
+ source "drivers/android/Kconfig"
+
++source "drivers/fpga/Kconfig"
++
+ endmenu
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 46d2554be404..3cf37ee08ad8 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS) += ras/
+ obj-$(CONFIG_THUNDERBOLT) += thunderbolt/
+ obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/
+ obj-$(CONFIG_ANDROID) += android/
++obj-$(CONFIG_FPGA) += fpga/
+diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
+new file mode 100644
+index 000000000000..f1f1f6df54d3
+--- /dev/null
++++ b/drivers/fpga/Kconfig
+@@ -0,0 +1,14 @@
++#
++# FPGA framework configuration
++#
++
++menu "FPGA Configuration Support"
++
++config FPGA
++ tristate "FPGA Configuration Framework"
++ help
++ Say Y here if you want support for configuring FPGAs from the
++ kernel. The FPGA framework adds a FPGA manager class and FPGA
++ manager drivers.
++
++endmenu
+diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
+new file mode 100644
+index 000000000000..3313c5266795
+--- /dev/null
++++ b/drivers/fpga/Makefile
+@@ -0,0 +1,8 @@
++#
++# Makefile for the fpga framework and fpga manager drivers.
++#
++
++# Core FPGA Manager Framework
++obj-$(CONFIG_FPGA) += fpga-mgr.o
++
++# FPGA Manager Drivers
+diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
+new file mode 100644
+index 000000000000..25261636687c
+--- /dev/null
++++ b/drivers/fpga/fpga-mgr.c
+@@ -0,0 +1,382 @@
++/*
++ * FPGA Manager Core
++ *
++ * Copyright (C) 2013-2015 Altera Corporation
++ *
++ * With code from the mailing list:
++ * Copyright (C) 2013 Xilinx, Inc.
++ *
++ * 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 <http://www.gnu.org/licenses/>.
++ */
++#include <linux/firmware.h>
++#include <linux/fpga/fpga-mgr.h>
++#include <linux/idr.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++
++static DEFINE_IDA(fpga_mgr_ida);
++static struct class *fpga_mgr_class;
++
++/**
++ * fpga_mgr_buf_load - load fpga from image in buffer
++ * @mgr: fpga manager
++ * @flags: flags setting fpga confuration modes
++ * @buf: buffer contain fpga image
++ * @count: byte count of buf
++ *
++ * Step the low level fpga manager through the device-specific steps of getting
++ * an FPGA ready to be configured, writing the image to it, then doing whatever
++ * post-configuration steps necessary.
++ *
++ * Return: 0 on success, negative error code otherwise.
++ */
++int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf,
++ size_t count)
++{
++ struct device *dev = &mgr->dev;
++ int ret;
++
++ if (!mgr)
++ return -ENODEV;
++
++ /*
++ * Call the low level driver's write_init function. This will do the
++ * device-specific things to get the FPGA into the state where it is
++ * ready to receive an FPGA image.
++ */
++ mgr->state = FPGA_MGR_STATE_WRITE_INIT;
++ ret = mgr->mops->write_init(mgr, flags, buf, count);
++ if (ret) {
++ dev_err(dev, "Error preparing FPGA for writing\n");
++ mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR;
++ return ret;
++ }
++
++ /*
++ * Write the FPGA image to the FPGA.
++ */
++ mgr->state = FPGA_MGR_STATE_WRITE;
++ ret = mgr->mops->write(mgr, buf, count);
++ if (ret) {
++ dev_err(dev, "Error while writing image data to FPGA\n");
++ mgr->state = FPGA_MGR_STATE_WRITE_ERR;
++ return ret;
++ }
++
++ /*
++ * After all the FPGA image has been written, do the device specific
++ * steps to finish and set the FPGA into operating mode.
++ */
++ mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE;
++ ret = mgr->mops->write_complete(mgr, flags);
++ if (ret) {
++ dev_err(dev, "Error after writing image data to FPGA\n");
++ mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
++ return ret;
++ }
++ mgr->state = FPGA_MGR_STATE_OPERATING;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(fpga_mgr_buf_load);
++
++/**
++ * fpga_mgr_firmware_load - request firmware and load to fpga
++ * @mgr: fpga manager
++ * @flags: flags setting fpga confuration modes
++ * @image_name: name of image file on the firmware search path
++ *
++ * Request an FPGA image using the firmware class, then write out to the FPGA.
++ * Update the state before each step to provide info on what step failed if
++ * there is a failure.
++ *
++ * Return: 0 on success, negative error code otherwise.
++ */
++int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
++ const char *image_name)
++{
++ struct device *dev = &mgr->dev;
++ const struct firmware *fw;
++ int ret;
++
++ if (!mgr)
++ return -ENODEV;
++
++ dev_info(dev, "writing %s to %s\n", image_name, mgr->name);
++
++ mgr->state = FPGA_MGR_STATE_FIRMWARE_REQ;
++
++ ret = request_firmware(&fw, image_name, dev);
++ if (ret) {
++ mgr->state = FPGA_MGR_STATE_FIRMWARE_REQ_ERR;
++ dev_err(dev, "Error requesting firmware %s\n", image_name);
++ return ret;
++ }
++
++ ret = fpga_mgr_buf_load(mgr, flags, fw->data, fw->size);
++ if (ret)
++ return ret;
++
++ release_firmware(fw);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(fpga_mgr_firmware_load);
++
++static const char * const state_str[] = {
++ [FPGA_MGR_STATE_UNKNOWN] = "unknown",
++ [FPGA_MGR_STATE_POWER_OFF] = "power off",
++ [FPGA_MGR_STATE_POWER_UP] = "power up",
++ [FPGA_MGR_STATE_RESET] = "reset",
++
++ /* requesting FPGA image from firmware */
++ [FPGA_MGR_STATE_FIRMWARE_REQ] = "firmware request",
++ [FPGA_MGR_STATE_FIRMWARE_REQ_ERR] = "firmware request error",
++
++ /* Preparing FPGA to receive image */
++ [FPGA_MGR_STATE_WRITE_INIT] = "write init",
++ [FPGA_MGR_STATE_WRITE_INIT_ERR] = "write init error",
++
++ /* Writing image to FPGA */
++ [FPGA_MGR_STATE_WRITE] = "write",
++ [FPGA_MGR_STATE_WRITE_ERR] = "write error",
++
++ /* Finishing configuration after image has been written */
++ [FPGA_MGR_STATE_WRITE_COMPLETE] = "write complete",
++ [FPGA_MGR_STATE_WRITE_COMPLETE_ERR] = "write complete error",
++
++ /* FPGA reports to be in normal operating mode */
++ [FPGA_MGR_STATE_OPERATING] = "operating",
++};
++
++static ssize_t name_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct fpga_manager *mgr = to_fpga_manager(dev);
++
++ return sprintf(buf, "%s\n", mgr->name);
++}
++
++static ssize_t state_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct fpga_manager *mgr = to_fpga_manager(dev);
++
++ return sprintf(buf, "%s\n", state_str[mgr->state]);
++}
++
++static DEVICE_ATTR_RO(name);
++static DEVICE_ATTR_RO(state);
++
++static struct attribute *fpga_mgr_attrs[] = {
++ &dev_attr_name.attr,
++ &dev_attr_state.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(fpga_mgr);
++
++static int fpga_mgr_of_node_match(struct device *dev, const void *data)
++{
++ return dev->of_node == data;
++}
++
++/**
++ * of_fpga_mgr_get - get an exclusive reference to a fpga mgr
++ * @node: device node
++ *
++ * Given a device node, get an exclusive reference to a fpga mgr.
++ *
++ * Return: fpga manager struct or IS_ERR() condition containing error code.
++ */
++struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
++{
++ struct fpga_manager *mgr;
++ struct device *dev;
++
++ if (!node)
++ return ERR_PTR(-EINVAL);
++
++ dev = class_find_device(fpga_mgr_class, NULL, node,
++ fpga_mgr_of_node_match);
++ if (!dev)
++ return ERR_PTR(-ENODEV);
++
++ mgr = to_fpga_manager(dev);
++ put_device(dev);
++ if (!mgr)
++ return ERR_PTR(-ENODEV);
++
++ /* Get exclusive use of fpga manager */
++ if (!mutex_trylock(&mgr->ref_mutex))
++ return ERR_PTR(-EBUSY);
++
++ if (!try_module_get(THIS_MODULE)) {
++ mutex_unlock(&mgr->ref_mutex);
++ return ERR_PTR(-ENODEV);
++ }
++
++ return mgr;
++}
++EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
++
++/**
++ * fpga_mgr_put - release a reference to a fpga manager
++ * @mgr: fpga manager structure
++ */
++void fpga_mgr_put(struct fpga_manager *mgr)
++{
++ if (mgr) {
++ module_put(THIS_MODULE);
++ mutex_unlock(&mgr->ref_mutex);
++ }
++}
++EXPORT_SYMBOL_GPL(fpga_mgr_put);
++
++/**
++ * fpga_mgr_register - register a low level fpga manager driver
++ * @dev: fpga manager device from pdev
++ * @name: fpga manager name
++ * @mops: pointer to structure of fpga manager ops
++ * @priv: fpga manager private data
++ *
++ * Return: 0 on success, negative error code otherwise.
++ */
++int fpga_mgr_register(struct device *dev, const char *name,
++ const struct fpga_manager_ops *mops,
++ void *priv)
++{
++ struct fpga_manager *mgr;
++ const char *dt_label;
++ int id, ret;
++
++ if (!mops || !mops->write_init || !mops->write ||
++ !mops->write_complete || !mops->state) {
++ dev_err(dev, "Attempt to register without fpga_manager_ops\n");
++ return -EINVAL;
++ }
++
++ if (!name || !strlen(name)) {
++ dev_err(dev, "Attempt to register with no name!\n");
++ return -EINVAL;
++ }
++
++ mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
++ if (!mgr)
++ return -ENOMEM;
++
++ id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL);
++ if (id < 0) {
++ ret = id;
++ goto error_kfree;
++ }
++
++ mutex_init(&mgr->ref_mutex);
++
++ mgr->name = name;
++ mgr->mops = mops;
++ mgr->priv = priv;
++
++ /*
++ * Initialize framework state by requesting low level driver read state
++ * from device. FPGA may be in reset mode or may have been programmed
++ * by bootloader or EEPROM.
++ */
++ mgr->state = mgr->mops->state(mgr);
++
++ device_initialize(&mgr->dev);
++ mgr->dev.class = fpga_mgr_class;
++ mgr->dev.parent = dev;
++ mgr->dev.of_node = dev->of_node;
++ mgr->dev.id = id;
++ dev_set_drvdata(dev, mgr);
++
++ dt_label = of_get_property(mgr->dev.of_node, "label", NULL);
++ if (dt_label)
++ ret = dev_set_name(&mgr->dev, "%s", dt_label);
++ else
++ ret = dev_set_name(&mgr->dev, "fpga%d", id);
++
++ ret = device_add(&mgr->dev);
++ if (ret)
++ goto error_device;
++
++ dev_info(&mgr->dev, "%s registered\n", mgr->name);
++
++ return 0;
++
++error_device:
++ ida_simple_remove(&fpga_mgr_ida, id);
++error_kfree:
++ kfree(mgr);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(fpga_mgr_register);
++
++/**
++ * fpga_mgr_unregister - unregister a low level fpga manager driver
++ * @dev: fpga manager device from pdev
++ */
++void fpga_mgr_unregister(struct device *dev)
++{
++ struct fpga_manager *mgr = dev_get_drvdata(dev);
++
++ dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name);
++
++ /*
++ * If the low level driver provides a method for putting fpga into
++ * a desired state upon unregister, do it.
++ */
++ if (mgr->mops->fpga_remove)
++ mgr->mops->fpga_remove(mgr);
++
++ device_unregister(&mgr->dev);
++}
++EXPORT_SYMBOL_GPL(fpga_mgr_unregister);
++
++static void fpga_mgr_dev_release(struct device *dev)
++{
++ struct fpga_manager *mgr = to_fpga_manager(dev);
++
++ ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
++ kfree(mgr);
++}
++
++static int __init fpga_mgr_class_init(void)
++{
++ pr_info("FPGA manager framework\n");
++
++ fpga_mgr_class = class_create(THIS_MODULE, "fpga_manager");
++ if (IS_ERR(fpga_mgr_class))
++ return PTR_ERR(fpga_mgr_class);
++
++ fpga_mgr_class->dev_groups = fpga_mgr_groups;
++ fpga_mgr_class->dev_release = fpga_mgr_dev_release;
++
++ return 0;
++}
++
++static void __exit fpga_mgr_class_exit(void)
++{
++ class_destroy(fpga_mgr_class);
++ ida_destroy(&fpga_mgr_ida);
++}
++
++MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
++MODULE_DESCRIPTION("FPGA manager framework");
++MODULE_LICENSE("GPL v2");
++
++subsys_initcall(fpga_mgr_class_init);
++module_exit(fpga_mgr_class_exit);
+diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
+new file mode 100644
+index 000000000000..0940bf45e2f2
+--- /dev/null
++++ b/include/linux/fpga/fpga-mgr.h
+@@ -0,0 +1,127 @@
++/*
++ * FPGA Framework
++ *
++ * Copyright (C) 2013-2015 Altera Corporation
++ *
++ * 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 <http://www.gnu.org/licenses/>.
++ */
++#include <linux/mutex.h>
++#include <linux/platform_device.h>
++
++#ifndef _LINUX_FPGA_MGR_H
++#define _LINUX_FPGA_MGR_H
++
++struct fpga_manager;
++
++/**
++ * enum fpga_mgr_states - fpga framework states
++ * @FPGA_MGR_STATE_UNKNOWN: can't determine state
++ * @FPGA_MGR_STATE_POWER_OFF: FPGA power is off
++ * @FPGA_MGR_STATE_POWER_UP: FPGA reports power is up
++ * @FPGA_MGR_STATE_RESET: FPGA in reset state
++ * @FPGA_MGR_STATE_FIRMWARE_REQ: firmware request in progress
++ * @FPGA_MGR_STATE_FIRMWARE_REQ_ERR: firmware request failed
++ * @FPGA_MGR_STATE_WRITE_INIT: preparing FPGA for programming
++ * @FPGA_MGR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage
++ * @FPGA_MGR_STATE_WRITE: writing image to FPGA
++ * @FPGA_MGR_STATE_WRITE_ERR: Error while writing FPGA
++ * @FPGA_MGR_STATE_WRITE_COMPLETE: Doing post programming steps
++ * @FPGA_MGR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE
++ * @FPGA_MGR_STATE_OPERATING: FPGA is programmed and operating
++ */
++enum fpga_mgr_states {
++ /* default FPGA states */
++ FPGA_MGR_STATE_UNKNOWN,
++ FPGA_MGR_STATE_POWER_OFF,
++ FPGA_MGR_STATE_POWER_UP,
++ FPGA_MGR_STATE_RESET,
++
++ /* getting an image for loading */
++ FPGA_MGR_STATE_FIRMWARE_REQ,
++ FPGA_MGR_STATE_FIRMWARE_REQ_ERR,
++
++ /* write sequence: init, write, complete */
++ FPGA_MGR_STATE_WRITE_INIT,
++ FPGA_MGR_STATE_WRITE_INIT_ERR,
++ FPGA_MGR_STATE_WRITE,
++ FPGA_MGR_STATE_WRITE_ERR,
++ FPGA_MGR_STATE_WRITE_COMPLETE,
++ FPGA_MGR_STATE_WRITE_COMPLETE_ERR,
++
++ /* fpga is programmed and operating */
++ FPGA_MGR_STATE_OPERATING,
++};
++
++/*
++ * FPGA Manager flags
++ * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported
++ */
++#define FPGA_MGR_PARTIAL_RECONFIG BIT(0)
++
++/**
++ * struct fpga_manager_ops - ops for low level fpga manager drivers
++ * @state: returns an enum value of the FPGA's state
++ * @write_init: prepare the FPGA to receive confuration data
++ * @write: write count bytes of configuration data to the FPGA
++ * @write_complete: set FPGA to operating state after writing is done
++ * @fpga_remove: optional: Set FPGA into a specific state during driver remove
++ *
++ * fpga_manager_ops are the low level functions implemented by a specific
++ * fpga manager driver. The optional ones are tested for NULL before being
++ * called, so leaving them out is fine.
++ */
++struct fpga_manager_ops {
++ enum fpga_mgr_states (*state)(struct fpga_manager *mgr);
++ int (*write_init)(struct fpga_manager *mgr, u32 flags,
++ const char *buf, size_t count);
++ int (*write)(struct fpga_manager *mgr, const char *buf, size_t count);
++ int (*write_complete)(struct fpga_manager *mgr, u32 flags);
++ void (*fpga_remove)(struct fpga_manager *mgr);
++};
++
++/**
++ * struct fpga_manager - fpga manager structure
++ * @name: name of low level fpga manager
++ * @dev: fpga manager device
++ * @ref_mutex: only allows one reference to fpga manager
++ * @state: state of fpga manager
++ * @mops: pointer to struct of fpga manager ops
++ * @priv: low level driver private date
++ */
++struct fpga_manager {
++ const char *name;
++ struct device dev;
++ struct mutex ref_mutex;
++ enum fpga_mgr_states state;
++ const struct fpga_manager_ops *mops;
++ void *priv;
++};
++
++#define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)
++
++int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags,
++ const char *buf, size_t count);
++
++int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
++ const char *image_name);
++
++struct fpga_manager *of_fpga_mgr_get(struct device_node *node);
++
++void fpga_mgr_put(struct fpga_manager *mgr);
++
++int fpga_mgr_register(struct device *dev, const char *name,
++ const struct fpga_manager_ops *mops, void *priv);
++
++void fpga_mgr_unregister(struct device *dev);
++
++#endif /*_LINUX_FPGA_MGR_H */
+--
+2.6.2
+
diff --git a/patches.altera/0004-fpga-manager-add-driver-for-socfpga-fpga-manager.patch b/patches.altera/0004-fpga-manager-add-driver-for-socfpga-fpga-manager.patch
new file mode 100644
index 00000000000000..167c56dde4a1b1
--- /dev/null
+++ b/patches.altera/0004-fpga-manager-add-driver-for-socfpga-fpga-manager.patch
@@ -0,0 +1,674 @@
+From eecacbe271611256a67f37240ec8585f0ec82456 Mon Sep 17 00:00:00 2001
+From: Alan Tull <atull@opensource.altera.com>
+Date: Wed, 7 Oct 2015 16:36:29 +0100
+Subject: [PATCH 4/7] fpga manager: add driver for socfpga fpga manager
+
+Add driver to fpga manager framework to allow configuration
+of FPGA in Altera SoCFPGA parts.
+
+Signed-off-by: Alan Tull <atull@opensource.altera.com>
+Acked-by: Michal Simek <michal.simek@xilinx.com>
+Acked-by: Moritz Fischer <moritz.fischer@ettus.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+(cherry picked from commit fab6266e82a8981cccec55af47589665daf69fb6)
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+---
+ drivers/fpga/Kconfig | 10 +
+ drivers/fpga/Makefile | 1 +
+ drivers/fpga/socfpga.c | 616 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 627 insertions(+)
+ create mode 100644 drivers/fpga/socfpga.c
+
+diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
+index f1f1f6df54d3..dfc1f1ec093b 100644
+--- a/drivers/fpga/Kconfig
++++ b/drivers/fpga/Kconfig
+@@ -11,4 +11,14 @@ config FPGA
+ kernel. The FPGA framework adds a FPGA manager class and FPGA
+ manager drivers.
+
++if FPGA
++
++config FPGA_MGR_SOCFPGA
++ tristate "Altera SOCFPGA FPGA Manager"
++ depends on ARCH_SOCFPGA
++ help
++ FPGA manager driver support for Altera SOCFPGA.
++
++endif # FPGA
++
+ endmenu
+diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
+index 3313c5266795..ba6c5c597a4d 100644
+--- a/drivers/fpga/Makefile
++++ b/drivers/fpga/Makefile
+@@ -6,3 +6,4 @@
+ obj-$(CONFIG_FPGA) += fpga-mgr.o
+
+ # FPGA Manager Drivers
++obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
+diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c
+new file mode 100644
+index 000000000000..706b80d25266
+--- /dev/null
++++ b/drivers/fpga/socfpga.c
+@@ -0,0 +1,616 @@
++/*
++ * FPGA Manager Driver for Altera SOCFPGA
++ *
++ * Copyright (C) 2013-2015 Altera Corporation
++ *
++ * 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 <http://www.gnu.org/licenses/>.
++ */
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/fpga/fpga-mgr.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/pm.h>
++
++/* Register offsets */
++#define SOCFPGA_FPGMGR_STAT_OFST 0x0
++#define SOCFPGA_FPGMGR_CTL_OFST 0x4
++#define SOCFPGA_FPGMGR_DCLKCNT_OFST 0x8
++#define SOCFPGA_FPGMGR_DCLKSTAT_OFST 0xc
++#define SOCFPGA_FPGMGR_GPIO_INTEN_OFST 0x830
++#define SOCFPGA_FPGMGR_GPIO_INTMSK_OFST 0x834
++#define SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST 0x838
++#define SOCFPGA_FPGMGR_GPIO_INT_POL_OFST 0x83c
++#define SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST 0x840
++#define SOCFPGA_FPGMGR_GPIO_RAW_INTSTAT_OFST 0x844
++#define SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST 0x84c
++#define SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST 0x850
++
++/* Register bit defines */
++/* SOCFPGA_FPGMGR_STAT register mode field values */
++#define SOCFPGA_FPGMGR_STAT_POWER_UP 0x0 /*ramping*/
++#define SOCFPGA_FPGMGR_STAT_RESET 0x1
++#define SOCFPGA_FPGMGR_STAT_CFG 0x2
++#define SOCFPGA_FPGMGR_STAT_INIT 0x3
++#define SOCFPGA_FPGMGR_STAT_USER_MODE 0x4
++#define SOCFPGA_FPGMGR_STAT_UNKNOWN 0x5
++#define SOCFPGA_FPGMGR_STAT_STATE_MASK 0x7
++/* This is a flag value that doesn't really happen in this register field */
++#define SOCFPGA_FPGMGR_STAT_POWER_OFF 0x0
++
++#define MSEL_PP16_FAST_NOAES_NODC 0x0
++#define MSEL_PP16_FAST_AES_NODC 0x1
++#define MSEL_PP16_FAST_AESOPT_DC 0x2
++#define MSEL_PP16_SLOW_NOAES_NODC 0x4
++#define MSEL_PP16_SLOW_AES_NODC 0x5
++#define MSEL_PP16_SLOW_AESOPT_DC 0x6
++#define MSEL_PP32_FAST_NOAES_NODC 0x8
++#define MSEL_PP32_FAST_AES_NODC 0x9
++#define MSEL_PP32_FAST_AESOPT_DC 0xa
++#define MSEL_PP32_SLOW_NOAES_NODC 0xc
++#define MSEL_PP32_SLOW_AES_NODC 0xd
++#define MSEL_PP32_SLOW_AESOPT_DC 0xe
++#define SOCFPGA_FPGMGR_STAT_MSEL_MASK 0x000000f8
++#define SOCFPGA_FPGMGR_STAT_MSEL_SHIFT 3
++
++/* SOCFPGA_FPGMGR_CTL register */
++#define SOCFPGA_FPGMGR_CTL_EN 0x00000001
++#define SOCFPGA_FPGMGR_CTL_NCE 0x00000002
++#define SOCFPGA_FPGMGR_CTL_NCFGPULL 0x00000004
++
++#define CDRATIO_X1 0x00000000
++#define CDRATIO_X2 0x00000040
++#define CDRATIO_X4 0x00000080
++#define CDRATIO_X8 0x000000c0
++#define SOCFPGA_FPGMGR_CTL_CDRATIO_MASK 0x000000c0
++
++#define SOCFPGA_FPGMGR_CTL_AXICFGEN 0x00000100
++
++#define CFGWDTH_16 0x00000000
++#define CFGWDTH_32 0x00000200
++#define SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK 0x00000200
++
++/* SOCFPGA_FPGMGR_DCLKSTAT register */
++#define SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE 0x1
++
++/* SOCFPGA_FPGMGR_GPIO_* registers share the same bit positions */
++#define SOCFPGA_FPGMGR_MON_NSTATUS 0x0001
++#define SOCFPGA_FPGMGR_MON_CONF_DONE 0x0002
++#define SOCFPGA_FPGMGR_MON_INIT_DONE 0x0004
++#define SOCFPGA_FPGMGR_MON_CRC_ERROR 0x0008
++#define SOCFPGA_FPGMGR_MON_CVP_CONF_DONE 0x0010
++#define SOCFPGA_FPGMGR_MON_PR_READY 0x0020
++#define SOCFPGA_FPGMGR_MON_PR_ERROR 0x0040
++#define SOCFPGA_FPGMGR_MON_PR_DONE 0x0080
++#define SOCFPGA_FPGMGR_MON_NCONFIG_PIN 0x0100
++#define SOCFPGA_FPGMGR_MON_NSTATUS_PIN 0x0200
++#define SOCFPGA_FPGMGR_MON_CONF_DONE_PIN 0x0400
++#define SOCFPGA_FPGMGR_MON_FPGA_POWER_ON 0x0800
++#define SOCFPGA_FPGMGR_MON_STATUS_MASK 0x0fff
++
++#define SOCFPGA_FPGMGR_NUM_SUPPLIES 3
++#define SOCFPGA_RESUME_TIMEOUT 3
++
++/* In power-up order. Reverse for power-down. */
++static const char *supply_names[SOCFPGA_FPGMGR_NUM_SUPPLIES] __maybe_unused = {
++ "FPGA-1.5V",
++ "FPGA-1.1V",
++ "FPGA-2.5V",
++};
++
++struct socfpga_fpga_priv {
++ void __iomem *fpga_base_addr;
++ void __iomem *fpga_data_addr;
++ struct completion status_complete;
++ int irq;
++};
++
++struct cfgmgr_mode {
++ /* Values to set in the CTRL register */
++ u32 ctrl;
++
++ /* flag that this table entry is a valid mode */
++ bool valid;
++};
++
++/* For SOCFPGA_FPGMGR_STAT_MSEL field */
++static struct cfgmgr_mode cfgmgr_modes[] = {
++ [MSEL_PP16_FAST_NOAES_NODC] = { CFGWDTH_16 | CDRATIO_X1, 1 },
++ [MSEL_PP16_FAST_AES_NODC] = { CFGWDTH_16 | CDRATIO_X2, 1 },
++ [MSEL_PP16_FAST_AESOPT_DC] = { CFGWDTH_16 | CDRATIO_X4, 1 },
++ [MSEL_PP16_SLOW_NOAES_NODC] = { CFGWDTH_16 | CDRATIO_X1, 1 },
++ [MSEL_PP16_SLOW_AES_NODC] = { CFGWDTH_16 | CDRATIO_X2, 1 },
++ [MSEL_PP16_SLOW_AESOPT_DC] = { CFGWDTH_16 | CDRATIO_X4, 1 },
++ [MSEL_PP32_FAST_NOAES_NODC] = { CFGWDTH_32 | CDRATIO_X1, 1 },
++ [MSEL_PP32_FAST_AES_NODC] = { CFGWDTH_32 | CDRATIO_X4, 1 },
++ [MSEL_PP32_FAST_AESOPT_DC] = { CFGWDTH_32 | CDRATIO_X8, 1 },
++ [MSEL_PP32_SLOW_NOAES_NODC] = { CFGWDTH_32 | CDRATIO_X1, 1 },
++ [MSEL_PP32_SLOW_AES_NODC] = { CFGWDTH_32 | CDRATIO_X4, 1 },
++ [MSEL_PP32_SLOW_AESOPT_DC] = { CFGWDTH_32 | CDRATIO_X8, 1 },
++};
++
++static u32 socfpga_fpga_readl(struct socfpga_fpga_priv *priv, u32 reg_offset)
++{
++ return readl(priv->fpga_base_addr + reg_offset);
++}
++
++static void socfpga_fpga_writel(struct socfpga_fpga_priv *priv, u32 reg_offset,
++ u32 value)
++{
++ writel(value, priv->fpga_base_addr + reg_offset);
++}
++
++static u32 socfpga_fpga_raw_readl(struct socfpga_fpga_priv *priv,
++ u32 reg_offset)
++{
++ return __raw_readl(priv->fpga_base_addr + reg_offset);
++}
++
++static void socfpga_fpga_raw_writel(struct socfpga_fpga_priv *priv,
++ u32 reg_offset, u32 value)
++{
++ __raw_writel(value, priv->fpga_base_addr + reg_offset);
++}
++
++static void socfpga_fpga_data_writel(struct socfpga_fpga_priv *priv, u32 value)
++{
++ writel(value, priv->fpga_data_addr);
++}
++
++static inline void socfpga_fpga_set_bitsl(struct socfpga_fpga_priv *priv,
++ u32 offset, u32 bits)
++{
++ u32 val;
++
++ val = socfpga_fpga_readl(priv, offset);
++ val |= bits;
++ socfpga_fpga_writel(priv, offset, val);
++}
++
++static inline void socfpga_fpga_clr_bitsl(struct socfpga_fpga_priv *priv,
++ u32 offset, u32 bits)
++{
++ u32 val;
++
++ val = socfpga_fpga_readl(priv, offset);
++ val &= ~bits;
++ socfpga_fpga_writel(priv, offset, val);
++}
++
++static u32 socfpga_fpga_mon_status_get(struct socfpga_fpga_priv *priv)
++{
++ return socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST) &
++ SOCFPGA_FPGMGR_MON_STATUS_MASK;
++}
++
++static u32 socfpga_fpga_state_get(struct socfpga_fpga_priv *priv)
++{
++ u32 status = socfpga_fpga_mon_status_get(priv);
++
++ if ((status & SOCFPGA_FPGMGR_MON_FPGA_POWER_ON) == 0)
++ return SOCFPGA_FPGMGR_STAT_POWER_OFF;
++
++ return socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_STAT_OFST) &
++ SOCFPGA_FPGMGR_STAT_STATE_MASK;
++}
++
++static void socfpga_fpga_clear_done_status(struct socfpga_fpga_priv *priv)
++{
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST,
++ SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE);
++}
++
++/*
++ * Set the DCLKCNT, wait for DCLKSTAT to report the count completed, and clear
++ * the complete status.
++ */
++static int socfpga_fpga_dclk_set_and_wait_clear(struct socfpga_fpga_priv *priv,
++ u32 count)
++{
++ int timeout = 2;
++ u32 done;
++
++ /* Clear any existing DONE status. */
++ if (socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST))
++ socfpga_fpga_clear_done_status(priv);
++
++ /* Issue the DCLK count. */
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_DCLKCNT_OFST, count);
++
++ /* Poll DCLKSTAT to see if it completed in the timeout period. */
++ do {
++ done = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST);
++ if (done == SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE) {
++ socfpga_fpga_clear_done_status(priv);
++ return 0;
++ }
++ udelay(1);
++ } while (timeout--);
++
++ return -ETIMEDOUT;
++}
++
++static int socfpga_fpga_wait_for_state(struct socfpga_fpga_priv *priv,
++ u32 state)
++{
++ int timeout = 2;
++
++ /*
++ * HW doesn't support an interrupt for changes in state, so poll to see
++ * if it matches the requested state within the timeout period.
++ */
++ do {
++ if ((socfpga_fpga_state_get(priv) & state) != 0)
++ return 0;
++ msleep(20);
++ } while (timeout--);
++
++ return -ETIMEDOUT;
++}
++
++static void socfpga_fpga_enable_irqs(struct socfpga_fpga_priv *priv, u32 irqs)
++{
++ /* set irqs to level sensitive */
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST, 0);
++
++ /* set interrupt polarity */
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INT_POL_OFST, irqs);
++
++ /* clear irqs */
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST, irqs);
++
++ /* unmask interrupts */
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTMSK_OFST, 0);
++
++ /* enable interrupts */
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTEN_OFST, irqs);
++}
++
++static void socfpga_fpga_disable_irqs(struct socfpga_fpga_priv *priv)
++{
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTEN_OFST, 0);
++}
++
++static irqreturn_t socfpga_fpga_isr(int irq, void *dev_id)
++{
++ struct socfpga_fpga_priv *priv = dev_id;
++ u32 irqs, st;
++ bool conf_done, nstatus;
++
++ /* clear irqs */
++ irqs = socfpga_fpga_raw_readl(priv, SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST);
++
++ socfpga_fpga_raw_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST, irqs);
++
++ st = socfpga_fpga_raw_readl(priv, SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST);
++ conf_done = (st & SOCFPGA_FPGMGR_MON_CONF_DONE) != 0;
++ nstatus = (st & SOCFPGA_FPGMGR_MON_NSTATUS) != 0;
++
++ /* success */
++ if (conf_done && nstatus) {
++ /* disable irqs */
++ socfpga_fpga_raw_writel(priv,
++ SOCFPGA_FPGMGR_GPIO_INTEN_OFST, 0);
++ complete(&priv->status_complete);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int socfpga_fpga_wait_for_config_done(struct socfpga_fpga_priv *priv)
++{
++ int timeout, ret = 0;
++
++ socfpga_fpga_disable_irqs(priv);
++ init_completion(&priv->status_complete);
++ socfpga_fpga_enable_irqs(priv, SOCFPGA_FPGMGR_MON_CONF_DONE);
++
++ timeout = wait_for_completion_interruptible_timeout(
++ &priv->status_complete,
++ msecs_to_jiffies(10));
++ if (timeout == 0)
++ ret = -ETIMEDOUT;
++
++ socfpga_fpga_disable_irqs(priv);
++ return ret;
++}
++
++static int socfpga_fpga_cfg_mode_get(struct socfpga_fpga_priv *priv)
++{
++ u32 msel;
++
++ msel = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_STAT_OFST);
++ msel &= SOCFPGA_FPGMGR_STAT_MSEL_MASK;
++ msel >>= SOCFPGA_FPGMGR_STAT_MSEL_SHIFT;
++
++ /* Check that this MSEL setting is supported */
++ if ((msel >= ARRAY_SIZE(cfgmgr_modes)) || !cfgmgr_modes[msel].valid)
++ return -EINVAL;
++
++ return msel;
++}
++
++static int socfpga_fpga_cfg_mode_set(struct socfpga_fpga_priv *priv)
++{
++ u32 ctrl_reg;
++ int mode;
++
++ /* get value from MSEL pins */
++ mode = socfpga_fpga_cfg_mode_get(priv);
++ if (mode < 0)
++ return mode;
++
++ /* Adjust CTRL for the CDRATIO */
++ ctrl_reg = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_CTL_OFST);
++ ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_CDRATIO_MASK;
++ ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK;
++ ctrl_reg |= cfgmgr_modes[mode].ctrl;
++
++ /* Set NCE to 0. */
++ ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_NCE;
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg);
++
++ return 0;
++}
++
++static int socfpga_fpga_reset(struct fpga_manager *mgr)
++{
++ struct socfpga_fpga_priv *priv = mgr->priv;
++ u32 ctrl_reg, status;
++ int ret;
++
++ /*
++ * Step 1:
++ * - Set CTRL.CFGWDTH, CTRL.CDRATIO to match cfg mode
++ * - Set CTRL.NCE to 0
++ */
++ ret = socfpga_fpga_cfg_mode_set(priv);
++ if (ret)
++ return ret;
++
++ /* Step 2: Set CTRL.EN to 1 */
++ socfpga_fpga_set_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
++ SOCFPGA_FPGMGR_CTL_EN);
++
++ /* Step 3: Set CTRL.NCONFIGPULL to 1 to put FPGA in reset */
++ ctrl_reg = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_CTL_OFST);
++ ctrl_reg |= SOCFPGA_FPGMGR_CTL_NCFGPULL;
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg);
++
++ /* Step 4: Wait for STATUS.MODE to report FPGA is in reset phase */
++ status = socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_RESET);
++
++ /* Step 5: Set CONTROL.NCONFIGPULL to 0 to release FPGA from reset */
++ ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_NCFGPULL;
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg);
++
++ /* Timeout waiting for reset */
++ if (status)
++ return -ETIMEDOUT;
++
++ return 0;
++}
++
++/*
++ * Prepare the FPGA to receive the configuration data.
++ */
++static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr, u32 flags,
++ const char *buf, size_t count)
++{
++ struct socfpga_fpga_priv *priv = mgr->priv;
++ int ret;
++
++ if (flags & FPGA_MGR_PARTIAL_RECONFIG) {
++ dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
++ return -EINVAL;
++ }
++ /* Steps 1 - 5: Reset the FPGA */
++ ret = socfpga_fpga_reset(mgr);
++ if (ret)
++ return ret;
++
++ /* Step 6: Wait for FPGA to enter configuration phase */
++ if (socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_CFG))
++ return -ETIMEDOUT;
++
++ /* Step 7: Clear nSTATUS interrupt */
++ socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST,
++ SOCFPGA_FPGMGR_MON_NSTATUS);
++
++ /* Step 8: Set CTRL.AXICFGEN to 1 to enable transfer of config data */
++ socfpga_fpga_set_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
++ SOCFPGA_FPGMGR_CTL_AXICFGEN);
++
++ return 0;
++}
++
++/*
++ * Step 9: write data to the FPGA data register
++ */
++static int socfpga_fpga_ops_configure_write(struct fpga_manager *mgr,
++ const char *buf, size_t count)
++{
++ struct socfpga_fpga_priv *priv = mgr->priv;
++ u32 *buffer_32 = (u32 *)buf;
++ size_t i = 0;
++
++ if (count <= 0)
++ return -EINVAL;
++
++ /* Write out the complete 32-bit chunks. */
++ while (count >= sizeof(u32)) {
++ socfpga_fpga_data_writel(priv, buffer_32[i++]);
++ count -= sizeof(u32);
++ }
++
++ /* Write out remaining non 32-bit chunks. */
++ switch (count) {
++ case 3:
++ socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x00ffffff);
++ break;
++ case 2:
++ socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x0000ffff);
++ break;
++ case 1:
++ socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x000000ff);
++ break;
++ case 0:
++ break;
++ default:
++ /* This will never happen. */
++ return -EFAULT;
++ }
++
++ return 0;
++}
++
++static int socfpga_fpga_ops_configure_complete(struct fpga_manager *mgr,
++ u32 flags)
++{
++ struct socfpga_fpga_priv *priv = mgr->priv;
++ u32 status;
++
++ /*
++ * Step 10:
++ * - Observe CONF_DONE and nSTATUS (active low)
++ * - if CONF_DONE = 1 and nSTATUS = 1, configuration was successful
++ * - if CONF_DONE = 0 and nSTATUS = 0, configuration failed
++ */
++ status = socfpga_fpga_wait_for_config_done(priv);
++ if (status)
++ return status;
++
++ /* Step 11: Clear CTRL.AXICFGEN to disable transfer of config data */
++ socfpga_fpga_clr_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
++ SOCFPGA_FPGMGR_CTL_AXICFGEN);
++
++ /*
++ * Step 12:
++ * - Write 4 to DCLKCNT
++ * - Wait for STATUS.DCNTDONE = 1
++ * - Clear W1C bit in STATUS.DCNTDONE
++ */
++ if (socfpga_fpga_dclk_set_and_wait_clear(priv, 4))
++ return -ETIMEDOUT;
++
++ /* Step 13: Wait for STATUS.MODE to report USER MODE */
++ if (socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_USER_MODE))
++ return -ETIMEDOUT;
++
++ /* Step 14: Set CTRL.EN to 0 */
++ socfpga_fpga_clr_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
++ SOCFPGA_FPGMGR_CTL_EN);
++
++ return 0;
++}
++
++/* Translate state register values to FPGA framework state */
++static const enum fpga_mgr_states socfpga_state_to_framework_state[] = {
++ [SOCFPGA_FPGMGR_STAT_POWER_OFF] = FPGA_MGR_STATE_POWER_OFF,
++ [SOCFPGA_FPGMGR_STAT_RESET] = FPGA_MGR_STATE_RESET,
++ [SOCFPGA_FPGMGR_STAT_CFG] = FPGA_MGR_STATE_WRITE_INIT,
++ [SOCFPGA_FPGMGR_STAT_INIT] = FPGA_MGR_STATE_WRITE_INIT,
++ [SOCFPGA_FPGMGR_STAT_USER_MODE] = FPGA_MGR_STATE_OPERATING,
++ [SOCFPGA_FPGMGR_STAT_UNKNOWN] = FPGA_MGR_STATE_UNKNOWN,
++};
++
++static enum fpga_mgr_states socfpga_fpga_ops_state(struct fpga_manager *mgr)
++{
++ struct socfpga_fpga_priv *priv = mgr->priv;
++ enum fpga_mgr_states ret;
++ u32 state;
++
++ state = socfpga_fpga_state_get(priv);
++
++ if (state < ARRAY_SIZE(socfpga_state_to_framework_state))
++ ret = socfpga_state_to_framework_state[state];
++ else
++ ret = FPGA_MGR_STATE_UNKNOWN;
++
++ return ret;
++}
++
++static const struct fpga_manager_ops socfpga_fpga_ops = {
++ .state = socfpga_fpga_ops_state,
++ .write_init = socfpga_fpga_ops_configure_init,
++ .write = socfpga_fpga_ops_configure_write,
++ .write_complete = socfpga_fpga_ops_configure_complete,
++};
++
++static int socfpga_fpga_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct socfpga_fpga_priv *priv;
++ struct resource *res;
++ int ret;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ priv->fpga_base_addr = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->fpga_base_addr))
++ return PTR_ERR(priv->fpga_base_addr);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ priv->fpga_data_addr = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->fpga_data_addr))
++ return PTR_ERR(priv->fpga_data_addr);
++
++ priv->irq = platform_get_irq(pdev, 0);
++ if (priv->irq < 0)
++ return priv->irq;
++
++ ret = devm_request_irq(dev, priv->irq, socfpga_fpga_isr, 0,
++ dev_name(dev), priv);
++ if (IS_ERR_VALUE(ret))
++ return ret;
++
++ return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
++ &socfpga_fpga_ops, priv);
++}
++
++static int socfpga_fpga_remove(struct platform_device *pdev)
++{
++ fpga_mgr_unregister(&pdev->dev);
++
++ return 0;
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id socfpga_fpga_of_match[] = {
++ { .compatible = "altr,socfpga-fpga-mgr", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, socfpga_fpga_of_match);
++#endif
++
++static struct platform_driver socfpga_fpga_driver = {
++ .probe = socfpga_fpga_probe,
++ .remove = socfpga_fpga_remove,
++ .driver = {
++ .name = "socfpga_fpga_manager",
++ .of_match_table = of_match_ptr(socfpga_fpga_of_match),
++ },
++};
++
++module_platform_driver(socfpga_fpga_driver);
++
++MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
++MODULE_DESCRIPTION("Altera SOCFPGA FPGA Manager");
++MODULE_LICENSE("GPL v2");
+--
+2.6.2
+
diff --git a/patches.altera/0005-MAINTAINERS-add-fpga-manager-framework.patch b/patches.altera/0005-MAINTAINERS-add-fpga-manager-framework.patch
new file mode 100644
index 00000000000000..e2155bd7201f4f
--- /dev/null
+++ b/patches.altera/0005-MAINTAINERS-add-fpga-manager-framework.patch
@@ -0,0 +1,32 @@
+From da7344379a9be3e4bd910bc210f5e93051206a0a Mon Sep 17 00:00:00 2001
+From: Alan Tull <atull@opensource.altera.com>
+Date: Wed, 7 Oct 2015 20:49:23 +0100
+Subject: [PATCH 5/7] MAINTAINERS: add fpga manager framework
+
+Add fpga manager framework to MAINTAINERS and add myself as
+maintainer.
+
+Signed-off-by: Alan Tull <atull@opensource.altera.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+(cherry picked from commit 3c0ed7d56d77b61f2177e8b72855ea32073c2091)
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+---
+ MAINTAINERS | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4089,6 +4089,13 @@ F: include/linux/fmc*.h
+ F: include/linux/ipmi-fru.h
+ K: fmc_d.*register
+
++FPGA MANAGER FRAMEWORK
++M: Alan Tull <atull@opensource.altera.com>
++S: Maintained
++F: drivers/fpga/
++F: include/linux/fpga/fpga-mgr.h
++W: http://www.rocketboards.org
++
+ FPU EMULATOR
+ M: Bill Metzenthen <billm@melbpc.org.au>
+ W: http://floatingpoint.sourceforge.net/emulator/index.html
diff --git a/patches.altera/0006-ARM-socfpga_defconfig-enable-fpga-manager.patch b/patches.altera/0006-ARM-socfpga_defconfig-enable-fpga-manager.patch
new file mode 100644
index 00000000000000..088df8c3ed3aa4
--- /dev/null
+++ b/patches.altera/0006-ARM-socfpga_defconfig-enable-fpga-manager.patch
@@ -0,0 +1,33 @@
+From d221d48b7a18798ea489ece65eb1cbad2980e6c7 Mon Sep 17 00:00:00 2001
+From: Alan Tull <atull@opensource.altera.com>
+Date: Tue, 13 Oct 2015 18:30:02 +0000
+Subject: [PATCH 6/7] ARM: socfpga_defconfig: enable fpga manager
+
+Enable fpga manager framework and low level driver for
+socfpga in socfpga_defconfig
+
+Signed-off-by: Alan Tull <atull@opensource.altera.com>
+Reviewed-by: Moritz Fischer <moritz.fischer@ettus.com>
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+(cherry picked from commit b97cecc7a61df121f2c1e350e09fc784a1706ef0)
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+---
+ arch/arm/configs/socfpga_defconfig | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig
+index a2956c3112f1..8128b93ed72c 100644
+--- a/arch/arm/configs/socfpga_defconfig
++++ b/arch/arm/configs/socfpga_defconfig
+@@ -86,6 +86,8 @@ CONFIG_USB_DWC2=y
+ CONFIG_USB_DWC2_HOST=y
+ CONFIG_MMC=y
+ CONFIG_MMC_DW=y
++CONFIG_FPGA=y
++CONFIG_FPGA_MGR_SOCFPGA=y
+ CONFIG_EXT2_FS=y
+ CONFIG_EXT2_FS_XATTR=y
+ CONFIG_EXT2_FS_POSIX_ACL=y
+--
+2.6.2
+
diff --git a/patches.altera/0007-ARM-socfpga-dts-add-fpga-manager.patch b/patches.altera/0007-ARM-socfpga-dts-add-fpga-manager.patch
new file mode 100644
index 00000000000000..9cdde6b26b4005
--- /dev/null
+++ b/patches.altera/0007-ARM-socfpga-dts-add-fpga-manager.patch
@@ -0,0 +1,32 @@
+From 12269e99151ad7a9157ac8defd76444b01e7d634 Mon Sep 17 00:00:00 2001
+From: Alan Tull <atull@opensource.altera.com>
+Date: Tue, 13 Oct 2015 19:38:59 +0000
+Subject: [PATCH 7/7] ARM: socfpga: dts: add fpga manager
+
+Add FPGA manager to device tree for SoCFPGA.
+
+Signed-off-by: Alan Tull <atull@opensource.altera.com>
+Reviewed-by: Moritz Fischer <moritz.fischer@ettus.com>
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+(cherry picked from commit ebb251030bf25b27b05f0e4204e27b85c5664364)
+Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
+---
+ arch/arm/boot/dts/socfpga.dtsi | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/arch/arm/boot/dts/socfpga.dtsi
++++ b/arch/arm/boot/dts/socfpga.dtsi
+@@ -484,6 +484,13 @@
+ };
+ };
+
++ fpgamgr0: fpgamgr@ff706000 {
++ compatible = "altr,socfpga-fpga-mgr";
++ reg = <0xff706000 0x1000
++ 0xffb90000 0x1000>;
++ interrupts = <0 175 4>;
++ };
++
+ gmac0: ethernet@ff700000 {
+ compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac";
+ altr,sysmgr-syscon = <&sysmgr 0x60 0>;
diff --git a/series b/series
index c1631098a11b53..a9dedde6b29d94 100644
--- a/series
+++ b/series
@@ -406,6 +406,14 @@ patches.altera/0036-EDAC-altera-Add-Arria10-EDAC-support.patch
patches.altera/0037-arm-socfpga-dts-Add-Arria10-SDRAM-EDAC-DTS-support.patch
patches.altera/0038-EDAC-altera-Do-not-allow-suspend-when-EDAC-is-enable.patch
patches.altera/0039-ARM-dts-socfpga-Add-support-of-Terasic-DE0-Atlas-boa.patch
+patches.altera/0001-usage-documentation-for-FPGA-manager-core.patch
+patches.altera/0002-fpga-manager-add-sysfs-interface-document.patch
+patches.altera/0003-add-FPGA-manager-core.patch
+patches.altera/0004-fpga-manager-add-driver-for-socfpga-fpga-manager.patch
+patches.altera/0005-MAINTAINERS-add-fpga-manager-framework.patch
+patches.altera/0006-ARM-socfpga_defconfig-enable-fpga-manager.patch
+patches.altera/0007-ARM-socfpga-dts-add-fpga-manager.patch
+
#############################################################################
# fixes that go after all of the above
@@ -414,3 +422,4 @@ patches.altera/0039-ARM-dts-socfpga-Add-support-of-Terasic-DE0-Atlas-boa.patch
+