// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016, Zodiac Inflight Innovations
* Copyright (c) 2007-2016, Synaptics Incorporated
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*/
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <asm/unaligned.h>
#include "rmi_driver.h"
#include "rmi_f34.h"
static int rmi_f34v7_read_flash_status(struct f34_data *f34)
{
u8 status;
u8 command;
int ret;
ret = rmi_read_block(f34->fn->rmi_dev,
f34->fn->fd.data_base_addr + V7_FLASH_STATUS_OFFSET,
&status,
sizeof(status));
if (ret < 0) {
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
"%s: Error %d reading flash status\n", __func__, ret);
return ret;
}
f34->v7.in_bl_mode = status >> 7;
f34->v7.flash_status = status & 0x1f;
if (f34->v7.flash_status != 0x00) {
dev_err(&f34->fn->dev, "%s: status=%d, command=0x%02x\n",
__func__, f34->v7.flash_status, f34->v7.command);
}
ret = rmi_read_block(f34->fn->rmi_dev,
f34->fn->fd.data_base_addr + V7_COMMAND_OFFSET,
&command,
sizeof(command));
if (ret < 0) {
dev_err(&f34->fn->dev, "%s: Failed to read flash command\n",
__func__);
return ret;
}
f34->v7.command = command;
return 0;
}
static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms)
{
unsigned long timeout;
timeout = msecs_to_jiffies(timeout_ms);
if (!wait_for_completion_timeout(&f34->v7.cmd_done, timeout)) {
dev_warn(&f34->fn->dev, "%s: Timed out waiting for idle status\n",
__func__);
return -ETIMEDOUT;
}
return 0;
}
static int rmi_f34v7_check_command_status(struct f34_data *f34, int timeout_ms)
{
int ret;
ret = rmi_f34v7_wait_for_idle(f34, timeout_ms);
if (ret < 0)
return ret;
ret = rmi_f34v7_read_flash_status(f34);
if (ret < 0)
return ret;
if (f34->v7.flash_status != 0x00)
return -EIO;
return 0;
}
static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34,
u8 cmd)
{
int ret;
u8 base;
struct f34v7_data_1_5 data_1_5;
base = f34->fn->fd.data_base_addr;
memset(&data_1_5, 0, sizeof(data_1_5));
switch (cmd) {
case v7_CMD_ERASE_ALL:
data_1_5.partition_id = CORE_CODE_PARTITION;
data_1_5.command = CMD_V7_ERASE_AP;
break;
case v7_CMD_ERASE_UI_FIRMWARE:
data_1_5.partition_id = CORE_CODE_PARTITION;
data_1_5.command = CMD_V7_ERASE;
break;
case v7_CMD_ERASE_BL_CONFIG:
data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION;
data_1_5.command = CMD_V7_ERASE;
break;
case v7_CMD_ERASE_UI_CONFIG:
data_1_5.partition_id = CORE_CONFIG_PARTITION;
data_1_5.command = CMD_V7_ERASE;
break;
case v7_CMD_ERASE_DISP_CONFIG:
data_1_5.partition_id = DISPLAY_CONFIG_PARTITION;
data_1_5.command = CMD_V7_ERASE;
break;
case v7_CMD_ERASE_FLASH_CONFIG:
data_1_5.partition_id = FLASH_CONFIG_PARTITION;
data_1_5.command = CMD_V7_ERASE;
break;
case v7_CMD_ERASE_GUEST_CODE:
data_1_5.partition_id = GUEST_CODE_PARTITION;
data_1_5.command = CMD_V7_ERASE;
break;
case v7_CMD_ENABLE_FLASH_PROG:
data_1_5.partition_id = BOOTLOADER_PARTITION;<