1 /* $OpenBSD: cn30xxpowvar.h,v 1.7 2024/05/20 23:13:33 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2007 Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #ifndef _CN30XXPOWVAR_H_
30 #define _CN30XXPOWVAR_H_
31
32 #define POW_TAG_TYPE_ORDERED 0
33 #define POW_TAG_TYPE_ATOMIC 1
34 #define POW_TAG_TYPE_NULL 2
35 #define POW_TAG_TYPE_NULL_NULL 3
36
37 #define POW_TAG_OP_SWTAG 0
38 #define POW_TAG_OP_SWTAG_FULL 1
39 #define POW_TAG_OP_SWTAG_DESCHED 2
40 #define POW_TAG_OP_DESCHED 3
41 #define POW_TAG_OP_ADDWQ 4
42 #define POW_TAG_OP_UPD_WQP_GRP 5
43 #define POW_TAG_OP_CLR_NSCHED 7
44 #define POW_TAG_OP_NOP 15
45
46 #define POW_WAIT 1
47 #define POW_NO_WAIT 0
48
49 #define POW_WORKQ_IRQ(group) (group)
50
51 /* XXX */
52 struct cn30xxpow_softc {
53 struct device sc_dev;
54 bus_space_tag_t sc_regt;
55 bus_space_handle_t sc_regh;
56 int sc_port;
57 int sc_int_pc_base;
58 };
59
60 /* XXX */
61 struct cn30xxpow_attach_args {
62 int aa_port;
63 bus_space_tag_t aa_regt;
64 };
65
66 void cn30xxpow_config(struct cn30xxpow_softc *, int);
67
68 #define _POW_RD8(sc, off) \
69 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
70 #define _POW_WR8(sc, off, v) \
71 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
72 #define _POW_GROUP_RD8(sc, pi, off) \
73 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, \
74 (off) + sizeof(uint64_t) * (pi)->pi_group)
75 #define _POW_GROUP_WR8(sc, pi, off, v) \
76 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, \
77 (off) + sizeof(uint64_t) * (pi)->pi_group, (v))
78
79 extern struct cn30xxpow_softc cn30xxpow_softc;
80
81 /* -------------------------------------------------------------------------- */
82
83 /* 5.11.1 Load Operations */
84
85 /* GET_WORK Loads */
86
87 static inline uint64_t
cn30xxpow_ops_get_work_load(int wait)88 cn30xxpow_ops_get_work_load(
89 int wait) /* 0-1 */
90 {
91 uint64_t ptr =
92 POW_OPERATION_BASE_IO_BIT |
93 __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
94 __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x00) |
95 __BITS64_SET(POW_GET_WORK_LOAD_WAIT, wait);
96
97 return octeon_xkphys_read_8(ptr);
98 }
99
100 /* 5.11.2 IOBDMA Operations */
101
102 /*
103 * XXXSEIL
104 * ``subdid'' values are inverted between ``get_work_addr'' and ``null_read_id''
105 * in CN30XX-HM-1.0 and CN31XX-HM-1.01. (Corrected in CN50XX-HM-0.99A.)
106 *
107 * XXXSEIL
108 * The ``scraddr'' part is index in 8 byte words, not address. This is not
109 * documented...
110 */
111
112 /* GET_WORK IOBDMAs */
113
114 static inline void
cn30xxpow_ops_get_work_iobdma(int scraddr,int wait)115 cn30xxpow_ops_get_work_iobdma(
116 int scraddr, /* 0-2047 */
117 int wait) /* 0-1 */
118 {
119 /* ``scraddr'' part is index in 64-bit words, not address */
120 const int scrindex = scraddr / sizeof(uint64_t);
121
122 uint64_t args =
123 __BITS64_SET(POW_IOBDMA_GET_WORK_WAIT, wait);
124 uint64_t value =
125 __BITS64_SET(POW_IOBDMA_BASE_SCRADDR, scrindex) |
126 __BITS64_SET(POW_IOBDMA_BASE_LEN, 0x01) |
127 __BITS64_SET(POW_IOBDMA_BASE_MAJOR_DID, 0x0c) |
128 __BITS64_SET(POW_IOBDMA_BASE_SUB_DID, 0x00) |
129 __BITS64_SET(POW_IOBDMA_BASE_39_0, args);
130
131 octeon_iobdma_write_8(value);
132 }
133
134 /* NULL_RD IOBDMAs */
135
136 static inline void
cn30xxpow_ops_null_rd_iobdma(int scraddr)137 cn30xxpow_ops_null_rd_iobdma(
138 int scraddr) /* 0-2047 */
139 {
140 /* ``scraddr'' part is index in 64-bit words, not address */
141 const int scrindex = scraddr / sizeof(uint64_t);
142
143 uint64_t value =
144 __BITS64_SET(POW_IOBDMA_BASE_SCRADDR, scrindex) |
145 __BITS64_SET(POW_IOBDMA_BASE_LEN, 0x01) |
146 __BITS64_SET(POW_IOBDMA_BASE_MAJOR_DID, 0x0c) |
147 __BITS64_SET(POW_IOBDMA_BASE_SUB_DID, 0x04) |
148 __BITS64_SET(POW_IOBDMA_BASE_39_0, 0);
149
150 octeon_iobdma_write_8(value);
151 }
152
153 /* 5.11.3 Store Operations */
154
155 static inline void
cn30xxpow_store(int subdid,uint64_t addr,int no_sched,int index,int op,int qos,int grp,int type,uint32_t tag)156 cn30xxpow_store(
157 int subdid, /* 0, 1, 3 */
158 uint64_t addr, /* 0-0x0000.000f.ffff.ffff */
159 int no_sched, /* 0, 1 */
160 int index, /* 0-8191 */
161 int op, /* 0-15 */
162 int qos, /* 0-7 */
163 int grp, /* 0-7 */
164 int type, /* 0-7 */
165 uint32_t tag) /* 0-0xffff.ffff */
166 {
167 /* Physical Address to Store to POW */
168 uint64_t ptr =
169 POW_OPERATION_BASE_IO_BIT |
170 __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
171 __BITS64_SET(POW_OPERATION_BASE_SUB_DID, subdid) |
172 __BITS64_SET(POW_PHY_ADDR_STORE_ADDR, addr);
173
174 /* Store Data on Store to POW */
175 uint64_t args =
176 __BITS64_SET(POW_STORE_DATA_NO_SCHED, no_sched) |
177 __BITS64_SET(POW_STORE_DATA_INDEX, index) |
178 __BITS64_SET(POW_STORE_DATA_OP, op) |
179 __BITS64_SET(POW_STORE_DATA_QOS, qos) |
180 __BITS64_SET(POW_STORE_DATA_GRP, grp) |
181 __BITS64_SET(POW_STORE_DATA_TYPE, type) |
182 __BITS64_SET(POW_STORE_DATA_TAG, tag);
183
184 octeon_xkphys_write_8(ptr, args);
185 }
186
187 /* SWTAG */
188
189 static inline void
cn30xxpow_ops_swtag(int type,uint32_t tag)190 cn30xxpow_ops_swtag(int type, uint32_t tag)
191 {
192 cn30xxpow_store(
193 1, /* subdid == 1 */
194 0, /* addr (not used for SWTAG) */
195 0, /* no_sched (not used for SWTAG) */
196 0, /* index (not used for SWTAG) */
197 POW_TAG_OP_SWTAG, /* op == SWTAG */
198 0, /* qos (not used for SWTAG) */
199 0, /* grp (not used for SWTAG) */
200 type,
201 tag);
202 /* switch to NULL completes immediately */
203 }
204
205 /* SWTAG_FULL */
206
207 static inline void
cn30xxpow_ops_swtag_full(paddr_t addr,int grp,int type,uint32_t tag)208 cn30xxpow_ops_swtag_full(paddr_t addr, int grp, int type, uint32_t tag)
209 {
210 cn30xxpow_store(
211 0, /* subdid == 0 */
212 addr,
213 0, /* no_sched (not used for SWTAG_FULL) */
214 0, /* index (not used for SWTAG_FULL) */
215 POW_TAG_OP_SWTAG_FULL, /* op == SWTAG_FULL */
216 0, /* qos (not used for SWTAG_FULL) */
217 grp,
218 type,
219 tag);
220 }
221
222 /* SWTAG_DESCHED */
223
224 static inline void
cn30xxpow_ops_swtag_desched(int no_sched,int grp,int type,uint32_t tag)225 cn30xxpow_ops_swtag_desched(int no_sched, int grp, int type, uint32_t tag)
226 {
227 cn30xxpow_store(
228 3, /* subdid == 3 */
229 0, /* addr (not used for SWTAG_DESCHED) */
230 no_sched,
231 0, /* index (not used for SWTAG_DESCHED) */
232 POW_TAG_OP_SWTAG_DESCHED, /* op == SWTAG_DESCHED */
233 0, /* qos (not used for SWTAG_DESCHED) */
234 grp,
235 type,
236 tag);
237 }
238
239 /* DESCHED */
240
241 static inline void
cn30xxpow_ops_desched(int no_sched)242 cn30xxpow_ops_desched(int no_sched)
243 {
244 cn30xxpow_store(
245 3, /* subdid == 3 */
246 0, /* addr (not used for DESCHED) */
247 no_sched,
248 0, /* index (not used for DESCHED) */
249 POW_TAG_OP_DESCHED, /* op == DESCHED */
250 0, /* qos (not used for DESCHED) */
251 0, /* grp (not used for DESCHED) */
252 0, /* type (not used for DESCHED) */
253 0); /* tag (not used for DESCHED) */
254 }
255
256 /* ADDWQ */
257
258 static inline void
cn30xxpow_ops_addwq(paddr_t addr,int qos,int grp,int type,uint32_t tag)259 cn30xxpow_ops_addwq(paddr_t addr, int qos, int grp, int type, uint32_t tag)
260 {
261 cn30xxpow_store(
262 1, /* subdid == 1 */
263 addr,
264 0, /* no_sched (not used for ADDWQ) */
265 0, /* index (not used for ADDWQ) */
266 POW_TAG_OP_ADDWQ, /* op == ADDWQ */
267 qos,
268 grp,
269 type,
270 tag);
271 }
272
273 /* UPD_WQP_GRP */
274
275 static inline void
cn30xxpow_ops_upd_wqp_grp(paddr_t addr,int grp)276 cn30xxpow_ops_upd_wqp_grp(paddr_t addr, int grp)
277 {
278 cn30xxpow_store(
279 1, /* subdid == 1 */
280 addr,
281 0, /* no_sched (not used for UPD_WQP_GRP) */
282 0, /* index (not used for UPD_WQP_GRP) */
283 POW_TAG_OP_UPD_WQP_GRP, /* op == UPD_WQP_GRP */
284 0, /* qos (not used for UPD_WQP_GRP) */
285 grp,
286 0, /* type (not used for UPD_WQP_GRP) */
287 0); /* tag (not used for UPD_WQP_GRP) */
288 }
289
290 /* CLR_NSCHED */
291
292 static inline void
cn30xxpow_ops_clr_nsched(paddr_t addr,int index)293 cn30xxpow_ops_clr_nsched(paddr_t addr, int index)
294 {
295 cn30xxpow_store(
296 1, /* subdid == 1 */
297 addr,
298 0, /* no_sched (not used for CLR_NSCHED) */
299 index,
300 POW_TAG_OP_CLR_NSCHED, /* op == CLR_NSCHED */
301 0, /* qos (not used for CLR_NSCHED) */
302 0, /* grp (not used for CLR_NSCHED) */
303 0, /* type (not used for CLR_NSCHED) */
304 0); /* tag (not used for CLR_NSCHED) */
305 }
306
307 /* NOP */
308
309 static inline void
cn30xxpow_ops_nop(void)310 cn30xxpow_ops_nop(void)
311 {
312 cn30xxpow_store(
313 1, /* subdid == 1 */
314 0, /* addr (not used for NOP) */
315 0, /* no_sched (not used for NOP) */
316 0, /* index (not used for NOP) */
317 POW_TAG_OP_NOP, /* op == NOP */
318 0, /* qos (not used for NOP) */
319 0, /* grp (not used for NOP) */
320 0, /* type (not used for NOP) */
321 0); /* tag (not used for NOP) */
322 }
323
324 /*
325 * Check if there is a pending POW tag switch.
326 */
327 static inline int
cn30xxpow_tag_sw_pending(void)328 cn30xxpow_tag_sw_pending(void)
329 {
330 int result;
331
332 /*
333 * "RDHWR rt, $30" returns:
334 * 0 => pending bit is set
335 * 1 => pending bit is clear
336 */
337
338 __asm volatile (
339 " .set push\n"
340 " .set noreorder\n"
341 " .set arch=mips64r2\n"
342 " rdhwr %0, $30\n"
343 " .set pop\n"
344 : "=r" (result));
345 return result == 0;
346 }
347
348 /*
349 * Wait until there is no pending POW tag switch.
350 */
351 static inline void
cn30xxpow_tag_sw_wait(void)352 cn30xxpow_tag_sw_wait(void)
353 {
354 while (cn30xxpow_tag_sw_pending())
355 continue;
356 }
357
358 /* -------------------------------------------------------------------------- */
359
360 /*
361 * global functions
362 */
363 void cn30xxpow_work_request_async(uint64_t, uint64_t);
364 uint64_t *cn30xxpow_work_response_async(uint64_t);
365 void cn30xxpow_ops_swtag(int, uint32_t);
366
367 static inline void
cn30xxpow_config_int_pc(struct cn30xxpow_softc * sc,int unit)368 cn30xxpow_config_int_pc(struct cn30xxpow_softc *sc, int unit)
369 {
370 uint64_t wq_int_pc;
371 uint64_t pc_thr;
372 static uint64_t cpu_clock_hz;
373
374 if (cpu_clock_hz == 0)
375 cpu_clock_hz = curcpu()->ci_hw.clock;
376
377 #if 0
378 /* from Documents */
379 /*
380 * => counter value is POW_WQ_INT_PC[PC_THR] * 256 + 255
381 * => counter is decremented every CPU clock
382 * => counter is reset when interrupt occurs
383 *
384 * cpu_clock_per_sec
385 * = cpu_clock_mhz * 1000000
386 * cpu_clock_per_msec
387 * = cpu_clock_mhz * 1000
388 * cpu_clock_per_usec
389 * = cpu_clock_mhz
390 *
391 * pc_thr_for_1sec * 256 + 255
392 * = cpu_clock_mhz * 1000000
393 * pc_thr_for_1sec
394 * = ((cpu_clock_mhz * 1000000) - 255) / 256
395 *
396 * pc_thr_for_1msec * 256 + 255
397 * = cpu_clock_mhz * 1000
398 * pc_thr_for_1msec
399 * = ((cpu_clock_mhz * 1000) - 255) / 256
400 *
401 * pc_thr_for_1usec * 256 + 255
402 * = cpu_clock_mhz
403 * pc_thr_for_1usec
404 * = (cpu_clock_mhz - 255) / 256
405 */
406 pc_thr = (((cpu_clock_hz / 1000000) * (unit)) - 255) / 256;
407 #else
408 pc_thr = (cpu_clock_hz) / (unit * 16 * 256);
409 #endif
410 wq_int_pc = pc_thr << POW_WQ_INT_PC_PC_THR_SHIFT;
411 _POW_WR8(sc, POW_WQ_INT_PC_OFFSET, wq_int_pc);
412 }
413
414 static inline void
cn30xxpow_config_int_pc_rate(struct cn30xxpow_softc * sc,int rate)415 cn30xxpow_config_int_pc_rate(struct cn30xxpow_softc *sc, int rate)
416 {
417 cn30xxpow_config_int_pc(sc, sc->sc_int_pc_base / rate);
418 }
419
420 #endif /* _CN30XXPOWVAR_H_ */
421