ipq6018: Support for new smem version
Change-Id: I2e847eface6d5604ff30ce245e767b8a9d923500
Signed-off-by: Antony Arun T <antothom@codeaurora.org>
diff --git a/arch/arm/cpu/armv7/qca/common/smem.c b/arch/arm/cpu/armv7/qca/common/smem.c
index 32e0810..e16dc64 100644
--- a/arch/arm/cpu/armv7/qca/common/smem.c
+++ b/arch/arm/cpu/armv7/qca/common/smem.c
@@ -140,6 +140,236 @@
qca_smem_flash_info_t qca_smem_flash_info;
qca_smem_bootconfig_info_t qca_smem_bootconfig_info;
+#ifdef CONFIG_SMEM_VERSION_C
+
+#define SMEM_COMMON_HOST 0xFFFE
+#ifndef CONFIG_QCA_SMEM_SIZE
+ #define CONFIG_QCA_SMEM_SIZE 0x100000
+#endif
+
+enum {
+ smem_enu_sucess,
+ smem_enu_failed,
+ smem_enu_no_init
+};
+
+u8 smem_enumeration_status = smem_enu_no_init;
+
+/**
+ * struct smem_ptable_entry - one entry in the @smem_ptable list
+ * @offset: offset, within the main shared memory region, of the partition
+ * @size: size of the partition
+ * @flags: flags for the partition (currently unused)
+ * @host0: first processor/host with access to this partition
+ * @host1: second processor/host with access to this partition
+ * @reserved: reserved entries for later use
+ */
+struct smem_ptable_entry {
+ __le32 offset;
+ __le32 size;
+ __le32 flags;
+ __le16 host0;
+ __le16 host1;
+ __le32 reserved[8];
+};
+
+/**
+ * struct smem_private_ptable - partition table for the private partitions
+ * @magic: magic number, must be SMEM_PTABLE_MAGIC
+ * @version: version of the partition table
+ * @num_entries: number of partitions in the table
+ * @reserved: for now reserved entries
+ * @entry: list of @smem_ptable_entry for the @num_entries partitions
+ */
+struct smem_private_ptable {
+ u8 magic[4];
+ __le32 version;
+ __le32 num_entries;
+ __le32 reserved[5];
+ struct smem_ptable_entry entry[];
+};
+
+/**
+ * struct smem_private_entry - header of each item in the private partition
+ * @canary: magic number, must be SMEM_PRIVATE_CANARY
+ * @item: identifying number of the smem item
+ * @size: size of the data, including padding bytes
+ * @padding_data: number of bytes of padding of data
+ * @padding_hdr: number of bytes of padding between the header and the data
+ * @reserved: for now reserved entry
+ */
+struct smem_private_entry {
+ u16 canary; /* bytes are the same so no swapping needed */
+ __le16 item;
+ __le32 size; /* includes padding bytes */
+ __le16 padding_data;
+ __le16 padding_hdr;
+ __le32 reserved;
+};
+
+#define SMEM_PRIVATE_CANARY 0xa5a5
+
+static const u8 SMEM_PTABLE_MAGIC[] = { 0x24, 0x54, 0x4f, 0x43 }; /* "$TOC" */
+/**
+ * struct smem_partition_header - header of the partitions
+ * @magic: magic number, must be SMEM_PART_MAGIC
+ * @host0: first processor/host with access to this partition
+ * @host1: second processor/host with access to this partition
+ * @size: size of the partition
+ * @offset_free_uncached: offset to the first free byte of uncached memory in
+ * this partition
+ * @offset_free_cached: offset to the first free byte of cached memory in this
+ * partition
+ * @reserved: for now reserved entries
+ */
+struct smem_partition_header {
+ u8 magic[4];
+ __le16 host0;
+ __le16 host1;
+ __le32 size;
+ __le32 offset_free_uncached;
+ __le32 offset_free_cached;
+ __le32 reserved[3];
+};
+
+static const u8 SMEM_PART_MAGIC[] = { 0x24, 0x50, 0x52, 0x54 }; /*$PRT*/
+
+struct smem_partition_header *smem_cmn_partition;
+
+/* Pointer to the one and only smem handle */
+
+static struct smem_private_entry *
+phdr_to_first_private_entry(struct smem_partition_header *phdr)
+{
+ void *p = phdr;
+
+ return p + sizeof(*phdr);
+}
+
+static struct smem_private_entry *
+phdr_to_last_private_entry(struct smem_partition_header *phdr)
+{
+ void *p = phdr;
+
+ return p + le32_to_cpu(phdr->offset_free_uncached);
+}
+
+static struct smem_private_entry *
+private_entry_next(struct smem_private_entry *e)
+{
+ void *p = e;
+
+ return p + sizeof(*e) + le16_to_cpu(e->padding_hdr) +
+ le32_to_cpu(e->size);
+}
+
+static void *entry_to_item(struct smem_private_entry *e)
+{
+ void *p = e;
+
+ return p + sizeof(*e) + le16_to_cpu(e->padding_hdr);
+}
+
+static void *qcom_smem_get_private(struct smem_partition_header *phdr,
+ unsigned item,
+ size_t *size)
+{
+ struct smem_private_entry *e, *end;
+
+ e = phdr_to_first_private_entry(phdr);
+ end = phdr_to_last_private_entry(phdr);
+
+ while (e < end) {
+ if (e->canary != SMEM_PRIVATE_CANARY) {
+ printf("Found invalid canary in\
+ host common partition\n");
+ return -EINVAL;
+ }
+ if (le16_to_cpu(e->item) == item) {
+ if (size != NULL)
+ *size = le32_to_cpu(e->size) -
+ le16_to_cpu(e->padding_data);
+
+ return entry_to_item(e);
+ }
+
+ e = private_entry_next(e);
+ }
+
+ return -ENOENT;
+}
+
+static int qcom_smem_enumerate_partitions()
+{
+ struct smem_partition_header *header;
+ struct smem_ptable_entry *entry;
+ struct smem_private_ptable *ptable;
+ u32 version, host0, host1;
+ int i;
+
+ ptable = CONFIG_QCA_SMEM_BASE + CONFIG_QCA_SMEM_SIZE - SZ_4K;
+ if (memcmp(ptable->magic, SMEM_PTABLE_MAGIC, sizeof(ptable->magic)))
+ return -EINVAL;
+
+ version = le32_to_cpu(ptable->version);
+ if (version != 1) {
+ printf("Unsupported partition header version %d\n", version);
+ return -EINVAL;
+ }
+ for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
+ entry = &ptable->entry[i];
+ host0 = le16_to_cpu(entry->host0);
+ host1 = le16_to_cpu(entry->host1);
+
+ if (host0 != SMEM_COMMON_HOST || host1 != SMEM_COMMON_HOST)
+ continue;
+
+ if (!le32_to_cpu(entry->offset))
+ continue;
+ printf("\noffset: 0X%X %u", entry->offset, entry->offset);
+
+ if (!le32_to_cpu(entry->size))
+ continue;
+ printf("\nsize: 0X%X %u", entry->size, entry->size);
+
+ if (smem_cmn_partition) {
+ printf("Already found a partition for host %x \n",
+ SMEM_COMMON_HOST);
+ return -EINVAL;
+ }
+
+ header = CONFIG_QCA_SMEM_BASE + le32_to_cpu(entry->offset);
+ host0 = le16_to_cpu(header->host0);
+ host1 = le16_to_cpu(header->host1);
+
+ if (memcmp(header->magic, SMEM_PART_MAGIC,
+ sizeof(header->magic))) {
+ printf("Partition %d has invalid magic\n", i);
+ return -EINVAL;
+ }
+
+ if (host0 != SMEM_COMMON_HOST || host1 != SMEM_COMMON_HOST) {
+ printf("Partition %d hosts are invalid\n", i);
+ return -EINVAL;
+ }
+
+ if (header->size != entry->size) {
+ printf("Partition %d has invalid size\n", i);
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) {
+ printf("Partition %d has invalid free pointer\n", i);
+ return -EINVAL;
+ }
+
+ smem_cmn_partition = header;
+ }
+ smem_enumeration_status = smem_enu_sucess;
+ return 0;
+}
+#endif
+
/**
* smem_read_alloc_entry - reads an entry from SMEM
* @type: the entry to read
@@ -157,7 +387,10 @@
unsigned *dest = buf;
unsigned src;
unsigned size;
-
+#ifdef CONFIG_SMEM_VERSION_C
+ void *ptr;
+ int ret;
+#endif
if (((len & 0x3) != 0) || (((unsigned)buf & 0x3) != 0))
return 1;
@@ -167,6 +400,27 @@
return 1;
}
+#ifdef CONFIG_SMEM_VERSION_C
+ if(smem_enumeration_status == smem_enu_no_init) {
+ ret = qcom_smem_enumerate_partitions();
+ if (ret) {
+ printf("Common SMEM Partition is not available\n");
+ smem_enumeration_status = smem_enu_failed;
+ return ret;
+ }
+ }
+
+ if ( smem_enumeration_status == smem_enu_sucess) {
+ ptr = qcom_smem_get_private(smem_cmn_partition,type, &size);
+ if (IS_ERR(ptr)) {
+ ret = PTR_ERR(ptr);
+ return ret;
+ }
+ memcpy(dest, ptr, len);
+ return 0;
+ }
+ return -EINVAL;
+#endif
ainfo = &smem->alloc_info[type];
if (readl(&ainfo->allocated) == 0)
{
@@ -572,6 +826,29 @@
return 1;
}
+/*
+ * smem_ptable_init - initializes RAM partition table from SMEM
+ *
+ */
+#ifdef CONFIG_SMEM_VERSION_C
+int smem_ram_ptable_init_v2(struct usable_ram_partition_table *usable_ram_partition_table)
+{
+ unsigned i;
+
+ i = smem_read_alloc_entry(SMEM_USABLE_RAM_PARTITION_TABLE,
+ usable_ram_partition_table,
+ sizeof(struct usable_ram_partition_table));
+ if (i != 0)
+ return 0;
+
+ if (usable_ram_partition_table->magic1 != _SMEM_RAM_PTABLE_MAGIC_1 ||
+ usable_ram_partition_table->magic2 != _SMEM_RAM_PTABLE_MAGIC_2) {
+ return 0;
+ }
+ return 1;
+}
+#endif
+
void qca_smem_part_to_mtdparts(char *mtdid, int len)
{
qca_smem_flash_info_t *sfi = &qca_smem_flash_info;
diff --git a/board/qca/arm/common/board_init.c b/board/qca/arm/common/board_init.c
index 05592e3..0606656 100644
--- a/board/qca/arm/common/board_init.c
+++ b/board/qca/arm/common/board_init.c
@@ -372,6 +372,30 @@
return 0;
}
+#ifdef CONFIG_SMEM_VERSION_C
+int ram_ptable_init_v2()
+{
+ struct usable_ram_partition_table rtable;
+ int mx = ARRAY_SIZE(rtable.ram_part_entry);
+ int i, ret;
+
+ if (smem_ram_ptable_init_v2(&rtable) > 0) {
+ gd->ram_size = 0;
+ for (i = 0; i < mx; i++) {
+ if (rtable.ram_part_entry[i].partition_category == RAM_PARTITION_SDRAM &&
+ rtable.ram_part_entry[i].partition_type == RAM_PARTITION_SYS_MEMORY) {
+ gd->ram_size += rtable.ram_part_entry[i].length;
+ return 0;
+ }
+ }
+ } else {
+ gd->ram_size = fdtdec_get_uint(gd->fdt_blob, 0, "ddr_size", 256);
+ gd->ram_size <<= 20;
+ }
+ return 0;
+}
+#endif
+
int dram_init(void)
{
struct smem_ram_ptable rtable;
@@ -379,6 +403,11 @@
int mx = ARRAY_SIZE(rtable.parts);
if (smem_ram_ptable_init(&rtable) > 0) {
+#ifdef CONFIG_SMEM_VERSION_C
+ if (rtable.version == 2) {
+ return ram_ptable_init_v2();
+ }
+#endif
gd->ram_size = 0;
for (i = 0; i < mx; i++) {
if (rtable.parts[i].category == RAM_PARTITION_SDRAM &&
diff --git a/board/qca/arm/ipq6018/ipq6018.h b/board/qca/arm/ipq6018/ipq6018.h
index b8d8b08..ea2ea07 100644
--- a/board/qca/arm/ipq6018/ipq6018.h
+++ b/board/qca/arm/ipq6018/ipq6018.h
@@ -192,6 +192,49 @@
#define GCC_PCIE0_RCHNG_CMD_RCGR 0x01875070
#define GCC_PCIE0_RCHNG_CFG_RCGR 0x01875074
+#ifdef CONFIG_SMEM_VERSION_C
+#define RAM_PART_NAME_LENGTH 16
+
+/**
+ * Number of RAM partition entries which are usable by APPS.
+ */
+#define RAM_NUM_PART_ENTRIES 32
+struct ram_partition_entry
+{
+ char name[RAM_PART_NAME_LENGTH]; /**< Partition name, unused for now */
+ u64 start_address; /**< Partition start address in RAM */
+ u64 length; /**< Partition length in RAM in Bytes */
+ u32 partition_attribute; /**< Partition attribute */
+ u32 partition_category; /**< Partition category */
+ u32 partition_domain; /**< Partition domain */
+ u32 partition_type; /**< Partition type */
+ u32 num_partitions; /**< Number of partitions on device */
+ u32 hw_info; /**< hw information such as type and frequency */
+ u8 highest_bank_bit; /**< Highest bit corresponding to a bank */
+ u8 reserve0; /**< Reserved for future use */
+ u8 reserve1; /**< Reserved for future use */
+ u8 reserve2; /**< Reserved for future use */
+ u32 reserved5; /**< Reserved for future use */
+ u64 available_length; /**< Available Partition length in RAM in Bytes */
+};
+
+struct usable_ram_partition_table
+{
+ u32 magic1; /**< Magic number to identify valid RAM partition table */
+ u32 magic2; /**< Magic number to identify valid RAM partition table */
+ u32 version; /**< Version number to track structure definition changes
+ and maintain backward compatibilities */
+ u32 reserved1; /**< Reserved for future use */
+
+ u32 num_partitions; /**< Number of RAM partition table entries */
+
+ u32 reserved2; /** < Added for 8 bytes alignment of header */
+
+ /** RAM partition table entries */
+ struct ram_partition_entry ram_part_entry[RAM_NUM_PART_ENTRIES];
+};
+#endif
+
struct smem_ram_ptn {
char name[16];
unsigned long long start;
diff --git a/include/configs/ipq6018.h b/include/configs/ipq6018.h
index 8bdbf98..0441ee7 100644
--- a/include/configs/ipq6018.h
+++ b/include/configs/ipq6018.h
@@ -96,7 +96,9 @@
#define CONFIG_OF_COMBINE 1
-#define CONFIG_QCA_SMEM_BASE 0x4AB00000
+#define CONFIG_SMEM_VERSION_C
+#define CONFIG_QCA_SMEM_BASE 0x48C00000
+#define CONFIG_QCA_SMEM_SIZE 0x100000
#define CONFIG_IPQ_FDT_HIGH 0x48700000
#define CONFIG_IPQ_NO_MACS 6