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; }
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; }
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; }
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); }
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; }