1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved.
7 */
8
9#include <linux/interrupt.h>
10#include <linux/types.h>
11#include <asm/sn/io.h>
12#include <asm/sn/pcibr_provider.h>
13#include <asm/sn/pcibus_provider_defs.h>
14#include <asm/sn/pcidev.h>
15#include <asm/sn/pic.h>
16#include <asm/sn/tiocp.h>
17
18union br_ptr {
19	struct tiocp tio;
20	struct pic pic;
21};
22
23/*
24 * Control Register Access -- Read/Write                            0000_0020
25 */
26void pcireg_control_bit_clr(struct pcibus_info *pcibus_info, u64 bits)
27{
28	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
29
30	if (pcibus_info) {
31		switch (pcibus_info->pbi_bridge_type) {
32		case PCIBR_BRIDGETYPE_TIOCP:
33			__sn_clrq_relaxed(&ptr->tio.cp_control, bits);
34			break;
35		case PCIBR_BRIDGETYPE_PIC:
36			__sn_clrq_relaxed(&ptr->pic.p_wid_control, bits);
37			break;
38		default:
39			panic
40			    ("pcireg_control_bit_clr: unknown bridgetype bridge 0x%p",
41			     ptr);
42		}
43	}
44}
45
46void pcireg_control_bit_set(struct pcibus_info *pcibus_info, u64 bits)
47{
48	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
49
50	if (pcibus_info) {
51		switch (pcibus_info->pbi_bridge_type) {
52		case PCIBR_BRIDGETYPE_TIOCP:
53			__sn_setq_relaxed(&ptr->tio.cp_control, bits);
54			break;
55		case PCIBR_BRIDGETYPE_PIC:
56			__sn_setq_relaxed(&ptr->pic.p_wid_control, bits);
57			break;
58		default:
59			panic
60			    ("pcireg_control_bit_set: unknown bridgetype bridge 0x%p",
61			     ptr);
62		}
63	}
64}
65
66/*
67 * PCI/PCIX Target Flush Register Access -- Read Only		    0000_0050
68 */
69u64 pcireg_tflush_get(struct pcibus_info *pcibus_info)
70{
71	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
72	u64 ret = 0;
73
74	if (pcibus_info) {
75		switch (pcibus_info->pbi_bridge_type) {
76		case PCIBR_BRIDGETYPE_TIOCP:
77			ret = __sn_readq_relaxed(&ptr->tio.cp_tflush);
78			break;
79		case PCIBR_BRIDGETYPE_PIC:
80			ret = __sn_readq_relaxed(&ptr->pic.p_wid_tflush);
81			break;
82		default:
83			panic
84			    ("pcireg_tflush_get: unknown bridgetype bridge 0x%p",
85			     ptr);
86		}
87	}
88
89	/* Read of the Target Flush should always return zero */
90	if (ret != 0)
91		panic("pcireg_tflush_get:Target Flush failed\n");
92
93	return ret;
94}
95
96/*
97 * Interrupt Status Register Access -- Read Only		    0000_0100
98 */
99u64 pcireg_intr_status_get(struct pcibus_info * pcibus_info)
100{
101	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
102	u64 ret = 0;
103
104	if (pcibus_info) {
105		switch (pcibus_info->pbi_bridge_type) {
106		case PCIBR_BRIDGETYPE_TIOCP:
107			ret = __sn_readq_relaxed(&ptr->tio.cp_int_status);
108			break;
109		case PCIBR_BRIDGETYPE_PIC:
110			ret = __sn_readq_relaxed(&ptr->pic.p_int_status);
111			break;
112		default:
113			panic
114			    ("pcireg_intr_status_get: unknown bridgetype bridge 0x%p",
115			     ptr);
116		}
117	}
118	return ret;
119}
120
121/*
122 * Interrupt Enable Register Access -- Read/Write                   0000_0108
123 */
124void pcireg_intr_enable_bit_clr(struct pcibus_info *pcibus_info, u64 bits)
125{
126	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
127
128	if (pcibus_info) {
129		switch (pcibus_info->pbi_bridge_type) {
130		case PCIBR_BRIDGETYPE_TIOCP:
131			__sn_clrq_relaxed(&ptr->tio.cp_int_enable, bits);
132			break;
133		case PCIBR_BRIDGETYPE_PIC:
134			__sn_clrq_relaxed(&ptr->pic.p_int_enable, bits);
135			break;
136		default:
137			panic
138			    ("pcireg_intr_enable_bit_clr: unknown bridgetype bridge 0x%p",
139			     ptr);
140		}
141	}
142}
143
144void pcireg_intr_enable_bit_set(struct pcibus_info *pcibus_info, u64 bits)
145{
146	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
147
148	if (pcibus_info) {
149		switch (pcibus_info->pbi_bridge_type) {
150		case PCIBR_BRIDGETYPE_TIOCP:
151			__sn_setq_relaxed(&ptr->tio.cp_int_enable, bits);
152			break;
153		case PCIBR_BRIDGETYPE_PIC:
154			__sn_setq_relaxed(&ptr->pic.p_int_enable, bits);
155			break;
156		default:
157			panic
158			    ("pcireg_intr_enable_bit_set: unknown bridgetype bridge 0x%p",
159			     ptr);
160		}
161	}
162}
163
164/*
165 * Intr Host Address Register (int_addr) -- Read/Write  0000_0130 - 0000_0168
166 */
167void pcireg_intr_addr_addr_set(struct pcibus_info *pcibus_info, int int_n,
168			       u64 addr)
169{
170	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
171
172	if (pcibus_info) {
173		switch (pcibus_info->pbi_bridge_type) {
174		case PCIBR_BRIDGETYPE_TIOCP:
175			__sn_clrq_relaxed(&ptr->tio.cp_int_addr[int_n],
176			    TIOCP_HOST_INTR_ADDR);
177			__sn_setq_relaxed(&ptr->tio.cp_int_addr[int_n],
178			    (addr & TIOCP_HOST_INTR_ADDR));
179			break;
180		case PCIBR_BRIDGETYPE_PIC:
181			__sn_clrq_relaxed(&ptr->pic.p_int_addr[int_n],
182			    PIC_HOST_INTR_ADDR);
183			__sn_setq_relaxed(&ptr->pic.p_int_addr[int_n],
184			    (addr & PIC_HOST_INTR_ADDR));
185			break;
186		default:
187			panic
188			    ("pcireg_intr_addr_addr_get: unknown bridgetype bridge 0x%p",
189			     ptr);
190		}
191	}
192}
193
194/*
195 * Force Interrupt Register Access -- Write Only	0000_01C0 - 0000_01F8
196 */
197void pcireg_force_intr_set(struct pcibus_info *pcibus_info, int int_n)
198{
199	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
200
201	if (pcibus_info) {
202		switch (pcibus_info->pbi_bridge_type) {
203		case PCIBR_BRIDGETYPE_TIOCP:
204			writeq(1, &ptr->tio.cp_force_pin[int_n]);
205			break;
206		case PCIBR_BRIDGETYPE_PIC:
207			writeq(1, &ptr->pic.p_force_pin[int_n]);
208			break;
209		default:
210			panic
211			    ("pcireg_force_intr_set: unknown bridgetype bridge 0x%p",
212			     ptr);
213		}
214	}
215}
216
217/*
218 * Device(x) Write Buffer Flush Reg Access -- Read Only 0000_0240 - 0000_0258
219 */
220u64 pcireg_wrb_flush_get(struct pcibus_info *pcibus_info, int device)
221{
222	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
223	u64 ret = 0;
224
225	if (pcibus_info) {
226		switch (pcibus_info->pbi_bridge_type) {
227		case PCIBR_BRIDGETYPE_TIOCP:
228			ret =
229			    __sn_readq_relaxed(&ptr->tio.cp_wr_req_buf[device]);
230			break;
231		case PCIBR_BRIDGETYPE_PIC:
232			ret =
233			    __sn_readq_relaxed(&ptr->pic.p_wr_req_buf[device]);
234			break;
235		default:
236		      panic("pcireg_wrb_flush_get: unknown bridgetype bridge 0x%p", ptr);
237		}
238
239	}
240	/* Read of the Write Buffer Flush should always return zero */
241	return ret;
242}
243
244void pcireg_int_ate_set(struct pcibus_info *pcibus_info, int ate_index,
245			u64 val)
246{
247	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
248
249	if (pcibus_info) {
250		switch (pcibus_info->pbi_bridge_type) {
251		case PCIBR_BRIDGETYPE_TIOCP:
252			writeq(val, &ptr->tio.cp_int_ate_ram[ate_index]);
253			break;
254		case PCIBR_BRIDGETYPE_PIC:
255			writeq(val, &ptr->pic.p_int_ate_ram[ate_index]);
256			break;
257		default:
258			panic
259			    ("pcireg_int_ate_set: unknown bridgetype bridge 0x%p",
260			     ptr);
261		}
262	}
263}
264
265u64 __iomem *pcireg_int_ate_addr(struct pcibus_info *pcibus_info, int ate_index)
266{
267	union br_ptr __iomem *ptr = (union br_ptr __iomem *)pcibus_info->pbi_buscommon.bs_base;
268	u64 __iomem *ret = NULL;
269
270	if (pcibus_info) {
271		switch (pcibus_info->pbi_bridge_type) {
272		case PCIBR_BRIDGETYPE_TIOCP:
273			ret = &ptr->tio.cp_int_ate_ram[ate_index];
274			break;
275		case PCIBR_BRIDGETYPE_PIC:
276			ret = &ptr->pic.p_int_ate_ram[ate_index];
277			break;
278		default:
279			panic
280			    ("pcireg_int_ate_addr: unknown bridgetype bridge 0x%p",
281			     ptr);
282		}
283	}
284	return ret;
285}
286