| 1 | /******************************************************************************* |
| 2 | Copyright (C) Marvell International Ltd. and its affiliates |
| 3 | |
| 4 | This software file (the "File") is owned and distributed by Marvell |
| 5 | International Ltd. and/or its affiliates ("Marvell") under the following |
| 6 | alternative licensing terms. Once you have made an election to distribute the |
| 7 | File under one of the following license alternatives, please (i) delete this |
| 8 | introductory statement regarding license alternatives, (ii) delete the two |
| 9 | license alternatives that you have not elected to use and (iii) preserve the |
| 10 | Marvell copyright notice above. |
| 11 | |
| 12 | ******************************************************************************** |
| 13 | Marvell Commercial License Option |
| 14 | |
| 15 | If you received this File from Marvell and you have entered into a commercial |
| 16 | license agreement (a "Commercial License") with Marvell, the File is licensed |
| 17 | to you under the terms of the applicable Commercial License. |
| 18 | |
| 19 | ******************************************************************************** |
| 20 | Marvell GPL License Option |
| 21 | |
| 22 | If you received this File from Marvell, you may opt to use, redistribute and/or |
| 23 | modify this File in accordance with the terms and conditions of the General |
| 24 | Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| 25 | available along with the File in the license.txt file or by writing to the Free |
| 26 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| 27 | on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| 28 | |
| 29 | THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| 30 | WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| 31 | DISCLAIMED. The GPL License provides additional details about this warranty |
| 32 | disclaimer. |
| 33 | ******************************************************************************** |
| 34 | Marvell BSD License Option |
| 35 | |
| 36 | If you received this File from Marvell, you may opt to use, redistribute and/or |
| 37 | modify this File under the following licensing terms. |
| 38 | Redistribution and use in source and binary forms, with or without modification, |
| 39 | are permitted provided that the following conditions are met: |
| 40 | |
| 41 | * Redistributions of source code must retain the above copyright notice, |
| 42 | this list of conditions and the following disclaimer. |
| 43 | |
| 44 | * Redistributions in binary form must reproduce the above copyright |
| 45 | notice, this list of conditions and the following disclaimer in the |
| 46 | documentation and/or other materials provided with the distribution. |
| 47 | |
| 48 | * Neither the name of Marvell nor the names of its contributors may be |
| 49 | used to endorse or promote products derived from this software without |
| 50 | specific prior written permission. |
| 51 | |
| 52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 53 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 54 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 55 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| 56 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 57 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 58 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| 59 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 60 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 61 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 62 | |
| 63 | *******************************************************************************/ |
| 64 | |
| 65 | #include "mvPex.h" |
| 66 | |
| 67 | //#define MV_DEBUG |
| 68 | /* defines */ |
| 69 | #ifdef MV_DEBUG |
| 70 | #define DB(x) x |
| 71 | #else |
| 72 | #define DB(x) |
| 73 | #endif |
| 74 | |
| 75 | /* locals */ |
| 76 | typedef struct |
| 77 | { |
| 78 | MV_U32 data; |
| 79 | MV_U32 mask; |
| 80 | }PEX_HEADER_DATA; |
| 81 | |
| 82 | /* local function forwad decleration */ |
| 83 | MV_U32 mvPexHwConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, |
| 84 | MV_U32 regOff); |
| 85 | MV_STATUS mvPexHwConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, |
| 86 | MV_U32 func, MV_U32 regOff, MV_U32 data); |
| 87 | void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev); |
| 88 | |
| 89 | |
| 90 | PEX_HEADER_DATA configHdr[16] = |
| 91 | { |
| 92 | {0x888811ab, 0x00000000}, /*[device ID, vendor ID] */ |
| 93 | {0x00100007, 0x0000ffff}, /*[status register, command register] */ |
| 94 | {0x0604000e, 0x00000000}, /*[programming interface, sub class code, class code, revision ID] */ |
| 95 | {0x00010008, 0x00000000}, /*[BIST, header type, latency time, cache line] */ |
| 96 | {0x00000000, 0x00000000}, /*[base address 0] */ |
| 97 | {0x00000000, 0x00000000}, /*[base address 1] */ |
| 98 | {0x00000000, 0x00ffffff}, /*[secondary latency timersubordinate bus number, secondary bus number, primary bus number] */ |
| 99 | {0x0000f101, 0x00000000}, /*[secondary status ,IO limit, IO base] */ |
| 100 | {0x9ff0a000, 0x00000000}, /*[memory limit, memory base] */ |
| 101 | {0x0001fff1, 0x00000000}, /*[prefetch memory limit, prefetch memory base] */ |
| 102 | {0xffffffff, 0x00000000}, /*[prefetch memory base upper] */ |
| 103 | {0x00000000, 0x00000000}, /*[prefetch memory limit upper] */ |
| 104 | {0xeffff000, 0x00000000}, /*[IO limit upper 16 bits, IO base upper 16 bits] */ |
| 105 | {0x00000000, 0x00000000}, /*[reserved, capability pointer] */ |
| 106 | {0x00000000, 0x00000000}, /*[expansion ROM base address] */ |
| 107 | {0x00000000, 0x000000FF}, /*[bridge control, interrupt pin, interrupt line] */ |
| 108 | }; |
| 109 | |
| 110 | |
| 111 | #define HEADER_WRITE(data, offset) configHdr[offset/4].data = ((configHdr[offset/4].data & ~configHdr[offset/4].mask) | \ |
| 112 | (data & configHdr[offset/4].mask)) |
| 113 | #define HEADER_READ(offset) configHdr[offset/4].data |
| 114 | |
| 115 | /******************************************************************************* |
| 116 | * mvVrtBrgPexInit - Initialize PEX interfaces |
| 117 | * |
| 118 | * DESCRIPTION: |
| 119 | * |
| 120 | * This function is responsible of intialization of the Pex Interface , It |
| 121 | * configure the Pex Bars and Windows in the following manner: |
| 122 | * |
| 123 | * Assumptions : |
| 124 | * Bar0 is always internal registers bar |
| 125 | * Bar1 is always the DRAM bar |
| 126 | * Bar2 is always the Device bar |
| 127 | * |
| 128 | * 1) Sets the Internal registers bar base by obtaining the base from |
| 129 | * the CPU Interface |
| 130 | * 2) Sets the DRAM bar base and size by getting the base and size from |
| 131 | * the CPU Interface when the size is the sum of all enabled DRAM |
| 132 | * chip selects and the base is the base of CS0 . |
| 133 | * 3) Sets the Device bar base and size by getting these values from the |
| 134 | * CPU Interface when the base is the base of the lowest base of the |
| 135 | * Device chip selects, and the |
| 136 | * |
| 137 | * |
| 138 | * INPUT: |
| 139 | * |
| 140 | * pexIf - PEX interface number. |
| 141 | * |
| 142 | * |
| 143 | * OUTPUT: |
| 144 | * None. |
| 145 | * |
| 146 | * RETURN: |
| 147 | * MV_OK if function success otherwise MV_ERROR or MV_BAD_PARAM |
| 148 | * |
| 149 | *******************************************************************************/ |
| 150 | MV_STATUS mvPexVrtBrgInit(MV_U32 pexIf) |
| 151 | { |
| 152 | /* reset PEX tree to recover previous U-boot/Boot configurations */ |
| 153 | MV_U32 localBus = mvPexLocalBusNumGet(pexIf); |
| 154 | |
| 155 | |
| 156 | resetPexConfig(pexIf, localBus, 1); |
| 157 | return MV_OK; |
| 158 | } |
| 159 | |
| 160 | |
| 161 | MV_U32 mvPexVrtBrgConfigRead (MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, |
| 162 | MV_U32 regOff) |
| 163 | { |
| 164 | |
| 165 | MV_U32 localBus = mvPexLocalBusNumGet(pexIf); |
| 166 | MV_U32 localDev = mvPexLocalDevNumGet(pexIf); |
| 167 | MV_U32 val; |
| 168 | if(bus == localBus) |
| 169 | { |
| 170 | if(dev > 1) |
| 171 | { |
| 172 | /* on the local device allow only device #0 & #1 */ |
| 173 | return 0xffffffff; |
| 174 | } |
| 175 | else |
| 176 | if (dev == localDev) |
| 177 | { |
| 178 | /* read the memory controller registers */ |
| 179 | return mvPexHwConfigRead (pexIf, bus, dev, func, regOff); |
| 180 | } |
| 181 | else |
| 182 | { |
| 183 | /* access the virtual brg header */ |
| 184 | return HEADER_READ(regOff); |
| 185 | } |
| 186 | } |
| 187 | else |
| 188 | if(bus == (localBus + 1)) |
| 189 | { |
| 190 | /* access the device behind the virtual bridge */ |
| 191 | if((dev == localDev) || (dev > 1)) |
| 192 | { |
| 193 | return 0xffffffff; |
| 194 | } |
| 195 | else |
| 196 | { |
| 197 | /* access the device behind the virtual bridge, in this case |
| 198 | * change the bus number to the local bus number in order to |
| 199 | * generate type 0 config cycle |
| 200 | */ |
| 201 | mvPexLocalBusNumSet(pexIf, bus); |
| 202 | mvPexLocalDevNumSet(pexIf, 1); |
| 203 | val = mvPexHwConfigRead (pexIf, bus, 0, func, regOff); |
| 204 | mvPexLocalBusNumSet(pexIf, localBus); |
| 205 | mvPexLocalDevNumSet(pexIf, localDev); |
| 206 | return val; |
| 207 | } |
| 208 | } |
| 209 | /* for all other devices use the HW function to get the |
| 210 | * requested registers |
| 211 | */ |
| 212 | mvPexLocalDevNumSet(pexIf, 1); |
| 213 | val = mvPexHwConfigRead (pexIf, bus, dev, func, regOff); |
| 214 | mvPexLocalDevNumSet(pexIf, localDev); |
| 215 | return val; |
| 216 | } |
| 217 | |
| 218 | |
| 219 | MV_STATUS mvPexVrtBrgConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, |
| 220 | MV_U32 func, MV_U32 regOff, MV_U32 data) |
| 221 | { |
| 222 | MV_U32 localBus = mvPexLocalBusNumGet(pexIf); |
| 223 | MV_U32 localDev = mvPexLocalDevNumGet(pexIf); |
| 224 | MV_STATUS status; |
| 225 | |
| 226 | if(bus == localBus) |
| 227 | { |
| 228 | if(dev > 1) |
| 229 | { |
| 230 | /* on the local device allow only device #0 & #1 */ |
| 231 | return MV_ERROR; |
| 232 | } |
| 233 | else |
| 234 | if (dev == localDev) |
| 235 | { |
| 236 | /* read the memory controller registers */ |
| 237 | return mvPexHwConfigWrite (pexIf, bus, dev, func, regOff, data); |
| 238 | } |
| 239 | else |
| 240 | { |
| 241 | /* access the virtual brg header */ |
| 242 | HEADER_WRITE(data, regOff); |
| 243 | return MV_OK; |
| 244 | } |
| 245 | } |
| 246 | else |
| 247 | if(bus == (localBus + 1)) |
| 248 | { |
| 249 | /* access the device behind the virtual bridge */ |
| 250 | if((dev == localDev) || (dev > 1)) |
| 251 | { |
| 252 | return MV_ERROR; |
| 253 | } |
| 254 | else |
| 255 | { |
| 256 | /* access the device behind the virtual bridge, in this case |
| 257 | * change the bus number to the local bus number in order to |
| 258 | * generate type 0 config cycle |
| 259 | */ |
| 260 | //return mvPexHwConfigWrite (pexIf, localBus, dev, func, regOff, data); |
| 261 | mvPexLocalBusNumSet(pexIf, bus); |
| 262 | mvPexLocalDevNumSet(pexIf, 1); |
| 263 | status = mvPexHwConfigWrite (pexIf, bus, 0, func, regOff, data); |
| 264 | mvPexLocalBusNumSet(pexIf, localBus); |
| 265 | mvPexLocalDevNumSet(pexIf, localDev); |
| 266 | return status; |
| 267 | |
| 268 | } |
| 269 | } |
| 270 | /* for all other devices use the HW function to get the |
| 271 | * requested registers |
| 272 | */ |
| 273 | mvPexLocalDevNumSet(pexIf, 1); |
| 274 | status = mvPexHwConfigWrite (pexIf, bus, dev, func, regOff, data); |
| 275 | mvPexLocalDevNumSet(pexIf, localDev); |
| 276 | return status; |
| 277 | } |
| 278 | |
| 279 | |
| 280 | |
| 281 | |
| 282 | void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev) |
| 283 | { |
| 284 | MV_U32 tData; |
| 285 | MV_U32 i; |
| 286 | |
| 287 | /* restore the PEX configuration to initialization state */ |
| 288 | /* in case PEX P2P call recursive and reset config */ |
| 289 | tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x0); |
| 290 | if(tData != 0xffffffff) |
| 291 | { |
| 292 | /* agent had been found - check whether P2P */ |
| 293 | tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x8); |
| 294 | if((tData & 0xffff0000) == 0x06040000) |
| 295 | {/* P2P */ |
| 296 | /* get the sec bus and the subordinate */ |
| 297 | MV_U32 secBus; |
| 298 | tData = mvPexHwConfigRead (pexIf, bus, dev, 0x0, 0x18); |
| 299 | secBus = ((tData >> 8) & 0xff); |
| 300 | /* now scan on sec bus */ |
| 301 | for(i = 0;i < 0xff;i++) |
| 302 | { |
| 303 | resetPexConfig(pexIf, secBus, i); |
| 304 | } |
| 305 | /* now reset this device */ |
| 306 | DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev)); |
| 307 | mvPexHwConfigWrite(pexIf, bus, dev, 0x0, 0x18, 0x0); |
| 308 | DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev)); |
| 309 | } |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | |
| 314 | |