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