aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/meilhaus/mefirmware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/meilhaus/mefirmware.c')
-rw-r--r--drivers/staging/meilhaus/mefirmware.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/drivers/staging/meilhaus/mefirmware.c b/drivers/staging/meilhaus/mefirmware.c
new file mode 100644
index 000000000000..c07d202e8cb5
--- /dev/null
+++ b/drivers/staging/meilhaus/mefirmware.c
@@ -0,0 +1,137 @@
+/**
+ * @file mefirmware.c
+ *
+ * @brief Implements the firmware handling.
+ * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
+ * @author Guenter Gebhardt
+ * @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
+ */
+
+/***************************************************************************
+ * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de) *
+ * Copyright (C) 2007 by Krzysztof Gantzke k.gantzke@meilhaus.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __KERNEL__
+# define __KERNEL__
+#endif
+
+#ifndef KBUILD_MODNAME
+# define KBUILD_MODNAME KBUILD_STR(mefirmware)
+#endif
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <linux/firmware.h>
+
+#include "meplx_reg.h"
+#include "medebug.h"
+
+#include "mefirmware.h"
+
+int me_xilinx_download(unsigned long register_base_control,
+ unsigned long register_base_data,
+ struct device *dev, const char *firmware_name)
+{
+ int err = ME_ERRNO_FIRMWARE;
+ uint32_t value = 0;
+ int idx = 0;
+
+ const struct firmware *fw;
+
+ PDEBUG("executed.\n");
+
+ if (!firmware_name) {
+ PERROR("Request for firmware failed. No name provided. \n");
+ return err;
+ }
+
+ PINFO("Request '%s' firmware.\n", firmware_name);
+ err = request_firmware(&fw, firmware_name, dev);
+
+ if (err) {
+ PERROR("Request for firmware failed.\n");
+ return err;
+ }
+ // Set PLX local interrupt 2 polarity to high.
+ // Interrupt is thrown by init pin of xilinx.
+ outl(PLX_INTCSR_LOCAL_INT2_POL, register_base_control + PLX_INTCSR);
+
+ // Set /CS and /WRITE of the Xilinx
+ value = inl(register_base_control + PLX_ICR);
+ value |= ME_FIRMWARE_CS_WRITE;
+ outl(value, register_base_control + PLX_ICR);
+
+ // Init Xilinx with CS1
+ inl(register_base_data + ME_XILINX_CS1_REG);
+
+ // Wait for init to complete
+ udelay(20);
+
+ // Checkl /INIT pin
+ if (!
+ (inl(register_base_control + PLX_INTCSR) &
+ PLX_INTCSR_LOCAL_INT2_STATE)) {
+ PERROR("Can't init Xilinx.\n");
+ release_firmware(fw);
+ return -EIO;
+ }
+ // Reset /CS and /WRITE of the Xilinx
+ value = inl(register_base_control + PLX_ICR);
+ value &= ~ME_FIRMWARE_CS_WRITE;
+ outl(value, register_base_control + PLX_ICR);
+
+ // Download Xilinx firmware
+ udelay(10);
+
+ for (idx = 0; idx < fw->size; idx++) {
+ outl(fw->data[idx], register_base_data);
+#ifdef ME6000_v2_4
+/// This checking only for board's version 2.4
+ // Check if BUSY flag is set (low = ready, high = busy)
+ if (inl(register_base_control + PLX_ICR) &
+ ME_FIRMWARE_BUSY_FLAG) {
+ PERROR("Xilinx is still busy (idx = %d)\n", idx);
+ release_firmware(fw);
+ return -EIO;
+ }
+#endif //ME6000_v2_4
+ }
+ PDEBUG("Download finished. %d bytes written to PLX.\n", idx);
+
+ // If done flag is high download was successful
+ if (inl(register_base_control + PLX_ICR) & ME_FIRMWARE_DONE_FLAG) {
+ PDEBUG("SUCCESS. Done flag is set.\n");
+ } else {
+ PERROR("FAILURE. DONE flag is not set.\n");
+ release_firmware(fw);
+ return -EIO;
+ }
+
+ // Set /CS and /WRITE
+ value = inl(register_base_control + PLX_ICR);
+ value |= ME_FIRMWARE_CS_WRITE;
+ outl(value, register_base_control + PLX_ICR);
+
+ PDEBUG("Enable interrupts on the PCI interface.\n");
+ outl(ME_PLX_PCI_ACTIVATE, register_base_control + PLX_INTCSR);
+ release_firmware(fw);
+
+ return 0;
+}