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

Commit 1142b662 authored by Jilai Wang's avatar Jilai Wang
Browse files

msm: npu: Add NPU support for Kona



This change is to update NPU driver to support Kona.

Change-Id: I055076c1daed5c8839a07105cf05aabd7de6684f
Signed-off-by: default avatarJilai Wang <jilaiw@codeaurora.org>
parent 3b3e314b
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@
#define ROW_BYTES 16
#define GROUP_BYTES 4

#define NUM_MAX_CLK_NUM			24
#define NUM_MAX_CLK_NUM			48
#define NPU_MAX_REGULATOR_NUM	2
#define NPU_MAX_DT_NAME_LEN	    21
#define NPU_MAX_PWRLEVELS		8
@@ -188,6 +188,7 @@ struct npu_irq {

struct npu_io_data {
	size_t size;
	phys_addr_t phy_addr;
	void __iomem *base;
};

@@ -203,6 +204,8 @@ struct npu_device {

	struct npu_io_data core_io;
	struct npu_io_data tcm_io;
	struct npu_io_data qdsp_io;
	struct npu_io_data apss_shared_io;
	struct npu_io_data bwmon_io;
	struct npu_io_data qfprom_io;

+58 −86
Original line number Diff line number Diff line
@@ -59,8 +59,6 @@ static ssize_t perf_mode_override_show(struct device *dev,
static ssize_t perf_mode_override_store(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count);
static void npu_suspend_devbw(struct npu_device *npu_dev);
static void npu_resume_devbw(struct npu_device *npu_dev);
static bool npu_is_post_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,
@@ -126,20 +124,21 @@ static const char * const npu_exclude_rate_clocks[] = {
	"npu_cpc_timer_clk",
	"qtimer_core_clk",
	"bwmon_clk",
	"bto_core_clk"
};

static struct npu_reg npu_saved_bw_registers[] = {
	{ BWMON2_SAMPLING_WINDOW, 0, false },
	{ BWMON2_BYTE_COUNT_THRESHOLD_HIGH, 0, false },
	{ BWMON2_BYTE_COUNT_THRESHOLD_MEDIUM, 0, false },
	{ BWMON2_BYTE_COUNT_THRESHOLD_LOW, 0, false },
	{ BWMON2_ZONE_ACTIONS, 0, false },
	{ BWMON2_ZONE_COUNT_THRESHOLD, 0, false },
	"bto_core_clk",
	"llm_xo_clk",
	"dpm_xo_clk",
	"rsc_xo_clk",
	"dsp_bwmon_clk",
	"dl_dpm_clk",
	"dpm_temp_clk",
	"dsp_bwmon_ahb_clk",
	"cal_hm0_perf_cnt_clk",
	"cal_hm1_perf_cnt_clk",
	"dsp_ahbs_clk"
};

static const struct npu_irq npu_irq_info[NPU_MAX_IRQ] = {
	{"ipc_irq", 0, IRQF_TRIGGER_HIGH},
	{"ipc_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT},
	{"error_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT},
	{"wdg_bite_irq", 0, IRQF_TRIGGER_RISING | IRQF_ONESHOT},
};
@@ -314,7 +313,6 @@ int npu_enable_core_power(struct npu_device *npu_dev)
			pwr->pwr_vote_num = 0;
			return ret;
		}
		npu_resume_devbw(npu_dev);
	}
	pwr->pwr_vote_num++;

@@ -330,7 +328,6 @@ void npu_disable_core_power(struct npu_device *npu_dev)
		return;
	pwr->pwr_vote_num--;
	if (!pwr->pwr_vote_num) {
		npu_suspend_devbw(npu_dev);
		npu_disable_core_clocks(npu_dev);
		npu_disable_regulators(npu_dev);
		pwr->active_pwrlevel = thermalctrl->pwr_level;
@@ -492,61 +489,6 @@ int npu_set_uc_power_level(struct npu_device *npu_dev,
	return npu_set_power_level(npu_dev, true);
}

/* -------------------------------------------------------------------------
 * Bandwidth Related
 * -------------------------------------------------------------------------
 */
static void npu_save_bw_registers(struct npu_device *npu_dev)
{
	int i;

	if (!npu_dev->bwmon_io.base)
		return;

	for (i = 0; i < ARRAY_SIZE(npu_saved_bw_registers); i++) {
		npu_saved_bw_registers[i].val = npu_bwmon_reg_read(npu_dev,
			npu_saved_bw_registers[i].off);
		npu_saved_bw_registers[i].valid = true;
	}
}

static void npu_restore_bw_registers(struct npu_device *npu_dev)
{
	int i;

	if (!npu_dev->bwmon_io.base)
		return;

	for (i = 0; i < ARRAY_SIZE(npu_saved_bw_registers); i++) {
		if (npu_saved_bw_registers[i].valid) {
			npu_bwmon_reg_write(npu_dev,
				npu_saved_bw_registers[i].off,
				npu_saved_bw_registers[i].val);
			npu_saved_bw_registers[i].valid = false;
		}
	}
}

static void npu_suspend_devbw(struct npu_device *npu_dev)
{
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;

	if (pwr->bwmon_enabled && pwr->devbw) {
		pwr->bwmon_enabled = 0;
		npu_save_bw_registers(npu_dev);
	}
}

static void npu_resume_devbw(struct npu_device *npu_dev)
{
	struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;

	if (!pwr->bwmon_enabled && pwr->devbw) {
		pwr->bwmon_enabled = 1;
		npu_restore_bw_registers(npu_dev);
	}
}

/* -------------------------------------------------------------------------
 * Clocks Related
 * -------------------------------------------------------------------------
@@ -761,13 +703,6 @@ int npu_enable_irq(struct npu_device *npu_dev)
{
	int i;

	/* clear pending irq state */
	REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0);
	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_CLEAR(0), NPU_ERROR_IRQ_MASK);
	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_ENABLE(0), NPU_ERROR_IRQ_MASK);
	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_OWNER(0), NPU_ERROR_IRQ_MASK);
	REGW(npu_dev, NPU_MASTERn_WDOG_IRQ_OWNER(0), NPU_WDOG_IRQ_MASK);

	for (i = 0; i < NPU_MAX_IRQ; i++) {
		if (npu_dev->irq[i].irq != 0) {
			enable_irq(npu_dev->irq[i].irq);
@@ -788,11 +723,6 @@ void npu_disable_irq(struct npu_device *npu_dev)
			pr_debug("disable irq %d\n", npu_dev->irq[i].irq);
		}
	}

	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_ENABLE(0), 0);
	/* clear pending irq state */
	REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0);
	REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_CLEAR(0), NPU_ERROR_IRQ_MASK);
}

/* -------------------------------------------------------------------------
@@ -1656,6 +1586,7 @@ static int npu_probe(struct platform_device *pdev)
		goto error_get_dev_num;
	}
	npu_dev->core_io.size = resource_size(res);
	npu_dev->core_io.phy_addr = res->start;
	npu_dev->core_io.base = devm_ioremap(&pdev->dev, res->start,
					npu_dev->core_io.size);
	if (unlikely(!npu_dev->core_io.base)) {
@@ -1663,7 +1594,7 @@ static int npu_probe(struct platform_device *pdev)
		rc = -ENOMEM;
		goto error_get_dev_num;
	}
	pr_debug("core phy address=0x%x virt=%pK\n",
	pr_debug("core phy address=0x%llx virt=%pK\n",
		res->start, npu_dev->core_io.base);

	res = platform_get_resource_byname(pdev,
@@ -1674,6 +1605,7 @@ static int npu_probe(struct platform_device *pdev)
		goto error_get_dev_num;
	}
	npu_dev->tcm_io.size = resource_size(res);
	npu_dev->tcm_io.phy_addr = res->start;
	npu_dev->tcm_io.base = devm_ioremap(&pdev->dev, res->start,
					npu_dev->tcm_io.size);
	if (unlikely(!npu_dev->tcm_io.base)) {
@@ -1681,15 +1613,54 @@ static int npu_probe(struct platform_device *pdev)
		rc = -ENOMEM;
		goto error_get_dev_num;
	}
	pr_debug("core phy address=0x%x virt=%pK\n",
	pr_debug("tcm phy address=0x%llx virt=%pK\n",
		res->start, npu_dev->tcm_io.base);

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

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

	res = platform_get_resource_byname(pdev,
		IORESOURCE_MEM, "bwmon");
	if (!res) {
		pr_info("unable to get bwmon resource\n");
	} else {
		npu_dev->bwmon_io.size = resource_size(res);
		npu_dev->bwmon_io.phy_addr = res->start;
		npu_dev->bwmon_io.base = devm_ioremap(&pdev->dev, res->start,
						npu_dev->bwmon_io.size);
		if (unlikely(!npu_dev->bwmon_io.base)) {
@@ -1697,7 +1668,7 @@ static int npu_probe(struct platform_device *pdev)
			rc = -ENOMEM;
			goto error_get_dev_num;
		}
		pr_debug("bwmon phy address=0x%x virt=%pK\n",
		pr_debug("bwmon phy address=0x%llx virt=%pK\n",
			res->start, npu_dev->bwmon_io.base);
	}

@@ -1707,6 +1678,7 @@ static int npu_probe(struct platform_device *pdev)
		pr_info("unable to get qfprom_physical resource\n");
	} else {
		npu_dev->qfprom_io.size = resource_size(res);
		npu_dev->qfprom_io.phy_addr = res->start;
		npu_dev->qfprom_io.base = devm_ioremap(&pdev->dev, res->start,
					npu_dev->qfprom_io.size);
		if (unlikely(!npu_dev->qfprom_io.base)) {
@@ -1714,7 +1686,7 @@ static int npu_probe(struct platform_device *pdev)
			rc = -ENOMEM;
			goto error_get_dev_num;
		}
		pr_debug("qfprom_physical phy address=0x%x virt=%pK\n",
		pr_debug("qfprom_physical phy address=0x%llx virt=%pK\n",
			res->start, npu_dev->qfprom_io.base);
	}

+2 −1
Original line number Diff line number Diff line
@@ -136,7 +136,8 @@ static int npu_host_ipc_init_hfi(struct npu_device *npu_dev)
	kfree(q_tbl_addr);
	/* Write in the NPU's address for where IPC starts */
	REGW(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_VALUE,
		(uint32_t)IPC_MEM_OFFSET_FROM_SSTCM);
		(uint32_t)(npu_dev->tcm_io.phy_addr +
		IPC_MEM_OFFSET_FROM_SSTCM));
	/* Set value bit */
	reg_val = REGR(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_STATUS);
	REGW(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_STATUS, reg_val |
+7 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@
#define NPU_GPR2 (0x00000108)
#define NPU_GPR3 (0x0000010C)
#define NPU_GPR4 (0x00000110)
#define NPU_GPR5 (0x00000114)
#define NPU_GPR11 (0x0000012c)
#define NPU_GPR13 (0x00000134)
#define NPU_GPR14 (0x00000138)
#define NPU_GPR15 (0x0000013C)
@@ -49,4 +51,9 @@
#define BWMON2_ZONE_ACTIONS (0x000003B8)
#define BWMON2_ZONE_COUNT_THRESHOLD (0x000003BC)

#define NPU_QDSP6SS_IPC 0x00088000
#define NPU_QDSP6SS_IPC1 0x00088004

#define APSS_SHARED_IPC_INTERRUPT_1 0x00000010

#endif /* NPU_HW_H */
+38 −30
Original line number Diff line number Diff line
@@ -37,6 +37,37 @@ void npu_core_reg_write(struct npu_device *npu_dev, uint32_t off, uint32_t val)
	__iowmb();
}

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

	ret = readl_relaxed(npu_dev->qdsp_io.base + off);
	__iormb();
	return ret;
}

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

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

	ret = readl_relaxed(npu_dev->apss_shared_io.base + off);
	__iormb();
	return ret;
}

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

uint32_t npu_bwmon_reg_read(struct npu_device *npu_dev, uint32_t off)
{
	uint32_t ret = 0;
@@ -78,6 +109,7 @@ void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src,
	uint32_t i = 0;
	uint32_t num = 0;

	pr_debug("write dst_off %x size %x\n", dst_off, size);
	num = size/4;
	for (i = 0; i < num; i++) {
		writel_relaxed(src_ptr32[i], npu_dev->tcm_io.base + dst_off);
@@ -104,6 +136,8 @@ int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst,
	uint32_t i = 0;
	uint32_t num = 0;

	pr_debug("read src_off %x size %x\n", src_off, size);

	num = size/4;
	for (i = 0; i < num; i++) {
		out32[i] = readl_relaxed(npu_dev->tcm_io.base + src_off);
@@ -132,44 +166,17 @@ void *npu_ipc_addr(void)
 */
void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num)
{
	struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
	uint32_t wdg_irq_sts = 0, error_irq_sts = 0;

	/* Clear irq state */
	REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0);

	wdg_irq_sts = REGR(npu_dev, NPU_MASTERn_WDOG_IRQ_STATUS(0));
	if (wdg_irq_sts != 0) {
		pr_err("wdg irq %x\n", wdg_irq_sts);
		host_ctx->wdg_irq_sts |= wdg_irq_sts;
		host_ctx->fw_error = true;
	}

	error_irq_sts = REGR(npu_dev, NPU_MASTERn_ERROR_IRQ_STATUS(0));
	error_irq_sts &= REGR(npu_dev, NPU_MASTERn_ERROR_IRQ_ENABLE(0));
	if (error_irq_sts != 0) {
		REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_CLEAR(0), error_irq_sts);
		pr_err("error irq %x\n", error_irq_sts);
		host_ctx->err_irq_sts |= error_irq_sts;
		host_ctx->fw_error = true;
	}
}

int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev)
{
	/* Bit 4 is setting IRQ_SOURCE_SELECT to local
	 * and we're triggering a pulse to NPU_MASTER0_IPC_IN_IRQ0
	 */
	npu_core_reg_write(npu_dev, NPU_MASTERn_IPC_IRQ_IN_CTRL(0), 0x1
		<< NPU_MASTER0_IPC_IRQ_IN_CTRL__IRQ_SOURCE_SELECT___S | 0x1);
	npu_apss_shared_reg_write(npu_dev, APSS_SHARED_IPC_INTERRUPT_1, 0x40);

	return 0;
}

int32_t npu_interrupt_raise_dsp(struct npu_device *npu_dev)
{
	npu_core_reg_write(npu_dev, NPU_MASTERn_IPC_IRQ_OUT_CTRL(1), 0x8);

	return 0;
}

@@ -194,7 +201,7 @@ static struct npu_ion_buf *npu_alloc_npu_ion_buffer(struct npu_client

	if (ret_val) {
		/* mapped already, treat as invalid request */
		pr_err("ion buf %x has been mapped\n");
		pr_err("ion buf has been mapped\n");
		ret_val = NULL;
	} else {
		ret_val = kzalloc(sizeof(*ret_val), GFP_KERNEL);
@@ -302,6 +309,7 @@ int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size,
	*addr = ion_buf->iova;
	pr_debug("mapped mem addr:0x%llx size:0x%x\n", ion_buf->iova,
		ion_buf->size);
	pr_debug("physical address 0x%llx\n", sg_phys(ion_buf->table->sgl));
map_end:
	if (ret)
		npu_mem_unmap(client, buf_hdl, 0);
@@ -354,7 +362,7 @@ void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr)
	}

	if (ion_buf->iova != addr)
		pr_warn("unmap address %lu doesn't match %lu\n", addr,
		pr_warn("unmap address %llu doesn't match %llu\n", addr,
			ion_buf->iova);

	if (ion_buf->table)
Loading