Commit 018b0c6f authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

[media] siano: make load firmware logic to work with newer firmwares



There are new firmwares for sms2xxx devices. Change the firmware
load logic to handle those newer firmwares and devices.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 73338395
Loading
Loading
Loading
Loading
+214 −134
Original line number Diff line number Diff line
@@ -683,6 +683,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
	/* init completion events */
	init_completion(&dev->version_ex_done);
	init_completion(&dev->data_download_done);
	init_completion(&dev->data_validity_done);
	init_completion(&dev->trigger_done);
	init_completion(&dev->init_device_done);
	init_completion(&dev->reload_start_done);
@@ -753,7 +754,13 @@ EXPORT_SYMBOL_GPL(smscore_register_device);

static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
		void *buffer, size_t size, struct completion *completion) {
	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
	int rc;

	if (completion == NULL)
		return -EINVAL;
	init_completion(completion);

	rc = coredev->sendrequest_handler(coredev->context, buffer, size);
	if (rc < 0) {
		sms_info("sendrequest returned error %d", rc);
		return rc;
@@ -850,8 +857,9 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
					 void *buffer, size_t size)
{
	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
	struct SmsMsgHdr_ST *msg;
	u32 mem_address;
	struct SmsMsgData_ST4 *msg;
	u32 mem_address,  calc_checksum = 0;
	u32 i, *ptr;
	u8 *payload = firmware->Payload;
	int rc = 0;
	firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
@@ -874,34 +882,35 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,

	if (coredev->mode != DEVICE_MODE_NONE) {
		sms_debug("sending reload command.");
		SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
		SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_START_REQ,
			     sizeof(struct SmsMsgHdr_ST));
		rc = smscore_sendrequest_and_wait(coredev, msg,
						  msg->msgLength,
						  msg->xMsgHeader.msgLength,
						  &coredev->reload_start_done);
		if (rc < 0) {
			sms_err("device reload failed, rc %d", rc);
			goto exit_fw_download;
		}
		mem_address = *(u32 *) &payload[20];
	}

	for (i = 0, ptr = (u32 *)firmware->Payload; i < firmware->Length/4 ;
	     i++, ptr++)
		calc_checksum += *ptr;

	while (size && rc >= 0) {
		struct SmsDataDownload_ST *DataMsg =
			(struct SmsDataDownload_ST *) msg;
		int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);

		SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
		SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_DOWNLOAD_REQ,
			     (u16)(sizeof(struct SmsMsgHdr_ST) +
				      sizeof(u32) + payload_size));

		DataMsg->MemAddr = mem_address;
		memcpy(DataMsg->Payload, payload, payload_size);

		if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
		    (coredev->mode == DEVICE_MODE_NONE))
			rc = coredev->sendrequest_handler(
				coredev->context, DataMsg,
				DataMsg->xMsgHeader.msgLength);
		else
			rc = smscore_sendrequest_and_wait(
				coredev, DataMsg,
		rc = smscore_sendrequest_and_wait(coredev, DataMsg,
				DataMsg->xMsgHeader.msgLength,
				&coredev->data_download_done);

@@ -910,44 +919,65 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
		mem_address += payload_size;
	}

	if (rc >= 0) {
	if (rc < 0)
		goto exit_fw_download;

	sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
		calc_checksum);
	SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_VALIDITY_REQ,
			sizeof(msg->xMsgHeader) +
			sizeof(u32) * 3);
	msg->msgData[0] = firmware->StartAddress;
		/* Entry point */
	msg->msgData[1] = firmware->Length;
	msg->msgData[2] = 0; /* Regular checksum*/
	smsendian_handle_tx_message(msg);
	rc = smscore_sendrequest_and_wait(coredev, msg,
					  msg->xMsgHeader.msgLength,
					  &coredev->data_validity_done);
	if (rc < 0)
		goto exit_fw_download;

	if (coredev->mode == DEVICE_MODE_NONE) {
		struct SmsMsgData_ST *TriggerMsg =
			(struct SmsMsgData_ST *) msg;

			SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
		sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
		SMS_INIT_MSG(&msg->xMsgHeader,
				MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
				sizeof(struct SmsMsgHdr_ST) +
				sizeof(u32) * 5);

		TriggerMsg->msgData[0] = firmware->StartAddress;
					/* Entry point */
			TriggerMsg->msgData[1] = 5; /* Priority */
		TriggerMsg->msgData[1] = 6; /* Priority */
		TriggerMsg->msgData[2] = 0x200; /* Stack size */
		TriggerMsg->msgData[3] = 0; /* Parameter */
		TriggerMsg->msgData[4] = 4; /* Task ID */

			if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
				rc = coredev->sendrequest_handler(
					coredev->context, TriggerMsg,
					TriggerMsg->xMsgHeader.msgLength);
				msleep(100);
			} else
				rc = smscore_sendrequest_and_wait(
					coredev, TriggerMsg,
		smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
		rc = smscore_sendrequest_and_wait(coredev, TriggerMsg,
					TriggerMsg->xMsgHeader.msgLength,
					&coredev->trigger_done);
	} else {
			SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
		SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_EXEC_REQ,
				sizeof(struct SmsMsgHdr_ST));

			rc = coredev->sendrequest_handler(coredev->context,
							  msg, msg->msgLength);
		}
		msleep(500);
		smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
		rc = coredev->sendrequest_handler(coredev->context, msg,
				msg->xMsgHeader.msgLength);
	}

	sms_debug("rc=%d, postload=%p ", rc,
		  coredev->postload_handler);
	if (rc < 0)
		goto exit_fw_download;

	/*
	 * backward compatibility - wait to device_ready_done for
	 * not more than 400 ms
	 */
	msleep(400);

exit_fw_download:
	sms_debug("rc=%d, postload=0x%p ", rc, coredev->postload_handler);

	kfree(msg);

@@ -956,6 +986,10 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
		rc;
}


static char *smscore_get_fw_filename(struct smscore_device_t *coredev,
			      int mode, int lookup);

/**
 * loads specified firmware into a buffer and calls device loadfirmware_handler
 *
@@ -967,41 +1001,43 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
 * @return 0 on success, <0 on error.
 */
static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
					   char *filename,
					   int mode, int lookup,
					   loadfirmware_t loadfirmware_handler)
{
	int rc = -ENOENT;
	u8 *fw_buf;
	u32 fw_buf_size;
	const struct firmware *fw;
	u8 *fw_buffer;

	if (loadfirmware_handler == NULL && !(coredev->device_flags &
					      SMS_DEVICE_FAMILY2))
	char *fw_filename = smscore_get_fw_filename(coredev, mode, lookup);
	if (!strcmp(fw_filename, "none"))
		return -ENOENT;

	if (loadfirmware_handler == NULL && !(coredev->device_flags
			& SMS_DEVICE_FAMILY2))
		return -EINVAL;

	rc = request_firmware(&fw, filename, coredev->device);
	rc = request_firmware(&fw, fw_filename, coredev->device);
	if (rc < 0) {
		sms_info("failed to open \"%s\"", filename);
		sms_info("failed to open \"%s\"", fw_filename);
		return rc;
	}
	sms_info("read FW %s, size=%zd", filename, fw->size);
	fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
	sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size);
	fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
			 GFP_KERNEL | GFP_DMA);
	if (fw_buffer) {
		memcpy(fw_buffer, fw->data, fw->size);

		rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
		      smscore_load_firmware_family2(coredev,
						    fw_buffer,
						    fw->size) :
		      loadfirmware_handler(coredev->context,
					   fw_buffer, fw->size);

		kfree(fw_buffer);
	} else {
	if (!fw_buf) {
		sms_info("failed to allocate firmware buffer");
		rc = -ENOMEM;
		return -ENOMEM;
	}
	memcpy(fw_buf, fw->data, fw->size);
	fw_buf_size = fw->size;

	rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
		smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
		: loadfirmware_handler(coredev->context, fw_buf,
		fw_buf_size);

	kfree(fw_buf);
	release_firmware(fw);

	return rc;
@@ -1050,7 +1086,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)

		sms_info("waiting for %d buffer(s)",
			 coredev->num_buffers - num_buffers);
		kmutex_unlock(&g_smscore_deviceslock);
		msleep(100);
		kmutex_lock(&g_smscore_deviceslock);
	}

	sms_info("freed %d buffers", num_buffers);
@@ -1107,30 +1145,73 @@ static int smscore_detect_mode(struct smscore_device_t *coredev)
}

static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
	/*Stellar		NOVA A0		Nova B0		VEGA*/
	/*Stellar, NOVA A0, Nova B0, VEGA, VENICE, MING, PELE, RIO, DENVER_1530, DENVER_2160 */
		/*DVBT*/
	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
	{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvb_rio.inp", "none", "none" },
		/*DVBH*/
	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
	{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvbh_rio.inp", "none", "none" },
		/*TDMB*/
	{"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
	{ "none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none", "none", "none", "none", "none", "none", "tdmb_denver.inp" },
		/*DABIP*/
	{"none", "none", "none", "none"},
	/*BDA*/
	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
	{ "none", "none", "none", "none", "none", "none", "none", "none", "none", "none" },
		/*DVBT_BDA*/
	{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvb_rio.inp", "none", "none" },
		/*ISDBT*/
	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
	/*ISDBTBDA*/
	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
	{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none", "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" },
		/*ISDBT_BDA*/
	{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none", "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" },
		/*CMMB*/
	{"none", "none", "none", "cmmb_vega_12mhz.inp"}
	{ "none", "none", "none", "cmmb_vega_12mhz.inp", "cmmb_venice_12mhz.inp", "cmmb_ming_app.inp", "none", "none", "none", 	"none" },
		/*RAW - not supported*/
	{ "none", "none", "none", "none", "none", "none", "none", "none", "none", "none" },
		/*FM*/
	{ "none", "none", "fm_radio.inp", "none", "none", "none", "none", "fm_radio_rio.inp", "none", "none" },
		/*FM_BDA*/
	{ "none", "none", "fm_radio.inp", "none", "none", "none", "none", "fm_radio_rio.inp", "none", "none" },
		/*ATSC*/
	{ "none", "none", "none", "none", "none", "none", "none", "none", "atsc_denver.inp", "none" }
};

static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
				    int mode, enum sms_device_type_st type)
/**
 * get firmware file name from one of the two mechanisms : sms_boards or
 * smscore_fw_lkup.
 * @param coredev pointer to a coredev object returned by
 *		  smscore_register_device
 * @param mode requested mode of operation
 * @param lookup if 1, always get the fw filename from smscore_fw_lkup
 *	 table. if 0, try first to get from sms_boards
 *
 * @return 0 on success, <0 on error.
 */
static char *smscore_get_fw_filename(struct smscore_device_t *coredev,
			      int mode, int lookup)
{
	char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
	return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
	char **fw;
	int board_id = smscore_get_board_id(coredev);
	enum sms_device_type_st type = smscore_registry_gettype(coredev->devpath);

	if ((board_id == SMS_BOARD_UNKNOWN) || (lookup == 1)) {
		sms_debug("trying to get fw name from lookup table mode %d type %d",
			  mode, type);
		return smscore_fw_lkup[mode][type];
	}

	sms_debug("trying to get fw name from sms_boards board_id %d mode %d",
		  board_id, mode);
	fw = sms_get_board(board_id)->fw;
	if (fw == NULL) {
		sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d",
			  mode, type);
		return smscore_fw_lkup[mode][type];
	}

	if (fw[mode] == NULL) {
		sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d",
			  mode, type);
		return smscore_fw_lkup[mode][type];
	}

	return fw[mode];
}

/**
@@ -1145,9 +1226,7 @@ static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
 */
int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
{
	void *buffer;
	int rc = 0;
	enum sms_device_type_st type;

	sms_debug("set device mode to %d", mode);
	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
@@ -1172,55 +1251,30 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
		}

		if (!(coredev->modes_supported & (1 << mode))) {
			char *fw_filename;

			type = smscore_registry_gettype(coredev->devpath);
			fw_filename = sms_get_fw_name(coredev, mode, type);

			rc = smscore_load_firmware_from_file(coredev,
							     fw_filename, NULL);
			if (rc < 0) {
				sms_warn("error %d loading firmware: %s, "
					 "trying again with default firmware",
					 rc, fw_filename);
							     mode, 0, NULL);

				/* try again with the default firmware */
				fw_filename = smscore_fw_lkup[mode][type];
			/*
			* try again with the default firmware -
			* get the fw filename from look-up table
			*/
			if (rc < 0) {
				sms_debug("error %d loading firmware, trying again with default firmware",
					  rc);
				rc = smscore_load_firmware_from_file(coredev,
							     fw_filename, NULL);

								     mode, 1,
								     NULL);
				if (rc < 0) {
					sms_warn("error %d loading "
						 "firmware: %s", rc,
						 fw_filename);
					sms_debug("error %d loading firmware",
						  rc);
					return rc;
				}
			}
			sms_log("firmware download success: %s", fw_filename);
		} else
			sms_info("mode %d supported by running "
				 "firmware", mode);

		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
		if (buffer) {
			struct SmsMsgData_ST *msg =
				(struct SmsMsgData_ST *)
					SMS_ALIGN_ADDRESS(buffer);

			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
				     sizeof(struct SmsMsgData_ST));
			msg->msgData[0] = mode;

			rc = smscore_sendrequest_and_wait(
				coredev, msg, msg->xMsgHeader.msgLength,
				&coredev->init_device_done);

			kfree(buffer);
			if (rc >= 0)
				sms_info("firmware download success");
		} else {
			sms_err("Could not allocate buffer for "
				"init device message.");
			rc = -ENOMEM;
			sms_info("mode %d is already supported by running firmware",
				 mode);
		}
	} else {
		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
@@ -1239,8 +1293,25 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
	}

	if (rc >= 0) {
		char *buffer;
		coredev->mode = mode;
		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;

		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
		if (buffer) {
			struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *) SMS_ALIGN_ADDRESS(buffer);

			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
				     sizeof(struct SmsMsgData_ST));
			msg->msgData[0] = mode;

			rc = smscore_sendrequest_and_wait(
				coredev, msg, msg->xMsgHeader.msgLength,
				&coredev->init_device_done);

			kfree(buffer);
		}
	}

	if (rc < 0)
@@ -1371,6 +1442,15 @@ void smscore_onresponse(struct smscore_device_t *coredev,
		case MSG_SW_RELOAD_START_RES:
			complete(&coredev->reload_start_done);
			break;
		case MSG_SMS_DATA_VALIDITY_RES:
		{
			struct SmsMsgData_ST *validity = (struct SmsMsgData_ST *) phdr;

			sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
				validity->msgData[0]);
			complete(&coredev->data_validity_done);
			break;
		}
		case MSG_SMS_DATA_DOWNLOAD_RES:
			complete(&coredev->data_download_done);
			break;
+6 −2
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ struct smscore_device_t {

	/* host <--> device messages */
	struct completion version_ex_done, data_download_done, trigger_done;
	struct completion data_validity_done, device_ready_done;
	struct completion init_device_done, reload_start_done, resume_done;
	struct completion gpio_configuration_done, gpio_set_level_done;
	struct completion gpio_get_level_done, ir_init_done;
@@ -594,6 +595,11 @@ struct SmsMsgData_ST2 {
	u32 msgData[2];
};

struct SmsMsgData_ST4 {
	struct SmsMsgHdr_ST xMsgHeader;
	u32 msgData[4];
};

struct SmsDataDownload_ST {
	struct SmsMsgHdr_ST	xMsgHeader;
	u32			MemAddr;
@@ -998,8 +1004,6 @@ extern void smscore_onresponse(struct smscore_device_t *coredev,
extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
				      struct vm_area_struct *vma);
extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
				   int mode, char *filename);
extern int smscore_send_fw_file(struct smscore_device_t *coredev,
				u8 *ufwbuf, int size);