159 lines
3.2 KiB
C
159 lines
3.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) Rockchip Electronics Co., Ltd.
|
|
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/iommu.h>
|
|
|
|
#include "rknpu_reset.h"
|
|
|
|
#ifndef FPGA_PLATFORM
|
|
static inline struct reset_control *rknpu_reset_control_get(struct device *dev,
|
|
const char *name)
|
|
{
|
|
struct reset_control *rst = NULL;
|
|
|
|
rst = devm_reset_control_get(dev, name);
|
|
if (IS_ERR(rst))
|
|
LOG_DEV_ERROR(dev,
|
|
"failed to get rknpu reset control: %s, %ld\n",
|
|
name, PTR_ERR(rst));
|
|
|
|
return rst;
|
|
}
|
|
#endif
|
|
|
|
int rknpu_reset_get(struct rknpu_device *rknpu_dev)
|
|
{
|
|
#ifndef FPGA_PLATFORM
|
|
int i = 0;
|
|
int num_srsts = 0;
|
|
|
|
num_srsts = of_count_phandle_with_args(rknpu_dev->dev->of_node,
|
|
"resets", "#reset-cells");
|
|
if (num_srsts <= 0) {
|
|
LOG_DEV_ERROR(rknpu_dev->dev,
|
|
"failed to get rknpu resets from dtb\n");
|
|
return num_srsts;
|
|
}
|
|
|
|
rknpu_dev->srsts = devm_kcalloc(rknpu_dev->dev, num_srsts,
|
|
sizeof(*rknpu_dev->srsts), GFP_KERNEL);
|
|
if (!rknpu_dev->srsts)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < num_srsts; ++i) {
|
|
rknpu_dev->srsts[i] = devm_reset_control_get_exclusive_by_index(
|
|
rknpu_dev->dev, i);
|
|
if (IS_ERR(rknpu_dev->srsts[i])) {
|
|
rknpu_dev->num_srsts = i;
|
|
return PTR_ERR(rknpu_dev->srsts[i]);
|
|
}
|
|
}
|
|
|
|
rknpu_dev->num_srsts = num_srsts;
|
|
|
|
return num_srsts;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifndef FPGA_PLATFORM
|
|
static int rknpu_reset_assert(struct reset_control *rst)
|
|
{
|
|
int ret = -EINVAL;
|
|
|
|
if (!rst)
|
|
return -EINVAL;
|
|
|
|
ret = reset_control_assert(rst);
|
|
if (ret < 0) {
|
|
LOG_ERROR("failed to assert rknpu reset: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rknpu_reset_deassert(struct reset_control *rst)
|
|
{
|
|
int ret = -EINVAL;
|
|
|
|
if (!rst)
|
|
return -EINVAL;
|
|
|
|
ret = reset_control_deassert(rst);
|
|
if (ret < 0) {
|
|
LOG_ERROR("failed to deassert rknpu reset: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
|
|
{
|
|
#ifndef FPGA_PLATFORM
|
|
struct iommu_domain *domain = NULL;
|
|
struct rknpu_subcore_data *subcore_data = NULL;
|
|
int ret = 0, i = 0;
|
|
|
|
if (rknpu_dev->bypass_soft_reset) {
|
|
LOG_WARN("bypass soft reset\n");
|
|
return 0;
|
|
}
|
|
|
|
if (!mutex_trylock(&rknpu_dev->reset_lock))
|
|
return 0;
|
|
|
|
rknpu_dev->soft_reseting = true;
|
|
|
|
msleep(100);
|
|
|
|
for (i = 0; i < rknpu_dev->config->num_irqs; ++i) {
|
|
subcore_data = &rknpu_dev->subcore_datas[i];
|
|
wake_up(&subcore_data->job_done_wq);
|
|
}
|
|
|
|
LOG_INFO("soft reset, num: %d\n", rknpu_dev->num_srsts);
|
|
|
|
for (i = 0; i < rknpu_dev->num_srsts; ++i)
|
|
ret |= rknpu_reset_assert(rknpu_dev->srsts[i]);
|
|
|
|
udelay(10);
|
|
|
|
for (i = 0; i < rknpu_dev->num_srsts; ++i)
|
|
ret |= rknpu_reset_deassert(rknpu_dev->srsts[i]);
|
|
|
|
udelay(10);
|
|
|
|
if (ret) {
|
|
LOG_DEV_ERROR(rknpu_dev->dev,
|
|
"failed to soft reset for rknpu: %d\n", ret);
|
|
mutex_unlock(&rknpu_dev->reset_lock);
|
|
return ret;
|
|
}
|
|
|
|
if (rknpu_dev->iommu_en)
|
|
domain = iommu_get_domain_for_dev(rknpu_dev->dev);
|
|
|
|
if (domain) {
|
|
iommu_detach_device(domain, rknpu_dev->dev);
|
|
iommu_attach_device(domain, rknpu_dev->dev);
|
|
}
|
|
|
|
rknpu_dev->soft_reseting = false;
|
|
|
|
if (rknpu_dev->config->state_init != NULL)
|
|
rknpu_dev->config->state_init(rknpu_dev);
|
|
|
|
mutex_unlock(&rknpu_dev->reset_lock);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|