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 update_mcu_bin(struct ssp_data *data, int iBinType) { int retry = BLMODE_RETRYCOUNT; int iRet = SUCCESS; struct stm32fwu_spi_cmd cmd; cmd.cmd = GO_COMMAND; cmd.xor_cmd = XOR_GO_COMMAND; cmd.timeout = 1000; cmd.ack_pad = (u8)((STM_APP_ADDR >> 24) & 0xFF); /* 1. Start system boot mode */ do { iRet = change_to_bootmode(data); ssp_info("bootmode %d retry: %d", iRet, 3 - retry); } while (retry-- > 0 && iRet != BL_ACK); if (iRet != BL_ACK) { ssp_errf("change_to_bootmode %d", iRet); return iRet; } /* 2. Flash erase all */ iRet = fw_erase_stm(data->spi); if (iRet < 0) { ssp_errf("fw_erase_stm %d", iRet); return iRet; } switch (iBinType) { case KERNEL_BINARY: /* HW request: I2C line is reversed */ iRet = load_kernel_fw_bootmode(data->spi, BL_FW_NAME); break; case KERNEL_CRASHED_BINARY: iRet = load_kernel_fw_bootmode(data->spi, BL_CRASHED_FW_NAME); break; case UMS_BINARY: iRet = load_ums_fw_bootmode(data->spi, BL_UMS_FW_NAME); break; default: ssp_err("binary type error!!"); } /* STM : GO USER ADDR */ stm32fwu_spi_send_cmd(data->spi, &cmd); send_addr(data->spi, STM_APP_ADDR, 0); data->spi->mode = SPI_MODE_1; if (spi_setup(data->spi)) ssp_err("failed to setup spi mode for app"); usleep_range(1000, 1100); return iRet; }
int check_fwbl(struct ssp_data *data) { unsigned int fw_revision; fw_revision = SSP_FIRMWARE_REVISION_STM; data->uCurFirmRev = get_firmware_rev(data); if ((data->uCurFirmRev == SSP_INVALID_REVISION) || (data->uCurFirmRev == SSP_INVALID_REVISION2)) { data->uCurFirmRev = SSP_INVALID_REVISION; ssp_err("SSP_INVALID_REVISION"); return FW_DL_STATE_NEED_TO_SCHEDULE; } else { if (data->uCurFirmRev != fw_revision) { ssp_info("MCU Firm Rev : Old = %8u, New = %8u", data->uCurFirmRev, fw_revision); return FW_DL_STATE_NEED_TO_SCHEDULE; } ssp_info("MCU Firm Rev : Old = %8u, New = %8u", data->uCurFirmRev, fw_revision); } return FW_DL_STATE_NONE; }
int forced_to_download_binary(struct ssp_data *data, int iBinType) { int iRet = 0; int retry = 3; ssp_infof("mcu binany update!"); ssp_enable(data, false); data->fw_dl_state = FW_DL_STATE_DOWNLOADING; ssp_infof("DL state = %d", data->fw_dl_state); data->spi->max_speed_hz = BOOT_SPI_HZ; if (spi_setup(data->spi)) ssp_err("failed to setup spi for ssp_boot"); do { ssp_info("%d try", 3 - retry); iRet = update_mcu_bin(data, iBinType); } while (retry-- > 0 && iRet < 0); data->spi->max_speed_hz = NORM_SPI_HZ; if (spi_setup(data->spi)) ssp_err("failed to setup spi for ssp_norm"); if (iRet < 0) { ssp_infof("update_mcu_bin failed!"); goto out; } data->fw_dl_state = FW_DL_STATE_SYNC; ssp_infof("DL state = %d", data->fw_dl_state); ssp_enable(data, true); get_proximity_threshold(data); proximity_open_calibration(data); accel_open_calibration(data); gyro_open_calibration(data); pressure_open_calibration(data); data->fw_dl_state = FW_DL_STATE_DONE; ssp_infof("DL state = %d", data->fw_dl_state); iRet = SUCCESS; out: return iRet; }
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 ssp_parse_dt(struct device *dev, struct ssp_data *data) { struct device_node *np = dev->of_node; enum of_gpio_flags flags; int errorno = 0; /* gpio pins */ data->mcu_int1 = of_get_named_gpio_flags(np, "ssp,mcu_int1-gpio", 0, &flags); if (data->mcu_int1 < 0) { errorno = data->mcu_int1; goto dt_exit; } data->mcu_int2 = of_get_named_gpio_flags(np, "ssp,mcu_int2-gpio", 0, &flags); if (data->mcu_int2 < 0) { errorno = data->mcu_int2; goto dt_exit; } data->ap_int = of_get_named_gpio_flags(np, "ssp,ap_int-gpio", 0, &flags); if (data->ap_int < 0) { errorno = data->ap_int; goto dt_exit; } data->rst = of_get_named_gpio_flags(np, "ssp,rst-gpio", 0, &flags); if (data->rst < 0) { errorno = data->rst; goto dt_exit; } /* sensor positions */ if (of_property_read_u32(np, "ssp,acc-position", &data->accel_position)) data->accel_position = 0; if (of_property_read_u32(np, "ssp,mag-position", &data->mag_position)) data->mag_position = 0; ssp_info("acc-posi[%d] mag-posi[%d]", data->accel_position, data->mag_position); /* prox thresh */ if (of_property_read_u32(np, "ssp,prox-hi_thresh", &data->uProxHiThresh_default)) data->uProxHiThresh_default = DEFUALT_HIGH_THRESHOLD; if (of_property_read_u32(np, "ssp,prox-low_thresh", &data->uProxLoThresh_default)) data->uProxLoThresh_default = DEFUALT_LOW_THRESHOLD; ssp_info("hi-thresh[%u] low-thresh[%u]", data->uProxHiThresh_default, data->uProxLoThresh_default); #ifdef CONFIG_SENSORS_MULTIPLE_GLASS_TYPE if (of_property_read_u32(np, "ssp-glass-type", &data->glass_type)) data->glass_type = 0; #endif /* mag matrix */ if (of_property_read_u8_array(np, "ssp,mag-array", data->pdc_matrix, sizeof(data->pdc_matrix))) { ssp_err("no mag-array, set as 0"); } /* set off gpio pins */ errorno = gpio_request(data->mcu_int1, "mcu_ap_int1"); if (errorno) { ssp_err("failed to request MCU_INT1 for SSP"); goto dt_exit; } errorno = gpio_direction_input(data->mcu_int1); if (errorno) { ssp_err("failed to set mcu_int1 as input"); goto dt_exit; } errorno = gpio_request(data->mcu_int2, "MCU_INT2"); if (errorno) { ssp_err("failed to request MCU_INT2 for SSP"); goto dt_exit; } gpio_direction_input(data->mcu_int2); errorno = gpio_request(data->ap_int, "AP_MCU_INT"); if (errorno) { ssp_err("failed to request AP_INT for SSP"); goto dt_exit; } gpio_direction_output(data->ap_int, 1); errorno = gpio_request(data->rst, "MCU_RST"); if (errorno) { ssp_err("failed to request MCU_RST for SSP"); goto dt_exit; } gpio_direction_output(data->rst, 1); dt_exit: return errorno; }
int debug_crash_dump(struct ssp_data *data, char *pchRcvDataFrame, int iLength) { struct timeval cur_time; char strFilePath[100]; int iRetWrite = 0; unsigned char datacount = pchRcvDataFrame[1]; unsigned int databodysize = iLength - 2; char *databody = &pchRcvDataFrame[2]; /* if(iLength != DEBUG_DUMP_DATA_SIZE) { ssp_errf("data length error(%d)", iLength); return FAIL; } else ssp_errf("length(%d)", databodysize); */ ssp_errf("length(%d)", databodysize); if (data->bSspShutdown) { ssp_infof("ssp shutdown, stop dumping"); return FAIL; } if (data->bMcuDumpMode == true) { wake_lock(&data->ssp_wake_lock); if (data->realtime_dump_file == NULL) { backup_fs = get_fs(); set_fs(get_ds()); do_gettimeofday(&cur_time); snprintf(strFilePath, sizeof(strFilePath), "%s%d.dump", DEBUG_DUMP_FILE_PATH, (int)cur_time.tv_sec); data->realtime_dump_file = filp_open(strFilePath, O_RDWR | O_CREAT | O_APPEND, 0660); ssp_err("save_crash_dump : open file(%s)", strFilePath); if (IS_ERR(data->realtime_dump_file)) { ssp_errf("Can't open dump file"); set_fs(backup_fs); data->realtime_dump_file = NULL; wake_unlock(&data->ssp_wake_lock); return FAIL; } } data->total_dump_size += databodysize; /* ssp_errf("total receive size(%d)", data->total_dump_size); */ iRetWrite = vfs_write(data->realtime_dump_file, (char __user *)databody, databodysize, &data->realtime_dump_file->f_pos); if (iRetWrite < 0) { ssp_errf("Can't write dump to file"); wake_unlock(&data->ssp_wake_lock); return FAIL; } if (datacount == DEBUG_DUMP_DATA_COMPLETE) { ssp_errf("close file(size=%d)", data->total_dump_size); filp_close(data->realtime_dump_file, current->files); set_fs(backup_fs); data->uDumpCnt++; data->total_dump_size = 0; data->realtime_dump_file = NULL; data->bDumping = false; } wake_unlock(&data->ssp_wake_lock); /* if(iLength == 2*1024) queue_refresh_task(data, 0); */ } return SUCCESS; }
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; }
static int load_kernel_fw_bootmode(struct spi_device *spi, const char *pFn) { const struct firmware *fw = NULL; int remaining; unsigned int uPos = 0; unsigned int fw_addr = STM_APP_ADDR; int iRet; int block = STM_MAX_XFER_SIZE; int count = 0; int err_count = 0; int retry_count = 0; ssp_info("ssp_load_fw start!!"); iRet = request_firmware(&fw, pFn, &spi->dev); if (iRet) { ssp_err("Unable to open firmware %s", pFn); return iRet; } remaining = fw->size; while (remaining > 0) { if (block > remaining) block = remaining; while (retry_count < 3) { iRet = fw_write_stm(spi, fw_addr, block, fw->data+uPos); if (iRet < block) { ssp_err("Err writing to addr 0x%08X", fw_addr); if (iRet < 0) { ssp_err("Error was %d", iRet); } else { ssp_err("Incomplete write of %d bytes", iRet); iRet = -EIO; } retry_count++; err_count++; } else { retry_count = 0; break; } } if (iRet < 0) { ssp_err("Writing MEM failed: %d, retry cont: %d", iRet, err_count); goto out_load_kernel; } remaining -= block; uPos += block; fw_addr += block; if (count++ == 20) { ssp_info("Updated %u bytes / %u bytes", uPos, (unsigned int)fw->size); count = 0; } } ssp_info("Firmware download is success(%d bytes, retry %d)", uPos, err_count); out_load_kernel: release_firmware(fw); return iRet; }
static int load_ums_fw_bootmode(struct spi_device *spi, const char *pFn) { const u8 *buff = NULL; char fw_path[BL_UMS_FW_PATH+1]; unsigned int uFSize = 0, uNRead = 0; unsigned int uPos = 0; int iRet = SUCCESS; int remaining; int block = STM_MAX_XFER_SIZE; unsigned int fw_addr = STM_APP_ADDR; int retry_count = 0; int err_count = 0; int count = 0; struct file *fp = NULL; mm_segment_t old_fs = get_fs(); ssp_info("ssp_load_ums_fw start!!"); old_fs = get_fs(); set_fs(get_ds()); snprintf(fw_path, BL_UMS_FW_PATH, "/sdcard/ssp/%s", pFn); fp = filp_open(fw_path, O_RDONLY, 0); if (IS_ERR(fp)) { iRet = ERROR; ssp_err("file %s open error", fw_path); goto err_open; } uFSize = (unsigned int)fp->f_path.dentry->d_inode->i_size; ssp_info("ssp_load_ums firmware size: %u", uFSize); buff = kzalloc((size_t)STM_MAX_XFER_SIZE, GFP_KERNEL); if (!buff) { iRet = ERROR; ssp_err("fail to alloc buffer for fw"); goto err_alloc; } remaining = uFSize; while (remaining > 0) { if (block > remaining) block = remaining; uNRead = (unsigned int)vfs_read(fp, (char __user *)buff, (unsigned int)block, &fp->f_pos); if (uNRead != block) { iRet = ERROR; ssp_err("fail to read file %s (nread = %u)", fw_path, uNRead); goto err_fw_size; } while (retry_count < 3) { iRet = fw_write_stm(spi, fw_addr, block, buff); if (iRet < block) { ssp_err("Err writing to addr 0x%08X", fw_addr); if (iRet < 0) { ssp_err("Error was %d", iRet); } else { ssp_err("Incomplete write of %d bytes", iRet); iRet = -EIO; } retry_count++; err_count++; } else { retry_count = 0; break; } } if (iRet < 0) { ssp_err("Writing MEM failed: %d, retry cont: %d", iRet, err_count); goto out; } remaining -= block; uPos += block; fw_addr += block; if (count++ == 50) { ssp_info("Updated %u bytes / %u bytes", uPos, uFSize); count = 0; } } ssp_info("Firm up(UMS) success(%d bytes, retry %d)", uPos, err_count); out: err_fw_size: kfree(buff); err_alloc: filp_close(fp, NULL); err_open: set_fs(old_fs); return iRet; }
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); ssp_dbgf(); #if SSP_STM_DEBUG ssp_info("sending WMEM_COMMAND"); #endif if (len > STM_MAX_XFER_SIZE) { ssp_err("Can't send more than 256 bytes per transaction"); 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) { ssp_err("Error %d sending read_mem cmd", res); return res; } res = send_addr(spi, fw_addr, 0); if (res != 0) { ssp_err("Error %d sending write_mem Address", res); return res; } res = stm32fwu_spi_write(spi, send_buff, len + 2); if (res < len) { ssp_err("Error writing to flash. res = %d", res); return (res > 0) ? -EIO : res; } ssp_dbgf("2"); 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) { ssp_err("Got NAK waiting for WRITE_MEM to complete"); return -EPROTO; } ssp_err("timeout waiting for ACK for WRITE_MEM command"); return -ETIME; }