xref: /openbsd/sys/arch/octeon/dev/cn30xxpowvar.h (revision a8b58197)
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