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_MMIO_H__
33#define __NLM_HAL_MMIO_H__
34
35/*
36 * This file contains platform specific memory mapped IO implementation
37 * and will provide a way to read 32/64 bit memory mapped registers in
38 * all ABIs
39 */
40
41/*
42 * For o32 compilation, we have to disable interrupts and enable KX bit to
43 * access 64 bit addresses or data.
44 *
45 * We need to disable interrupts because we save just the lower 32 bits of
46 * registers in  interrupt handling. So if we get hit by an interrupt while
47 * using the upper 32 bits of a register, we lose.
48 */
49static inline uint32_t nlm_save_flags_kx(void)
50{
51	uint32_t sr = mips_rd_status();
52
53	mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_KX);
54	return (sr);
55}
56
57static inline uint32_t nlm_save_flags_cop2(void)
58{
59	uint32_t sr = mips_rd_status();
60
61	mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_COP_2_BIT);
62	return (sr);
63}
64
65static inline void nlm_restore_flags(uint32_t sr)
66{
67	mips_wr_status(sr);
68}
69
70static inline uint32_t
71nlm_load_word(uint64_t addr)
72{
73	volatile uint32_t *p = (volatile uint32_t *)(long)addr;
74
75	return *p;
76}
77
78static inline void
79nlm_store_word(uint64_t addr, uint32_t val)
80{
81	volatile uint32_t *p = (volatile uint32_t *)(long)addr;
82
83	*p = val;
84}
85
86#if defined(__mips_n64) || defined(__mips_n32)
87static inline uint64_t
88nlm_load_dword(volatile uint64_t addr)
89{
90	volatile uint64_t *p = (volatile uint64_t *)(long)addr;
91
92	return *p;
93}
94
95static inline void
96nlm_store_dword(volatile uint64_t addr, uint64_t val)
97{
98	volatile uint64_t *p = (volatile uint64_t *)(long)addr;
99
100	*p = val;
101}
102
103#else /* o32 */
104static inline uint64_t
105nlm_load_dword(uint64_t addr)
106{
107	volatile uint64_t *p = (volatile uint64_t *)(long)addr;
108	uint32_t valhi, vallo, sr;
109
110	sr = nlm_save_flags_kx();
111	__asm__ __volatile__(
112		".set	push\n\t"
113		".set	mips64\n\t"
114		"ld	$8, 0(%2)\n\t"
115		"dsra32	%0, $8, 0\n\t"
116		"sll	%1, $8, 0\n\t"
117		".set	pop\n"
118		: "=r"(valhi), "=r"(vallo)
119		: "r"(p)
120		: "$8");
121	nlm_restore_flags(sr);
122
123	return ((uint64_t)valhi << 32) | vallo;
124}
125
126static inline void
127nlm_store_dword(uint64_t addr, uint64_t val)
128{
129	volatile uint64_t *p = (volatile uint64_t *)(long)addr;
130	uint32_t valhi, vallo, sr;
131
132	valhi = val >> 32;
133	vallo = val & 0xffffffff;
134
135	sr = nlm_save_flags_kx();
136	__asm__ __volatile__(
137		".set	push\n\t"
138		".set	mips64\n\t"
139		"dsll32	$8, %1, 0\n\t"
140		"dsll32	$9, %2, 0\n\t"  /* get rid of the */
141		"dsrl32	$9, $9, 0\n\t"  /* sign extend */
142		"or	$9, $9, $8\n\t"
143		"sd	$9, 0(%0)\n\t"
144		".set	pop\n"
145		: : "r"(p), "r"(valhi), "r"(vallo)
146		: "$8", "$9", "memory");
147	nlm_restore_flags(sr);
148}
149#endif
150
151#if defined(__mips_n64)
152static inline uint64_t
153nlm_load_word_daddr(uint64_t addr)
154{
155	volatile uint32_t *p = (volatile uint32_t *)(long)addr;
156
157	return *p;
158}
159
160static inline void
161nlm_store_word_daddr(uint64_t addr, uint32_t val)
162{
163	volatile uint32_t *p = (volatile uint32_t *)(long)addr;
164
165	*p = val;
166}
167
168static inline uint64_t
169nlm_load_dword_daddr(uint64_t addr)
170{
171	volatile uint64_t *p = (volatile uint64_t *)(long)addr;
172
173	return *p;
174}
175
176static inline void
177nlm_store_dword_daddr(uint64_t addr, uint64_t val)
178{
179	volatile uint64_t *p = (volatile uint64_t *)(long)addr;
180
181	*p = val;
182}
183
184#elif defined(__mips_n32)
185
186static inline uint64_t
187nlm_load_word_daddr(uint64_t addr)
188{
189	uint32_t val;
190
191	__asm__ __volatile__(
192		".set	push\n\t"
193		".set	mips64\n\t"
194		"lw		%0, 0(%1)\n\t"
195		".set	pop\n"
196		: "=r"(val)
197		: "r"(addr));
198
199	return val;
200}
201
202static inline void
203nlm_store_word_daddr(uint64_t addr, uint32_t val)
204{
205	__asm__ __volatile__(
206		".set	push\n\t"
207		".set	mips64\n\t"
208		"sw		%0, 0(%1)\n\t"
209		".set	pop\n"
210		: : "r"(val), "r"(addr)
211		: "memory");
212}
213
214static inline uint64_t
215nlm_load_dword_daddr(uint64_t addr)
216{
217	uint64_t val;
218
219	__asm__ __volatile__(
220		".set	push\n\t"
221		".set	mips64\n\t"
222		"ld		%0, 0(%1)\n\t"
223		".set	pop\n"
224		: "=r"(val)
225		: "r"(addr));
226	return val;
227}
228
229static inline void
230nlm_store_dword_daddr(uint64_t addr, uint64_t val)
231{
232	__asm__ __volatile__(
233		".set	push\n\t"
234		".set	mips64\n\t"
235		"sd		%0, 0(%1)\n\t"
236		".set	pop\n"
237		: : "r"(val), "r"(addr)
238		: "memory");
239}
240
241#else /* o32 */
242static inline uint64_t
243nlm_load_word_daddr(uint64_t addr)
244{
245	uint32_t val, addrhi, addrlo, sr;
246
247	addrhi = addr >> 32;
248	addrlo = addr & 0xffffffff;
249
250	sr = nlm_save_flags_kx();
251	__asm__ __volatile__(
252		".set	push\n\t"
253		".set	mips64\n\t"
254		"dsll32	$8, %1, 0\n\t"
255		"dsll32	$9, %2, 0\n\t"
256		"dsrl32	$9, $9, 0\n\t"
257		"or	$9, $9, $8\n\t"
258		"lw	%0, 0($9)\n\t"
259		".set	pop\n"
260		:	"=r"(val)
261		:	"r"(addrhi), "r"(addrlo)
262		:	"$8", "$9");
263	nlm_restore_flags(sr);
264
265	return val;
266
267}
268
269static inline void
270nlm_store_word_daddr(uint64_t addr, uint32_t val)
271{
272	uint32_t addrhi, addrlo, sr;
273
274	addrhi = addr >> 32;
275	addrlo = addr & 0xffffffff;
276
277	sr = nlm_save_flags_kx();
278	__asm__ __volatile__(
279		".set	push\n\t"
280		".set	mips64\n\t"
281		"dsll32	$8, %1, 0\n\t"
282		"dsll32	$9, %2, 0\n\t"
283		"dsrl32	$9, $9, 0\n\t"
284		"or	$9, $9, $8\n\t"
285		"sw	%0, 0($9)\n\t"
286		".set	pop\n"
287		: : "r"(val), "r"(addrhi), "r"(addrlo)
288		:	"$8", "$9", "memory");
289	nlm_restore_flags(sr);
290}
291
292static inline uint64_t
293nlm_load_dword_daddr(uint64_t addr)
294{
295	uint32_t addrh, addrl, sr;
296	uint32_t valh, vall;
297
298	addrh = addr >> 32;
299	addrl = addr & 0xffffffff;
300
301	sr = nlm_save_flags_kx();
302	__asm__ __volatile__(
303		".set	push\n\t"
304		".set	mips64\n\t"
305		"dsll32	$8, %2, 0\n\t"
306		"dsll32	$9, %3, 0\n\t"
307		"dsrl32	$9, $9, 0\n\t"
308		"or	$9, $9, $8\n\t"
309		"ld	$8, 0($9)\n\t"
310		"dsra32	%0, $8, 0\n\t"
311		"sll	%1, $8, 0\n\t"
312		".set	pop\n"
313		: "=r"(valh), "=r"(vall)
314		: "r"(addrh), "r"(addrl)
315		: "$8", "$9");
316	nlm_restore_flags(sr);
317
318	return ((uint64_t)valh << 32) | vall;
319}
320
321static inline void
322nlm_store_dword_daddr(uint64_t addr, uint64_t val)
323{
324	uint32_t addrh, addrl, sr;
325	uint32_t valh, vall;
326
327	addrh = addr >> 32;
328	addrl = addr & 0xffffffff;
329	valh = val >> 32;
330	vall = val & 0xffffffff;
331
332	sr = nlm_save_flags_kx();
333	__asm__ __volatile__(
334		".set	push\n\t"
335		".set	mips64\n\t"
336		"dsll32	$8, %2, 0\n\t"
337		"dsll32	$9, %3, 0\n\t"
338		"dsrl32	$9, $9, 0\n\t"
339		"or	$9, $9, $8\n\t"
340		"dsll32	$8, %0, 0\n\t"
341		"dsll32	$10, %1, 0\n\t"
342		"dsrl32	$10, $10, 0\n\t"
343		"or	$8, $8, $10\n\t"
344		"sd	$8, 0($9)\n\t"
345		".set	pop\n"
346		: :	"r"(valh), "r"(vall), "r"(addrh), "r"(addrl)
347		:	"$8", "$9", "memory");
348	nlm_restore_flags(sr);
349}
350#endif /* __mips_n64 */
351
352static inline uint32_t
353nlm_read_reg(uint64_t base, uint32_t reg)
354{
355	volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg;
356
357	return *addr;
358}
359
360static inline void
361nlm_write_reg(uint64_t base, uint32_t reg, uint32_t val)
362{
363	volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg;
364
365	*addr = val;
366}
367
368static inline uint64_t
369nlm_read_reg64(uint64_t base, uint32_t reg)
370{
371	uint64_t addr = base + (reg >> 1) * sizeof(uint64_t);
372
373	return nlm_load_dword(addr);
374}
375
376static inline void
377nlm_write_reg64(uint64_t base, uint32_t reg, uint64_t val)
378{
379	uint64_t addr = base + (reg >> 1) * sizeof(uint64_t);
380
381	return nlm_store_dword(addr, val);
382}
383
384/*
385 * Routines to store 32/64 bit values to 64 bit addresses,
386 * used when going thru XKPHYS to access registers
387 */
388static inline uint32_t
389nlm_read_reg_xkphys(uint64_t base, uint32_t reg)
390{
391	uint64_t addr = base + reg * sizeof(uint32_t);
392
393	return nlm_load_word_daddr(addr);
394}
395
396static inline void
397nlm_write_reg_xkphys(uint64_t base, uint32_t reg, uint32_t val)
398{
399	uint64_t addr = base + reg * sizeof(uint32_t);
400	return nlm_store_word_daddr(addr, val);
401}
402
403static inline uint64_t
404nlm_read_reg64_xkphys(uint64_t base, uint32_t reg)
405{
406	uint64_t addr = base + (reg >> 1) * sizeof(uint64_t);
407
408	return nlm_load_dword_daddr(addr);
409}
410
411static inline void
412nlm_write_reg64_xkphys(uint64_t base, uint32_t reg, uint64_t val)
413{
414	uint64_t addr = base + (reg >> 1) * sizeof(uint64_t);
415
416	return nlm_store_dword_daddr(addr, val);
417}
418
419/* Location where IO base is mapped */
420extern uint64_t xlp_io_base;
421
422static inline uint64_t
423nlm_pcicfg_base(uint32_t devoffset)
424{
425	return xlp_io_base + devoffset;
426}
427
428static inline uint64_t
429nlm_xkphys_map_pcibar0(uint64_t pcibase)
430{
431	uint64_t paddr;
432
433	paddr = nlm_read_reg(pcibase, 0x4) & ~0xfu;
434	return (uint64_t)0x9000000000000000 | paddr;
435}
436
437#endif
438