diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-11-27 17:38:56 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-11-27 17:38:56 -0800 |
commit | ab2fa693c905f2dd6ad435082fa8c175a1ddbd23 (patch) | |
tree | a93c56e1049d6817f42429e34b6cc1377f8092a4 | |
parent | 7dcbe3014ffc969629a250b4c614a43856a585ea (diff) | |
download | ltsi-kernel-ab2fa693c905f2dd6ad435082fa8c175a1ddbd23.tar.gz |
Altera fpga patches
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>; @@ -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 + |