/******************************************************************************** Copyright (C) 2016 Marvell International Ltd. SPDX-License-Identifier: BSD-2-Clause-Patent *******************************************************************************/ #include #include #include #include #include #include #define MPP_PIN_VAL(pin,func) (((func) & 0xf) << ((pin) * 4)) #define MPP_MAX_REGS 8 #define MPP_PINS_PER_REG 8 #define PCD_PINS_PER_GROUP 10 #define SD_MMC_PHY_AP_MPP_OFFSET 0x100 #define SD_MMC_PHY_CP0_MPP_OFFSET 0x424 #define MPP_ON_SDPHY_ENABLE (1 << 0) #define MAX_CHIPS 4 #define GET_PCD_PTR(id,num) PcdGetPtr(PcdChip##id##MppSel##num) #define GET_PIN_COUNT(id) PcdGet32(PcdChip##id##MppPinCount) #define GET_BASE(id) PcdGet64(PcdChip##id##MppBaseAddress) #define GET_REV_FLAG(id) PcdGetBool(PcdChip##id##MppReverseFlag) /* We get chip number */ #define GetMppPcd(id) { \ PinCount[id] = GET_PIN_COUNT(id); \ MppRegPcd[id][7] = GET_PCD_PTR(id,7); \ MppRegPcd[id][6] = GET_PCD_PTR(id,6); \ MppRegPcd[id][5] = GET_PCD_PTR(id,5); \ MppRegPcd[id][4] = GET_PCD_PTR(id,4); \ MppRegPcd[id][3] = GET_PCD_PTR(id,3); \ MppRegPcd[id][2] = GET_PCD_PTR(id,2); \ MppRegPcd[id][1] = GET_PCD_PTR(id,1); \ MppRegPcd[id][0] = GET_PCD_PTR(id,0); \ BaseAddr[id] = GET_BASE(id); \ ReverseFlag[id] = GET_REV_FLAG(id); \ } STATIC VOID SetRegisterValue ( UINT8 RegCount, UINT8 MppRegPcd[][MPP_PINS_PER_REG], UINTN BaseAddr, BOOLEAN ReverseFlag ) { UINT32 i, j, CtrlVal, CtrlMask, PinIndex; INTN Sign; Sign = ReverseFlag ? -1 : 1; for (i = 0; i < RegCount; i++) { CtrlVal = 0; CtrlMask = 0; for (j = 0; j < MPP_PINS_PER_REG; j++) { PinIndex = 7 * (UINTN)ReverseFlag + j * Sign; if (MppRegPcd[i][PinIndex] != 0xff) { CtrlVal |= MPP_PIN_VAL(PinIndex, MppRegPcd[i][PinIndex]); CtrlMask |= MPP_PIN_VAL(PinIndex, 0xf); } } MmioAndThenOr32 (BaseAddr + 4 * i * Sign, ~CtrlMask, CtrlVal); } } STATIC /* Transform PCD MPP group format into hardware register format */ UINT8 PcdToMppRegs ( UINTN PinCount, UINT8 **MppRegPcd, UINT8 MppRegPcdTmp[][MPP_PINS_PER_REG] ) { UINT8 PcdGroupCount, MppRegCount; UINTN i, j, k, l; if (PinCount == 0) { return 0; } PcdGroupCount = PinCount / PCD_PINS_PER_GROUP; if ((PinCount % PCD_PINS_PER_GROUP) != 0) { PcdGroupCount += 1; } MppRegCount = PinCount / MPP_PINS_PER_REG; if ((PinCount % MPP_PINS_PER_REG) != 0) { MppRegCount += 1; } /* Fill temporary table with data from PCD groups in HW format */ for (i = 0; i < PcdGroupCount; i++) { for (j = 0; j < PCD_PINS_PER_GROUP; j++) { k = (PCD_PINS_PER_GROUP * i + j) / MPP_PINS_PER_REG; l = (PCD_PINS_PER_GROUP * i + j) % MPP_PINS_PER_REG; MppRegPcdTmp[k][l] = (UINT8)MppRegPcd[i][j]; } } return MppRegCount; } STATIC VOID SetSdMmcPhyMpp ( UINTN BaseAddr, UINT32 Index ) { UINTN Size, Offset; UINT8 *Ptr; UINT32 Reg; Size = PcdGetSize(PcdPciESdhci); Ptr = (UINT8 *) PcdGetPtr(PcdPciESdhci); if (Ptr == NULL || Index >= Size) { return; } /* Check if SDHCI controller is enabled on the HW block */ if (Ptr[Index] != 1) { return; } /* Choose adequate Offset */ switch (Index) { case 0: Offset = SD_MMC_PHY_AP_MPP_OFFSET; break; default: Offset = SD_MMC_PHY_CP0_MPP_OFFSET; break; } /* * If there is SDHCI controller on platform, connect SD/MMC PHY to * SD/MMC controller insted of using it as MPP multiplexer */ Reg = MmioRead32 (BaseAddr + Offset); Reg &= ~MPP_ON_SDPHY_ENABLE; MmioWrite32 (BaseAddr + Offset, Reg); } EFI_STATUS MppInitialize ( ) { UINTN BaseAddr[MAX_CHIPS], PinCount[MAX_CHIPS], RegCount; BOOLEAN ReverseFlag[MAX_CHIPS]; UINT8 *MppRegPcd[MAX_CHIPS][MPP_MAX_REGS]; UINT32 i, ChipCount; UINT8 TmpMppValue[MPP_MAX_REGS][MPP_PINS_PER_REG]; ChipCount = PcdGet32 (PcdMppChipCount); /* Read all needed PCD for MPP configuration */ GetMppPcd(0); GetMppPcd(1); GetMppPcd(2); GetMppPcd(3); for (i = 0; i < MAX_CHIPS; i++) { if (i == ChipCount) break; RegCount = PcdToMppRegs (PinCount[i], MppRegPcd[i], TmpMppValue); SetRegisterValue (RegCount, TmpMppValue, BaseAddr[i], ReverseFlag[i]); /* * eMMC PHY IP has its own MPP configuration. */ SetSdMmcPhyMpp (BaseAddr[i], i); } return EFI_SUCCESS; }