Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 36 additions & 30 deletions drivers/soc/qcom/qcom-geni-se.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,6 @@ struct se_fw_hdr {
/*Magic numbers*/
#define SE_MAGIC_NUM 0x57464553

#define MAX_GENI_CFG_RAMn_CNT 455

#define MI_PBT_NON_PAGED_SEGMENT 0x0
#define MI_PBT_HASH_SEGMENT 0x2
#define MI_PBT_NOTUSED_SEGMENT 0x3
Expand Down Expand Up @@ -997,25 +995,31 @@ EXPORT_SYMBOL_GPL(geni_icc_disable);

/**
* geni_find_protocol_fw() - Locate and validate SE firmware for a protocol.
* @dev: Pointer to the device structure.
* @se: Pointer to the serial engine structure.
* @fw: Pointer to the firmware image.
* @protocol: Expected serial engine protocol type.
* @fw_size_out: Non-NULL output parameter; receives the rounded, validated
* firmware word count on success.
*
* Identifies the appropriate firmware image or configuration required for a
* specific communication protocol instance running on a Qualcomm GENI
* controller.
* specific communication protocol instance running on a Qualcomm GENI
* controller. Validates the firmware size against the hardware PROG_RAM_DEPTH
* read from SE_HW_PARAM_2.
*
* Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise.
* Return: pointer to a valid 'const struct se_fw_hdr' if found, or NULL otherwise.
*/
static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
enum geni_se_protocol_type protocol)
static const struct se_fw_hdr *geni_find_protocol_fw(struct geni_se *se, const struct firmware *fw,
enum geni_se_protocol_type protocol,
u32 *fw_size_out)
{
struct device *dev = se->dev;
const struct elf32_hdr *ehdr;
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
struct se_fw_hdr *sefw;
const struct se_fw_hdr *sefw;
u32 fw_end, cfg_idx_end, cfg_val_end;
u16 fw_size;
u32 prog_ram_depth;
u32 fw_size;
int i;

if (!fw || fw->size < sizeof(struct elf32_hdr))
Expand Down Expand Up @@ -1054,29 +1058,30 @@ static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct
if (phdr->p_filesz < sizeof(struct se_fw_hdr))
continue;

sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
sefw = (const struct se_fw_hdr *)(fw->data + phdr->p_offset);
fw_size = le16_to_cpu(sefw->fw_size_in_items);
fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);

if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
continue;

if (le32_to_cpu(sefw->serial_protocol) != protocol)
if (le16_to_cpu(sefw->serial_protocol) != protocol)
continue;

if (fw_size % 2 != 0) {
/* Round up so fw_end covers the full copy range. */
if (fw_size % 2 != 0)
fw_size++;
sefw->fw_size_in_items = cpu_to_le16(fw_size);
}

if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
dev_err(dev,
"Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
fw_size, MAX_GENI_CFG_RAMn_CNT);
fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);

prog_ram_depth = FIELD_GET(PROG_RAM_DEPTH_MSK,
readl_relaxed(se->base + SE_HW_PARAM_2));
if (fw_size >= prog_ram_depth) {
dev_err(dev, "Firmware size (%u) exceeds RAM size (%u)\n",
fw_size, prog_ram_depth);
continue;
}

Expand All @@ -1086,6 +1091,7 @@ static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct
continue;
}

*fw_size_out = fw_size;
return sefw;
}

Expand Down Expand Up @@ -1196,17 +1202,17 @@ static int geni_load_se_fw(struct geni_se *se, const struct firmware *fw,
{
const u32 *fw_data, *cfg_val_arr;
const u8 *cfg_idx_arr;
u32 i, reg_value;
u32 i, reg_value, fw_size_in_items;
int ret;
struct se_fw_hdr *hdr;
const struct se_fw_hdr *hdr;

hdr = geni_find_protocol_fw(se->dev, fw, protocol);
hdr = geni_find_protocol_fw(se, fw, protocol, &fw_size_in_items);
if (!hdr)
return -EINVAL;

fw_data = (const u32 *)((u8 *)hdr + le16_to_cpu(hdr->fw_offset));
fw_data = (const u32 *)((const u8 *)hdr + le16_to_cpu(hdr->fw_offset));
cfg_idx_arr = (const u8 *)hdr + le16_to_cpu(hdr->cfg_idx_offset);
cfg_val_arr = (const u32 *)((u8 *)hdr + le16_to_cpu(hdr->cfg_val_offset));
cfg_val_arr = (const u32 *)((const u8 *)hdr + le16_to_cpu(hdr->cfg_val_offset));

ret = geni_icc_set_bw(se);
if (ret)
Expand Down Expand Up @@ -1277,7 +1283,7 @@ static int geni_load_se_fw(struct geni_se *se, const struct firmware *fw,

/* Program RAM address space. */
memcpy_toio(se->base + SE_GENI_CFG_RAMN, fw_data,
le16_to_cpu(hdr->fw_size_in_items) * sizeof(u32));
fw_size_in_items * sizeof(u32));

/* Put default values on GENI's output pads. */
writel_relaxed(0x1, se->base + GENI_FORCE_DEFAULT_REG);
Expand Down
4 changes: 4 additions & 0 deletions include/linux/soc/qcom/geni-se.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ struct geni_se {
#define SE_DMA_RX_FSM_RST 0xd58
#define SE_HW_PARAM_0 0xe24
#define SE_HW_PARAM_1 0xe28
#define SE_HW_PARAM_2 0xe2c

/* GENI_FORCE_DEFAULT_REG fields */
#define FORCE_DEFAULT BIT(0)
Expand Down Expand Up @@ -287,6 +288,9 @@ struct geni_se {
#define RX_FIFO_DEPTH_MSK GENMASK(21, 16)
#define RX_FIFO_DEPTH_SHFT 16

/* SE_HW_PARAM_2 fields */
#define PROG_RAM_DEPTH_MSK GENMASK(10, 0)

#define HW_VER_MAJOR_MASK GENMASK(31, 28)
#define HW_VER_MAJOR_SHFT 28
#define HW_VER_MINOR_MASK GENMASK(27, 16)
Expand Down
Loading