220 lines
6.7 KiB
C
220 lines
6.7 KiB
C
|
/* Copyright (c) 2013, 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.
|
||
|
*/
|
||
|
|
||
|
#include <linux/clk.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/err.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/errno.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/miscdevice.h>
|
||
|
#include <linux/of_coresight.h>
|
||
|
#include <linux/coresight.h>
|
||
|
#include <linux/memory_alloc.h>
|
||
|
#include <linux/io.h>
|
||
|
#include <linux/of.h>
|
||
|
|
||
|
#include "kgsl.h"
|
||
|
#include "kgsl_device.h"
|
||
|
#include "adreno.h"
|
||
|
|
||
|
struct coresight_attr {
|
||
|
struct device_attribute attr;
|
||
|
int regname;
|
||
|
};
|
||
|
|
||
|
#define CORESIGHT_CREATE_REG_ATTR(_attrname, _regname) \
|
||
|
struct coresight_attr coresight_attr_##_attrname = \
|
||
|
{ __ATTR(_attrname, S_IRUGO | S_IWUSR, gfx_show_reg, gfx_store_reg),\
|
||
|
_regname}
|
||
|
|
||
|
/**
|
||
|
* adreno_coresight_enable() - Generic function to enable coresight debugging
|
||
|
* @csdev: Pointer to coresight's device struct
|
||
|
*
|
||
|
* This is a generic function to enable coresight debug bus on adreno
|
||
|
* devices. This should be used in all cases of enabling
|
||
|
* coresight debug bus for adreno devices. This function in turn calls
|
||
|
* the adreno device specific function through gpudev hook.
|
||
|
* This function is registered as the coresight enable function
|
||
|
* with coresight driver. It should only be called through coresight driver
|
||
|
* as that would ensure that the necessary setup required to be done
|
||
|
* on coresight driver's part is also done.
|
||
|
*/
|
||
|
int adreno_coresight_enable(struct coresight_device *csdev)
|
||
|
{
|
||
|
struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
|
||
|
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||
|
|
||
|
/* Check if coresight compatible device, return error otherwise */
|
||
|
if (adreno_dev->gpudev->coresight_enable)
|
||
|
return adreno_dev->gpudev->coresight_enable(device);
|
||
|
else
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* adreno_coresight_disable() - Generic function to disable coresight debugging
|
||
|
* @csdev: Pointer to coresight's device struct
|
||
|
*
|
||
|
* This is a generic function to disable coresight debug bus on adreno
|
||
|
* devices. This should be used in all cases of disabling
|
||
|
* coresight debug bus for adreno devices. This function in turn calls
|
||
|
* the adreno device specific function through the gpudev hook.
|
||
|
* This function is registered as the coresight disable function
|
||
|
* with coresight driver. It should only be called through coresight driver
|
||
|
* as that would ensure that the necessary setup required to be done on
|
||
|
* coresight driver's part is also done.
|
||
|
*/
|
||
|
void adreno_coresight_disable(struct coresight_device *csdev)
|
||
|
{
|
||
|
struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
|
||
|
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||
|
|
||
|
/* Check if coresight compatible device, bail otherwise */
|
||
|
if (adreno_dev->gpudev->coresight_disable)
|
||
|
return adreno_dev->gpudev->coresight_disable(device);
|
||
|
}
|
||
|
|
||
|
static const struct coresight_ops_source adreno_coresight_ops_source = {
|
||
|
.enable = adreno_coresight_enable,
|
||
|
.disable = adreno_coresight_disable,
|
||
|
};
|
||
|
|
||
|
static const struct coresight_ops adreno_coresight_cs_ops = {
|
||
|
.source_ops = &adreno_coresight_ops_source,
|
||
|
};
|
||
|
|
||
|
void adreno_coresight_remove(struct platform_device *pdev)
|
||
|
{
|
||
|
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
|
||
|
coresight_unregister(pdata->csdev);
|
||
|
}
|
||
|
|
||
|
static ssize_t coresight_read_reg(struct kgsl_device *device,
|
||
|
unsigned int offset, char *buf)
|
||
|
{
|
||
|
unsigned int regval = 0;
|
||
|
|
||
|
mutex_lock(&device->mutex);
|
||
|
if (!kgsl_active_count_get(device)) {
|
||
|
adreno_regread(device, offset, ®val);
|
||
|
kgsl_active_count_put(device);
|
||
|
}
|
||
|
mutex_unlock(&device->mutex);
|
||
|
return snprintf(buf, PAGE_SIZE, "0x%X", regval);
|
||
|
}
|
||
|
|
||
|
static inline unsigned int coresight_convert_reg(const char *buf)
|
||
|
{
|
||
|
long regval = 0;
|
||
|
int rv = 0;
|
||
|
|
||
|
rv = kstrtoul(buf, 16, ®val);
|
||
|
if (!rv)
|
||
|
return (unsigned int)regval;
|
||
|
else
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
static ssize_t gfx_show_reg(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct kgsl_device *device = dev_get_drvdata(dev->parent);
|
||
|
struct coresight_attr *csight_attr = container_of(attr,
|
||
|
struct coresight_attr, attr);
|
||
|
return coresight_read_reg(device, csight_attr->regname, buf);
|
||
|
}
|
||
|
|
||
|
static ssize_t gfx_store_reg(struct device *dev,
|
||
|
struct device_attribute *attr,
|
||
|
const char *buf, size_t size)
|
||
|
{
|
||
|
struct kgsl_device *device = dev_get_drvdata(dev->parent);
|
||
|
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||
|
struct coresight_attr *csight_attr = container_of(attr,
|
||
|
struct coresight_attr, attr);
|
||
|
unsigned int regval = 0;
|
||
|
|
||
|
regval = coresight_convert_reg(buf);
|
||
|
|
||
|
if (adreno_dev->gpudev->coresight_config_debug_reg)
|
||
|
adreno_dev->gpudev->coresight_config_debug_reg(device,
|
||
|
csight_attr->regname, regval);
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
CORESIGHT_CREATE_REG_ATTR(config_debug_bus, DEBUG_BUS_CTL);
|
||
|
CORESIGHT_CREATE_REG_ATTR(config_trace_stop_cnt, TRACE_STOP_CNT);
|
||
|
CORESIGHT_CREATE_REG_ATTR(config_trace_start_cnt, TRACE_START_CNT);
|
||
|
CORESIGHT_CREATE_REG_ATTR(config_trace_period_cnt, TRACE_PERIOD_CNT);
|
||
|
CORESIGHT_CREATE_REG_ATTR(config_trace_cmd, TRACE_CMD);
|
||
|
CORESIGHT_CREATE_REG_ATTR(config_trace_bus_ctl, TRACE_BUS_CTL);
|
||
|
|
||
|
static struct attribute *gfx_attrs[] = {
|
||
|
&coresight_attr_config_debug_bus.attr.attr,
|
||
|
&coresight_attr_config_trace_start_cnt.attr.attr,
|
||
|
&coresight_attr_config_trace_stop_cnt.attr.attr,
|
||
|
&coresight_attr_config_trace_period_cnt.attr.attr,
|
||
|
&coresight_attr_config_trace_cmd.attr.attr,
|
||
|
&coresight_attr_config_trace_bus_ctl.attr.attr,
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
static struct attribute_group gfx_attr_grp = {
|
||
|
.attrs = gfx_attrs,
|
||
|
};
|
||
|
|
||
|
static const struct attribute_group *gfx_attr_grps[] = {
|
||
|
&gfx_attr_grp,
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
int adreno_coresight_init(struct platform_device *pdev)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
|
||
|
struct device *dev = &pdev->dev;
|
||
|
struct coresight_desc *desc;
|
||
|
|
||
|
if (IS_ERR_OR_NULL(pdata->coresight_pdata))
|
||
|
return -ENODATA;
|
||
|
|
||
|
|
||
|
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
|
||
|
if (!desc)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
|
||
|
desc->type = CORESIGHT_DEV_TYPE_SOURCE;
|
||
|
desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS;
|
||
|
desc->ops = &adreno_coresight_cs_ops;
|
||
|
desc->pdata = pdata->coresight_pdata;
|
||
|
desc->dev = &pdev->dev;
|
||
|
desc->owner = THIS_MODULE;
|
||
|
desc->groups = gfx_attr_grps;
|
||
|
pdata->csdev = coresight_register(desc);
|
||
|
if (IS_ERR(pdata->csdev)) {
|
||
|
ret = PTR_ERR(pdata->csdev);
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
err:
|
||
|
devm_kfree(dev, desc);
|
||
|
return ret;
|
||
|
}
|
||
|
|