1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * NETLOGIC_BSD
31 * $FreeBSD$
32 */
33
34#ifndef __NLM_HAL_COP2_H__
35#define	__NLM_HAL_COP2_H__
36
37#define	COP2_TX_BUF		0
38#define	COP2_RX_BUF		1
39#define	COP2_TXMSGSTATUS	2
40#define	COP2_RXMSGSTATUS	3
41#define	COP2_MSGSTATUS1		4
42#define	COP2_MSGCONFIG		5
43#define	COP2_MSGERROR		6
44
45#define	CROSSTHR_POPQ_EN	0x01
46#define	VC0_POPQ_EN		0x02
47#define	VC1_POPQ_EN		0x04
48#define	VC2_POPQ_EN		0x08
49#define	VC3_POPQ_EN		0x10
50#define	ALL_VC_POPQ_EN		0x1E
51#define	ALL_VC_CT_POPQ_EN	0x1F
52
53struct nlm_fmn_msg {
54	uint64_t msg[4];
55};
56
57#define	NLM_DEFINE_COP2_ACCESSORS32(name, reg, sel)		\
58static inline uint32_t nlm_read_c2_##name(void)			\
59{								\
60	uint32_t __rv;						\
61	__asm__ __volatile__ (					\
62	".set	push\n"						\
63	".set	noreorder\n"					\
64	".set	mips64\n"					\
65	"mfc2	%0, $%1, %2\n"					\
66	".set	pop\n"						\
67	: "=r" (__rv)						\
68	: "i" (reg), "i" (sel));				\
69	return __rv;						\
70}								\
71								\
72static inline void nlm_write_c2_##name(uint32_t val)		\
73{								\
74	__asm__ __volatile__(					\
75	".set	push\n"						\
76	".set	noreorder\n"					\
77	".set	mips64\n"					\
78	"mtc2	%0, $%1, %2\n"					\
79	".set	pop\n"						\
80	: : "r" (val), "i" (reg), "i" (sel));			\
81} struct __hack
82
83#if (__mips == 64)
84#define	NLM_DEFINE_COP2_ACCESSORS64(name, reg, sel)		\
85static inline uint64_t nlm_read_c2_##name(void)			\
86{								\
87	uint64_t __rv;						\
88	__asm__ __volatile__ (					\
89	".set	push\n"						\
90	".set	noreorder\n"					\
91	".set	mips64\n"					\
92	"dmfc2	%0, $%1, %2\n"					\
93	".set	pop\n"						\
94	: "=r" (__rv)						\
95	: "i" (reg), "i" (sel));				\
96	return __rv;						\
97}								\
98								\
99static inline void nlm_write_c2_##name(uint64_t val)		\
100{								\
101	__asm__ __volatile__ (					\
102	".set	push\n"						\
103	".set	noreorder\n"					\
104	".set	mips64\n"					\
105	"dmtc2	%0, $%1, %2\n"					\
106	".set	pop\n"						\
107	: : "r" (val), "i" (reg), "i" (sel));			\
108} struct __hack
109
110#else
111
112#define	NLM_DEFINE_COP2_ACCESSORS64(name, reg, sel)		\
113static inline uint64_t nlm_read_c2_##name(void)			\
114{								\
115	uint32_t __high, __low;					\
116	__asm__ __volatile__ (					\
117	".set	push\n"						\
118	".set	noreorder\n"					\
119	".set	mips64\n"					\
120	"dmfc2	$8, $%2, %3\n"					\
121	"dsra32	%0, $8, 0\n"					\
122	"sll	%1, $8, 0\n"					\
123	".set	pop\n"						\
124	: "=r"(__high), "=r"(__low)				\
125	: "i"(reg), "i"(sel)					\
126	: "$8");						\
127								\
128	return ((uint64_t)__high << 32) | __low;		\
129}								\
130								\
131static inline void nlm_write_c2_##name(uint64_t val)		\
132{								\
133	uint32_t __high = val >> 32;				\
134	uint32_t __low = val & 0xffffffff;			\
135	__asm__ __volatile__ (					\
136	".set	push\n"						\
137	".set	noreorder\n"					\
138	".set	mips64\n"					\
139	"dsll32	$8, %1, 0\n"					\
140	"dsll32	$9, %0, 0\n"					\
141	"dsrl32	$8, $8, 0\n"					\
142	"or	$8, $8, $9\n"					\
143	"dmtc2	$8, $%2, %3\n"					\
144	".set	pop\n"						\
145	: : "r"(__high), "r"(__low),  "i"(reg), "i"(sel)	\
146	: "$8", "$9");						\
147} struct __hack
148
149#endif
150
151NLM_DEFINE_COP2_ACCESSORS64(txbuf0, COP2_TX_BUF, 0);
152NLM_DEFINE_COP2_ACCESSORS64(txbuf1, COP2_TX_BUF, 1);
153NLM_DEFINE_COP2_ACCESSORS64(txbuf2, COP2_TX_BUF, 2);
154NLM_DEFINE_COP2_ACCESSORS64(txbuf3, COP2_TX_BUF, 3);
155
156NLM_DEFINE_COP2_ACCESSORS64(rxbuf0, COP2_RX_BUF, 0);
157NLM_DEFINE_COP2_ACCESSORS64(rxbuf1, COP2_RX_BUF, 1);
158NLM_DEFINE_COP2_ACCESSORS64(rxbuf2, COP2_RX_BUF, 2);
159NLM_DEFINE_COP2_ACCESSORS64(rxbuf3, COP2_RX_BUF, 3);
160
161NLM_DEFINE_COP2_ACCESSORS32(txmsgstatus, COP2_TXMSGSTATUS, 0);
162NLM_DEFINE_COP2_ACCESSORS32(rxmsgstatus, COP2_RXMSGSTATUS, 0);
163NLM_DEFINE_COP2_ACCESSORS32(msgstatus1, COP2_MSGSTATUS1, 0);
164NLM_DEFINE_COP2_ACCESSORS32(msgconfig, COP2_MSGCONFIG, 0);
165NLM_DEFINE_COP2_ACCESSORS32(msgerror0, COP2_MSGERROR, 0);
166NLM_DEFINE_COP2_ACCESSORS32(msgerror1, COP2_MSGERROR, 1);
167NLM_DEFINE_COP2_ACCESSORS32(msgerror2, COP2_MSGERROR, 2);
168NLM_DEFINE_COP2_ACCESSORS32(msgerror3, COP2_MSGERROR, 3);
169
170/* successful completion returns 1, else 0 */
171static inline int
172nlm_msgsend(int val)
173{
174	int result;
175	__asm__ volatile (
176		".set push\n"
177		".set noreorder\n"
178		".set mips64\n"
179		"move	$8, %1\n"
180		"sync\n"
181		"/* msgsnds	$9, $8 */\n"
182		".word	0x4a084801\n"
183		"move	%0, $9\n"
184		".set pop\n"
185		: "=r" (result)
186		: "r" (val)
187		: "$8", "$9");
188	return result;
189}
190
191static inline int
192nlm_msgld(int vc)
193{
194	int val;
195	__asm__ volatile (
196		".set push\n"
197		".set noreorder\n"
198		".set mips64\n"
199		"move	$8, %1\n"
200		"/* msgld	$9, $8 */\n"
201		".word 0x4a084802\n"
202		"move	%0, $9\n"
203		".set pop\n"
204		: "=r" (val)
205		: "r" (vc)
206		: "$8", "$9");
207	return val;
208}
209
210static inline void
211nlm_msgwait(int vc)
212{
213	__asm__ volatile (
214		".set push\n"
215		".set noreorder\n"
216		".set mips64\n"
217		"move	$8, %0\n"
218		"/* msgwait	$8 */\n"
219		".word 0x4a080003\n"
220		".set pop\n"
221		: : "r" (vc)
222		: "$8");
223}
224
225static inline int
226nlm_fmn_msgsend(int dstid, int size, int swcode, struct nlm_fmn_msg *m)
227{
228	uint32_t flags, status;
229	int rv;
230
231	size -= 1;
232	flags = nlm_save_flags_cop2();
233	switch (size) {
234	case 3:
235		nlm_write_c2_txbuf3(m->msg[3]);
236	case 2:
237		nlm_write_c2_txbuf2(m->msg[2]);
238	case 1:
239		nlm_write_c2_txbuf1(m->msg[1]);
240	case 0:
241		nlm_write_c2_txbuf0(m->msg[0]);
242	}
243
244	dstid |= ((swcode << 24) | (size << 16));
245	status = nlm_msgsend(dstid);
246	rv = !status;
247	if (rv != 0)
248		rv = nlm_read_c2_txmsgstatus();
249	nlm_restore_flags(flags);
250
251	return rv;
252}
253
254static inline int
255nlm_fmn_msgrcv(int vc, int *srcid, int *size, int *code, struct nlm_fmn_msg *m)
256{
257	uint32_t status;
258	uint32_t msg_status, flags;
259	int tmp_sz, rv;
260
261	flags = nlm_save_flags_cop2();
262	status = nlm_msgld(vc); /* will return 0, if error */
263	rv = !status;
264	if (rv == 0) {
265		msg_status = nlm_read_c2_rxmsgstatus();
266		*size = ((msg_status >> 26) & 0x3) + 1;
267		*code = (msg_status >> 18) & 0xff;
268		*srcid = (msg_status >> 4) & 0xfff;
269		tmp_sz = *size - 1;
270		switch (tmp_sz) {
271		case 3:
272			m->msg[3] = nlm_read_c2_rxbuf3();
273		case 2:
274			m->msg[2] = nlm_read_c2_rxbuf2();
275		case 1:
276			m->msg[1] = nlm_read_c2_rxbuf1();
277		case 0:
278			m->msg[0] = nlm_read_c2_rxbuf0();
279		}
280	}
281	nlm_restore_flags(flags);
282
283	return rv;
284}
285
286static inline void
287nlm_fmn_cpu_init(int int_vec, int ecc_en, int v0pe, int v1pe, int v2pe, int v3pe)
288{
289	uint32_t val = nlm_read_c2_msgconfig();
290
291	/* Note: in XLP PRM 0.8.1, the int_vec bits are un-documented
292	 * in msgconfig register of cop2.
293	 * As per chip/cpu RTL, [16:20] bits consist of int_vec.
294	 */
295	val |= (((int_vec & 0x1f) << 16) |
296		((ecc_en & 0x1) << 8) |
297		((v3pe & 0x1) << 4) |
298		((v2pe & 0x1) << 3) |
299		((v1pe & 0x1) << 2) |
300		((v0pe & 0x1) << 1));
301
302	nlm_write_c2_msgconfig(val);
303}
304#endif
305