[media] drx-j: get rid of drx_driver.c
This file contains just the firmware load code, that it is also somewhat duplicated at drxj.c. Move the code into there. Latter patches will remove the duplicated code. Acked-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
ad55f6c881
commit
b240eacdd5
|
@ -1,4 +1,4 @@
|
||||||
drx39xyj-objs := drx39xxj.o drx_driver.o drx39xxj_dummy.o drxj.o drx_dap_fasi.o
|
drx39xyj-objs := drx39xxj.o drx39xxj_dummy.o drxj.o drx_dap_fasi.o
|
||||||
|
|
||||||
obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj.o
|
obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj.o
|
||||||
|
|
||||||
|
|
|
@ -1,651 +0,0 @@
|
||||||
/*
|
|
||||||
Generic DRX functionality, DRX driver core.
|
|
||||||
|
|
||||||
Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Trident Microsystems nor Hauppauge Computer Works
|
|
||||||
nor the names of its contributors may be used to endorse or promote
|
|
||||||
products derived from this software without specific prior written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
|
||||||
INCLUDE FILES
|
|
||||||
------------------------------------------------------------------------------*/
|
|
||||||
#include "drx_driver.h"
|
|
||||||
|
|
||||||
#define VERSION_MAJOR 0
|
|
||||||
#define VERSION_MINOR 0
|
|
||||||
#define VERSION_PATCH 0
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DEFINES
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MICROCODE RELATED DEFINES
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Magic word for checking correct Endianess of microcode data */
|
|
||||||
#define DRX_UCODE_MAGIC_WORD ((((u16)'H')<<8)+((u16)'L'))
|
|
||||||
|
|
||||||
/* CRC flag in ucode header, flags field. */
|
|
||||||
#define DRX_UCODE_CRC_FLAG (0x0001)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Maximum size of buffer used to verify the microcode.
|
|
||||||
* Must be an even number
|
|
||||||
*/
|
|
||||||
#define DRX_UCODE_MAX_BUF_SIZE (DRXDAP_MAX_RCHUNKSIZE)
|
|
||||||
|
|
||||||
#if DRX_UCODE_MAX_BUF_SIZE & 1
|
|
||||||
#error DRX_UCODE_MAX_BUF_SIZE must be an even number
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Power mode macros
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DRX_ISPOWERDOWNMODE(mode) ((mode == DRX_POWER_MODE_9) || \
|
|
||||||
(mode == DRX_POWER_MODE_10) || \
|
|
||||||
(mode == DRX_POWER_MODE_11) || \
|
|
||||||
(mode == DRX_POWER_MODE_12) || \
|
|
||||||
(mode == DRX_POWER_MODE_13) || \
|
|
||||||
(mode == DRX_POWER_MODE_14) || \
|
|
||||||
(mode == DRX_POWER_MODE_15) || \
|
|
||||||
(mode == DRX_POWER_MODE_16) || \
|
|
||||||
(mode == DRX_POWER_DOWN))
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
|
||||||
STRUCTURES
|
|
||||||
------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct drxu_code_block_hdr - Structure of the microcode block headers
|
|
||||||
*
|
|
||||||
* @addr: Destination address of the data in this block
|
|
||||||
* @size: Size of the block data following this header counted in
|
|
||||||
* 16 bits words
|
|
||||||
* @CRC: CRC value of the data block, only valid if CRC flag is
|
|
||||||
* set.
|
|
||||||
*/
|
|
||||||
struct drxu_code_block_hdr {
|
|
||||||
u32 addr;
|
|
||||||
u16 size;
|
|
||||||
u16 flags;
|
|
||||||
u16 CRC;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
|
||||||
FUNCTIONS
|
|
||||||
------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Microcode related functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* drx_u_code_compute_crc - Compute CRC of block of microcode data.
|
|
||||||
* @block_data: Pointer to microcode data.
|
|
||||||
* @nr_words: Size of microcode block (number of 16 bits words).
|
|
||||||
*
|
|
||||||
* returns The computed CRC residue.
|
|
||||||
*/
|
|
||||||
static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words)
|
|
||||||
{
|
|
||||||
u16 i = 0;
|
|
||||||
u16 j = 0;
|
|
||||||
u32 crc_word = 0;
|
|
||||||
u32 carry = 0;
|
|
||||||
|
|
||||||
while (i < nr_words) {
|
|
||||||
crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
|
|
||||||
for (j = 0; j < 16; j++) {
|
|
||||||
crc_word <<= 1;
|
|
||||||
if (carry != 0)
|
|
||||||
crc_word ^= 0x80050000UL;
|
|
||||||
carry = crc_word & 0x80000000UL;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
block_data += (sizeof(u16));
|
|
||||||
}
|
|
||||||
return (u16)(crc_word >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* drx_check_firmware - checks if the loaded firmware is valid
|
|
||||||
*
|
|
||||||
* @demod: demod structure
|
|
||||||
* @mc_data: pointer to the start of the firmware
|
|
||||||
* @size: firmware size
|
|
||||||
*/
|
|
||||||
static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
|
|
||||||
unsigned size)
|
|
||||||
{
|
|
||||||
struct drxu_code_block_hdr block_hdr;
|
|
||||||
int i;
|
|
||||||
unsigned count = 2 * sizeof(u16);
|
|
||||||
u32 mc_dev_type, mc_version, mc_base_version;
|
|
||||||
u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Scan microcode blocks first for version info
|
|
||||||
* and firmware check
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Clear version block */
|
|
||||||
DRX_ATTR_MCRECORD(demod).aux_type = 0;
|
|
||||||
DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
|
|
||||||
DRX_ATTR_MCRECORD(demod).mc_version = 0;
|
|
||||||
DRX_ATTR_MCRECORD(demod).mc_base_version = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < mc_nr_of_blks; i++) {
|
|
||||||
if (count + 3 * sizeof(u16) + sizeof(u32) > size)
|
|
||||||
goto eof;
|
|
||||||
|
|
||||||
/* Process block header */
|
|
||||||
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
|
|
||||||
count += sizeof(u32);
|
|
||||||
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
|
|
||||||
count += sizeof(u16);
|
|
||||||
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
|
|
||||||
count += sizeof(u16);
|
|
||||||
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
|
|
||||||
count += sizeof(u16);
|
|
||||||
|
|
||||||
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
|
||||||
count, block_hdr.addr, block_hdr.size, block_hdr.flags,
|
|
||||||
block_hdr.CRC);
|
|
||||||
|
|
||||||
if (block_hdr.flags & 0x8) {
|
|
||||||
u8 *auxblk = ((void *)mc_data) + block_hdr.addr;
|
|
||||||
u16 auxtype;
|
|
||||||
|
|
||||||
if (block_hdr.addr + sizeof(u16) > size)
|
|
||||||
goto eof;
|
|
||||||
|
|
||||||
auxtype = be16_to_cpu(*(u32 *)(auxblk));
|
|
||||||
|
|
||||||
/* Aux block. Check type */
|
|
||||||
if (DRX_ISMCVERTYPE(auxtype)) {
|
|
||||||
if (block_hdr.addr + 2 * sizeof(u16) + 2 * sizeof (u32) > size)
|
|
||||||
goto eof;
|
|
||||||
|
|
||||||
auxblk += sizeof(u16);
|
|
||||||
mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
|
|
||||||
auxblk += sizeof(u32);
|
|
||||||
mc_version = be32_to_cpu(*(u32 *)(auxblk));
|
|
||||||
auxblk += sizeof(u32);
|
|
||||||
mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
|
|
||||||
|
|
||||||
DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
|
|
||||||
DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
|
|
||||||
DRX_ATTR_MCRECORD(demod).mc_version = mc_version;
|
|
||||||
DRX_ATTR_MCRECORD(demod).mc_base_version = mc_base_version;
|
|
||||||
|
|
||||||
pr_info("Firmware dev %x, ver %x, base ver %x\n",
|
|
||||||
mc_dev_type, mc_version, mc_base_version);
|
|
||||||
|
|
||||||
}
|
|
||||||
} else if (count + block_hdr.size * sizeof(u16) > size)
|
|
||||||
goto eof;
|
|
||||||
|
|
||||||
count += block_hdr.size * sizeof(u16);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
eof:
|
|
||||||
pr_err("Firmware is truncated at pos %u/%u\n", count, size);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* drx_ctrl_u_code - Handle microcode upload or verify.
|
|
||||||
* @dev_addr: Address of device.
|
|
||||||
* @mc_info: Pointer to information about microcode data.
|
|
||||||
* @action: Either UCODE_UPLOAD or UCODE_VERIFY
|
|
||||||
*
|
|
||||||
* This function returns:
|
|
||||||
* 0:
|
|
||||||
* - In case of UCODE_UPLOAD: code is successfully uploaded.
|
|
||||||
* - In case of UCODE_VERIFY: image on device is equal to
|
|
||||||
* image provided to this control function.
|
|
||||||
* -EIO:
|
|
||||||
* - In case of UCODE_UPLOAD: I2C error.
|
|
||||||
* - In case of UCODE_VERIFY: I2C error or image on device
|
|
||||||
* is not equal to image provided to this control function.
|
|
||||||
* -EINVAL:
|
|
||||||
* - Invalid arguments.
|
|
||||||
* - Provided image is corrupt
|
|
||||||
*/
|
|
||||||
static int drx_ctrl_u_code(struct drx_demod_instance *demod,
|
|
||||||
struct drxu_code_info *mc_info,
|
|
||||||
enum drxu_code_action action)
|
|
||||||
{
|
|
||||||
struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
|
|
||||||
int rc;
|
|
||||||
u16 i = 0;
|
|
||||||
u16 mc_nr_of_blks = 0;
|
|
||||||
u16 mc_magic_word = 0;
|
|
||||||
const u8 *mc_data_init = NULL;
|
|
||||||
u8 *mc_data = NULL;
|
|
||||||
unsigned size;
|
|
||||||
char *mc_file = mc_info->mc_file;
|
|
||||||
|
|
||||||
/* Check arguments */
|
|
||||||
if (!mc_info || !mc_file)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!demod->firmware) {
|
|
||||||
const struct firmware *fw = NULL;
|
|
||||||
|
|
||||||
rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);
|
|
||||||
if (rc < 0) {
|
|
||||||
pr_err("Couldn't read firmware %s\n", mc_file);
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
demod->firmware = fw;
|
|
||||||
|
|
||||||
if (demod->firmware->size < 2 * sizeof(u16)) {
|
|
||||||
rc = -EINVAL;
|
|
||||||
pr_err("Firmware is too short!\n");
|
|
||||||
goto release;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("Firmware %s, size %zu\n",
|
|
||||||
mc_file, demod->firmware->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
mc_data_init = demod->firmware->data;
|
|
||||||
size = demod->firmware->size;
|
|
||||||
|
|
||||||
mc_data = (void *)mc_data_init;
|
|
||||||
/* Check data */
|
|
||||||
mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
|
|
||||||
mc_data += sizeof(u16);
|
|
||||||
mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
|
|
||||||
mc_data += sizeof(u16);
|
|
||||||
|
|
||||||
if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
|
|
||||||
rc = -EINVAL;
|
|
||||||
pr_err("Firmware magic word doesn't match\n");
|
|
||||||
goto release;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action == UCODE_UPLOAD) {
|
|
||||||
rc = drx_check_firmware(demod, (u8 *)mc_data_init, size);
|
|
||||||
if (rc)
|
|
||||||
goto release;
|
|
||||||
|
|
||||||
/* After scanning, validate the microcode.
|
|
||||||
It is also valid if no validation control exists.
|
|
||||||
*/
|
|
||||||
rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL);
|
|
||||||
if (rc != 0 && rc != -ENOTSUPP) {
|
|
||||||
pr_err("Validate ucode not supported\n");
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
pr_info("Uploading firmware %s\n", mc_file);
|
|
||||||
} else if (action == UCODE_VERIFY) {
|
|
||||||
pr_info("Verifying if firmware upload was ok.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process microcode blocks */
|
|
||||||
for (i = 0; i < mc_nr_of_blks; i++) {
|
|
||||||
struct drxu_code_block_hdr block_hdr;
|
|
||||||
u16 mc_block_nr_bytes = 0;
|
|
||||||
|
|
||||||
/* Process block header */
|
|
||||||
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
|
|
||||||
mc_data += sizeof(u32);
|
|
||||||
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
|
|
||||||
mc_data += sizeof(u16);
|
|
||||||
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
|
|
||||||
mc_data += sizeof(u16);
|
|
||||||
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
|
|
||||||
mc_data += sizeof(u16);
|
|
||||||
|
|
||||||
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
|
||||||
(unsigned)(mc_data - mc_data_init), block_hdr.addr,
|
|
||||||
block_hdr.size, block_hdr.flags, block_hdr.CRC);
|
|
||||||
|
|
||||||
/* Check block header on:
|
|
||||||
- data larger than 64Kb
|
|
||||||
- if CRC enabled check CRC
|
|
||||||
*/
|
|
||||||
if ((block_hdr.size > 0x7FFF) ||
|
|
||||||
(((block_hdr.flags & DRX_UCODE_CRC_FLAG) != 0) &&
|
|
||||||
(block_hdr.CRC != drx_u_code_compute_crc(mc_data, block_hdr.size)))
|
|
||||||
) {
|
|
||||||
/* Wrong data ! */
|
|
||||||
rc = -EINVAL;
|
|
||||||
pr_err("firmware CRC is wrong\n");
|
|
||||||
goto release;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!block_hdr.size)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
mc_block_nr_bytes = block_hdr.size * ((u16) sizeof(u16));
|
|
||||||
|
|
||||||
/* Perform the desired action */
|
|
||||||
switch (action) {
|
|
||||||
case UCODE_UPLOAD: /* Upload microcode */
|
|
||||||
if (demod->my_access_funct->write_block_func(dev_addr,
|
|
||||||
block_hdr.addr,
|
|
||||||
mc_block_nr_bytes,
|
|
||||||
mc_data, 0x0000)) {
|
|
||||||
rc = -EIO;
|
|
||||||
pr_err("error writing firmware at pos %u\n",
|
|
||||||
(unsigned)(mc_data - mc_data_init));
|
|
||||||
goto release;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UCODE_VERIFY: { /* Verify uploaded microcode */
|
|
||||||
int result = 0;
|
|
||||||
u8 mc_data_buffer[DRX_UCODE_MAX_BUF_SIZE];
|
|
||||||
u32 bytes_to_comp = 0;
|
|
||||||
u32 bytes_left = mc_block_nr_bytes;
|
|
||||||
u32 curr_addr = block_hdr.addr;
|
|
||||||
u8 *curr_ptr = mc_data;
|
|
||||||
|
|
||||||
while (bytes_left != 0) {
|
|
||||||
if (bytes_left > DRX_UCODE_MAX_BUF_SIZE)
|
|
||||||
bytes_to_comp = DRX_UCODE_MAX_BUF_SIZE;
|
|
||||||
else
|
|
||||||
bytes_to_comp = bytes_left;
|
|
||||||
|
|
||||||
if (demod->my_access_funct->
|
|
||||||
read_block_func(dev_addr,
|
|
||||||
curr_addr,
|
|
||||||
(u16)bytes_to_comp,
|
|
||||||
(u8 *)mc_data_buffer,
|
|
||||||
0x0000)) {
|
|
||||||
pr_err("error reading firmware at pos %u\n",
|
|
||||||
(unsigned)(mc_data - mc_data_init));
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
result =drxbsp_hst_memcmp(curr_ptr,
|
|
||||||
mc_data_buffer,
|
|
||||||
bytes_to_comp);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
pr_err("error verifying firmware at pos %u\n",
|
|
||||||
(unsigned)(mc_data - mc_data_init));
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
curr_addr += ((dr_xaddr_t)(bytes_to_comp / 2));
|
|
||||||
curr_ptr =&(curr_ptr[bytes_to_comp]);
|
|
||||||
bytes_left -=((u32) bytes_to_comp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
mc_data += mc_block_nr_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
release:
|
|
||||||
release_firmware(demod->firmware);
|
|
||||||
demod->firmware = NULL;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*============================================================================*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* drx_ctrl_version - Build list of version information.
|
|
||||||
* @demod: A pointer to a demodulator instance.
|
|
||||||
* @version_list: Pointer to linked list of versions.
|
|
||||||
*
|
|
||||||
* This function returns:
|
|
||||||
* 0: Version information stored in version_list
|
|
||||||
* -EINVAL: Invalid arguments.
|
|
||||||
*/
|
|
||||||
static int drx_ctrl_version(struct drx_demod_instance *demod,
|
|
||||||
struct drx_version_list **version_list)
|
|
||||||
{
|
|
||||||
static char drx_driver_core_module_name[] = "Core driver";
|
|
||||||
static char drx_driver_core_version_text[] =
|
|
||||||
DRX_VERSIONSTRING(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
|
||||||
|
|
||||||
static struct drx_version drx_driver_core_version;
|
|
||||||
static struct drx_version_list drx_driver_core_version_list;
|
|
||||||
|
|
||||||
struct drx_version_list *demod_version_list = NULL;
|
|
||||||
int return_status = -EIO;
|
|
||||||
|
|
||||||
/* Check arguments */
|
|
||||||
if (version_list == NULL)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Get version info list from demod */
|
|
||||||
return_status = (*(demod->my_demod_funct->ctrl_func)) (demod,
|
|
||||||
DRX_CTRL_VERSION,
|
|
||||||
(void *)
|
|
||||||
&demod_version_list);
|
|
||||||
|
|
||||||
/* Always fill in the information of the driver SW . */
|
|
||||||
drx_driver_core_version.module_type = DRX_MODULE_DRIVERCORE;
|
|
||||||
drx_driver_core_version.module_name = drx_driver_core_module_name;
|
|
||||||
drx_driver_core_version.v_major = VERSION_MAJOR;
|
|
||||||
drx_driver_core_version.v_minor = VERSION_MINOR;
|
|
||||||
drx_driver_core_version.v_patch = VERSION_PATCH;
|
|
||||||
drx_driver_core_version.v_string = drx_driver_core_version_text;
|
|
||||||
|
|
||||||
drx_driver_core_version_list.version = &drx_driver_core_version;
|
|
||||||
drx_driver_core_version_list.next = (struct drx_version_list *) (NULL);
|
|
||||||
|
|
||||||
if ((return_status == 0) && (demod_version_list != NULL)) {
|
|
||||||
/* Append versioninfo from driver to versioninfo from demod */
|
|
||||||
/* Return version info in "bottom-up" order. This way, multiple
|
|
||||||
devices can be handled without using malloc. */
|
|
||||||
struct drx_version_list *current_list_element = demod_version_list;
|
|
||||||
while (current_list_element->next != NULL)
|
|
||||||
current_list_element = current_list_element->next;
|
|
||||||
current_list_element->next = &drx_driver_core_version_list;
|
|
||||||
|
|
||||||
*version_list = demod_version_list;
|
|
||||||
} else {
|
|
||||||
/* Just return versioninfo from driver */
|
|
||||||
*version_list = &drx_driver_core_version_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Exported functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* drx_open - Open a demodulator instance.
|
|
||||||
* @demod: A pointer to a demodulator instance.
|
|
||||||
*
|
|
||||||
* This function returns:
|
|
||||||
* 0: Opened demod instance with succes.
|
|
||||||
* -EIO: Driver not initialized or unable to initialize
|
|
||||||
* demod.
|
|
||||||
* -EINVAL: Demod instance has invalid content.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
int drx_open(struct drx_demod_instance *demod)
|
|
||||||
{
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
if ((demod == NULL) ||
|
|
||||||
(demod->my_demod_funct == NULL) ||
|
|
||||||
(demod->my_common_attr == NULL) ||
|
|
||||||
(demod->my_ext_attr == NULL) ||
|
|
||||||
(demod->my_i2c_dev_addr == NULL) ||
|
|
||||||
(demod->my_common_attr->is_opened)) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = (*(demod->my_demod_funct->open_func)) (demod);
|
|
||||||
|
|
||||||
if (status == 0)
|
|
||||||
demod->my_common_attr->is_opened = true;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*============================================================================*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* drx_close - Close device
|
|
||||||
* @demod: A pointer to a demodulator instance.
|
|
||||||
*
|
|
||||||
* Free resources occupied by device instance.
|
|
||||||
* Put device into sleep mode.
|
|
||||||
*
|
|
||||||
* This function returns:
|
|
||||||
* 0: Closed demod instance with succes.
|
|
||||||
* -EIO: Driver not initialized or error during close
|
|
||||||
* demod.
|
|
||||||
* -EINVAL: Demod instance has invalid content.
|
|
||||||
*/
|
|
||||||
int drx_close(struct drx_demod_instance *demod)
|
|
||||||
{
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
if ((demod == NULL) ||
|
|
||||||
(demod->my_demod_funct == NULL) ||
|
|
||||||
(demod->my_common_attr == NULL) ||
|
|
||||||
(demod->my_ext_attr == NULL) ||
|
|
||||||
(demod->my_i2c_dev_addr == NULL) ||
|
|
||||||
(!demod->my_common_attr->is_opened)) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = (*(demod->my_demod_funct->close_func)) (demod);
|
|
||||||
|
|
||||||
DRX_ATTR_ISOPENED(demod) = false;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* drx_ctrl - Control the device.
|
|
||||||
* @demod: A pointer to a demodulator instance.
|
|
||||||
* @ctrl: Reference to desired control function.
|
|
||||||
* @ctrl_data: Pointer to data structure for control function.
|
|
||||||
*
|
|
||||||
* Data needed or returned by the control function is stored in ctrl_data.
|
|
||||||
*
|
|
||||||
* This function returns:
|
|
||||||
* 0: Control function completed successfully.
|
|
||||||
* -EIO: Driver not initialized or error during control demod.
|
|
||||||
* -EINVAL: Demod instance or ctrl_data has invalid content.
|
|
||||||
* -ENOTSUPP: Specified control function is not available.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int drx_ctrl(struct drx_demod_instance *demod, u32 ctrl, void *ctrl_data)
|
|
||||||
{
|
|
||||||
int status = -EIO;
|
|
||||||
|
|
||||||
if ((demod == NULL) ||
|
|
||||||
(demod->my_demod_funct == NULL) ||
|
|
||||||
(demod->my_common_attr == NULL) ||
|
|
||||||
(demod->my_ext_attr == NULL) || (demod->my_i2c_dev_addr == NULL)
|
|
||||||
) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((!demod->my_common_attr->is_opened) &&
|
|
||||||
(ctrl != DRX_CTRL_PROBE_DEVICE) && (ctrl != DRX_CTRL_VERSION))
|
|
||||||
) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode) &&
|
|
||||||
(ctrl != DRX_CTRL_POWER_MODE) &&
|
|
||||||
(ctrl != DRX_CTRL_PROBE_DEVICE) &&
|
|
||||||
(ctrl != DRX_CTRL_NOP) && (ctrl != DRX_CTRL_VERSION)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fixed control functions */
|
|
||||||
switch (ctrl) {
|
|
||||||
/*======================================================================*/
|
|
||||||
case DRX_CTRL_NOP:
|
|
||||||
/* No operation */
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*======================================================================*/
|
|
||||||
case DRX_CTRL_VERSION:
|
|
||||||
return drx_ctrl_version(demod, (struct drx_version_list **)ctrl_data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*======================================================================*/
|
|
||||||
default:
|
|
||||||
/* Do nothing */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Virtual functions */
|
|
||||||
/* First try calling function from derived class */
|
|
||||||
status = (*(demod->my_demod_funct->ctrl_func)) (demod, ctrl, ctrl_data);
|
|
||||||
if (status == -ENOTSUPP) {
|
|
||||||
/* Now try calling a the base class function */
|
|
||||||
switch (ctrl) {
|
|
||||||
/*===================================================================*/
|
|
||||||
case DRX_CTRL_LOAD_UCODE:
|
|
||||||
return drx_ctrl_u_code(demod,
|
|
||||||
(struct drxu_code_info *)ctrl_data,
|
|
||||||
UCODE_UPLOAD);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*===================================================================*/
|
|
||||||
case DRX_CTRL_VERIFY_UCODE:
|
|
||||||
{
|
|
||||||
return drx_ctrl_u_code(demod,
|
|
||||||
(struct drxu_code_info *)ctrl_data,
|
|
||||||
UCODE_VERIFY);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*===================================================================*/
|
|
||||||
default:
|
|
||||||
pr_err("control %d not supported\n", ctrl);
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -39,6 +39,7 @@ INCLUDE FILES
|
||||||
|
|
||||||
#include "drxj.h"
|
#include "drxj.h"
|
||||||
#include "drxj_map.h"
|
#include "drxj_map.h"
|
||||||
|
#include "drx_driver.h"
|
||||||
|
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
/*=== DEFINES ================================================================*/
|
/*=== DEFINES ================================================================*/
|
||||||
|
@ -309,6 +310,40 @@ DEFINES
|
||||||
#define DRX_UIO_MODE_FIRMWARE_SMA DRX_UIO_MODE_FIRMWARE0
|
#define DRX_UIO_MODE_FIRMWARE_SMA DRX_UIO_MODE_FIRMWARE0
|
||||||
#define DRX_UIO_MODE_FIRMWARE_SAW DRX_UIO_MODE_FIRMWARE1
|
#define DRX_UIO_MODE_FIRMWARE_SAW DRX_UIO_MODE_FIRMWARE1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MICROCODE RELATED DEFINES
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Magic word for checking correct Endianess of microcode data */
|
||||||
|
#define DRX_UCODE_MAGIC_WORD ((((u16)'H')<<8)+((u16)'L'))
|
||||||
|
|
||||||
|
/* CRC flag in ucode header, flags field. */
|
||||||
|
#define DRX_UCODE_CRC_FLAG (0x0001)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum size of buffer used to verify the microcode.
|
||||||
|
* Must be an even number
|
||||||
|
*/
|
||||||
|
#define DRX_UCODE_MAX_BUF_SIZE (DRXDAP_MAX_RCHUNKSIZE)
|
||||||
|
|
||||||
|
#if DRX_UCODE_MAX_BUF_SIZE & 1
|
||||||
|
#error DRX_UCODE_MAX_BUF_SIZE must be an even number
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power mode macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DRX_ISPOWERDOWNMODE(mode) ((mode == DRX_POWER_MODE_9) || \
|
||||||
|
(mode == DRX_POWER_MODE_10) || \
|
||||||
|
(mode == DRX_POWER_MODE_11) || \
|
||||||
|
(mode == DRX_POWER_MODE_12) || \
|
||||||
|
(mode == DRX_POWER_MODE_13) || \
|
||||||
|
(mode == DRX_POWER_MODE_14) || \
|
||||||
|
(mode == DRX_POWER_MODE_15) || \
|
||||||
|
(mode == DRX_POWER_MODE_16) || \
|
||||||
|
(mode == DRX_POWER_DOWN))
|
||||||
|
|
||||||
#ifdef DRXJ_SPLIT_UCODE_UPLOAD
|
#ifdef DRXJ_SPLIT_UCODE_UPLOAD
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
/*=== MICROCODE RELATED DEFINES ==============================================*/
|
/*=== MICROCODE RELATED DEFINES ==============================================*/
|
||||||
|
@ -1050,20 +1085,25 @@ struct drxj_hi_cmd {
|
||||||
u16 param6;
|
u16 param6;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DRXJ_SPLIT_UCODE_UPLOAD
|
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
/*=== MICROCODE RELATED STRUCTURES ===========================================*/
|
/*=== MICROCODE RELATED STRUCTURES ===========================================*/
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct drxu_code_block_hdr - Structure of the microcode block headers
|
||||||
|
*
|
||||||
|
* @addr: Destination address of the data in this block
|
||||||
|
* @size: Size of the block data following this header counted in
|
||||||
|
* 16 bits words
|
||||||
|
* @CRC: CRC value of the data block, only valid if CRC flag is
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
struct drxu_code_block_hdr {
|
struct drxu_code_block_hdr {
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u16 size;
|
u16 size;
|
||||||
u16 flags; /* bit[15..2]=reserved,
|
u16 flags;
|
||||||
bit[1]= compression on/off
|
|
||||||
bit[0]= CRC on/off */
|
|
||||||
u16 CRC;
|
u16 CRC;
|
||||||
};
|
};
|
||||||
#endif /* DRXJ_SPLIT_UCODE_UPLOAD */
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
FUNCTIONS
|
FUNCTIONS
|
||||||
|
@ -20607,3 +20647,550 @@ drxj_ctrl(struct drx_demod_instance *demod, u32 ctrl, void *ctrl_data)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Microcode related functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drx_u_code_compute_crc - Compute CRC of block of microcode data.
|
||||||
|
* @block_data: Pointer to microcode data.
|
||||||
|
* @nr_words: Size of microcode block (number of 16 bits words).
|
||||||
|
*
|
||||||
|
* returns The computed CRC residue.
|
||||||
|
*/
|
||||||
|
static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words)
|
||||||
|
{
|
||||||
|
u16 i = 0;
|
||||||
|
u16 j = 0;
|
||||||
|
u32 crc_word = 0;
|
||||||
|
u32 carry = 0;
|
||||||
|
|
||||||
|
while (i < nr_words) {
|
||||||
|
crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
|
||||||
|
for (j = 0; j < 16; j++) {
|
||||||
|
crc_word <<= 1;
|
||||||
|
if (carry != 0)
|
||||||
|
crc_word ^= 0x80050000UL;
|
||||||
|
carry = crc_word & 0x80000000UL;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
block_data += (sizeof(u16));
|
||||||
|
}
|
||||||
|
return (u16)(crc_word >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drx_check_firmware - checks if the loaded firmware is valid
|
||||||
|
*
|
||||||
|
* @demod: demod structure
|
||||||
|
* @mc_data: pointer to the start of the firmware
|
||||||
|
* @size: firmware size
|
||||||
|
*/
|
||||||
|
static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
|
||||||
|
unsigned size)
|
||||||
|
{
|
||||||
|
struct drxu_code_block_hdr block_hdr;
|
||||||
|
int i;
|
||||||
|
unsigned count = 2 * sizeof(u16);
|
||||||
|
u32 mc_dev_type, mc_version, mc_base_version;
|
||||||
|
u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan microcode blocks first for version info
|
||||||
|
* and firmware check
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Clear version block */
|
||||||
|
DRX_ATTR_MCRECORD(demod).aux_type = 0;
|
||||||
|
DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
|
||||||
|
DRX_ATTR_MCRECORD(demod).mc_version = 0;
|
||||||
|
DRX_ATTR_MCRECORD(demod).mc_base_version = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < mc_nr_of_blks; i++) {
|
||||||
|
if (count + 3 * sizeof(u16) + sizeof(u32) > size)
|
||||||
|
goto eof;
|
||||||
|
|
||||||
|
/* Process block header */
|
||||||
|
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
|
||||||
|
count += sizeof(u32);
|
||||||
|
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||||
|
count += sizeof(u16);
|
||||||
|
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||||
|
count += sizeof(u16);
|
||||||
|
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||||
|
count += sizeof(u16);
|
||||||
|
|
||||||
|
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
||||||
|
count, block_hdr.addr, block_hdr.size, block_hdr.flags,
|
||||||
|
block_hdr.CRC);
|
||||||
|
|
||||||
|
if (block_hdr.flags & 0x8) {
|
||||||
|
u8 *auxblk = ((void *)mc_data) + block_hdr.addr;
|
||||||
|
u16 auxtype;
|
||||||
|
|
||||||
|
if (block_hdr.addr + sizeof(u16) > size)
|
||||||
|
goto eof;
|
||||||
|
|
||||||
|
auxtype = be16_to_cpu(*(u32 *)(auxblk));
|
||||||
|
|
||||||
|
/* Aux block. Check type */
|
||||||
|
if (DRX_ISMCVERTYPE(auxtype)) {
|
||||||
|
if (block_hdr.addr + 2 * sizeof(u16) + 2 * sizeof (u32) > size)
|
||||||
|
goto eof;
|
||||||
|
|
||||||
|
auxblk += sizeof(u16);
|
||||||
|
mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
|
||||||
|
auxblk += sizeof(u32);
|
||||||
|
mc_version = be32_to_cpu(*(u32 *)(auxblk));
|
||||||
|
auxblk += sizeof(u32);
|
||||||
|
mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
|
||||||
|
|
||||||
|
DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
|
||||||
|
DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
|
||||||
|
DRX_ATTR_MCRECORD(demod).mc_version = mc_version;
|
||||||
|
DRX_ATTR_MCRECORD(demod).mc_base_version = mc_base_version;
|
||||||
|
|
||||||
|
pr_info("Firmware dev %x, ver %x, base ver %x\n",
|
||||||
|
mc_dev_type, mc_version, mc_base_version);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (count + block_hdr.size * sizeof(u16) > size)
|
||||||
|
goto eof;
|
||||||
|
|
||||||
|
count += block_hdr.size * sizeof(u16);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
eof:
|
||||||
|
pr_err("Firmware is truncated at pos %u/%u\n", count, size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drx_ctrl_u_code - Handle microcode upload or verify.
|
||||||
|
* @dev_addr: Address of device.
|
||||||
|
* @mc_info: Pointer to information about microcode data.
|
||||||
|
* @action: Either UCODE_UPLOAD or UCODE_VERIFY
|
||||||
|
*
|
||||||
|
* This function returns:
|
||||||
|
* 0:
|
||||||
|
* - In case of UCODE_UPLOAD: code is successfully uploaded.
|
||||||
|
* - In case of UCODE_VERIFY: image on device is equal to
|
||||||
|
* image provided to this control function.
|
||||||
|
* -EIO:
|
||||||
|
* - In case of UCODE_UPLOAD: I2C error.
|
||||||
|
* - In case of UCODE_VERIFY: I2C error or image on device
|
||||||
|
* is not equal to image provided to this control function.
|
||||||
|
* -EINVAL:
|
||||||
|
* - Invalid arguments.
|
||||||
|
* - Provided image is corrupt
|
||||||
|
*/
|
||||||
|
static int drx_ctrl_u_code(struct drx_demod_instance *demod,
|
||||||
|
struct drxu_code_info *mc_info,
|
||||||
|
enum drxu_code_action action)
|
||||||
|
{
|
||||||
|
struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
|
||||||
|
int rc;
|
||||||
|
u16 i = 0;
|
||||||
|
u16 mc_nr_of_blks = 0;
|
||||||
|
u16 mc_magic_word = 0;
|
||||||
|
const u8 *mc_data_init = NULL;
|
||||||
|
u8 *mc_data = NULL;
|
||||||
|
unsigned size;
|
||||||
|
char *mc_file = mc_info->mc_file;
|
||||||
|
|
||||||
|
/* Check arguments */
|
||||||
|
if (!mc_info || !mc_file)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!demod->firmware) {
|
||||||
|
const struct firmware *fw = NULL;
|
||||||
|
|
||||||
|
rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("Couldn't read firmware %s\n", mc_file);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
demod->firmware = fw;
|
||||||
|
|
||||||
|
if (demod->firmware->size < 2 * sizeof(u16)) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
pr_err("Firmware is too short!\n");
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("Firmware %s, size %zu\n",
|
||||||
|
mc_file, demod->firmware->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_data_init = demod->firmware->data;
|
||||||
|
size = demod->firmware->size;
|
||||||
|
|
||||||
|
mc_data = (void *)mc_data_init;
|
||||||
|
/* Check data */
|
||||||
|
mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
|
||||||
|
mc_data += sizeof(u16);
|
||||||
|
mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
|
||||||
|
mc_data += sizeof(u16);
|
||||||
|
|
||||||
|
if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
pr_err("Firmware magic word doesn't match\n");
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == UCODE_UPLOAD) {
|
||||||
|
rc = drx_check_firmware(demod, (u8 *)mc_data_init, size);
|
||||||
|
if (rc)
|
||||||
|
goto release;
|
||||||
|
|
||||||
|
/* After scanning, validate the microcode.
|
||||||
|
It is also valid if no validation control exists.
|
||||||
|
*/
|
||||||
|
rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL);
|
||||||
|
if (rc != 0 && rc != -ENOTSUPP) {
|
||||||
|
pr_err("Validate ucode not supported\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
pr_info("Uploading firmware %s\n", mc_file);
|
||||||
|
} else if (action == UCODE_VERIFY) {
|
||||||
|
pr_info("Verifying if firmware upload was ok.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process microcode blocks */
|
||||||
|
for (i = 0; i < mc_nr_of_blks; i++) {
|
||||||
|
struct drxu_code_block_hdr block_hdr;
|
||||||
|
u16 mc_block_nr_bytes = 0;
|
||||||
|
|
||||||
|
/* Process block header */
|
||||||
|
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
|
||||||
|
mc_data += sizeof(u32);
|
||||||
|
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
|
||||||
|
mc_data += sizeof(u16);
|
||||||
|
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
|
||||||
|
mc_data += sizeof(u16);
|
||||||
|
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
|
||||||
|
mc_data += sizeof(u16);
|
||||||
|
|
||||||
|
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
||||||
|
(unsigned)(mc_data - mc_data_init), block_hdr.addr,
|
||||||
|
block_hdr.size, block_hdr.flags, block_hdr.CRC);
|
||||||
|
|
||||||
|
/* Check block header on:
|
||||||
|
- data larger than 64Kb
|
||||||
|
- if CRC enabled check CRC
|
||||||
|
*/
|
||||||
|
if ((block_hdr.size > 0x7FFF) ||
|
||||||
|
(((block_hdr.flags & DRX_UCODE_CRC_FLAG) != 0) &&
|
||||||
|
(block_hdr.CRC != drx_u_code_compute_crc(mc_data, block_hdr.size)))
|
||||||
|
) {
|
||||||
|
/* Wrong data ! */
|
||||||
|
rc = -EINVAL;
|
||||||
|
pr_err("firmware CRC is wrong\n");
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!block_hdr.size)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mc_block_nr_bytes = block_hdr.size * ((u16) sizeof(u16));
|
||||||
|
|
||||||
|
/* Perform the desired action */
|
||||||
|
switch (action) {
|
||||||
|
case UCODE_UPLOAD: /* Upload microcode */
|
||||||
|
if (demod->my_access_funct->write_block_func(dev_addr,
|
||||||
|
block_hdr.addr,
|
||||||
|
mc_block_nr_bytes,
|
||||||
|
mc_data, 0x0000)) {
|
||||||
|
rc = -EIO;
|
||||||
|
pr_err("error writing firmware at pos %u\n",
|
||||||
|
(unsigned)(mc_data - mc_data_init));
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UCODE_VERIFY: { /* Verify uploaded microcode */
|
||||||
|
int result = 0;
|
||||||
|
u8 mc_data_buffer[DRX_UCODE_MAX_BUF_SIZE];
|
||||||
|
u32 bytes_to_comp = 0;
|
||||||
|
u32 bytes_left = mc_block_nr_bytes;
|
||||||
|
u32 curr_addr = block_hdr.addr;
|
||||||
|
u8 *curr_ptr = mc_data;
|
||||||
|
|
||||||
|
while (bytes_left != 0) {
|
||||||
|
if (bytes_left > DRX_UCODE_MAX_BUF_SIZE)
|
||||||
|
bytes_to_comp = DRX_UCODE_MAX_BUF_SIZE;
|
||||||
|
else
|
||||||
|
bytes_to_comp = bytes_left;
|
||||||
|
|
||||||
|
if (demod->my_access_funct->
|
||||||
|
read_block_func(dev_addr,
|
||||||
|
curr_addr,
|
||||||
|
(u16)bytes_to_comp,
|
||||||
|
(u8 *)mc_data_buffer,
|
||||||
|
0x0000)) {
|
||||||
|
pr_err("error reading firmware at pos %u\n",
|
||||||
|
(unsigned)(mc_data - mc_data_init));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
result =drxbsp_hst_memcmp(curr_ptr,
|
||||||
|
mc_data_buffer,
|
||||||
|
bytes_to_comp);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
pr_err("error verifying firmware at pos %u\n",
|
||||||
|
(unsigned)(mc_data - mc_data_init));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr_addr += ((dr_xaddr_t)(bytes_to_comp / 2));
|
||||||
|
curr_ptr =&(curr_ptr[bytes_to_comp]);
|
||||||
|
bytes_left -=((u32) bytes_to_comp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
mc_data += mc_block_nr_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
release:
|
||||||
|
release_firmware(demod->firmware);
|
||||||
|
demod->firmware = NULL;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drx_ctrl_version - Build list of version information.
|
||||||
|
* @demod: A pointer to a demodulator instance.
|
||||||
|
* @version_list: Pointer to linked list of versions.
|
||||||
|
*
|
||||||
|
* This function returns:
|
||||||
|
* 0: Version information stored in version_list
|
||||||
|
* -EINVAL: Invalid arguments.
|
||||||
|
*/
|
||||||
|
static int drx_ctrl_version(struct drx_demod_instance *demod,
|
||||||
|
struct drx_version_list **version_list)
|
||||||
|
{
|
||||||
|
static char drx_driver_core_module_name[] = "Core driver";
|
||||||
|
static char drx_driver_core_version_text[] =
|
||||||
|
DRX_VERSIONSTRING(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||||
|
|
||||||
|
static struct drx_version drx_driver_core_version;
|
||||||
|
static struct drx_version_list drx_driver_core_version_list;
|
||||||
|
|
||||||
|
struct drx_version_list *demod_version_list = NULL;
|
||||||
|
int return_status = -EIO;
|
||||||
|
|
||||||
|
/* Check arguments */
|
||||||
|
if (version_list == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Get version info list from demod */
|
||||||
|
return_status = (*(demod->my_demod_funct->ctrl_func)) (demod,
|
||||||
|
DRX_CTRL_VERSION,
|
||||||
|
(void *)
|
||||||
|
&demod_version_list);
|
||||||
|
|
||||||
|
/* Always fill in the information of the driver SW . */
|
||||||
|
drx_driver_core_version.module_type = DRX_MODULE_DRIVERCORE;
|
||||||
|
drx_driver_core_version.module_name = drx_driver_core_module_name;
|
||||||
|
drx_driver_core_version.v_major = VERSION_MAJOR;
|
||||||
|
drx_driver_core_version.v_minor = VERSION_MINOR;
|
||||||
|
drx_driver_core_version.v_patch = VERSION_PATCH;
|
||||||
|
drx_driver_core_version.v_string = drx_driver_core_version_text;
|
||||||
|
|
||||||
|
drx_driver_core_version_list.version = &drx_driver_core_version;
|
||||||
|
drx_driver_core_version_list.next = (struct drx_version_list *) (NULL);
|
||||||
|
|
||||||
|
if ((return_status == 0) && (demod_version_list != NULL)) {
|
||||||
|
/* Append versioninfo from driver to versioninfo from demod */
|
||||||
|
/* Return version info in "bottom-up" order. This way, multiple
|
||||||
|
devices can be handled without using malloc. */
|
||||||
|
struct drx_version_list *current_list_element = demod_version_list;
|
||||||
|
while (current_list_element->next != NULL)
|
||||||
|
current_list_element = current_list_element->next;
|
||||||
|
current_list_element->next = &drx_driver_core_version_list;
|
||||||
|
|
||||||
|
*version_list = demod_version_list;
|
||||||
|
} else {
|
||||||
|
/* Just return versioninfo from driver */
|
||||||
|
*version_list = &drx_driver_core_version_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exported functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drx_open - Open a demodulator instance.
|
||||||
|
* @demod: A pointer to a demodulator instance.
|
||||||
|
*
|
||||||
|
* This function returns:
|
||||||
|
* 0: Opened demod instance with succes.
|
||||||
|
* -EIO: Driver not initialized or unable to initialize
|
||||||
|
* demod.
|
||||||
|
* -EINVAL: Demod instance has invalid content.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int drx_open(struct drx_demod_instance *demod)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if ((demod == NULL) ||
|
||||||
|
(demod->my_demod_funct == NULL) ||
|
||||||
|
(demod->my_common_attr == NULL) ||
|
||||||
|
(demod->my_ext_attr == NULL) ||
|
||||||
|
(demod->my_i2c_dev_addr == NULL) ||
|
||||||
|
(demod->my_common_attr->is_opened)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = (*(demod->my_demod_funct->open_func)) (demod);
|
||||||
|
|
||||||
|
if (status == 0)
|
||||||
|
demod->my_common_attr->is_opened = true;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drx_close - Close device
|
||||||
|
* @demod: A pointer to a demodulator instance.
|
||||||
|
*
|
||||||
|
* Free resources occupied by device instance.
|
||||||
|
* Put device into sleep mode.
|
||||||
|
*
|
||||||
|
* This function returns:
|
||||||
|
* 0: Closed demod instance with succes.
|
||||||
|
* -EIO: Driver not initialized or error during close
|
||||||
|
* demod.
|
||||||
|
* -EINVAL: Demod instance has invalid content.
|
||||||
|
*/
|
||||||
|
int drx_close(struct drx_demod_instance *demod)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if ((demod == NULL) ||
|
||||||
|
(demod->my_demod_funct == NULL) ||
|
||||||
|
(demod->my_common_attr == NULL) ||
|
||||||
|
(demod->my_ext_attr == NULL) ||
|
||||||
|
(demod->my_i2c_dev_addr == NULL) ||
|
||||||
|
(!demod->my_common_attr->is_opened)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = (*(demod->my_demod_funct->close_func)) (demod);
|
||||||
|
|
||||||
|
DRX_ATTR_ISOPENED(demod) = false;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* drx_ctrl - Control the device.
|
||||||
|
* @demod: A pointer to a demodulator instance.
|
||||||
|
* @ctrl: Reference to desired control function.
|
||||||
|
* @ctrl_data: Pointer to data structure for control function.
|
||||||
|
*
|
||||||
|
* Data needed or returned by the control function is stored in ctrl_data.
|
||||||
|
*
|
||||||
|
* This function returns:
|
||||||
|
* 0: Control function completed successfully.
|
||||||
|
* -EIO: Driver not initialized or error during control demod.
|
||||||
|
* -EINVAL: Demod instance or ctrl_data has invalid content.
|
||||||
|
* -ENOTSUPP: Specified control function is not available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int drx_ctrl(struct drx_demod_instance *demod, u32 ctrl, void *ctrl_data)
|
||||||
|
{
|
||||||
|
int status = -EIO;
|
||||||
|
|
||||||
|
if ((demod == NULL) ||
|
||||||
|
(demod->my_demod_funct == NULL) ||
|
||||||
|
(demod->my_common_attr == NULL) ||
|
||||||
|
(demod->my_ext_attr == NULL) || (demod->my_i2c_dev_addr == NULL)
|
||||||
|
) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((!demod->my_common_attr->is_opened) &&
|
||||||
|
(ctrl != DRX_CTRL_PROBE_DEVICE) && (ctrl != DRX_CTRL_VERSION))
|
||||||
|
) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode) &&
|
||||||
|
(ctrl != DRX_CTRL_POWER_MODE) &&
|
||||||
|
(ctrl != DRX_CTRL_PROBE_DEVICE) &&
|
||||||
|
(ctrl != DRX_CTRL_NOP) && (ctrl != DRX_CTRL_VERSION)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixed control functions */
|
||||||
|
switch (ctrl) {
|
||||||
|
/*======================================================================*/
|
||||||
|
case DRX_CTRL_NOP:
|
||||||
|
/* No operation */
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*======================================================================*/
|
||||||
|
case DRX_CTRL_VERSION:
|
||||||
|
return drx_ctrl_version(demod, (struct drx_version_list **)ctrl_data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*======================================================================*/
|
||||||
|
default:
|
||||||
|
/* Do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Virtual functions */
|
||||||
|
/* First try calling function from derived class */
|
||||||
|
status = (*(demod->my_demod_funct->ctrl_func)) (demod, ctrl, ctrl_data);
|
||||||
|
if (status == -ENOTSUPP) {
|
||||||
|
/* Now try calling a the base class function */
|
||||||
|
switch (ctrl) {
|
||||||
|
/*===================================================================*/
|
||||||
|
case DRX_CTRL_LOAD_UCODE:
|
||||||
|
return drx_ctrl_u_code(demod,
|
||||||
|
(struct drxu_code_info *)ctrl_data,
|
||||||
|
UCODE_UPLOAD);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*===================================================================*/
|
||||||
|
case DRX_CTRL_VERIFY_UCODE:
|
||||||
|
{
|
||||||
|
return drx_ctrl_u_code(demod,
|
||||||
|
(struct drxu_code_info *)ctrl_data,
|
||||||
|
UCODE_VERIFY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*===================================================================*/
|
||||||
|
default:
|
||||||
|
pr_err("control %d not supported\n", ctrl);
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue