1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) Rockchip Electronics Co.Ltd
4 * Author: Felix Zeng <felix.zeng@rock-chips.com>
5 */
6
7 #include <linux/delay.h>
8 #include <linux/iommu.h>
9
10 #include "rknpu_reset.h"
11
12 #ifndef FPGA_PLATFORM
rknpu_reset_control_get(struct device * dev,const char * name)13 static inline struct reset_control *rknpu_reset_control_get(struct device *dev,
14 const char *name)
15 {
16 struct reset_control *rst = NULL;
17
18 rst = devm_reset_control_get(dev, name);
19 if (IS_ERR(rst))
20 LOG_DEV_ERROR(dev,
21 "failed to get rknpu reset control: %s, %ld\n",
22 name, PTR_ERR(rst));
23
24 return rst;
25 }
26 #endif
27
rknpu_reset_get(struct rknpu_device * rknpu_dev)28 int rknpu_reset_get(struct rknpu_device *rknpu_dev)
29 {
30 #ifndef FPGA_PLATFORM
31 struct reset_control *srst_a = NULL;
32 struct reset_control *srst_h = NULL;
33 int i = 0;
34
35 for (i = 0; i < rknpu_dev->config->num_resets; i++) {
36 srst_a = rknpu_reset_control_get(
37 rknpu_dev->dev,
38 rknpu_dev->config->resets[i].srst_a_name);
39 if (IS_ERR(srst_a))
40 return PTR_ERR(srst_a);
41
42 rknpu_dev->srst_a[i] = srst_a;
43
44 srst_h = rknpu_reset_control_get(
45 rknpu_dev->dev,
46 rknpu_dev->config->resets[i].srst_h_name);
47 if (IS_ERR(srst_h))
48 return PTR_ERR(srst_h);
49
50 rknpu_dev->srst_h[i] = srst_h;
51 }
52 #endif
53
54 return 0;
55 }
56
57 #ifndef FPGA_PLATFORM
rknpu_reset_assert(struct reset_control * rst)58 static int rknpu_reset_assert(struct reset_control *rst)
59 {
60 int ret = -EINVAL;
61
62 if (!rst)
63 return -EINVAL;
64
65 ret = reset_control_assert(rst);
66 if (ret < 0) {
67 LOG_ERROR("failed to assert rknpu reset: %d\n", ret);
68 return ret;
69 }
70
71 return 0;
72 }
73
rknpu_reset_deassert(struct reset_control * rst)74 static int rknpu_reset_deassert(struct reset_control *rst)
75 {
76 int ret = -EINVAL;
77
78 if (!rst)
79 return -EINVAL;
80
81 ret = reset_control_deassert(rst);
82 if (ret < 0) {
83 LOG_ERROR("failed to deassert rknpu reset: %d\n", ret);
84 return ret;
85 }
86
87 return 0;
88 }
89 #endif
90
rknpu_soft_reset(struct rknpu_device * rknpu_dev)91 int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
92 {
93 #ifndef FPGA_PLATFORM
94 struct iommu_domain *domain = NULL;
95 struct rknpu_subcore_data *subcore_data = NULL;
96 int ret = -EINVAL, i = 0;
97
98 if (rknpu_dev->bypass_soft_reset) {
99 LOG_WARN("bypass soft reset\n");
100 return 0;
101 }
102
103 if (!mutex_trylock(&rknpu_dev->reset_lock))
104 return 0;
105
106 rknpu_dev->soft_reseting = true;
107
108 msleep(100);
109
110 for (i = 0; i < rknpu_dev->config->num_irqs; ++i) {
111 subcore_data = &rknpu_dev->subcore_datas[i];
112 wake_up(&subcore_data->job_done_wq);
113 }
114
115 LOG_INFO("soft reset\n");
116
117 for (i = 0; i < rknpu_dev->config->num_resets; i++) {
118 ret = rknpu_reset_assert(rknpu_dev->srst_a[i]);
119 ret |= rknpu_reset_assert(rknpu_dev->srst_h[i]);
120
121 udelay(10);
122
123 ret |= rknpu_reset_deassert(rknpu_dev->srst_a[i]);
124 ret |= rknpu_reset_deassert(rknpu_dev->srst_h[i]);
125 }
126
127 if (ret) {
128 LOG_DEV_ERROR(rknpu_dev->dev,
129 "failed to soft reset for rknpu: %d\n", ret);
130 mutex_unlock(&rknpu_dev->reset_lock);
131 return ret;
132 }
133
134 if (rknpu_dev->iommu_en)
135 domain = iommu_get_domain_for_dev(rknpu_dev->dev);
136
137 if (domain) {
138 iommu_detach_device(domain, rknpu_dev->dev);
139 iommu_attach_device(domain, rknpu_dev->dev);
140 }
141
142 rknpu_dev->soft_reseting = false;
143
144 mutex_unlock(&rknpu_dev->reset_lock);
145 #endif
146
147 return 0;
148 }
149