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

Commit 8dfc046a authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: npu: Add SSR support"

parents d8810959 6115bb2c
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@
		status = "ok";
		reg = <0x9800000 0x800000>;
		reg-names = "npu_base";
		interrupts = <GIC_SPI 368 IRQ_TYPE_EDGE_RISING>;
		interrupts = <GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
				<GIC_SPI 366 IRQ_TYPE_EDGE_RISING>,
				<GIC_SPI 368 IRQ_TYPE_EDGE_RISING>;
		interrupt-names = "error_irq", "wdg_bite_irq", "ipc_irq";
		iommus = <&apps_smmu 0x1461 0x0>, <&apps_smmu 0x2061 0x0>;
		cache-slice-names = "npu";
		cache-slices = <&llcc 23>;
+9 −2
Original line number Diff line number Diff line
@@ -185,6 +185,13 @@ struct npu_thermalctrl {
	uint32_t pwr_level;
};

#define NPU_MAX_IRQ		3

struct npu_irq {
	char *name;
	int irq;
};

struct npu_device {
	struct mutex ctx_lock;

@@ -205,7 +212,7 @@ struct npu_device {
	uint32_t regulator_num;
	struct npu_regulator regulators[NPU_MAX_DT_NAME_LEN];

	uint32_t irq;
	struct npu_irq irq[NPU_MAX_IRQ];

	struct npu_ion_buf mapped_buffers;

@@ -242,6 +249,6 @@ int npu_set_uc_power_level(struct npu_device *npu_dev,
	uint32_t pwr_level);

int fw_init(struct npu_device *npu_dev);
void fw_deinit(struct npu_device *npu_dev);
void fw_deinit(struct npu_device *npu_dev, bool fw_alive);

#endif /* _NPU_COMMON_H */
+11 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
 */
#include <linux/debugfs.h>

#include "npu_hw.h"
#include "npu_hw_access.h"
#include "npu_common.h"

@@ -372,7 +373,14 @@ static ssize_t npu_debug_ctrl_write(struct file *file,
			pr_info("error in fw_init\n");
	} else if (strcmp(buf, "off") == 0) {
		pr_info("triggering fw_deinit\n");
		fw_deinit(npu_dev);
		fw_deinit(npu_dev, true);
	} else if (strcmp(buf, "ssr") == 0) {
		pr_info("trigger error irq\n");
		if (npu_enable_core_power(npu_dev))
			return -EPERM;

		REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_SET(0), 2);
		npu_disable_core_power(npu_dev);
	} else if (strcmp(buf, "0") == 0) {
		pr_info("setting power state to 0\n");
		npu_dev->pwrctrl.active_pwrlevel = 0;
@@ -446,8 +454,8 @@ int npu_debugfs_init(struct npu_device *npu_dev)
		goto err;
	}

	if (!debugfs_create_bool("fw_state", 0444,
		debugfs->root, &(host_ctx->fw_enabled))) {
	if (!debugfs_create_u32("fw_state", 0444,
		debugfs->root, &(host_ctx->fw_state))) {
		pr_err("debugfs_creat_bool fail for fw_state\n");
		goto err;
	}
+85 −28
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
 */
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/regulator/consumer.h>
@@ -155,6 +156,12 @@ static struct npu_reg npu_saved_bw_registers[] = {
	{ BWMON2_ZONE_COUNT_THRESHOLD, 0, false },
};

static const struct npu_irq npu_irq_info[NPU_MAX_IRQ] = {
	{"ipc_irq", 0},
	{"error_irq", 0},
	{"wdg_bite_irq", 0},
};

/* -------------------------------------------------------------------------
 * Entry Points for Probe
 * -------------------------------------------------------------------------
@@ -297,7 +304,7 @@ void npu_disable_core_power(struct npu_device *npu_dev)
		return;
	pwr->pwr_vote_num--;
	if (!pwr->pwr_vote_num) {
		if (!npu_dev->host_ctx.fw_enabled)
		if (npu_dev->host_ctx.fw_state == FW_DISABLED)
			npu_suspend_devbw(npu_dev);
		npu_disable_core_clocks(npu_dev);
		npu_disable_regulators(npu_dev);
@@ -372,7 +379,7 @@ static int npu_set_power_level(struct npu_device *npu_dev)
			npu_dev->core_clks[i].clk_name))
			continue;

		if (!npu_dev->host_ctx.fw_enabled) {
		if (npu_dev->host_ctx.fw_state == FW_DISABLED) {
			if (npu_is_post_clock(
				npu_dev->core_clks[i].clk_name))
				continue;
@@ -381,14 +388,11 @@ static int npu_set_power_level(struct npu_device *npu_dev)
		pr_debug("requested rate of clock [%s] to [%ld]\n",
			npu_dev->core_clks[i].clk_name, pwrlevel->clk_freq[i]);

		clk_rate = clk_round_rate(npu_dev->core_clks[i].clk,
			pwrlevel->clk_freq[i]);

		pr_debug("actual round clk rate [%ld]\n", clk_rate);

		ret = clk_set_rate(npu_dev->core_clks[i].clk, clk_rate);
		if (ret) {
			pr_err("clk_set_rate %s to %ld failed with %d\n",
			pr_debug("clk_set_rate %s to %ld failed with %d\n",
				npu_dev->core_clks[i].clk_name,
				clk_rate, ret);
			break;
@@ -571,7 +575,7 @@ static void npu_disable_core_clocks(struct npu_device *npu_dev)
	for (i = (npu_dev->core_clk_num)-1; i >= 0 ; i--) {
		if (npu_is_exclude_clock(core_clks[i].clk_name))
			continue;
		if (!npu_dev->host_ctx.fw_enabled) {
		if (npu_dev->host_ctx.fw_state == FW_DISABLED) {
			if (npu_is_post_clock(npu_dev->core_clks[i].clk_name))
				continue;
		}
@@ -679,18 +683,38 @@ static void npu_disable_regulators(struct npu_device *npu_dev)
 */
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);
	enable_irq(npu_dev->irq);
	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);

	for (i = 0; i < NPU_MAX_IRQ; i++) {
		if (npu_dev->irq[i].irq != 0) {
			enable_irq(npu_dev->irq[i].irq);
			pr_debug("enable irq %d\n", npu_dev->irq[i].irq);
		}
	}

	return 0;
}

void npu_disable_irq(struct npu_device *npu_dev)
{
	disable_irq(npu_dev->irq);
	int i;

	for (i = 0; i < NPU_MAX_IRQ; i++) {
		if (npu_dev->irq[i].irq != 0) {
			disable_irq(npu_dev->irq[i].irq);
			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);
}

/* -------------------------------------------------------------------------
@@ -1089,6 +1113,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev,
		uint32_t j = 0;
		uint32_t index;
		uint32_t clk_array_values[NUM_TOTAL_CLKS];
		uint32_t clk_rate;
		struct npu_pwrlevel *level;

		if (of_property_read_u32(child, "reg", &index))
@@ -1116,18 +1141,25 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev,
			of_property_read_string_index(pdev->dev.of_node,
				"clock-names", i, &clock_name);

			if (npu_is_exclude_rate_clock(clock_name))
				continue;

			for (j = 0; j < npu_dev->core_clk_num; j++) {
				if (!strcmp(npu_clock_order[j],
					clock_name)) {
					level->clk_freq[j] =
						clk_array_values[i];
					clock_name))
					break;
			}
			}

			if (j == npu_dev->core_clk_num) {
				pr_err("pwrlevel clock is not in ordered list\n");
				return -EINVAL;
			}

			clk_rate = clk_round_rate(npu_dev->core_clks[j].clk,
				clk_array_values[i]);
			pr_debug("clk %s rate [%ld]:[%ld]\n", clock_name,
				clk_array_values[i], clk_rate);
			level->clk_freq[j] = clk_rate;
		}
	}

@@ -1201,6 +1233,42 @@ static int npu_thermalctrl_init(struct npu_device *npu_dev)
	return ret;
}

static int npu_irq_init(struct npu_device *npu_dev)
{
	unsigned long irq_type;
	int ret = 0, i;

	memcpy(npu_dev->irq, npu_irq_info, sizeof(npu_irq_info));
	for (i = 0; i < NPU_MAX_IRQ; i++) {
		irq_type = IRQF_TRIGGER_RISING | IRQF_ONESHOT;
		npu_dev->irq[i].irq = platform_get_irq_byname(
			npu_dev->pdev, npu_dev->irq[i].name);
		if (npu_dev->irq[i].irq < 0) {
			pr_err("get_irq for %s failed\n\n",
				npu_dev->irq[i].name);
			ret = -EINVAL;
			break;
		}

		pr_debug("irq %s: %d\n", npu_dev->irq[i].name,
			npu_dev->irq[i].irq);
		irq_set_status_flags(npu_dev->irq[i].irq,
						IRQ_NOAUTOEN);
		ret = devm_request_irq(&npu_dev->pdev->dev,
				npu_dev->irq[i].irq, npu_intr_hdler,
				irq_type, npu_dev->irq[i].name,
				npu_dev);
		if (ret) {
			pr_err("devm_request_irq(%s:%d) failed\n",
				npu_dev->irq[i].name,
				npu_dev->irq[i].irq);
			break;
		}
	}

	return ret;
}

/* -------------------------------------------------------------------------
 * Probe/Remove
 * -------------------------------------------------------------------------
@@ -1245,6 +1313,10 @@ static int npu_probe(struct platform_device *pdev)
	if (rc)
		goto error_get_dev_num;

	rc = npu_irq_init(npu_dev);
	if (rc)
		goto error_get_dev_num;

	npu_dev->npu_base = devm_ioremap(&pdev->dev, res->start,
					npu_dev->reg_size);
	if (unlikely(!npu_dev->npu_base)) {
@@ -1257,21 +1329,6 @@ static int npu_probe(struct platform_device *pdev)
	pr_debug("hw base phy address=0x%x virt=%pK\n",
		npu_dev->npu_phys, npu_dev->npu_base);

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		pr_err("unable to get irq\n");
		rc = -ENOMEM;
		goto error_get_dev_num;
	}
	rc = devm_request_irq(&pdev->dev, res->start,
				npu_intr_hdler, 0x0, "npu", npu_dev);
	if (rc) {
		pr_err("devm_request_irq() failed\n");
		goto error_get_dev_num;
	}
	disable_irq(res->start);
	npu_dev->irq = res->start;
	pr_debug("irq %d\n", npu_dev->irq);
	/* character device might be optional */
	rc = alloc_chrdev_region(&npu_dev->dev_num, 0, 1, DRIVER_NAME);
	if (rc < 0) {
+13 −0
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@

#define QUEUE_TBL_VERSION 0x87654321

static DEFINE_SPINLOCK(hfi_rd_lock);
static DEFINE_SPINLOCK(hfi_wr_lock);

/* -------------------------------------------------------------------------
 * Data Structures
 * -------------------------------------------------------------------------
@@ -207,6 +210,7 @@ static int ipc_queue_read(struct npu_device *npu_dev,
	uint32_t packet_size, new_read_idx;
	size_t read_ptr;
	size_t offset = 0;
	unsigned long flags;

	offset = (size_t)IPC_ADDR + sizeof(struct hfi_queue_tbl_header) +
		target_que * sizeof(struct hfi_queue_header);
@@ -214,6 +218,8 @@ static int ipc_queue_read(struct npu_device *npu_dev,
	if ((packet == NULL) || (is_tx_req_set == NULL))
		return -EINVAL;

	spin_lock_irqsave(&hfi_rd_lock, flags);

	/* Read the queue */
	MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue,
		HFI_QUEUE_HEADER_SIZE);
@@ -288,6 +294,8 @@ static int ipc_queue_read(struct npu_device *npu_dev,
		(size_t)&(queue.qhdr_read_idx) - (size_t)&queue)),
		(uint8_t *)&queue.qhdr_read_idx, sizeof(queue.qhdr_read_idx));

	spin_unlock_irqrestore(&hfi_rd_lock, flags);

	return status;
}

@@ -301,6 +309,7 @@ static int ipc_queue_write(struct npu_device *npu_dev,
	uint32_t empty_space;
	void *write_ptr;
	uint32_t read_idx;
	unsigned long flags;

	size_t offset = (size_t)IPC_ADDR +
		sizeof(struct hfi_queue_tbl_header) +
@@ -309,6 +318,8 @@ static int ipc_queue_write(struct npu_device *npu_dev,
	if ((packet == NULL) || (is_rx_req_set == NULL))
		return -EINVAL;

	spin_lock_irqsave(&hfi_wr_lock, flags);

	MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue,
		HFI_QUEUE_HEADER_SIZE);
	packet_size = (*(uint32_t *)packet);
@@ -384,6 +395,8 @@ static int ipc_queue_write(struct npu_device *npu_dev,
		(size_t)&(queue.qhdr_write_idx) - (size_t)&queue))),
		&queue.qhdr_write_idx, sizeof(queue.qhdr_write_idx));

	spin_unlock_irqrestore(&hfi_wr_lock, flags);

	return status;
}

Loading