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

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

Merge changes Iba109421,Ia7d367d0,I71c5768f,I6abcfefc,I859c451b into msm-next

* changes:
  soc: qcom: Add init time configuration support to DCC
  soc: qcom: Insert poison value into DCC SRAM
  soc: qcom: Fix the programming of DCC registers for CRC,DCCV2
  soc: qcom: Remove memory dump handling from DCC driver
  soc: qcom: dcc_v2: Add timeout for linked list
parents 541d78fe f3ed1dbe
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -35,6 +35,14 @@ Optional properties:
		  "atb"	  : To send captured data over ATB to a trace sink
		  "sram"  : To save captured data in dcc internal SRAM.

- qcom,curr-link-list: int, To specify the link list to use for the default list.

- qcom,link-list: The values to be programmed into the default link list.
		  The enum values for DCC operations is defined in dt-bindings/soc/qcom,dcc_v2.h
		  The following gives basic structure to be used for each operation:
		  <DCC_operation addr val apb_bus>
		  val is to be interpreted based on what operation is to be performed.

Example:

	dcc: dcc@4b3000 {
@@ -47,6 +55,13 @@ Example:
		clocks = <&clock_gcc clk_gcc_dcc_ahb_clk>;
		clock-names = "dcc_clk";

		qcom,curr-link-list = <2>;
		qcom,link-list = <DCC_READ 0x1740300 6 0>,
				 <DCC_READ 0x1620500 4 0>,
				 <DCC_READ 0x7840000 1 0>,
				 <DCC_READ 0x7841010 12 0>,
				 <DCC_READ 0x7842000 16 0>,
				 <DCC_READ 0x7842500 2 0>;
		qcom,save-reg;
	};
+118 −128
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/uaccess.h>
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/scm.h>
#include <dt-bindings/soc/qcom,dcc_v2.h>

#define TIMEOUT_US		(100)

@@ -148,11 +149,6 @@ struct dcc_drvdata {
	struct class		*sram_class;
	struct list_head	cfg_head[DCC_MAX_LINK_LIST];
	uint32_t		nr_config[DCC_MAX_LINK_LIST];
	void			*reg_buf;
	struct msm_dump_data	reg_data;
	bool			save_reg;
	void			*sram_buf;
	struct msm_dump_data	sram_data;
	uint8_t			curr_list;
	uint8_t			cti_trig;
};
@@ -490,39 +486,6 @@ static int __dcc_ll_cfg(struct dcc_drvdata *drvdata, int curr_list)
	return ret;
}

static void __dcc_reg_dump(struct dcc_drvdata *drvdata)
{
	uint32_t *reg_buf;
	uint8_t i = 0;
	uint8_t j;

	if (!drvdata->reg_buf)
		return;

	drvdata->reg_data.version = DCC_REG_DUMP_VER;

	reg_buf = drvdata->reg_buf;

	reg_buf[i++] = dcc_readl(drvdata, DCC_HW_VERSION);
	reg_buf[i++] = dcc_readl(drvdata, DCC_HW_INFO);
	reg_buf[i++] = dcc_readl(drvdata, DCC_EXEC_CTRL);
	reg_buf[i++] = dcc_readl(drvdata, DCC_STATUS);
	reg_buf[i++] = dcc_readl(drvdata, DCC_CFG);
	reg_buf[i++] = dcc_readl(drvdata, DCC_FDA_CURR);
	reg_buf[i++] = dcc_readl(drvdata, DCC_LLA_CURR);

	for (j = 0; j < DCC_MAX_LINK_LIST; j++)
		reg_buf[i++] = dcc_readl(drvdata, DCC_LL_LOCK(j));
	for (j = 0; j < DCC_MAX_LINK_LIST; j++)
		reg_buf[i++] = dcc_readl(drvdata, DCC_LL_CFG(j));
	for (j = 0; j < DCC_MAX_LINK_LIST; j++)
		reg_buf[i++] = dcc_readl(drvdata, DCC_LL_BASE(j));
	for (j = 0; j < DCC_MAX_LINK_LIST; j++)
		reg_buf[i++] = dcc_readl(drvdata, DCC_FD_BASE(j));

	drvdata->reg_data.magic = DCC_REG_DUMP_MAGIC_V2;
}

static void __dcc_first_crc(struct dcc_drvdata *drvdata)
{
	int i;
@@ -574,7 +537,7 @@ static int dcc_enable(struct dcc_drvdata *drvdata)

	mutex_lock(&drvdata->mutex);

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

	for (list = 0; list < DCC_MAX_LINK_LIST; list++) {

@@ -592,14 +555,12 @@ static int dcc_enable(struct dcc_drvdata *drvdata)
			goto err;
		}

		/* 3. If in capture mode program DCC_RAM_CFG reg */
		if (drvdata->func_type[list] == DCC_FUNC_TYPE_CAPTURE) {
		/* 3. program DCC_RAM_CFG reg */
		dcc_writel(drvdata, ram_cfg_base +
			   drvdata->ram_offset/4, DCC_LL_BASE(list));
		dcc_writel(drvdata, drvdata->ram_start +
			   drvdata->ram_offset/4, DCC_FD_BASE(list));
			dcc_writel(drvdata, 0, DCC_LL_TIMEOUT(list));
		}
		dcc_writel(drvdata, 0xFFF, DCC_LL_TIMEOUT(list));

		/* 4. Configure trigger, data sink and function type */
		dcc_writel(drvdata, BIT(9) | ((drvdata->cti_trig << 8) |
@@ -626,9 +587,6 @@ static int dcc_enable(struct dcc_drvdata *drvdata)
					   DCC_LL_INT_ENABLE(list));
		}
	}
	/* Save DCC registers */
	if (drvdata->save_reg)
		__dcc_reg_dump(drvdata);

err:
	mutex_unlock(&drvdata->mutex);
@@ -653,9 +611,6 @@ static void dcc_disable(struct dcc_drvdata *drvdata)
	}
	drvdata->ram_cfg = 0;
	drvdata->ram_start = 0;
	/* Save DCC registers */
	if (drvdata->save_reg)
		__dcc_reg_dump(drvdata);

	mutex_unlock(&drvdata->mutex);
}
@@ -857,6 +812,9 @@ static ssize_t dcc_show_config(struct device *dev,

	buf[0] = '\0';

	if (drvdata->curr_list >= DCC_MAX_LINK_LIST)
		return -EINVAL;

	mutex_lock(&drvdata->mutex);
	list_for_each_entry(entry,
			    &drvdata->cfg_head[drvdata->curr_list], list) {
@@ -1132,14 +1090,30 @@ static ssize_t dcc_store_interrupt_disable(struct device *dev,
static DEVICE_ATTR(interrupt_disable, 0644,
		   dcc_show_interrupt_disable, dcc_store_interrupt_disable);

static int dcc_add_loop(struct dcc_drvdata *drvdata, unsigned long loop_cnt)
{
	struct dcc_config_entry *entry;

	entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
	if (!entry)
		return -ENOMEM;

	entry->loop_cnt = min_t(uint32_t, loop_cnt, MAX_LOOP_CNT);
	entry->index = drvdata->nr_config[drvdata->curr_list]++;
	entry->desc_type = DCC_LOOP_TYPE;
	INIT_LIST_HEAD(&entry->list);
	list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);

	return 0;
}

static ssize_t dcc_store_loop(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t size)
{
	int ret = size;
	int ret;
	unsigned long loop_cnt;
	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
	struct dcc_config_entry *entry;

	mutex_lock(&drvdata->mutex);

@@ -1154,18 +1128,12 @@ static ssize_t dcc_store_loop(struct device *dev,
		goto err;
	}

	entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
	if (!entry) {
		ret = -ENOMEM;
	ret = dcc_add_loop(drvdata, loop_cnt);
	if (ret)
		goto err;
	}

	entry->loop_cnt = min_t(uint32_t, loop_cnt, MAX_LOOP_CNT);
	entry->index = drvdata->nr_config[drvdata->curr_list]++;
	entry->desc_type = DCC_LOOP_TYPE;
	INIT_LIST_HEAD(&entry->list);
	list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);

	mutex_unlock(&drvdata->mutex);
	return size;
err:
	mutex_unlock(&drvdata->mutex);
	return ret;
@@ -1215,16 +1183,37 @@ static ssize_t dcc_rd_mod_wr(struct device *dev,
}
static DEVICE_ATTR(rd_mod_wr, 0200, NULL, dcc_rd_mod_wr);

static int dcc_add_write(struct dcc_drvdata *drvdata, unsigned int addr,
			 unsigned int write_val, int apb_bus)
{
	struct dcc_config_entry *entry;

	entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
	if (!entry)
		return -ENOMEM;

	entry->desc_type = DCC_WRITE_TYPE;
	entry->base = addr & BM(4, 31);
	entry->offset = addr - entry->base;
	entry->write_val = write_val;
	entry->index = drvdata->nr_config[drvdata->curr_list]++;
	entry->len = 1;
	entry->apb_bus = apb_bus;
	INIT_LIST_HEAD(&entry->list);
	list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);

	return 0;
}

static ssize_t dcc_write(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t size)
{
	int ret = size;
	int ret;
	int nval;
	unsigned int addr, write_val;
	int apb_bus;
	int apb_bus = 0;
	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
	struct dcc_config_entry *entry;

	mutex_lock(&drvdata->mutex);

@@ -1241,23 +1230,15 @@ static ssize_t dcc_write(struct device *dev,
		goto err;
	}

	entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
	if (!entry) {
		ret = -ENOMEM;
		goto err;
	}
	if (nval == 3 && apb_bus != 0)
		apb_bus = 1;

	if (nval == 3)
		entry->apb_bus = true;
	ret = dcc_add_write(drvdata, addr, write_val, apb_bus);
	if (ret)
		goto err;

	entry->desc_type = DCC_WRITE_TYPE;
	entry->base = addr & BM(4, 31);
	entry->offset = addr - entry->base;
	entry->write_val = write_val;
	entry->index = drvdata->nr_config[drvdata->curr_list]++;
	entry->len = 1;
	INIT_LIST_HEAD(&entry->list);
	list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
	mutex_unlock(&drvdata->mutex);
	return size;
err:
	mutex_unlock(&drvdata->mutex);
	return ret;
@@ -1462,44 +1443,61 @@ static void dcc_sram_dev_exit(struct dcc_drvdata *drvdata)
	dcc_sram_dev_deregister(drvdata);
}

static void dcc_allocate_dump_mem(struct dcc_drvdata *drvdata)
static void dcc_configure_list(struct dcc_drvdata *drvdata,
			       struct device_node *np)
{
	int ret;
	struct device *dev = drvdata->dev;
	struct msm_dump_entry reg_dump_entry, sram_dump_entry;

	/* Allocate memory for dcc reg dump */
	drvdata->reg_buf = devm_kzalloc(dev, drvdata->reg_size, GFP_KERNEL);
	if (drvdata->reg_buf) {
		drvdata->reg_data.addr = virt_to_phys(drvdata->reg_buf);
		drvdata->reg_data.len = drvdata->reg_size;
		reg_dump_entry.id = MSM_DUMP_DATA_DCC_REG;
		reg_dump_entry.addr = virt_to_phys(&drvdata->reg_data);
		ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
					     &reg_dump_entry);
		if (ret) {
			dev_err(dev, "DCC REG dump setup failed\n");
			devm_kfree(dev, drvdata->reg_buf);
	int ret, i;
	const __be32 *prop;
	uint32_t len, entry, val1, val2, apb_bus;
	uint32_t curr_link_list;

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

	if (curr_link_list >= DCC_MAX_LINK_LIST) {
		dev_err(drvdata->dev, "List configuration failed");
		return;
	}
	} else {
		dev_err(dev, "DCC REG dump allocation failed\n");
	}

	/* Allocate memory for dcc sram dump */
	drvdata->sram_buf = devm_kzalloc(dev, drvdata->ram_size, GFP_KERNEL);
	if (drvdata->sram_buf) {
		drvdata->sram_data.addr = virt_to_phys(drvdata->sram_buf);
		drvdata->sram_data.len = drvdata->ram_size;
		sram_dump_entry.id = MSM_DUMP_DATA_DCC_SRAM;
		sram_dump_entry.addr = virt_to_phys(&drvdata->sram_data);
		ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
					     &sram_dump_entry);
	drvdata->curr_list = curr_link_list;

	prop = of_get_property(np, "qcom,link-list", &len);
	if (prop) {
		len /= sizeof(__be32);
		i = 0;
		while (i < len) {
			entry = be32_to_cpu(prop[i++]);
			val1 = be32_to_cpu(prop[i++]);
			val2 = be32_to_cpu(prop[i++]);
			apb_bus = be32_to_cpu(prop[i++]);

			switch (entry) {
			case DCC_READ:
				ret = dcc_config_add(drvdata, val1,
						     val2, apb_bus);
				break;
			case DCC_WRITE:
				ret = dcc_add_write(drvdata, val1,
						    val2, apb_bus);
				break;
			case DCC_LOOP:
				ret = dcc_add_loop(drvdata, val1);
				break;
			default:
				ret = -EINVAL;
			}

			if (ret) {
			dev_err(dev, "DCC SRAM dump setup failed\n");
			devm_kfree(dev, drvdata->sram_buf);
				dev_err(drvdata->dev,
					"DCC init time config failed err:%d\n",
					ret);
				break;
			}
	} else {
		dev_err(dev, "DCC SRAM dump allocation failed\n");
		}

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

@@ -1542,9 +1540,6 @@ static int dcc_probe(struct platform_device *pdev)
	if (ret)
		return -EINVAL;

	drvdata->save_reg = of_property_read_bool(pdev->dev.of_node,
						  "qcom,save-reg");

	mutex_init(&drvdata->mutex);

	for (i = 0; i < DCC_MAX_LINK_LIST; i++) {
@@ -1580,7 +1575,8 @@ static int dcc_probe(struct platform_device *pdev)
	if (ret)
		goto err;

	dcc_allocate_dump_mem(drvdata);
	dcc_configure_list(drvdata, pdev->dev.of_node);

	return 0;
err:
	return ret;
@@ -1616,13 +1612,7 @@ static int __init dcc_init(void)
{
	return platform_driver_register(&dcc_driver);
}
module_init(dcc_init);

static void __exit dcc_exit(void)
{
	platform_driver_unregister(&dcc_driver);
}
module_exit(dcc_exit);
pure_initcall(dcc_init);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MSM data capture and compare engine");
+20 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __DT_BINDINGS_QCOM_DCC_V2_H
#define __DT_BINDINGS_QCOM_DCC_V2_H

#define DCC_READ	0
#define DCC_WRITE	1
#define DCC_LOOP	2

#endif