Merge tag 'drm-misc-next-2021-10-14' of git://anongit.freedesktop.org/drm/drm-misc...
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / intel_pcode.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2013-2021 Intel Corporation
4  */
5
6 #include "i915_drv.h"
7 #include "intel_pcode.h"
8
9 static int gen6_check_mailbox_status(u32 mbox)
10 {
11         switch (mbox & GEN6_PCODE_ERROR_MASK) {
12         case GEN6_PCODE_SUCCESS:
13                 return 0;
14         case GEN6_PCODE_UNIMPLEMENTED_CMD:
15                 return -ENODEV;
16         case GEN6_PCODE_ILLEGAL_CMD:
17                 return -ENXIO;
18         case GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:
19         case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:
20                 return -EOVERFLOW;
21         case GEN6_PCODE_TIMEOUT:
22                 return -ETIMEDOUT;
23         default:
24                 MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK);
25                 return 0;
26         }
27 }
28
29 static int gen7_check_mailbox_status(u32 mbox)
30 {
31         switch (mbox & GEN6_PCODE_ERROR_MASK) {
32         case GEN6_PCODE_SUCCESS:
33                 return 0;
34         case GEN6_PCODE_ILLEGAL_CMD:
35                 return -ENXIO;
36         case GEN7_PCODE_TIMEOUT:
37                 return -ETIMEDOUT;
38         case GEN7_PCODE_ILLEGAL_DATA:
39                 return -EINVAL;
40         case GEN11_PCODE_ILLEGAL_SUBCOMMAND:
41                 return -ENXIO;
42         case GEN11_PCODE_LOCKED:
43                 return -EBUSY;
44         case GEN11_PCODE_REJECTED:
45                 return -EACCES;
46         case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:
47                 return -EOVERFLOW;
48         default:
49                 MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK);
50                 return 0;
51         }
52 }
53
54 static int __sandybridge_pcode_rw(struct drm_i915_private *i915,
55                                   u32 mbox, u32 *val, u32 *val1,
56                                   int fast_timeout_us,
57                                   int slow_timeout_ms,
58                                   bool is_read)
59 {
60         struct intel_uncore *uncore = &i915->uncore;
61
62         lockdep_assert_held(&i915->sb_lock);
63
64         /*
65          * GEN6_PCODE_* are outside of the forcewake domain, we can use
66          * intel_uncore_read/write_fw variants to reduce the amount of work
67          * required when reading/writing.
68          */
69
70         if (intel_uncore_read_fw(uncore, GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY)
71                 return -EAGAIN;
72
73         intel_uncore_write_fw(uncore, GEN6_PCODE_DATA, *val);
74         intel_uncore_write_fw(uncore, GEN6_PCODE_DATA1, val1 ? *val1 : 0);
75         intel_uncore_write_fw(uncore,
76                               GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox);
77
78         if (__intel_wait_for_register_fw(uncore,
79                                          GEN6_PCODE_MAILBOX,
80                                          GEN6_PCODE_READY, 0,
81                                          fast_timeout_us,
82                                          slow_timeout_ms,
83                                          &mbox))
84                 return -ETIMEDOUT;
85
86         if (is_read)
87                 *val = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA);
88         if (is_read && val1)
89                 *val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1);
90
91         if (GRAPHICS_VER(i915) > 6)
92                 return gen7_check_mailbox_status(mbox);
93         else
94                 return gen6_check_mailbox_status(mbox);
95 }
96
97 int sandybridge_pcode_read(struct drm_i915_private *i915, u32 mbox,
98                            u32 *val, u32 *val1)
99 {
100         int err;
101
102         mutex_lock(&i915->sb_lock);
103         err = __sandybridge_pcode_rw(i915, mbox, val, val1,
104                                      500, 20,
105                                      true);
106         mutex_unlock(&i915->sb_lock);
107
108         if (err) {
109                 drm_dbg(&i915->drm,
110                         "warning: pcode (read from mbox %x) mailbox access failed for %ps: %d\n",
111                         mbox, __builtin_return_address(0), err);
112         }
113
114         return err;
115 }
116
117 int sandybridge_pcode_write_timeout(struct drm_i915_private *i915,
118                                     u32 mbox, u32 val,
119                                     int fast_timeout_us,
120                                     int slow_timeout_ms)
121 {
122         int err;
123
124         mutex_lock(&i915->sb_lock);
125         err = __sandybridge_pcode_rw(i915, mbox, &val, NULL,
126                                      fast_timeout_us, slow_timeout_ms,
127                                      false);
128         mutex_unlock(&i915->sb_lock);
129
130         if (err) {
131                 drm_dbg(&i915->drm,
132                         "warning: pcode (write of 0x%08x to mbox %x) mailbox access failed for %ps: %d\n",
133                         val, mbox, __builtin_return_address(0), err);
134         }
135
136         return err;
137 }
138
139 static bool skl_pcode_try_request(struct drm_i915_private *i915, u32 mbox,
140                                   u32 request, u32 reply_mask, u32 reply,
141                                   u32 *status)
142 {
143         *status = __sandybridge_pcode_rw(i915, mbox, &request, NULL,
144                                          500, 0,
145                                          true);
146
147         return *status || ((request & reply_mask) == reply);
148 }
149
150 /**
151  * skl_pcode_request - send PCODE request until acknowledgment
152  * @i915: device private
153  * @mbox: PCODE mailbox ID the request is targeted for
154  * @request: request ID
155  * @reply_mask: mask used to check for request acknowledgment
156  * @reply: value used to check for request acknowledgment
157  * @timeout_base_ms: timeout for polling with preemption enabled
158  *
159  * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE
160  * reports an error or an overall timeout of @timeout_base_ms+50 ms expires.
161  * The request is acknowledged once the PCODE reply dword equals @reply after
162  * applying @reply_mask. Polling is first attempted with preemption enabled
163  * for @timeout_base_ms and if this times out for another 50 ms with
164  * preemption disabled.
165  *
166  * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some
167  * other error as reported by PCODE.
168  */
169 int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request,
170                       u32 reply_mask, u32 reply, int timeout_base_ms)
171 {
172         u32 status;
173         int ret;
174
175         mutex_lock(&i915->sb_lock);
176
177 #define COND \
178         skl_pcode_try_request(i915, mbox, request, reply_mask, reply, &status)
179
180         /*
181          * Prime the PCODE by doing a request first. Normally it guarantees
182          * that a subsequent request, at most @timeout_base_ms later, succeeds.
183          * _wait_for() doesn't guarantee when its passed condition is evaluated
184          * first, so send the first request explicitly.
185          */
186         if (COND) {
187                 ret = 0;
188                 goto out;
189         }
190         ret = _wait_for(COND, timeout_base_ms * 1000, 10, 10);
191         if (!ret)
192                 goto out;
193
194         /*
195          * The above can time out if the number of requests was low (2 in the
196          * worst case) _and_ PCODE was busy for some reason even after a
197          * (queued) request and @timeout_base_ms delay. As a workaround retry
198          * the poll with preemption disabled to maximize the number of
199          * requests. Increase the timeout from @timeout_base_ms to 50ms to
200          * account for interrupts that could reduce the number of these
201          * requests, and for any quirks of the PCODE firmware that delays
202          * the request completion.
203          */
204         drm_dbg_kms(&i915->drm,
205                     "PCODE timeout, retrying with preemption disabled\n");
206         drm_WARN_ON_ONCE(&i915->drm, timeout_base_ms > 3);
207         preempt_disable();
208         ret = wait_for_atomic(COND, 50);
209         preempt_enable();
210
211 out:
212         mutex_unlock(&i915->sb_lock);
213         return ret ? ret : status;
214 #undef COND
215 }
216
217 int intel_pcode_init(struct drm_i915_private *i915)
218 {
219         int ret = 0;
220
221         if (!IS_DGFX(i915))
222                 return ret;
223
224         ret = skl_pcode_request(i915, DG1_PCODE_STATUS,
225                                 DG1_UNCORE_GET_INIT_STATUS,
226                                 DG1_UNCORE_INIT_STATUS_COMPLETE,
227                                 DG1_UNCORE_INIT_STATUS_COMPLETE, 180000);
228
229         drm_dbg(&i915->drm, "PCODE init status %d\n", ret);
230
231         if (ret)
232                 drm_err(&i915->drm, "Pcode did not report uncore initialization completion!\n");
233
234         return ret;
235 }