Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c996d9cb authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge changes...

Merge changes I6ef5690a,I354e1f76,I5a64107e,If3813542,I14e2d137,I7520d13f,I6f3e837e,Ic111d719 into msm-next

* changes:
  power: reset: Remove deprecated APIs usage related to SCM
  power: reset: Skip emmc_dload sysfs entry creation
  power: reset: Disable SDI when dload mode is not supported
  power: reset: Add support for EMMC dload
  power: reset: Disable SDI when dload mode is disabled
  power: reset: Store KASLR offset in IMEM
  Documentation: msm: imem: snapshot of imem documentation file
  power: reset: Fix compilation error when CONFIG_QCOM_DLOAD_MODE=n
parents f9d9126f adcb4288
Loading
Loading
Loading
Loading
+124 −0
Original line number Diff line number Diff line
Qualcomm IMEM

IMEM is fast on-chip memory used for various debug features and dma transactions.

Required properties

-compatible: "qcom,msm-imem"
-reg: start address and size of imem memory

If any children nodes exist the following properties are required:
-#address-cells: should be 1
-#size-cells: should be 1
-ranges: A triplet that includes the child address, parent address, &
	 length.  The child address is assumed to be 0.

Child nodes:
------------

Peripheral Image Loader (pil):
------------------------------
Required properties:
-compatible: "qcom,msm-imem-pil"
-reg: start address and size of PIL region in imem

Bootloader Stats:
-----------------
Required properties:
-compatible: "qcom,msm-imem-boot_stats"
-reg: start address and size of boot_stats region in imem

Cache error reporting:
-----------------
Required properties:
-compatible: "qcom,msm-imem-cache_erp"
-reg: start address and size of cache_erp region in imem

Memory Dump:
------------
Required properties:
-compatible: "qcom,msm-imem-mem_dump_table"
-reg: start address and size of mem_dump_table region in imem

Restart Reason:
---------------
Required properties:
-compatible: "qcom,msm-imem-restart_reason
-reg: start address and size of restart_reason region in imem

Download Mode Type:
-------------------
Required properties:
-compatible: "qcom,msm-imem-dload-type"
-reg: start address and size of dload type region in imem

Download Mode:
--------------
Required properties:
-compatible: "qcom,msm-imem-download_mode"
-reg: start address and size of download_mode region in imem

Emergency Download Mode:
------------------------
-compatible: "qcom,msm-imem-emergency_download_mode"
-reg: start address and size of emergency_download_mode region in imem

Kaslr Offset:
------------------------
-compatible: "qcom,msm-imem-kaslr_offset"
-reg: start address and size of kaslr_offset region in imem

USB Diag Cookies:
-----------------
Memory region used to store USB PID and serial numbers to be used by
bootloader in download mode.

Required properties:
-compatible: "qcom,msm-imem-diag-dload"
-reg: start address and size of USB Diag download mode region in imem

Example:

	qcom,msm-imem {
		compatible = "qcom,msm-imem";
		reg = <0xdeadbeef 0x1000>; /* < start_address size > */
		ranges = <0x0 0xdeadbeef 0x1000>;
		#address-cells = <1>;
		#size-cells = <1>;

		download_mode@0 {
			compatible = "qcom,msm-imem-download_mode";
			reg = <0x0 8>;
		};

		restart_reason@65c {
			compatible = "qcom,msm-imem-restart_reason";
			reg = <0x65c 4>;
		};

		imem_cache_erp: cache_erp@6a4 {
			compatible = "qcom,msm-imem-cache_erp";
			reg = <0x6a4 4>;
		};

		boot_stats@6b0 {
			compatible = "qcom,msm-imem-boot_stats";
			reg = <0x6b0 32>;
		};

		kaslr_offset@6d0 {
			compatible = "qcom,msm-imem-kaslr_offset";
			reg = <0x6d0 12>;
		};


		pil@94c {
			compatible = "qcom,msm-imem-pil";
			reg = <0x94c 200>;
		};

		emergency_download_mode@fe0 {
			compatible = "qcom,msm-imem-emergency_download_mode";
			reg = <0xfe0 12>;
		};
	};
+188 −54
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@

#include <asm/cacheflush.h>
#include <asm/system_misc.h>
#include <asm/memory.h>

#include <soc/qcom/scm.h>
#include <soc/qcom/restart.h>
@@ -36,6 +37,7 @@
#define EMERGENCY_DLOAD_MAGIC1    0x322A4F99
#define EMERGENCY_DLOAD_MAGIC2    0xC67E4350
#define EMERGENCY_DLOAD_MAGIC3    0x77777777
#define EMMC_DLOAD_TYPE		0x2

#define SCM_IO_DISABLE_PMIC_ARBITER	1
#define SCM_IO_DEASSERT_PS_HOLD		2
@@ -46,27 +48,56 @@


static int restart_mode;
void *restart_reason;
static void *restart_reason, *dload_type_addr;
static bool scm_pmic_arbiter_disable_supported;
static bool scm_deassert_ps_hold_supported;
/* Download mode master kill-switch */
static void __iomem *msm_ps_hold;
static phys_addr_t tcsr_boot_misc_detect;
static void scm_disable_sdi(void);

/*
 * Runtime could be only changed value once.
 * There is no API from TZ to re-enable the registers.
 * So the SDI cannot be re-enabled when it already by-passed.
 */
static int download_mode = 1;
static struct kobject dload_kobj;

#ifdef CONFIG_QCOM_DLOAD_MODE
#define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode"
#define DL_MODE_PROP "qcom,msm-imem-download_mode"
#ifdef CONFIG_RANDOMIZE_BASE
#define KASLR_OFFSET_PROP "qcom,msm-imem-kaslr_offset"
#endif

static int in_panic;
static void *dload_mode_addr;
static bool dload_mode_enabled;
static void *emergency_dload_mode_addr;
#ifdef CONFIG_RANDOMIZE_BASE
static void *kaslr_imem_addr;
#endif
static bool scm_dload_supported;

static int dload_set(const char *val, struct kernel_param *kp);
static int download_mode = 1;
/* interface for exporting attributes */
struct reset_attribute {
	struct attribute        attr;
	ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
			char *buf);
	size_t (*store)(struct kobject *kobj, struct attribute *attr,
			const char *buf, size_t count);
};
#define to_reset_attr(_attr) \
	container_of(_attr, struct reset_attribute, attr)
#define RESET_ATTR(_name, _mode, _show, _store)	\
	static struct reset_attribute reset_attr_##_name = \
			__ATTR(_name, _mode, _show, _store)

module_param_call(download_mode, dload_set, param_get_int,
			&download_mode, 0644);

static int panic_prep_restart(struct notifier_block *this,
			      unsigned long event, void *ptr)
{
@@ -93,10 +124,6 @@ int scm_set_dload_mode(int arg1, int arg2)
		return 0;
	}

	if (!is_scm_armv8())
		return scm_call_atomic2(SCM_SVC_BOOT, SCM_DLOAD_CMD, arg1,
					arg2);

	return scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, SCM_DLOAD_CMD),
				&desc);
}
@@ -174,7 +201,10 @@ static int dload_set(const char *val, struct kernel_param *kp)
	return 0;
}
#else
#define set_dload_mode(x) do {} while (0)
static void set_dload_mode(int on)
{
	return;
}

static void enable_emergency_dload_mode(void)
{
@@ -187,6 +217,22 @@ static bool get_dload_mode(void)
}
#endif

static void scm_disable_sdi(void)
{
	int ret;
	struct scm_desc desc = {
		.args[0] = 1,
		.args[1] = 0,
		.arginfo = SCM_ARGS(2),
	};

	/* Needed to bypass debug image on some chips */
	ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT,
			  SCM_WDOG_DEBUG_BOOT_PART), &desc);
	if (ret)
		pr_err("Failed to disable secure wdog debug: %d\n", ret);
}

void msm_set_restart_mode(int mode)
{
	restart_mode = mode;
@@ -208,10 +254,6 @@ static void halt_spmi_pmic_arbiter(void)

	if (scm_pmic_arbiter_disable_supported) {
		pr_crit("Calling SCM to disable SPMI PMIC arbiter\n");
		if (!is_scm_armv8())
			scm_call_atomic1(SCM_SVC_PWR,
					 SCM_IO_DISABLE_PMIC_ARBITER, 0);
		else
		scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_PWR,
				SCM_IO_DISABLE_PMIC_ARBITER), &desc);
	}
@@ -219,10 +261,8 @@ static void halt_spmi_pmic_arbiter(void)

static void msm_restart_prepare(const char *cmd)
{
#ifdef CONFIG_QCOM_DLOAD_MODE
	bool need_warm_reset = false;


#ifdef CONFIG_QCOM_DLOAD_MODE
	/* Write download mode flags if we're panic'ing
	 * Write download mode flags if restart_mode says so
	 * Kill download mode if master-kill switch is set
@@ -289,8 +329,6 @@ static void msm_restart_prepare(const char *cmd)
		}
	}

	flush_cache_all();

	/*outer_flush_all is not supported by 64bit kernel*/
#ifndef CONFIG_ARM64
	outer_flush_all();
@@ -324,13 +362,6 @@ static void deassert_ps_hold(void)

static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
{
	int ret;
	struct scm_desc desc = {
		.args[0] = 1,
		.args[1] = 0,
		.arginfo = SCM_ARGS(2),
	};

	pr_notice("Going down for restart now\n");

	msm_restart_prepare(cmd);
@@ -345,16 +376,7 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
		msm_trigger_wdog_bite();
#endif

	/* Needed to bypass debug image on some chips */
	if (!is_scm_armv8())
		ret = scm_call_atomic2(SCM_SVC_BOOT,
			       SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
	else
		ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT,
			  SCM_WDOG_DEBUG_BOOT_PART), &desc);
	if (ret)
		pr_err("Failed to disable secure wdog debug: %d\n", ret);

	scm_disable_sdi();
	halt_spmi_pmic_arbiter();
	deassert_ps_hold();

@@ -363,27 +385,11 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)

static void do_msm_poweroff(void)
{
	int ret;
	struct scm_desc desc = {
		.args[0] = 1,
		.args[1] = 0,
		.arginfo = SCM_ARGS(2),
	};

	pr_notice("Powering off the SoC\n");
#ifdef CONFIG_QCOM_DLOAD_MODE

	set_dload_mode(0);
#endif
	scm_disable_sdi();
	qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
	/* Needed to bypass debug image on some chips */
	if (!is_scm_armv8())
		ret = scm_call_atomic2(SCM_SVC_BOOT,
			       SCM_WDOG_DEBUG_BOOT_PART, 1, 0);
	else
		ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT,
			  SCM_WDOG_DEBUG_BOOT_PART), &desc);
	if (ret)
		pr_err("Failed to disable wdog debug: %d\n", ret);

	halt_spmi_pmic_arbiter();
	deassert_ps_hold();
@@ -392,6 +398,84 @@ static void do_msm_poweroff(void)
	pr_err("Powering off has failed\n");
}

static ssize_t attr_show(struct kobject *kobj, struct attribute *attr,
				char *buf)
{
	struct reset_attribute *reset_attr = to_reset_attr(attr);
	ssize_t ret = -EIO;

	if (reset_attr->show)
		ret = reset_attr->show(kobj, attr, buf);

	return ret;
}

static ssize_t attr_store(struct kobject *kobj, struct attribute *attr,
				const char *buf, size_t count)
{
	struct reset_attribute *reset_attr = to_reset_attr(attr);
	ssize_t ret = -EIO;

	if (reset_attr->store)
		ret = reset_attr->store(kobj, attr, buf, count);

	return ret;
}

static const struct sysfs_ops reset_sysfs_ops = {
	.show	= attr_show,
	.store	= attr_store,
};

static struct kobj_type reset_ktype = {
	.sysfs_ops	= &reset_sysfs_ops,
};

static ssize_t show_emmc_dload(struct kobject *kobj, struct attribute *attr,
				char *buf)
{
	uint32_t read_val, show_val;

	read_val = __raw_readl(dload_type_addr);
	if (read_val == EMMC_DLOAD_TYPE)
		show_val = 1;
	else
		show_val = 0;

	return snprintf(buf, sizeof(show_val), "%u\n", show_val);
}

static size_t store_emmc_dload(struct kobject *kobj, struct attribute *attr,
				const char *buf, size_t count)
{
	uint32_t enabled;
	int ret;

	ret = kstrtouint(buf, 0, &enabled);
	if (ret < 0)
		return ret;

	if (!((enabled == 0) || (enabled == 1)))
		return -EINVAL;

	if (enabled == 1)
		__raw_writel(EMMC_DLOAD_TYPE, dload_type_addr);
	else
		__raw_writel(0, dload_type_addr);

	return count;
}
RESET_ATTR(emmc_dload, 0644, show_emmc_dload, store_emmc_dload);

static struct attribute *reset_attrs[] = {
	&reset_attr_emmc_dload.attr,
	NULL
};

static struct attribute_group reset_attr_group = {
	.attrs = reset_attrs,
};

static int msm_restart_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
@@ -422,6 +506,54 @@ static int msm_restart_probe(struct platform_device *pdev)
			pr_err("unable to map imem EDLOAD mode offset\n");
	}

#ifdef CONFIG_RANDOMIZE_BASE
#define KASLR_OFFSET_BIT_MASK	0x00000000FFFFFFFF
	np = of_find_compatible_node(NULL, NULL, KASLR_OFFSET_PROP);
	if (!np) {
		pr_err("unable to find DT imem KASLR_OFFSET node\n");
	} else {
		kaslr_imem_addr = of_iomap(np, 0);
		if (!kaslr_imem_addr)
			pr_err("unable to map imem KASLR offset\n");
	}

	if (kaslr_imem_addr && scm_is_secure_device()) {
		__raw_writel(0xdead4ead, kaslr_imem_addr);
		__raw_writel(KASLR_OFFSET_BIT_MASK &
		(kimage_vaddr - KIMAGE_VADDR), kaslr_imem_addr + 4);
		__raw_writel(KASLR_OFFSET_BIT_MASK &
			((kimage_vaddr - KIMAGE_VADDR) >> 32),
			kaslr_imem_addr + 8);
		iounmap(kaslr_imem_addr);
	}
#endif
	np = of_find_compatible_node(NULL, NULL,
				"qcom,msm-imem-dload-type");
	if (!np) {
		pr_err("unable to find DT imem dload-type node\n");
		goto skip_sysfs_create;
	} else {
		dload_type_addr = of_iomap(np, 0);
		if (!dload_type_addr) {
			pr_err("unable to map imem dload-type offset\n");
			goto skip_sysfs_create;
		}
	}

	ret = kobject_init_and_add(&dload_kobj, &reset_ktype,
			kernel_kobj, "%s", "dload");
	if (ret) {
		pr_err("%s:Error in creation kobject_add\n", __func__);
		kobject_put(&dload_kobj);
		goto skip_sysfs_create;
	}

	ret = sysfs_create_group(&dload_kobj, &reset_attr_group);
	if (ret) {
		pr_err("%s:Error in creation sysfs_create_group\n", __func__);
		kobject_del(&dload_kobj);
	}
skip_sysfs_create:
#endif
	np = of_find_compatible_node(NULL, NULL,
				"qcom,msm-imem-restart_reason");
@@ -457,6 +589,8 @@ static int msm_restart_probe(struct platform_device *pdev)

	download_mode = scm_is_secure_device();
	set_dload_mode(download_mode);
	if (!download_mode)
		scm_disable_sdi();

	return 0;

@@ -486,4 +620,4 @@ static int __init msm_restart_init(void)
{
	return platform_driver_register(&msm_restart_driver);
}
device_initcall(msm_restart_init);
pure_initcall(msm_restart_init);