| /******************************************************************************* |
| 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 "mvHighSpeedEnvSpec.h" |
| |
| #define SERDES_VERION "1.0.0" |
| #define ENDED_OK "High speed PHY - Ended Successfully\n" |
| |
| /**************************** globals *****************************/ |
| |
| MV_BOARD_TOPOLOGY_CONFIG boardTopologyConfig[] = |
| { |
| /* board name Lane 1, Lane 2 Lane3 Sgmii Speed*/ |
| #ifdef CONFIG_CUSTOMER_BOARD_SUPPORT |
| {"AVANTA_LP_CUSTOMER_0", {SERDES_UNIT_PEX, SERDES_UNIT_SATA, SERDES_UNIT_USB3 }, MV_SGMII_GEN1}, |
| {"AVANTA_LP_CUSTOMER_1", {SERDES_UNIT_PEX, SERDES_UNIT_SATA, SERDES_UNIT_USB3 }, MV_SGMII_GEN1}, |
| #else |
| {"RD_88F6650_BP", {SERDES_UNIT_PEX, SERDES_UNIT_UNCONNECTED, SERDES_UNIT_UNCONNECTED}, MV_SGMII_NA}, |
| {"DB_88F6650_BP", {SERDES_UNIT_PEX, SERDES_UNIT_UNCONNECTED, SERDES_UNIT_UNCONNECTED}, MV_SGMII_NA}, |
| {"RD_88F6660_BP", {SERDES_UNIT_PEX, SERDES_UNIT_SATA, SERDES_UNIT_USB3 }, MV_SGMII_NA}, |
| {"DB_88F6660_BP", {SERDES_UNIT_PEX, SERDES_UNIT_UNCONNECTED, SERDES_UNIT_UNCONNECTED}, MV_SGMII_NA},/*Lane 2 and Lane 3 configuration is set in run time*/ |
| #endif |
| }; |
| |
| MV_BIN_SERDES_UNIT_INDX boardLaneConfig[MAX_LANE_NUM] = {SERDES_UNIT_UNCONNECTED, |
| SERDES_UNIT_UNCONNECTED, |
| SERDES_UNIT_UNCONNECTED, |
| SERDES_UNIT_UNCONNECTED}; |
| |
| /****************** Macros ******************************/ |
| #define ALP_A0_COMMON_PHY_CONFIG(regData) \ |
| regData |= POWER_UP_IVREF_MASK; /* Power UP IVREF = Power Up */ \ |
| regData &= ~(REF_CLK_DIS_MASK); /* Request to disable the PHY digital reference clock */ \ |
| regData |= PIN_TX_IDLE_MASK; /* to keep phyTxP/N output to idle during Phy init */ |
| |
| #define ALP_A0_RESET_DFE_SEQUENCE(serdesLaneNum) \ |
| MV_REG_WRITE(POWER_REG1_REG(serdesLaneNum),0xE409); /* Reset DFE sequence */ \ |
| MV_REG_WRITE(POWER_REG1_REG(serdesLaneNum),0xE008); /* Unreset DFE sequence */ |
| |
| /**************************** Local function *****************************************/ |
| MV_U32 mvPexConfigRead(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, MV_U32 regOff); |
| MV_STATUS mvPexLocalBusNumSet(MV_U32 pexIf, MV_U32 busNum); |
| MV_STATUS mvPexLocalDevNumSet(MV_U32 pexIf, MV_U32 devNum); |
| MV_STATUS mvPexAgentReset(); |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| MV_STATUS mvUsb2PhyInit(MV_U32 dev); |
| #endif |
| MV_STATUS mvPONPhyInit(); |
| |
| /**************************** function implementation *****************************************/ |
| |
| /******************************************************************************* |
| * mvReverseBits |
| * |
| * DESCRIPTION: |
| * This function Reverts the direction of the bits (LSB to MSB and vice versa) |
| * |
| * INPUT: |
| * num - MV_U8 number to revert |
| * |
| * OUTPUT: |
| * Reverted number |
| * |
| * RETURN: |
| * None |
| * |
| *******************************************************************************/ |
| static MV_U8 mvReverseBits(MV_U8 num) |
| { |
| num = (num & 0xF0) >> 4 | (num & 0x0F) << 4; |
| num = (num & 0xCC) >> 2 | (num & 0x33) << 2; |
| num = (num & 0xAA) >> 1 | (num & 0x55) << 1; |
| return num; |
| } |
| |
| /******************************************************************************* |
| * mvBoardDb6660IsEepromEnabled - read jumper and verify if EEPROM is enabled |
| * |
| * DESCRIPTION: |
| * This function returns MV_TRUE if board configuration jumper is set to EEPROM. |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_BOOL : MV_TRUE if EEPROM enabled, else return MV_FALSE. |
| * |
| *******************************************************************************/ |
| MV_BOOL mvBoardDb6660IsEepromEnabled() |
| { |
| MV_U8 regVal; |
| |
| if (MV_OK == mvBoardTwsiGet(BOARD_DEV_TWSI_IO_EXPANDER_JUMPER1, 0, 0, MV_FALSE, ®Val)) |
| return ((regVal & 0x80)? MV_FALSE : MV_TRUE); |
| return MV_FALSE; |
| } |
| |
| /******************************************************************************* |
| * mvCtrlBoardTopologyConfigGet - read Board Configuration, from EEPROM / Dip Switch |
| * |
| * DESCRIPTION: |
| * This function reads all board configuration from EEPROM / Dip Switch: |
| * 1. read the EEPROM enable jumper, and read from configured device |
| * 2. read first 2 registers for all boards |
| * 3. read specific registers for specific boards |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_BOOL : MV_TRUE if EEPROM enabled, else return MV_FALSE. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvBoardDb6660LaneConfigGet(MV_U8 *tempVal) |
| { |
| MV_STATUS rc1, rc2, rc3; |
| MV_BOOL isEepromEnabled = mvBoardDb6660IsEepromEnabled(); |
| MV_U8 temp0,temp1; |
| MV_U32 address, address1, devNum, regNum; |
| MV_BOOL isMoreThen256; |
| |
| if (isEepromEnabled) { |
| address = BOARD_DEV_TWSI_EEPROM; |
| address1 = BOARD_DEV_TWSI_EEPROM; |
| devNum = DEV_NUM1; |
| regNum = REG_NUM2; |
| isMoreThen256 = MV_TRUE; |
| } |
| else { |
| address = BOARD_DEV_TWSI_IO_EXPANDER; |
| address1 = BOARD_DEV_TWSI_IO_EXPANDER_SW7; |
| devNum = DEV_NUM1; |
| regNum = REG_NUM0; |
| isMoreThen256 = MV_FALSE; |
| } |
| |
| rc1 = mvBoardTwsiGet(address, DEV_NUM0, REG_NUM0, isMoreThen256, &tempVal[0]); /* EEPROM/Dip Switch Reg#0 */ |
| rc2 = mvBoardTwsiGet(address, DEV_NUM0, REG_NUM1, isMoreThen256, &tempVal[1]); /* EEPROM/Dip Switch Reg#1 */ |
| rc3 = mvBoardTwsiGet(address1, devNum, regNum, isMoreThen256, &tempVal[2]); /* Dip Switch -> Reg#0, EEPROM -> Reg#2 */ |
| |
| /* |
| * Workaround for DIP Switch IO Expander 0x21 bug in DB-6660 board |
| * Bug: Pins at IO expander 0x21 are reversed (only on DB-6660) |
| * Solution: after reading IO expander, reverse bits of both registers |
| */ |
| if (isEepromEnabled != MV_TRUE) { |
| /* Reverse all BITS */ |
| tempVal[0] = mvReverseBits(tempVal[0]); |
| tempVal[1] = mvReverseBits(tempVal[1]); |
| |
| /* Swap field's MSB with LSB */ |
| temp0 = (tempVal[0] & 0x18) >> 3; |
| temp0 = mvReverseBits(temp0) >> 6; |
| tempVal[0] &= ~0x18; |
| tempVal[0] |= temp0 << 3; |
| temp1 = (tempVal[1] & 0x18) >> 3; |
| temp1 = mvReverseBits(temp1) >> 6; |
| tempVal[1] &= ~0x18; |
| tempVal[1] |= temp1 << 3; |
| } |
| /* verify that all TWSI reads were successfully */ |
| if ((rc1 != MV_OK) || (rc2 != MV_OK) || (rc3 != MV_OK)) |
| return MV_ERROR; |
| |
| return MV_OK; |
| } |
| |
| /*****************************************************************:************** |
| * mvDb6660UpdateBoardTopologyConfig |
| * |
| * DESCRIPTION: read DB-6660 board configuration (using TWSI/EEPROM access) |
| * |
| * INPUT: None |
| * |
| * OUTPUT: None |
| * |
| * RETURN: NONE |
| * |
| *******************************************************************************/ |
| MV_STATUS mvDb6660UpdateBoardTopologyConfig(void) |
| { |
| MV_U8 configVal[MV_IO_EXP_MAX_REGS]; |
| MV_U8 tmp, boardIdIndex = mvBoardIdIndexGet(DB_6660_ID); |
| |
| /*Read rest of Board Configuration, EEPROM / Dip Switch access read : */ |
| |
| /* lane 1 config */ |
| if (mvBoardDb6660LaneConfigGet(configVal) == MV_OK) { |
| tmp = ((configVal[1] & 0x18) >> 3); |
| |
| switch (tmp) { |
| case 0: |
| boardTopologyConfig[boardIdIndex].serdesTopology.lane1 = SERDES_UNIT_PEX; |
| break; |
| case 1: |
| boardTopologyConfig[boardIdIndex].serdesTopology.lane1 = SERDES_UNIT_SGMII; |
| break; |
| case 2: |
| boardTopologyConfig[boardIdIndex].serdesTopology.lane1 = SERDES_UNIT_SATA; |
| break; |
| case 3: |
| default: |
| DEBUG_INIT_S("Error: Read board configuration (SERDES LANE1) from EEPROM/Dip Switch failed\n"); |
| return MV_INIT_ERROR; |
| |
| } |
| |
| /* lane 2 config */ |
| boardTopologyConfig[boardIdIndex].serdesTopology.lane2 = ((configVal[1] & 0x20) >> 5)? SERDES_UNIT_SGMII:SERDES_UNIT_SATA; |
| |
| /* lane 3 config */ |
| boardTopologyConfig[boardIdIndex].serdesTopology.lane3 = ((configVal[1] & 0x40) >> 6)? SERDES_UNIT_SGMII:SERDES_UNIT_USB3; |
| } |
| else{ |
| DEBUG_INIT_S("Error: Read board configuration from EEPROM/Dip Switch failed \n"); |
| DEBUG_INIT_S("setting default Serdes lanes configuration: PCIe-0, PCIe-1 SATA2, USB3\n"); |
| } |
| |
| /* update SGMII speed config */ |
| boardTopologyConfig[boardIdIndex].sgmiiSpeed = (configVal[0] & 0x40) ? MV_SGMII_GEN2 : MV_SGMII_GEN1; |
| |
| return MV_OK; |
| } |
| |
| /*****************************************************************:************** |
| * mvBoardUpdateSerdesTopology |
| * |
| * DESCRIPTION: Updates the topology structure of a specific board according to dynamic configuration |
| * |
| * INPUT: None |
| * |
| * OUTPUT: None |
| * |
| * RETURN: NONE |
| * |
| *******************************************************************************/ |
| MV_STATUS mvBoardUpdateBoardTopologyConfig(MV_U32 boardId) |
| { |
| /* this routine must be implemented, in order to use dynamic Serdes /SGMII settings configuration. |
| 1. scan requested configuration 2. update boardTopologyConfig[] according to config */ |
| switch(boardId) { |
| case DB_6660_ID: |
| return mvDb6660UpdateBoardTopologyConfig(); |
| case AVANTA_LP_CUSTOMER_BOARD_ID0: |
| case AVANTA_LP_CUSTOMER_BOARD_ID1: |
| return MV_OK; |
| default: |
| return MV_OK; |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvCtrlSerdesMaxLinesGet - Get Marvell controller number of SERDES lanes. |
| * |
| * DESCRIPTION: |
| * This function returns Marvell controller number of SERDES lanes. |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * Marvell controller number of PEX units. If controller |
| * ID is undefined the function returns '0'. |
| * |
| *******************************************************************************/ |
| MV_U32 mvCtrlSerdesMaxLanesGet(MV_VOID){ |
| switch (mvCtrlModelGet()) { |
| case MV_6660_DEV_ID: |
| return 4; |
| case MV_6650_DEV_ID: |
| return 1; |
| case MV_6610_DEV_ID: |
| if (mvBoardIdGet() == DB_6650_ID) |
| return 1; |
| else |
| return 0; |
| default: |
| return 0; |
| } |
| } |
| |
| /******************************************************************************* |
| * mvGetSerdesLaneCfg |
| * |
| * DESCRIPTION: This function returns the serdes unit index from the boardLaneConfig |
| * array |
| * |
| * INPUT: |
| * serdes lane number |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * serdes unit index |
| * |
| *******************************************************************************/ |
| #define mvGetSerdesLaneCfg(serdesLaneNum) boardLaneConfig[serdesLaneNum] |
| /******************************************************************************* |
| * GetLaneSelectorConfig |
| * |
| * DESCRIPTION: This function returns the value of the serdes configuration |
| * to the comphy selector |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * Register value |
| * |
| *******************************************************************************/ |
| MV_U32 GetLaneSelectorConfig(void) |
| { |
| MV_U32 tmp = 0,uiReg; |
| MV_U8 uiLan2Offs=0,uiLan3Offs=0; |
| |
| switch(mvCtrlRevisionGet()) { |
| case TSMC_Z1: |
| case UMC_Z1: |
| case TSMC_Z1_GPON_METAL_FIX: |
| uiLan2Offs = 2; |
| uiLan3Offs = 3; |
| break; |
| case UMC_A0: |
| uiLan2Offs = 3; |
| uiLan3Offs = 4; |
| break; |
| default: |
| break; |
| } |
| |
| uiReg = 0x1; /* lane 0 is always PEX */ |
| |
| switch (mvGetSerdesLaneCfg(1)) { |
| case SERDES_UNIT_PEX: |
| case SERDES_UNIT_UNCONNECTED: /* if SerDes is not connected, don't modify selector */ |
| tmp = 0; |
| break; |
| case SERDES_UNIT_SGMII: |
| tmp = 1; |
| break; |
| case SERDES_UNIT_SATA: |
| tmp = 2; |
| break; |
| default: |
| break; |
| } |
| uiReg |= (tmp << 1); /* lane 1 */ |
| |
| uiReg |= (((mvGetSerdesLaneCfg(2) == SERDES_UNIT_SGMII) ? 0 : 1) << uiLan2Offs); /* lane 2 */ |
| uiReg |= (((mvGetSerdesLaneCfg(3) == SERDES_UNIT_SGMII) ? 1 : 0) << uiLan3Offs); /* lane 3 */ |
| |
| DEBUG_INIT_FULL_S(">>>>>>> after GetLaneSelectorConfig, uiReg=0x"); |
| DEBUG_INIT_FULL_D(uiReg, 8); |
| DEBUG_INIT_FULL_S(" <<<<<<<<<\n"); |
| return uiReg; |
| } |
| /******************************************************************************* |
| * getSerdesSpeedConfig |
| * |
| * DESCRIPTION: This function return the ser-des speed configuration |
| * |
| * INPUT: |
| * serdes lane configuration |
| * |
| * OUTPUT: |
| * speed configuration |
| * |
| * RETURN: |
| * speed configuration |
| * |
| *******************************************************************************/ |
| MV_U32 getSerdesSpeedConfig(MV_U32 boardIdIndex, MV_BIN_SERDES_UNIT_INDX serdesLaneCfg) |
| { |
| |
| switch (serdesLaneCfg){ |
| case SERDES_UNIT_SGMII: |
| if(boardTopologyConfig[boardIdIndex].sgmiiSpeed == MV_SGMII_NA) { |
| DEBUG_INIT_S("Error: SGMII speed was not initialized for board "); |
| DEBUG_INIT_S(boardTopologyConfig[boardIdIndex].boardName); |
| DEBUG_INIT_S("\n"); |
| return MV_BAD_VALUE; |
| } |
| return (boardTopologyConfig[boardIdIndex].sgmiiSpeed == MV_SGMII_GEN1) ? 0x6 : 0x8; /* 0x6-> GEN1, 0x8->GEN2*/ |
| case SERDES_UNIT_USB3: |
| case SERDES_UNIT_SATA: |
| return 0x1; |
| default: |
| return 0; |
| } |
| } |
| |
| /******************************************************************************* |
| * resetPhyAndPipe |
| * |
| * DESCRIPTION: This function reset or un-reset the phy and pipe as a result of |
| * device revision ID |
| * |
| * INPUT: |
| * serdesLaneNum |
| * |
| * OUTPUT: |
| * |
| * |
| * RETURN: |
| * |
| * |
| *******************************************************************************/ |
| MV_VOID resetPhyAndPipe(MV_U32 serdesLaneNum, MV_BOOL bReset) |
| { |
| MV_U32 uiReg; |
| |
| uiReg = MV_REG_READ(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum)); |
| if(bReset) { |
| uiReg |= PHY_SOFTWARE_RESET_MASK; /* PHY Software Reset = Reset Mode */ |
| uiReg |= PHY_RESET_CORE_MASK; /* PHY Reset Core = 0x1 */ |
| uiReg &= ~(PHY_CORE_RST_MASK); /* PHY Core RSTn = Reset */ |
| uiReg &= ~(PHY_POWER_ON_RESET_MASK); /* PHY Power On Reset = Reset */ |
| } else { |
| uiReg &= ~(PHY_SOFTWARE_RESET_MASK); /* PHY Software Reset = Normal Mode */ |
| uiReg &= ~(PHY_RESET_CORE_MASK); /* PHY Reset Core = 0x0 */ |
| uiReg |= PHY_CORE_RST_MASK; /* PHY Core RSTn = Normal */ |
| uiReg |= PHY_POWER_ON_RESET_MASK; /* PHY Power On Reset = Normal */ |
| } |
| MV_REG_WRITE(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum),uiReg); |
| } |
| |
| /******************************************************************************* |
| * mvCtrlHighSpeedSerdesPhyConfig |
| * |
| * DESCRIPTION: This is the main function which configure the |
| * PU sequence of the ser-des |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - success |
| * MV_ERROR - failure |
| *******************************************************************************/ |
| MV_STATUS mvCtrlHighSpeedSerdesPhyConfig(MV_VOID) |
| { |
| MV_BIN_SERDES_UNIT_INDX serdesLaneCfg; |
| MV_U32 serdesLaneNum, pexUnit, uiReg, tmp, tempReg, tempPexReg, first_busno, next_busno, addr ,pexIf=0; |
| MV_U32 regAddr[16][11], regVal[16][11]; /* addr/value for each line @ every setup step */ |
| MV_TWSI_ADDR slave; |
| MV_U32 boardIdIndex, boardId = mvBoardIdGet(); |
| MV_U8 maxSerdesLanes = mvCtrlSerdesMaxLanesGet(); |
| |
| boardIdIndex = mvBoardIdIndexGet(boardId); |
| |
| if (maxSerdesLanes == 0) |
| return MV_OK; |
| |
| /*Set MPP1 for twsi access */ |
| uiReg = (MV_REG_READ(MPP_CONTROL_REG(1)) & 0x00FFFFFF) | 0x22000000; |
| MV_REG_WRITE(MPP_CONTROL_REG(1), uiReg); |
| |
| /* TWSI init */ |
| slave.type = ADDR7_BIT; |
| slave.address = 0; |
| mvTwsiInit(0, TWSI_SPEED, mvBoardTclkGet(), &slave, 0); |
| |
| mvUartInit(); |
| |
| /* update board configuration (serdes lane topology and speed), if needed */ |
| mvBoardUpdateBoardTopologyConfig(boardId); |
| |
| /* Initialize board configuration database */ |
| boardLaneConfig[0] = SERDES_UNIT_PEX; /* SerDes 0 is alwyas PCIe0*/ |
| boardLaneConfig[1] = boardTopologyConfig[boardIdIndex].serdesTopology.lane1; |
| boardLaneConfig[2] = boardTopologyConfig[boardIdIndex].serdesTopology.lane2; |
| boardLaneConfig[3] = boardTopologyConfig[boardIdIndex].serdesTopology.lane3; |
| |
| /* Release PEX agents reset */ |
| mvPexAgentReset(); |
| |
| memset(regAddr, 0, sizeof(regAddr)); |
| memset(regVal, 0, sizeof(regVal)); |
| |
| /* Check if DRAM is already initialized */ |
| if (MV_REG_READ(REG_BOOTROM_ROUTINE_ADDR) & (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) { |
| DEBUG_INIT_S("High speed PHY - Version: "); |
| DEBUG_INIT_S(SERDES_VERION); |
| DEBUG_INIT_S(" - 2nd boot - Skip \n"); |
| return MV_OK; |
| } |
| DEBUG_INIT_S("High speed PHY - Version: "); |
| DEBUG_INIT_S(SERDES_VERION); |
| DEBUG_INIT_S(" (COM-PHY-V20) \n"); |
| DEBUG_INIT_FULL_C("SERDES 0=",boardLaneConfig[0],2); |
| DEBUG_INIT_FULL_C("SERDES 1=",boardLaneConfig[1],2); |
| DEBUG_INIT_FULL_C("SERDES 2=",boardLaneConfig[2],2); |
| DEBUG_INIT_FULL_C("SERDES 3=",boardLaneConfig[3],2); |
| |
| /*------------------------------------------*/ |
| /* STEP - 1 Power Down PLL, RX, TX all phys */ |
| /*------------------------------------------*/ |
| for (serdesLaneNum = 0; serdesLaneNum < maxSerdesLanes; serdesLaneNum++) { |
| uiReg=MV_REG_READ(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum)); |
| uiReg &= ~(PHY_POWER_UP_PLL_MASK | PHY_POWER_UP_RX_MASK | PHY_POWER_UP_TX_MASK); |
| MV_REG_WRITE(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum),uiReg); |
| } |
| mvOsUDelay(10000); |
| |
| /*--------------------------------------------------------*/ |
| /* STEP - 2 Reset PHY and PIPE (Zx: Un-reset, Ax: Reset)*/ |
| /*--------------------------------------------------------*/ |
| for (serdesLaneNum = 0; serdesLaneNum < maxSerdesLanes; serdesLaneNum++) { |
| if (mvCtrlRevisionGet() >= UMC_A0) |
| resetPhyAndPipe(serdesLaneNum, MV_TRUE); |
| else |
| resetPhyAndPipe(serdesLaneNum, MV_FALSE); |
| } |
| |
| /*--------------------------------*/ |
| /* STEP - 3 Common PHYs Selectors */ |
| /*--------------------------------*/ |
| MV_REG_WRITE(COMMON_PHY_SELECTOR_REG, GetLaneSelectorConfig()); |
| |
| /*--------------------------------*/ |
| /* STEP - 4 Configuration 1 */ |
| /*--------------------------------*/ |
| for (serdesLaneNum = 0; serdesLaneNum < maxSerdesLanes; serdesLaneNum++) { |
| serdesLaneCfg = mvGetSerdesLaneCfg(serdesLaneNum); |
| if(serdesLaneCfg >= SERDES_LAST_UNIT) |
| return MV_ERROR; |
| uiReg = MV_REG_READ(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum)); |
| switch(serdesLaneCfg){ |
| case SERDES_UNIT_USB3: |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| ALP_A0_COMMON_PHY_CONFIG(uiReg); |
| #endif |
| uiReg |= PHY_MODE_MASK; /* PHY Mode = USB */ |
| uiReg |= PIPE_SELECT_MASK ; /* Select USB3_PEX */ |
| break; |
| case SERDES_UNIT_PEX: |
| uiReg |= PIPE_SELECT_MASK ; /* Select USB3_PEX */ |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| uiReg &= ~(PHY_MODE_MASK); /* PHY Mode = PEX */ |
| ALP_A0_COMMON_PHY_CONFIG(uiReg); |
| #endif |
| break; |
| case SERDES_UNIT_SGMII: |
| case SERDES_UNIT_SATA: |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| ALP_A0_COMMON_PHY_CONFIG(uiReg); |
| #endif |
| uiReg &= ~(PIPE_SELECT_MASK); /* Select SATA_SGMII */ |
| uiReg |= POWER_UP_IVREF_MASK; /* Power UP IVREF = Power Up */ |
| break; |
| case SERDES_UNIT_UNCONNECTED: |
| default: |
| break; |
| } |
| |
| /* Serdes speed config */ |
| tmp = getSerdesSpeedConfig(boardIdIndex, serdesLaneCfg); |
| uiReg &= ~(GEN_RX_MASK); /* SERDES RX Speed config */ |
| uiReg |= tmp<<GEN_RX_OFFS; |
| uiReg &= ~(GEN_TX_MASK); /* SERDES TX Speed config */ |
| uiReg |= tmp<<GEN_TX_OFFS; |
| MV_REG_WRITE(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum),uiReg); |
| } |
| |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| /*------------------------------------------*/ |
| /* STEP - 5 Unreset PHY and PIPE(only Ax)*/ |
| /*------------------------------------------*/ |
| if (mvCtrlRevisionGet() >= UMC_A0) |
| for (serdesLaneNum = 0; serdesLaneNum < maxSerdesLanes; serdesLaneNum++) |
| resetPhyAndPipe(serdesLaneNum, MV_FALSE); |
| #endif |
| /*----------------------------------------*/ |
| /* STEP - 6 COMPHY register configuration */ |
| /*----------------------------------------*/ |
| for (serdesLaneNum = 0; serdesLaneNum < maxSerdesLanes; serdesLaneNum++) { |
| serdesLaneCfg = mvGetSerdesLaneCfg(serdesLaneNum); |
| if(serdesLaneCfg >= SERDES_LAST_UNIT) |
| return MV_ERROR; |
| switch(serdesLaneCfg){ |
| case SERDES_UNIT_PEX: |
| MV_REG_WRITE(RESET_AND_CLOCK_CONTROL_REG(serdesLaneNum),0x25); /* Enable soft_reset*/ |
| MV_REG_WRITE(POWER_AND_PLL_CONTROL_REG(serdesLaneNum),0xFC60); /* PHY Mode = PEX */ |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| MV_REG_WRITE(MISCELLANEOUS_CONTROL0_REG(serdesLaneNum),0x6017); /* REFCLK SEL =0x0 (100Mhz) */ |
| MV_REG_WRITE(INTERFACE_REG1_REG(serdesLaneNum),0x1400); /* PHY_Gen_Max = 5G */ |
| MV_REG_WRITE(DIGITAL_LOOPBACK_ENABLE_REG(serdesLaneNum),0x400); /* SEL_Bits = 20-Bit */ |
| ALP_A0_RESET_DFE_SEQUENCE(serdesLaneNum); |
| #else |
| MV_REG_WRITE(KVCO_CALOBRATION_CONTROL_REG(serdesLaneNum),0x40); /* use_max_pll_rate=0x0, ext_force_cal_done=0x0 */ |
| #endif |
| MV_REG_WRITE(RESET_AND_CLOCK_CONTROL_REG(serdesLaneNum),0x24); /* Release soft_reset */ |
| break; |
| case SERDES_UNIT_USB3: |
| MV_REG_WRITE(RESET_AND_CLOCK_CONTROL_REG(serdesLaneNum),0x21); /* Enable soft_reset*/ |
| MV_REG_WRITE(POWER_AND_PLL_CONTROL_REG(serdesLaneNum),0xFCA0); /* PHY Mode = USB3 */ |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| MV_REG_WRITE(LANE_CONFIGURATION_4_REG(serdesLaneNum),0x13); /* Ref_Clk =100Mhz */ |
| MV_REG_WRITE(MISCELLANEOUS_CONTROL0_REG(serdesLaneNum),0x6017); /* REFCLK SEL =0x0 (100Mhz) */ |
| MV_REG_WRITE(INTERFACE_REG1_REG(serdesLaneNum),0x1400); /* PHY_Gen_Max = 5G */ |
| MV_REG_WRITE(DIGITAL_LOOPBACK_ENABLE_REG(serdesLaneNum),0x400); /* SEL_Bits = 20-Bit */ |
| ALP_A0_RESET_DFE_SEQUENCE(serdesLaneNum); |
| #else |
| MV_REG_WRITE(KVCO_CALOBRATION_CONTROL_REG(serdesLaneNum),0x40); /* use_max_pll_rate=0x0, ext_force_cal_done=0x0 */ |
| MV_REG_WRITE(GENERETION_2_SETTINGS_1_REG(serdesLaneNum),0x149); /* Mulitiple frequency setup */ |
| #endif |
| MV_REG_WRITE(RESET_AND_CLOCK_CONTROL_REG(serdesLaneNum),0x20); /* Release soft_reset */ |
| break; |
| case SERDES_UNIT_SATA: |
| MV_REG_WRITE(POWER_AND_PLL_CONTROL_REG(serdesLaneNum),0xFC01); /* PHY Mode = SATA */ |
| MV_REG_WRITE(MISCELLANEOUS_CONTROL0_REG(serdesLaneNum),0x6417); /* REFCLK SEL =0x1 (25Mhz) */ |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| MV_REG_WRITE(INTERFACE_REG1_REG(serdesLaneNum),0x1400); /* PHY_Gen_Max = 5G */ |
| MV_REG_WRITE(DIGITAL_LOOPBACK_ENABLE_REG(serdesLaneNum),0x400); /* SEL_Bits = 20-Bit */ |
| MV_REG_WRITE(DIGITAL_RESERVED0_REG(serdesLaneNum),0xE); /* Reg_sq_de_glitch_en */ |
| ALP_A0_RESET_DFE_SEQUENCE(serdesLaneNum); |
| #else |
| MV_REG_WRITE(RESERVED_46_REG(serdesLaneNum),0xFF00); |
| #endif |
| break; |
| case SERDES_UNIT_SGMII: |
| MV_REG_WRITE(POWER_AND_PLL_CONTROL_REG(serdesLaneNum),0xFC81); /* PHY Mode = SGMII */ /*moti need to change offset*/ |
| MV_REG_WRITE(DIGITAL_LOOPBACK_ENABLE_REG(serdesLaneNum),0x0); /* SEL_BITS = 0x0 (10-bits mode) */ |
| MV_REG_WRITE(MISCELLANEOUS_CONTROL0_REG(serdesLaneNum),0x6417); /* REFCLK SEL =0x1 (25Mhz) */ |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| MV_REG_WRITE(DIGITAL_RESERVED0_REG(serdesLaneNum),0xE); /* Reg_sq_de_glitch_en */ |
| ALP_A0_RESET_DFE_SEQUENCE(serdesLaneNum); |
| #else |
| MV_REG_WRITE(RESERVED_46_REG(serdesLaneNum),0xFF00); /* Enable soft_reset*/ |
| #endif |
| MV_REG_WRITE(PHY_ISOLATION_MODE_CONTROL_REG(serdesLaneNum),0x166); /* Set PHY_GEN_TX/RX to 1.25Gbps */ |
| break; |
| case SERDES_UNIT_UNCONNECTED: |
| default: |
| break; |
| } |
| } |
| |
| /*------------------------------------------*/ |
| /* STEP - 7 Power up PLL, RX, TX all phys */ |
| /*------------------------------------------*/ |
| for (serdesLaneNum = 0; serdesLaneNum < maxSerdesLanes; serdesLaneNum++) { |
| uiReg=MV_REG_READ(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum)); |
| uiReg &= ~PIN_TX_IDLE_MASK; |
| uiReg |= (PHY_POWER_UP_PLL_MASK | PHY_POWER_UP_RX_MASK | PHY_POWER_UP_TX_MASK); |
| MV_REG_WRITE(COMMON_PHY_CONFIGURATION1_REG(serdesLaneNum),uiReg); |
| } |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| mvOsUDelay(5000); |
| /*--------------------------------------------------------------------*/ |
| /* STEP - 8 (Only SGMII/SATA): WAIT for PHY Power up sequence to finish */ |
| /*--------------------------------------------------------------------*/ |
| for (serdesLaneNum = 0; serdesLaneNum < maxSerdesLanes; serdesLaneNum++) { |
| serdesLaneCfg = mvGetSerdesLaneCfg(serdesLaneNum); |
| if(serdesLaneCfg >= SERDES_LAST_UNIT) |
| return MV_ERROR; |
| switch(serdesLaneCfg){ |
| case SERDES_UNIT_SATA: |
| case SERDES_UNIT_SGMII: |
| uiReg = MV_REG_READ(COMMON_PHY_STATUS1_REG(serdesLaneNum)); |
| if ((uiReg & 0x6) != 0x6) { |
| DEBUG_INIT_S("Phy Power up did't finished\n"); |
| return MV_ERROR; |
| } |
| break; |
| case SERDES_UNIT_UNCONNECTED: |
| default: |
| break; |
| } |
| } |
| #endif |
| |
| /*----------------------------------------*/ |
| /* STEP - 9 PEX Only */ |
| /*----------------------------------------*/ |
| for (pexUnit = 0; pexUnit < 4; pexUnit++) { |
| if (boardLaneConfig[pexUnit] != SERDES_UNIT_PEX) |
| continue; |
| tmp = MV_REG_READ(PEX_CAPABILITIES_REG(pexUnit)); |
| DEBUG_RD_REG(PEX_CAPABILITIES_REG(pexUnit), tmp ); |
| tmp &= ~(0xf<<20); |
| tmp |= (0x4<<20); |
| MV_REG_WRITE(PEX_CAPABILITIES_REG(pexUnit),tmp); |
| DEBUG_WR_REG(PEX_CAPABILITIES_REG(pexUnit),tmp); |
| } |
| tmp = MV_REG_READ(SOC_CTRL_REG); |
| DEBUG_RD_REG(SOC_CTRL_REG, tmp); |
| tmp &= ~(0x03); |
| tmp |= 0x1<<PCIE0_ENABLE_OFFS; |
| if (boardLaneConfig[1] == SERDES_UNIT_PEX) |
| tmp |= 0x1<<PCIE1_ENABLE_OFFS; |
| MV_REG_WRITE(SOC_CTRL_REG, tmp); |
| DEBUG_WR_REG(SOC_CTRL_REG, tmp); |
| |
| /*----------------------------------------*/ |
| /* STEP - 10 PEX Only - support gen1/gen2 */ |
| /*----------------------------------------*/ |
| next_busno = 0; |
| mvOsDelay(150); |
| for (pexIf = 0; pexIf < 2; pexIf++) // only pexIf 0 on avanta_lp |
| { |
| if (boardLaneConfig[pexIf] != SERDES_UNIT_PEX) |
| continue; |
| tmp = MV_REG_READ(PEX_DBG_STATUS_REG(pexIf)); |
| DEBUG_RD_REG(PEX_DBG_STATUS_REG(pexIf), tmp); |
| first_busno = next_busno; |
| if ((tmp & 0x7f) == 0x7E) { |
| next_busno++; |
| tempPexReg = MV_REG_READ((PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CAPABILITY_REG))); |
| DEBUG_RD_REG((PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CAPABILITY_REG)),tempPexReg ); |
| tempPexReg &= (0xF); |
| if (tempPexReg == 0x2) { |
| tempReg = (MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG)) & 0xF0000) >> 16; |
| DEBUG_RD_REG(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_LINK_CTRL_STAT_REG),tempReg ); |
| /* check if the link established is GEN1 */ |
| if (tempReg == 0x1) { |
| mvPexLocalBusNumSet(pexIf, first_busno); |
| mvPexLocalDevNumSet(pexIf, 1); |
| DEBUG_INIT_FULL_S("PEX: pexIf "); |
| DEBUG_INIT_FULL_D(pexIf, 1); |
| DEBUG_INIT_FULL_S(", link is Gen1, checking the EP capability \n"); |
| /* link is Gen1, check the EP capability */ |
| addr = mvPexConfigRead(pexIf, first_busno, 0, 0, 0x34) & 0xFF; |
| DEBUG_INIT_FULL_C("mvPexConfigRead: return addr=0x%x", addr,4); |
| if (addr == 0xff) { |
| DEBUG_INIT_FULL_C("mvPexConfigRead: return 0xff -->PEX (%d): Detected No Link.", pexIf,1); |
| continue; |
| } |
| while ((mvPexConfigRead(pexIf, first_busno, 0, 0, addr) & 0xFF) != 0x10) { |
| addr = (mvPexConfigRead(pexIf, first_busno, 0, 0, addr) & 0xFF00) >> 8; |
| } |
| if ((mvPexConfigRead(pexIf, first_busno, 0, 0, addr + 0xC) & 0xF) >= 0x2) { |
| tmp = MV_REG_READ(PEX_LINK_CTRL_STATUS2_REG(pexIf)); |
| DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pexIf),tmp ); |
| tmp &=~(BIT0 | BIT1); |
| tmp |= BIT1; |
| MV_REG_WRITE(PEX_LINK_CTRL_STATUS2_REG(pexIf),tmp); |
| DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pexIf),tmp); |
| tmp = MV_REG_READ(PEX_CTRL_REG(pexIf)); |
| DEBUG_RD_REG(PEX_CTRL_REG(pexIf), tmp ); |
| tmp |= BIT10; |
| MV_REG_WRITE(PEX_CTRL_REG(pexIf),tmp); |
| DEBUG_WR_REG(PEX_CTRL_REG(pexIf),tmp); |
| mvOsUDelay(10000);/* We need to wait 10ms before reading the PEX_DBG_STATUS_REG in order not to read the status of the former state*/ |
| DEBUG_INIT_FULL_S("PEX: pexIf "); |
| DEBUG_INIT_FULL_D(pexIf, 1); |
| DEBUG_INIT_FULL_S(", Link upgraded to Gen2 based on client cpabilities \n"); |
| } else { |
| DEBUG_INIT_FULL_S("PEX: pexIf "); |
| DEBUG_INIT_FULL_D(pexIf, 1); |
| DEBUG_INIT_FULL_S(", remains Gen1\n"); |
| } |
| } |
| } |
| } else { |
| DEBUG_INIT_FULL_S("PEX: pexIf "); |
| DEBUG_INIT_FULL_D(pexIf, 1); |
| DEBUG_INIT_FULL_S(", detected no link\n"); |
| } |
| } |
| |
| /*------------------------------*/ |
| /* Step 11: update pex DEVICE ID*/ |
| /*------------------------------*/ |
| { |
| MV_U32 devId; |
| MV_U32 ctrlMode = mvCtrlModelGet(); |
| for (pexIf = 0; pexIf < 2; pexIf++) { |
| if (boardLaneConfig[pexIf] != SERDES_UNIT_PEX) |
| continue; |
| devId = MV_REG_READ(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_DEVICE_AND_VENDOR_ID)); |
| devId &= 0xFFFF; |
| devId |= ((ctrlMode << 16) & 0xffff0000); |
| MV_REG_WRITE(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_DEVICE_AND_VENDOR_ID), devId); |
| } |
| DEBUG_INIT_FULL_S("Update PEX Device ID 0x"); |
| DEBUG_INIT_FULL_D(ctrlMode,4); |
| DEBUG_INIT_FULL_S("\n"); |
| } |
| |
| /* Step 8: Configure PON on lane3 */ |
| mvPONPhyInit(); |
| |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| mvUsb2PhyInit(0); |
| mvUsb2PhyInit(1); |
| #endif |
| |
| DEBUG_INIT_S(ENDED_OK); |
| DEBUG_INIT_S("\n"); |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvPexConfigRead - Read from configuration space |
| * |
| * DESCRIPTION: |
| * This function performs a 32 bit read from PEX configuration space. |
| * It supports both type 0 and type 1 of Configuration Transactions |
| * (local and over bridge). In order to read from local bus segment, use |
| * bus number retrieved from mvPexLocalBusNumGet(). Other bus numbers |
| * will result configuration transaction of type 1 (over bridge). |
| * |
| * INPUT: |
| * pexIf - PEX interface number. |
| * bus - PEX segment bus number. |
| * dev - PEX device number. |
| * func - Function number. |
| * regOffs - Register offset. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * 32bit register data, 0xffffffff on error |
| * |
| *******************************************************************************/ |
| MV_U32 mvPexConfigRead(MV_U32 pexIf, MV_U32 bus, MV_U32 dev, MV_U32 func, MV_U32 regOff) |
| { |
| MV_U32 pexData = 0; |
| MV_U32 localDev, localBus; |
| MV_U32 pexStatus; |
| |
| pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf)); |
| |
| localDev = ((pexStatus & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS); |
| localBus = ((pexStatus & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS); |
| |
| |
| /* in PCI Express we have only one device number */ |
| /* and this number is the first number we encounter |
| else that the localDev */ |
| /* spec pex define return on config read/write on any device */ |
| if (bus == localBus) { |
| if (localDev == 0) { |
| /* if local dev is 0 then the first number we encounter |
| after 0 is 1 */ |
| if ((dev != 1) && (dev != localDev)) |
| return MV_ERROR; |
| } else { |
| /* if local dev is not 0 then the first number we encounter |
| is 0 */ |
| |
| if ((dev != 0) && (dev != localDev)) |
| return MV_ERROR; |
| } |
| } |
| /* Creating PEX address to be passed */ |
| pexData = (bus << PXCAR_BUS_NUM_OFFS); |
| pexData |= (dev << PXCAR_DEVICE_NUM_OFFS); |
| pexData |= (func << PXCAR_FUNC_NUM_OFFS); |
| pexData |= (regOff & PXCAR_REG_NUM_MASK); /* lgacy register space */ |
| /* extended register space */ |
| pexData |= (((regOff & PXCAR_REAL_EXT_REG_NUM_MASK) >> |
| PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS); |
| |
| pexData |= PXCAR_CONFIG_EN; |
| |
| /* Write the address to the PEX configuration address register */ |
| MV_REG_WRITE(PEX_CFG_ADDR_REG(pexIf), pexData); |
| |
| /* In order to let the PEX controller absorbed the address of the read */ |
| /* transaction we perform a validity check that the address was written */ |
| if (pexData != MV_REG_READ(PEX_CFG_ADDR_REG(pexIf))) |
| return MV_ERROR; |
| |
| /* cleaning Master Abort */ |
| MV_REG_BIT_SET(PEX_CFG_DIRECT_ACCESS(pexIf, PEX_STATUS_AND_COMMAND), PXSAC_MABORT); |
| /* Read the Data returned in the PEX Data register */ |
| pexData = MV_REG_READ(PEX_CFG_DATA_REG(pexIf)); |
| |
| |
| DEBUG_INIT_FULL_C(" --> ", pexData,4); |
| |
| return pexData; |
| |
| } |
| /******************************************************************************* |
| * mvPexLocalBusNumSet - Set PEX interface local bus number. |
| * |
| * DESCRIPTION: |
| * This function sets given PEX interface its local bus number. |
| * Note: In case the PEX interface is PEX-X, the information is read-only. |
| * |
| * INPUT: |
| * pexIf - PEX interface number. |
| * busNum - Bus number. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_NOT_ALLOWED in case PEX interface is PEX-X. |
| * MV_BAD_PARAM on bad parameters , |
| * otherwise MV_OK |
| * |
| *******************************************************************************/ |
| MV_STATUS mvPexLocalBusNumSet(MV_U32 pexIf, MV_U32 busNum) |
| { |
| MV_U32 pexStatus; |
| |
| if (busNum >= MAX_PEX_BUSSES) { |
| DEBUG_INIT_C("mvPexLocalBusNumSet: ERR. bus number illigal %d\n", busNum,4); |
| return MV_ERROR; |
| } |
| |
| pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf)); |
| |
| pexStatus &= ~PXSR_PEX_BUS_NUM_MASK; |
| |
| pexStatus |= (busNum << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK; |
| |
| MV_REG_WRITE(PEX_STATUS_REG(pexIf), pexStatus); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvPexLocalDevNumSet - Set PEX interface local device number. |
| * |
| * DESCRIPTION: |
| * This function sets given PEX interface its local device number. |
| * Note: In case the PEX interface is PEX-X, the information is read-only. |
| * |
| * INPUT: |
| * pexIf - PEX interface number. |
| * devNum - Device number. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_NOT_ALLOWED in case PEX interface is PEX-X. |
| * MV_BAD_PARAM on bad parameters , |
| * otherwise MV_OK |
| * |
| *******************************************************************************/ |
| MV_STATUS mvPexLocalDevNumSet(MV_U32 pexIf, MV_U32 devNum) |
| { |
| MV_U32 pexStatus; |
| |
| pexStatus = MV_REG_READ(PEX_STATUS_REG(pexIf)); |
| |
| pexStatus &= ~PXSR_PEX_DEV_NUM_MASK; |
| |
| pexStatus |= (devNum << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK; |
| |
| MV_REG_WRITE(PEX_STATUS_REG(pexIf), pexStatus); |
| |
| return MV_OK; |
| } |
| /******************************************************************************* |
| * mvPexAgentReset - Release PEX agent reset. |
| * |
| * DESCRIPTION: |
| * This function is relevant for RD6650 and RD6660 |
| * it configure the relevant MPP to be GPIO out at HIGH state |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * otherwise MV_OK |
| * |
| *******************************************************************************/ |
| MV_STATUS mvPexAgentReset() |
| { |
| MV_U32 uiReg, reNum, bitNum; |
| MV_U32 boardId = mvBoardIdGet(); |
| |
| if ((boardId == RD_6650_ID) || (boardId == RD_6660_ID)) { |
| if (boardId == RD_6650_ID) { |
| reNum = 0; |
| bitNum = 0x20000000; |
| } else if (boardId == RD_6660_ID) { |
| reNum = 2; |
| bitNum = 0x4; |
| } |
| uiReg = MV_REG_READ(GPIO_DATA_OUT_ENABLE_REG(reNum)); |
| uiReg &= ~(bitNum); |
| MV_REG_WRITE(GPIO_DATA_OUT_ENABLE_REG(reNum), uiReg); |
| uiReg = MV_REG_READ(GPIO_DATA_OUT_REG(reNum)); |
| uiReg |= bitNum; |
| MV_REG_WRITE(GPIO_DATA_OUT_REG(reNum), uiReg); |
| } |
| return MV_OK; |
| } |
| |
| #ifndef CONFIG_ALP_A375_ZX_REV |
| /* USB Phy init specific for 40nm LP (88F6660) */ |
| MV_STATUS mvUsb2PhyInit(MV_U32 dev) |
| { |
| MV_U32 regVal; |
| |
| /*Set USB PHY config selector to USB 2.0*/ |
| regVal = MV_REG_READ(USB_CLUSTER_CONTROL_REG); |
| regVal &= ~0x1; |
| MV_REG_WRITE(USB_CLUSTER_CONTROL_REG, regVal); |
| |
| /* set LPF_COEF parameter: configure Rx PLL tolerance to ppm deviation (change to 2000ppm) */ |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 8)); |
| regVal = (regVal & (~0xC)) | (8); |
| MV_REG_WRITE(MV_USB2_PHY_CHANNEL_REG(dev, 8), regVal); |
| |
| /* Set the PLL clocks to 450 MHz. Our ref clock is 25 Mhz so to |
| * achieve 480 MHz we set divider = 5 multiplier = 96 */ |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 1)); |
| regVal = (regVal & (~0x1FF)) | (96); |
| regVal = (regVal & (~0x1E00)) | (5 << 9); |
| MV_REG_WRITE(MV_USB2_PHY_CHANNEL_REG(dev, 1), regVal); |
| |
| /* Turn on the PLL and wait 200 usec */ |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 2)); |
| regVal |= BIT13; |
| MV_REG_WRITE(MV_USB2_PHY_CHANNEL_REG(dev, 2), regVal); |
| mvOsUDelay(2); |
| |
| /* Enable the analog part of the PHY */ |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 13)); |
| regVal |= BIT14; |
| MV_REG_WRITE(MV_USB2_PHY_CHANNEL_REG(dev, 13), regVal); |
| mvOsUDelay(2); |
| |
| /* Turn on the VCO calibration */ |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 2)); |
| regVal |= BIT2; |
| MV_REG_WRITE(MV_USB2_PHY_CHANNEL_REG(dev, 2), regVal); |
| mvOsUDelay(10); |
| |
| /* Perform Impedance calibration for 40 usec */ |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 4)); |
| regVal |= BIT13; |
| MV_REG_WRITE(MV_USB2_PHY_CHANNEL_REG(dev, 4), regVal); |
| mvOsUDelay(1); |
| |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 4)); |
| regVal &= ~BIT13; |
| MV_REG_WRITE(MV_USB2_PHY_CHANNEL_REG(dev, 4), regVal); |
| mvOsUDelay(400); |
| |
| /* Check if the PHY is ready */ |
| regVal = MV_REG_READ(MV_USB2_PHY_CHANNEL_REG(dev, 2)); |
| if ((regVal & BIT15) == 0) { |
| DEBUG_INIT_S("Error: USB2 UTMI PHY not ready\n"); |
| return MV_NOT_READY; |
| } |
| |
| DEBUG_INIT_S("USB2 UTMI PHY initialized succesfully\n"); |
| |
| return MV_OK;} |
| #endif |
| |
| MV_STATUS mvPONPhyInit() |
| { |
| /*TBD - make the sequence clear*/ |
| MV_REG_WRITE(0x184f4, 0x53000238); |
| MV_REG_WRITE(0x184f4, 0x53000210); |
| MV_REG_WRITE(0x184f4, 0x53001210); |
| MV_REG_WRITE(0x18754, 0x8); |
| MV_REG_WRITE(0x18754, 0xA); |
| MV_REG_WRITE(0x18754, 0xE); |
| MV_REG_WRITE(0x32004, 0xf400); |
| MV_REG_WRITE(0x32144, 0x104); |
| MV_REG_WRITE(0x320f4, 0x400); |
| MV_REG_WRITE(0x3208c, 0x0000); |
| MV_REG_WRITE(0x184f4, 0x53001217); |
| MV_REG_WRITE(0x184f4, 0x52001247); |
| MV_REG_WRITE(0x184f4, 0x52001207); |
| MV_REG_WRITE(0x32098, 0x0); |
| |
| return MV_OK; |
| } |