Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: pci_bridge.h | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | #ifndef __PCI_BRIDGE_H__ | |
24 | #define __PCI_BRIDGE_H__ | |
25 | ||
26 | ||
27 | // this file contains register definitions of some | |
28 | // registers found in type 1 header of pci/pcie bridge. | |
29 | ||
30 | ||
31 | ||
32 | #include "pci_common.h" | |
33 | ||
34 | #define swap_hword(value) \ | |
35 | ((uint32_t)(((value) & 0xff) << 8 | (value) >> 8)) | |
36 | ||
37 | #define swap_word(value) \ | |
38 | ((uint32_t)((Word)swap_hword((HWord)((value) & 0xffff)) << 16 | \ | |
39 | (Word)swap_hword((HWord)((value) >> 16)))) | |
40 | ||
41 | #define swap_lword(value) \ | |
42 | ((uint64_t)((((LWord)swap_word(LO_W(value))) << 32) | \ | |
43 | ((LWord)swap_word(HI_W(value))))) | |
44 | ||
45 | ||
46 | // some macros originally defined in pcie-pci bridge code | |
47 | ||
48 | #define GET_IO_BASE(cfg_space) ( (cfg_space->readConf(PCI_BCNF_IO_BASE_HI) << 16) | \ | |
49 | (cfg_space->readConf(PCI_BCNF_IO_BASE_LOW) >> 4 << 12)) | |
50 | #define GET_IO_LIMIT(cfg_space) ( (cfg_space->readConf(PCI_BCNF_IO_LIMIT_HI) << 16) | \ | |
51 | ((cfg_space->readConf(PCI_BCNF_IO_LIMIT_LOW) >> 4 << 12) | 0xfff)) | |
52 | #define GET_PF_MEM_BASE(cfg_space) ((uint64_t)cfg_space->readConf(PCI_BCNF_PF_BASE_HIGH) << 32) | \ | |
53 | (cfg_space->readConf(PCI_BCNF_PF_BASE_LOW) >> 4 << 20) | |
54 | #define GET_PF_MEM_LIMIT(cfg_space) ((( (uint64_t)cfg_space->readConf(PCI_BCNF_PF_LIMIT_HIGH) << 32) | \ | |
55 | (cfg_space->readConf(PCI_BCNF_PF_LIMIT_LOW) >> 4 << 20)) | 0xfffff) | |
56 | #define GET_MEM_BASE(cfg_space) cfg_space->readConf(PCI_BCNF_MEM_BASE) >> 4 << 20 | |
57 | #define GET_MEM_LIMIT(cfg_space) ((cfg_space->readConf(PCI_BCNF_MEM_LIMIT) >> 4 << 20) | 0xfffff) | |
58 | ||
59 | ||
60 | class bridgeCommandReg:public pciConfReg{ | |
61 | private: | |
62 | enum commandRegBits {IO_SPACE = 0, MEM_SPACE = 1, BUS_MASTER = 2}; | |
63 | enum space_type {IO = 0, MEM = 1, PREFETCH_MEM = 2}; | |
64 | ||
65 | bool io_enabled, mem_enabled; | |
66 | void enable_io() {io_enabled = true;} | |
67 | void enable_mem() {mem_enabled = true;} | |
68 | void disable_io() {io_enabled = false;} | |
69 | void disable_mem() {mem_enabled = false;} | |
70 | ||
71 | void check_map(space_type spt, uint64_t base, uint64_t limit, bool isMap) { | |
72 | if (base >= limit) | |
73 | return; | |
74 | if(debug_level >= 2) | |
75 | fprintf(stderr, "%s: %s %llx %llx\n", isMap ? "Map" : "Unmap", | |
76 | spt == IO ? "PCIE IO" : | |
77 | (spt == MEM ? "PCIE MEM" : "PCIE PREFETCHABLE MEM"), base, limit); | |
78 | if (spt == IO) { | |
79 | if (isMap) | |
80 | assert(((genericPcieDev*)data)->mapSpace(PCIE_IO, base, limit - base + 1)); | |
81 | else | |
82 | assert(((genericPcieDev*)data)->unmapSpace(PCIE_IO, base)); | |
83 | } else { | |
84 | if (isMap) | |
85 | assert(((genericPcieDev*)data)->mapSpace(PCIE_MEM, base, limit - base + 1)); | |
86 | else | |
87 | assert(((genericPcieDev*)data)->unmapSpace(PCIE_MEM, base)); | |
88 | } | |
89 | if (!isMap) { | |
90 | base = 0; | |
91 | limit = 0; | |
92 | } | |
93 | } | |
94 | ||
95 | void mapSpace(pcie_space spc, bool isMap){ | |
96 | uint64_t base, limit, up_base, up_limit; | |
97 | if (spc == PCIE_IO) { | |
98 | base = GET_IO_BASE(((genericPcieDev*)data)->confSpace); | |
99 | limit = GET_IO_LIMIT(((genericPcieDev*)data)->confSpace); | |
100 | check_map(IO, base, limit, isMap); | |
101 | } else { | |
102 | base = GET_PF_MEM_BASE(((genericPcieDev*)data)->confSpace); | |
103 | limit = GET_PF_MEM_LIMIT(((genericPcieDev*)data)->confSpace); | |
104 | check_map(PREFETCH_MEM, base, limit, isMap); | |
105 | ||
106 | base = GET_MEM_BASE(((genericPcieDev*)data)->confSpace); | |
107 | limit = GET_MEM_LIMIT(((genericPcieDev*)data)->confSpace); | |
108 | check_map(MEM, base, limit, isMap); | |
109 | } | |
110 | } | |
111 | ||
112 | public: | |
113 | bridgeCommandReg(const char * name, genericPcieDev * d, uint16_t write_mask,uint16_t val=0):pciConfReg(name,2,val,write_mask & 0x547, (void *)d) | |
114 | { | |
115 | if(!d){ | |
116 | printf("Bridge command reg constructor error: must provide genericPcieDev device pointer\n"); | |
117 | exit(-1); | |
118 | } | |
119 | io_enabled = mem_enabled = false; | |
120 | } | |
121 | ||
122 | bool io_mapped() {return io_enabled;} | |
123 | bool mem_mapped() {return mem_enabled;} | |
124 | ||
125 | uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write) { | |
126 | assert(!byte_offset); | |
127 | ||
128 | uint8_t ret; | |
129 | if(bytes_to_write <= 2) | |
130 | ret = bytes_to_write; | |
131 | else | |
132 | ret = 2; | |
133 | ||
134 | buf &= ~((int32_t)-1 << (ret << 3)); | |
135 | ||
136 | uint32_t new_val = val | (mask & buf); | |
137 | uint32_t changed_bits = new_val ^ val; | |
138 | ||
139 | if(debug_level >= 2) | |
140 | printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,val,new_val); | |
141 | ||
142 | val = new_val; | |
143 | ||
144 | if(changed_bits & 1 << IO_SPACE){ //I/O space map bit has changed | |
145 | if(val & 1 << IO_SPACE) { //bit set to 1 | |
146 | assert(!io_mapped()); | |
147 | mapSpace(PCIE_IO, true); | |
148 | enable_io(); | |
149 | } else if (io_mapped()) { //bit set to 0 | |
150 | mapSpace(PCIE_IO, false); | |
151 | disable_io(); | |
152 | } | |
153 | } | |
154 | ||
155 | if(changed_bits & 1 << MEM_SPACE){ | |
156 | if(val & 1 << MEM_SPACE){ //bit set to 1 | |
157 | assert(!mem_mapped()); | |
158 | mapSpace(PCIE_MEM, true); | |
159 | enable_mem(); | |
160 | }else if (mem_mapped()) { | |
161 | mapSpace(PCIE_MEM, false); | |
162 | disable_mem(); | |
163 | } | |
164 | } | |
165 | return ret; | |
166 | } | |
167 | }; | |
168 | ||
169 | ||
170 | ||
171 | class pciSecondaryStatusReg:public pciConfReg{ | |
172 | public: | |
173 | enum{ | |
174 | MHZ_CAPABLE_66 = 5, | |
175 | FAST_BACKTO_BACK = 7, | |
176 | MASTER_DATA_PARITY_ERR = 8, | |
177 | DEVSEL_TIMING_LBP = 9, | |
178 | DEVSEL_TIMING_RBP = 10, | |
179 | SIGNALED_TARGET_ABORT = 11, | |
180 | RECVD_TARGET_ABORT = 12, | |
181 | RECVD_MASTER_ABORT = 13, | |
182 | RECEIVD_SYSTEM_ERR = 14, | |
183 | DETECTED_PARITY_ERR = 15 | |
184 | }; | |
185 | ||
186 | enum{ | |
187 | FAST_DEVSEL_TIMING = 0, | |
188 | MEDIUM_DEVSEL_TIMING = 1, | |
189 | SLOW_DEVSEL_TIMIMG = 2, | |
190 | }; | |
191 | pciSecondaryStatusReg(uint16_t por_val = 0x0, uint16_t mask = 0xf900, \ | |
192 | void * d = 0, const char * name = "pciSecStatReg") | |
193 | :pciConfReg(name, 2, por_val, mask, d){} | |
194 | ||
195 | uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){ | |
196 | assert(bytes_to_write == 2); | |
197 | uint32_t oldval = val; | |
198 | ||
199 | // if fails, write a more generic function in here. | |
200 | buf &= mask; // 0 out the ro bits if any in buf | |
201 | buf = ~buf; // flip the 0's to 1's and vice versa | |
202 | val &= buf; // and with val so that bits set to 1 are turned off | |
203 | // bits written to with 0 are unaffected. | |
204 | if(debug_level >= 2) | |
205 | printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val); | |
206 | ||
207 | ||
208 | return 2; | |
209 | } | |
210 | ||
211 | }; | |
212 | ||
213 | class pciBridgeControlReg:public pciConfReg{ | |
214 | public: | |
215 | enum{ | |
216 | PARITY_ERROR_RESPONSE_EN = 0, | |
217 | SERR_EN = 1, | |
218 | ISA_EN = 2, | |
219 | VGA_EN = 3, | |
220 | VGA_16_BIT_DECODE = 4, | |
221 | MASTER_ABORT = 5, | |
222 | SEC_BUS_RESET = 6, | |
223 | FAST_BACK_TO_BACK_EN = 7, | |
224 | PRIMARY_DISCARD_TIMER = 8, | |
225 | SECONDARY_DISCARD_TIMER = 9, | |
226 | DISCARD_TIMER_STATUS = 10, // RW1C bit | |
227 | DISCARD_TIMER_ERR_EN = 11 | |
228 | }; | |
229 | ||
230 | pciBridgeControlReg(uint16_t por_val = 0x0, uint16_t mask = 0xeff, \ | |
231 | void * d = 0, const char * name = "pciBridgeCtrlReg") | |
232 | :pciConfReg(name, 2, por_val, mask, d){} | |
233 | ||
234 | uint8_t write(uint32_t buf, uint8_t byte_offset, uint8_t bytes_to_write){ | |
235 | uint32_t bit10_in_buf = buf & 1 << DISCARD_TIMER_STATUS; | |
236 | uint32_t bit10_in_val = val & 1 << DISCARD_TIMER_STATUS; | |
237 | uint32_t oldval = val; | |
238 | ||
239 | pciConfReg::write(buf,byte_offset,bytes_to_write); | |
240 | ||
241 | if((bytes_to_write > 1) && bit10_in_buf && bit10_in_val) | |
242 | val &= ~((uint32_t)1 << DISCARD_TIMER_STATUS); | |
243 | ||
244 | if(debug_level >= 2) | |
245 | printf("Name<%s>,size<0x%x>mask<0x%lx>value<0x%lx -> 0x%lx>\n",name,size,mask,oldval,val); | |
246 | return bytes_to_write; | |
247 | } | |
248 | }; | |
249 | ||
250 | #endif// __PCI_BRIDGE_H__ | |
251 |