Skip to content

Commit

Permalink
Feat: Support for specific overlay triggers based on a combination of…
Browse files Browse the repository at this point in the history
… EEPROM IDs and exact device tree paths of those EEPROMS

The current behaviour of NV UEFI is that if any EEPROM product ID from any I2C bus matches any of the ids listed in board_config, the overlay is triggered. Effectively all EEPROMs add to a global list of Board IDs, regardless of which device they actually represent. This means a single camera plugged into a single port would make the whole board be treated as matching that camera.

This is a problem, since:
* it prevents plugging different camera models into different ports and have them work without re-flashing the whole device (any CSI camera port change requires a reflash, instead of supporting various models automatically, and having the interposer board partly populated)
* Causes the kernel to create devnodes for devices that don't exist, (causing preventable error logs in nvargus-daemon)

This PR adds support for a new, more controlled overlay behaviour via the new (optional) eeprom-dt-paths board_config property, where an overlay can be triggered based on a match of the ID in the EEPROM and a match of the exact I2C device tree path the EEPROM product ID came from. (Old behaviour with existing board_configs should be unchanged). This means that the presence of a single camera no longer adds this Product ID to the global list of board IDs, but that you can selectively apply an overlay only when a specific ID was read from a specific device tree path (i.e. individual CSI cameras can be enumerated during boot and the kernel never creates devnodes for missing devices).

```
board_config {
	ids = "framos-imx462-0";
	eeprom-dt-paths = "/i2c@3180000/pca9547@70/i2c@1/eeprom@55", "/i2c@3180000/pca9547@70/i2c@1/eeprom@56";
	sw-modules = "kernel";
};
```

Signed-off-by: Anonymous <[email protected]>
  • Loading branch information
Anonymous committed May 19, 2023
1 parent dada7ca commit 4c1473e
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 33 deletions.
9 changes: 9 additions & 0 deletions Silicon/NVIDIA/Drivers/EepromDxe/Eeprom.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ EepromDxeDriverBindingStart (
TEGRA_EEPROM_BOARD_INFO *CvmBoardInfo;
TEGRA_EEPROM_BOARD_INFO *IdBoardInfo;
BOOLEAN SkipEepromCRC;
INT32 DeviceTreePathLen;

NVIDIA_TEGRA_I2C_SLAVE_DEVICE_TREE_NODE_PROTOCOL *I2cSlaveDeviceTreeNode = NULL;
NVIDIA_DEVICE_TREE_NODE_PROTOCOL EepromDeviceTreeNode;
Expand Down Expand Up @@ -424,6 +425,14 @@ EepromDxeDriverBindingStart (
goto ErrorExit;
}

DeviceTreePathLen = fdt_get_path(EepromDeviceTreeNode.DeviceTreeBase, EepromDeviceTreeNode.NodeOffset, IdBoardInfo->EepromDeviceTreePath, MAX_I2C_DEVICE_DT_PATH);

if (DeviceTreePathLen != 0) {
DEBUG((DEBUG_ERROR, "%a: Failed to get device tree path length for I2c sub-device 0x%lx on I2c Bus 0x%lx (error: %d).\n", __FUNCTION__, I2cIo->DeviceIndex >> 16, I2cIo->DeviceIndex & 0xFFFF, DeviceTreePathLen));
} else {
DEBUG ((DEBUG_INFO, "%a: Starting (TEGRA_PLATFORM_SILICON) Bus %x Device %x %a\r\n", __FUNCTION__, I2cIo->DeviceIndex >> 16, I2cIo->DeviceIndex & 0xFFFF, IdBoardInfo->EepromDeviceTreePath));
}

Status = PopulateEepromData (RawData, IdBoardInfo);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Eeprom data population failed(%r)\r\n", Status));
Expand Down
2 changes: 2 additions & 0 deletions Silicon/NVIDIA/Include/Protocol/Eeprom.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define NVIDIA_EEPROM_BOARD_ID_PREFIX "699"
#define CUSTOMER_EEPROM_BOARD_ID_MAGIC 0xcc

#define MAX_I2C_DEVICE_DT_PATH 64
/**
* @brief The Product Part Number structure that is embedded into
* EEPROM layout structure
Expand Down Expand Up @@ -224,6 +225,7 @@ typedef struct {
CHAR8 SerialNumber[TEGRA_SERIAL_NUM_LEN];
UINT8 MacAddr[NET_ETHER_ADDR_LEN];
UINT8 NumMacs;
CHAR8 EepromDeviceTreePath[MAX_I2C_DEVICE_DT_PATH];
} TEGRA_EEPROM_BOARD_INFO;

static inline
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ ReadBoardInfo (

BoardInfo->IdCount = ProtocolCount;
BoardInfo->ProductIds = (EEPROM_PART_NUMBER *)AllocateZeroPool (BoardInfo->IdCount * sizeof (EEPROM_PART_NUMBER));
BoardInfo->EepromDeviceTreePaths = (CHAR8 **)AllocateZeroPool (BoardInfo->IdCount * sizeof (CHAR8 *));

for (i = 0; i < ProtocolCount; i++) {
Status = gBS->HandleProtocol (
Expand All @@ -81,6 +82,7 @@ ReadBoardInfo (
}

CopyMem ((VOID *)(&BoardInfo->ProductIds[i]), (VOID *)&Eeprom->ProductId, TEGRA_PRODUCT_ID_LEN);
BoardInfo->EepromDeviceTreePaths[i] = Eeprom->EepromDeviceTreePath;
}

if (BoardInfo->IdCount == 0) {
Expand All @@ -90,7 +92,7 @@ ReadBoardInfo (

DEBUG ((DEBUG_INFO, "Eeprom product Ids: \n"));
for (i = 0; i < BoardInfo->IdCount; i++) {
DEBUG ((DEBUG_INFO, "%d. %a \n", i+1, BoardInfo->ProductIds[i]));
DEBUG ((DEBUG_INFO, "%d. %a (%a)\n", i+1, BoardInfo->ProductIds[i], BoardInfo->EepromDeviceTreePaths[i]));
}

return EFI_SUCCESS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ ReadBoardInfo (
BoardInfo->FuseCount = TegraBoardInfo->FuseCount;
BoardInfo->IdCount = 2; /*CVM and CVB*/
BoardInfo->ProductIds = (EEPROM_PART_NUMBER *)AllocateZeroPool (BoardInfo->IdCount * sizeof (EEPROM_PART_NUMBER));
BoardInfo->EepromDeviceTreePaths = (CHAR8 **)AllocateZeroPool (BoardInfo->IdCount * sizeof (CHAR8*));
CopyMem ((VOID *)&BoardInfo->ProductIds[0], (VOID *)TegraBoardInfo->CvmProductId, TEGRA_PRODUCT_ID_LEN);
CopyMem ((VOID *)&BoardInfo->ProductIds[1], (VOID *)TegraBoardInfo->CvbProductId, TEGRA_PRODUCT_ID_LEN);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ typedef enum {
} MATCH_OPERATOR;

typedef struct {
CHAR8 Name[16];
UINT32 Count;
CHAR8 Name[2][16];
UINT32 Count[2];
MATCH_OPERATOR MatchOp;
BOOLEAN (*IsMatch)(
VOID *Fdt,
CONST CHAR8 *Item,
CONST CHAR8 *DTPath,
VOID *Param
);
} DT_MATCH_INFO;
Expand All @@ -55,48 +56,52 @@ STATIC BOOLEAN
MatchId (
VOID *,
CONST CHAR8 *,
CONST CHAR8 *,
VOID *
);

STATIC BOOLEAN
MatchOdmData (
VOID *,
CONST CHAR8 *,
CONST CHAR8 *,
VOID *
);

STATIC BOOLEAN
MatchSWModule (
VOID *,
CONST CHAR8 *,
CONST CHAR8 *,
VOID *
);

STATIC BOOLEAN
MatchFuseInfo (
VOID *,
CONST CHAR8 *,
CONST CHAR8 *,
VOID *
);

DT_MATCH_INFO MatchInfoArray[] = {
{
.Name = "ids",
.Name = {"ids", "eeprom-dt-paths"},
.MatchOp = MATCH_OR,
.IsMatch = MatchId,
},
{
.Name = "odm-data",
.Name = {"odm-data"},
.MatchOp = MATCH_AND,
.IsMatch = MatchOdmData,
},
{
.Name = "sw-modules",
.Name = {"sw-modules"},
.MatchOp = MATCH_OR,
.IsMatch = MatchSWModule,
},
{
.Name = "fuse-info",
.Name = {"fuse-info"},
.MatchOp = MATCH_AND,
.IsMatch = MatchFuseInfo,
},
Expand Down Expand Up @@ -152,6 +157,7 @@ STATIC BOOLEAN
MatchId (
VOID *Fdt,
CONST CHAR8 *Id,
CONST CHAR8 *TargetDTPath,
VOID *Param
)
{
Expand All @@ -162,6 +168,7 @@ MatchId (
INTN BoardIdLen;
UINTN FabIdPrefixLen;
CONST CHAR8 *BoardId = NULL;
CHAR8 *EeepromDeviceTreePath = NULL;

BOOLEAN Matched = FALSE;

Expand Down Expand Up @@ -222,15 +229,19 @@ MatchId (
}

for (i = 0; i < BoardInfo->IdCount; i++) {
Matched = FALSE;
BoardId = TegraBoardIdFromPartNumber (&BoardInfo->ProductIds[i]);
EeepromDeviceTreePath = BoardInfo->EepromDeviceTreePaths[i];
BoardIdLen = strlen (BoardId);
BoardFabId = GetFabId (BoardId, NULL);
DEBUG ((
DEBUG_INFO,
"%a: check if overlay node id %a match with %a\n",
"%a: check if overlay node id %a match with %a (DT path %a, target DT path %a)\n",
__FUNCTION__,
Id,
BoardId
BoardId,
EeepromDeviceTreePath,
TargetDTPath
));

switch (MatchType) {
Expand Down Expand Up @@ -290,7 +301,20 @@ MatchId (
}

if (Matched == TRUE) {
break;
if (TargetDTPath != NULL) {
if (EeepromDeviceTreePath == NULL) {
Matched = FALSE;
} else {
EeepromDeviceTreePath = BoardInfo->EepromDeviceTreePaths[i];
INT32 TargetDTPathLen = strlen(TargetDTPath);
INT32 EepromPathLen = strlen(EeepromDeviceTreePath);
if (!(EepromPathLen == TargetDTPathLen && !CompareMem (TargetDTPath, EeepromDeviceTreePath, EepromPathLen))) {
Matched = FALSE;
} else {
break;
}
}
}
}
}

Expand All @@ -303,6 +327,7 @@ STATIC BOOLEAN
MatchOdmData (
VOID *Fdt,
CONST CHAR8 *OdmData,
CONST CHAR8 *DTPath,
VOID *Param
)
{
Expand All @@ -328,6 +353,7 @@ STATIC BOOLEAN
MatchSWModule (
VOID *Fdt,
CONST CHAR8 *ModuleStr,
CONST CHAR8 *DTPath,
VOID *Param
)
{
Expand All @@ -342,6 +368,7 @@ STATIC BOOLEAN
MatchFuseInfo (
VOID *Fdt,
CONST CHAR8 *FuseStr,
CONST CHAR8 *DTPath,
VOID *Param
)
{
Expand Down Expand Up @@ -375,18 +402,28 @@ PMGetPropertyCount (
UINTN AllCount = 0;
UINTN Index;
INTN PropCount;
INTN PropCount2;

for (Index = 0; Index < ARRAY_SIZE (MatchInfoArray); MatchIter++, Index++) {
PropCount = fdt_stringlist_count (Fdt, Node, MatchIter->Name);
PropCount = fdt_stringlist_count (Fdt, Node, MatchIter->Name[0]);
if (PropCount < 0) {
DEBUG ((DEBUG_INFO, "%a: Node: %d, Property: %a: Not Found.\n", __FUNCTION__, Node, MatchIter->Name));
MatchIter->Count = 0;
MatchIter->Count[0] = 0;
} else {
MatchIter->Count = PropCount;
MatchIter->Count[0] = PropCount;
DEBUG ((DEBUG_INFO, "%a: Node: %d, Property: %a: Count: %d.\n", __FUNCTION__, Node, MatchIter->Name, PropCount));
}

AllCount += MatchIter->Count;
if (MatchIter->Name[1][0] != 0) {
PropCount2 = fdt_stringlist_count (Fdt, Node, MatchIter->Name[1]);
if (PropCount2 < 0) {
DEBUG ((DEBUG_INFO, "%a: Node: %d, Property: %a: Not Found.\n", __FUNCTION__, Node, MatchIter->Name[1]));
MatchIter->Count[1] = 0;
} else {
MatchIter->Count[1] = PropCount2;
DEBUG ((DEBUG_INFO, "%a: Node: %d, Property: %a: Count: %d.\n", __FUNCTION__, Node, MatchIter->Name[1], PropCount2));
}
}
AllCount += MatchIter->Count[0] + MatchIter->Count[1];
}

if (!AllCount) {
Expand Down Expand Up @@ -593,13 +630,15 @@ ProcessOverlayDeviceTree (
CONST CHAR8 *NodeName;
INTN ConfigNode;
CONST CHAR8 *PropStr;
CONST CHAR8 *PropStr2;
INTN PropCount;
INT32 FdtErr;
EFI_STATUS Status = EFI_SUCCESS;
BOOLEAN Found = FALSE;
DT_MATCH_INFO *MatchIter;
UINT32 Index;
UINT32 Count;
UINT32 Count2;
UINT32 NumberSubnodes;
UINT32 FixupNodes = 0;

Expand Down Expand Up @@ -637,27 +676,53 @@ ProcessOverlayDeviceTree (

MatchIter = MatchInfoArray;
for (Index = 0; Index < ARRAY_SIZE (MatchInfoArray); Index++, MatchIter++) {
if ((MatchIter->Count > 0) && MatchIter->IsMatch) {
if ((MatchIter->Count[0] > 0) && MatchIter->IsMatch) {
UINT32 Data = 0;

for (Count = 0, Found = FALSE; Count < MatchIter->Count; Count++) {
PropStr = fdt_stringlist_get (FdtOverlay, ConfigNode, MatchIter->Name, Count, NULL);
DEBUG ((
DEBUG_INFO,
"Check if property %a[%a] on /%a match\n",
MatchIter->Name,
PropStr,
FrName
));

Found = MatchIter->IsMatch (FdtBase, PropStr, &Data);
if (!Found && (MatchIter->MatchOp == MATCH_AND)) {
break;
}
for (Count = 0, Found = FALSE; Count < MatchIter->Count[0]; Count++) {
PropStr = fdt_stringlist_get (FdtOverlay, ConfigNode, MatchIter->Name[0], Count, NULL);

if (MatchIter->Count[1] > 0) {
// This case should only be for "ids" and "eeprom-dt-paths"
for (Count2 = 0; Count2 < MatchIter->Count[1]; Count2++) {
PropStr2 = fdt_stringlist_get (FdtOverlay, ConfigNode, MatchIter->Name[1], Count2, NULL);

DEBUG ((
DEBUG_INFO,
"Check if property %a[%a] with %a on /%a match \n",
MatchIter->Name,
PropStr,
PropStr2,
FrName
));

Found = MatchIter->IsMatch (FdtBase, PropStr, PropStr2, &Data);
if (Found && (MatchIter->MatchOp == MATCH_OR)) {
break;
}

}
if (Found && (MatchIter->MatchOp == MATCH_OR)) {
break;
}
} else {
DEBUG ((
DEBUG_INFO,
"Check if property %a[%a] on /%a match\n",
MatchIter->Name,
PropStr,
FrName
));

Found = MatchIter->IsMatch (FdtBase, PropStr, NULL, &Data);
if (!Found && (MatchIter->MatchOp == MATCH_AND)) {
break;
}

if (Found && (MatchIter->MatchOp == MATCH_OR)) {
break;
}
if (Found && (MatchIter->MatchOp == MATCH_OR)) {
break;
}
}
}

if (!Found) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ typedef struct {
UINTN FuseCount;
EEPROM_PART_NUMBER *ProductIds;
UINTN IdCount;
CHAR8 **EepromDeviceTreePaths;
} OVERLAY_BOARD_INFO;

EFI_STATUS
Expand Down

0 comments on commit 4c1473e

Please sign in to comment.