static int change_to_bootmode(struct ssp_data *data)
{
	int iCnt;
	int ret;
	char syncb = BL_SPI_SOF;
	struct stm32fwu_spi_cmd dummy_cmd;
	pr_debug("[SSP]%s\n", __func__);

	dummy_cmd.timeout = DEF_ACKCMD_NUMBER;

	gpio_set_value_cansleep(data->rst, 0);
	mdelay(4);
	gpio_set_value_cansleep(data->rst, 1);
	usleep_range(45000, 47000);


	for (iCnt = 0; iCnt < 9; iCnt++) {
		gpio_set_value_cansleep(data->rst, 0);
		mdelay(4);
		gpio_set_value_cansleep(data->rst, 1);
		usleep_range(15000, 15500);
	}

	ret = stm32fwu_spi_write(data->spi, &syncb, 1);
#if SSP_STM_DEBUG
	pr_info("[SSP] stm32fwu_spi_write(sync byte) returned %d\n", ret);
#endif

	ret = stm32fwu_spi_wait_for_ack(data->spi, &dummy_cmd, BL_DUMMY);
#if SSP_STM_DEBUG
	pr_info("[SSP] stm32fwu_spi_wait_for_ack returned %d (0x%x)\n", ret, ret);
#endif

	return ret;
}
static int send_byte_count(struct spi_device *spi, int bytes, int get_ack)
{
	int res;
	uchar bbuff[3];
	struct stm32fwu_spi_cmd dummy_cmd;
	pr_debug("[SSP]%s\n", __func__);

	if (bytes > 256) {
		return -EINVAL;
	}

	bbuff[0] = bytes - 1;
	bbuff[1] = ~bbuff[0];

	res = stm32fwu_spi_write(spi, bbuff, 2);

	if (res <  2) {
		return -EPROTO;
	}

	if (get_ack) {
		dummy_cmd.timeout = DEF_ACKROOF_NUMBER;
		res = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, BL_ACK);

		if (res != BL_ACK) {
			return -EPROTO;
		}
	}
	return 0;
}
Example #3
0
static int fw_erase_stm(struct spi_device *spi)
{
	struct stm32fwu_spi_cmd cmd;
	struct stm32fwu_spi_cmd dummy_cmd;
	int ret;
	char buff[EXT_ER_DATA_LEN] = {0xff, 0xff, 0x00};
	ssp_dbgf();
	cmd.cmd = EXT_ER_COMMAND;
	cmd.xor_cmd = XOR_EXT_ER_COMMAND;
	cmd.timeout = DEF_ACKCMD_NUMBER;
	cmd.ack_pad = BL_DUMMY;

	ret = stm32fwu_spi_send_cmd(spi, &cmd);

	if (ret != BL_ACK) {
		ssp_err("fw_erase failed - %d", ret);
		return ret;
	}

	ret = stm32fwu_spi_write(spi, buff, EXT_ER_DATA_LEN);
	if (ret < EXT_ER_DATA_LEN) {
		ssp_err("fw_erase write failed");
		return 0;
	}

	dummy_cmd.timeout = DEF_ACK_ERASE_NUMBER;

	ret = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, BL_ACK);
	if (ret == BL_ACK)
		return 0;
	else if (ret == BL_NACK)
		return -EPROTO;
	else
		return -ETIME;
}
Example #4
0
static int fw_erase_stm(struct spi_device *spi)
{
	struct stm32fwu_spi_cmd cmd;
	struct stm32fwu_spi_cmd dummy_cmd;
	int ret;
	char buff[EXT_ER_DATA_LEN] = {0xff, 0xff, 0x00};

	cmd.cmd = EXT_ER_COMMAND;
	cmd.xor_cmd = XOR_EXT_ER_COMMAND;
	cmd.timeout = DEF_ACKCMD_NUMBER;
	cmd.ack_pad = 0xFF;

	ret = stm32fwu_spi_send_cmd(spi, &cmd);

	if (ret < 0 || ret != BL_ACK) {
		pr_err("[SSP] fw_erase failed\n");
		return ret;
	}
	if (cmd.ack_loops == 0)
		ret = stm32fwu_spi_write(spi, buff, EXT_ER_DATA_LEN);
	else
		ret = stm32fwu_spi_write(spi, buff, EXT_ER_DATA_LEN-1);

	if (ret < (EXT_ER_DATA_LEN - cmd.ack_loops)) {
		return -EPROTO;
	}
	dummy_cmd.timeout = DEF_ACK_ERASE_NUMBER;
	ret = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, BL_ACK);


	if (ret == BL_ACK)
		return 0;
	else if (ret == BL_NACK)
		return -EPROTO;
	else
		return -ETIME;

}
Example #5
0
static int change_to_bootmode(struct ssp_data *data)
{
	int iCnt;
	int ret;
	char syncb = BL_SPI_SOF;
	int ncount = 5;
	struct stm32fwu_spi_cmd dummy_cmd;
	ssp_dbgf();

	/* dummy_cmd.timeout = DEF_ACKCMD_NUMBER; */
	dummy_cmd.timeout = ncount;

	gpio_set_value_cansleep(data->rst, 0);
	usleep_range(4000, 4400);
	gpio_set_value_cansleep(data->rst, 1);
	usleep_range(45000, 47000);

	for (iCnt = 0; iCnt < 9; iCnt++) {
		gpio_set_value_cansleep(data->rst, 0);
		usleep_range(4000, 4400);
		gpio_set_value_cansleep(data->rst, 1);
		usleep_range(15000, 15500);
	}

	data->spi->mode = SPI_MODE_0;
	if (spi_setup(data->spi))
		ssp_err("failed to setup spi mode for boot");
	usleep_range(1000, 1100);

	msleep(30);

	while (ncount-- >= 0) {
		ret = stm32fwu_spi_write(data->spi, &syncb, 1);
#if SSP_STM_DEBUG
		ssp_info("stm32fwu_spi_write(sync byte) returned %d", ret);
#endif
		ret = stm32fwu_spi_wait_for_ack(data->spi, &dummy_cmd, BL_DUMMY);
#if SSP_STM_DEBUG
		ssp_info("stm32fwu_spi_wait_for_ack returned %d (0x%x)", ret, ret);
#endif
		if (ret == BL_ACK)
			break;
	}

	return ret;
}
static int fw_erase_stm(struct spi_device *spi)
{
	struct stm32fwu_spi_cmd cmd;
	struct stm32fwu_spi_cmd dummy_cmd;
	int ret;
	char buff[EXT_ER_DATA_LEN] = {0xff, 0xff, 0x00};
	pr_debug("[SSP]%s\n", __func__);
	cmd.cmd = EXT_ER_COMMAND;
	cmd.xor_cmd = XOR_EXT_ER_COMMAND;
	cmd.timeout = DEF_ACKCMD_NUMBER;
	cmd.ack_pad = BL_DUMMY;

	ret = stm32fwu_spi_send_cmd(spi, &cmd);
	if (ret < 0 || ret != BL_ACK) {
		pr_err("[SSP] fw_erase failed\n");
		return ret;
	}

	ret = stm32fwu_spi_write(spi, buff, EXT_ER_DATA_LEN);

	if( ret < EXT_ER_DATA_LEN )
	{
		pr_err("[SSP] fw_erase write failed\n");
		return 0;
	}

	dummy_cmd.timeout = DEF_ACK_ERASE_NUMBER;

	ret = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, BL_ACK);

#if SSP_STM_DEBUG
	pr_info("[SSP] %s: stm32fwu_spi_wait_for_ack returned %d (0x%x)\n",
		__func__, ret, ret);
#endif

	if (ret == BL_ACK)
		return 0;
	else if (ret == BL_NACK)
		return -EPROTO;
	else
		return -ETIME;

}
static int fw_write_stm(struct spi_device *spi, u32 fw_addr,
	int len, const u8 *buffer)
{
	int res;
	struct stm32fwu_spi_cmd cmd;
	struct stm32fwu_spi_cmd dummy_cmd;
	int i;
	u8 xor = 0;
	u8 send_buff[STM_MAX_BUFFER_SIZE] = {0,};

	cmd.cmd = WMEM_COMMAND;
	cmd.xor_cmd = XOR_WMEM_COMMAND;
	cmd.timeout = DEF_ACKCMD_NUMBER;
	cmd.ack_pad = (u8)((fw_addr >> 24) & 0xFF);
	pr_debug("[SSP]%s\n", __func__);
#if SSP_STM_DEBUG
	pr_info("[SSP] sending WMEM_COMMAND\n");
#endif

	if (len > STM_MAX_XFER_SIZE) {
		pr_err("[SSP] Can't send more than 256 bytes per transaction\n");
		return -EINVAL;
	}

	send_buff[0] = len - 1;
	memcpy(&send_buff[1], buffer, len);
	for (i = 0; i < (len + 1); i++)
		xor ^= send_buff[i];

	send_buff[len + 1] = xor;

	res = stm32fwu_spi_send_cmd(spi, &cmd);
	if (res != BL_ACK) {
		pr_err("[SSP] Error %d sending read_mem cmd\n", res);
		return res;
	}

	res = send_addr(spi, fw_addr, 0);

	if (res != 0) {
		pr_err("[SSP] Error %d sending write_mem Address\n", res);
		return res;
	}

	res = stm32fwu_spi_write(spi, send_buff, len + 2);
	if (res < len) {
		pr_err("[SSP] Error writing to flash. res = %d\n", res);
		return ((res > 0) ? -EIO : res);
	}
	pr_debug("[SSP]%s 2\n", __func__);

	dummy_cmd.timeout = DEF_ACKROOF_NUMBER;
	usleep_range(100, 150); /* Samsung added */
	res = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, BL_ACK);
	if (res == BL_ACK) {
		return len;
	}

	if (res == BL_NACK) {
		pr_err("[SSP] Got NAK waiting for WRITE_MEM to complete\n");
		return -EPROTO;
	}
	pr_err("[SSP] timeout waiting for ACK for WRITE_MEM command\n");
	return -ETIME;
}
static int stm32fwu_spi_write(struct spi_device *spi,
	const u8 *buffer, ssize_t len)
{
	int ret;
	u8 rx_buf[STM_MAX_BUFFER_SIZE] = {0,};
	struct spi_message m;
#if BYTETOBYTE_USED
	struct spi_transfer t[STM_MAX_BUFFER_SIZE];
	memset(t, 0, STM_MAX_BUFFER_SIZE * sizeof(struct spi_transfer));
	int i;
#else
	struct spi_transfer	t = {
		.tx_buf		= buffer,
		.rx_buf		= rx_buf,
		.len		= len,
		.bits_per_word = 8,
	};
#endif
	spi_message_init(&m);
#if BYTETOBYTE_USED
	for (i = 0; i < len; i++) {
		t[i].tx_buf = &buffer[i];
		t[i].rx_buf = &rx_buf[i];
		t[i].len = 1;
		t[i].bits_per_word = 8;
		t[i].delay_usecs = BYTE_DELAY_WRITE;
		spi_message_add_tail(&t[i], &m);
	}
#else
	spi_message_add_tail(&t, &m);
#endif
	ret = spi_sync(spi, &m);

	if (ret < 0) {
		pr_err("[SSP] Error in %d spi_write()\n", ret);
		return ret;
	}

	return len;
}

static int send_addr(struct spi_device *spi, u32 fw_addr, int send_short)
{
	int res;
	int i = send_short;
	int len = SEND_ADDR_LEN - send_short;
	u8 header[SEND_ADDR_LEN];
	struct stm32fwu_spi_cmd dummy_cmd;
	dummy_cmd.timeout = DEF_ACKROOF_NUMBER;
	pr_debug("[SSP]%s\n", __func__);


	header[0] = (u8)((fw_addr >> 24) & 0xFF);
	header[1] = (u8)((fw_addr >> 16) & 0xFF);
	header[2] = (u8)((fw_addr >> 8) & 0xFF);
	header[3] = (u8)(fw_addr & 0xFF);
	header[4] = header[0] ^ header[1] ^ header[2] ^ header[3];

	res = stm32fwu_spi_write(spi, &header[i], len);

	if (res <  len) {
		pr_err("[SSP] Error in sending address. Res  %d\n", res);
		return ((res > 0) ? -EIO : res);
	}

	res = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, BL_ACK);
	if (res != BL_ACK) {
		pr_err("[SSP] send_addr(): rcv_ack returned 0x%x\n",
			res);
		return res;
	}
	return 0;
}
static void stm32fwu_spi_send_ack( struct spi_device *spi, u8 SyncData )
{
    u8 syncb[2] = {0};
    syncb[0] = SyncData;
    stm32fwu_spi_write(spi, syncb, 1);
}
Example #10
0
static int stm32fwu_spi_wait_for_ack(struct spi_device *spi,
				struct stm32fwu_spi_cmd *cmd, u8 dummy_bytes)
{
	static int check_spi_wait_cnt = 1;

	struct spi_message m;
	char tx_buf = 0x0;
	char rx_buf = 0x0;
	struct spi_transfer	t = {
		.tx_buf		= &tx_buf,
		.rx_buf		= &rx_buf,
		.len		= 1,
		.bits_per_word = 8,
	};
	int i = 0;
	int ret;
	dummy_bytes = BL_DUMMY;
#if SSP_STM_DEBUG
	ssp_infof("dummy byte = 0x%02hhx", dummy_bytes);
#endif
	while (i < cmd->timeout) {
		tx_buf = dummy_bytes;
		spi_message_init(&m);
		spi_message_add_tail(&t, &m);

		ret = spi_sync(spi, &m);

		if (ret < 0) {
			dev_err(&spi->dev, "%s: spi error %d\n", __func__, ret);
			return ret;
		} else if ((rx_buf == BL_ACK) || (rx_buf == BL_NACK)) {
			/* ACK cmd set */
			stm32fwu_spi_send_ack(spi, BL_ACK);
			return (int)rx_buf;
		} else {
			/* Cross cmd set */
			tx_buf = rx_buf;
		}
		if (check_spi_wait_cnt % 20 == 0)
			usleep_range(1000, 1100);
		else
			usleep_range(1000, 1100);
		i++;
		check_spi_wait_cnt++;
	}
#if SSP_STM_DEBUG
	dev_err(&spi->dev, "%s: Timeout after %d loops\n",
			__func__, cmd->timeout);
#endif
	return -EIO;
}

static int stm32fwu_spi_send_cmd(struct spi_device *spi,
				 struct stm32fwu_spi_cmd *cmd)
{
	u8 tx_buf[3] = {0,};
	u8 rx_buf[3] = {0,};
	u8 dummy_byte = 0;
	struct spi_message m;
	int ret;
#if BYTETOBYTE_USED
	int i;
	struct spi_transfer t[STM_MAX_BUFFER_SIZE];
	memset(t, 0, STM_MAX_BUFFER_SIZE * sizeof(struct spi_transfer));
#else
	struct spi_transfer	t = {
		.tx_buf		= tx_buf,
		.rx_buf		= rx_buf,
		.len		= 3,
		.bits_per_word = 8,
	};
#endif
	ssp_dbgf();

	spi_message_init(&m);
	tx_buf[0] = BL_SPI_SOF;
	tx_buf[1] = cmd->cmd;
	tx_buf[2] = cmd->xor_cmd;

#if BYTETOBYTE_USED
	for (i = 0; i < 3; i++) {
		t[i].tx_buf = &tx_buf[i];
		t[i].rx_buf = &rx_buf[i];
		t[i].len = 1;
		t[i].bits_per_word = 8;
		t[i].delay_usecs = BYTE_DELAY_WRITE;
		spi_message_add_tail(&t[i], &m);
	}
#else
	spi_message_add_tail(&t, &m);
#endif

	ret = spi_sync(spi, &m);
	if (ret < 0) {
		dev_err(&spi->dev, "%s: spi error %d\n", __func__, ret);
		return ret;
	}

	dummy_byte = cmd->ack_pad;

	/* check for ack/nack and loop until found */
	ret = stm32fwu_spi_wait_for_ack(spi, cmd, dummy_byte);
	cmd->status = ret;

	if (ret != BL_ACK) {
		ssp_errf("Got NAK or Error %d", ret);
		return ret;
	}

	return ret;
}

static int stm32fwu_spi_write(struct spi_device *spi,
	const u8 *buffer, ssize_t len)
{
	int ret;
	u8 rx_buf[STM_MAX_BUFFER_SIZE] = {0,};
	struct spi_message m;
#if BYTETOBYTE_USED
	struct spi_transfer t[STM_MAX_BUFFER_SIZE];
	memset(t, 0, STM_MAX_BUFFER_SIZE * sizeof(struct spi_transfer));
	int i;
#else
	struct spi_transfer	t = {
		.tx_buf		= buffer,
		.rx_buf		= rx_buf,
		.len		= (unsigned int)len,
		.bits_per_word = 8,
	};
#endif
	spi_message_init(&m);
#if BYTETOBYTE_USED
	for (i = 0; i < len; i++) {
		t[i].tx_buf = &buffer[i];
		t[i].rx_buf = &rx_buf[i];
		t[i].len = 1;
		t[i].bits_per_word = 8;
		t[i].delay_usecs = BYTE_DELAY_WRITE;
		spi_message_add_tail(&t[i], &m);
	}
#else
	spi_message_add_tail(&t, &m);
#endif
	ret = spi_sync(spi, &m);

	if (ret < 0) {
		ssp_err("Error in %d spi_write()", ret);
		return ret;
	}

	return len;
}

static int send_addr(struct spi_device *spi, u32 fw_addr, int send_short)
{
	int res;
	int i = send_short;
	int len = SEND_ADDR_LEN - send_short;
	u8 header[SEND_ADDR_LEN];
	struct stm32fwu_spi_cmd dummy_cmd;
	dummy_cmd.timeout = DEF_ACKROOF_NUMBER;
	ssp_dbgf();

	header[0] = (u8)((fw_addr >> 24) & 0xFF);
	header[1] = (u8)((fw_addr >> 16) & 0xFF);
	header[2] = (u8)((fw_addr >> 8) & 0xFF);
	header[3] = (u8)(fw_addr & 0xFF);
	header[4] = header[0] ^ header[1] ^ header[2] ^ header[3];

	res = stm32fwu_spi_write(spi, &header[i], len);

	if (res < len) {
		ssp_err("Error in sending address. Res %d", res);
		return (res > 0) ? -EIO : res;
	}

	res = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, BL_ACK);
	if (res != BL_ACK) {
		ssp_err("send_addr(): rcv_ack returned 0x%x", res);
		return res;
	}
	return 0;
}