#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/delay.h>
+#include <linux/of_fdt.h>
+#if defined(CONFIG_BOOTINFO)
+#include <soc/samsung/bootinfo.h>
+#endif
+
+
+void __attribute__((weak)) mach_cpuinfo_show(struct seq_file *m, void *v);
/*
* In case the boot CPU is hotpluggable, we record its initial state and
seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
}
+#if defined(CONFIG_BOOTINFO)
+ seq_printf(m, "Revision\t: %04x\n", system_rev);
+ seq_printf(m, "Serial\t\t: %08x%08x\n",
+ system_serial_high, system_serial_low);
+
+ if (mach_cpuinfo_show)
+ mach_cpuinfo_show(m, v);
+#endif
return 0;
}
depends on DEBUG_SNAPSHOT
default y
+config MMI_SOC_INFO
+ default n
+ bool "Motorola Mobility SOC Info"
+ help
+ Provide mechanism to export SOC info.
+
+config MMI_RAM_INFO
+ default n
+ bool "Motorola Mobility RAM Info"
+ help
+ Provide mechanism to access RAM size and MR registers values via sysfs.
+
+config MMI_STORAGE_INFO
+ default n
+ bool "Motorola Mobility STORAGE Info"
+ help
+ Provide mechanism to export EMMC/UFS type, size and vendor info.
+
+config MMI_UNIT_INFO
+ default n
+ bool "Motorola Mobility Unit Info"
+ help
+ Provide mechanism to expose unit information to other cpu via smem.
+
config BOOTINFO
bool "Boot Information Feature"
default n
# bootinfo
obj-$(CONFIG_BOOTINFO) += bootinfo.o
+
+obj-$(CONFIG_MMI_SOC_INFO) += mmi_soc_info.o
+obj-$(CONFIG_MMI_RAM_INFO) += mmi-ram-info.o
+obj-$(CONFIG_MMI_STORAGE_INFO) += mmi_storage_info.o
+obj-$(CONFIG_MMI_UNIT_INFO) += mmi-unit-info.o
--- /dev/null
+/*
+ * Copyright (C) 2012 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/pstore.h>
+#include <linux/of.h>
+
+static struct mmi_ddr_info {
+ unsigned mr5;
+ unsigned mr6;
+ unsigned mr7;
+ unsigned mr8;
+ unsigned ramsize;
+} *smem_ddr_info;
+
+static char sysfsram_type_name[20] = "unknown";
+static char sysfsram_vendor_name[20] = "unknown";
+static uint32_t sysfsram_ramsize;
+static struct mmi_ddr_info ddr_info;
+
+static ssize_t sysfsram_mr_register_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ uint32_t val = 0;
+ const char *name = attr->attr.name;
+
+ if (smem_ddr_info != NULL &&
+ strnlen(name, 4) == 3 && name[0] == 'm' && name[1] == 'r')
+ {
+ switch (name[2]) {
+ case '5': val = smem_ddr_info->mr5; break;
+ case '6': val = smem_ddr_info->mr6; break;
+ case '7': val = smem_ddr_info->mr7; break;
+ case '8': val = smem_ddr_info->mr8; break;
+ }
+ }
+
+ return snprintf(buf, 6, "0x%02x\n", val);
+}
+
+static ssize_t sysfsram_size_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 12, "%u\n", sysfsram_ramsize);
+}
+
+static ssize_t sysfsram_info_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 60, "%s:%s:%uMB\n",
+ sysfsram_vendor_name,
+ sysfsram_type_name,
+ sysfsram_ramsize);
+}
+
+static ssize_t sysfsram_type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 20, "%s\n", sysfsram_type_name);
+}
+
+static struct kobj_attribute ddr_mr5_register_attr =
+ __ATTR(mr5, 0444, sysfsram_mr_register_show, NULL);
+
+static struct kobj_attribute ddr_mr6_register_attr =
+ __ATTR(mr6, 0444, sysfsram_mr_register_show, NULL);
+
+static struct kobj_attribute ddr_mr7_register_attr =
+ __ATTR(mr7, 0444, sysfsram_mr_register_show, NULL);
+
+static struct kobj_attribute ddr_mr8_register_attr =
+ __ATTR(mr8, 0444, sysfsram_mr_register_show, NULL);
+
+static struct kobj_attribute ddr_size_attr =
+ __ATTR(size, 0444, sysfsram_size_show, NULL);
+
+static struct kobj_attribute ddr_type_attr =
+ __ATTR(type, 0444, sysfsram_type_show, NULL);
+
+static struct kobj_attribute ddr_info_attr =
+ __ATTR(info, 0444, sysfsram_info_show, NULL);
+
+static struct attribute *ram_info_properties_attrs[] = {
+ &ddr_mr5_register_attr.attr,
+ &ddr_mr6_register_attr.attr,
+ &ddr_mr7_register_attr.attr,
+ &ddr_mr8_register_attr.attr,
+ &ddr_size_attr.attr,
+ &ddr_type_attr.attr,
+ &ddr_info_attr.attr,
+ NULL
+};
+
+static struct attribute_group ram_info_properties_attr_group = {
+ .attrs = ram_info_properties_attrs,
+};
+
+static int __init init_mmi_ram_info(void)
+{
+ int status = 0;
+ int rc;
+ struct device_node *n;
+
+ static struct kobject *ram_info_properties_kobj;
+ uint32_t vid, tid;
+ const char *tname = "unknown";
+ const char *vname = "unknown";
+ static const char *vendors[] = {
+ "unknown",
+ "Samsung",
+ "Qimonda",
+ "Elpida",
+ "Etron",
+ "Nanya",
+ "Hynix",
+ "Mosel",
+ "Winbond",
+ "ESMT",
+ "unknown",
+ "Spansion",
+ "SST",
+ "ZMOS",
+ "Intel"
+ };
+ static const char *types[] = {
+ "S4 SDRAM",
+ "S2 SDRAM",
+ "N NVM",
+ "Reserved"
+ };
+
+ smem_ddr_info = NULL;
+ n = of_find_node_by_path("/chosen/mmi,ram");
+ if (n != NULL) {
+ rc = of_property_read_u32(n,"ramsize", &ddr_info.ramsize);
+ if (rc == 0 )
+ rc = of_property_read_u32(n,"mr5", &ddr_info.mr5);
+ if (rc == 0 )
+ rc = of_property_read_u32(n,"mr6", &ddr_info.mr6);
+ if (rc == 0 )
+ rc = of_property_read_u32(n,"mr7", &ddr_info.mr7);
+ if (rc == 0 )
+ rc = of_property_read_u32(n,"mr8", &ddr_info.mr8);
+ of_node_put(n);
+ if (rc == 0 )
+ smem_ddr_info = &ddr_info;
+ }
+
+ if (smem_ddr_info != NULL) {
+ char apanic_annotation[128];
+
+ /* identify vendor */
+ vid = smem_ddr_info->mr5 & 0xFF;
+ if (vid < (sizeof(vendors)/sizeof(vendors[0])))
+ vname = vendors[vid];
+ else if (vid == 0xFE)
+ vname = "Numonyx";
+ else if (vid == 0xFF)
+ vname = "Micron";
+
+ snprintf(sysfsram_vendor_name, sizeof(sysfsram_vendor_name),
+ "%s", vname);
+
+ /* identify type */
+ tid = smem_ddr_info->mr8 & 0x03;
+ if (tid < (sizeof(types)/sizeof(types[0])))
+ tname = types[tid];
+
+ snprintf(sysfsram_type_name, sizeof(sysfsram_type_name),
+ "%s", tname);
+
+ /* extract size */
+ sysfsram_ramsize = smem_ddr_info->ramsize;
+
+ snprintf(apanic_annotation, sizeof(apanic_annotation),
+ "RAM: %s, %s, %u MB, MR5:0x%02X, MR6:0x%02X, "
+ "MR7:0x%02X, MR8:0x%02X\n",
+ vname, tname, smem_ddr_info->ramsize,
+ smem_ddr_info->mr5, smem_ddr_info->mr6,
+ smem_ddr_info->mr7, smem_ddr_info->mr8);
+ pstore_annotate(apanic_annotation);
+ }
+ else {
+ /* complain, but do not fail if SMEM was not allocated */
+ /* defaults will be reported */
+ pr_err("%s: failed to access RAM info in SMEM\n", __func__);
+ }
+
+ /* create sysfs object */
+ ram_info_properties_kobj = kobject_create_and_add("ram", NULL);
+
+ if (ram_info_properties_kobj)
+ status = sysfs_create_group(ram_info_properties_kobj,
+ &ram_info_properties_attr_group);
+
+ if (!ram_info_properties_kobj || status) {
+ pr_err("%s: failed to create /sys/ram\n", __func__);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+module_init(init_mmi_ram_info);
+MODULE_DESCRIPTION("Motorola Mobility Inc. RAM Info");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Copyright (C) 2013 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <asm/setup.h>
+#include <soc/samsung/bootinfo.h>
+
+#include "mmi-unit-info.h"
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+
+static u32 prod_id;
+
+#define SERIALNO_MAX_LEN 64
+static char serialno[SERIALNO_MAX_LEN];
+int __init board_serialno_init(char *s)
+{
+ strlcpy(serialno, s, SERIALNO_MAX_LEN);
+ return 1;
+}
+__setup("androidboot.serialno=", board_serialno_init);
+
+static char carrier[CARRIER_MAX_LEN];
+int __init board_carrier_init(char *s)
+{
+ strlcpy(carrier, s, SERIALNO_MAX_LEN);
+ return 1;
+}
+__setup("androidboot.carrier=", board_carrier_init);
+
+static char baseband[BASEBAND_MAX_LEN];
+int __init board_baseband_init(char *s)
+{
+ strlcpy(baseband, s, SERIALNO_MAX_LEN);
+ return 1;
+}
+__setup("androidboot.baseband=", board_baseband_init);
+
+#define ANDROIDBOOT_DEVICE_MAX_LEN 32
+static char androidboot_device[ANDROIDBOOT_DEVICE_MAX_LEN];
+int __init setup_androidboot_device_init(char *s)
+{
+ strlcpy(androidboot_device, s, ANDROIDBOOT_DEVICE_MAX_LEN);
+ return 1;
+}
+__setup("androidboot.device=", setup_androidboot_device_init);
+
+static unsigned int androidboot_radio;
+static char androidboot_radio_str[RADIO_MAX_LEN];
+int __init setup_androidboot_radio_init(char *s)
+{
+ int retval = kstrtouint(s, 16, &androidboot_radio);
+
+ if (retval < 0) {
+ androidboot_radio = 0;
+ }
+
+ strlcpy(androidboot_radio_str, s, RADIO_MAX_LEN);
+
+ return 1;
+}
+__setup("androidboot.radio=", setup_androidboot_radio_init);
+
+static struct mmi_unit_info *mui;
+void mmi_set_pureason(uint32_t val)
+{
+ if (mui) {
+ mui->powerup_reason = val;
+ pr_debug("%s: Set modem PU reason value in SMEM to %d\n",
+ __func__, mui->powerup_reason);
+ }
+}
+
+static char soc_hw[SOCHW_MAX_LEN+1];
+
+void mach_cpuinfo_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "Device\t\t: %s\n", androidboot_device);
+ /* Zero is not a valid "Radio" value. */
+ /* Lack of "Radio" entry in cpuinfo means: */
+ /* look for radio in "Revision" */
+ if (strnlen(androidboot_radio_str, RADIO_MAX_LEN))
+ seq_printf(m, "Radio\t\t: %s\n", androidboot_radio_str);
+
+ seq_printf(m, "SOC Hardware\t: %s\n", soc_hw);
+}
+
+static char extended_baseband[BASEBAND_MAX_LEN+1] = "\0";
+
+struct mmi_of_lookup {
+ const char *compatible;
+ unsigned int *data;
+};
+
+static struct mmi_of_lookup mmi_of_setup[] __initdata = {
+ { .compatible = "linux,seriallow", .data = &system_serial_low },
+ { .compatible = "linux,serialhigh", .data = &system_serial_high },
+ { .compatible = "linux,hwrev", .data = &system_rev },
+ { .compatible = "mmi,prod_id", .data = &prod_id },
+ { }
+};
+
+static void __init mmi_of_populate_setup(void)
+{
+ struct device_node *n = of_find_node_by_path("/chosen");
+ struct mmi_of_lookup *tbl = mmi_of_setup;
+ const char *baseband;
+ const char *temp;
+
+ while (tbl->data) {
+ of_property_read_u32(n, tbl->compatible, tbl->data);
+ tbl++;
+ }
+
+ if (0 == of_property_read_string(n, "mmi,baseband", &baseband))
+ strlcpy(extended_baseband, baseband, sizeof(extended_baseband));
+
+ if (0 == of_property_read_string(n, "mmi,soc_hw", &temp))
+ strlcpy(soc_hw, temp, sizeof(soc_hw));
+
+ of_node_put(n);
+}
+
+static int __init mmi_unit_info_init(void)
+{
+ int ret = 0;
+ struct mmi_unit_info *mui_copy;
+
+ mmi_of_populate_setup();
+
+ #define SMEM_KERNEL_RESERVE_SIZE 1024
+ mui_copy = kzalloc(SMEM_KERNEL_RESERVE_SIZE, GFP_KERNEL);
+ if (!mui_copy) {
+ pr_err("%s: failed to allocate space for mmi_unit_info\n",
+ __func__);
+ ret = 1;
+ goto err;
+ }
+
+ mui_copy->version = MMI_UNIT_INFO_VER;
+ mui_copy->system_rev = system_rev;
+ mui_copy->system_serial_low = system_serial_low;
+ mui_copy->system_serial_high = system_serial_high;
+#ifndef CONFIG_ARM64
+ strlcpy(mui_copy->machine, machine_desc->name, MACHINE_MAX_LEN);
+#else
+ strlcpy(mui_copy->machine, "", MACHINE_MAX_LEN);
+#endif
+ strlcpy(mui_copy->barcode, serialno, BARCODE_MAX_LEN);
+ strlcpy(mui_copy->baseband, extended_baseband, BASEBAND_MAX_LEN);
+ strlcpy(mui_copy->carrier, carrier, CARRIER_MAX_LEN);
+ strlcpy(mui_copy->device, androidboot_device, DEVICE_MAX_LEN);
+ mui_copy->radio = androidboot_radio;
+ strlcpy(mui_copy->radio_str, androidboot_radio_str, RADIO_MAX_LEN);
+ mui_copy->powerup_reason = bi_powerup_reason();
+
+ pr_info("mmi_unit_info (SMEM) for modem: version = 0x%02x,"
+ " device = '%s', radio = 0x%x, radio_str = '%s',"
+ " system_rev = 0x%04x, system_serial = 0x%08x%08x,"
+ " machine = '%s', barcode = '%s', baseband = '%s',"
+ " carrier = '%s', pu_reason = 0x%08x\n",
+ mui_copy->version,
+ mui_copy->device,
+ mui_copy->radio,
+ mui_copy->radio_str,
+ mui_copy->system_rev,
+ mui_copy->system_serial_high, mui_copy->system_serial_low,
+ mui_copy->machine, mui_copy->barcode,
+ mui_copy->baseband, mui_copy->carrier,
+ mui_copy->powerup_reason);
+
+ mui = NULL;
+
+ if (!mui) {
+ pr_err("%s: failed to allocate mmi_unit_info in SMEM\n",
+ __func__);
+ ret = 1;
+ goto err_free;
+ } else if (PTR_ERR(mui_copy) == -EPROBE_DEFER) {
+ pr_err("%s: SMEM not yet initialized\n", __func__);
+ ret = 1;
+ goto err_free;
+ }
+
+ memcpy(mui, mui_copy, SMEM_KERNEL_RESERVE_SIZE);
+
+err_free:
+ kfree(mui_copy);
+err:
+ return ret;
+}
+
+module_init(mmi_unit_info_init);
+MODULE_DESCRIPTION("Motorola Mobility LLC. Unit Info");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Copyright (C) 2013 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ARCH_ARM_MACH_SOC_MMI_UNIT_INFO_H
+#define __ARCH_ARM_MACH_SOC_MMI_UNIT_INFO_H
+
+/* set of data provided to the modem over SMEM */
+#define MMI_UNIT_INFO_VER 3
+#define BARCODE_MAX_LEN 65
+#define MACHINE_MAX_LEN 33
+#define CARRIER_MAX_LEN 65
+#define BASEBAND_MAX_LEN 97
+#define SOCHW_MAX_LEN 32
+#define DEVICE_MAX_LEN 33
+#define RADIO_MAX_LEN 33
+struct mmi_unit_info {
+ uint32_t version;
+ uint32_t system_rev;
+ uint32_t system_serial_low;
+ uint32_t system_serial_high;
+ char machine[MACHINE_MAX_LEN];
+ char barcode[BARCODE_MAX_LEN];
+ char carrier[CARRIER_MAX_LEN];
+ char baseband[BASEBAND_MAX_LEN];
+ char device[DEVICE_MAX_LEN];
+ uint32_t radio;
+ uint32_t powerup_reason;
+ char radio_str[RADIO_MAX_LEN];
+};
+
+/* Function that sets the modem reset value in the SMEM location
+ * where mmi_unit_info is stored.
+ */
+void mmi_set_pureason(uint32_t val);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2013 - 2015 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/pstore.h>
+
+#include "socinfo.h"
+
+struct mmi_soc_bin {
+ int set;
+ int speed;
+ int pvs;
+ int ver;
+};
+
+#define MMI_SOC_BIN_INVAL INT_MAX
+#define ACPU_BIN_SET BIT(0)
+
+static struct mmi_soc_bin mmi_soc_bin_info;
+static DEFINE_SPINLOCK(mmi_soc_bin_lock);
+
+static inline void mmi_panic_annotate(const char *str)
+{
+ pstore_annotate(str);
+}
+
+static void __init mmi_soc_annotate_socinfo(void)
+{
+ char socinfo[32];
+
+ snprintf(socinfo, sizeof(socinfo), "socinfo: id=%u, ",
+ socinfo_get_id());
+ mmi_panic_annotate(socinfo);
+
+ snprintf(socinfo, sizeof(socinfo), "ver=%u.%u, ",
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()),
+ SOCINFO_VERSION_MINOR(socinfo_get_version()));
+ mmi_panic_annotate(socinfo);
+
+ snprintf(socinfo, sizeof(socinfo), "raw_id=%u, ",
+ socinfo_get_raw_id());
+ mmi_panic_annotate(socinfo);
+
+ snprintf(socinfo, sizeof(socinfo), "raw_ver=%u, ",
+ socinfo_get_raw_version());
+ mmi_panic_annotate(socinfo);
+
+ snprintf(socinfo, sizeof(socinfo), "hw_plat=%u, ",
+ socinfo_get_platform_type());
+ mmi_panic_annotate(socinfo);
+
+ snprintf(socinfo, sizeof(socinfo), "hw_plat_ver=%u, ",
+ socinfo_get_platform_version());
+ mmi_panic_annotate(socinfo);
+
+ snprintf(socinfo, sizeof(socinfo), "hw_plat_subtype=%u\n",
+ socinfo_get_platform_subtype());
+ mmi_panic_annotate(socinfo);
+}
+
+static ssize_t mmi_acpu_proc_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ void *data = PDE_DATA(file_inode(file));
+ char local_buf[8];
+ int len = snprintf(local_buf, 2, "%1p", data);
+
+ return simple_read_from_buffer(buf, count, ppos, local_buf, len);
+}
+
+static const struct file_operations mmi_acpu_proc_fops = {
+ .read = mmi_acpu_proc_read,
+ .llseek = default_llseek,
+};
+
+void mmi_acpu_bin_set(int *speed, int *pvs, int *ver)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mmi_soc_bin_lock, flags);
+ if (mmi_soc_bin_info.set & ACPU_BIN_SET) {
+ spin_unlock_irqrestore(&mmi_soc_bin_lock, flags);
+ return;
+ }
+ mmi_soc_bin_info.speed = speed ? *speed : MMI_SOC_BIN_INVAL;
+ mmi_soc_bin_info.pvs = pvs ? *pvs : MMI_SOC_BIN_INVAL;
+ mmi_soc_bin_info.ver = ver ? *ver : MMI_SOC_BIN_INVAL;
+ mmi_soc_bin_info.set |= ACPU_BIN_SET;
+ spin_unlock_irqrestore(&mmi_soc_bin_lock, flags);
+}
+
+static void __init mmi_soc_acpu_bin_export(void)
+{
+ struct proc_dir_entry *proc;
+ unsigned long flags;
+ char acpu[64];
+
+ spin_lock_irqsave(&mmi_soc_bin_lock, flags);
+ if (!(mmi_soc_bin_info.set & ACPU_BIN_SET)) {
+ spin_unlock_irqrestore(&mmi_soc_bin_lock, flags);
+ pr_err("ACPU Bin is not available.\n");
+ return;
+ }
+ spin_unlock_irqrestore(&mmi_soc_bin_lock, flags);
+
+ mmi_panic_annotate("ACPU: ");
+ if (mmi_soc_bin_info.speed != MMI_SOC_BIN_INVAL) {
+ snprintf(acpu, sizeof(acpu), "Speed bin %d ",
+ mmi_soc_bin_info.speed);
+ mmi_panic_annotate(acpu);
+ }
+ if (mmi_soc_bin_info.pvs != MMI_SOC_BIN_INVAL) {
+ proc = proc_create_data("cpu/soc_acpu_pvs",
+ (S_IFREG | S_IRUGO), NULL,
+ &mmi_acpu_proc_fops, (void *)(uintptr_t)mmi_soc_bin_info.pvs);
+ if (!proc)
+ pr_err("Failed to create /proc/cpu/soc_acpu_pvs.\n");
+ else
+ proc_set_size(proc, 1);
+ snprintf(acpu, sizeof(acpu), "PVS bin %d ",
+ mmi_soc_bin_info.pvs);
+ mmi_panic_annotate(acpu);
+ }
+ if (mmi_soc_bin_info.ver != MMI_SOC_BIN_INVAL) {
+ snprintf(acpu, sizeof(acpu), "PVS version %d ",
+ mmi_soc_bin_info.ver);
+ mmi_panic_annotate(acpu);
+ }
+ mmi_panic_annotate("\n");
+}
+
+static int __init init_mmi_soc_info(void)
+{
+ mmi_soc_annotate_socinfo();
+ mmi_soc_acpu_bin_export();
+ return 0;
+}
+module_init(init_mmi_soc_info);
+MODULE_DESCRIPTION("Motorola Mobility LLC. SOC Info");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Copyright (C) 2016 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/pstore.h>
+#include "mmi_storage_info.h"
+
+struct mmi_storage_info *info;
+
+static ssize_t sysfsst_fw_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 32, "%s\n", info->firmware_version);
+}
+
+static ssize_t sysfsst_model_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 32, "%s\n", info->product_name);
+}
+
+static ssize_t sysfsst_vendor_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 32, "%s\n", info->card_manufacturer);
+}
+
+static ssize_t sysfsst_size_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 16, "%s\n", info->size);
+}
+
+static ssize_t sysfsst_type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 16, "%s\n", info->type);
+}
+
+static struct kobj_attribute st_fw_attr =
+ __ATTR(fw, 0444, sysfsst_fw_show, NULL);
+
+static struct kobj_attribute st_model_attr =
+ __ATTR(model, 0444, sysfsst_model_show, NULL);
+
+static struct kobj_attribute st_vendor_attr =
+ __ATTR(vendor, 0444, sysfsst_vendor_show, NULL);
+
+static struct kobj_attribute st_size_attr =
+ __ATTR(size, 0444, sysfsst_size_show, NULL);
+
+static struct kobj_attribute st_type_attr =
+ __ATTR(type, 0444, sysfsst_type_show, NULL);
+
+static struct attribute *st_info_properties_attrs[] = {
+ &st_fw_attr.attr,
+ &st_model_attr.attr,
+ &st_vendor_attr.attr,
+ &st_size_attr.attr,
+ &st_type_attr.attr,
+ NULL
+};
+
+static struct attribute_group st_info_properties_attr_group = {
+ .attrs = st_info_properties_attrs,
+};
+
+static int __init mmi_storage_info_init(void)
+{
+ int ret = 0;
+ int status = 0;
+ struct property *p;
+ struct device_node *n;
+ char apanic_annotation[128];
+ static struct kobject *st_info_properties_kobj;
+
+ n = of_find_node_by_path("/chosen/mmi,storage");
+ if (n == NULL) {
+ ret = 1;
+ goto err;
+ }
+
+ info = kzalloc(sizeof(struct mmi_storage_info), GFP_KERNEL);
+ if (!info) {
+ pr_err("%s: failed to allocate space for mmi_storage_info\n",
+ __func__);
+ ret = 1;
+ goto err;
+ }
+
+ for_each_property_of_node(n, p) {
+ if (!strcmp(p->name, "type") && p->value)
+ strlcpy(info->type, (char *)p->value,
+ sizeof(info->type));
+ if (!strcmp(p->name, "size") && p->value)
+ strlcpy(info->size, (char *)p->value,
+ sizeof(info->size));
+ if (!strcmp(p->name, "manufacturer") && p->value)
+ strlcpy(info->card_manufacturer, (char *)p->value,
+ sizeof(info->card_manufacturer));
+ if (!strcmp(p->name, "product") && p->value)
+ strlcpy(info->product_name, (char *)p->value,
+ sizeof(info->product_name));
+ if (!strcmp(p->name, "firmware") && p->value)
+ strlcpy(info->firmware_version, (char *)p->value,
+ sizeof(info->firmware_version));
+ }
+
+ of_node_put(n);
+
+ pr_info("mmi_storage_info :%s: %s %s %s FV=%s\n",
+ info->type,
+ info->size,
+ info->card_manufacturer,
+ info->product_name,
+ info->firmware_version);
+
+ /* Append the storage info to apanic annotation */
+ snprintf(apanic_annotation, sizeof(apanic_annotation),
+ "%s: %s %s %s FV=%s\n",
+ info->type,
+ info->size,
+ info->card_manufacturer,
+ info->product_name,
+ info->firmware_version);
+ pstore_annotate(apanic_annotation);
+
+ /* Export to sysfs*/
+ st_info_properties_kobj = kobject_create_and_add("storage", NULL);
+ if (st_info_properties_kobj)
+ status = sysfs_create_group(st_info_properties_kobj,
+ &st_info_properties_attr_group);
+
+ if (!st_info_properties_kobj || status) {
+ pr_err("%s: failed to create /sys/storage\n", __func__);
+ ret = 1;
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
+void __exit mmi_storage_info_exit(void)
+{
+ if (info) {
+ kfree(info);
+ info = NULL;
+ }
+}
+
+module_init(mmi_storage_info_init);
+module_exit(mmi_storage_info_exit);
+MODULE_DESCRIPTION("Motorola Mobility LLC. Storage Info");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * Copyright (C) 2016 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ARCH_ARM_MACH_SOC_MMI_EMMC_INFO_H
+#define __ARCH_ARM_MACH_SOC_MMI_EMMC_INFO_H
+
+struct mmi_storage_info {
+ char type[16]; /* UFS or eMMC */
+ char size[16]; /* size in GB */
+ char card_manufacturer[32];
+ char product_name[32]; /* model ID */
+ char firmware_version[32];
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SOCINFO_H_
+#define _SOCINFO_H_
+
+#define SOCINFO_VERSION_MAJOR(ver) (((ver) & 0xffff0000) >> 16)
+#define SOCINFO_VERSION_MINOR(ver) ((ver) & 0x0000ffff)
+#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff))
+
+
+uint32_t socinfo_get_id(void)
+{
+ return 0;
+}
+uint32_t socinfo_get_version(void)
+{
+ return 0;
+}
+uint32_t socinfo_get_raw_id(void)
+{
+ return 0;
+}
+uint32_t socinfo_get_raw_version(void)
+{
+ return 0;
+}
+uint32_t socinfo_get_platform_type(void)
+{
+ return 0;
+}
+uint32_t socinfo_get_platform_subtype(void)
+{
+ return 0;
+}
+uint32_t socinfo_get_platform_version(void)
+{
+ return 0;
+}
+
+#endif