/* 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 #include #include #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; }