| /** | 
 |  * @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; | 
 | } |