| /******************************************************************************* |
| Copyright (C) Marvell International Ltd. and its affiliates |
| |
| This software file (the "File") is owned and distributed by Marvell |
| International Ltd. and/or its affiliates ("Marvell") under the following |
| alternative licensing terms. Once you have made an election to distribute the |
| File under one of the following license alternatives, please (i) delete this |
| introductory statement regarding license alternatives, (ii) delete the two |
| license alternatives that you have not elected to use and (iii) preserve the |
| Marvell copyright notice above. |
| |
| ******************************************************************************** |
| Marvell Commercial License Option |
| |
| If you received this File from Marvell and you have entered into a commercial |
| license agreement (a "Commercial License") with Marvell, the File is licensed |
| to you under the terms of the applicable Commercial License. |
| |
| ******************************************************************************** |
| Marvell GPL License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File in accordance with the terms and conditions of the General |
| Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| available along with the File in the license.txt file or by writing to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| |
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| DISCLAIMED. The GPL License provides additional details about this warranty |
| disclaimer. |
| ******************************************************************************** |
| Marvell BSD License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File under the following licensing terms. |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright notice, |
| this list of conditions and the following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| * Neither the name of Marvell nor the names of its contributors may be |
| used to endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| *******************************************************************************/ |
| |
| #include "mvPex.h" |
| |
| /* #define MV_DEBUG */ |
| /* defines */ |
| #ifdef MV_DEBUG |
| #define DB(x) x |
| #else |
| #define DB(x) |
| #endif |
| |
| /* locals */ |
| typedef struct { |
| MV_U32 data; |
| MV_U32 mask; |
| } PEX_HEADER_DATA; |
| |
| /* local function forwad decleration */ |
| MV_U32 mvPexHwConfigRead(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, MV_U32 regOff); |
| MV_STATUS mvPexHwConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, MV_U32 regOff, MV_U32 data); |
| void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev); |
| |
| PEX_HEADER_DATA configHdr[16] = { |
| {0x888811ab, 0x00000000}, /*[device ID, vendor ID] */ |
| {0x00100007, 0x0000ffff}, /*[status register, command register] */ |
| {0x0604000e, 0x00000000}, /*[programming interface, sub class code, class code, revision ID] */ |
| {0x00010008, 0x00000000}, /*[BIST, header type, latency time, cache line] */ |
| {0x00000000, 0x00000000}, /*[base address 0] */ |
| {0x00000000, 0x00000000}, /*[base address 1] */ |
| {0x00000000, 0x00ffffff}, /*[secondary latency timersubordinate bus number, |
| secondary bus number, primary bus number] */ |
| {0x0000f101, 0x00000000}, /*[secondary status ,IO limit, IO base] */ |
| {0x9ff0a000, 0x00000000}, /*[memory limit, memory base] */ |
| {0x0001fff1, 0x00000000}, /*[prefetch memory limit, prefetch memory base] */ |
| {0xffffffff, 0x00000000}, /*[prefetch memory base upper] */ |
| {0x00000000, 0x00000000}, /*[prefetch memory limit upper] */ |
| {0xeffff000, 0x00000000}, /*[IO limit upper 16 bits, IO base upper 16 bits] */ |
| {0x00000000, 0x00000000}, /*[reserved, capability pointer] */ |
| {0x00000000, 0x00000000}, /*[expansion ROM base address] */ |
| {0x00000000, 0x000000FF}, /*[bridge control, interrupt pin, interrupt line] */ |
| }; |
| |
| #define HEADER_WRITE(data, offset) configHdr[offset/4].data = \ |
| ((configHdr[offset/4].data & ~configHdr[offset/4].mask) | \ |
| (data & configHdr[offset/4].mask)) |
| #define HEADER_READ(offset) configHdr[offset/4].data |
| |
| /******************************************************************************* |
| * mvVrtBrgPexInit - Initialize PEX interfaces |
| * |
| * Description: |
| * This function is responsible of intialization of the Pex Interface , It |
| * configure the Pex Bars and Windows in the following manner: |
| * |
| * Assumptions : |
| * Bar0 is always internal registers bar |
| * Bar1 is always the DRAM bar |
| * Bar2 is always the Device bar |
| * |
| * 1) Sets the Internal registers bar base by obtaining the base from |
| * the CPU Interface |
| * 2) Sets the DRAM bar base and size by getting the base and size from |
| * the CPU Interface when the size is the sum of all enabled DRAM |
| * chip selects and the base is the base of CS0 . |
| * 3) Sets the Device bar base and size by getting these values from the |
| * CPU Interface when the base is the base of the lowest base of the |
| * Device chip selects, and the |
| * |
| * INPUT: |
| * pexIf - PEX interface number. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK if function success otherwise MV_ERROR or MV_BAD_PARAM |
| * |
| *******************************************************************************/ |
| MV_STATUS mvPexVrtBrgInit(MV_U32 pexIf) |
| { |
| /* reset PEX tree to recover previous U-boot/Boot configurations */ |
| MV_U32 localBus = mvPexLocalBusNumGet(pexIf); |
| |
| resetPexConfig(pexIf, localBus, 1); |
| return MV_OK; |
| } |
| |
| MV_U32 mvPexVrtBrgConfigRead(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, MV_U32 regOff) |
| { |
| |
| MV_U32 localBus = mvPexLocalBusNumGet(pexIf); |
| MV_U32 localDev = mvPexLocalDevNumGet(pexIf); |
| MV_U32 val; |
| if (bus == localBus) { |
| if (dev > 1) { |
| /* on the local device allow only device #0 & #1 */ |
| return 0xffffffff; |
| } else if (dev == localDev) { |
| /* read the memory controller registers */ |
| return mvPexHwConfigRead(pexIf, bus, dev, func, regOff); |
| } else { |
| /* access the virtual brg header */ |
| return HEADER_READ(regOff); |
| } |
| } else if (bus == (localBus + 1)) { |
| /* access the device behind the virtual bridge */ |
| if ((dev == localDev) || (dev > 1)) { |
| return 0xffffffff; |
| } else { |
| /* access the device behind the virtual bridge, in this case |
| * change the bus number to the local bus number in order to |
| * generate type 0 config cycle |
| */ |
| mvPexLocalBusNumSet(pexIf, bus); |
| mvPexLocalDevNumSet(pexIf, 1); |
| val = mvPexHwConfigRead(pexIf, bus, 0, func, regOff); |
| mvPexLocalBusNumSet(pexIf, localBus); |
| mvPexLocalDevNumSet(pexIf, localDev); |
| return val; |
| } |
| } |
| /* for all other devices use the HW function to get the |
| * requested registers |
| */ |
| mvPexLocalDevNumSet(pexIf, 1); |
| val = mvPexHwConfigRead(pexIf, bus, dev, func, regOff); |
| mvPexLocalDevNumSet(pexIf, localDev); |
| return val; |
| } |
| |
| MV_STATUS mvPexVrtBrgConfigWrite(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, MV_U32 regOff, MV_U32 data) |
| { |
| MV_U32 localBus = mvPexLocalBusNumGet(pexIf); |
| MV_U32 localDev = mvPexLocalDevNumGet(pexIf); |
| MV_STATUS status; |
| |
| if (bus == localBus) { |
| if (dev > 1) { |
| /* on the local device allow only device #0 & #1 */ |
| return MV_ERROR; |
| } else if (dev == localDev) { |
| /* read the memory controller registers */ |
| return mvPexHwConfigWrite(pexIf, bus, dev, func, regOff, data); |
| } else { |
| /* access the virtual brg header */ |
| HEADER_WRITE(data, regOff); |
| return MV_OK; |
| } |
| } else if (bus == (localBus + 1)) { |
| /* access the device behind the virtual bridge */ |
| if ((dev == localDev) || (dev > 1)) { |
| return MV_ERROR; |
| } else { |
| /* access the device behind the virtual bridge, in this case |
| * change the bus number to the local bus number in order to |
| * generate type 0 config cycle |
| */ |
| /* return mvPexHwConfigWrite (pexIf, localBus, dev, func, regOff, data); */ |
| mvPexLocalBusNumSet(pexIf, bus); |
| mvPexLocalDevNumSet(pexIf, 1); |
| status = mvPexHwConfigWrite(pexIf, bus, 0, func, regOff, data); |
| mvPexLocalBusNumSet(pexIf, localBus); |
| mvPexLocalDevNumSet(pexIf, localDev); |
| return status; |
| |
| } |
| } |
| /* for all other devices use the HW function to get the |
| * requested registers |
| */ |
| mvPexLocalDevNumSet(pexIf, 1); |
| status = mvPexHwConfigWrite(pexIf, bus, dev, func, regOff, data); |
| mvPexLocalDevNumSet(pexIf, localDev); |
| return status; |
| } |
| |
| void resetPexConfig(MV_U32 pexIf, MV_U32 bus, MV_U32 dev) |
| { |
| MV_U32 tData; |
| MV_U32 i; |
| |
| /* restore the PEX configuration to initialization state */ |
| /* in case PEX P2P call recursive and reset config */ |
| tData = mvPexHwConfigRead(pexIf, bus, dev, 0x0, 0x0); |
| if (tData != 0xffffffff) { |
| /* agent had been found - check whether P2P */ |
| tData = mvPexHwConfigRead(pexIf, bus, dev, 0x0, 0x8); |
| if ((tData & 0xffff0000) == 0x06040000) { /* P2P */ |
| /* get the sec bus and the subordinate */ |
| MV_U32 secBus; |
| tData = mvPexHwConfigRead(pexIf, bus, dev, 0x0, 0x18); |
| secBus = ((tData >> 8) & 0xff); |
| |
| /* now scan on sec bus */ |
| for (i = 0; i < 0xff; i++) |
| resetPexConfig(pexIf, secBus, i); |
| |
| /* now reset this device */ |
| DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev)); |
| mvPexHwConfigWrite(pexIf, bus, dev, 0x0, 0x18, 0x0); |
| DB(mvOsPrintf("Reset bus %d dev %d\n", bus, dev)); |
| } |
| } |
| } |