Commit 7e92b704 authored by Declan Snyder's avatar Declan Snyder Committed by Henrik Brix Andersen
Browse files

include: devicetree: Add more PHA macros



Add more macros for interacting with controller/data type of
relationships (phandle arrays / cells)

Add macros for arbitrarily iterating cells of phandle specifiers

Add tests for the new macros

Signed-off-by: default avatarDeclan Snyder <declan.snyder@nxp.com>
parent 8d61b363
Loading
Loading
Loading
Loading
+128 −0
Original line number Diff line number Diff line
@@ -3817,6 +3817,134 @@
#define DT_PHA_HAS_CELL(node_id, pha, cell) \
	DT_PHA_HAS_CELL_AT_IDX(node_id, pha, 0, cell)

/**
 * @brief Iterate over all cells in a phandle array element by index
 *
 * This macro calls @p fn(cell_value) for each cell value in the
 * phandle array element at index @p idx.
 *
 * In general, this macro expands to:
 *
 *     fn(node_id, pha, idx, cell[0]) fn(node_id, pha, idx, cell[1]) [...]
 *     fn(node_id, pha, idx, cell[n-1])
 *
 * where `n` is the number of cells in @p pha, as it would be
 * returned by `DT_PHA_NUM_CELLS_BY_IDX(node_id, pha, idx)`, and cell[x] is the NAME of the cell
 * in the specifier.
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param idx index of the phandle array element
 * @param fn macro to call for each cell value
 */
#define DT_FOREACH_PHA_CELL_BY_IDX(node_id, pha, idx, fn)	\
	DT_CAT6(node_id, _P_, pha, _IDX_, idx, _FOREACH_CELL)(fn)

/**
 * @brief Iterate over all cells in a phandle array element by index with separator
 *
 * This is like DT_FOREACH_PHA_CELL_BY_IDX(), but @p sep is placed between
 * each invocation of @p fn.
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param idx index of the phandle array element
 * @param fn macro to call for each cell value
 * @param sep separator (e.g. comma or semicolon)
 */
#define DT_FOREACH_PHA_CELL_BY_IDX_SEP(node_id, pha, idx, fn, sep)	\
	DT_CAT6(node_id, _P_, pha, _IDX_, idx, _FOREACH_CELL_SEP)(fn, sep)

/**
 * @brief Get the number of cells in a phandle array element by index
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param idx index of the phandle array element
 * @return number of cells in the element at index @p idx
 */
#define DT_PHA_NUM_CELLS_BY_IDX(node_id, pha, idx) \
	DT_CAT6(node_id, _P_, pha, _IDX_, idx, _NUM_CELLS)

/**
 * @brief Get the name of a phandle array element by index
 *
 * This returns the name in the *-names property of the node
 * corresponding to the index @p idx of @p pha
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param idx index of the phandle array element
 * @return name of the element at index @p idx
 */
#define DT_PHA_ELEM_NAME_BY_IDX(node_id, pha, idx) \
	DT_CAT6(node_id, _P_, pha, _IDX_, idx, _NAME)

/**
 * @brief Iterate over all cells in a phandle array element by name
 *
 * This macro calls @p fn(cell_value) for each cell value in the
 * phandle array @p pha element with the given @p name in the *-names property.
 *
 * In general, this macro expands to:
 *
 *     fn(node_id, pha, name, cell[0]) fn(node_id, pha, idx, cell[1]) [...]
 *     fn(node_id, pha, idx, cell[n-1])
 *
 * where `n` is the number of cells in @p pha, as it would be
 * returned by `DT_PHA_NUM_CELLS_BY_NAME(node_id, pha, name)`, and cell[x] is the NAME of the cell
 * in the specifier.
 *
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param name lowercase-and-underscores name of the phandle array element
 * @param fn macro to call for each cell value
 */
#define DT_FOREACH_PHA_CELL_BY_NAME(node_id, pha, name, fn)	\
	DT_CAT6(node_id, _P_, pha, _NAME_, name, _FOREACH_CELL)(fn)

/**
 * @brief Iterate over all cells in a phandle array element by name with separator
 *
 * This is like DT_FOREACH_PHA_CELL_BY_NAME(), but @p sep is placed between
 * each invocation of @p fn.
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param name lowercase-and-underscores name of the phandle array element
 * @param fn macro to call for each cell value
 * @param sep separator (e.g. comma or semicolon)
 */
#define DT_FOREACH_PHA_CELL_BY_NAME_SEP(node_id, pha, name, fn, sep)	\
	DT_CAT6(node_id, _P_, pha, _NAME_, name, _FOREACH_CELL_SEP)(fn, sep)

/**
 * @brief Get the number of cells in a phandle array element by name
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param name lowercase-and-underscores name of the phandle array element
 * @return number of cells in the element with the given @p name
 */
#define DT_PHA_NUM_CELLS_BY_NAME(node_id, pha, name) \
	DT_CAT6(node_id, _P_, pha, _NAME_, name, _NUM_CELLS)

/**
 * @brief Get the index of a phandle array element by name
 *
 * This returns the index of the @p pha which has the name @p name in the corresponding
 * *-names property.
 *
 * @param node_id node identifier
 * @param pha lowercase-and-underscores property with type `phandle-array`
 * @param name lowercase-and-underscores name of the phandle array element
 * @return index of the element with the given @p name
 */
#define DT_PHA_ELEM_IDX_BY_NAME(node_id, pha, name) \
	DT_CAT6(node_id, _P_, pha, _NAME_, name, _IDX)


/**
 * @}
 */
+34 −5
Original line number Diff line number Diff line
@@ -569,7 +569,7 @@ def write_gpio_hogs(node: edtlib.Node) -> None:
    macro = f"{node.z_path_id}_GPIO_HOGS"
    macro2val = {}
    for i, entry in enumerate(node.gpio_hogs):
        macro2val.update(controller_and_data_macros(entry, i, macro))
        macro2val.update(controller_and_data_macros(entry, i, macro, ""))

    if macro2val:
        out_comment("GPIO hog properties:")
@@ -835,12 +835,12 @@ def phandle_macros(prop: edtlib.Property, macro: str) -> dict:
                ret[f"{macro}_IDX_{i}_EXISTS"] = 0
                continue

            ret.update(controller_and_data_macros(entry, i, macro))
            ret.update(controller_and_data_macros(entry, i, macro, prop.name))

    return ret


def controller_and_data_macros(entry: edtlib.ControllerAndData, i: int, macro: str):
def controller_and_data_macros(entry: edtlib.ControllerAndData, i: int, macro: str, pname: str):
    # Helper procedure used by phandle_macros().
    #
    # Its purpose is to write the "controller" (i.e. label property of
@@ -849,6 +849,8 @@ def controller_and_data_macros(entry: edtlib.ControllerAndData, i: int, macro: s

    ret = {}
    data = entry.data
    node = entry.node
    pname = edtlib.str_as_token(str2ident(pname))

    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_EXISTS
    ret[f"{macro}_IDX_{i}_EXISTS"] = 1
@@ -858,13 +860,40 @@ def controller_and_data_macros(entry: edtlib.ControllerAndData, i: int, macro: s
    for cell, val in data.items():
        ret[f"{macro}_IDX_{i}_VAL_{str2ident(cell)}"] = val
        ret[f"{macro}_IDX_{i}_VAL_{str2ident(cell)}_EXISTS"] = 1
    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_EXISTS
    ret[f"{macro}_IDX_{i}_EXISTS"] = 1
    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_FOREACH_CELL
    ret[f"{macro}_IDX_{i}_FOREACH_CELL(fn)"] = (
            ' \\\n\t'.join(f'fn(DT_{node.z_path_id}, {pname}, {i}, {cell})'
                           for cell in data))
    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_FOREACH_CELL_SEP
    ret[f"{macro}_IDX_{i}_FOREACH_CELL_SEP(fn, sep)"] = (
        ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
            f'fn(DT_{node.z_path_id}, {pname}, {i}, {cell})'
               for cell in data))
    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_NUM_CELLS
    ret[f"{macro}_IDX_{i}_NUM_CELLS"] = len(data)

    if not entry.name:
        return ret

    name = str2ident(entry.name)
    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_EXISTS
    ret[f"{macro}_IDX_{i}_EXISTS"] = 1

    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_NAME
    ret[f"{macro}_IDX_{i}_NAME"] = edtlib.str_as_token(name)
    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_IDX
    ret[f"{macro}_NAME_{name}_IDX"] = i
    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_FOREACH_CELL
    ret[f"{macro}_NAME_{name}_FOREACH_CELL(fn)"] = (
            ' \\\n\t'.join(f'fn(DT_{node.z_path_id}, {pname}, {name}, {cell})'
                           for cell in data))
    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_FOREACH_CELL_SEP
    ret[f"{macro}_NAME_{name}_FOREACH_CELL_SEP(fn, sep)"] = (
        ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
            f'fn(DT_{node.z_path_id}, {pname}, {name}, {cell})'
               for cell in data))
    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_NUM_CELLS
    ret[f"{macro}_NAME_{name}_NUM_CELLS"] = len(data)
    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_NAME
    ret[f"{macro}_IDX_{i}_NAME"] = quote_str(entry.name)
    # DT_N_<node-id>_P_<prop-id>_NAME_<NAME>_PH
+1 −1
Original line number Diff line number Diff line
@@ -855,7 +855,7 @@ class ControllerAndData:
      *-names property

    basename:
      Basename for the controller when supporting named cells
      Basename for the controller when supporting named cells. AKA, the specifier space.
    """
    node: 'Node'
    controller: 'Node'
+60 −1
Original line number Diff line number Diff line
@@ -1114,6 +1114,65 @@ ZTEST(devicetree_api, test_phandles)
	zassert_true(DT_SAME_NODE(DT_PHANDLE_BY_NAME(TEST_PH, foos, a), TEST_GPIO_1), "");
	zassert_true(DT_SAME_NODE(DT_PHANDLE_BY_NAME(TEST_PH, foos, b_c), TEST_GPIO_2), "");

	/* DT_PHA_NUM_CELLS_BY_IDX */
	zassert_equal(DT_PHA_NUM_CELLS_BY_IDX(TEST_PH, foos, 0), 1);
	zassert_equal(DT_PHA_NUM_CELLS_BY_IDX(TEST_PH, pha_gpios, 2), 1);
	zassert_equal(DT_PHA_NUM_CELLS_BY_IDX(TEST_PH, pha_gpios, 3), 2);

	/* DT_PHA_NUM_CELLS_BY_NAME */
	zassert_equal(DT_PHA_NUM_CELLS_BY_NAME(TEST_PH, foos, a), 1);
	zassert_equal(DT_PHA_NUM_CELLS_BY_NAME(TEST_PH, pwms, green), 3);
	zassert_equal(DT_PHA_NUM_CELLS_BY_NAME(TEST_PH, pwms, red), 3);

	/* DT_PHA_ELEM_NAME_BY_IDX */
	zassert_str_equal(DT_PHA_ELEM_NAME_BY_IDX(TEST_PH, foos, 0), "A");
	zassert_str_equal(DT_PHA_ELEM_NAME_BY_IDX(TEST_PH, foos, 1), "b-c");
	zassert_str_equal(DT_PHA_ELEM_NAME_BY_IDX(TEST_PH, pwms, 0), "red");
	zassert_str_equal(DT_PHA_ELEM_NAME_BY_IDX(TEST_PH, pwms, 1), "green");

	/* DT_PHA_ELEM_IDX_BY_NAME */
	zassert_equal(DT_PHA_ELEM_IDX_BY_NAME(TEST_PH, foos, a), 0);
	zassert_equal(DT_PHA_ELEM_IDX_BY_NAME(TEST_PH, foos, b_c), 1);
	zassert_equal(DT_PHA_ELEM_IDX_BY_NAME(TEST_PH, pwms, red), 0);
	zassert_equal(DT_PHA_ELEM_IDX_BY_NAME(TEST_PH, pwms, green), 1);

	/* DT_FOREACH_PHA_CELL_BY_IDX */
	int chksum;

#define ADD_TWO(node_id, pha, idx, x) (DT_PHA_BY_IDX(node_id, pha, idx, x) + 2) +
	chksum = DT_FOREACH_PHA_CELL_BY_IDX(TEST_PH, pwms, 0, ADD_TWO) 0;
	zassert_equal(chksum, 211 + 6);
	chksum = DT_FOREACH_PHA_CELL_BY_IDX(TEST_PH, foos, 1, ADD_TWO) 0;
	zassert_equal(chksum, 110 + 2);

	/* DT_FOREACH_PHA_CELL_BY_IDX_SEP */
	int cells_one[2] = {
		DT_FOREACH_PHA_CELL_BY_IDX_SEP(TEST_PH, pha_gpios, 0, DT_PHA_BY_IDX, (,))
	};
	int cells_two[1] = {
		DT_FOREACH_PHA_CELL_BY_IDX_SEP(TEST_PH, pha_gpios, 2, DT_PHA_BY_IDX, (,))
	};

	zassert_equal(cells_one[0], 50);
	zassert_equal(cells_one[1], 60);
	zassert_equal(cells_two[0], 70);

	/* DT_FOREACH_PHA_CELL_BY_NAME */
#define ADD_THREE(node_id, pha, idx, x) (DT_PHA_BY_NAME(node_id, pha, idx, x) + 3) +
	chksum = DT_FOREACH_PHA_CELL_BY_NAME(TEST_PH, pwms, red, ADD_THREE) 0;
	zassert_equal(chksum, 211 + 9);
	chksum = DT_FOREACH_PHA_CELL_BY_NAME(TEST_PH, pwms, green, ADD_THREE) 0;
	zassert_equal(chksum, 106 + 9);

	/* DT_FOREACH_PHA_CELL_BY_NAME_SEP */
	int cells_pwms[3] = {
		DT_FOREACH_PHA_CELL_BY_NAME_SEP(TEST_PH, pwms, green, DT_PHA_BY_NAME, (,))
	};

	zassert_equal(cells_pwms[0], 5);
	zassert_equal(cells_pwms[1], 100);
	zassert_equal(cells_pwms[2], 1);

	/* array initializers */
	zassert_equal(gps[0].pin, 10, "");
	zassert_equal(gps[0].flags, 20, "");