blob: c07d202e8cb51efe49c509295453d705691fe587 [file] [log] [blame]
/**
* @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;
}