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

Commit e208a816 authored by Shaoqing Liu's avatar Shaoqing Liu Committed by Tingwei Zhang
Browse files

soc: qcom: dcc_v2: support multiple link lists



DCC can program multiple link lists. Add driver support to
parse multiple link lists in device tree.  Support upto
8 link lists.

Change-Id: Ib8a53253d44f4f8568a7dec079c8713e831c2c4d
Signed-off-by: default avatarShaoqing Liu <shaoqingliu@codeaurora.org>
Signed-off-by: default avatarTingwei Zhang <tingwei@codeaurora.org>
parent bdc7f8fb
Loading
Loading
Loading
Loading
+69 −43
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
// SPDX-License-Identifier: GPL-2.0
/*
/*
 * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 */
 */


#include <linux/module.h>
#include <linux/module.h>
@@ -75,7 +75,7 @@
#define DCC_AHB_IND			0x00
#define DCC_AHB_IND			0x00
#define DCC_APB_IND			BIT(29)
#define DCC_APB_IND			BIT(29)


#define DCC_MAX_LINK_LIST		5
#define DCC_MAX_LINK_LIST		8
#define DCC_INVALID_LINK_LIST		0xFF
#define DCC_INVALID_LINK_LIST		0xFF


enum dcc_func_type {
enum dcc_func_type {
@@ -131,7 +131,7 @@ struct dcc_drvdata {
	void __iomem		*ram_base;
	void __iomem		*ram_base;
	uint32_t		ram_size;
	uint32_t		ram_size;
	uint32_t		ram_offset;
	uint32_t		ram_offset;
	enum dcc_data_sink	data_sink;
	enum dcc_data_sink	data_sink[DCC_MAX_LINK_LIST];
	enum dcc_func_type	func_type[DCC_MAX_LINK_LIST];
	enum dcc_func_type	func_type[DCC_MAX_LINK_LIST];
	uint32_t		ram_cfg;
	uint32_t		ram_cfg;
	uint32_t		ram_start;
	uint32_t		ram_start;
@@ -459,7 +459,7 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list)
	sram_offset += 4;
	sram_offset += 4;


	/* Update ram_cfg and check if the data will overstep */
	/* Update ram_cfg and check if the data will overstep */
	if (drvdata->data_sink == DCC_DATA_SINK_SRAM &&
	if (drvdata->data_sink[curr_list] == DCC_DATA_SINK_SRAM &&
	    drvdata->func_type[curr_list] == DCC_FUNC_TYPE_CAPTURE) {
	    drvdata->func_type[curr_list] == DCC_FUNC_TYPE_CAPTURE) {
		drvdata->ram_cfg = (sram_offset + total_len) / 4;
		drvdata->ram_cfg = (sram_offset + total_len) / 4;


@@ -561,12 +561,7 @@ static int dcc_enable(struct dcc_drvdata *drvdata)
				drvdata->ram_offset/4, DCC_FD_BASE(list));
				drvdata->ram_offset/4, DCC_FD_BASE(list));
		dcc_writel(drvdata, 0xFFF, DCC_LL_TIMEOUT(list));
		dcc_writel(drvdata, 0xFFF, DCC_LL_TIMEOUT(list));


		/* 4. Configure data sink and function type */
		/* 4. Clears interrupt status register */
		dcc_writel(drvdata, ((drvdata->cti_trig << 8) |
			   (drvdata->data_sink << 4) |
			   (drvdata->func_type[list])), DCC_LL_CFG(list));

		/* 5. Clears interrupt status register */
		dcc_writel(drvdata, 0, DCC_LL_INT_ENABLE(list));
		dcc_writel(drvdata, 0, DCC_LL_INT_ENABLE(list));
		dcc_writel(drvdata, (BIT(0) | BIT(1) | BIT(2)),
		dcc_writel(drvdata, (BIT(0) | BIT(1) | BIT(2)),
			   DCC_LL_INT_STATUS(list));
			   DCC_LL_INT_STATUS(list));
@@ -586,9 +581,9 @@ static int dcc_enable(struct dcc_drvdata *drvdata)
					   DCC_LL_INT_ENABLE(list));
					   DCC_LL_INT_ENABLE(list));
		}
		}


		/* 6. Configure trigger */
		/* 5. Configure trigger */
		dcc_writel(drvdata, BIT(9) | ((drvdata->cti_trig << 8) |
		dcc_writel(drvdata, BIT(9) | ((drvdata->cti_trig << 8) |
			   (drvdata->data_sink << 4) |
			   (drvdata->data_sink[list] << 4) |
			   (drvdata->func_type[list])), DCC_LL_CFG(list));
			   (drvdata->func_type[list])), DCC_LL_CFG(list));
	}
	}


@@ -712,9 +707,14 @@ static ssize_t data_sink_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
				  struct device_attribute *attr, char *buf)
{
{
	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
	ssize_t len = 0;
	unsigned int i;


	return scnprintf(buf, PAGE_SIZE, "%s\n",
	for (i = 0; i < DCC_MAX_LINK_LIST; i++)
			 str_dcc_data_sink[drvdata->data_sink]);
		len += scnprintf(buf + len, PAGE_SIZE - len, "%u :%s\n",
				 i, str_dcc_data_sink[drvdata->data_sink[i]]);

	return len;
}
}


static ssize_t data_sink_store(struct device *dev,
static ssize_t data_sink_store(struct device *dev,
@@ -731,15 +731,22 @@ static ssize_t data_sink_store(struct device *dev,
		return -EINVAL;
		return -EINVAL;


	mutex_lock(&drvdata->mutex);
	mutex_lock(&drvdata->mutex);
	if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
		dev_err(dev,
			"Select link list to program using curr_list\n");
		ret = -EINVAL;
		goto out;
	}

	if (drvdata->enable[drvdata->curr_list]) {
	if (drvdata->enable[drvdata->curr_list]) {
		ret = -EBUSY;
		ret = -EBUSY;
		goto out;
		goto out;
	}
	}


	if (!strcmp(str, str_dcc_data_sink[DCC_DATA_SINK_SRAM]))
	if (!strcmp(str, str_dcc_data_sink[DCC_DATA_SINK_SRAM]))
		drvdata->data_sink = DCC_DATA_SINK_SRAM;
		drvdata->data_sink[drvdata->curr_list] = DCC_DATA_SINK_SRAM;
	else if (!strcmp(str, str_dcc_data_sink[DCC_DATA_SINK_ATB]))
	else if (!strcmp(str, str_dcc_data_sink[DCC_DATA_SINK_ATB]))
		drvdata->data_sink = DCC_DATA_SINK_ATB;
		drvdata->data_sink[drvdata->curr_list] = DCC_DATA_SINK_ATB;
	else {
	else {
		ret = -EINVAL;
		ret = -EINVAL;
		goto out;
		goto out;
@@ -1485,25 +1492,41 @@ static void dcc_sram_dev_exit(struct dcc_drvdata *drvdata)
	dcc_sram_dev_deregister(drvdata);
	dcc_sram_dev_deregister(drvdata);
}
}


static void dcc_configure_list(struct dcc_drvdata *drvdata,
static int dcc_dt_parse(struct dcc_drvdata *drvdata, struct device_node *np)
			       struct device_node *np)
{
{
	int ret, i;
	int i, ret = -1;
	const __be32 *prop;
	const __be32 *prop;
	uint32_t len, entry, val1, val2, apb_bus;
	uint32_t len, entry, val1, val2, apb_bus;
	uint32_t curr_link_list;
	uint32_t curr_link_list;
	const char *data_sink;


	ret = of_property_read_u32(np, "qcom,curr-link-list",
	ret = of_property_read_u32(np, "qcom,curr-link-list",
				&curr_link_list);
				&curr_link_list);
	if (ret)
	if (ret)
		return;
		return ret;


	if (curr_link_list >= DCC_MAX_LINK_LIST) {
	if (curr_link_list >= DCC_MAX_LINK_LIST) {
		dev_err(drvdata->dev, "List configuration failed.\n");
		dev_err(drvdata->dev, "List configuration failed.\n");
		return;
		return ret;
	}
	}
	drvdata->curr_list = curr_link_list;
	drvdata->curr_list = curr_link_list;


	drvdata->data_sink[curr_link_list] = DCC_DATA_SINK_SRAM;
	ret = of_property_read_string(np, "qcom,data-sink",
					&data_sink);
	if (!ret) {
		for (i = 0; i < ARRAY_SIZE(str_dcc_data_sink); i++)
			if (!strcmp(data_sink, str_dcc_data_sink[i])) {
				drvdata->data_sink[curr_link_list] = i;
				break;
			}

		if (i == ARRAY_SIZE(str_dcc_data_sink)) {
			dev_err(drvdata->dev, "Unknown sink type for DCC Using '%s' as data sink\n",
			str_dcc_data_sink[drvdata->data_sink[curr_link_list]]);
		}
	}

	prop = of_get_property(np, "qcom,link-list", &len);
	prop = of_get_property(np, "qcom,link-list", &len);
	if (prop) {
	if (prop) {
		len /= sizeof(__be32);
		len /= sizeof(__be32);
@@ -1537,11 +1560,31 @@ static void dcc_configure_list(struct dcc_drvdata *drvdata,
				break;
				break;
			}
			}
		}
		}
	}
	return ret;
}

static void dcc_configure_list(struct dcc_drvdata *drvdata,
			       struct device_node *np)
{
	int ret = -1;
	struct device_node *link_node = NULL;

	for_each_available_child_of_node(np, link_node) {
		ret = dcc_dt_parse(drvdata, link_node);
		if (ret) {
			dev_err(drvdata->dev,
				"DCC link list config failed err:%d\n", ret);
			break;
		}
	}

	if (ret == -1)
		ret = dcc_dt_parse(drvdata, np);


	if (!ret)
	if (!ret)
		dcc_enable(drvdata);
		dcc_enable(drvdata);
}
}
}


static int dcc_probe(struct platform_device *pdev)
static int dcc_probe(struct platform_device *pdev)
{
{
@@ -1549,7 +1592,6 @@ static int dcc_probe(struct platform_device *pdev)
	struct device *dev = &pdev->dev;
	struct device *dev = &pdev->dev;
	struct dcc_drvdata *drvdata;
	struct dcc_drvdata *drvdata;
	struct resource *res;
	struct resource *res;
	const char *data_sink;


	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
	if (!drvdata)
	if (!drvdata)
@@ -1591,22 +1633,6 @@ static int dcc_probe(struct platform_device *pdev)


	memset_io(drvdata->ram_base, 0, drvdata->ram_size);
	memset_io(drvdata->ram_base, 0, drvdata->ram_size);


	drvdata->data_sink = DCC_DATA_SINK_SRAM;
	ret = of_property_read_string(pdev->dev.of_node, "qcom,data-sink",
				      &data_sink);
	if (!ret) {
		for (i = 0; i < ARRAY_SIZE(str_dcc_data_sink); i++)
			if (!strcmp(data_sink, str_dcc_data_sink[i])) {
				drvdata->data_sink = i;
				break;
			}

		if (i == ARRAY_SIZE(str_dcc_data_sink)) {
			dev_err(dev, "Unknown sink type for DCC Using '%s' as data sink\n",
				str_dcc_data_sink[drvdata->data_sink]);
		}
	}

	drvdata->curr_list = DCC_INVALID_LINK_LIST;
	drvdata->curr_list = DCC_INVALID_LINK_LIST;


	ret = dcc_sram_dev_init(drvdata);
	ret = dcc_sram_dev_init(drvdata);