|
1290 | 1290 | */ |
1291 | 1291 | #define DT_PHANDLE(node_id, prop) DT_PHANDLE_BY_IDX(node_id, prop, 0) |
1292 | 1292 |
|
| 1293 | +/** |
| 1294 | + * @} |
| 1295 | + */ |
| 1296 | + |
| 1297 | +/** |
| 1298 | + * @defgroup devicetree-ranges-prop ranges property |
| 1299 | + * @ingroup devicetree |
| 1300 | + * @{ |
| 1301 | + */ |
| 1302 | + |
| 1303 | +/** |
| 1304 | + * @brief Get the number of range blocks in the ranges property |
| 1305 | + * |
| 1306 | + * Use this instead of DT_PROP_LEN(node_id, ranges). |
| 1307 | + * |
| 1308 | + * Example devicetree fragment: |
| 1309 | + * |
| 1310 | + * pcie0: pcie@0 { |
| 1311 | + * compatible = "intel,pcie"; |
| 1312 | + * reg = <0 1>; |
| 1313 | + * #address-cells = <3>; |
| 1314 | + * #size-cells = <2>; |
| 1315 | + * |
| 1316 | + * ranges = <0x1000000 0 0 0 0x3eff0000 0 0x10000>, |
| 1317 | + * <0x2000000 0 0x10000000 0 0x10000000 0 0x2eff0000>, |
| 1318 | + * <0x3000000 0x80 0 0x80 0 0x80 0>; |
| 1319 | + * }; |
| 1320 | + * |
| 1321 | + * other: other@1 { |
| 1322 | + * reg = <1 1>; |
| 1323 | + * |
| 1324 | + * ranges = <0x0 0x0 0x0 0x3eff0000 0x10000>, |
| 1325 | + * <0x0 0x10000000 0x0 0x10000000 0x2eff0000>; |
| 1326 | + * }; |
| 1327 | + * |
| 1328 | + * Example usage: |
| 1329 | + * |
| 1330 | + * DT_NUM_RANGES(DT_NODELABEL(pcie0)) // 3 |
| 1331 | + * DT_NUM_RANGES(DT_NODELABEL(other)) // 2 |
| 1332 | + * |
| 1333 | + * @param node_id node identifier |
| 1334 | + */ |
| 1335 | +#define DT_NUM_RANGES(node_id) DT_CAT(node_id, _RANGES_NUM) |
| 1336 | + |
| 1337 | +/** |
| 1338 | + * @brief Is "idx" a valid range block index? |
| 1339 | + * |
| 1340 | + * If this returns 1, then DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(node_id, idx), |
| 1341 | + * DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(node_id, idx) or |
| 1342 | + * DT_RANGES_LENGTH_BY_IDX(node_id, idx) are valid. |
| 1343 | + * For DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(node_id, idx) the return value |
| 1344 | + * of DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(node_id, idx) will indicate |
| 1345 | + * validity. |
| 1346 | + * If it returns 0, it is an error to use those macros with index "idx", |
| 1347 | + * including DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(node_id, idx). |
| 1348 | + * |
| 1349 | + * Example devicetree fragment: |
| 1350 | + * |
| 1351 | + * |
| 1352 | + * pcie0: pcie@0 { |
| 1353 | + * compatible = "intel,pcie"; |
| 1354 | + * reg = <0 1>; |
| 1355 | + * #address-cells = <3>; |
| 1356 | + * #size-cells = <2>; |
| 1357 | + * |
| 1358 | + * ranges = <0x1000000 0 0 0 0x3eff0000 0 0x10000>, |
| 1359 | + * <0x2000000 0 0x10000000 0 0x10000000 0 0x2eff0000>, |
| 1360 | + * <0x3000000 0x80 0 0x80 0 0x80 0>; |
| 1361 | + * }; |
| 1362 | + * |
| 1363 | + * other: other@1 { |
| 1364 | + * reg = <1 1>; |
| 1365 | + * |
| 1366 | + * ranges = <0x0 0x0 0x0 0x3eff0000 0x10000>, |
| 1367 | + * <0x0 0x10000000 0x0 0x10000000 0x2eff0000>; |
| 1368 | + * }; |
| 1369 | + * |
| 1370 | + * Example usage: |
| 1371 | + * |
| 1372 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(pcie0), 0) // 1 |
| 1373 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(pcie0), 1) // 1 |
| 1374 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(pcie0), 2) // 1 |
| 1375 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(pcie0), 3) // 0 |
| 1376 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(other), 0) // 1 |
| 1377 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(other), 1) // 1 |
| 1378 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(other), 2) // 0 |
| 1379 | + * DT_RANGES_HAS_IDX(DT_NODELABEL(other), 3) // 0 |
| 1380 | + * |
| 1381 | + * @param node_id node identifier |
| 1382 | + * @param idx index to check |
| 1383 | + * @return 1 if "idx" is a valid register block index, |
| 1384 | + * 0 otherwise. |
| 1385 | + */ |
| 1386 | +#define DT_RANGES_HAS_IDX(node_id, idx) \ |
| 1387 | + IS_ENABLED(DT_CAT4(node_id, _RANGES_IDX_, idx, _EXISTS)) |
| 1388 | + |
| 1389 | +/** |
| 1390 | + * @brief Does a ranges property have child bus flags at index? |
| 1391 | + * |
| 1392 | + * If this returns 1, then DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(node_id, idx) is valid. |
| 1393 | + * If it returns 0, it is an error to use this macro with index "idx". |
| 1394 | + * This macro only returns 1 for PCIe buses (i.e. nodes whose bindings specify they |
| 1395 | + * are "pcie" bus nodes.) |
| 1396 | + * |
| 1397 | + * Example devicetree fragment: |
| 1398 | + * |
| 1399 | + * parent { |
| 1400 | + * #address-cells = <2>; |
| 1401 | + * |
| 1402 | + * pcie0: pcie@0 { |
| 1403 | + * compatible = "intel,pcie"; |
| 1404 | + * reg = <0 0 1>; |
| 1405 | + * #address-cells = <3>; |
| 1406 | + * #size-cells = <2>; |
| 1407 | + * |
| 1408 | + * ranges = <0x1000000 0 0 0 0x3eff0000 0 0x10000>, |
| 1409 | + * <0x2000000 0 0x10000000 0 0x10000000 0 0x2eff0000>, |
| 1410 | + * <0x3000000 0x80 0 0x80 0 0x80 0>; |
| 1411 | + * }; |
| 1412 | + * |
| 1413 | + * other: other@1 { |
| 1414 | + * reg = <0 1 1>; |
| 1415 | + * |
| 1416 | + * ranges = <0x0 0x0 0x0 0x3eff0000 0x10000>, |
| 1417 | + * <0x0 0x10000000 0x0 0x10000000 0x2eff0000>; |
| 1418 | + * }; |
| 1419 | + * }; |
| 1420 | + * |
| 1421 | + * Example usage: |
| 1422 | + * |
| 1423 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(pcie0), 0) // 1 |
| 1424 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(pcie0), 1) // 1 |
| 1425 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(pcie0), 2) // 1 |
| 1426 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(pcie0), 3) // 0 |
| 1427 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(other), 0) // 0 |
| 1428 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(other), 1) // 0 |
| 1429 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(other), 2) // 0 |
| 1430 | + * DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(DT_NODELABEL(other), 3) // 0 |
| 1431 | + * |
| 1432 | + * @param node_id node identifier |
| 1433 | + * @param idx logical index into the ranges array |
| 1434 | + * @return 1 if "idx" is a valid child bus flags index, |
| 1435 | + * 0 otherwise. |
| 1436 | + */ |
| 1437 | +#define DT_RANGES_HAS_CHILD_BUS_FLAGS_AT_IDX(node_id, idx) \ |
| 1438 | + IS_ENABLED(DT_CAT4(node_id, _RANGES_IDX_, idx, _VAL_CHILD_BUS_FLAGS_EXISTS)) |
| 1439 | + |
| 1440 | +/** |
| 1441 | + * @brief Get the ranges property child bus flags at index |
| 1442 | + * |
| 1443 | + * When the node is a PCIe bus, the Child Bus Address has an extra cell used to store some |
| 1444 | + * flags, thus this cell is extracted from the Child Bus Address as Child Bus Flags field. |
| 1445 | + * |
| 1446 | + * Example devicetree fragments: |
| 1447 | + * |
| 1448 | + * parent { |
| 1449 | + * #address-cells = <2>; |
| 1450 | + * |
| 1451 | + * pcie0: pcie@0 { |
| 1452 | + * compatible = "intel,pcie"; |
| 1453 | + * reg = <0 0 1>; |
| 1454 | + * #address-cells = <3>; |
| 1455 | + * #size-cells = <2>; |
| 1456 | + * |
| 1457 | + * ranges = <0x1000000 0 0 0 0x3eff0000 0 0x10000>, |
| 1458 | + * <0x2000000 0 0x10000000 0 0x10000000 0 0x2eff0000>, |
| 1459 | + * <0x3000000 0x80 0 0x80 0 0x80 0>; |
| 1460 | + * }; |
| 1461 | + * }; |
| 1462 | + * |
| 1463 | + * Example usage: |
| 1464 | + * |
| 1465 | + * DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(DT_NODELABEL(pcie0), 0) // 0x1000000 |
| 1466 | + * DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(DT_NODELABEL(pcie0), 1) // 0x2000000 |
| 1467 | + * DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(DT_NODELABEL(pcie0), 2) // 0x3000000 |
| 1468 | + * |
| 1469 | + * @param node_id node identifier |
| 1470 | + * @param idx logical index into the ranges array |
| 1471 | + * @returns range child bus flags field at idx |
| 1472 | + */ |
| 1473 | +#define DT_RANGES_CHILD_BUS_FLAGS_BY_IDX(node_id, idx) \ |
| 1474 | + DT_CAT4(node_id, _RANGES_IDX_, idx, _VAL_CHILD_BUS_FLAGS) |
| 1475 | + |
| 1476 | +/** |
| 1477 | + * @brief Get the ranges property child bus address at index |
| 1478 | + * |
| 1479 | + * When the node is a PCIe bus, the Child Bus Address has an extra cell used to store some |
| 1480 | + * flags, thus this cell is removed from the Child Bus Address. |
| 1481 | + * |
| 1482 | + * Example devicetree fragments: |
| 1483 | + * |
| 1484 | + * parent { |
| 1485 | + * #address-cells = <2>; |
| 1486 | + * |
| 1487 | + * pcie0: pcie@0 { |
| 1488 | + * compatible = "intel,pcie"; |
| 1489 | + * reg = <0 0 1>; |
| 1490 | + * #address-cells = <3>; |
| 1491 | + * #size-cells = <2>; |
| 1492 | + * |
| 1493 | + * ranges = <0x1000000 0 0 0 0x3eff0000 0 0x10000>, |
| 1494 | + * <0x2000000 0 0x10000000 0 0x10000000 0 0x2eff0000>, |
| 1495 | + * <0x3000000 0x80 0 0x80 0 0x80 0>; |
| 1496 | + * }; |
| 1497 | + * |
| 1498 | + * other: other@1 { |
| 1499 | + * reg = <0 1 1>; |
| 1500 | + * |
| 1501 | + * ranges = <0x0 0x0 0x0 0x3eff0000 0x10000>, |
| 1502 | + * <0x0 0x10000000 0x0 0x10000000 0x2eff0000>; |
| 1503 | + * }; |
| 1504 | + * }; |
| 1505 | + * |
| 1506 | + * Example usage: |
| 1507 | + * |
| 1508 | + * DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(DT_NODELABEL(pcie0), 0) // 0 |
| 1509 | + * DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(DT_NODELABEL(pcie0), 1) // 0x10000000 |
| 1510 | + * DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(DT_NODELABEL(pcie0), 2) // 0x8000000000 |
| 1511 | + * DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(DT_NODELABEL(other), 0) // 0 |
| 1512 | + * DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(DT_NODELABEL(other), 1) // 0x10000000 |
| 1513 | + * |
| 1514 | + * @param node_id node identifier |
| 1515 | + * @param idx logical index into the ranges array |
| 1516 | + * @returns range child bus address field at idx |
| 1517 | + */ |
| 1518 | +#define DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(node_id, idx) \ |
| 1519 | + DT_CAT4(node_id, _RANGES_IDX_, idx, _VAL_CHILD_BUS_ADDRESS) |
| 1520 | + |
| 1521 | +/** |
| 1522 | + * @brief Get the ranges property parent bus address at index |
| 1523 | + * |
| 1524 | + * Similarly to DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(), this properly accounts |
| 1525 | + * for child bus flags cells when the node is a PCIe bus. |
| 1526 | + * |
| 1527 | + * Example devicetree fragment: |
| 1528 | + * |
| 1529 | + * parent { |
| 1530 | + * #address-cells = <2>; |
| 1531 | + * |
| 1532 | + * pcie0: pcie@0 { |
| 1533 | + * compatible = "intel,pcie"; |
| 1534 | + * reg = <0 0 1>; |
| 1535 | + * #address-cells = <3>; |
| 1536 | + * #size-cells = <2>; |
| 1537 | + * |
| 1538 | + * ranges = <0x1000000 0 0 0 0x3eff0000 0 0x10000>, |
| 1539 | + * <0x2000000 0 0x10000000 0 0x10000000 0 0x2eff0000>, |
| 1540 | + * <0x3000000 0x80 0 0x80 0 0x80 0>; |
| 1541 | + * }; |
| 1542 | + * |
| 1543 | + * other: other@1 { |
| 1544 | + * reg = <0 1 1>; |
| 1545 | + * |
| 1546 | + * ranges = <0x0 0x0 0x0 0x3eff0000 0x10000>, |
| 1547 | + * <0x0 0x10000000 0x0 0x10000000 0x2eff0000>; |
| 1548 | + * }; |
| 1549 | + * }; |
| 1550 | + * |
| 1551 | + * Example usage: |
| 1552 | + * |
| 1553 | + * DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(DT_NODELABEL(pcie0), 0) // 0x3eff0000 |
| 1554 | + * DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(DT_NODELABEL(pcie0), 1) // 0x10000000 |
| 1555 | + * DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(DT_NODELABEL(pcie0), 2) // 0x8000000000 |
| 1556 | + * DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(DT_NODELABEL(other), 0) // 0x3eff0000 |
| 1557 | + * DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(DT_NODELABEL(other), 1) // 0x10000000 |
| 1558 | + * |
| 1559 | + * @param node_id node identifier |
| 1560 | + * @param idx logical index into the ranges array |
| 1561 | + * @returns range parent bus address field at idx |
| 1562 | + */ |
| 1563 | +#define DT_RANGES_PARENT_BUS_ADDRESS_BY_IDX(node_id, idx) \ |
| 1564 | + DT_CAT4(node_id, _RANGES_IDX_, idx, _VAL_PARENT_BUS_ADDRESS) |
| 1565 | + |
| 1566 | +/** |
| 1567 | + * @brief Get the ranges property length at index |
| 1568 | + * |
| 1569 | + * Similarly to DT_RANGES_CHILD_BUS_ADDRESS_BY_IDX(), this properly accounts |
| 1570 | + * for child bus flags cells when the node is a PCIe bus. |
| 1571 | + * |
| 1572 | + * Example devicetree fragment: |
| 1573 | + * |
| 1574 | + * parent { |
| 1575 | + * #address-cells = <2>; |
| 1576 | + * |
| 1577 | + * pcie0: pcie@0 { |
| 1578 | + * compatible = "intel,pcie"; |
| 1579 | + * reg = <0 0 1>; |
| 1580 | + * #address-cells = <3>; |
| 1581 | + * #size-cells = <2>; |
| 1582 | + * |
| 1583 | + * ranges = <0x1000000 0 0 0 0x3eff0000 0 0x10000>, |
| 1584 | + * <0x2000000 0 0x10000000 0 0x10000000 0 0x2eff0000>, |
| 1585 | + * <0x3000000 0x80 0 0x80 0 0x80 0>; |
| 1586 | + * }; |
| 1587 | + * |
| 1588 | + * other: other@1 { |
| 1589 | + * reg = <0 1 1>; |
| 1590 | + * |
| 1591 | + * ranges = <0x0 0x0 0x0 0x3eff0000 0x10000>, |
| 1592 | + * <0x0 0x10000000 0x0 0x10000000 0x2eff0000>; |
| 1593 | + * }; |
| 1594 | + * }; |
| 1595 | + * |
| 1596 | + * Example usage: |
| 1597 | + * |
| 1598 | + * DT_RANGES_LENGTH_BY_IDX(DT_NODELABEL(pcie0), 0) // 0x10000 |
| 1599 | + * DT_RANGES_LENGTH_BY_IDX(DT_NODELABEL(pcie0), 1) // 0x2eff0000 |
| 1600 | + * DT_RANGES_LENGTH_BY_IDX(DT_NODELABEL(pcie0), 2) // 0x8000000000 |
| 1601 | + * DT_RANGES_LENGTH_BY_IDX(DT_NODELABEL(other), 0) // 0x10000 |
| 1602 | + * DT_RANGES_LENGTH_BY_IDX(DT_NODELABEL(other), 1) // 0x2eff0000 |
| 1603 | + * |
| 1604 | + * @param node_id node identifier |
| 1605 | + * @param idx logical index into the ranges array |
| 1606 | + * @returns range length field at idx |
| 1607 | + */ |
| 1608 | +#define DT_RANGES_LENGTH_BY_IDX(node_id, idx) \ |
| 1609 | + DT_CAT4(node_id, _RANGES_IDX_, idx, _VAL_LENGTH) |
| 1610 | + |
| 1611 | +/** |
| 1612 | + * @brief Invokes "fn" for each entry of "node_id" ranges property |
| 1613 | + * |
| 1614 | + * The macro "fn" must take two parameters, "node_id" which will be the node |
| 1615 | + * identifier of the node with the ranges property and "idx" the index of |
| 1616 | + * the ranges block. |
| 1617 | + * |
| 1618 | + * Example devicetree fragment: |
| 1619 | + * |
| 1620 | + * n: node@0 { |
| 1621 | + * reg = <0 0 1>; |
| 1622 | + * |
| 1623 | + * ranges = <0x0 0x0 0x0 0x3eff0000 0x10000>, |
| 1624 | + * <0x0 0x10000000 0x0 0x10000000 0x2eff0000>; |
| 1625 | + * }; |
| 1626 | + * |
| 1627 | + * Example usage: |
| 1628 | + * |
| 1629 | + * #define RANGE_LENGTH(node_id, idx) DT_RANGES_LENGTH_BY_IDX(node_id, idx), |
| 1630 | + * |
| 1631 | + * const uint64_t *ranges_length[] = { |
| 1632 | + * DT_FOREACH_RANGE(DT_NODELABEL(n), RANGE_LENGTH) |
| 1633 | + * }; |
| 1634 | + * |
| 1635 | + * This expands to: |
| 1636 | + * |
| 1637 | + * const char *ranges_length[] = { |
| 1638 | + * 0x10000, 0x2eff0000, |
| 1639 | + * }; |
| 1640 | + * |
| 1641 | + * @param node_id node identifier |
| 1642 | + * @param fn macro to invoke |
| 1643 | + */ |
| 1644 | +#define DT_FOREACH_RANGE(node_id, fn) \ |
| 1645 | + DT_CAT(node_id, _FOREACH_RANGE)(fn) |
| 1646 | + |
1293 | 1647 | /** |
1294 | 1648 | * @} |
1295 | 1649 | */ |
|
0 commit comments