Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qcom/FdtTargetMmcSdhciLib: Additional FDT parsing #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 136 additions & 12 deletions Qcom/Library/FdtTargetMmcSdhciLib/QcomTargetMmcSdhciLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ VOID LibQcomTargetMmcSdhciInit(INIT_SLOT_CB InitSlot)
FindNodeStatus = FdtClient->FindNextCompatibleNode (FdtClient, "qcom,sdhci-msm", Node, &Node))
{
struct mmc_config_data config = {0};
INT32 TmpNode;
CONST UINT32 *FdtU32;
CONST CHAR8 *FdtChar8;
CONST CHAR8 *TmpChar8;
CONST UINT32 *FdtPinCtrlArray;
UINTN NumPinCtrls;
UINT32 tlmm_reg = 0;
Expand All @@ -41,6 +43,8 @@ VOID LibQcomTargetMmcSdhciInit(INIT_SLOT_CB InitSlot)
UINT32 cmd_pull_off;
UINT32 data_pull_off;
UINT32 rclk_pull_off;
UINT32 InterruptCells;
UINT32 InterruptOffset;
UINT8 clk_drv;
UINT8 cmd_drv;
UINT8 dat_drv;
Expand Down Expand Up @@ -100,39 +104,141 @@ VOID LibQcomTargetMmcSdhciInit(INIT_SLOT_CB InitSlot)

// get regs
Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg", (CONST VOID **)&FdtU32, &PropertySize);
if (EFI_ERROR (Status) || PropertySize != sizeof(*FdtU32)*4) {
if (EFI_ERROR (Status)) {
DEBUG((DEBUG_INFO, "FDT read error: \"reg\"\n"));
continue;
}
// get reg names
Status = FdtClient->GetNodeProperty(FdtClient, Node, "reg-names", (CONST VOID **)&FdtChar8, NULL);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_INFO, "FDT read error: \"reg-names\"\n"));
continue;
}

config.sdhc_base = 0;
config.pwrctl_base = 0;

// get base addresses
config.sdhc_base = SwapBytes32 (FdtU32[0]);
config.pwrctl_base = SwapBytes32 (FdtU32[2]);
Index = 0;
for (TmpChar8 = FdtChar8; *TmpChar8; TmpChar8 += 1 + AsciiStrLen(TmpChar8)) {
if (AsciiStrnCmp("hc_mem", TmpChar8, 6) == 0) {
config.sdhc_base = SwapBytes32(FdtU32[Index * 2]);
}
else if (AsciiStrnCmp("core_mem", TmpChar8, 8) == 0) {
config.pwrctl_base = SwapBytes32(FdtU32[Index * 2]);
}
else {
DEBUG((DEBUG_INFO, "Unhandled register: \"%a\" = 0x%08X\n", TmpChar8, SwapBytes32(FdtU32[Index * 2])));
}
//not handled: "cmdq_mem"
Index++;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have to 0-check sdhc_base and pwrctl_base here

if (config.sdhc_base == 0) {
DEBUG((DEBUG_INFO, "sdhc_base cannot be NULL\n"));
continue;
}

if (config.pwrctl_base == 0) {
DEBUG((DEBUG_INFO, "pwrctl_base cannot be NULL\n"));
continue;
}

DEBUG ((DEBUG_INFO, "sdhc_base: %x\n", config.sdhc_base));
DEBUG ((DEBUG_INFO, "pwrctl_base: %x\n", config.pwrctl_base));

// find interrupt parent
for (TmpNode = Node; !FdtClient->HasNodeProperty(FdtClient, TmpNode, "interrupt-parent"); Status = FdtClient->GetParentNode(FdtClient, TmpNode, &TmpNode)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that loop needed? I think that linux code only checks the current node and the root node.
Correct me if I'm wrong.

if (EFI_ERROR(Status))
break;
}
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_INFO, "Could not find interrupt-parent\n"));
continue;
}

// get PHandle to interrupt-parent
Status = FdtClient->GetNodeProperty(FdtClient, TmpNode, "interrupt-parent", (CONST VOID **)&FdtU32, &PropertySize);
if (EFI_ERROR(Status) || PropertySize != sizeof(*FdtU32)) {
DEBUG((DEBUG_INFO, "FDT read error: \"interrupt-parent\"\n"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing "continue"

continue;
}

// get actual interrupt-parent node
Status = FdtClient->FindNodeByPHandle(FdtClient, SwapBytes32(*FdtU32), &TmpNode);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_INFO, "FDT node not accessible\n"));
continue;
}

// read #interrupt-cells
Status = FdtClient->GetNodeProperty(FdtClient, TmpNode, "#interrupt-cells", (CONST VOID **)&FdtU32, &PropertySize);
if (EFI_ERROR(Status) || PropertySize != sizeof(*FdtU32)) {
DEBUG((DEBUG_INFO, "FDT read error: \"#interrupt-cells\"\n"));
continue;
}
InterruptCells = SwapBytes32(*FdtU32);

switch (InterruptCells) {
case 1:
InterruptOffset = 0;
break;
case 3:
InterruptOffset = 1;
break;
default:
DEBUG((DEBUG_INFO, "#interrupt-cells value not supported: 0x%08X\n", InterruptCells));
continue;
}

DEBUG((DEBUG_INFO, "#interrupt-cells: 0x%08X; offset: 0x%08X\n", InterruptCells, InterruptOffset));

// get interrupts
Status = FdtClient->GetNodeProperty (FdtClient, Node, "interrupts", (CONST VOID **)&FdtU32, &PropertySize);
if (EFI_ERROR (Status) || PropertySize != sizeof(*FdtU32)*6) {
if (EFI_ERROR (Status) || (PropertySize/sizeof(*FdtU32) % InterruptCells) != 0) {
DEBUG((DEBUG_INFO, "FDT read error \"interrupts\"\n"));
continue;
}

// get interrupt-names
Status = FdtClient->GetNodeProperty(FdtClient, Node, "interrupt-names", (CONST VOID **)&FdtChar8, NULL);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_INFO, "FDT read error: \"interrupt-names\"\n"));
}

config.pwr_irq = 0;

// get power irq
config.pwr_irq = PcdGet64(PcdGicSpiStart) + SwapBytes32 (FdtU32[4]);
DEBUG ((DEBUG_INFO, "pwr_irq: %d\n", config.pwr_irq));
Index = 0;
for (TmpChar8 = FdtChar8; *TmpChar8; TmpChar8 += 1 + AsciiStrLen(TmpChar8)) {
if (AsciiStrnCmp(TmpChar8, "pwr_irq", 7) == 0) {
config.pwr_irq = PcdGet64(PcdGicSpiStart) + SwapBytes32(FdtU32[(Index * InterruptCells) + InterruptOffset]);
}
else {
DEBUG((DEBUG_INFO, "Unhandled interrupt: \"%a\" = 0x%08X\n", TmpChar8, SwapBytes32(FdtU32[(Index * InterruptCells) + InterruptOffset])));
}
// not handled: hc_irq, status_irq
Index++;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have to 0-check pwr_irq here.

if (config.pwr_irq == 0) {
DEBUG((DEBUG_INFO, "pwr_irq cannot be NULL\n"));
continue;
}

DEBUG ((DEBUG_INFO, "pwr_irq: %d\n", config.pwr_irq));
config.hs200_support = 0;
config.hs400_support = 0;
config.use_io_switch = 0;

// get speed mode
Status = FdtClient->GetNodeProperty(FdtClient, Node, "qcom,bus-speed-mode", (CONST VOID **)&FdtChar8, &PropertySize);
if (!EFI_ERROR (Status)) {
for (FdtChar8 = FdtChar8; FdtChar8 < FdtChar8 + PropertySize && *FdtChar8;
FdtChar8 += 1 + AsciiStrLen (FdtChar8)) {
if (AsciiStrnCmp ("HS400", FdtChar8, 5) == 0) {
for (TmpChar8 = FdtChar8; *TmpChar8; TmpChar8 += 1 + AsciiStrLen(TmpChar8)) {
if (AsciiStrnCmp ("HS400", TmpChar8, 5) == 0) {
config.hs400_support = 1;
}
else if (AsciiStrnCmp ("HS200", FdtChar8, 5) == 0) {
else if (AsciiStrnCmp ("HS200", TmpChar8, 5) == 0) {
config.hs200_support = 1;
}
}
Expand Down Expand Up @@ -170,12 +276,30 @@ VOID LibQcomTargetMmcSdhciInit(INIT_SLOT_CB InitSlot)
break;
}

// switch to config subnode if it exists (new FDT format)
Status = FdtClient->FindSubNode(FdtClient, PinCtrlNode, &TmpNode);
if (!EFI_ERROR(Status)) {
DEBUG((DEBUG_INFO, "Found config subnode\n"));
PinCtrlNode = TmpNode;
}

// get label
Status = FdtClient->GetNodeProperty(FdtClient, PinCtrlParentNode, "label", (CONST VOID **)&FdtChar8, NULL);
if (EFI_ERROR (Status)) {
IsError = TRUE;
break;
Status = FdtClient->GetNodeProperty(FdtClient, PinCtrlNode, "pins", (CONST VOID **)&FdtChar8, NULL);
if (EFI_ERROR(Status)) {
DEBUG((DEBUG_INFO, "FDT read error: cannot get node label\n"));
IsError = TRUE;
break;
}
}

/*
* If devices with config for multiple SDC pins in the same node appear,
* loop through them here, and handle all of them properly instead of
* ignoring all but the first one
*/

DEBUG((DEBUG_ERROR, "label: %a\n", FdtChar8));

// get pull
Expand Down