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

Commit 03347a2f authored by Jilai Wang's avatar Jilai Wang
Browse files

msm: npu: Add auto PIL support



This change is to add auto PIL support for NPU. It will create a
sysfs node which can be used to preload NPU fw during system boots
up. When executing networks, driver won't load fw, but only turn on
NPU power and clocks.

Change-Id: I7ab37ae73db8ff6e1a2f88c5707ff861cf0268b3
Signed-off-by: default avatarJilai Wang <jilaiw@codeaurora.org>
parent f74ff626
Loading
Loading
Loading
Loading
+11 −4
Original line number Original line Diff line number Diff line
@@ -186,12 +186,13 @@ struct npu_thermalctrl {
	uint32_t pwr_level;
	uint32_t pwr_level;
};
};


#define NPU_MAX_IRQ		3
#define NPU_MAX_IRQ		8


struct npu_irq {
struct npu_irq {
	char *name;
	char *name;
	int irq;
	int irq;
	int irq_type;
	int irq_type;
	irq_handler_t handler;
};
};


struct npu_io_data {
struct npu_io_data {
@@ -212,6 +213,7 @@ struct npu_device {


	struct npu_io_data core_io;
	struct npu_io_data core_io;
	struct npu_io_data tcm_io;
	struct npu_io_data tcm_io;
	struct npu_io_data cc_io;
	struct npu_io_data qdsp_io;
	struct npu_io_data qdsp_io;
	struct npu_io_data apss_shared_io;
	struct npu_io_data apss_shared_io;
	struct npu_io_data qfprom_io;
	struct npu_io_data qfprom_io;
@@ -268,12 +270,17 @@ void npu_disable_core_power(struct npu_device *npu_dev);
int npu_enable_post_pil_clocks(struct npu_device *npu_dev);
int npu_enable_post_pil_clocks(struct npu_device *npu_dev);
void npu_disable_post_pil_clocks(struct npu_device *npu_dev);
void npu_disable_post_pil_clocks(struct npu_device *npu_dev);


irqreturn_t npu_intr_hdler(int irq, void *ptr);
irqreturn_t npu_ipc_intr_hdlr(int irq, void *ptr);
irqreturn_t npu_general_intr_hdlr(int irq, void *ptr);
irqreturn_t npu_err_intr_hdlr(int irq, void *ptr);
irqreturn_t npu_wdg_intr_hdlr(int irq, void *ptr);


int npu_set_uc_power_level(struct npu_device *npu_dev,
int npu_set_uc_power_level(struct npu_device *npu_dev,
	uint32_t pwr_level);
	uint32_t pwr_level);


int fw_init(struct npu_device *npu_dev);
int enable_fw(struct npu_device *npu_dev);
void fw_deinit(struct npu_device *npu_dev, bool ssr, bool fw_alive);
void disable_fw(struct npu_device *npu_dev);
int load_fw(struct npu_device *npu_dev);
int unload_fw(struct npu_device *npu_dev);


#endif /* _NPU_COMMON_H */
#endif /* _NPU_COMMON_H */
+2 −2
Original line number Original line Diff line number Diff line
@@ -365,11 +365,11 @@ static ssize_t npu_debug_ctrl_write(struct file *file,


	if (strcmp(buf, "on") == 0) {
	if (strcmp(buf, "on") == 0) {
		NPU_INFO("triggering fw_init\n");
		NPU_INFO("triggering fw_init\n");
		if (fw_init(npu_dev) != 0)
		if (enable_fw(npu_dev) != 0)
			NPU_INFO("error in fw_init\n");
			NPU_INFO("error in fw_init\n");
	} else if (strcmp(buf, "off") == 0) {
	} else if (strcmp(buf, "off") == 0) {
		NPU_INFO("triggering fw_deinit\n");
		NPU_INFO("triggering fw_deinit\n");
		fw_deinit(npu_dev, false, true);
		disable_fw(npu_dev);
	} else if (strcmp(buf, "ssr") == 0) {
	} else if (strcmp(buf, "ssr") == 0) {
		NPU_INFO("trigger error irq\n");
		NPU_INFO("trigger error irq\n");
		if (npu_enable_core_power(npu_dev))
		if (npu_enable_core_power(npu_dev))
+94 −8
Original line number Original line Diff line number Diff line
@@ -57,6 +57,9 @@ static ssize_t perf_mode_override_show(struct device *dev,
static ssize_t perf_mode_override_store(struct device *dev,
static ssize_t perf_mode_override_store(struct device *dev,
					  struct device_attribute *attr,
					  struct device_attribute *attr,
					  const char *buf, size_t count);
					  const char *buf, size_t count);
static ssize_t boot_store(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count);
static bool npu_is_post_clock(const char *clk_name);
static bool npu_is_post_clock(const char *clk_name);
static bool npu_is_exclude_rate_clock(const char *clk_name);
static bool npu_is_exclude_rate_clock(const char *clk_name);
static int npu_get_max_state(struct thermal_cooling_device *cdev,
static int npu_get_max_state(struct thermal_cooling_device *cdev,
@@ -129,10 +132,13 @@ static const char * const npu_exclude_rate_clocks[] = {
	"s2p_clk",
	"s2p_clk",
};
};


static const struct npu_irq npu_irq_info[NPU_MAX_IRQ] = {
static const struct npu_irq npu_irq_info[] = {
	{"ipc_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT},
	{"ipc_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT, npu_ipc_intr_hdlr},
	{"error_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT},
	{"general_irq", 0,  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
	{"wdg_bite_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT},
		npu_general_intr_hdlr},
	{"error_irq", 0,  IRQF_TRIGGER_HIGH | IRQF_ONESHOT, npu_err_intr_hdlr},
	{"wdg_bite_irq", 0,  IRQF_TRIGGER_RISING | IRQF_ONESHOT,
		npu_wdg_intr_hdlr}
};
};


static struct npu_device *g_npu_dev;
static struct npu_device *g_npu_dev;
@@ -145,11 +151,13 @@ static struct npu_device *g_npu_dev;
static DEVICE_ATTR_RO(caps);
static DEVICE_ATTR_RO(caps);
static DEVICE_ATTR_RW(pwr);
static DEVICE_ATTR_RW(pwr);
static DEVICE_ATTR_RW(perf_mode_override);
static DEVICE_ATTR_RW(perf_mode_override);
static DEVICE_ATTR_WO(boot);


static struct attribute *npu_fs_attrs[] = {
static struct attribute *npu_fs_attrs[] = {
	&dev_attr_caps.attr,
	&dev_attr_caps.attr,
	&dev_attr_pwr.attr,
	&dev_attr_pwr.attr,
	&dev_attr_perf_mode_override.attr,
	&dev_attr_perf_mode_override.attr,
	&dev_attr_boot.attr,
	NULL
	NULL
};
};


@@ -285,6 +293,36 @@ static ssize_t perf_mode_override_store(struct device *dev,
	return count;
	return count;
}
}


/* -------------------------------------------------------------------------
 * SysFS - npu_boot
 * -------------------------------------------------------------------------
 */
static ssize_t boot_store(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count)
{
	struct npu_device *npu_dev = dev_get_drvdata(dev);
	bool enable = false;
	int rc;

	if (strtobool(buf, &enable) < 0)
		return -EINVAL;

	if (enable) {
		NPU_DBG("%s: load fw\n", __func__);
		rc = load_fw(npu_dev);
		if (rc) {
			NPU_ERR("fw init failed\n");
			return rc;
		}
	} else {
		NPU_INFO("%s: unload fw\n", __func__);
		unload_fw(npu_dev);
	}

	return count;
}

/* -------------------------------------------------------------------------
/* -------------------------------------------------------------------------
 * Power Related
 * Power Related
 * -------------------------------------------------------------------------
 * -------------------------------------------------------------------------
@@ -451,12 +489,13 @@ static int npu_set_power_level(struct npu_device *npu_dev, bool notify_cxlimit)


		ret = 0;
		ret = 0;
	}
	}

	for (i = 0; i < npu_dev->core_clk_num; i++) {
	for (i = 0; i < npu_dev->core_clk_num; i++) {
		if (npu_is_exclude_rate_clock(
		if (npu_is_exclude_rate_clock(
			npu_dev->core_clks[i].clk_name))
			npu_dev->core_clks[i].clk_name))
			continue;
			continue;


		if (npu_dev->host_ctx.fw_state == FW_DISABLED) {
		if (npu_dev->host_ctx.fw_state != FW_ENABLED) {
			if (npu_is_post_clock(
			if (npu_is_post_clock(
				npu_dev->core_clks[i].clk_name))
				npu_dev->core_clks[i].clk_name))
				continue;
				continue;
@@ -721,7 +760,21 @@ static void npu_disable_regulators(struct npu_device *npu_dev)
int npu_enable_irq(struct npu_device *npu_dev)
int npu_enable_irq(struct npu_device *npu_dev)
{
{
	int i;
	int i;

	uint32_t reg_val;

	/* setup general irq */
	reg_val = npu_cc_reg_read(npu_dev,
		NPU_CC_NPU_MASTERn_GENERAL_IRQ_OWNER(0));
	reg_val |= RSC_SHUTDOWN_REQ_IRQ_ENABLE | RSC_BRINGUP_REQ_IRQ_ENABLE;
	npu_cc_reg_write(npu_dev, NPU_CC_NPU_MASTERn_GENERAL_IRQ_OWNER(0),
		reg_val);
	reg_val = npu_cc_reg_read(npu_dev,
		NPU_CC_NPU_MASTERn_GENERAL_IRQ_ENABLE(0));
	reg_val |= RSC_SHUTDOWN_REQ_IRQ_ENABLE | RSC_BRINGUP_REQ_IRQ_ENABLE;
	npu_cc_reg_write(npu_dev, NPU_CC_NPU_MASTERn_GENERAL_IRQ_ENABLE(0),
		reg_val);
	npu_cc_reg_write(npu_dev, NPU_CC_NPU_MASTERn_GENERAL_IRQ_CLEAR(0),
		RSC_SHUTDOWN_REQ_IRQ_ENABLE | RSC_BRINGUP_REQ_IRQ_ENABLE);
	for (i = 0; i < NPU_MAX_IRQ; i++) {
	for (i = 0; i < NPU_MAX_IRQ; i++) {
		if (npu_dev->irq[i].irq != 0) {
		if (npu_dev->irq[i].irq != 0) {
			enable_irq(npu_dev->irq[i].irq);
			enable_irq(npu_dev->irq[i].irq);
@@ -735,6 +788,7 @@ int npu_enable_irq(struct npu_device *npu_dev)
void npu_disable_irq(struct npu_device *npu_dev)
void npu_disable_irq(struct npu_device *npu_dev)
{
{
	int i;
	int i;
	uint32_t reg_val;


	for (i = 0; i < NPU_MAX_IRQ; i++) {
	for (i = 0; i < NPU_MAX_IRQ; i++) {
		if (npu_dev->irq[i].irq != 0) {
		if (npu_dev->irq[i].irq != 0) {
@@ -742,6 +796,19 @@ void npu_disable_irq(struct npu_device *npu_dev)
			NPU_DBG("disable irq %d\n", npu_dev->irq[i].irq);
			NPU_DBG("disable irq %d\n", npu_dev->irq[i].irq);
		}
		}
	}
	}

	reg_val = npu_cc_reg_read(npu_dev,
		NPU_CC_NPU_MASTERn_GENERAL_IRQ_OWNER(0));
	reg_val &= ~(RSC_SHUTDOWN_REQ_IRQ_ENABLE | RSC_BRINGUP_REQ_IRQ_ENABLE);
	npu_cc_reg_write(npu_dev, NPU_CC_NPU_MASTERn_GENERAL_IRQ_OWNER(0),
		reg_val);
	reg_val = npu_cc_reg_read(npu_dev,
		NPU_CC_NPU_MASTERn_GENERAL_IRQ_ENABLE(0));
	reg_val &= ~(RSC_SHUTDOWN_REQ_IRQ_ENABLE | RSC_BRINGUP_REQ_IRQ_ENABLE);
	npu_cc_reg_write(npu_dev, NPU_CC_NPU_MASTERn_GENERAL_IRQ_ENABLE(0),
		reg_val);
	npu_cc_reg_write(npu_dev, NPU_CC_NPU_MASTERn_GENERAL_IRQ_CLEAR(0),
		RSC_SHUTDOWN_REQ_IRQ_ENABLE | RSC_BRINGUP_REQ_IRQ_ENABLE);
}
}


/* -------------------------------------------------------------------------
/* -------------------------------------------------------------------------
@@ -1513,7 +1580,7 @@ static int npu_irq_init(struct npu_device *npu_dev)
	int ret = 0, i;
	int ret = 0, i;


	memcpy(npu_dev->irq, npu_irq_info, sizeof(npu_irq_info));
	memcpy(npu_dev->irq, npu_irq_info, sizeof(npu_irq_info));
	for (i = 0; i < NPU_MAX_IRQ; i++) {
	for (i = 0; i < ARRAY_SIZE(npu_irq_info); i++) {
		irq_type = npu_irq_info[i].irq_type;
		irq_type = npu_irq_info[i].irq_type;
		npu_dev->irq[i].irq = platform_get_irq_byname(
		npu_dev->irq[i].irq = platform_get_irq_byname(
			npu_dev->pdev, npu_dev->irq[i].name);
			npu_dev->pdev, npu_dev->irq[i].name);
@@ -1529,7 +1596,7 @@ static int npu_irq_init(struct npu_device *npu_dev)
		irq_set_status_flags(npu_dev->irq[i].irq,
		irq_set_status_flags(npu_dev->irq[i].irq,
						IRQ_NOAUTOEN);
						IRQ_NOAUTOEN);
		ret = devm_request_irq(&npu_dev->pdev->dev,
		ret = devm_request_irq(&npu_dev->pdev->dev,
				npu_dev->irq[i].irq, npu_intr_hdler,
				npu_dev->irq[i].irq, npu_dev->irq[i].handler,
				irq_type, npu_dev->irq[i].name,
				irq_type, npu_dev->irq[i].name,
				npu_dev);
				npu_dev);
		if (ret) {
		if (ret) {
@@ -1629,6 +1696,25 @@ static int npu_probe(struct platform_device *pdev)
	NPU_DBG("tcm phy address=0x%llx virt=%pK\n",
	NPU_DBG("tcm phy address=0x%llx virt=%pK\n",
		res->start, npu_dev->tcm_io.base);
		res->start, npu_dev->tcm_io.base);


	res = platform_get_resource_byname(pdev,
		IORESOURCE_MEM, "cc");
	if (!res) {
		NPU_ERR("unable to get cc resource\n");
		rc = -ENODEV;
		goto error_get_dev_num;
	}
	npu_dev->cc_io.size = resource_size(res);
	npu_dev->cc_io.phy_addr = res->start;
	npu_dev->cc_io.base = devm_ioremap(&pdev->dev, res->start,
					npu_dev->cc_io.size);
	if (unlikely(!npu_dev->cc_io.base)) {
		NPU_ERR("unable to map cc\n");
		rc = -ENOMEM;
		goto error_get_dev_num;
	}
	NPU_DBG("cc_io phy address=0x%llx virt=%pK\n",
		res->start, npu_dev->cc_io.base);

	res = platform_get_resource_byname(pdev,
	res = platform_get_resource_byname(pdev,
		IORESOURCE_MEM, "qdsp");
		IORESOURCE_MEM, "qdsp");
	if (!res) {
	if (!res) {
+20 −0
Original line number Original line Diff line number Diff line
@@ -52,4 +52,24 @@


#define APSS_SHARED_IPC_INTERRUPT_1 0x00000010
#define APSS_SHARED_IPC_INTERRUPT_1 0x00000010


/* NPU_CC */
#define NPU_CC_NPU_MASTERn_ERROR_IRQ_OWNER(n) (0x00006000+4*(n))
#define NPU_CC_NPU_MASTERn_ERROR_IRQ_STATUS(n) (0x00009010+0x1000*(n))
#define NPU_CC_NPU_MASTERn_ERROR_IRQ_ENABLE(n) (0x00009018+0x1000*(n))
#define NPU_CC_NPU_MASTERn_ERROR_IRQ_CLEAR(n) (0x0000901C+0x1000*(n))
#define NPU_CC_NPU_MASTERn_GENERAL_IRQ_OWNER(n) (0x00006030+4*(n))
#define NPU_CC_NPU_MASTERn_GENERAL_IRQ_STATUS(n) (0x00009050+0xFC0*(n))
#define NPU_CC_NPU_MASTERn_GENERAL_IRQ_INCLUDE(n) (0x00009054+0xFC0*(n))
#define RSC_SHUTDOWN_REQ_IRQ_STATUS (1 << 11)
#define RSC_BRINGUP_REQ_IRQ_STATUS (1 << 12)
#define NPU_CC_NPU_MASTERn_GENERAL_IRQ_ENABLE(n) (0x00009058+0xFC0*(n))
#define NPU_CC_NPU_MASTERn_GENERAL_IRQ_CLEAR(n) (0x0000905C+0xFC0*(n))
#define RSC_SHUTDOWN_REQ_IRQ_ENABLE (1 << 11)
#define RSC_BRINGUP_REQ_IRQ_ENABLE (1 << 12)
#define NPU_CC_NPU_CPC_RSC_CTRL (0x000011C8)
#define Q6SS_RSC_BRINGUP_ACK_EN (1 << 0)
#define Q6SS_RSC_SHUTDOWN_ACK_EN (1 << 1)
#define NPU_CC_NPU_MASTERn_WDOG_BITE_IRQ_OWNER(n) (0x0006010+4*(n))
#define NPU_CC_NPU_MASTERn_WDOG_BITE_IRQ_STATUS(n) (0x00009030+0x1000*(n))

#endif /* NPU_HW_H */
#endif /* NPU_HW_H */
+16 −0
Original line number Original line Diff line number Diff line
@@ -63,6 +63,22 @@ void npu_apss_shared_reg_write(struct npu_device *npu_dev, uint32_t off,
	__iowmb();
	__iowmb();
}
}


uint32_t npu_cc_reg_read(struct npu_device *npu_dev, uint32_t off)
{
	uint32_t ret = 0;

	ret = readl_relaxed(npu_dev->cc_io.base + off);

	return ret;
}

void npu_cc_reg_write(struct npu_device *npu_dev, uint32_t off,
	uint32_t val)
{
	writel_relaxed(val, npu_dev->cc_io.base + off);
	__iowmb();
}

uint32_t npu_qfprom_reg_read(struct npu_device *npu_dev, uint32_t off)
uint32_t npu_qfprom_reg_read(struct npu_device *npu_dev, uint32_t off)
{
{
	uint32_t ret = 0;
	uint32_t ret = 0;
Loading