/********************************************************************************
|
Copyright (C) 2016 Marvell International Ltd.
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
*******************************************************************************/
|
|
#include <Library/ArmLib.h>
|
#include <Library/ArmPlatformLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/PcdLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
#include <Library/IoLib.h>
|
|
#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;
|
}
|