M7350/kernel/drivers/gpu/msm/adreno_coresight.c
2024-09-09 08:57:42 +00:00

334 lines
9.0 KiB
C

/* Copyright (c) 2013-2015, 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/platform_device.h>
#include <linux/of_coresight.h>
#include <linux/coresight.h>
#include "adreno.h"
#define TO_ADRENO_CORESIGHT_ATTR(_attr) \
container_of(_attr, struct adreno_coresight_attr, attr)
ssize_t adreno_coresight_show_register(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned int val = 0;
struct kgsl_device *device = dev_get_drvdata(dev->parent);
struct adreno_device *adreno_dev;
struct adreno_coresight_attr *cattr = TO_ADRENO_CORESIGHT_ATTR(attr);
if (device == NULL)
return -EINVAL;
adreno_dev = ADRENO_DEVICE(device);
if (cattr->reg == NULL)
return -EINVAL;
/*
* Return the current value of the register if coresight is enabled,
* otherwise report 0
*/
mutex_lock(&device->mutex);
if (test_bit(ADRENO_DEVICE_CORESIGHT, &adreno_dev->priv)) {
/*
* If the device isn't power collapsed read the actual value
* from the hardware - otherwise return the cached value
*/
if (device->state == KGSL_STATE_ACTIVE ||
device->state == KGSL_STATE_NAP) {
if (!kgsl_active_count_get(device)) {
kgsl_regread(device, cattr->reg->offset,
&cattr->reg->value);
kgsl_active_count_put(device);
}
}
val = cattr->reg->value;
}
mutex_unlock(&device->mutex);
return snprintf(buf, PAGE_SIZE, "0x%X\n", val);
}
ssize_t adreno_coresight_store_register(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;
struct adreno_coresight_attr *cattr = TO_ADRENO_CORESIGHT_ATTR(attr);
unsigned long val;
int ret;
if (device == NULL)
return -EINVAL;
adreno_dev = ADRENO_DEVICE(device);
if (cattr->reg == NULL)
return -EINVAL;
ret = kstrtoul(buf, 0, &val);
if (ret)
return ret;
mutex_lock(&device->mutex);
/* Ignore writes while coresight is off */
if (!test_bit(ADRENO_DEVICE_CORESIGHT, &adreno_dev->priv))
goto out;
cattr->reg->value = val;
/* Program the hardware if it is not power collapsed */
if (device->state == KGSL_STATE_ACTIVE ||
device->state == KGSL_STATE_NAP) {
if (!kgsl_active_count_get(device)) {
kgsl_regwrite(device, cattr->reg->offset,
cattr->reg->value);
kgsl_active_count_put(device);
}
}
out:
mutex_unlock(&device->mutex);
return size;
}
/**
* 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.
*/
static void adreno_coresight_disable(struct coresight_device *csdev)
{
struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
struct adreno_device *adreno_dev;
struct adreno_gpudev *gpudev;
struct adreno_coresight *coresight;
int i;
if (device == NULL)
return;
adreno_dev = ADRENO_DEVICE(device);
gpudev = ADRENO_GPU_DEVICE(adreno_dev);
coresight = gpudev->coresight;
if (coresight == NULL)
return;
mutex_lock(&device->mutex);
if (!kgsl_active_count_get(device)) {
for (i = 0; i < coresight->count; i++)
kgsl_regwrite(device, coresight->registers[i].offset,
0);
kgsl_active_count_put(device);
}
clear_bit(ADRENO_DEVICE_CORESIGHT, &adreno_dev->priv);
mutex_unlock(&device->mutex);
}
/**
* _adreno_coresight_get_and_clear(): Save the current value of coresight
* registers and clear the registers subsequently. Clearing registers
* has the effect of disabling coresight.
* @adreno_dev: Pointer to adreno device struct
*/
static int _adreno_coresight_get_and_clear(struct adreno_device *adreno_dev)
{
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct kgsl_device *device = &adreno_dev->dev;
struct adreno_coresight *coresight = gpudev->coresight;
int i;
if (coresight == NULL)
return -ENODEV;
kgsl_pre_hwaccess(device);
/*
* Save the current value of each coresight register
* and then clear each register
*/
for (i = 0; i < coresight->count; i++) {
kgsl_regread(device, coresight->registers[i].offset,
&coresight->registers[i].value);
kgsl_regwrite(device, coresight->registers[i].offset,
0);
}
return 0;
}
static int _adreno_coresight_set(struct adreno_device *adreno_dev)
{
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct kgsl_device *device = &adreno_dev->dev;
struct adreno_coresight *coresight = gpudev->coresight;
int i;
if (coresight == NULL)
return -ENODEV;
BUG_ON(!kgsl_state_is_awake(device));
for (i = 0; i < coresight->count; i++)
kgsl_regwrite(device, coresight->registers[i].offset,
coresight->registers[i].value);
return 0;
}
/**
* 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 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.
*/
static int adreno_coresight_enable(struct coresight_device *csdev)
{
struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
struct adreno_device *adreno_dev;
struct adreno_gpudev *gpudev;
struct adreno_coresight *coresight;
int ret = 0;
if (device == NULL)
return -ENODEV;
adreno_dev = ADRENO_DEVICE(device);
gpudev = ADRENO_GPU_DEVICE(adreno_dev);
coresight = gpudev->coresight;
if (coresight == NULL)
return -ENODEV;
mutex_lock(&device->mutex);
if (!test_and_set_bit(ADRENO_DEVICE_CORESIGHT, &adreno_dev->priv)) {
int i;
/* Reset all the debug registers to their default values */
for (i = 0; i < coresight->count; i++)
coresight->registers[i].value =
coresight->registers[i].initial;
if (kgsl_state_is_awake(device)) {
ret = kgsl_active_count_get(device);
if (!ret) {
ret = _adreno_coresight_set(adreno_dev);
kgsl_active_count_put(device);
}
}
}
mutex_unlock(&device->mutex);
return ret;
}
/**
* adreno_coresight_start() - Reprogram coresight registers after power collapse
* @adreno_dev: Pointer to the adreno device structure
*
* Cache the current coresight register values so they can be restored after
* power collapse
*/
void adreno_coresight_stop(struct adreno_device *adreno_dev)
{
if (test_bit(ADRENO_DEVICE_CORESIGHT, &adreno_dev->priv))
_adreno_coresight_get_and_clear(adreno_dev);
}
/**
* adreno_coresight_start() - Reprogram coresight registers after power collapse
* @adreno_dev: Pointer to the adreno device structure
*
* Reprogram the cached values to the coresight registers on power up
*/
void adreno_coresight_start(struct adreno_device *adreno_dev)
{
if (test_bit(ADRENO_DEVICE_CORESIGHT, &adreno_dev->priv))
_adreno_coresight_set(adreno_dev);
}
static const struct coresight_ops_source adreno_coresight_source_ops = {
.enable = adreno_coresight_enable,
.disable = adreno_coresight_disable,
};
static const struct coresight_ops adreno_coresight_ops = {
.source_ops = &adreno_coresight_source_ops,
};
void adreno_coresight_remove(struct adreno_device *adreno_dev)
{
coresight_unregister(adreno_dev->csdev);
adreno_dev->csdev = NULL;
}
int adreno_coresight_init(struct adreno_device *adreno_dev)
{
int ret = 0;
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct kgsl_device *device = &adreno_dev->dev;
struct coresight_desc desc;
if (gpudev->coresight == NULL)
return -ENODEV;
if (!IS_ERR_OR_NULL(adreno_dev->csdev))
return 0;
memset(&desc, 0, sizeof(desc));
desc.pdata = of_get_coresight_platform_data(&device->pdev->dev,
device->pdev->dev.of_node);
if (desc.pdata == NULL)
return -ENODEV;
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS;
desc.ops = &adreno_coresight_ops;
desc.dev = &device->pdev->dev;
desc.owner = THIS_MODULE;
desc.groups = gpudev->coresight->groups;
adreno_dev->csdev = coresight_register(&desc);
if (IS_ERR(adreno_dev->csdev))
ret = PTR_ERR(adreno_dev->csdev);
return ret;
}